diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-05-13 15:44:54 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-06-16 09:40:02 -0400 |
commit | 12f7a505331e6b2754684b509f2ac8f0011ce644 (patch) | |
tree | da127aa83f0fdf0fc6be32c6386a304d5087c858 /net/ipv6 | |
parent | ae243bee397102c51fbf9db440eca3b077e0e702 (diff) |
netfilter: add user-space connection tracking helper infrastructure
There are good reasons to supports helpers in user-space instead:
* Rapid connection tracking helper development, as developing code
in user-space is usually faster.
* Reliability: A buggy helper does not crash the kernel. Moreover,
we can monitor the helper process and restart it in case of problems.
* Security: Avoid complex string matching and mangling in kernel-space
running in privileged mode. Going further, we can even think about
running user-space helpers as a non-root process.
* Extensibility: It allows the development of very specific helpers (most
likely non-standard proprietary protocols) that are very likely not to be
accepted for mainline inclusion in the form of kernel-space connection
tracking helpers.
This patch adds the infrastructure to allow the implementation of
user-space conntrack helpers by means of the new nfnetlink subsystem
`nfnetlink_cthelper' and the existing queueing infrastructure
(nfnetlink_queue).
I had to add the new hook NF_IP6_PRI_CONNTRACK_HELPER to register
ipv[4|6]_helper which results from splitting ipv[4|6]_confirm into
two pieces. This change is required not to break NAT sequence
adjustment and conntrack confirmation for traffic that is enqueued
to our user-space conntrack helpers.
Basic operation, in a few steps:
1) Register user-space helper by means of `nfct':
nfct helper add ftp inet tcp
[ It must be a valid existing helper supported by conntrack-tools ]
2) Add rules to enable the FTP user-space helper which is
used to track traffic going to TCP port 21.
For locally generated packets:
iptables -I OUTPUT -t raw -p tcp --dport 21 -j CT --helper ftp
For non-locally generated packets:
iptables -I PREROUTING -t raw -p tcp --dport 21 -j CT --helper ftp
3) Run the test conntrackd in helper mode (see example files under
doc/helper/conntrackd.conf
conntrackd
4) Generate FTP traffic going, if everything is OK, then conntrackd
should create expectations (you can check that with `conntrack':
conntrack -E expect
[NEW] 301 proto=6 src=192.168.1.136 dst=130.89.148.12 sport=0 dport=54037 mask-src=255.255.255.255 mask-dst=255.255.255.255 sport=0 dport=65535 master-src=192.168.1.136 master-dst=130.89.148.12 sport=57127 dport=21 class=0 helper=ftp
[DESTROY] 301 proto=6 src=192.168.1.136 dst=130.89.148.12 sport=0 dport=54037 mask-src=255.255.255.255 mask-dst=255.255.255.255 sport=0 dport=65535 master-src=192.168.1.136 master-dst=130.89.148.12 sport=57127 dport=21 class=0 helper=ftp
This confirms that our test helper is receiving packets including the
conntrack information, and adding expectations in kernel-space.
The user-space helper can also store its private tracking information
in the conntrack structure in the kernel via the CTA_HELP_INFO. The
kernel will consider this a binary blob whose layout is unknown. This
information will be included in the information that is transfered
to user-space via glue code that integrates nfnetlink_queue and
ctnetlink.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index fca10da80ea7..4794f96cf2e0 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -143,11 +143,11 @@ static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff, | |||
143 | return NF_ACCEPT; | 143 | return NF_ACCEPT; |
144 | } | 144 | } |
145 | 145 | ||
146 | static unsigned int ipv6_confirm(unsigned int hooknum, | 146 | static unsigned int ipv6_helper(unsigned int hooknum, |
147 | struct sk_buff *skb, | 147 | struct sk_buff *skb, |
148 | const struct net_device *in, | 148 | const struct net_device *in, |
149 | const struct net_device *out, | 149 | const struct net_device *out, |
150 | int (*okfn)(struct sk_buff *)) | 150 | int (*okfn)(struct sk_buff *)) |
151 | { | 151 | { |
152 | struct nf_conn *ct; | 152 | struct nf_conn *ct; |
153 | const struct nf_conn_help *help; | 153 | const struct nf_conn_help *help; |
@@ -161,15 +161,15 @@ static unsigned int ipv6_confirm(unsigned int hooknum, | |||
161 | /* This is where we call the helper: as the packet goes out. */ | 161 | /* This is where we call the helper: as the packet goes out. */ |
162 | ct = nf_ct_get(skb, &ctinfo); | 162 | ct = nf_ct_get(skb, &ctinfo); |
163 | if (!ct || ctinfo == IP_CT_RELATED_REPLY) | 163 | if (!ct || ctinfo == IP_CT_RELATED_REPLY) |
164 | goto out; | 164 | return NF_ACCEPT; |
165 | 165 | ||
166 | help = nfct_help(ct); | 166 | help = nfct_help(ct); |
167 | if (!help) | 167 | if (!help) |
168 | goto out; | 168 | return NF_ACCEPT; |
169 | /* rcu_read_lock()ed by nf_hook_slow */ | 169 | /* rcu_read_lock()ed by nf_hook_slow */ |
170 | helper = rcu_dereference(help->helper); | 170 | helper = rcu_dereference(help->helper); |
171 | if (!helper) | 171 | if (!helper) |
172 | goto out; | 172 | return NF_ACCEPT; |
173 | 173 | ||
174 | protoff = nf_ct_ipv6_skip_exthdr(skb, extoff, &pnum, | 174 | protoff = nf_ct_ipv6_skip_exthdr(skb, extoff, &pnum, |
175 | skb->len - extoff); | 175 | skb->len - extoff); |
@@ -179,12 +179,19 @@ static unsigned int ipv6_confirm(unsigned int hooknum, | |||
179 | } | 179 | } |
180 | 180 | ||
181 | ret = helper->help(skb, protoff, ct, ctinfo); | 181 | ret = helper->help(skb, protoff, ct, ctinfo); |
182 | if (ret != NF_ACCEPT) { | 182 | if (ret != NF_ACCEPT && (ret & NF_VERDICT_MASK) != NF_QUEUE) { |
183 | nf_log_packet(NFPROTO_IPV6, hooknum, skb, in, out, NULL, | 183 | nf_log_packet(NFPROTO_IPV6, hooknum, skb, in, out, NULL, |
184 | "nf_ct_%s: dropping packet", helper->name); | 184 | "nf_ct_%s: dropping packet", helper->name); |
185 | return ret; | ||
186 | } | 185 | } |
187 | out: | 186 | return ret; |
187 | } | ||
188 | |||
189 | static unsigned int ipv6_confirm(unsigned int hooknum, | ||
190 | struct sk_buff *skb, | ||
191 | const struct net_device *in, | ||
192 | const struct net_device *out, | ||
193 | int (*okfn)(struct sk_buff *)) | ||
194 | { | ||
188 | /* We've seen it coming out the other side: confirm it */ | 195 | /* We've seen it coming out the other side: confirm it */ |
189 | return nf_conntrack_confirm(skb); | 196 | return nf_conntrack_confirm(skb); |
190 | } | 197 | } |
@@ -254,6 +261,13 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { | |||
254 | .priority = NF_IP6_PRI_CONNTRACK, | 261 | .priority = NF_IP6_PRI_CONNTRACK, |
255 | }, | 262 | }, |
256 | { | 263 | { |
264 | .hook = ipv6_helper, | ||
265 | .owner = THIS_MODULE, | ||
266 | .pf = NFPROTO_IPV6, | ||
267 | .hooknum = NF_INET_POST_ROUTING, | ||
268 | .priority = NF_IP6_PRI_CONNTRACK_HELPER, | ||
269 | }, | ||
270 | { | ||
257 | .hook = ipv6_confirm, | 271 | .hook = ipv6_confirm, |
258 | .owner = THIS_MODULE, | 272 | .owner = THIS_MODULE, |
259 | .pf = NFPROTO_IPV6, | 273 | .pf = NFPROTO_IPV6, |
@@ -261,6 +275,13 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { | |||
261 | .priority = NF_IP6_PRI_LAST, | 275 | .priority = NF_IP6_PRI_LAST, |
262 | }, | 276 | }, |
263 | { | 277 | { |
278 | .hook = ipv6_helper, | ||
279 | .owner = THIS_MODULE, | ||
280 | .pf = NFPROTO_IPV6, | ||
281 | .hooknum = NF_INET_LOCAL_IN, | ||
282 | .priority = NF_IP6_PRI_CONNTRACK_HELPER, | ||
283 | }, | ||
284 | { | ||
264 | .hook = ipv6_confirm, | 285 | .hook = ipv6_confirm, |
265 | .owner = THIS_MODULE, | 286 | .owner = THIS_MODULE, |
266 | .pf = NFPROTO_IPV6, | 287 | .pf = NFPROTO_IPV6, |