1a0ae2562SFlorian Westphal // SPDX-License-Identifier: GPL-2.0 28f03dea5SMartin Josefsson 38f03dea5SMartin Josefsson #include <linux/types.h> 48f03dea5SMartin Josefsson #include <linux/netfilter.h> 58f03dea5SMartin Josefsson #include <linux/module.h> 65a0e3ad6STejun Heo #include <linux/slab.h> 7d62f9ed4SPatrick McHardy #include <linux/mutex.h> 88f03dea5SMartin Josefsson #include <linux/vmalloc.h> 98f03dea5SMartin Josefsson #include <linux/stddef.h> 108f03dea5SMartin Josefsson #include <linux/err.h> 118f03dea5SMartin Josefsson #include <linux/percpu.h> 128f03dea5SMartin Josefsson #include <linux/notifier.h> 138f03dea5SMartin Josefsson #include <linux/kernel.h> 148f03dea5SMartin Josefsson #include <linux/netdevice.h> 158f03dea5SMartin Josefsson 168f03dea5SMartin Josefsson #include <net/netfilter/nf_conntrack.h> 17605dcad6SMartin Josefsson #include <net/netfilter/nf_conntrack_l4proto.h> 188f03dea5SMartin Josefsson #include <net/netfilter/nf_conntrack_core.h> 19c4f3db15SFlorian Westphal #include <net/netfilter/nf_log.h> 208f03dea5SMartin Josefsson 21a0ae2562SFlorian Westphal #include <linux/ip.h> 22a0ae2562SFlorian Westphal #include <linux/icmp.h> 23a0ae2562SFlorian Westphal #include <linux/sysctl.h> 24a0ae2562SFlorian Westphal #include <net/route.h> 25a0ae2562SFlorian Westphal #include <net/ip.h> 26a0ae2562SFlorian Westphal 27a0ae2562SFlorian Westphal #include <linux/netfilter_ipv4.h> 28a0ae2562SFlorian Westphal #include <linux/netfilter_ipv6.h> 29a0ae2562SFlorian Westphal #include <linux/netfilter_ipv6/ip6_tables.h> 30a0ae2562SFlorian Westphal #include <net/netfilter/nf_conntrack_helper.h> 31a0ae2562SFlorian Westphal #include <net/netfilter/nf_conntrack_zones.h> 32a0ae2562SFlorian Westphal #include <net/netfilter/nf_conntrack_seqadj.h> 33a0ae2562SFlorian Westphal #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> 34a0ae2562SFlorian Westphal #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> 35a0ae2562SFlorian Westphal #include <net/netfilter/nf_nat_helper.h> 36a0ae2562SFlorian Westphal #include <net/netfilter/ipv4/nf_defrag_ipv4.h> 37a0ae2562SFlorian Westphal #include <net/netfilter/ipv6/nf_defrag_ipv6.h> 38a0ae2562SFlorian Westphal 39a0ae2562SFlorian Westphal #include <linux/ipv6.h> 40a0ae2562SFlorian Westphal #include <linux/in6.h> 41a0ae2562SFlorian Westphal #include <net/ipv6.h> 42a0ae2562SFlorian Westphal #include <net/inet_frag.h> 43a0ae2562SFlorian Westphal 44a0ae2562SFlorian Westphal extern unsigned int nf_conntrack_net_id; 45a0ae2562SFlorian Westphal 46dd2934a9SFlorian Westphal static struct nf_conntrack_l4proto __rcu *nf_ct_protos[MAX_NF_CT_PROTO] __read_mostly; 478f03dea5SMartin Josefsson 48b19caa0cSPatrick McHardy static DEFINE_MUTEX(nf_ct_proto_mutex); 49d62f9ed4SPatrick McHardy 50b19caa0cSPatrick McHardy #ifdef CONFIG_SYSCTL 51d62f9ed4SPatrick McHardy static int 522c352f44SGao feng nf_ct_register_sysctl(struct net *net, 532c352f44SGao feng struct ctl_table_header **header, 542c352f44SGao feng const char *path, 55fa34fff5SGao feng struct ctl_table *table) 56d62f9ed4SPatrick McHardy { 57d62f9ed4SPatrick McHardy if (*header == NULL) { 582c352f44SGao feng *header = register_net_sysctl(net, path, table); 59d62f9ed4SPatrick McHardy if (*header == NULL) 60d62f9ed4SPatrick McHardy return -ENOMEM; 61d62f9ed4SPatrick McHardy } 622c352f44SGao feng 63d62f9ed4SPatrick McHardy return 0; 64d62f9ed4SPatrick McHardy } 65d62f9ed4SPatrick McHardy 66d62f9ed4SPatrick McHardy static void 67d62f9ed4SPatrick McHardy nf_ct_unregister_sysctl(struct ctl_table_header **header, 682c352f44SGao feng struct ctl_table **table, 69fa34fff5SGao feng unsigned int users) 70d62f9ed4SPatrick McHardy { 71fa34fff5SGao feng if (users > 0) 72d62f9ed4SPatrick McHardy return; 73b3fd3ffeSPavel Emelyanov 745dd3df10SEric W. Biederman unregister_net_sysctl_table(*header); 752c352f44SGao feng kfree(*table); 76d62f9ed4SPatrick McHardy *header = NULL; 772c352f44SGao feng *table = NULL; 78d62f9ed4SPatrick McHardy } 79c4f3db15SFlorian Westphal 80c4f3db15SFlorian Westphal __printf(5, 6) 81c4f3db15SFlorian Westphal void nf_l4proto_log_invalid(const struct sk_buff *skb, 82c4f3db15SFlorian Westphal struct net *net, 83c4f3db15SFlorian Westphal u16 pf, u8 protonum, 84c4f3db15SFlorian Westphal const char *fmt, ...) 85c4f3db15SFlorian Westphal { 86c4f3db15SFlorian Westphal struct va_format vaf; 87c4f3db15SFlorian Westphal va_list args; 88c4f3db15SFlorian Westphal 89c4f3db15SFlorian Westphal if (net->ct.sysctl_log_invalid != protonum || 90c4f3db15SFlorian Westphal net->ct.sysctl_log_invalid != IPPROTO_RAW) 91c4f3db15SFlorian Westphal return; 92c4f3db15SFlorian Westphal 93c4f3db15SFlorian Westphal va_start(args, fmt); 94c4f3db15SFlorian Westphal vaf.fmt = fmt; 95c4f3db15SFlorian Westphal vaf.va = &args; 96c4f3db15SFlorian Westphal 97c4f3db15SFlorian Westphal nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, 98c4f3db15SFlorian Westphal "nf_ct_proto_%d: %pV ", protonum, &vaf); 99c4f3db15SFlorian Westphal va_end(args); 100c4f3db15SFlorian Westphal } 101c4f3db15SFlorian Westphal EXPORT_SYMBOL_GPL(nf_l4proto_log_invalid); 1023d0b527bSFlorian Westphal 1033d0b527bSFlorian Westphal __printf(3, 4) 1043d0b527bSFlorian Westphal void nf_ct_l4proto_log_invalid(const struct sk_buff *skb, 1053d0b527bSFlorian Westphal const struct nf_conn *ct, 1063d0b527bSFlorian Westphal const char *fmt, ...) 1073d0b527bSFlorian Westphal { 1083d0b527bSFlorian Westphal struct va_format vaf; 1093d0b527bSFlorian Westphal struct net *net; 1103d0b527bSFlorian Westphal va_list args; 1113d0b527bSFlorian Westphal 1123d0b527bSFlorian Westphal net = nf_ct_net(ct); 1133d0b527bSFlorian Westphal if (likely(net->ct.sysctl_log_invalid == 0)) 1143d0b527bSFlorian Westphal return; 1153d0b527bSFlorian Westphal 1163d0b527bSFlorian Westphal va_start(args, fmt); 1173d0b527bSFlorian Westphal vaf.fmt = fmt; 1183d0b527bSFlorian Westphal vaf.va = &args; 1193d0b527bSFlorian Westphal 1203d0b527bSFlorian Westphal nf_l4proto_log_invalid(skb, net, nf_ct_l3num(ct), 1213d0b527bSFlorian Westphal nf_ct_protonum(ct), "%pV", &vaf); 1223d0b527bSFlorian Westphal va_end(args); 1233d0b527bSFlorian Westphal } 1243d0b527bSFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_l4proto_log_invalid); 125d62f9ed4SPatrick McHardy #endif 126d62f9ed4SPatrick McHardy 127dd2934a9SFlorian Westphal const struct nf_conntrack_l4proto *__nf_ct_l4proto_find(u8 l4proto) 1288f03dea5SMartin Josefsson { 129dd2934a9SFlorian Westphal if (unlikely(l4proto >= ARRAY_SIZE(nf_ct_protos))) 130605dcad6SMartin Josefsson return &nf_conntrack_l4proto_generic; 1318f03dea5SMartin Josefsson 132dd2934a9SFlorian Westphal return rcu_dereference(nf_ct_protos[l4proto]); 1338f03dea5SMartin Josefsson } 13413b18339SPatrick McHardy EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find); 1358f03dea5SMartin Josefsson 136dd2934a9SFlorian Westphal const struct nf_conntrack_l4proto *nf_ct_l4proto_find_get(u8 l4num) 137c1ebd7dfSPablo Neira Ayuso { 138b3480fe0SFlorian Westphal const struct nf_conntrack_l4proto *p; 139c1ebd7dfSPablo Neira Ayuso 140c1ebd7dfSPablo Neira Ayuso rcu_read_lock(); 141dd2934a9SFlorian Westphal p = __nf_ct_l4proto_find(l4num); 142c1ebd7dfSPablo Neira Ayuso if (!try_module_get(p->me)) 143c1ebd7dfSPablo Neira Ayuso p = &nf_conntrack_l4proto_generic; 144c1ebd7dfSPablo Neira Ayuso rcu_read_unlock(); 145c1ebd7dfSPablo Neira Ayuso 146c1ebd7dfSPablo Neira Ayuso return p; 147c1ebd7dfSPablo Neira Ayuso } 148c1ebd7dfSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get); 149c1ebd7dfSPablo Neira Ayuso 1502a04aabfSJulia Lawall void nf_ct_l4proto_put(const struct nf_conntrack_l4proto *p) 151c1ebd7dfSPablo Neira Ayuso { 152c1ebd7dfSPablo Neira Ayuso module_put(p->me); 153c1ebd7dfSPablo Neira Ayuso } 154c1ebd7dfSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_l4proto_put); 155c1ebd7dfSPablo Neira Ayuso 156605dcad6SMartin Josefsson static int kill_l4proto(struct nf_conn *i, void *data) 1578f03dea5SMartin Josefsson { 158b3480fe0SFlorian Westphal const struct nf_conntrack_l4proto *l4proto; 15968ad546aSsimran singhal l4proto = data; 160dd2934a9SFlorian Westphal return nf_ct_protonum(i) == l4proto->l4proto; 1618f03dea5SMartin Josefsson } 1628f03dea5SMartin Josefsson 1632c352f44SGao feng static struct nf_proto_net *nf_ct_l4proto_net(struct net *net, 1642a04aabfSJulia Lawall const struct nf_conntrack_l4proto *l4proto) 1652c352f44SGao feng { 16608911475SPablo Neira Ayuso if (l4proto->get_net_proto) { 16708911475SPablo Neira Ayuso /* statically built-in protocols use static per-net */ 16808911475SPablo Neira Ayuso return l4proto->get_net_proto(net); 16908911475SPablo Neira Ayuso } else if (l4proto->net_id) { 17008911475SPablo Neira Ayuso /* ... and loadable protocols use dynamic per-net */ 1712c352f44SGao feng return net_generic(net, *l4proto->net_id); 1722c352f44SGao feng } 17315f585bdSGao feng return NULL; 17415f585bdSGao feng } 1752c352f44SGao feng 1762c352f44SGao feng static 1772c352f44SGao feng int nf_ct_l4proto_register_sysctl(struct net *net, 178fa34fff5SGao feng struct nf_proto_net *pn, 1792a04aabfSJulia Lawall const struct nf_conntrack_l4proto *l4proto) 180d62f9ed4SPatrick McHardy { 181d62f9ed4SPatrick McHardy int err = 0; 182d62f9ed4SPatrick McHardy 183d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 1842c352f44SGao feng if (pn->ctl_table != NULL) { 1852c352f44SGao feng err = nf_ct_register_sysctl(net, 1862c352f44SGao feng &pn->ctl_table_header, 187f99e8f71SEric W. Biederman "net/netfilter", 188fa34fff5SGao feng pn->ctl_table); 1892c352f44SGao feng if (err < 0) { 1902c352f44SGao feng if (!pn->users) { 1912c352f44SGao feng kfree(pn->ctl_table); 1922c352f44SGao feng pn->ctl_table = NULL; 1932c352f44SGao feng } 194d62f9ed4SPatrick McHardy } 1952c352f44SGao feng } 196933a41e7SPatrick McHardy #endif /* CONFIG_SYSCTL */ 197d62f9ed4SPatrick McHardy return err; 198d62f9ed4SPatrick McHardy } 199d62f9ed4SPatrick McHardy 2002c352f44SGao feng static 2012c352f44SGao feng void nf_ct_l4proto_unregister_sysctl(struct net *net, 202fa34fff5SGao feng struct nf_proto_net *pn, 2032a04aabfSJulia Lawall const struct nf_conntrack_l4proto *l4proto) 204d62f9ed4SPatrick McHardy { 205d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 2062c352f44SGao feng if (pn->ctl_table_header != NULL) 2072c352f44SGao feng nf_ct_unregister_sysctl(&pn->ctl_table_header, 2082c352f44SGao feng &pn->ctl_table, 209fa34fff5SGao feng pn->users); 210933a41e7SPatrick McHardy #endif /* CONFIG_SYSCTL */ 211d62f9ed4SPatrick McHardy } 212d62f9ed4SPatrick McHardy 2138f03dea5SMartin Josefsson /* FIXME: Allow NULL functions and sub in pointers to generic for 2148f03dea5SMartin Josefsson them. --RR */ 215cd9ceafcSFlorian Westphal int nf_ct_l4proto_register_one(const struct nf_conntrack_l4proto *l4proto) 2168f03dea5SMartin Josefsson { 2178f03dea5SMartin Josefsson int ret = 0; 2188f03dea5SMartin Josefsson 21939215846SFlorian Westphal if ((l4proto->to_nlattr && l4proto->nlattr_size == 0) || 2200e54d217SDavide Caratti (l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size)) 221d0dba725SHolger Eitzenberger return -EINVAL; 222d0dba725SHolger Eitzenberger 223b19caa0cSPatrick McHardy mutex_lock(&nf_ct_proto_mutex); 224dd2934a9SFlorian Westphal if (rcu_dereference_protected( 225dd2934a9SFlorian Westphal nf_ct_protos[l4proto->l4proto], 2260e60ebe0SEric Dumazet lockdep_is_held(&nf_ct_proto_mutex) 2270e60ebe0SEric Dumazet ) != &nf_conntrack_l4proto_generic) { 228c6a1e615SPatrick McHardy ret = -EBUSY; 229c6a1e615SPatrick McHardy goto out_unlock; 2308f03dea5SMartin Josefsson } 2318f03dea5SMartin Josefsson 232dd2934a9SFlorian Westphal rcu_assign_pointer(nf_ct_protos[l4proto->l4proto], l4proto); 2338f03dea5SMartin Josefsson out_unlock: 234b19caa0cSPatrick McHardy mutex_unlock(&nf_ct_proto_mutex); 2358f03dea5SMartin Josefsson return ret; 2368f03dea5SMartin Josefsson } 2370e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_register_one); 2382c352f44SGao feng 2390e54d217SDavide Caratti int nf_ct_l4proto_pernet_register_one(struct net *net, 2402a04aabfSJulia Lawall const struct nf_conntrack_l4proto *l4proto) 2412c352f44SGao feng { 2422c352f44SGao feng int ret = 0; 243fa34fff5SGao feng struct nf_proto_net *pn = NULL; 2442c352f44SGao feng 245fa0f61f0SGao feng if (l4proto->init_net) { 246ca2ca6e1SFlorian Westphal ret = l4proto->init_net(net); 247fa0f61f0SGao feng if (ret < 0) 248fa34fff5SGao feng goto out; 249fa0f61f0SGao feng } 2502c352f44SGao feng 251fa34fff5SGao feng pn = nf_ct_l4proto_net(net, l4proto); 252fa34fff5SGao feng if (pn == NULL) 253fa34fff5SGao feng goto out; 254fa34fff5SGao feng 255fa34fff5SGao feng ret = nf_ct_l4proto_register_sysctl(net, pn, l4proto); 2562c352f44SGao feng if (ret < 0) 257fa34fff5SGao feng goto out; 2582c352f44SGao feng 259fa34fff5SGao feng pn->users++; 260fa34fff5SGao feng out: 261fa0f61f0SGao feng return ret; 2622c352f44SGao feng } 2630e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register_one); 2648f03dea5SMartin Josefsson 2652a04aabfSJulia Lawall static void __nf_ct_l4proto_unregister_one(const struct nf_conntrack_l4proto *l4proto) 2662c41f33cSFlorian Westphal 2678f03dea5SMartin Josefsson { 268dd2934a9SFlorian Westphal BUG_ON(l4proto->l4proto >= ARRAY_SIZE(nf_ct_protos)); 269ae5718fbSMartin Josefsson 2700e60ebe0SEric Dumazet BUG_ON(rcu_dereference_protected( 271dd2934a9SFlorian Westphal nf_ct_protos[l4proto->l4proto], 2720e60ebe0SEric Dumazet lockdep_is_held(&nf_ct_proto_mutex) 2730e60ebe0SEric Dumazet ) != l4proto); 274dd2934a9SFlorian Westphal rcu_assign_pointer(nf_ct_protos[l4proto->l4proto], 275923f4902SPatrick McHardy &nf_conntrack_l4proto_generic); 2762c41f33cSFlorian Westphal } 2772c41f33cSFlorian Westphal 2782a04aabfSJulia Lawall void nf_ct_l4proto_unregister_one(const struct nf_conntrack_l4proto *l4proto) 2792c41f33cSFlorian Westphal { 2802c41f33cSFlorian Westphal mutex_lock(&nf_ct_proto_mutex); 2812c41f33cSFlorian Westphal __nf_ct_l4proto_unregister_one(l4proto); 2820661cca9SPatrick McHardy mutex_unlock(&nf_ct_proto_mutex); 2830661cca9SPatrick McHardy 2841c117d3bSFlorian Westphal synchronize_net(); 2851c117d3bSFlorian Westphal /* Remove all contrack entries for this protocol */ 2861c117d3bSFlorian Westphal nf_ct_iterate_destroy(kill_l4proto, (void *)l4proto); 2872c352f44SGao feng } 2880e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_unregister_one); 289d62f9ed4SPatrick McHardy 2900e54d217SDavide Caratti void nf_ct_l4proto_pernet_unregister_one(struct net *net, 2912a04aabfSJulia Lawall const struct nf_conntrack_l4proto *l4proto) 2922c352f44SGao feng { 293809c2d9aSAaron Conole struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto); 294fa34fff5SGao feng 295fa34fff5SGao feng if (pn == NULL) 296fa34fff5SGao feng return; 297fa34fff5SGao feng 298fa34fff5SGao feng pn->users--; 299fa34fff5SGao feng nf_ct_l4proto_unregister_sysctl(net, pn, l4proto); 3008f03dea5SMartin Josefsson } 3010e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_unregister_one); 3020e54d217SDavide Caratti 303a0ae2562SFlorian Westphal static void 304a0ae2562SFlorian Westphal nf_ct_l4proto_unregister(const struct nf_conntrack_l4proto * const l4proto[], 305a0ae2562SFlorian Westphal unsigned int num_proto) 306a0ae2562SFlorian Westphal { 3071c117d3bSFlorian Westphal int i; 3081c117d3bSFlorian Westphal 309a0ae2562SFlorian Westphal mutex_lock(&nf_ct_proto_mutex); 3101c117d3bSFlorian Westphal for (i = 0; i < num_proto; i++) 3111c117d3bSFlorian Westphal __nf_ct_l4proto_unregister_one(l4proto[i]); 312a0ae2562SFlorian Westphal mutex_unlock(&nf_ct_proto_mutex); 313a0ae2562SFlorian Westphal 314a0ae2562SFlorian Westphal synchronize_net(); 3151c117d3bSFlorian Westphal 3161c117d3bSFlorian Westphal for (i = 0; i < num_proto; i++) 3171c117d3bSFlorian Westphal nf_ct_iterate_destroy(kill_l4proto, (void *)l4proto[i]); 318a0ae2562SFlorian Westphal } 319a0ae2562SFlorian Westphal 320a0ae2562SFlorian Westphal static int 321a0ae2562SFlorian Westphal nf_ct_l4proto_register(const struct nf_conntrack_l4proto * const l4proto[], 3220e54d217SDavide Caratti unsigned int num_proto) 3230e54d217SDavide Caratti { 324dd2934a9SFlorian Westphal int ret = -EINVAL; 3250e54d217SDavide Caratti unsigned int i; 3260e54d217SDavide Caratti 3270e54d217SDavide Caratti for (i = 0; i < num_proto; i++) { 3280e54d217SDavide Caratti ret = nf_ct_l4proto_register_one(l4proto[i]); 3290e54d217SDavide Caratti if (ret < 0) 3300e54d217SDavide Caratti break; 3310e54d217SDavide Caratti } 3320e54d217SDavide Caratti if (i != num_proto) { 333dd2934a9SFlorian Westphal pr_err("nf_conntrack: can't register l4 %d proto.\n", 334dd2934a9SFlorian Westphal l4proto[i]->l4proto); 3350e54d217SDavide Caratti nf_ct_l4proto_unregister(l4proto, i); 3360e54d217SDavide Caratti } 3370e54d217SDavide Caratti return ret; 3380e54d217SDavide Caratti } 3390e54d217SDavide Caratti 3400e54d217SDavide Caratti int nf_ct_l4proto_pernet_register(struct net *net, 341cd9ceafcSFlorian Westphal const struct nf_conntrack_l4proto *const l4proto[], 3420e54d217SDavide Caratti unsigned int num_proto) 3430e54d217SDavide Caratti { 3440e54d217SDavide Caratti int ret = -EINVAL; 3450e54d217SDavide Caratti unsigned int i; 3460e54d217SDavide Caratti 3470e54d217SDavide Caratti for (i = 0; i < num_proto; i++) { 3480e54d217SDavide Caratti ret = nf_ct_l4proto_pernet_register_one(net, l4proto[i]); 3490e54d217SDavide Caratti if (ret < 0) 3500e54d217SDavide Caratti break; 3510e54d217SDavide Caratti } 3520e54d217SDavide Caratti if (i != num_proto) { 353dd2934a9SFlorian Westphal pr_err("nf_conntrack %d: pernet registration failed\n", 354dd2934a9SFlorian Westphal l4proto[i]->l4proto); 3550e54d217SDavide Caratti nf_ct_l4proto_pernet_unregister(net, l4proto, i); 3560e54d217SDavide Caratti } 3570e54d217SDavide Caratti return ret; 3580e54d217SDavide Caratti } 3590e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register); 3600e54d217SDavide Caratti 3610e54d217SDavide Caratti void nf_ct_l4proto_pernet_unregister(struct net *net, 362cd9ceafcSFlorian Westphal const struct nf_conntrack_l4proto *const l4proto[], 3630e54d217SDavide Caratti unsigned int num_proto) 3640e54d217SDavide Caratti { 3650e54d217SDavide Caratti while (num_proto-- != 0) 3660e54d217SDavide Caratti nf_ct_l4proto_pernet_unregister_one(net, l4proto[num_proto]); 3670e54d217SDavide Caratti } 368c296bb4dSGao feng EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_unregister); 369ac5357ebSPatrick McHardy 370a0ae2562SFlorian Westphal static unsigned int ipv4_helper(void *priv, 371a0ae2562SFlorian Westphal struct sk_buff *skb, 372a0ae2562SFlorian Westphal const struct nf_hook_state *state) 373a0ae2562SFlorian Westphal { 374a0ae2562SFlorian Westphal struct nf_conn *ct; 375a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 376a0ae2562SFlorian Westphal const struct nf_conn_help *help; 377a0ae2562SFlorian Westphal const struct nf_conntrack_helper *helper; 378a0ae2562SFlorian Westphal 379a0ae2562SFlorian Westphal /* This is where we call the helper: as the packet goes out. */ 380a0ae2562SFlorian Westphal ct = nf_ct_get(skb, &ctinfo); 381a0ae2562SFlorian Westphal if (!ct || ctinfo == IP_CT_RELATED_REPLY) 382a0ae2562SFlorian Westphal return NF_ACCEPT; 383a0ae2562SFlorian Westphal 384a0ae2562SFlorian Westphal help = nfct_help(ct); 385a0ae2562SFlorian Westphal if (!help) 386a0ae2562SFlorian Westphal return NF_ACCEPT; 387a0ae2562SFlorian Westphal 388a0ae2562SFlorian Westphal /* rcu_read_lock()ed by nf_hook_thresh */ 389a0ae2562SFlorian Westphal helper = rcu_dereference(help->helper); 390a0ae2562SFlorian Westphal if (!helper) 391a0ae2562SFlorian Westphal return NF_ACCEPT; 392a0ae2562SFlorian Westphal 393a0ae2562SFlorian Westphal return helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), 394a0ae2562SFlorian Westphal ct, ctinfo); 395a0ae2562SFlorian Westphal } 396a0ae2562SFlorian Westphal 397a0ae2562SFlorian Westphal static unsigned int ipv4_confirm(void *priv, 398a0ae2562SFlorian Westphal struct sk_buff *skb, 399a0ae2562SFlorian Westphal const struct nf_hook_state *state) 400a0ae2562SFlorian Westphal { 401a0ae2562SFlorian Westphal struct nf_conn *ct; 402a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 403a0ae2562SFlorian Westphal 404a0ae2562SFlorian Westphal ct = nf_ct_get(skb, &ctinfo); 405a0ae2562SFlorian Westphal if (!ct || ctinfo == IP_CT_RELATED_REPLY) 406a0ae2562SFlorian Westphal goto out; 407a0ae2562SFlorian Westphal 408a0ae2562SFlorian Westphal /* adjust seqs for loopback traffic only in outgoing direction */ 409a0ae2562SFlorian Westphal if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && 410a0ae2562SFlorian Westphal !nf_is_loopback_packet(skb)) { 411a0ae2562SFlorian Westphal if (!nf_ct_seq_adjust(skb, ct, ctinfo, ip_hdrlen(skb))) { 412a0ae2562SFlorian Westphal NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); 413a0ae2562SFlorian Westphal return NF_DROP; 414a0ae2562SFlorian Westphal } 415a0ae2562SFlorian Westphal } 416a0ae2562SFlorian Westphal out: 417a0ae2562SFlorian Westphal /* We've seen it coming out the other side: confirm it */ 418a0ae2562SFlorian Westphal return nf_conntrack_confirm(skb); 419a0ae2562SFlorian Westphal } 420a0ae2562SFlorian Westphal 421a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_in(void *priv, 422a0ae2562SFlorian Westphal struct sk_buff *skb, 423a0ae2562SFlorian Westphal const struct nf_hook_state *state) 424a0ae2562SFlorian Westphal { 42593e66024SFlorian Westphal return nf_conntrack_in(skb, state); 426a0ae2562SFlorian Westphal } 427a0ae2562SFlorian Westphal 428a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_local(void *priv, 429a0ae2562SFlorian Westphal struct sk_buff *skb, 430a0ae2562SFlorian Westphal const struct nf_hook_state *state) 431a0ae2562SFlorian Westphal { 432a0ae2562SFlorian Westphal if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */ 433a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 434a0ae2562SFlorian Westphal struct nf_conn *tmpl; 435a0ae2562SFlorian Westphal 436a0ae2562SFlorian Westphal tmpl = nf_ct_get(skb, &ctinfo); 437a0ae2562SFlorian Westphal if (tmpl && nf_ct_is_template(tmpl)) { 438a0ae2562SFlorian Westphal /* when skipping ct, clear templates to avoid fooling 439a0ae2562SFlorian Westphal * later targets/matches 440a0ae2562SFlorian Westphal */ 441a0ae2562SFlorian Westphal skb->_nfct = 0; 442a0ae2562SFlorian Westphal nf_ct_put(tmpl); 443a0ae2562SFlorian Westphal } 444a0ae2562SFlorian Westphal return NF_ACCEPT; 445a0ae2562SFlorian Westphal } 446a0ae2562SFlorian Westphal 44793e66024SFlorian Westphal return nf_conntrack_in(skb, state); 448a0ae2562SFlorian Westphal } 449a0ae2562SFlorian Westphal 450a0ae2562SFlorian Westphal /* Connection tracking may drop packets, but never alters them, so 451a0ae2562SFlorian Westphal * make it the first hook. 452a0ae2562SFlorian Westphal */ 453a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv4_conntrack_ops[] = { 454a0ae2562SFlorian Westphal { 455a0ae2562SFlorian Westphal .hook = ipv4_conntrack_in, 456a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 457a0ae2562SFlorian Westphal .hooknum = NF_INET_PRE_ROUTING, 458a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK, 459a0ae2562SFlorian Westphal }, 460a0ae2562SFlorian Westphal { 461a0ae2562SFlorian Westphal .hook = ipv4_conntrack_local, 462a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 463a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_OUT, 464a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK, 465a0ae2562SFlorian Westphal }, 466a0ae2562SFlorian Westphal { 467a0ae2562SFlorian Westphal .hook = ipv4_helper, 468a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 469a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING, 470a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_HELPER, 471a0ae2562SFlorian Westphal }, 472a0ae2562SFlorian Westphal { 473a0ae2562SFlorian Westphal .hook = ipv4_confirm, 474a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 475a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING, 476a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_CONFIRM, 477a0ae2562SFlorian Westphal }, 478a0ae2562SFlorian Westphal { 479a0ae2562SFlorian Westphal .hook = ipv4_helper, 480a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 481a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN, 482a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_HELPER, 483a0ae2562SFlorian Westphal }, 484a0ae2562SFlorian Westphal { 485a0ae2562SFlorian Westphal .hook = ipv4_confirm, 486a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 487a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN, 488a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_CONFIRM, 489a0ae2562SFlorian Westphal }, 490a0ae2562SFlorian Westphal }; 491a0ae2562SFlorian Westphal 492a0ae2562SFlorian Westphal /* Fast function for those who don't want to parse /proc (and I don't 493a0ae2562SFlorian Westphal * blame them). 494a0ae2562SFlorian Westphal * Reversing the socket's dst/src point of view gives us the reply 495a0ae2562SFlorian Westphal * mapping. 496a0ae2562SFlorian Westphal */ 497a0ae2562SFlorian Westphal static int 498a0ae2562SFlorian Westphal getorigdst(struct sock *sk, int optval, void __user *user, int *len) 499a0ae2562SFlorian Westphal { 500a0ae2562SFlorian Westphal const struct inet_sock *inet = inet_sk(sk); 501a0ae2562SFlorian Westphal const struct nf_conntrack_tuple_hash *h; 502a0ae2562SFlorian Westphal struct nf_conntrack_tuple tuple; 503a0ae2562SFlorian Westphal 504a0ae2562SFlorian Westphal memset(&tuple, 0, sizeof(tuple)); 505a0ae2562SFlorian Westphal 506a0ae2562SFlorian Westphal lock_sock(sk); 507a0ae2562SFlorian Westphal tuple.src.u3.ip = inet->inet_rcv_saddr; 508a0ae2562SFlorian Westphal tuple.src.u.tcp.port = inet->inet_sport; 509a0ae2562SFlorian Westphal tuple.dst.u3.ip = inet->inet_daddr; 510a0ae2562SFlorian Westphal tuple.dst.u.tcp.port = inet->inet_dport; 511a0ae2562SFlorian Westphal tuple.src.l3num = PF_INET; 512a0ae2562SFlorian Westphal tuple.dst.protonum = sk->sk_protocol; 513a0ae2562SFlorian Westphal release_sock(sk); 514a0ae2562SFlorian Westphal 515a0ae2562SFlorian Westphal /* We only do TCP and SCTP at the moment: is there a better way? */ 516a0ae2562SFlorian Westphal if (tuple.dst.protonum != IPPROTO_TCP && 517a0ae2562SFlorian Westphal tuple.dst.protonum != IPPROTO_SCTP) { 518a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: Not a TCP/SCTP socket\n"); 519a0ae2562SFlorian Westphal return -ENOPROTOOPT; 520a0ae2562SFlorian Westphal } 521a0ae2562SFlorian Westphal 522a0ae2562SFlorian Westphal if ((unsigned int)*len < sizeof(struct sockaddr_in)) { 523a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: len %d not %zu\n", 524a0ae2562SFlorian Westphal *len, sizeof(struct sockaddr_in)); 525a0ae2562SFlorian Westphal return -EINVAL; 526a0ae2562SFlorian Westphal } 527a0ae2562SFlorian Westphal 528a0ae2562SFlorian Westphal h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple); 529a0ae2562SFlorian Westphal if (h) { 530a0ae2562SFlorian Westphal struct sockaddr_in sin; 531a0ae2562SFlorian Westphal struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); 532a0ae2562SFlorian Westphal 533a0ae2562SFlorian Westphal sin.sin_family = AF_INET; 534a0ae2562SFlorian Westphal sin.sin_port = ct->tuplehash[IP_CT_DIR_ORIGINAL] 535a0ae2562SFlorian Westphal .tuple.dst.u.tcp.port; 536a0ae2562SFlorian Westphal sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL] 537a0ae2562SFlorian Westphal .tuple.dst.u3.ip; 538a0ae2562SFlorian Westphal memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); 539a0ae2562SFlorian Westphal 540a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: %pI4 %u\n", 541a0ae2562SFlorian Westphal &sin.sin_addr.s_addr, ntohs(sin.sin_port)); 542a0ae2562SFlorian Westphal nf_ct_put(ct); 543a0ae2562SFlorian Westphal if (copy_to_user(user, &sin, sizeof(sin)) != 0) 544a0ae2562SFlorian Westphal return -EFAULT; 545a0ae2562SFlorian Westphal else 546a0ae2562SFlorian Westphal return 0; 547a0ae2562SFlorian Westphal } 548a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: Can't find %pI4/%u-%pI4/%u.\n", 549a0ae2562SFlorian Westphal &tuple.src.u3.ip, ntohs(tuple.src.u.tcp.port), 550a0ae2562SFlorian Westphal &tuple.dst.u3.ip, ntohs(tuple.dst.u.tcp.port)); 551a0ae2562SFlorian Westphal return -ENOENT; 552a0ae2562SFlorian Westphal } 553a0ae2562SFlorian Westphal 554a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst = { 555a0ae2562SFlorian Westphal .pf = PF_INET, 556a0ae2562SFlorian Westphal .get_optmin = SO_ORIGINAL_DST, 557a0ae2562SFlorian Westphal .get_optmax = SO_ORIGINAL_DST + 1, 558a0ae2562SFlorian Westphal .get = getorigdst, 559a0ae2562SFlorian Westphal .owner = THIS_MODULE, 560a0ae2562SFlorian Westphal }; 561a0ae2562SFlorian Westphal 562a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 563a0ae2562SFlorian Westphal static int 564a0ae2562SFlorian Westphal ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len) 565a0ae2562SFlorian Westphal { 566a0ae2562SFlorian Westphal struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 }; 567a0ae2562SFlorian Westphal const struct ipv6_pinfo *inet6 = inet6_sk(sk); 568a0ae2562SFlorian Westphal const struct inet_sock *inet = inet_sk(sk); 569a0ae2562SFlorian Westphal const struct nf_conntrack_tuple_hash *h; 570a0ae2562SFlorian Westphal struct sockaddr_in6 sin6; 571a0ae2562SFlorian Westphal struct nf_conn *ct; 572a0ae2562SFlorian Westphal __be32 flow_label; 573a0ae2562SFlorian Westphal int bound_dev_if; 574a0ae2562SFlorian Westphal 575a0ae2562SFlorian Westphal lock_sock(sk); 576a0ae2562SFlorian Westphal tuple.src.u3.in6 = sk->sk_v6_rcv_saddr; 577a0ae2562SFlorian Westphal tuple.src.u.tcp.port = inet->inet_sport; 578a0ae2562SFlorian Westphal tuple.dst.u3.in6 = sk->sk_v6_daddr; 579a0ae2562SFlorian Westphal tuple.dst.u.tcp.port = inet->inet_dport; 580a0ae2562SFlorian Westphal tuple.dst.protonum = sk->sk_protocol; 581a0ae2562SFlorian Westphal bound_dev_if = sk->sk_bound_dev_if; 582a0ae2562SFlorian Westphal flow_label = inet6->flow_label; 583a0ae2562SFlorian Westphal release_sock(sk); 584a0ae2562SFlorian Westphal 585a0ae2562SFlorian Westphal if (tuple.dst.protonum != IPPROTO_TCP && 586a0ae2562SFlorian Westphal tuple.dst.protonum != IPPROTO_SCTP) 587a0ae2562SFlorian Westphal return -ENOPROTOOPT; 588a0ae2562SFlorian Westphal 589a0ae2562SFlorian Westphal if (*len < 0 || (unsigned int)*len < sizeof(sin6)) 590a0ae2562SFlorian Westphal return -EINVAL; 591a0ae2562SFlorian Westphal 592a0ae2562SFlorian Westphal h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple); 593a0ae2562SFlorian Westphal if (!h) { 594a0ae2562SFlorian Westphal pr_debug("IP6T_SO_ORIGINAL_DST: Can't find %pI6c/%u-%pI6c/%u.\n", 595a0ae2562SFlorian Westphal &tuple.src.u3.ip6, ntohs(tuple.src.u.tcp.port), 596a0ae2562SFlorian Westphal &tuple.dst.u3.ip6, ntohs(tuple.dst.u.tcp.port)); 597a0ae2562SFlorian Westphal return -ENOENT; 598a0ae2562SFlorian Westphal } 599a0ae2562SFlorian Westphal 600a0ae2562SFlorian Westphal ct = nf_ct_tuplehash_to_ctrack(h); 601a0ae2562SFlorian Westphal 602a0ae2562SFlorian Westphal sin6.sin6_family = AF_INET6; 603a0ae2562SFlorian Westphal sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port; 604a0ae2562SFlorian Westphal sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK; 605a0ae2562SFlorian Westphal memcpy(&sin6.sin6_addr, 606a0ae2562SFlorian Westphal &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6, 607a0ae2562SFlorian Westphal sizeof(sin6.sin6_addr)); 608a0ae2562SFlorian Westphal 609a0ae2562SFlorian Westphal nf_ct_put(ct); 610a0ae2562SFlorian Westphal sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if); 611a0ae2562SFlorian Westphal return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0; 612a0ae2562SFlorian Westphal } 613a0ae2562SFlorian Westphal 614a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst6 = { 615a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 616a0ae2562SFlorian Westphal .get_optmin = IP6T_SO_ORIGINAL_DST, 617a0ae2562SFlorian Westphal .get_optmax = IP6T_SO_ORIGINAL_DST + 1, 618a0ae2562SFlorian Westphal .get = ipv6_getorigdst, 619a0ae2562SFlorian Westphal .owner = THIS_MODULE, 620a0ae2562SFlorian Westphal }; 621a0ae2562SFlorian Westphal 622a0ae2562SFlorian Westphal static unsigned int ipv6_confirm(void *priv, 623a0ae2562SFlorian Westphal struct sk_buff *skb, 624a0ae2562SFlorian Westphal const struct nf_hook_state *state) 625a0ae2562SFlorian Westphal { 626a0ae2562SFlorian Westphal struct nf_conn *ct; 627a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 628a0ae2562SFlorian Westphal unsigned char pnum = ipv6_hdr(skb)->nexthdr; 629a0ae2562SFlorian Westphal int protoff; 630a0ae2562SFlorian Westphal __be16 frag_off; 631a0ae2562SFlorian Westphal 632a0ae2562SFlorian Westphal ct = nf_ct_get(skb, &ctinfo); 633a0ae2562SFlorian Westphal if (!ct || ctinfo == IP_CT_RELATED_REPLY) 634a0ae2562SFlorian Westphal goto out; 635a0ae2562SFlorian Westphal 636a0ae2562SFlorian Westphal protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum, 637a0ae2562SFlorian Westphal &frag_off); 638a0ae2562SFlorian Westphal if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { 639a0ae2562SFlorian Westphal pr_debug("proto header not found\n"); 640a0ae2562SFlorian Westphal goto out; 641a0ae2562SFlorian Westphal } 642a0ae2562SFlorian Westphal 643a0ae2562SFlorian Westphal /* adjust seqs for loopback traffic only in outgoing direction */ 644a0ae2562SFlorian Westphal if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && 645a0ae2562SFlorian Westphal !nf_is_loopback_packet(skb)) { 646a0ae2562SFlorian Westphal if (!nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) { 647a0ae2562SFlorian Westphal NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); 648a0ae2562SFlorian Westphal return NF_DROP; 649a0ae2562SFlorian Westphal } 650a0ae2562SFlorian Westphal } 651a0ae2562SFlorian Westphal out: 652a0ae2562SFlorian Westphal /* We've seen it coming out the other side: confirm it */ 653a0ae2562SFlorian Westphal return nf_conntrack_confirm(skb); 654a0ae2562SFlorian Westphal } 655a0ae2562SFlorian Westphal 656a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_in(void *priv, 657a0ae2562SFlorian Westphal struct sk_buff *skb, 658a0ae2562SFlorian Westphal const struct nf_hook_state *state) 659a0ae2562SFlorian Westphal { 66093e66024SFlorian Westphal return nf_conntrack_in(skb, state); 661a0ae2562SFlorian Westphal } 662a0ae2562SFlorian Westphal 663a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_local(void *priv, 664a0ae2562SFlorian Westphal struct sk_buff *skb, 665a0ae2562SFlorian Westphal const struct nf_hook_state *state) 666a0ae2562SFlorian Westphal { 66793e66024SFlorian Westphal return nf_conntrack_in(skb, state); 668a0ae2562SFlorian Westphal } 669a0ae2562SFlorian Westphal 670a0ae2562SFlorian Westphal static unsigned int ipv6_helper(void *priv, 671a0ae2562SFlorian Westphal struct sk_buff *skb, 672a0ae2562SFlorian Westphal const struct nf_hook_state *state) 673a0ae2562SFlorian Westphal { 674a0ae2562SFlorian Westphal struct nf_conn *ct; 675a0ae2562SFlorian Westphal const struct nf_conn_help *help; 676a0ae2562SFlorian Westphal const struct nf_conntrack_helper *helper; 677a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 678a0ae2562SFlorian Westphal __be16 frag_off; 679a0ae2562SFlorian Westphal int protoff; 680a0ae2562SFlorian Westphal u8 nexthdr; 681a0ae2562SFlorian Westphal 682a0ae2562SFlorian Westphal /* This is where we call the helper: as the packet goes out. */ 683a0ae2562SFlorian Westphal ct = nf_ct_get(skb, &ctinfo); 684a0ae2562SFlorian Westphal if (!ct || ctinfo == IP_CT_RELATED_REPLY) 685a0ae2562SFlorian Westphal return NF_ACCEPT; 686a0ae2562SFlorian Westphal 687a0ae2562SFlorian Westphal help = nfct_help(ct); 688a0ae2562SFlorian Westphal if (!help) 689a0ae2562SFlorian Westphal return NF_ACCEPT; 690a0ae2562SFlorian Westphal /* rcu_read_lock()ed by nf_hook_thresh */ 691a0ae2562SFlorian Westphal helper = rcu_dereference(help->helper); 692a0ae2562SFlorian Westphal if (!helper) 693a0ae2562SFlorian Westphal return NF_ACCEPT; 694a0ae2562SFlorian Westphal 695a0ae2562SFlorian Westphal nexthdr = ipv6_hdr(skb)->nexthdr; 696a0ae2562SFlorian Westphal protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, 697a0ae2562SFlorian Westphal &frag_off); 698a0ae2562SFlorian Westphal if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { 699a0ae2562SFlorian Westphal pr_debug("proto header not found\n"); 700a0ae2562SFlorian Westphal return NF_ACCEPT; 701a0ae2562SFlorian Westphal } 702a0ae2562SFlorian Westphal 703a0ae2562SFlorian Westphal return helper->help(skb, protoff, ct, ctinfo); 704a0ae2562SFlorian Westphal } 705a0ae2562SFlorian Westphal 706a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv6_conntrack_ops[] = { 707a0ae2562SFlorian Westphal { 708a0ae2562SFlorian Westphal .hook = ipv6_conntrack_in, 709a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 710a0ae2562SFlorian Westphal .hooknum = NF_INET_PRE_ROUTING, 711a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK, 712a0ae2562SFlorian Westphal }, 713a0ae2562SFlorian Westphal { 714a0ae2562SFlorian Westphal .hook = ipv6_conntrack_local, 715a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 716a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_OUT, 717a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK, 718a0ae2562SFlorian Westphal }, 719a0ae2562SFlorian Westphal { 720a0ae2562SFlorian Westphal .hook = ipv6_helper, 721a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 722a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING, 723a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK_HELPER, 724a0ae2562SFlorian Westphal }, 725a0ae2562SFlorian Westphal { 726a0ae2562SFlorian Westphal .hook = ipv6_confirm, 727a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 728a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING, 729a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_LAST, 730a0ae2562SFlorian Westphal }, 731a0ae2562SFlorian Westphal { 732a0ae2562SFlorian Westphal .hook = ipv6_helper, 733a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 734a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN, 735a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK_HELPER, 736a0ae2562SFlorian Westphal }, 737a0ae2562SFlorian Westphal { 738a0ae2562SFlorian Westphal .hook = ipv6_confirm, 739a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 740a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN, 741a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_LAST - 1, 742a0ae2562SFlorian Westphal }, 743a0ae2562SFlorian Westphal }; 744a0ae2562SFlorian Westphal #endif 745a0ae2562SFlorian Westphal 746f94e6380SFlorian Westphal static int nf_ct_tcp_fixup(struct nf_conn *ct, void *_nfproto) 747f94e6380SFlorian Westphal { 748f94e6380SFlorian Westphal u8 nfproto = (unsigned long)_nfproto; 749f94e6380SFlorian Westphal 750f94e6380SFlorian Westphal if (nf_ct_l3num(ct) != nfproto) 751f94e6380SFlorian Westphal return 0; 752f94e6380SFlorian Westphal 753f94e6380SFlorian Westphal if (nf_ct_protonum(ct) == IPPROTO_TCP && 754f94e6380SFlorian Westphal ct->proto.tcp.state == TCP_CONNTRACK_ESTABLISHED) { 755f94e6380SFlorian Westphal ct->proto.tcp.seen[0].td_maxwin = 0; 756f94e6380SFlorian Westphal ct->proto.tcp.seen[1].td_maxwin = 0; 757f94e6380SFlorian Westphal } 758f94e6380SFlorian Westphal 759f94e6380SFlorian Westphal return 0; 760f94e6380SFlorian Westphal } 761f94e6380SFlorian Westphal 762a0ae2562SFlorian Westphal static int nf_ct_netns_do_get(struct net *net, u8 nfproto) 763a0ae2562SFlorian Westphal { 764a0ae2562SFlorian Westphal struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); 765f94e6380SFlorian Westphal bool fixup_needed = false; 766a0ae2562SFlorian Westphal int err = 0; 767a0ae2562SFlorian Westphal 768a0ae2562SFlorian Westphal mutex_lock(&nf_ct_proto_mutex); 769a0ae2562SFlorian Westphal 770a0ae2562SFlorian Westphal switch (nfproto) { 771a0ae2562SFlorian Westphal case NFPROTO_IPV4: 772a0ae2562SFlorian Westphal cnet->users4++; 773a0ae2562SFlorian Westphal if (cnet->users4 > 1) 774a0ae2562SFlorian Westphal goto out_unlock; 775a0ae2562SFlorian Westphal err = nf_defrag_ipv4_enable(net); 776a0ae2562SFlorian Westphal if (err) { 777a0ae2562SFlorian Westphal cnet->users4 = 0; 778a0ae2562SFlorian Westphal goto out_unlock; 779a0ae2562SFlorian Westphal } 780a0ae2562SFlorian Westphal 781a0ae2562SFlorian Westphal err = nf_register_net_hooks(net, ipv4_conntrack_ops, 782a0ae2562SFlorian Westphal ARRAY_SIZE(ipv4_conntrack_ops)); 783a0ae2562SFlorian Westphal if (err) 784a0ae2562SFlorian Westphal cnet->users4 = 0; 785f94e6380SFlorian Westphal else 786f94e6380SFlorian Westphal fixup_needed = true; 787a0ae2562SFlorian Westphal break; 788a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 789a0ae2562SFlorian Westphal case NFPROTO_IPV6: 790a0ae2562SFlorian Westphal cnet->users6++; 791a0ae2562SFlorian Westphal if (cnet->users6 > 1) 792a0ae2562SFlorian Westphal goto out_unlock; 793a0ae2562SFlorian Westphal err = nf_defrag_ipv6_enable(net); 794a0ae2562SFlorian Westphal if (err < 0) { 795a0ae2562SFlorian Westphal cnet->users6 = 0; 796a0ae2562SFlorian Westphal goto out_unlock; 797a0ae2562SFlorian Westphal } 798a0ae2562SFlorian Westphal 799a0ae2562SFlorian Westphal err = nf_register_net_hooks(net, ipv6_conntrack_ops, 800a0ae2562SFlorian Westphal ARRAY_SIZE(ipv6_conntrack_ops)); 801a0ae2562SFlorian Westphal if (err) 802a0ae2562SFlorian Westphal cnet->users6 = 0; 803f94e6380SFlorian Westphal else 804f94e6380SFlorian Westphal fixup_needed = true; 805a0ae2562SFlorian Westphal break; 806a0ae2562SFlorian Westphal #endif 807a0ae2562SFlorian Westphal default: 808a0ae2562SFlorian Westphal err = -EPROTO; 809a0ae2562SFlorian Westphal break; 810a0ae2562SFlorian Westphal } 811a0ae2562SFlorian Westphal out_unlock: 812a0ae2562SFlorian Westphal mutex_unlock(&nf_ct_proto_mutex); 813f94e6380SFlorian Westphal 814f94e6380SFlorian Westphal if (fixup_needed) 815f94e6380SFlorian Westphal nf_ct_iterate_cleanup_net(net, nf_ct_tcp_fixup, 816f94e6380SFlorian Westphal (void *)(unsigned long)nfproto, 0, 0); 817f94e6380SFlorian Westphal 818a0ae2562SFlorian Westphal return err; 819a0ae2562SFlorian Westphal } 820a0ae2562SFlorian Westphal 821a0ae2562SFlorian Westphal static void nf_ct_netns_do_put(struct net *net, u8 nfproto) 822a0ae2562SFlorian Westphal { 823a0ae2562SFlorian Westphal struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); 824a0ae2562SFlorian Westphal 825a0ae2562SFlorian Westphal mutex_lock(&nf_ct_proto_mutex); 826a0ae2562SFlorian Westphal switch (nfproto) { 827a0ae2562SFlorian Westphal case NFPROTO_IPV4: 828a0ae2562SFlorian Westphal if (cnet->users4 && (--cnet->users4 == 0)) 829a0ae2562SFlorian Westphal nf_unregister_net_hooks(net, ipv4_conntrack_ops, 830a0ae2562SFlorian Westphal ARRAY_SIZE(ipv4_conntrack_ops)); 831a0ae2562SFlorian Westphal break; 832a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 833a0ae2562SFlorian Westphal case NFPROTO_IPV6: 834a0ae2562SFlorian Westphal if (cnet->users6 && (--cnet->users6 == 0)) 835a0ae2562SFlorian Westphal nf_unregister_net_hooks(net, ipv6_conntrack_ops, 836a0ae2562SFlorian Westphal ARRAY_SIZE(ipv6_conntrack_ops)); 837a0ae2562SFlorian Westphal break; 838a0ae2562SFlorian Westphal #endif 839a0ae2562SFlorian Westphal } 840a0ae2562SFlorian Westphal 841a0ae2562SFlorian Westphal mutex_unlock(&nf_ct_proto_mutex); 842a0ae2562SFlorian Westphal } 843a0ae2562SFlorian Westphal 844a0ae2562SFlorian Westphal int nf_ct_netns_get(struct net *net, u8 nfproto) 845a0ae2562SFlorian Westphal { 846a0ae2562SFlorian Westphal int err; 847a0ae2562SFlorian Westphal 848a0ae2562SFlorian Westphal if (nfproto == NFPROTO_INET) { 849a0ae2562SFlorian Westphal err = nf_ct_netns_do_get(net, NFPROTO_IPV4); 850a0ae2562SFlorian Westphal if (err < 0) 851a0ae2562SFlorian Westphal goto err1; 852a0ae2562SFlorian Westphal err = nf_ct_netns_do_get(net, NFPROTO_IPV6); 853a0ae2562SFlorian Westphal if (err < 0) 854a0ae2562SFlorian Westphal goto err2; 855a0ae2562SFlorian Westphal } else { 856a0ae2562SFlorian Westphal err = nf_ct_netns_do_get(net, nfproto); 857a0ae2562SFlorian Westphal if (err < 0) 858a0ae2562SFlorian Westphal goto err1; 859a0ae2562SFlorian Westphal } 860a0ae2562SFlorian Westphal return 0; 861a0ae2562SFlorian Westphal 862a0ae2562SFlorian Westphal err2: 863a0ae2562SFlorian Westphal nf_ct_netns_put(net, NFPROTO_IPV4); 864a0ae2562SFlorian Westphal err1: 865a0ae2562SFlorian Westphal return err; 866a0ae2562SFlorian Westphal } 867a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_get); 868a0ae2562SFlorian Westphal 869a0ae2562SFlorian Westphal void nf_ct_netns_put(struct net *net, uint8_t nfproto) 870a0ae2562SFlorian Westphal { 871a0ae2562SFlorian Westphal if (nfproto == NFPROTO_INET) { 872a0ae2562SFlorian Westphal nf_ct_netns_do_put(net, NFPROTO_IPV4); 873a0ae2562SFlorian Westphal nf_ct_netns_do_put(net, NFPROTO_IPV6); 874a0ae2562SFlorian Westphal } else { 875a0ae2562SFlorian Westphal nf_ct_netns_do_put(net, nfproto); 876a0ae2562SFlorian Westphal } 877a0ae2562SFlorian Westphal } 878a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_put); 879a0ae2562SFlorian Westphal 880a0ae2562SFlorian Westphal static const struct nf_conntrack_l4proto * const builtin_l4proto[] = { 881dd2934a9SFlorian Westphal &nf_conntrack_l4proto_tcp, 882dd2934a9SFlorian Westphal &nf_conntrack_l4proto_udp, 883a0ae2562SFlorian Westphal &nf_conntrack_l4proto_icmp, 884a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_DCCP 885dd2934a9SFlorian Westphal &nf_conntrack_l4proto_dccp, 886a0ae2562SFlorian Westphal #endif 887a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_SCTP 888dd2934a9SFlorian Westphal &nf_conntrack_l4proto_sctp, 889a0ae2562SFlorian Westphal #endif 890a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_UDPLITE 891dd2934a9SFlorian Westphal &nf_conntrack_l4proto_udplite, 892a0ae2562SFlorian Westphal #endif 893a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 894a0ae2562SFlorian Westphal &nf_conntrack_l4proto_icmpv6, 895a0ae2562SFlorian Westphal #endif /* CONFIG_IPV6 */ 896a0ae2562SFlorian Westphal }; 897a0ae2562SFlorian Westphal 898a0ae2562SFlorian Westphal int nf_conntrack_proto_init(void) 899a0ae2562SFlorian Westphal { 900dd2934a9SFlorian Westphal int ret = 0, i; 901a0ae2562SFlorian Westphal 902a0ae2562SFlorian Westphal ret = nf_register_sockopt(&so_getorigdst); 903a0ae2562SFlorian Westphal if (ret < 0) 904a0ae2562SFlorian Westphal return ret; 905a0ae2562SFlorian Westphal 906a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 907a0ae2562SFlorian Westphal ret = nf_register_sockopt(&so_getorigdst6); 908a0ae2562SFlorian Westphal if (ret < 0) 909a0ae2562SFlorian Westphal goto cleanup_sockopt; 910a0ae2562SFlorian Westphal #endif 911dd2934a9SFlorian Westphal 912dd2934a9SFlorian Westphal for (i = 0; i < ARRAY_SIZE(nf_ct_protos); i++) 913dd2934a9SFlorian Westphal RCU_INIT_POINTER(nf_ct_protos[i], 914dd2934a9SFlorian Westphal &nf_conntrack_l4proto_generic); 915dd2934a9SFlorian Westphal 916a0ae2562SFlorian Westphal ret = nf_ct_l4proto_register(builtin_l4proto, 917a0ae2562SFlorian Westphal ARRAY_SIZE(builtin_l4proto)); 918a0ae2562SFlorian Westphal if (ret < 0) 919a0ae2562SFlorian Westphal goto cleanup_sockopt2; 920a0ae2562SFlorian Westphal 921a0ae2562SFlorian Westphal return ret; 922a0ae2562SFlorian Westphal cleanup_sockopt2: 923a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst); 924a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 925a0ae2562SFlorian Westphal cleanup_sockopt: 926a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst6); 927a0ae2562SFlorian Westphal #endif 928a0ae2562SFlorian Westphal return ret; 929a0ae2562SFlorian Westphal } 930a0ae2562SFlorian Westphal 931a0ae2562SFlorian Westphal void nf_conntrack_proto_fini(void) 932a0ae2562SFlorian Westphal { 933a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst); 934a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 935a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst6); 936a0ae2562SFlorian Westphal #endif 937a0ae2562SFlorian Westphal } 938a0ae2562SFlorian Westphal 93904d87001SGao feng int nf_conntrack_proto_pernet_init(struct net *net) 940ac5357ebSPatrick McHardy { 941ac5357ebSPatrick McHardy int err; 942fa34fff5SGao feng struct nf_proto_net *pn = nf_ct_l4proto_net(net, 943fa34fff5SGao feng &nf_conntrack_l4proto_generic); 944fa34fff5SGao feng 945ca2ca6e1SFlorian Westphal err = nf_conntrack_l4proto_generic.init_net(net); 94615f585bdSGao feng if (err < 0) 94715f585bdSGao feng return err; 94815f585bdSGao feng err = nf_ct_l4proto_register_sysctl(net, 949fa34fff5SGao feng pn, 95015f585bdSGao feng &nf_conntrack_l4proto_generic); 951ac5357ebSPatrick McHardy if (err < 0) 952ac5357ebSPatrick McHardy return err; 953ac5357ebSPatrick McHardy 954a0ae2562SFlorian Westphal err = nf_ct_l4proto_pernet_register(net, builtin_l4proto, 955a0ae2562SFlorian Westphal ARRAY_SIZE(builtin_l4proto)); 956a0ae2562SFlorian Westphal if (err < 0) { 957a0ae2562SFlorian Westphal nf_ct_l4proto_unregister_sysctl(net, pn, 958a0ae2562SFlorian Westphal &nf_conntrack_l4proto_generic); 959a0ae2562SFlorian Westphal return err; 960a0ae2562SFlorian Westphal } 961a0ae2562SFlorian Westphal 962fa34fff5SGao feng pn->users++; 963ac5357ebSPatrick McHardy return 0; 964ac5357ebSPatrick McHardy } 965ac5357ebSPatrick McHardy 96604d87001SGao feng void nf_conntrack_proto_pernet_fini(struct net *net) 967ac5357ebSPatrick McHardy { 968fa34fff5SGao feng struct nf_proto_net *pn = nf_ct_l4proto_net(net, 969fa34fff5SGao feng &nf_conntrack_l4proto_generic); 970fa34fff5SGao feng 971a0ae2562SFlorian Westphal nf_ct_l4proto_pernet_unregister(net, builtin_l4proto, 972a0ae2562SFlorian Westphal ARRAY_SIZE(builtin_l4proto)); 973fa34fff5SGao feng pn->users--; 97415f585bdSGao feng nf_ct_l4proto_unregister_sysctl(net, 975fa34fff5SGao feng pn, 97615f585bdSGao feng &nf_conntrack_l4proto_generic); 97704d87001SGao feng } 97804d87001SGao feng 97904d87001SGao feng 980a0ae2562SFlorian Westphal module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, 981a0ae2562SFlorian Westphal &nf_conntrack_htable_size, 0600); 982a0ae2562SFlorian Westphal 983a0ae2562SFlorian Westphal MODULE_ALIAS("ip_conntrack"); 984a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET)); 985a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); 986a0ae2562SFlorian Westphal MODULE_LICENSE("GPL"); 987