|
@@ -1038,21 +1038,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (del_timer(&ct->timeout)) {
|
|
|
- if (nf_conntrack_event_report(IPCT_DESTROY, ct,
|
|
|
- NETLINK_CB(skb).portid,
|
|
|
- nlmsg_report(nlh)) < 0) {
|
|
|
- nf_ct_delete_from_lists(ct);
|
|
|
- /* we failed to report the event, try later */
|
|
|
- nf_ct_dying_timeout(ct);
|
|
|
- nf_ct_put(ct);
|
|
|
- return 0;
|
|
|
- }
|
|
|
- /* death_by_timeout would report the event again */
|
|
|
- set_bit(IPS_DYING_BIT, &ct->status);
|
|
|
- nf_ct_delete_from_lists(ct);
|
|
|
- nf_ct_put(ct);
|
|
|
- }
|
|
|
+ if (del_timer(&ct->timeout))
|
|
|
+ nf_ct_delete(ct, NETLINK_CB(skb).portid, nlmsg_report(nlh));
|
|
|
+
|
|
|
nf_ct_put(ct);
|
|
|
|
|
|
return 0;
|
|
@@ -1999,6 +1987,27 @@ out:
|
|
|
return err == -EAGAIN ? -ENOBUFS : err;
|
|
|
}
|
|
|
|
|
|
+static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
|
|
|
+ [CTA_EXPECT_MASTER] = { .type = NLA_NESTED },
|
|
|
+ [CTA_EXPECT_TUPLE] = { .type = NLA_NESTED },
|
|
|
+ [CTA_EXPECT_MASK] = { .type = NLA_NESTED },
|
|
|
+ [CTA_EXPECT_TIMEOUT] = { .type = NLA_U32 },
|
|
|
+ [CTA_EXPECT_ID] = { .type = NLA_U32 },
|
|
|
+ [CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING,
|
|
|
+ .len = NF_CT_HELPER_NAME_LEN - 1 },
|
|
|
+ [CTA_EXPECT_ZONE] = { .type = NLA_U16 },
|
|
|
+ [CTA_EXPECT_FLAGS] = { .type = NLA_U32 },
|
|
|
+ [CTA_EXPECT_CLASS] = { .type = NLA_U32 },
|
|
|
+ [CTA_EXPECT_NAT] = { .type = NLA_NESTED },
|
|
|
+ [CTA_EXPECT_FN] = { .type = NLA_NUL_STRING },
|
|
|
+};
|
|
|
+
|
|
|
+static struct nf_conntrack_expect *
|
|
|
+ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct,
|
|
|
+ struct nf_conntrack_helper *helper,
|
|
|
+ struct nf_conntrack_tuple *tuple,
|
|
|
+ struct nf_conntrack_tuple *mask);
|
|
|
+
|
|
|
#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
|
|
|
static size_t
|
|
|
ctnetlink_nfqueue_build_size(const struct nf_conn *ct)
|
|
@@ -2139,10 +2148,69 @@ ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int ctnetlink_nfqueue_exp_parse(const struct nlattr * const *cda,
|
|
|
+ const struct nf_conn *ct,
|
|
|
+ struct nf_conntrack_tuple *tuple,
|
|
|
+ struct nf_conntrack_tuple *mask)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+
|
|
|
+ err = ctnetlink_parse_tuple(cda, tuple, CTA_EXPECT_TUPLE,
|
|
|
+ nf_ct_l3num(ct));
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ return ctnetlink_parse_tuple(cda, mask, CTA_EXPECT_MASK,
|
|
|
+ nf_ct_l3num(ct));
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+ctnetlink_nfqueue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
|
|
|
+ u32 portid, u32 report)
|
|
|
+{
|
|
|
+ struct nlattr *cda[CTA_EXPECT_MAX+1];
|
|
|
+ struct nf_conntrack_tuple tuple, mask;
|
|
|
+ struct nf_conntrack_helper *helper;
|
|
|
+ struct nf_conntrack_expect *exp;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ err = nla_parse_nested(cda, CTA_EXPECT_MAX, attr, exp_nla_policy);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ err = ctnetlink_nfqueue_exp_parse((const struct nlattr * const *)cda,
|
|
|
+ ct, &tuple, &mask);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ if (cda[CTA_EXPECT_HELP_NAME]) {
|
|
|
+ const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
|
|
|
+
|
|
|
+ helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
|
|
|
+ nf_ct_protonum(ct));
|
|
|
+ if (helper == NULL)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+ }
|
|
|
+
|
|
|
+ exp = ctnetlink_alloc_expect((const struct nlattr * const *)cda, ct,
|
|
|
+ helper, &tuple, &mask);
|
|
|
+ if (IS_ERR(exp))
|
|
|
+ return PTR_ERR(exp);
|
|
|
+
|
|
|
+ err = nf_ct_expect_related_report(exp, portid, report);
|
|
|
+ if (err < 0) {
|
|
|
+ nf_ct_expect_put(exp);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static struct nfq_ct_hook ctnetlink_nfqueue_hook = {
|
|
|
.build_size = ctnetlink_nfqueue_build_size,
|
|
|
.build = ctnetlink_nfqueue_build,
|
|
|
.parse = ctnetlink_nfqueue_parse,
|
|
|
+ .attach_expect = ctnetlink_nfqueue_attach_expect,
|
|
|
};
|
|
|
#endif /* CONFIG_NETFILTER_NETLINK_QUEUE_CT */
|
|
|
|
|
@@ -2510,21 +2578,6 @@ static int ctnetlink_dump_exp_ct(struct sock *ctnl, struct sk_buff *skb,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
|
|
|
- [CTA_EXPECT_MASTER] = { .type = NLA_NESTED },
|
|
|
- [CTA_EXPECT_TUPLE] = { .type = NLA_NESTED },
|
|
|
- [CTA_EXPECT_MASK] = { .type = NLA_NESTED },
|
|
|
- [CTA_EXPECT_TIMEOUT] = { .type = NLA_U32 },
|
|
|
- [CTA_EXPECT_ID] = { .type = NLA_U32 },
|
|
|
- [CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING,
|
|
|
- .len = NF_CT_HELPER_NAME_LEN - 1 },
|
|
|
- [CTA_EXPECT_ZONE] = { .type = NLA_U16 },
|
|
|
- [CTA_EXPECT_FLAGS] = { .type = NLA_U32 },
|
|
|
- [CTA_EXPECT_CLASS] = { .type = NLA_U32 },
|
|
|
- [CTA_EXPECT_NAT] = { .type = NLA_NESTED },
|
|
|
- [CTA_EXPECT_FN] = { .type = NLA_NUL_STRING },
|
|
|
-};
|
|
|
-
|
|
|
static int
|
|
|
ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
|
|
|
const struct nlmsghdr *nlh,
|
|
@@ -2747,76 +2800,26 @@ ctnetlink_parse_expect_nat(const struct nlattr *attr,
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
-static int
|
|
|
-ctnetlink_create_expect(struct net *net, u16 zone,
|
|
|
- const struct nlattr * const cda[],
|
|
|
- u_int8_t u3,
|
|
|
- u32 portid, int report)
|
|
|
+static struct nf_conntrack_expect *
|
|
|
+ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
|
|
|
+ struct nf_conntrack_helper *helper,
|
|
|
+ struct nf_conntrack_tuple *tuple,
|
|
|
+ struct nf_conntrack_tuple *mask)
|
|
|
{
|
|
|
- struct nf_conntrack_tuple tuple, mask, master_tuple;
|
|
|
- struct nf_conntrack_tuple_hash *h = NULL;
|
|
|
+ u_int32_t class = 0;
|
|
|
struct nf_conntrack_expect *exp;
|
|
|
- struct nf_conn *ct;
|
|
|
struct nf_conn_help *help;
|
|
|
- struct nf_conntrack_helper *helper = NULL;
|
|
|
- u_int32_t class = 0;
|
|
|
- int err = 0;
|
|
|
-
|
|
|
- /* caller guarantees that those three CTA_EXPECT_* exist */
|
|
|
- err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
|
|
|
- if (err < 0)
|
|
|
- return err;
|
|
|
- err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK, u3);
|
|
|
- if (err < 0)
|
|
|
- return err;
|
|
|
- err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER, u3);
|
|
|
- if (err < 0)
|
|
|
- return err;
|
|
|
-
|
|
|
- /* Look for master conntrack of this expectation */
|
|
|
- h = nf_conntrack_find_get(net, zone, &master_tuple);
|
|
|
- if (!h)
|
|
|
- return -ENOENT;
|
|
|
- ct = nf_ct_tuplehash_to_ctrack(h);
|
|
|
-
|
|
|
- /* Look for helper of this expectation */
|
|
|
- if (cda[CTA_EXPECT_HELP_NAME]) {
|
|
|
- const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
|
|
|
-
|
|
|
- helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
|
|
|
- nf_ct_protonum(ct));
|
|
|
- if (helper == NULL) {
|
|
|
-#ifdef CONFIG_MODULES
|
|
|
- if (request_module("nfct-helper-%s", helpname) < 0) {
|
|
|
- err = -EOPNOTSUPP;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- helper = __nf_conntrack_helper_find(helpname,
|
|
|
- nf_ct_l3num(ct),
|
|
|
- nf_ct_protonum(ct));
|
|
|
- if (helper) {
|
|
|
- err = -EAGAIN;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-#endif
|
|
|
- err = -EOPNOTSUPP;
|
|
|
- goto out;
|
|
|
- }
|
|
|
- }
|
|
|
+ int err;
|
|
|
|
|
|
if (cda[CTA_EXPECT_CLASS] && helper) {
|
|
|
class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS]));
|
|
|
- if (class > helper->expect_class_max) {
|
|
|
- err = -EINVAL;
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ if (class > helper->expect_class_max)
|
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
}
|
|
|
exp = nf_ct_expect_alloc(ct);
|
|
|
- if (!exp) {
|
|
|
- err = -ENOMEM;
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ if (!exp)
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
+
|
|
|
help = nfct_help(ct);
|
|
|
if (!help) {
|
|
|
if (!cda[CTA_EXPECT_TIMEOUT]) {
|
|
@@ -2854,21 +2857,89 @@ ctnetlink_create_expect(struct net *net, u16 zone,
|
|
|
exp->class = class;
|
|
|
exp->master = ct;
|
|
|
exp->helper = helper;
|
|
|
- memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple));
|
|
|
- memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3));
|
|
|
- exp->mask.src.u.all = mask.src.u.all;
|
|
|
+ exp->tuple = *tuple;
|
|
|
+ exp->mask.src.u3 = mask->src.u3;
|
|
|
+ exp->mask.src.u.all = mask->src.u.all;
|
|
|
|
|
|
if (cda[CTA_EXPECT_NAT]) {
|
|
|
err = ctnetlink_parse_expect_nat(cda[CTA_EXPECT_NAT],
|
|
|
- exp, u3);
|
|
|
+ exp, nf_ct_l3num(ct));
|
|
|
if (err < 0)
|
|
|
goto err_out;
|
|
|
}
|
|
|
- err = nf_ct_expect_related_report(exp, portid, report);
|
|
|
+ return exp;
|
|
|
err_out:
|
|
|
nf_ct_expect_put(exp);
|
|
|
-out:
|
|
|
- nf_ct_put(nf_ct_tuplehash_to_ctrack(h));
|
|
|
+ return ERR_PTR(err);
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+ctnetlink_create_expect(struct net *net, u16 zone,
|
|
|
+ const struct nlattr * const cda[],
|
|
|
+ u_int8_t u3, u32 portid, int report)
|
|
|
+{
|
|
|
+ struct nf_conntrack_tuple tuple, mask, master_tuple;
|
|
|
+ struct nf_conntrack_tuple_hash *h = NULL;
|
|
|
+ struct nf_conntrack_helper *helper = NULL;
|
|
|
+ struct nf_conntrack_expect *exp;
|
|
|
+ struct nf_conn *ct;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ /* caller guarantees that those three CTA_EXPECT_* exist */
|
|
|
+ err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK, u3);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER, u3);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ /* Look for master conntrack of this expectation */
|
|
|
+ h = nf_conntrack_find_get(net, zone, &master_tuple);
|
|
|
+ if (!h)
|
|
|
+ return -ENOENT;
|
|
|
+ ct = nf_ct_tuplehash_to_ctrack(h);
|
|
|
+
|
|
|
+ if (cda[CTA_EXPECT_HELP_NAME]) {
|
|
|
+ const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
|
|
|
+
|
|
|
+ helper = __nf_conntrack_helper_find(helpname, u3,
|
|
|
+ nf_ct_protonum(ct));
|
|
|
+ if (helper == NULL) {
|
|
|
+#ifdef CONFIG_MODULES
|
|
|
+ if (request_module("nfct-helper-%s", helpname) < 0) {
|
|
|
+ err = -EOPNOTSUPP;
|
|
|
+ goto err_ct;
|
|
|
+ }
|
|
|
+ helper = __nf_conntrack_helper_find(helpname, u3,
|
|
|
+ nf_ct_protonum(ct));
|
|
|
+ if (helper) {
|
|
|
+ err = -EAGAIN;
|
|
|
+ goto err_ct;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ err = -EOPNOTSUPP;
|
|
|
+ goto err_ct;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ exp = ctnetlink_alloc_expect(cda, ct, helper, &tuple, &mask);
|
|
|
+ if (IS_ERR(exp)) {
|
|
|
+ err = PTR_ERR(exp);
|
|
|
+ goto err_ct;
|
|
|
+ }
|
|
|
+
|
|
|
+ err = nf_ct_expect_related_report(exp, portid, report);
|
|
|
+ if (err < 0)
|
|
|
+ goto err_exp;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+err_exp:
|
|
|
+ nf_ct_expect_put(exp);
|
|
|
+err_ct:
|
|
|
+ nf_ct_put(ct);
|
|
|
return err;
|
|
|
}
|
|
|
|