Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tproxy: split off ipv6 defragmentation to a separate module

Like with IPv4, TProxy needs IPv6 defragmentation but does not
require connection tracking. Since defragmentation was coupled
with conntrack, I split off the two, creating an nf_defrag_ipv6 module,
similar to the already existing nf_defrag_ipv4.

Signed-off-by: Balazs Scheidler <bazsi@balabit.hu>
Signed-off-by: KOVACS Krisztian <hidden@balabit.hu>
Signed-off-by: Patrick McHardy <kaber@trash.net>

authored by

Balazs Scheidler and committed by
Patrick McHardy
e97c3e27 093d2823

+156 -78
+6
include/net/netfilter/ipv6/nf_defrag_ipv6.h
··· 1 + #ifndef _NF_DEFRAG_IPV6_H 2 + #define _NF_DEFRAG_IPV6_H 3 + 4 + extern void nf_defrag_ipv6_enable(void); 5 + 6 + #endif /* _NF_DEFRAG_IPV6_H */
+3 -2
net/ipv6/netfilter/Makefile
··· 11 11 obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o 12 12 13 13 # objects for l3 independent conntrack 14 - nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o 14 + nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o 15 + nf_defrag_ipv6-objs := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o 15 16 16 17 # l3 independent conntrack 17 - obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o 18 + obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o nf_defrag_ipv6.o 18 19 19 20 # matches 20 21 obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
+3 -75
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
··· 16 16 #include <linux/module.h> 17 17 #include <linux/skbuff.h> 18 18 #include <linux/icmp.h> 19 - #include <linux/sysctl.h> 20 19 #include <net/ipv6.h> 21 20 #include <net/inet_frag.h> 22 21 ··· 28 29 #include <net/netfilter/nf_conntrack_core.h> 29 30 #include <net/netfilter/nf_conntrack_zones.h> 30 31 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> 32 + #include <net/netfilter/ipv6/nf_defrag_ipv6.h> 31 33 #include <net/netfilter/nf_log.h> 32 34 33 35 static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, ··· 189 189 return nf_conntrack_confirm(skb); 190 190 } 191 191 192 - static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, 193 - struct sk_buff *skb) 194 - { 195 - u16 zone = NF_CT_DEFAULT_ZONE; 196 - 197 - if (skb->nfct) 198 - zone = nf_ct_zone((struct nf_conn *)skb->nfct); 199 - 200 - #ifdef CONFIG_BRIDGE_NETFILTER 201 - if (skb->nf_bridge && 202 - skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) 203 - return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone; 204 - #endif 205 - if (hooknum == NF_INET_PRE_ROUTING) 206 - return IP6_DEFRAG_CONNTRACK_IN + zone; 207 - else 208 - return IP6_DEFRAG_CONNTRACK_OUT + zone; 209 - 210 - } 211 - 212 - static unsigned int ipv6_defrag(unsigned int hooknum, 213 - struct sk_buff *skb, 214 - const struct net_device *in, 215 - const struct net_device *out, 216 - int (*okfn)(struct sk_buff *)) 217 - { 218 - struct sk_buff *reasm; 219 - 220 - /* Previously seen (loopback)? */ 221 - if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) 222 - return NF_ACCEPT; 223 - 224 - reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); 225 - /* queued */ 226 - if (reasm == NULL) 227 - return NF_STOLEN; 228 - 229 - /* error occured or not fragmented */ 230 - if (reasm == skb) 231 - return NF_ACCEPT; 232 - 233 - nf_ct_frag6_output(hooknum, reasm, (struct net_device *)in, 234 - (struct net_device *)out, okfn); 235 - 236 - return NF_STOLEN; 237 - } 238 - 239 192 static unsigned int __ipv6_conntrack_in(struct net *net, 240 193 unsigned int hooknum, 241 194 struct sk_buff *skb, ··· 241 288 242 289 static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { 243 290 { 244 - .hook = ipv6_defrag, 245 - .owner = THIS_MODULE, 246 - .pf = NFPROTO_IPV6, 247 - .hooknum = NF_INET_PRE_ROUTING, 248 - .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, 249 - }, 250 - { 251 291 .hook = ipv6_conntrack_in, 252 292 .owner = THIS_MODULE, 253 293 .pf = NFPROTO_IPV6, ··· 253 307 .pf = NFPROTO_IPV6, 254 308 .hooknum = NF_INET_LOCAL_OUT, 255 309 .priority = NF_IP6_PRI_CONNTRACK, 256 - }, 257 - { 258 - .hook = ipv6_defrag, 259 - .owner = THIS_MODULE, 260 - .pf = NFPROTO_IPV6, 261 - .hooknum = NF_INET_LOCAL_OUT, 262 - .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, 263 310 }, 264 311 { 265 312 .hook = ipv6_confirm, ··· 326 387 .nlattr_to_tuple = ipv6_nlattr_to_tuple, 327 388 .nla_policy = ipv6_nla_policy, 328 389 #endif 329 - #ifdef CONFIG_SYSCTL 330 - .ctl_table_path = nf_net_netfilter_sysctl_path, 331 - .ctl_table = nf_ct_ipv6_sysctl_table, 332 - #endif 333 390 .me = THIS_MODULE, 334 391 }; 335 392 ··· 338 403 int ret = 0; 339 404 340 405 need_conntrack(); 406 + nf_defrag_ipv6_enable(); 341 407 342 - ret = nf_ct_frag6_init(); 343 - if (ret < 0) { 344 - pr_err("nf_conntrack_ipv6: can't initialize frag6.\n"); 345 - return ret; 346 - } 347 408 ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp6); 348 409 if (ret < 0) { 349 410 pr_err("nf_conntrack_ipv6: can't register tcp.\n"); 350 - goto cleanup_frag6; 411 + return ret; 351 412 } 352 413 353 414 ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp6); ··· 381 450 nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6); 382 451 cleanup_tcp: 383 452 nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6); 384 - cleanup_frag6: 385 - nf_ct_frag6_cleanup(); 386 453 return ret; 387 454 } 388 455 ··· 392 463 nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmpv6); 393 464 nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6); 394 465 nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6); 395 - nf_ct_frag6_cleanup(); 396 466 } 397 467 398 468 module_init(nf_conntrack_l3proto_ipv6_init);
+13 -1
net/ipv6/netfilter/nf_conntrack_reasm.c
··· 73 73 static struct netns_frags nf_init_frags; 74 74 75 75 #ifdef CONFIG_SYSCTL 76 - struct ctl_table nf_ct_ipv6_sysctl_table[] = { 76 + struct ctl_table nf_ct_frag6_sysctl_table[] = { 77 77 { 78 78 .procname = "nf_conntrack_frag6_timeout", 79 79 .data = &nf_init_frags.timeout, ··· 97 97 }, 98 98 { } 99 99 }; 100 + 101 + static struct ctl_table_header *nf_ct_frag6_sysctl_header; 100 102 #endif 101 103 102 104 static unsigned int nf_hashfn(struct inet_frag_queue *q) ··· 625 623 inet_frags_init_net(&nf_init_frags); 626 624 inet_frags_init(&nf_frags); 627 625 626 + nf_ct_frag6_sysctl_header = register_sysctl_paths(nf_net_netfilter_sysctl_path, 627 + nf_ct_frag6_sysctl_table); 628 + if (!nf_ct_frag6_sysctl_header) { 629 + inet_frags_fini(&nf_frags); 630 + return -ENOMEM; 631 + } 632 + 628 633 return 0; 629 634 } 630 635 631 636 void nf_ct_frag6_cleanup(void) 632 637 { 638 + unregister_sysctl_table(nf_ct_frag6_sysctl_header); 639 + nf_ct_frag6_sysctl_header = NULL; 640 + 633 641 inet_frags_fini(&nf_frags); 634 642 635 643 nf_init_frags.low_thresh = 0;
+131
net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
··· 1 + /* (C) 1999-2001 Paul `Rusty' Russell 2 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #include <linux/types.h> 10 + #include <linux/ipv6.h> 11 + #include <linux/in6.h> 12 + #include <linux/netfilter.h> 13 + #include <linux/module.h> 14 + #include <linux/skbuff.h> 15 + #include <linux/icmp.h> 16 + #include <linux/sysctl.h> 17 + #include <net/ipv6.h> 18 + #include <net/inet_frag.h> 19 + 20 + #include <linux/netfilter_ipv6.h> 21 + #include <linux/netfilter_bridge.h> 22 + #include <net/netfilter/nf_conntrack.h> 23 + #include <net/netfilter/nf_conntrack_helper.h> 24 + #include <net/netfilter/nf_conntrack_l4proto.h> 25 + #include <net/netfilter/nf_conntrack_l3proto.h> 26 + #include <net/netfilter/nf_conntrack_core.h> 27 + #include <net/netfilter/nf_conntrack_zones.h> 28 + #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> 29 + #include <net/netfilter/ipv6/nf_defrag_ipv6.h> 30 + 31 + static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, 32 + struct sk_buff *skb) 33 + { 34 + u16 zone = NF_CT_DEFAULT_ZONE; 35 + 36 + if (skb->nfct) 37 + zone = nf_ct_zone((struct nf_conn *)skb->nfct); 38 + 39 + #ifdef CONFIG_BRIDGE_NETFILTER 40 + if (skb->nf_bridge && 41 + skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) 42 + return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone; 43 + #endif 44 + if (hooknum == NF_INET_PRE_ROUTING) 45 + return IP6_DEFRAG_CONNTRACK_IN + zone; 46 + else 47 + return IP6_DEFRAG_CONNTRACK_OUT + zone; 48 + 49 + } 50 + 51 + static unsigned int ipv6_defrag(unsigned int hooknum, 52 + struct sk_buff *skb, 53 + const struct net_device *in, 54 + const struct net_device *out, 55 + int (*okfn)(struct sk_buff *)) 56 + { 57 + struct sk_buff *reasm; 58 + 59 + /* Previously seen (loopback)? */ 60 + if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) 61 + return NF_ACCEPT; 62 + 63 + reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); 64 + /* queued */ 65 + if (reasm == NULL) 66 + return NF_STOLEN; 67 + 68 + /* error occured or not fragmented */ 69 + if (reasm == skb) 70 + return NF_ACCEPT; 71 + 72 + nf_ct_frag6_output(hooknum, reasm, (struct net_device *)in, 73 + (struct net_device *)out, okfn); 74 + 75 + return NF_STOLEN; 76 + } 77 + 78 + static struct nf_hook_ops ipv6_defrag_ops[] = { 79 + { 80 + .hook = ipv6_defrag, 81 + .owner = THIS_MODULE, 82 + .pf = NFPROTO_IPV6, 83 + .hooknum = NF_INET_PRE_ROUTING, 84 + .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, 85 + }, 86 + { 87 + .hook = ipv6_defrag, 88 + .owner = THIS_MODULE, 89 + .pf = NFPROTO_IPV6, 90 + .hooknum = NF_INET_LOCAL_OUT, 91 + .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, 92 + }, 93 + }; 94 + 95 + static int __init nf_defrag_init(void) 96 + { 97 + int ret = 0; 98 + 99 + ret = nf_ct_frag6_init(); 100 + if (ret < 0) { 101 + pr_err("nf_defrag_ipv6: can't initialize frag6.\n"); 102 + return ret; 103 + } 104 + ret = nf_register_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops)); 105 + if (ret < 0) { 106 + pr_err("nf_defrag_ipv6: can't register hooks\n"); 107 + goto cleanup_frag6; 108 + } 109 + return ret; 110 + 111 + cleanup_frag6: 112 + nf_ct_frag6_cleanup(); 113 + return ret; 114 + 115 + } 116 + 117 + static void __exit nf_defrag_fini(void) 118 + { 119 + nf_unregister_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops)); 120 + nf_ct_frag6_cleanup(); 121 + } 122 + 123 + void nf_defrag_ipv6_enable(void) 124 + { 125 + } 126 + EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable); 127 + 128 + module_init(nf_defrag_init); 129 + module_exit(nf_defrag_fini); 130 + 131 + MODULE_LICENSE("GPL");