X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv6%2Fnetfilter%2Fnf_conntrack_l3proto_ipv6.c;fp=net%2Fipv6%2Fnetfilter%2Fnf_conntrack_l3proto_ipv6.c;h=ac702a29dd160a0cd2bcc774d24aae1e6f0a8f62;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=c2ab38ff46af523159e7b1e090fdc008fc16f87d;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index c2ab38ff4..ac702a29d 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -20,6 +20,7 @@ * structures. */ +#include #include #include #include @@ -178,36 +179,31 @@ static unsigned int ipv6_confirm(unsigned int hooknum, int (*okfn)(struct sk_buff *)) { struct nf_conn *ct; - struct nf_conn_help *help; enum ip_conntrack_info ctinfo; - unsigned int ret, protoff; - unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1) - - (*pskb)->data; - unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr; - /* This is where we call the helper: as the packet goes out. */ ct = nf_ct_get(*pskb, &ctinfo); - if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY) - goto out; - - help = nfct_help(ct); - if (!help || !help->helper) - goto out; + if (ct && ct->helper) { + unsigned int ret, protoff; + unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1) + - (*pskb)->data; + unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr; + + protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, + (*pskb)->len - extoff); + if (protoff < 0 || protoff > (*pskb)->len || + pnum == NEXTHDR_FRAGMENT) { + DEBUGP("proto header not found\n"); + return NF_ACCEPT; + } - protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, - (*pskb)->len - extoff); - if (protoff < 0 || protoff > (*pskb)->len || - pnum == NEXTHDR_FRAGMENT) { - DEBUGP("proto header not found\n"); - return NF_ACCEPT; + ret = ct->helper->help(pskb, protoff, ct, ctinfo); + if (ret != NF_ACCEPT) + return ret; } - ret = help->helper->help(pskb, protoff, ct, ctinfo); - if (ret != NF_ACCEPT) - return ret; -out: /* We've seen it coming out the other side: confirm it */ + return nf_conntrack_confirm(pskb); } @@ -285,49 +281,55 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum, return ipv6_conntrack_in(hooknum, pskb, in, out, okfn); } -static struct nf_hook_ops ipv6_conntrack_ops[] = { - { - .hook = ipv6_defrag, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_PRE_ROUTING, - .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, - }, - { - .hook = ipv6_conntrack_in, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_PRE_ROUTING, - .priority = NF_IP6_PRI_CONNTRACK, - }, - { - .hook = ipv6_conntrack_local, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_LOCAL_OUT, - .priority = NF_IP6_PRI_CONNTRACK, - }, - { - .hook = ipv6_defrag, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_LOCAL_OUT, - .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, - }, - { - .hook = ipv6_confirm, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_POST_ROUTING, - .priority = NF_IP6_PRI_LAST, - }, - { - .hook = ipv6_confirm, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_LOCAL_IN, - .priority = NF_IP6_PRI_LAST-1, - }, +/* Connection tracking may drop packets, but never alters them, so + make it the first hook. */ +static struct nf_hook_ops ipv6_conntrack_defrag_ops = { + .hook = ipv6_defrag, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_PRE_ROUTING, + .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, +}; + +static struct nf_hook_ops ipv6_conntrack_in_ops = { + .hook = ipv6_conntrack_in, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_PRE_ROUTING, + .priority = NF_IP6_PRI_CONNTRACK, +}; + +static struct nf_hook_ops ipv6_conntrack_local_out_ops = { + .hook = ipv6_conntrack_local, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_LOCAL_OUT, + .priority = NF_IP6_PRI_CONNTRACK, +}; + +static struct nf_hook_ops ipv6_conntrack_defrag_local_out_ops = { + .hook = ipv6_defrag, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_LOCAL_OUT, + .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, +}; + +/* Refragmenter; last chance. */ +static struct nf_hook_ops ipv6_conntrack_out_ops = { + .hook = ipv6_confirm, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_POST_ROUTING, + .priority = NF_IP6_PRI_LAST, +}; + +static struct nf_hook_ops ipv6_conntrack_local_in_ops = { + .hook = ipv6_confirm, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_LOCAL_IN, + .priority = NF_IP6_PRI_LAST-1, }; #ifdef CONFIG_SYSCTL @@ -463,21 +465,16 @@ extern struct nf_conntrack_protocol nf_conntrack_protocol_udp6; extern struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6; extern int nf_ct_frag6_init(void); extern void nf_ct_frag6_cleanup(void); - -MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI "); - -static int __init nf_conntrack_l3proto_ipv6_init(void) +static int init_or_cleanup(int init) { int ret = 0; - need_conntrack(); + if (!init) goto cleanup; ret = nf_ct_frag6_init(); if (ret < 0) { printk("nf_conntrack_ipv6: can't initialize frag6.\n"); - return ret; + goto cleanup_nothing; } ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp6); if (ret < 0) { @@ -503,27 +500,71 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) goto cleanup_icmpv6; } - ret = nf_register_hooks(ipv6_conntrack_ops, - ARRAY_SIZE(ipv6_conntrack_ops)); + ret = nf_register_hook(&ipv6_conntrack_defrag_ops); if (ret < 0) { printk("nf_conntrack_ipv6: can't register pre-routing defrag " "hook.\n"); goto cleanup_ipv6; } + + ret = nf_register_hook(&ipv6_conntrack_defrag_local_out_ops); + if (ret < 0) { + printk("nf_conntrack_ipv6: can't register local_out defrag " + "hook.\n"); + goto cleanup_defragops; + } + + ret = nf_register_hook(&ipv6_conntrack_in_ops); + if (ret < 0) { + printk("nf_conntrack_ipv6: can't register pre-routing hook.\n"); + goto cleanup_defraglocalops; + } + + ret = nf_register_hook(&ipv6_conntrack_local_out_ops); + if (ret < 0) { + printk("nf_conntrack_ipv6: can't register local out hook.\n"); + goto cleanup_inops; + } + + ret = nf_register_hook(&ipv6_conntrack_out_ops); + if (ret < 0) { + printk("nf_conntrack_ipv6: can't register post-routing hook.\n"); + goto cleanup_inandlocalops; + } + + ret = nf_register_hook(&ipv6_conntrack_local_in_ops); + if (ret < 0) { + printk("nf_conntrack_ipv6: can't register local in hook.\n"); + goto cleanup_inoutandlocalops; + } + #ifdef CONFIG_SYSCTL nf_ct_ipv6_sysctl_header = register_sysctl_table(nf_ct_net_table, 0); if (nf_ct_ipv6_sysctl_header == NULL) { printk("nf_conntrack: can't register to sysctl.\n"); ret = -ENOMEM; - goto cleanup_hooks; + goto cleanup_localinops; } #endif return ret; + cleanup: + synchronize_net(); #ifdef CONFIG_SYSCTL - cleanup_hooks: - nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); + unregister_sysctl_table(nf_ct_ipv6_sysctl_header); + cleanup_localinops: #endif + nf_unregister_hook(&ipv6_conntrack_local_in_ops); + cleanup_inoutandlocalops: + nf_unregister_hook(&ipv6_conntrack_out_ops); + cleanup_inandlocalops: + nf_unregister_hook(&ipv6_conntrack_local_out_ops); + cleanup_inops: + nf_unregister_hook(&ipv6_conntrack_in_ops); + cleanup_defraglocalops: + nf_unregister_hook(&ipv6_conntrack_defrag_local_out_ops); + cleanup_defragops: + nf_unregister_hook(&ipv6_conntrack_defrag_ops); cleanup_ipv6: nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6); cleanup_icmpv6: @@ -534,22 +575,23 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp6); cleanup_frag6: nf_ct_frag6_cleanup(); + cleanup_nothing: return ret; } -static void __exit nf_conntrack_l3proto_ipv6_fini(void) +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI "); + +static int __init init(void) { - synchronize_net(); -#ifdef CONFIG_SYSCTL - unregister_sysctl_table(nf_ct_ipv6_sysctl_header); -#endif - nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); - nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6); - nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmpv6); - nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp6); - nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp6); - nf_ct_frag6_cleanup(); + need_conntrack(); + return init_or_cleanup(1); +} + +static void __exit fini(void) +{ + init_or_cleanup(0); } -module_init(nf_conntrack_l3proto_ipv6_init); -module_exit(nf_conntrack_l3proto_ipv6_fini); +module_init(init); +module_exit(fini);