* [PATCH 0/4] We all need more expectations @ 2010-09-21 9:34 Pablo Neira Ayuso 2010-09-21 9:34 ` [PATCH 1/4] netfilter: nf_nat: better error handling of nf_ct_expect_related() in helpers Pablo Neira Ayuso ` (3 more replies) 0 siblings, 4 replies; 16+ messages in thread From: Pablo Neira Ayuso @ 2010-09-21 9:34 UTC (permalink / raw) To: netfilter-devel; +Cc: kaber Hi Patrick, The following patches are focuses on conntrack expectations. The first one is an improvement for the situation in which the expectation table is full for conntrack NAT helpers. Then, another quite simple to include a missing attribute validation. To conclude, a couple of patches oriented to support user-space conntrack helpers. Hope that you like them. --- Pablo Neira Ayuso (4): netfilter: nf_nat: better error handling of nf_ct_expect_related() in helpers netfilter: ctnetlink: missing validation of CTA_EXPECT_ZONE attribute netfilter: ctnetlink: allow to specify the expectation flags netfilter: ctnetlink: add support for user-space expectation helpers include/linux/netfilter/nf_conntrack_common.h | 5 ++ include/linux/netfilter/nfnetlink_conntrack.h | 1 include/net/netfilter/nf_conntrack_expect.h | 3 - net/ipv4/netfilter/nf_nat_amanda.c | 9 ++++ net/ipv4/netfilter/nf_nat_ftp.c | 9 ++++ net/ipv4/netfilter/nf_nat_h323.c | 53 ++++++++++++++++++++++--- net/ipv4/netfilter/nf_nat_irc.c | 9 ++++ net/ipv4/netfilter/nf_nat_sip.c | 27 +++++++++++-- net/netfilter/nf_conntrack_expect.c | 40 ++++++++++++------- net/netfilter/nf_conntrack_netlink.c | 38 ++++++++++++------ 10 files changed, 149 insertions(+), 45 deletions(-) ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/4] netfilter: nf_nat: better error handling of nf_ct_expect_related() in helpers 2010-09-21 9:34 [PATCH 0/4] We all need more expectations Pablo Neira Ayuso @ 2010-09-21 9:34 ` Pablo Neira Ayuso 2010-09-21 15:07 ` Patrick McHardy 2010-09-22 6:35 ` Patrick McHardy 2010-09-21 9:34 ` [PATCH 2/4] netfilter: ctnetlink: missing validation of CTA_EXPECT_ZONE attribute Pablo Neira Ayuso ` (2 subsequent siblings) 3 siblings, 2 replies; 16+ messages in thread From: Pablo Neira Ayuso @ 2010-09-21 9:34 UTC (permalink / raw) To: netfilter-devel; +Cc: kaber This patch improves the situation in which the expectation table is full for conntrack NAT helpers. Basically, we give up if we don't find a place in the table instead of looping over nf_ct_expect_related() with a different port (we should only do this if it returns -EBUSY, for -EMFILE or -ESHUTDOWN I think that it's better to skip this). Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- net/ipv4/netfilter/nf_nat_amanda.c | 9 +++++- net/ipv4/netfilter/nf_nat_ftp.c | 9 +++++- net/ipv4/netfilter/nf_nat_h323.c | 53 +++++++++++++++++++++++++++++++----- net/ipv4/netfilter/nf_nat_irc.c | 9 +++++- net/ipv4/netfilter/nf_nat_sip.c | 27 ++++++++++++++++-- 5 files changed, 93 insertions(+), 14 deletions(-) diff --git a/net/ipv4/netfilter/nf_nat_amanda.c b/net/ipv4/netfilter/nf_nat_amanda.c index c31b876..0f23b3f 100644 --- a/net/ipv4/netfilter/nf_nat_amanda.c +++ b/net/ipv4/netfilter/nf_nat_amanda.c @@ -44,9 +44,16 @@ static unsigned int help(struct sk_buff *skb, /* Try to get same port: if not, try to change it. */ for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { + int ret; + exp->tuple.dst.u.tcp.port = htons(port); - if (nf_ct_expect_related(exp) == 0) + ret = nf_ct_expect_related(exp); + if (ret == 0) + break; + else if (ret != -EBUSY) { + port = 0; break; + } } if (port == 0) diff --git a/net/ipv4/netfilter/nf_nat_ftp.c b/net/ipv4/netfilter/nf_nat_ftp.c index 86e0e84..dc73abb 100644 --- a/net/ipv4/netfilter/nf_nat_ftp.c +++ b/net/ipv4/netfilter/nf_nat_ftp.c @@ -79,9 +79,16 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb, /* Try to get same port: if not, try to change it. */ for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { + int ret; + exp->tuple.dst.u.tcp.port = htons(port); - if (nf_ct_expect_related(exp) == 0) + ret = nf_ct_expect_related(exp); + if (ret == 0) + break; + else if (ret != -EBUSY) { + port = 0; break; + } } if (port == 0) diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c index 5045196..790f316 100644 --- a/net/ipv4/netfilter/nf_nat_h323.c +++ b/net/ipv4/netfilter/nf_nat_h323.c @@ -222,13 +222,24 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct, /* Try to get a pair of ports. */ for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port); nated_port != 0; nated_port += 2) { + int ret; + rtp_exp->tuple.dst.u.udp.port = htons(nated_port); - if (nf_ct_expect_related(rtp_exp) == 0) { + ret = nf_ct_expect_related(rtp_exp); + if (ret == 0) { rtcp_exp->tuple.dst.u.udp.port = htons(nated_port + 1); - if (nf_ct_expect_related(rtcp_exp) == 0) + ret = nf_ct_expect_related(rtcp_exp); + if (ret == 0) + break; + else if (ret != -EBUSY) { + nf_ct_unexpect_related(rtp_exp); + nated_port = 0; break; - nf_ct_unexpect_related(rtp_exp); + } + } else if (ret != -EBUSY) { + nated_port = 0; + break; } } @@ -284,9 +295,16 @@ static int nat_t120(struct sk_buff *skb, struct nf_conn *ct, /* Try to get same port: if not, try to change it. */ for (; nated_port != 0; nated_port++) { + int ret; + exp->tuple.dst.u.tcp.port = htons(nated_port); - if (nf_ct_expect_related(exp) == 0) + ret = nf_ct_expect_related(exp); + if (ret == 0) + break; + else if (ret != -EBUSY) { + nated_port = 0; break; + } } if (nated_port == 0) { /* No port available */ @@ -334,9 +352,16 @@ static int nat_h245(struct sk_buff *skb, struct nf_conn *ct, /* Try to get same port: if not, try to change it. */ for (; nated_port != 0; nated_port++) { + int ret; + exp->tuple.dst.u.tcp.port = htons(nated_port); - if (nf_ct_expect_related(exp) == 0) + ret = nf_ct_expect_related(exp); + if (ret == 0) break; + else if (ret != -EBUSY) { + nated_port = 0; + break; + } } if (nated_port == 0) { /* No port available */ @@ -418,9 +443,16 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct, /* Try to get same port: if not, try to change it. */ for (; nated_port != 0; nated_port++) { + int ret; + exp->tuple.dst.u.tcp.port = htons(nated_port); - if (nf_ct_expect_related(exp) == 0) + ret = nf_ct_expect_related(exp); + if (ret == 0) + break; + else if (ret != -EBUSY) { + nated_port = 0; break; + } } if (nated_port == 0) { /* No port available */ @@ -500,9 +532,16 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct, /* Try to get same port: if not, try to change it. */ for (nated_port = ntohs(port); nated_port != 0; nated_port++) { + int ret; + exp->tuple.dst.u.tcp.port = htons(nated_port); - if (nf_ct_expect_related(exp) == 0) + ret = nf_ct_expect_related(exp); + if (ret == 0) break; + else if (ret != -EBUSY) { + nated_port = 0; + break; + } } if (nated_port == 0) { /* No port available */ diff --git a/net/ipv4/netfilter/nf_nat_irc.c b/net/ipv4/netfilter/nf_nat_irc.c index ea83a88..535e1a8 100644 --- a/net/ipv4/netfilter/nf_nat_irc.c +++ b/net/ipv4/netfilter/nf_nat_irc.c @@ -45,9 +45,16 @@ static unsigned int help(struct sk_buff *skb, /* Try to get same port: if not, try to change it. */ for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { + int ret; + exp->tuple.dst.u.tcp.port = htons(port); - if (nf_ct_expect_related(exp) == 0) + ret = nf_ct_expect_related(exp); + if (ret == 0) + break; + else if (ret != -EBUSY) { + port = 0; break; + } } if (port == 0) diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 11b538d..e40cf78 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -307,9 +307,16 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int dataoff, exp->expectfn = ip_nat_sip_expected; for (; port != 0; port++) { + int ret; + exp->tuple.dst.u.udp.port = htons(port); - if (nf_ct_expect_related(exp) == 0) + ret = nf_ct_expect_related(exp); + if (ret == 0) + break; + else if (ret != -EBUSY) { + port = 0; break; + } } if (port == 0) @@ -480,13 +487,25 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff, /* Try to get same pair of ports: if not, try to change them. */ for (port = ntohs(rtp_exp->tuple.dst.u.udp.port); port != 0; port += 2) { + int ret; + rtp_exp->tuple.dst.u.udp.port = htons(port); - if (nf_ct_expect_related(rtp_exp) != 0) + ret = nf_ct_expect_related(rtp_exp); + if (ret == -EBUSY) continue; + else if (ret < 0) { + port = 0; + break; + } rtcp_exp->tuple.dst.u.udp.port = htons(port + 1); - if (nf_ct_expect_related(rtcp_exp) == 0) + ret = nf_ct_expect_related(rtcp_exp); + if (ret == 0) break; - nf_ct_unexpect_related(rtp_exp); + else if (ret != -EBUSY) { + nf_ct_unexpect_related(rtp_exp); + port = 0; + break; + } } if (port == 0) ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 1/4] netfilter: nf_nat: better error handling of nf_ct_expect_related() in helpers 2010-09-21 9:34 ` [PATCH 1/4] netfilter: nf_nat: better error handling of nf_ct_expect_related() in helpers Pablo Neira Ayuso @ 2010-09-21 15:07 ` Patrick McHardy 2010-09-22 6:35 ` Patrick McHardy 1 sibling, 0 replies; 16+ messages in thread From: Patrick McHardy @ 2010-09-21 15:07 UTC (permalink / raw) To: Pablo Neira Ayuso; +Cc: netfilter-devel Am 21.09.2010 11:34, schrieb Pablo Neira Ayuso: > This patch improves the situation in which the expectation table is > full for conntrack NAT helpers. Basically, we give up if we don't > find a place in the table instead of looping over nf_ct_expect_related() > with a different port (we should only do this if it returns -EBUSY, for > -EMFILE or -ESHUTDOWN I think that it's better to skip this). Indeed, this makes a lot more sense than our current behaviour. ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/4] netfilter: nf_nat: better error handling of nf_ct_expect_related() in helpers 2010-09-21 9:34 ` [PATCH 1/4] netfilter: nf_nat: better error handling of nf_ct_expect_related() in helpers Pablo Neira Ayuso 2010-09-21 15:07 ` Patrick McHardy @ 2010-09-22 6:35 ` Patrick McHardy 1 sibling, 0 replies; 16+ messages in thread From: Patrick McHardy @ 2010-09-22 6:35 UTC (permalink / raw) To: Pablo Neira Ayuso; +Cc: netfilter-devel Am 21.09.2010 11:34, schrieb Pablo Neira Ayuso: > This patch improves the situation in which the expectation table is > full for conntrack NAT helpers. Basically, we give up if we don't > find a place in the table instead of looping over nf_ct_expect_related() > with a different port (we should only do this if it returns -EBUSY, for > -EMFILE or -ESHUTDOWN I think that it's better to skip this). Applied, thanks Pablo. ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 2/4] netfilter: ctnetlink: missing validation of CTA_EXPECT_ZONE attribute 2010-09-21 9:34 [PATCH 0/4] We all need more expectations Pablo Neira Ayuso 2010-09-21 9:34 ` [PATCH 1/4] netfilter: nf_nat: better error handling of nf_ct_expect_related() in helpers Pablo Neira Ayuso @ 2010-09-21 9:34 ` Pablo Neira Ayuso 2010-09-22 6:36 ` Patrick McHardy 2010-09-21 9:35 ` [PATCH 3/4] netfilter: ctnetlink: allow to specify the expectation flags Pablo Neira Ayuso 2010-09-21 9:35 ` [PATCH 4/4] netfilter: ctnetlink: add support for user-space expectation helpers Pablo Neira Ayuso 3 siblings, 1 reply; 16+ messages in thread From: Pablo Neira Ayuso @ 2010-09-21 9:34 UTC (permalink / raw) To: netfilter-devel; +Cc: kaber This patch adds the missing validation of the CTA_EXPECT_ZONE attribute in the ctnetlink code. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- net/netfilter/nf_conntrack_netlink.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 5bae1cd..37533a3 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1733,6 +1733,7 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { [CTA_EXPECT_TIMEOUT] = { .type = NLA_U32 }, [CTA_EXPECT_ID] = { .type = NLA_U32 }, [CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING }, + [CTA_EXPECT_ZONE] = { .type = NLA_U16 }, }; static int ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 2/4] netfilter: ctnetlink: missing validation of CTA_EXPECT_ZONE attribute 2010-09-21 9:34 ` [PATCH 2/4] netfilter: ctnetlink: missing validation of CTA_EXPECT_ZONE attribute Pablo Neira Ayuso @ 2010-09-22 6:36 ` Patrick McHardy 0 siblings, 0 replies; 16+ messages in thread From: Patrick McHardy @ 2010-09-22 6:36 UTC (permalink / raw) To: Pablo Neira Ayuso; +Cc: netfilter-devel Am 21.09.2010 11:34, schrieb Pablo Neira Ayuso: > This patch adds the missing validation of the CTA_EXPECT_ZONE > attribute in the ctnetlink code. Applied, thanks. ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 3/4] netfilter: ctnetlink: allow to specify the expectation flags 2010-09-21 9:34 [PATCH 0/4] We all need more expectations Pablo Neira Ayuso 2010-09-21 9:34 ` [PATCH 1/4] netfilter: nf_nat: better error handling of nf_ct_expect_related() in helpers Pablo Neira Ayuso 2010-09-21 9:34 ` [PATCH 2/4] netfilter: ctnetlink: missing validation of CTA_EXPECT_ZONE attribute Pablo Neira Ayuso @ 2010-09-21 9:35 ` Pablo Neira Ayuso 2010-09-21 15:18 ` Patrick McHardy 2010-09-21 9:35 ` [PATCH 4/4] netfilter: ctnetlink: add support for user-space expectation helpers Pablo Neira Ayuso 3 siblings, 1 reply; 16+ messages in thread From: Pablo Neira Ayuso @ 2010-09-21 9:35 UTC (permalink / raw) To: netfilter-devel; +Cc: kaber With this patch, you can specify the expectation flags for user-space created expectations. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- include/linux/netfilter/nf_conntrack_common.h | 4 ++++ include/linux/netfilter/nfnetlink_conntrack.h | 1 + include/net/netfilter/nf_conntrack_expect.h | 3 --- net/netfilter/nf_conntrack_netlink.c | 7 ++++++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h index 1afd18c..fdc50ca 100644 --- a/include/linux/netfilter/nf_conntrack_common.h +++ b/include/linux/netfilter/nf_conntrack_common.h @@ -100,6 +100,10 @@ enum ip_conntrack_expect_events { IPEXP_NEW, /* new expectation */ }; +/* expectation flags */ +#define NF_CT_EXPECT_PERMANENT 0x1 +#define NF_CT_EXPECT_INACTIVE 0x2 + #ifdef __KERNEL__ struct ip_conntrack_stat { unsigned int searched; diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index 9ed534c..455f0ce 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h @@ -161,6 +161,7 @@ enum ctattr_expect { CTA_EXPECT_ID, CTA_EXPECT_HELP_NAME, CTA_EXPECT_ZONE, + CTA_EXPECT_FLAGS, __CTA_EXPECT_MAX }; #define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1) diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 11e8150..96bb42a 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -67,9 +67,6 @@ struct nf_conntrack_expect_policy { #define NF_CT_EXPECT_CLASS_DEFAULT 0 -#define NF_CT_EXPECT_PERMANENT 0x1 -#define NF_CT_EXPECT_INACTIVE 0x2 - int nf_conntrack_expect_init(struct net *net); void nf_conntrack_expect_fini(struct net *net); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 37533a3..82363f0 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1734,6 +1734,7 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { [CTA_EXPECT_ID] = { .type = NLA_U32 }, [CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING }, [CTA_EXPECT_ZONE] = { .type = NLA_U16 }, + [CTA_EXPECT_FLAGS] = { .type = NLA_U32 }, }; static int @@ -1933,9 +1934,13 @@ ctnetlink_create_expect(struct net *net, u16 zone, goto out; } + if (cda[CTA_EXPECT_FLAGS]) + exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS])); + else + exp->flags = 0; + exp->class = 0; exp->expectfn = NULL; - exp->flags = 0; exp->master = ct; exp->helper = NULL; memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple)); ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 3/4] netfilter: ctnetlink: allow to specify the expectation flags 2010-09-21 9:35 ` [PATCH 3/4] netfilter: ctnetlink: allow to specify the expectation flags Pablo Neira Ayuso @ 2010-09-21 15:18 ` Patrick McHardy 2010-09-21 22:38 ` Pablo Neira Ayuso 0 siblings, 1 reply; 16+ messages in thread From: Patrick McHardy @ 2010-09-21 15:18 UTC (permalink / raw) To: Pablo Neira Ayuso; +Cc: netfilter-devel Am 21.09.2010 11:35, schrieb Pablo Neira Ayuso: > With this patch, you can specify the expectation flags for user-space > created expectations. We don't seem to be dumping the flags to userspace. I think this should be added for consistency. ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 3/4] netfilter: ctnetlink: allow to specify the expectation flags 2010-09-21 15:18 ` Patrick McHardy @ 2010-09-21 22:38 ` Pablo Neira Ayuso 2010-09-22 6:37 ` Patrick McHardy 0 siblings, 1 reply; 16+ messages in thread From: Pablo Neira Ayuso @ 2010-09-21 22:38 UTC (permalink / raw) To: Patrick McHardy; +Cc: netfilter-devel [-- Attachment #1: Type: text/plain, Size: 366 bytes --] On 21/09/10 17:18, Patrick McHardy wrote: > Am 21.09.2010 11:35, schrieb Pablo Neira Ayuso: >> With this patch, you can specify the expectation flags for user-space >> created expectations. > > We don't seem to be dumping the flags to userspace. I think this > should be added for consistency. I have included this in a new version of the patch, find it attached. [-- Attachment #2: exp-flags.patch --] [-- Type: text/x-patch, Size: 3198 bytes --] netfilter: ctnetlink: allow to specify the expectation flags With this patch, you can specify the expectation flags for user-space created expectations. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- include/linux/netfilter/nf_conntrack_common.h | 4 ++++ include/linux/netfilter/nfnetlink_conntrack.h | 1 + include/net/netfilter/nf_conntrack_expect.h | 3 --- net/netfilter/nf_conntrack_netlink.c | 8 +++++++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h index 1afd18c..fdc50ca 100644 --- a/include/linux/netfilter/nf_conntrack_common.h +++ b/include/linux/netfilter/nf_conntrack_common.h @@ -100,6 +100,10 @@ enum ip_conntrack_expect_events { IPEXP_NEW, /* new expectation */ }; +/* expectation flags */ +#define NF_CT_EXPECT_PERMANENT 0x1 +#define NF_CT_EXPECT_INACTIVE 0x2 + #ifdef __KERNEL__ struct ip_conntrack_stat { unsigned int searched; diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index 9ed534c..455f0ce 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h @@ -161,6 +161,7 @@ enum ctattr_expect { CTA_EXPECT_ID, CTA_EXPECT_HELP_NAME, CTA_EXPECT_ZONE, + CTA_EXPECT_FLAGS, __CTA_EXPECT_MAX }; #define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1) diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 11e8150..96bb42a 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -67,9 +67,6 @@ struct nf_conntrack_expect_policy { #define NF_CT_EXPECT_CLASS_DEFAULT 0 -#define NF_CT_EXPECT_PERMANENT 0x1 -#define NF_CT_EXPECT_INACTIVE 0x2 - int nf_conntrack_expect_init(struct net *net); void nf_conntrack_expect_fini(struct net *net); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 37533a3..0804e0e 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1577,6 +1577,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)); NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)); + NLA_PUT_BE32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)); helper = rcu_dereference(nfct_help(master)->helper); if (helper) NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name); @@ -1734,6 +1735,7 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { [CTA_EXPECT_ID] = { .type = NLA_U32 }, [CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING }, [CTA_EXPECT_ZONE] = { .type = NLA_U16 }, + [CTA_EXPECT_FLAGS] = { .type = NLA_U32 }, }; static int @@ -1933,9 +1935,13 @@ ctnetlink_create_expect(struct net *net, u16 zone, goto out; } + if (cda[CTA_EXPECT_FLAGS]) + exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS])); + else + exp->flags = 0; + exp->class = 0; exp->expectfn = NULL; - exp->flags = 0; exp->master = ct; exp->helper = NULL; memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple)); ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 3/4] netfilter: ctnetlink: allow to specify the expectation flags 2010-09-21 22:38 ` Pablo Neira Ayuso @ 2010-09-22 6:37 ` Patrick McHardy 0 siblings, 0 replies; 16+ messages in thread From: Patrick McHardy @ 2010-09-22 6:37 UTC (permalink / raw) To: Pablo Neira Ayuso; +Cc: netfilter-devel Am 22.09.2010 00:38, schrieb Pablo Neira Ayuso: > On 21/09/10 17:18, Patrick McHardy wrote: >> Am 21.09.2010 11:35, schrieb Pablo Neira Ayuso: >>> With this patch, you can specify the expectation flags for user-space >>> created expectations. >> >> We don't seem to be dumping the flags to userspace. I think this >> should be added for consistency. > > I have included this in a new version of the patch, find it attached. Applied, thanks. ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 4/4] netfilter: ctnetlink: add support for user-space expectation helpers 2010-09-21 9:34 [PATCH 0/4] We all need more expectations Pablo Neira Ayuso ` (2 preceding siblings ...) 2010-09-21 9:35 ` [PATCH 3/4] netfilter: ctnetlink: allow to specify the expectation flags Pablo Neira Ayuso @ 2010-09-21 9:35 ` Pablo Neira Ayuso 2010-09-21 15:20 ` Patrick McHardy 2010-09-28 19:08 ` Patrick McHardy 3 siblings, 2 replies; 16+ messages in thread From: Pablo Neira Ayuso @ 2010-09-21 9:35 UTC (permalink / raw) To: netfilter-devel; +Cc: kaber This patch adds the basic infrastructure to support user-space expectation helpers via ctnetlink and the netfilter queuing infrastructure NFQUEUE. Basically, this patch: * adds NF_CT_EXPECT_USERSPACE flag to identify user-space created expectations. I have also added a sanity check in __nf_ct_expect_check() to avoid that kernel-space helpers may create an expectation if the master conntrack has no helper assigned. * adds some branches to check if the master conntrack helper exists, otherwise we skip the code that refers to kernel-space helper such as the local expectation list and the expectation policy. * allows to set the timeout for user-space expectations with no helper assigned. This patch also modifies ctnetlink to skip including the helper name in the Netlink messages if no kernel-space helper is set (since no user-space expectation has not kernel-space kernel assigned). You can access an example user-space FTP conntrack helper at: http://people.netfilter.org/pablo/nf-ftp-helper-userspace-POC.tar.bz Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- include/linux/netfilter/nf_conntrack_common.h | 1 + net/netfilter/nf_conntrack_expect.c | 40 ++++++++++++++++--------- net/netfilter/nf_conntrack_netlink.c | 38 ++++++++++++++---------- 3 files changed, 48 insertions(+), 31 deletions(-) diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h index fdc50ca..23a1a08 100644 --- a/include/linux/netfilter/nf_conntrack_common.h +++ b/include/linux/netfilter/nf_conntrack_common.h @@ -103,6 +103,7 @@ enum ip_conntrack_expect_events { /* expectation flags */ #define NF_CT_EXPECT_PERMANENT 0x1 #define NF_CT_EXPECT_INACTIVE 0x2 +#define NF_CT_EXPECT_USERSPACE 0x4 #ifdef __KERNEL__ struct ip_conntrack_stat { diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index acb29cc..b53e817 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -44,14 +44,15 @@ void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) struct nf_conn_help *master_help = nfct_help(exp->master); struct net *net = nf_ct_exp_net(exp); - NF_CT_ASSERT(master_help); NF_CT_ASSERT(!timer_pending(&exp->timeout)); hlist_del_rcu(&exp->hnode); net->ct.expect_count--; - hlist_del(&exp->lnode); - master_help->expecting[exp->class]--; + if (master_help) { + hlist_del(&exp->lnode); + master_help->expecting[exp->class]--; + } nf_ct_expect_put(exp); NF_CT_STAT_INC(net, expect_delete); @@ -320,16 +321,20 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp) atomic_inc(&exp->use); - hlist_add_head(&exp->lnode, &master_help->expectations); - master_help->expecting[exp->class]++; + if (master_help) { + hlist_add_head(&exp->lnode, &master_help->expectations); + master_help->expecting[exp->class]++; + } hlist_add_head_rcu(&exp->hnode, &net->ct.expect_hash[h]); net->ct.expect_count++; setup_timer(&exp->timeout, nf_ct_expectation_timed_out, (unsigned long)exp); - p = &master_help->helper->expect_policy[exp->class]; - exp->timeout.expires = jiffies + p->timeout * HZ; + if (master_help) { + p = &master_help->helper->expect_policy[exp->class]; + exp->timeout.expires = jiffies + p->timeout * HZ; + } add_timer(&exp->timeout); atomic_inc(&exp->use); @@ -380,7 +385,9 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) unsigned int h; int ret = 1; - if (!master_help->helper) { + /* Don't allow expectations created from kernel-space with no helper */ + if (!(expect->flags & NF_CT_EXPECT_USERSPACE) && + (!master_help || (master_help && !master_help->helper))) { ret = -ESHUTDOWN; goto out; } @@ -398,13 +405,16 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) } } /* Will be over limit? */ - p = &master_help->helper->expect_policy[expect->class]; - if (p->max_expected && - master_help->expecting[expect->class] >= p->max_expected) { - evict_oldest_expect(master, expect); - if (master_help->expecting[expect->class] >= p->max_expected) { - ret = -EMFILE; - goto out; + if (master_help) { + p = &master_help->helper->expect_policy[expect->class]; + if (p->max_expected && + master_help->expecting[expect->class] >= p->max_expected) { + evict_oldest_expect(master, expect); + if (master_help->expecting[expect->class] + >= p->max_expected) { + ret = -EMFILE; + goto out; + } } } diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 82363f0..cddf4b6 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1560,8 +1560,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, const struct nf_conntrack_expect *exp) { struct nf_conn *master = exp->master; - struct nf_conntrack_helper *helper; long timeout = (exp->timeout.expires - jiffies) / HZ; + struct nf_conn_help *help; if (timeout < 0) timeout = 0; @@ -1577,9 +1577,14 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)); NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)); - helper = rcu_dereference(nfct_help(master)->helper); - if (helper) - NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name); + help = nfct_help(master); + if (help) { + struct nf_conntrack_helper *helper; + + helper = rcu_dereference(help->helper); + if (helper) + NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name); + } return 0; @@ -1920,24 +1925,25 @@ ctnetlink_create_expect(struct net *net, u16 zone, if (!h) return -ENOENT; ct = nf_ct_tuplehash_to_ctrack(h); - help = nfct_help(ct); - - if (!help || !help->helper) { - /* such conntrack hasn't got any helper, abort */ - err = -EOPNOTSUPP; - goto out; - } - exp = nf_ct_expect_alloc(ct); if (!exp) { err = -ENOMEM; goto out; } - - if (cda[CTA_EXPECT_FLAGS]) + help = nfct_help(ct); + if (!help) { + if (!cda[CTA_EXPECT_TIMEOUT]) { + err = -EINVAL; + goto out; + } + exp->timeout.expires = + jiffies + ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ; + } + if (cda[CTA_EXPECT_FLAGS]) { exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS])); - else - exp->flags = 0; + exp->flags |= NF_CT_EXPECT_USERSPACE; + } else + exp->flags = NF_CT_EXPECT_USERSPACE; exp->class = 0; exp->expectfn = NULL; ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 4/4] netfilter: ctnetlink: add support for user-space expectation helpers 2010-09-21 9:35 ` [PATCH 4/4] netfilter: ctnetlink: add support for user-space expectation helpers Pablo Neira Ayuso @ 2010-09-21 15:20 ` Patrick McHardy 2010-09-21 22:38 ` Pablo Neira Ayuso 2010-09-28 19:08 ` Patrick McHardy 1 sibling, 1 reply; 16+ messages in thread From: Patrick McHardy @ 2010-09-21 15:20 UTC (permalink / raw) To: Pablo Neira Ayuso; +Cc: netfilter-devel Am 21.09.2010 11:35, schrieb Pablo Neira Ayuso: > This patch adds the basic infrastructure to support user-space > expectation helpers via ctnetlink and the netfilter queuing > infrastructure NFQUEUE. Basically, this patch: > > * adds NF_CT_EXPECT_USERSPACE flag to identify user-space > created expectations. I have also added a sanity check in > __nf_ct_expect_check() to avoid that kernel-space helpers > may create an expectation if the master conntrack has no > helper assigned. > * adds some branches to check if the master conntrack helper > exists, otherwise we skip the code that refers to kernel-space > helper such as the local expectation list and the expectation > policy. > * allows to set the timeout for user-space expectations with > no helper assigned. > > This patch also modifies ctnetlink to skip including the helper > name in the Netlink messages if no kernel-space helper is set > (since no user-space expectation has not kernel-space kernel > assigned). My main question is - what will be cleaning up these expectations on module unload? Currently expectations are cleaned up on unload of the corresponding helper module, which obviously doesn't happen in this case. ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 4/4] netfilter: ctnetlink: add support for user-space expectation helpers 2010-09-21 15:20 ` Patrick McHardy @ 2010-09-21 22:38 ` Pablo Neira Ayuso 2010-09-22 6:45 ` Patrick McHardy 0 siblings, 1 reply; 16+ messages in thread From: Pablo Neira Ayuso @ 2010-09-21 22:38 UTC (permalink / raw) To: Patrick McHardy; +Cc: netfilter-devel [-- Attachment #1: Type: text/plain, Size: 1430 bytes --] On 21/09/10 17:20, Patrick McHardy wrote: > Am 21.09.2010 11:35, schrieb Pablo Neira Ayuso: >> This patch adds the basic infrastructure to support user-space >> expectation helpers via ctnetlink and the netfilter queuing >> infrastructure NFQUEUE. Basically, this patch: >> >> * adds NF_CT_EXPECT_USERSPACE flag to identify user-space >> created expectations. I have also added a sanity check in >> __nf_ct_expect_check() to avoid that kernel-space helpers >> may create an expectation if the master conntrack has no >> helper assigned. >> * adds some branches to check if the master conntrack helper >> exists, otherwise we skip the code that refers to kernel-space >> helper such as the local expectation list and the expectation >> policy. >> * allows to set the timeout for user-space expectations with >> no helper assigned. >> >> This patch also modifies ctnetlink to skip including the helper >> name in the Netlink messages if no kernel-space helper is set >> (since no user-space expectation has not kernel-space kernel >> assigned). > > My main question is - what will be cleaning up these expectations > on module unload? Currently expectations are cleaned up on unload > of the corresponding helper module, which obviously doesn't > happen in this case. Indeed. I have reworked the patch to add the nf_ct_userspace_expect_list that is used to delete all the user-space created expectations if ctnetlink is unloaded. [-- Attachment #2: exp.patch --] [-- Type: text/x-patch, Size: 8738 bytes --] netfilter: ctnetlink: add support for user-space expectation helpers This patch adds the basic infrastructure to support user-space expectation helpers via ctnetlink and the netfilter queuing infrastructure NFQUEUE. Basically, this patch: * adds NF_CT_EXPECT_USERSPACE flag to identify user-space created expectations. I have also added a sanity check in __nf_ct_expect_check() to avoid that kernel-space helpers may create an expectation if the master conntrack has no helper assigned. * adds some branches to check if the master conntrack helper exists, otherwise we skip the code that refers to kernel-space helper such as the local expectation list and the expectation policy. * allows to set the timeout for user-space expectations with no helper assigned. * a list of expectations created from user-space that depends on ctnetlink (if this module is removed, they are deleted). This patch also modifies ctnetlink to skip including the helper name in the Netlink messages if no kernel-space helper is set (since no user-space expectation has not kernel-space kernel assigned). You can access an example user-space FTP conntrack helper at: http://people.netfilter.org/pablo/nf-ftp-helper-userspace-POC.tar.bz Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- include/linux/netfilter/nf_conntrack_common.h | 1 include/net/netfilter/nf_conntrack_expect.h | 1 net/netfilter/nf_conntrack_expect.c | 61 +++++++++++++++++++------ net/netfilter/nf_conntrack_netlink.c | 39 +++++++++------- 4 files changed, 72 insertions(+), 30 deletions(-) diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h index fdc50ca..23a1a08 100644 --- a/include/linux/netfilter/nf_conntrack_common.h +++ b/include/linux/netfilter/nf_conntrack_common.h @@ -103,6 +103,7 @@ enum ip_conntrack_expect_events { /* expectation flags */ #define NF_CT_EXPECT_PERMANENT 0x1 #define NF_CT_EXPECT_INACTIVE 0x2 +#define NF_CT_EXPECT_USERSPACE 0x4 #ifdef __KERNEL__ struct ip_conntrack_stat { diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 96bb42a..416b838 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -85,6 +85,7 @@ nf_ct_find_expectation(struct net *net, u16 zone, void nf_ct_unlink_expect(struct nf_conntrack_expect *exp); void nf_ct_remove_expectations(struct nf_conn *ct); void nf_ct_unexpect_related(struct nf_conntrack_expect *exp); +void nf_ct_remove_userspace_expectations(void); /* Allocate space for an expectation: this is mandatory before calling nf_ct_expect_related. You will have to call put afterwards. */ diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index acb29cc..361a8ba 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -38,20 +38,26 @@ static int nf_ct_expect_hash_rnd_initted __read_mostly; static struct kmem_cache *nf_ct_expect_cachep __read_mostly; +static HLIST_HEAD(nf_ct_userspace_expect_list); +static int nf_ct_userspace_expect_list_counter; + /* nf_conntrack_expect helper functions */ void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) { struct nf_conn_help *master_help = nfct_help(exp->master); struct net *net = nf_ct_exp_net(exp); - NF_CT_ASSERT(master_help); NF_CT_ASSERT(!timer_pending(&exp->timeout)); hlist_del_rcu(&exp->hnode); net->ct.expect_count--; hlist_del(&exp->lnode); - master_help->expecting[exp->class]--; + if (exp->flags & NF_CT_EXPECT_USERSPACE) + nf_ct_userspace_expect_list_counter--; + else + master_help->expecting[exp->class]--; + nf_ct_expect_put(exp); NF_CT_STAT_INC(net, expect_delete); @@ -320,16 +326,23 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp) atomic_inc(&exp->use); - hlist_add_head(&exp->lnode, &master_help->expectations); - master_help->expecting[exp->class]++; + if (master_help) { + hlist_add_head(&exp->lnode, &master_help->expectations); + master_help->expecting[exp->class]++; + } else if (exp->flags & NF_CT_EXPECT_USERSPACE) { + hlist_add_head(&exp->lnode, &nf_ct_userspace_expect_list); + nf_ct_userspace_expect_list_counter++; + } hlist_add_head_rcu(&exp->hnode, &net->ct.expect_hash[h]); net->ct.expect_count++; setup_timer(&exp->timeout, nf_ct_expectation_timed_out, (unsigned long)exp); - p = &master_help->helper->expect_policy[exp->class]; - exp->timeout.expires = jiffies + p->timeout * HZ; + if (master_help) { + p = &master_help->helper->expect_policy[exp->class]; + exp->timeout.expires = jiffies + p->timeout * HZ; + } add_timer(&exp->timeout); atomic_inc(&exp->use); @@ -380,7 +393,9 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) unsigned int h; int ret = 1; - if (!master_help->helper) { + /* Don't allow expectations created from kernel-space with no helper */ + if (!(expect->flags & NF_CT_EXPECT_USERSPACE) && + (!master_help || (master_help && !master_help->helper))) { ret = -ESHUTDOWN; goto out; } @@ -398,13 +413,16 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) } } /* Will be over limit? */ - p = &master_help->helper->expect_policy[expect->class]; - if (p->max_expected && - master_help->expecting[expect->class] >= p->max_expected) { - evict_oldest_expect(master, expect); - if (master_help->expecting[expect->class] >= p->max_expected) { - ret = -EMFILE; - goto out; + if (master_help) { + p = &master_help->helper->expect_policy[expect->class]; + if (p->max_expected && + master_help->expecting[expect->class] >= p->max_expected) { + evict_oldest_expect(master, expect); + if (master_help->expecting[expect->class] + >= p->max_expected) { + ret = -EMFILE; + goto out; + } } } @@ -439,6 +457,21 @@ out: } EXPORT_SYMBOL_GPL(nf_ct_expect_related_report); +void nf_ct_remove_userspace_expectations(void) +{ + struct nf_conntrack_expect *exp; + struct hlist_node *n, *next; + + hlist_for_each_entry_safe(exp, n, next, + &nf_ct_userspace_expect_list, lnode) { + if (del_timer(&exp->timeout)) { + nf_ct_unlink_expect(exp); + nf_ct_expect_put(exp); + } + } +} +EXPORT_SYMBOL_GPL(nf_ct_remove_userspace_expectations); + #ifdef CONFIG_PROC_FS struct ct_expect_iter_state { struct seq_net_private p; diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 0804e0e..83b11e3 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1560,8 +1560,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, const struct nf_conntrack_expect *exp) { struct nf_conn *master = exp->master; - struct nf_conntrack_helper *helper; long timeout = (exp->timeout.expires - jiffies) / HZ; + struct nf_conn_help *help; if (timeout < 0) timeout = 0; @@ -1578,9 +1578,14 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)); NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)); NLA_PUT_BE32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)); - helper = rcu_dereference(nfct_help(master)->helper); - if (helper) - NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name); + help = nfct_help(master); + if (help) { + struct nf_conntrack_helper *helper; + + helper = rcu_dereference(help->helper); + if (helper) + NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name); + } return 0; @@ -1921,24 +1926,25 @@ ctnetlink_create_expect(struct net *net, u16 zone, if (!h) return -ENOENT; ct = nf_ct_tuplehash_to_ctrack(h); - help = nfct_help(ct); - - if (!help || !help->helper) { - /* such conntrack hasn't got any helper, abort */ - err = -EOPNOTSUPP; - goto out; - } - exp = nf_ct_expect_alloc(ct); if (!exp) { err = -ENOMEM; goto out; } - - if (cda[CTA_EXPECT_FLAGS]) + help = nfct_help(ct); + if (!help) { + if (!cda[CTA_EXPECT_TIMEOUT]) { + err = -EINVAL; + goto out; + } + exp->timeout.expires = + jiffies + ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ; + } + if (cda[CTA_EXPECT_FLAGS]) { exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS])); - else - exp->flags = 0; + exp->flags |= NF_CT_EXPECT_USERSPACE; + } else + exp->flags = NF_CT_EXPECT_USERSPACE; exp->class = 0; exp->expectfn = NULL; @@ -2109,6 +2115,7 @@ static void __exit ctnetlink_exit(void) { pr_info("ctnetlink: unregistering from nfnetlink.\n"); + nf_ct_remove_userspace_expectations(); #ifdef CONFIG_NF_CONNTRACK_EVENTS nf_ct_expect_unregister_notifier(&ctnl_notifier_exp); nf_conntrack_unregister_notifier(&ctnl_notifier); ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 4/4] netfilter: ctnetlink: add support for user-space expectation helpers 2010-09-21 22:38 ` Pablo Neira Ayuso @ 2010-09-22 6:45 ` Patrick McHardy 2010-09-22 11:07 ` Pablo Neira Ayuso 0 siblings, 1 reply; 16+ messages in thread From: Patrick McHardy @ 2010-09-22 6:45 UTC (permalink / raw) To: Pablo Neira Ayuso; +Cc: netfilter-devel Am 22.09.2010 00:38, schrieb Pablo Neira Ayuso: >> >> My main question is - what will be cleaning up these expectations >> on module unload? Currently expectations are cleaned up on unload >> of the corresponding helper module, which obviously doesn't >> happen in this case. > > Indeed. I have reworked the patch to add the nf_ct_userspace_expect_list > that is used to delete all the user-space created expectations if > ctnetlink is unloaded. > diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h > index fdc50ca..23a1a08 100644 > --- a/include/linux/netfilter/nf_conntrack_common.h > +++ b/include/linux/netfilter/nf_conntrack_common.h > @@ -103,6 +103,7 @@ enum ip_conntrack_expect_events { > /* expectation flags */ > #define NF_CT_EXPECT_PERMANENT 0x1 > #define NF_CT_EXPECT_INACTIVE 0x2 > +#define NF_CT_EXPECT_USERSPACE 0x4 Does this flag need to be exposed to userspace? I also don't see anything preventing userspace incorrectly setting it on an expectation that actually does have a master, which will probably cause problems later on. > diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c > index acb29cc..361a8ba 100644 > --- a/net/netfilter/nf_conntrack_expect.c > +++ b/net/netfilter/nf_conntrack_expect.c > @@ -38,20 +38,26 @@ static int nf_ct_expect_hash_rnd_initted __read_mostly; > > static struct kmem_cache *nf_ct_expect_cachep __read_mostly; > > +static HLIST_HEAD(nf_ct_userspace_expect_list); > +static int nf_ct_userspace_expect_list_counter; This counter is write-only. ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 4/4] netfilter: ctnetlink: add support for user-space expectation helpers 2010-09-22 6:45 ` Patrick McHardy @ 2010-09-22 11:07 ` Pablo Neira Ayuso 0 siblings, 0 replies; 16+ messages in thread From: Pablo Neira Ayuso @ 2010-09-22 11:07 UTC (permalink / raw) To: Patrick McHardy; +Cc: netfilter-devel [-- Attachment #1: Type: text/plain, Size: 1510 bytes --] Hi Patrick, On 22/09/10 08:45, Patrick McHardy wrote: >> diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h >> index fdc50ca..23a1a08 100644 >> --- a/include/linux/netfilter/nf_conntrack_common.h >> +++ b/include/linux/netfilter/nf_conntrack_common.h >> @@ -103,6 +103,7 @@ enum ip_conntrack_expect_events { >> /* expectation flags */ >> #define NF_CT_EXPECT_PERMANENT 0x1 >> #define NF_CT_EXPECT_INACTIVE 0x2 >> +#define NF_CT_EXPECT_USERSPACE 0x4 > > Does this flag need to be exposed to userspace? I also don't > see anything preventing userspace incorrectly setting it on > an expectation that actually does have a master, which will > probably cause problems later on. I have reworked the patch again: the flag is exposed to user-space but you cannot set/unset it. >> diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c >> index acb29cc..361a8ba 100644 >> --- a/net/netfilter/nf_conntrack_expect.c >> +++ b/net/netfilter/nf_conntrack_expect.c >> @@ -38,20 +38,26 @@ static int nf_ct_expect_hash_rnd_initted __read_mostly; >> >> static struct kmem_cache *nf_ct_expect_cachep __read_mostly; >> >> +static HLIST_HEAD(nf_ct_userspace_expect_list); >> +static int nf_ct_userspace_expect_list_counter; > > This counter is write-only. Removed this counter! I have also modified the /proc output to display USERSPACE for expectation whose user-space flag is set (this was missing in the previous patch). [-- Attachment #2: exp.patch --] [-- Type: text/x-patch, Size: 9346 bytes --] netfilter: ctnetlink: add support for user-space expectation helpers This patch adds the basic infrastructure to support user-space expectation helpers via ctnetlink and the netfilter queuing infrastructure NFQUEUE. Basically, this patch: * adds NF_CT_EXPECT_USERSPACE flag to identify user-space created expectations. I have also added a sanity check in __nf_ct_expect_check() to avoid that kernel-space helpers may create an expectation if the master conntrack has no helper assigned. * adds some branches to check if the master conntrack helper exists, otherwise we skip the code that refers to kernel-space helper such as the local expectation list and the expectation policy. * allows to set the timeout for user-space expectations with no helper assigned. * a list of expectations created from user-space that depends on ctnetlink (if this module is removed, they are deleted). * includes USERSPACE in the /proc output for expectations that have been created by a user-space helper. This patch also modifies ctnetlink to skip including the helper name in the Netlink messages if no kernel-space helper is set (since no user-space expectation has not kernel-space kernel assigned). You can access an example user-space FTP conntrack helper at: http://people.netfilter.org/pablo/nf-ftp-helper-userspace-POC.tar.bz Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- include/linux/netfilter/nf_conntrack_common.h | 1 include/net/netfilter/nf_conntrack_expect.h | 1 net/netfilter/nf_conntrack_expect.c | 62 +++++++++++++++++++------ net/netfilter/nf_conntrack_netlink.c | 46 ++++++++++++------- 4 files changed, 79 insertions(+), 31 deletions(-) diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h index fdc50ca..23a1a08 100644 --- a/include/linux/netfilter/nf_conntrack_common.h +++ b/include/linux/netfilter/nf_conntrack_common.h @@ -103,6 +103,7 @@ enum ip_conntrack_expect_events { /* expectation flags */ #define NF_CT_EXPECT_PERMANENT 0x1 #define NF_CT_EXPECT_INACTIVE 0x2 +#define NF_CT_EXPECT_USERSPACE 0x4 #ifdef __KERNEL__ struct ip_conntrack_stat { diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 96bb42a..416b838 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -85,6 +85,7 @@ nf_ct_find_expectation(struct net *net, u16 zone, void nf_ct_unlink_expect(struct nf_conntrack_expect *exp); void nf_ct_remove_expectations(struct nf_conn *ct); void nf_ct_unexpect_related(struct nf_conntrack_expect *exp); +void nf_ct_remove_userspace_expectations(void); /* Allocate space for an expectation: this is mandatory before calling nf_ct_expect_related. You will have to call put afterwards. */ diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index acb29cc..b30a1f2 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -38,20 +38,23 @@ static int nf_ct_expect_hash_rnd_initted __read_mostly; static struct kmem_cache *nf_ct_expect_cachep __read_mostly; +static HLIST_HEAD(nf_ct_userspace_expect_list); + /* nf_conntrack_expect helper functions */ void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) { struct nf_conn_help *master_help = nfct_help(exp->master); struct net *net = nf_ct_exp_net(exp); - NF_CT_ASSERT(master_help); NF_CT_ASSERT(!timer_pending(&exp->timeout)); hlist_del_rcu(&exp->hnode); net->ct.expect_count--; hlist_del(&exp->lnode); - master_help->expecting[exp->class]--; + if (!(exp->flags & NF_CT_EXPECT_USERSPACE)) + master_help->expecting[exp->class]--; + nf_ct_expect_put(exp); NF_CT_STAT_INC(net, expect_delete); @@ -320,16 +323,21 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp) atomic_inc(&exp->use); - hlist_add_head(&exp->lnode, &master_help->expectations); - master_help->expecting[exp->class]++; + if (master_help) { + hlist_add_head(&exp->lnode, &master_help->expectations); + master_help->expecting[exp->class]++; + } else if (exp->flags & NF_CT_EXPECT_USERSPACE) + hlist_add_head(&exp->lnode, &nf_ct_userspace_expect_list); hlist_add_head_rcu(&exp->hnode, &net->ct.expect_hash[h]); net->ct.expect_count++; setup_timer(&exp->timeout, nf_ct_expectation_timed_out, (unsigned long)exp); - p = &master_help->helper->expect_policy[exp->class]; - exp->timeout.expires = jiffies + p->timeout * HZ; + if (master_help) { + p = &master_help->helper->expect_policy[exp->class]; + exp->timeout.expires = jiffies + p->timeout * HZ; + } add_timer(&exp->timeout); atomic_inc(&exp->use); @@ -380,7 +388,9 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) unsigned int h; int ret = 1; - if (!master_help->helper) { + /* Don't allow expectations created from kernel-space with no helper */ + if (!(expect->flags & NF_CT_EXPECT_USERSPACE) && + (!master_help || (master_help && !master_help->helper))) { ret = -ESHUTDOWN; goto out; } @@ -398,13 +408,16 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) } } /* Will be over limit? */ - p = &master_help->helper->expect_policy[expect->class]; - if (p->max_expected && - master_help->expecting[expect->class] >= p->max_expected) { - evict_oldest_expect(master, expect); - if (master_help->expecting[expect->class] >= p->max_expected) { - ret = -EMFILE; - goto out; + if (master_help) { + p = &master_help->helper->expect_policy[expect->class]; + if (p->max_expected && + master_help->expecting[expect->class] >= p->max_expected) { + evict_oldest_expect(master, expect); + if (master_help->expecting[expect->class] + >= p->max_expected) { + ret = -EMFILE; + goto out; + } } } @@ -439,6 +452,21 @@ out: } EXPORT_SYMBOL_GPL(nf_ct_expect_related_report); +void nf_ct_remove_userspace_expectations(void) +{ + struct nf_conntrack_expect *exp; + struct hlist_node *n, *next; + + hlist_for_each_entry_safe(exp, n, next, + &nf_ct_userspace_expect_list, lnode) { + if (del_timer(&exp->timeout)) { + nf_ct_unlink_expect(exp); + nf_ct_expect_put(exp); + } + } +} +EXPORT_SYMBOL_GPL(nf_ct_remove_userspace_expectations); + #ifdef CONFIG_PROC_FS struct ct_expect_iter_state { struct seq_net_private p; @@ -529,8 +557,12 @@ static int exp_seq_show(struct seq_file *s, void *v) seq_printf(s, "PERMANENT"); delim = ","; } - if (expect->flags & NF_CT_EXPECT_INACTIVE) + if (expect->flags & NF_CT_EXPECT_INACTIVE) { seq_printf(s, "%sINACTIVE", delim); + delim = ","; + } + if (expect->flags & NF_CT_EXPECT_USERSPACE) + seq_printf(s, "%sUSERSPACE", delim); helper = rcu_dereference(nfct_help(expect->master)->helper); if (helper) { diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 0804e0e..b4077be 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1560,8 +1560,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, const struct nf_conntrack_expect *exp) { struct nf_conn *master = exp->master; - struct nf_conntrack_helper *helper; long timeout = (exp->timeout.expires - jiffies) / HZ; + struct nf_conn_help *help; if (timeout < 0) timeout = 0; @@ -1578,9 +1578,14 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)); NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)); NLA_PUT_BE32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)); - helper = rcu_dereference(nfct_help(master)->helper); - if (helper) - NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name); + help = nfct_help(master); + if (help) { + struct nf_conntrack_helper *helper; + + helper = rcu_dereference(help->helper); + if (helper) + NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name); + } return 0; @@ -1921,24 +1926,32 @@ ctnetlink_create_expect(struct net *net, u16 zone, if (!h) return -ENOENT; ct = nf_ct_tuplehash_to_ctrack(h); - help = nfct_help(ct); - - if (!help || !help->helper) { - /* such conntrack hasn't got any helper, abort */ - err = -EOPNOTSUPP; - goto out; - } - exp = nf_ct_expect_alloc(ct); if (!exp) { err = -ENOMEM; goto out; } + help = nfct_help(ct); + if (!help) { + if (!cda[CTA_EXPECT_TIMEOUT]) { + err = -EINVAL; + goto out; + } + exp->timeout.expires = + jiffies + ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ; - if (cda[CTA_EXPECT_FLAGS]) - exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS])); - else - exp->flags = 0; + exp->flags = NF_CT_EXPECT_USERSPACE; + if (cda[CTA_EXPECT_FLAGS]) { + exp->flags |= + ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS])); + } + } else { + if (cda[CTA_EXPECT_FLAGS]) { + exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS])); + exp->flags &= ~NF_CT_EXPECT_USERSPACE; + } else + exp->flags = 0; + } exp->class = 0; exp->expectfn = NULL; @@ -2109,6 +2122,7 @@ static void __exit ctnetlink_exit(void) { pr_info("ctnetlink: unregistering from nfnetlink.\n"); + nf_ct_remove_userspace_expectations(); #ifdef CONFIG_NF_CONNTRACK_EVENTS nf_ct_expect_unregister_notifier(&ctnl_notifier_exp); nf_conntrack_unregister_notifier(&ctnl_notifier); ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 4/4] netfilter: ctnetlink: add support for user-space expectation helpers 2010-09-21 9:35 ` [PATCH 4/4] netfilter: ctnetlink: add support for user-space expectation helpers Pablo Neira Ayuso 2010-09-21 15:20 ` Patrick McHardy @ 2010-09-28 19:08 ` Patrick McHardy 1 sibling, 0 replies; 16+ messages in thread From: Patrick McHardy @ 2010-09-28 19:08 UTC (permalink / raw) To: Pablo Neira Ayuso; +Cc: netfilter-devel Am 21.09.2010 11:35, schrieb Pablo Neira Ayuso: > This patch adds the basic infrastructure to support user-space > expectation helpers via ctnetlink and the netfilter queuing > infrastructure NFQUEUE. Basically, this patch: > > * adds NF_CT_EXPECT_USERSPACE flag to identify user-space > created expectations. I have also added a sanity check in > __nf_ct_expect_check() to avoid that kernel-space helpers > may create an expectation if the master conntrack has no > helper assigned. > * adds some branches to check if the master conntrack helper > exists, otherwise we skip the code that refers to kernel-space > helper such as the local expectation list and the expectation > policy. > * allows to set the timeout for user-space expectations with > no helper assigned. > > This patch also modifies ctnetlink to skip including the helper > name in the Netlink messages if no kernel-space helper is set > (since no user-space expectation has not kernel-space kernel > assigned). > > You can access an example user-space FTP conntrack helper at: > http://people.netfilter.org/pablo/nf-ftp-helper-userspace-POC.tar.bz Applied, thanks Pablo. I've also fixed up the URL to include userspace-conntrack-helpers/ in the path :) ^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2010-09-28 19:08 UTC | newest] Thread overview: 16+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-09-21 9:34 [PATCH 0/4] We all need more expectations Pablo Neira Ayuso 2010-09-21 9:34 ` [PATCH 1/4] netfilter: nf_nat: better error handling of nf_ct_expect_related() in helpers Pablo Neira Ayuso 2010-09-21 15:07 ` Patrick McHardy 2010-09-22 6:35 ` Patrick McHardy 2010-09-21 9:34 ` [PATCH 2/4] netfilter: ctnetlink: missing validation of CTA_EXPECT_ZONE attribute Pablo Neira Ayuso 2010-09-22 6:36 ` Patrick McHardy 2010-09-21 9:35 ` [PATCH 3/4] netfilter: ctnetlink: allow to specify the expectation flags Pablo Neira Ayuso 2010-09-21 15:18 ` Patrick McHardy 2010-09-21 22:38 ` Pablo Neira Ayuso 2010-09-22 6:37 ` Patrick McHardy 2010-09-21 9:35 ` [PATCH 4/4] netfilter: ctnetlink: add support for user-space expectation helpers Pablo Neira Ayuso 2010-09-21 15:20 ` Patrick McHardy 2010-09-21 22:38 ` Pablo Neira Ayuso 2010-09-22 6:45 ` Patrick McHardy 2010-09-22 11:07 ` Pablo Neira Ayuso 2010-09-28 19:08 ` Patrick McHardy
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).