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 #if IS_ENABLED(CONFIG_NF_CONNTRACK) 23 #include <net/netfilter/nf_conntrack.h> 24 #include <net/netfilter/nf_conntrack_helper.h> 25 #include <net/netfilter/nf_conntrack_l4proto.h> 26 #include <net/netfilter/nf_conntrack_l3proto.h> 27 #include <net/netfilter/nf_conntrack_core.h> 28 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> 29 #endif 30 #include <net/netfilter/nf_conntrack_zones.h> 31 #include <net/netfilter/ipv6/nf_defrag_ipv6.h> 32 33 static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, 34 struct sk_buff *skb) 35 { 36 u16 zone = NF_CT_DEFAULT_ZONE; 37 38 #if IS_ENABLED(CONFIG_NF_CONNTRACK) 39 if (skb->nfct) 40 zone = nf_ct_zone((struct nf_conn *)skb->nfct); 41 #endif 42 43 #ifdef CONFIG_BRIDGE_NETFILTER 44 if (skb->nf_bridge && 45 skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) 46 return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone; 47 #endif 48 if (hooknum == NF_INET_PRE_ROUTING) 49 return IP6_DEFRAG_CONNTRACK_IN + zone; 50 else 51 return IP6_DEFRAG_CONNTRACK_OUT + zone; 52 53 } 54 55 static unsigned int ipv6_defrag(const struct nf_hook_ops *ops, 56 struct sk_buff *skb, 57 const struct net_device *in, 58 const struct net_device *out, 59 int (*okfn)(struct sk_buff *)) 60 { 61 struct sk_buff *reasm; 62 63 #if IS_ENABLED(CONFIG_NF_CONNTRACK) 64 /* Previously seen (loopback)? */ 65 if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) 66 return NF_ACCEPT; 67 #endif 68 69 reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(ops->hooknum, skb)); 70 /* queued */ 71 if (reasm == NULL) 72 return NF_STOLEN; 73 74 /* error occurred or not fragmented */ 75 if (reasm == skb) 76 return NF_ACCEPT; 77 78 nf_ct_frag6_consume_orig(reasm); 79 80 NF_HOOK_THRESH(NFPROTO_IPV6, ops->hooknum, reasm, 81 (struct net_device *) in, (struct net_device *) out, 82 okfn, NF_IP6_PRI_CONNTRACK_DEFRAG + 1); 83 84 return NF_STOLEN; 85 } 86 87 static struct nf_hook_ops ipv6_defrag_ops[] = { 88 { 89 .hook = ipv6_defrag, 90 .owner = THIS_MODULE, 91 .pf = NFPROTO_IPV6, 92 .hooknum = NF_INET_PRE_ROUTING, 93 .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, 94 }, 95 { 96 .hook = ipv6_defrag, 97 .owner = THIS_MODULE, 98 .pf = NFPROTO_IPV6, 99 .hooknum = NF_INET_LOCAL_OUT, 100 .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, 101 }, 102 }; 103 104 static int __init nf_defrag_init(void) 105 { 106 int ret = 0; 107 108 ret = nf_ct_frag6_init(); 109 if (ret < 0) { 110 pr_err("nf_defrag_ipv6: can't initialize frag6.\n"); 111 return ret; 112 } 113 ret = nf_register_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops)); 114 if (ret < 0) { 115 pr_err("nf_defrag_ipv6: can't register hooks\n"); 116 goto cleanup_frag6; 117 } 118 return ret; 119 120 cleanup_frag6: 121 nf_ct_frag6_cleanup(); 122 return ret; 123 124 } 125 126 static void __exit nf_defrag_fini(void) 127 { 128 nf_unregister_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops)); 129 nf_ct_frag6_cleanup(); 130 } 131 132 void nf_defrag_ipv6_enable(void) 133 { 134 } 135 EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable); 136 137 module_init(nf_defrag_init); 138 module_exit(nf_defrag_fini); 139 140 MODULE_LICENSE("GPL"); 141