]> Pileus Git - ~andy/linux/commitdiff
netfilter: nfnetlink_queue: allow to attach expectations to conntracks
authorPablo Neira Ayuso <pablo@netfilter.org>
Wed, 7 Aug 2013 16:13:20 +0000 (18:13 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 13 Aug 2013 14:32:10 +0000 (16:32 +0200)
This patch adds the capability to attach expectations via nfnetlink_queue.
This is required by conntrack helpers that trigger expectations based on
the first packet seen like the TFTP and the DHCPv6 user-space helpers.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/linux/netfilter.h
include/net/netfilter/nfnetlink_queue.h
include/uapi/linux/netfilter/nfnetlink_queue.h
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nfnetlink_queue_core.c
net/netfilter/nfnetlink_queue_ct.c

index 655d5d198d49acd8e0f85957b9da4bd2b075c908..e2cf786be22fafc2766bdfc8fde1ab71571f86c6 100644 (file)
@@ -325,6 +325,8 @@ struct nfq_ct_hook {
        size_t (*build_size)(const struct nf_conn *ct);
        int (*build)(struct sk_buff *skb, struct nf_conn *ct);
        int (*parse)(const struct nlattr *attr, struct nf_conn *ct);
+       int (*attach_expect)(const struct nlattr *attr, struct nf_conn *ct,
+                            u32 portid, u32 report);
 };
 extern struct nfq_ct_hook __rcu *nfq_ct_hook;
 
index 86267a529514e2f1ca0e181df54fe62f5a1e0863..aff88ba9139121445bfca2169e3f39b71f354fa6 100644 (file)
@@ -15,6 +15,8 @@ int nfqnl_ct_put(struct sk_buff *skb, struct nf_conn *ct,
                 enum ip_conntrack_info ctinfo);
 void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
                         enum ip_conntrack_info ctinfo, int diff);
+int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr,
+                       u32 portid, u32 report);
 #else
 inline struct nf_conn *
 nfqnl_ct_get(struct sk_buff *entskb, size_t *size, enum ip_conntrack_info *ctinfo)
@@ -39,5 +41,11 @@ inline void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
                                enum ip_conntrack_info ctinfo, int diff)
 {
 }
+
+inline int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr,
+                              u32 portid, u32 report)
+{
+       return 0;
+}
 #endif /* NF_CONNTRACK */
 #endif
index 3a9b92147339d14d871ba836e5b8840f6d5cce8c..0132bad79de7f6860120d13c6df2d508ad2d5d14 100644 (file)
@@ -46,6 +46,7 @@ enum nfqnl_attr_type {
        NFQA_CT_INFO,                   /* enum ip_conntrack_info */
        NFQA_CAP_LEN,                   /* __u32 length of captured packet */
        NFQA_SKB_INFO,                  /* __u32 skb meta information */
+       NFQA_EXP,                       /* nf_conntrack_netlink.h */
 
        __NFQA_MAX
 };
index 9aaa68bbbcdb9d5dad11316a8c58c99da5db2f1c..fa61fea63234d171d6ba8e32d61cc3e491be0634 100644 (file)
@@ -1987,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)
@@ -2127,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 */
 
@@ -2498,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,
index ec9de12aa488b7985e6ea6dd85614959ae3c4127..e8c9f3bb779cd6c108409911f348f73f5a1689f7 100644 (file)
@@ -859,6 +859,7 @@ static const struct nla_policy nfqa_verdict_policy[NFQA_MAX+1] = {
        [NFQA_MARK]             = { .type = NLA_U32 },
        [NFQA_PAYLOAD]          = { .type = NLA_UNSPEC },
        [NFQA_CT]               = { .type = NLA_UNSPEC },
+       [NFQA_EXP]              = { .type = NLA_UNSPEC },
 };
 
 static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = {
@@ -987,8 +988,14 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
        if (entry == NULL)
                return -ENOENT;
 
-       if (nfqa[NFQA_CT])
+       if (nfqa[NFQA_CT]) {
                ct = nfqnl_ct_parse(entry->skb, nfqa[NFQA_CT], &ctinfo);
+               if (ct && nfqa[NFQA_EXP]) {
+                       nfqnl_attach_expect(ct, nfqa[NFQA_EXP],
+                                           NETLINK_CB(skb).portid,
+                                           nlmsg_report(nlh));
+               }
+       }
 
        if (nfqa[NFQA_PAYLOAD]) {
                u16 payload_len = nla_len(nfqa[NFQA_PAYLOAD]);
index ab61d66bc0b9e53fb5c0b657d0d954f8ea16cf3b..be893039966d5b4be828b8b0418e86cb0282c383 100644 (file)
@@ -96,3 +96,18 @@ void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
        if ((ct->status & IPS_NAT_MASK) && diff)
                nfq_nat_ct->seq_adjust(skb, ct, ctinfo, diff);
 }
+
+int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr,
+                       u32 portid, u32 report)
+{
+       struct nfq_ct_hook *nfq_ct;
+
+       if (nf_ct_is_untracked(ct))
+               return 0;
+
+       nfq_ct = rcu_dereference(nfq_ct_hook);
+       if (nfq_ct == NULL)
+               return -EOPNOTSUPP;
+
+       return nfq_ct->attach_expect(attr, ct, portid, report);
+}