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 46b7b5fda4SFlorian Westphal static struct nf_conntrack_l4proto __rcu **nf_ct_protos[NFPROTO_NUMPROTO] __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 127b3480fe0SFlorian Westphal const struct nf_conntrack_l4proto * 128605dcad6SMartin Josefsson __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto) 1298f03dea5SMartin Josefsson { 130b7b5fda4SFlorian Westphal if (unlikely(l3proto >= NFPROTO_NUMPROTO || nf_ct_protos[l3proto] == NULL)) 131605dcad6SMartin Josefsson return &nf_conntrack_l4proto_generic; 1328f03dea5SMartin Josefsson 133923f4902SPatrick McHardy return rcu_dereference(nf_ct_protos[l3proto][l4proto]); 1348f03dea5SMartin Josefsson } 13513b18339SPatrick McHardy EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find); 1368f03dea5SMartin Josefsson 137b3480fe0SFlorian Westphal const struct nf_conntrack_l4proto * 138c1ebd7dfSPablo Neira Ayuso nf_ct_l4proto_find_get(u_int16_t l3num, u_int8_t l4num) 139c1ebd7dfSPablo Neira Ayuso { 140b3480fe0SFlorian Westphal const struct nf_conntrack_l4proto *p; 141c1ebd7dfSPablo Neira Ayuso 142c1ebd7dfSPablo Neira Ayuso rcu_read_lock(); 143c1ebd7dfSPablo Neira Ayuso p = __nf_ct_l4proto_find(l3num, l4num); 144c1ebd7dfSPablo Neira Ayuso if (!try_module_get(p->me)) 145c1ebd7dfSPablo Neira Ayuso p = &nf_conntrack_l4proto_generic; 146c1ebd7dfSPablo Neira Ayuso rcu_read_unlock(); 147c1ebd7dfSPablo Neira Ayuso 148c1ebd7dfSPablo Neira Ayuso return p; 149c1ebd7dfSPablo Neira Ayuso } 150c1ebd7dfSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get); 151c1ebd7dfSPablo Neira Ayuso 1522a04aabfSJulia Lawall void nf_ct_l4proto_put(const struct nf_conntrack_l4proto *p) 153c1ebd7dfSPablo Neira Ayuso { 154c1ebd7dfSPablo Neira Ayuso module_put(p->me); 155c1ebd7dfSPablo Neira Ayuso } 156c1ebd7dfSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_l4proto_put); 157c1ebd7dfSPablo Neira Ayuso 158605dcad6SMartin Josefsson static int kill_l4proto(struct nf_conn *i, void *data) 1598f03dea5SMartin Josefsson { 160b3480fe0SFlorian Westphal const struct nf_conntrack_l4proto *l4proto; 16168ad546aSsimran singhal l4proto = data; 1625e8fbe2aSPatrick McHardy return nf_ct_protonum(i) == l4proto->l4proto && 1635e8fbe2aSPatrick McHardy nf_ct_l3num(i) == l4proto->l3proto; 1648f03dea5SMartin Josefsson } 1658f03dea5SMartin Josefsson 1662c352f44SGao feng static struct nf_proto_net *nf_ct_l4proto_net(struct net *net, 1672a04aabfSJulia Lawall const struct nf_conntrack_l4proto *l4proto) 1682c352f44SGao feng { 16908911475SPablo Neira Ayuso if (l4proto->get_net_proto) { 17008911475SPablo Neira Ayuso /* statically built-in protocols use static per-net */ 17108911475SPablo Neira Ayuso return l4proto->get_net_proto(net); 17208911475SPablo Neira Ayuso } else if (l4proto->net_id) { 17308911475SPablo Neira Ayuso /* ... and loadable protocols use dynamic per-net */ 1742c352f44SGao feng return net_generic(net, *l4proto->net_id); 1752c352f44SGao feng } 17615f585bdSGao feng return NULL; 17715f585bdSGao feng } 1782c352f44SGao feng 1792c352f44SGao feng static 1802c352f44SGao feng int nf_ct_l4proto_register_sysctl(struct net *net, 181fa34fff5SGao feng struct nf_proto_net *pn, 1822a04aabfSJulia Lawall const struct nf_conntrack_l4proto *l4proto) 183d62f9ed4SPatrick McHardy { 184d62f9ed4SPatrick McHardy int err = 0; 185d62f9ed4SPatrick McHardy 186d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 1872c352f44SGao feng if (pn->ctl_table != NULL) { 1882c352f44SGao feng err = nf_ct_register_sysctl(net, 1892c352f44SGao feng &pn->ctl_table_header, 190f99e8f71SEric W. Biederman "net/netfilter", 191fa34fff5SGao feng pn->ctl_table); 1922c352f44SGao feng if (err < 0) { 1932c352f44SGao feng if (!pn->users) { 1942c352f44SGao feng kfree(pn->ctl_table); 1952c352f44SGao feng pn->ctl_table = NULL; 1962c352f44SGao feng } 197d62f9ed4SPatrick McHardy } 1982c352f44SGao feng } 199933a41e7SPatrick McHardy #endif /* CONFIG_SYSCTL */ 200d62f9ed4SPatrick McHardy return err; 201d62f9ed4SPatrick McHardy } 202d62f9ed4SPatrick McHardy 2032c352f44SGao feng static 2042c352f44SGao feng void nf_ct_l4proto_unregister_sysctl(struct net *net, 205fa34fff5SGao feng struct nf_proto_net *pn, 2062a04aabfSJulia Lawall const struct nf_conntrack_l4proto *l4proto) 207d62f9ed4SPatrick McHardy { 208d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 2092c352f44SGao feng if (pn->ctl_table_header != NULL) 2102c352f44SGao feng nf_ct_unregister_sysctl(&pn->ctl_table_header, 2112c352f44SGao feng &pn->ctl_table, 212fa34fff5SGao feng pn->users); 213933a41e7SPatrick McHardy #endif /* CONFIG_SYSCTL */ 214d62f9ed4SPatrick McHardy } 215d62f9ed4SPatrick McHardy 2168f03dea5SMartin Josefsson /* FIXME: Allow NULL functions and sub in pointers to generic for 2178f03dea5SMartin Josefsson them. --RR */ 218cd9ceafcSFlorian Westphal int nf_ct_l4proto_register_one(const struct nf_conntrack_l4proto *l4proto) 2198f03dea5SMartin Josefsson { 2208f03dea5SMartin Josefsson int ret = 0; 2218f03dea5SMartin Josefsson 222b7b5fda4SFlorian Westphal if (l4proto->l3proto >= ARRAY_SIZE(nf_ct_protos)) 2230661cca9SPatrick McHardy return -EBUSY; 224ae5718fbSMartin Josefsson 22539215846SFlorian Westphal if ((l4proto->to_nlattr && l4proto->nlattr_size == 0) || 2260e54d217SDavide Caratti (l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size)) 227d0dba725SHolger Eitzenberger return -EINVAL; 228d0dba725SHolger Eitzenberger 229b19caa0cSPatrick McHardy mutex_lock(&nf_ct_proto_mutex); 230c6a1e615SPatrick McHardy if (!nf_ct_protos[l4proto->l3proto]) { 2318f03dea5SMartin Josefsson /* l3proto may be loaded latter. */ 232c5d277d2SEric Dumazet struct nf_conntrack_l4proto __rcu **proto_array; 2338f03dea5SMartin Josefsson int i; 2348f03dea5SMartin Josefsson 2356da2ec56SKees Cook proto_array = 2366da2ec56SKees Cook kmalloc_array(MAX_NF_CT_PROTO, 237605dcad6SMartin Josefsson sizeof(struct nf_conntrack_l4proto *), 2388f03dea5SMartin Josefsson GFP_KERNEL); 2398f03dea5SMartin Josefsson if (proto_array == NULL) { 2408f03dea5SMartin Josefsson ret = -ENOMEM; 241b19caa0cSPatrick McHardy goto out_unlock; 2428f03dea5SMartin Josefsson } 243c6a1e615SPatrick McHardy 2448f03dea5SMartin Josefsson for (i = 0; i < MAX_NF_CT_PROTO; i++) 2450e54d217SDavide Caratti RCU_INIT_POINTER(proto_array[i], 2460e54d217SDavide Caratti &nf_conntrack_l4proto_generic); 247d817d29dSEric Dumazet 248d817d29dSEric Dumazet /* Before making proto_array visible to lockless readers, 249d817d29dSEric Dumazet * we must make sure its content is committed to memory. 250d817d29dSEric Dumazet */ 251d817d29dSEric Dumazet smp_wmb(); 252d817d29dSEric Dumazet 253605dcad6SMartin Josefsson nf_ct_protos[l4proto->l3proto] = proto_array; 2540e60ebe0SEric Dumazet } else if (rcu_dereference_protected( 2550e60ebe0SEric Dumazet nf_ct_protos[l4proto->l3proto][l4proto->l4proto], 2560e60ebe0SEric Dumazet lockdep_is_held(&nf_ct_proto_mutex) 2570e60ebe0SEric Dumazet ) != &nf_conntrack_l4proto_generic) { 258c6a1e615SPatrick McHardy ret = -EBUSY; 259c6a1e615SPatrick McHardy goto out_unlock; 2608f03dea5SMartin Josefsson } 2618f03dea5SMartin Josefsson 262c6a1e615SPatrick McHardy rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], 263c6a1e615SPatrick McHardy l4proto); 2648f03dea5SMartin Josefsson out_unlock: 265b19caa0cSPatrick McHardy mutex_unlock(&nf_ct_proto_mutex); 2668f03dea5SMartin Josefsson return ret; 2678f03dea5SMartin Josefsson } 2680e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_register_one); 2692c352f44SGao feng 2700e54d217SDavide Caratti int nf_ct_l4proto_pernet_register_one(struct net *net, 2712a04aabfSJulia Lawall const struct nf_conntrack_l4proto *l4proto) 2722c352f44SGao feng { 2732c352f44SGao feng int ret = 0; 274fa34fff5SGao feng struct nf_proto_net *pn = NULL; 2752c352f44SGao feng 276fa0f61f0SGao feng if (l4proto->init_net) { 277f1caad27SGao feng ret = l4proto->init_net(net, l4proto->l3proto); 278fa0f61f0SGao feng if (ret < 0) 279fa34fff5SGao feng goto out; 280fa0f61f0SGao feng } 2812c352f44SGao feng 282fa34fff5SGao feng pn = nf_ct_l4proto_net(net, l4proto); 283fa34fff5SGao feng if (pn == NULL) 284fa34fff5SGao feng goto out; 285fa34fff5SGao feng 286fa34fff5SGao feng ret = nf_ct_l4proto_register_sysctl(net, pn, l4proto); 2872c352f44SGao feng if (ret < 0) 288fa34fff5SGao feng goto out; 2892c352f44SGao feng 290fa34fff5SGao feng pn->users++; 291fa34fff5SGao feng out: 292fa0f61f0SGao feng return ret; 2932c352f44SGao feng } 2940e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register_one); 2958f03dea5SMartin Josefsson 2962a04aabfSJulia Lawall static void __nf_ct_l4proto_unregister_one(const struct nf_conntrack_l4proto *l4proto) 2972c41f33cSFlorian Westphal 2988f03dea5SMartin Josefsson { 299b7b5fda4SFlorian Westphal BUG_ON(l4proto->l3proto >= ARRAY_SIZE(nf_ct_protos)); 300ae5718fbSMartin Josefsson 3010e60ebe0SEric Dumazet BUG_ON(rcu_dereference_protected( 3020e60ebe0SEric Dumazet nf_ct_protos[l4proto->l3proto][l4proto->l4proto], 3030e60ebe0SEric Dumazet lockdep_is_held(&nf_ct_proto_mutex) 3040e60ebe0SEric Dumazet ) != l4proto); 305923f4902SPatrick McHardy rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], 306923f4902SPatrick McHardy &nf_conntrack_l4proto_generic); 3072c41f33cSFlorian Westphal } 3082c41f33cSFlorian Westphal 3092a04aabfSJulia Lawall void nf_ct_l4proto_unregister_one(const struct nf_conntrack_l4proto *l4proto) 3102c41f33cSFlorian Westphal { 3112c41f33cSFlorian Westphal mutex_lock(&nf_ct_proto_mutex); 3122c41f33cSFlorian Westphal __nf_ct_l4proto_unregister_one(l4proto); 3130661cca9SPatrick McHardy mutex_unlock(&nf_ct_proto_mutex); 3140661cca9SPatrick McHardy 3151c117d3bSFlorian Westphal synchronize_net(); 3161c117d3bSFlorian Westphal /* Remove all contrack entries for this protocol */ 3171c117d3bSFlorian Westphal nf_ct_iterate_destroy(kill_l4proto, (void *)l4proto); 3182c352f44SGao feng } 3190e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_unregister_one); 320d62f9ed4SPatrick McHardy 3210e54d217SDavide Caratti void nf_ct_l4proto_pernet_unregister_one(struct net *net, 3222a04aabfSJulia Lawall const struct nf_conntrack_l4proto *l4proto) 3232c352f44SGao feng { 324809c2d9aSAaron Conole struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto); 325fa34fff5SGao feng 326fa34fff5SGao feng if (pn == NULL) 327fa34fff5SGao feng return; 328fa34fff5SGao feng 329fa34fff5SGao feng pn->users--; 330fa34fff5SGao feng nf_ct_l4proto_unregister_sysctl(net, pn, l4proto); 3318f03dea5SMartin Josefsson } 3320e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_unregister_one); 3330e54d217SDavide Caratti 334a0ae2562SFlorian Westphal static void 335a0ae2562SFlorian Westphal nf_ct_l4proto_unregister(const struct nf_conntrack_l4proto * const l4proto[], 336a0ae2562SFlorian Westphal unsigned int num_proto) 337a0ae2562SFlorian Westphal { 3381c117d3bSFlorian Westphal int i; 3391c117d3bSFlorian Westphal 340a0ae2562SFlorian Westphal mutex_lock(&nf_ct_proto_mutex); 3411c117d3bSFlorian Westphal for (i = 0; i < num_proto; i++) 3421c117d3bSFlorian Westphal __nf_ct_l4proto_unregister_one(l4proto[i]); 343a0ae2562SFlorian Westphal mutex_unlock(&nf_ct_proto_mutex); 344a0ae2562SFlorian Westphal 345a0ae2562SFlorian Westphal synchronize_net(); 3461c117d3bSFlorian Westphal 3471c117d3bSFlorian Westphal for (i = 0; i < num_proto; i++) 3481c117d3bSFlorian Westphal nf_ct_iterate_destroy(kill_l4proto, (void *)l4proto[i]); 349a0ae2562SFlorian Westphal } 350a0ae2562SFlorian Westphal 351a0ae2562SFlorian Westphal static int 352a0ae2562SFlorian Westphal nf_ct_l4proto_register(const struct nf_conntrack_l4proto * const l4proto[], 3530e54d217SDavide Caratti unsigned int num_proto) 3540e54d217SDavide Caratti { 3550e54d217SDavide Caratti int ret = -EINVAL, ver; 3560e54d217SDavide Caratti unsigned int i; 3570e54d217SDavide Caratti 3580e54d217SDavide Caratti for (i = 0; i < num_proto; i++) { 3590e54d217SDavide Caratti ret = nf_ct_l4proto_register_one(l4proto[i]); 3600e54d217SDavide Caratti if (ret < 0) 3610e54d217SDavide Caratti break; 3620e54d217SDavide Caratti } 3630e54d217SDavide Caratti if (i != num_proto) { 3640e54d217SDavide Caratti ver = l4proto[i]->l3proto == PF_INET6 ? 6 : 4; 36509ec82f5SFlorian Westphal pr_err("nf_conntrack_ipv%d: can't register l4 %d proto.\n", 36609ec82f5SFlorian Westphal ver, l4proto[i]->l4proto); 3670e54d217SDavide Caratti nf_ct_l4proto_unregister(l4proto, i); 3680e54d217SDavide Caratti } 3690e54d217SDavide Caratti return ret; 3700e54d217SDavide Caratti } 3710e54d217SDavide Caratti 3720e54d217SDavide Caratti int nf_ct_l4proto_pernet_register(struct net *net, 373cd9ceafcSFlorian Westphal const struct nf_conntrack_l4proto *const l4proto[], 3740e54d217SDavide Caratti unsigned int num_proto) 3750e54d217SDavide Caratti { 3760e54d217SDavide Caratti int ret = -EINVAL; 3770e54d217SDavide Caratti unsigned int i; 3780e54d217SDavide Caratti 3790e54d217SDavide Caratti for (i = 0; i < num_proto; i++) { 3800e54d217SDavide Caratti ret = nf_ct_l4proto_pernet_register_one(net, l4proto[i]); 3810e54d217SDavide Caratti if (ret < 0) 3820e54d217SDavide Caratti break; 3830e54d217SDavide Caratti } 3840e54d217SDavide Caratti if (i != num_proto) { 38509ec82f5SFlorian Westphal pr_err("nf_conntrack_proto_%d %d: pernet registration failed\n", 38609ec82f5SFlorian Westphal l4proto[i]->l4proto, 3870e54d217SDavide Caratti l4proto[i]->l3proto == PF_INET6 ? 6 : 4); 3880e54d217SDavide Caratti nf_ct_l4proto_pernet_unregister(net, l4proto, i); 3890e54d217SDavide Caratti } 3900e54d217SDavide Caratti return ret; 3910e54d217SDavide Caratti } 3920e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register); 3930e54d217SDavide Caratti 3940e54d217SDavide Caratti void nf_ct_l4proto_pernet_unregister(struct net *net, 395cd9ceafcSFlorian Westphal const struct nf_conntrack_l4proto *const l4proto[], 3960e54d217SDavide Caratti unsigned int num_proto) 3970e54d217SDavide Caratti { 3980e54d217SDavide Caratti while (num_proto-- != 0) 3990e54d217SDavide Caratti nf_ct_l4proto_pernet_unregister_one(net, l4proto[num_proto]); 4000e54d217SDavide Caratti } 401c296bb4dSGao feng EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_unregister); 402ac5357ebSPatrick McHardy 403a0ae2562SFlorian Westphal static unsigned int ipv4_helper(void *priv, 404a0ae2562SFlorian Westphal struct sk_buff *skb, 405a0ae2562SFlorian Westphal const struct nf_hook_state *state) 406a0ae2562SFlorian Westphal { 407a0ae2562SFlorian Westphal struct nf_conn *ct; 408a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 409a0ae2562SFlorian Westphal const struct nf_conn_help *help; 410a0ae2562SFlorian Westphal const struct nf_conntrack_helper *helper; 411a0ae2562SFlorian Westphal 412a0ae2562SFlorian Westphal /* This is where we call the helper: as the packet goes out. */ 413a0ae2562SFlorian Westphal ct = nf_ct_get(skb, &ctinfo); 414a0ae2562SFlorian Westphal if (!ct || ctinfo == IP_CT_RELATED_REPLY) 415a0ae2562SFlorian Westphal return NF_ACCEPT; 416a0ae2562SFlorian Westphal 417a0ae2562SFlorian Westphal help = nfct_help(ct); 418a0ae2562SFlorian Westphal if (!help) 419a0ae2562SFlorian Westphal return NF_ACCEPT; 420a0ae2562SFlorian Westphal 421a0ae2562SFlorian Westphal /* rcu_read_lock()ed by nf_hook_thresh */ 422a0ae2562SFlorian Westphal helper = rcu_dereference(help->helper); 423a0ae2562SFlorian Westphal if (!helper) 424a0ae2562SFlorian Westphal return NF_ACCEPT; 425a0ae2562SFlorian Westphal 426a0ae2562SFlorian Westphal return helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), 427a0ae2562SFlorian Westphal ct, ctinfo); 428a0ae2562SFlorian Westphal } 429a0ae2562SFlorian Westphal 430a0ae2562SFlorian Westphal static unsigned int ipv4_confirm(void *priv, 431a0ae2562SFlorian Westphal struct sk_buff *skb, 432a0ae2562SFlorian Westphal const struct nf_hook_state *state) 433a0ae2562SFlorian Westphal { 434a0ae2562SFlorian Westphal struct nf_conn *ct; 435a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 436a0ae2562SFlorian Westphal 437a0ae2562SFlorian Westphal ct = nf_ct_get(skb, &ctinfo); 438a0ae2562SFlorian Westphal if (!ct || ctinfo == IP_CT_RELATED_REPLY) 439a0ae2562SFlorian Westphal goto out; 440a0ae2562SFlorian Westphal 441a0ae2562SFlorian Westphal /* adjust seqs for loopback traffic only in outgoing direction */ 442a0ae2562SFlorian Westphal if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && 443a0ae2562SFlorian Westphal !nf_is_loopback_packet(skb)) { 444a0ae2562SFlorian Westphal if (!nf_ct_seq_adjust(skb, ct, ctinfo, ip_hdrlen(skb))) { 445a0ae2562SFlorian Westphal NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); 446a0ae2562SFlorian Westphal return NF_DROP; 447a0ae2562SFlorian Westphal } 448a0ae2562SFlorian Westphal } 449a0ae2562SFlorian Westphal out: 450a0ae2562SFlorian Westphal /* We've seen it coming out the other side: confirm it */ 451a0ae2562SFlorian Westphal return nf_conntrack_confirm(skb); 452a0ae2562SFlorian Westphal } 453a0ae2562SFlorian Westphal 454a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_in(void *priv, 455a0ae2562SFlorian Westphal struct sk_buff *skb, 456a0ae2562SFlorian Westphal const struct nf_hook_state *state) 457a0ae2562SFlorian Westphal { 458a0ae2562SFlorian Westphal return nf_conntrack_in(state->net, PF_INET, state->hook, skb); 459a0ae2562SFlorian Westphal } 460a0ae2562SFlorian Westphal 461a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_local(void *priv, 462a0ae2562SFlorian Westphal struct sk_buff *skb, 463a0ae2562SFlorian Westphal const struct nf_hook_state *state) 464a0ae2562SFlorian Westphal { 465a0ae2562SFlorian Westphal if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */ 466a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 467a0ae2562SFlorian Westphal struct nf_conn *tmpl; 468a0ae2562SFlorian Westphal 469a0ae2562SFlorian Westphal tmpl = nf_ct_get(skb, &ctinfo); 470a0ae2562SFlorian Westphal if (tmpl && nf_ct_is_template(tmpl)) { 471a0ae2562SFlorian Westphal /* when skipping ct, clear templates to avoid fooling 472a0ae2562SFlorian Westphal * later targets/matches 473a0ae2562SFlorian Westphal */ 474a0ae2562SFlorian Westphal skb->_nfct = 0; 475a0ae2562SFlorian Westphal nf_ct_put(tmpl); 476a0ae2562SFlorian Westphal } 477a0ae2562SFlorian Westphal return NF_ACCEPT; 478a0ae2562SFlorian Westphal } 479a0ae2562SFlorian Westphal 480a0ae2562SFlorian Westphal return nf_conntrack_in(state->net, PF_INET, state->hook, skb); 481a0ae2562SFlorian Westphal } 482a0ae2562SFlorian Westphal 483a0ae2562SFlorian Westphal /* Connection tracking may drop packets, but never alters them, so 484a0ae2562SFlorian Westphal * make it the first hook. 485a0ae2562SFlorian Westphal */ 486a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv4_conntrack_ops[] = { 487a0ae2562SFlorian Westphal { 488a0ae2562SFlorian Westphal .hook = ipv4_conntrack_in, 489a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 490a0ae2562SFlorian Westphal .hooknum = NF_INET_PRE_ROUTING, 491a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK, 492a0ae2562SFlorian Westphal }, 493a0ae2562SFlorian Westphal { 494a0ae2562SFlorian Westphal .hook = ipv4_conntrack_local, 495a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 496a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_OUT, 497a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK, 498a0ae2562SFlorian Westphal }, 499a0ae2562SFlorian Westphal { 500a0ae2562SFlorian Westphal .hook = ipv4_helper, 501a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 502a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING, 503a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_HELPER, 504a0ae2562SFlorian Westphal }, 505a0ae2562SFlorian Westphal { 506a0ae2562SFlorian Westphal .hook = ipv4_confirm, 507a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 508a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING, 509a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_CONFIRM, 510a0ae2562SFlorian Westphal }, 511a0ae2562SFlorian Westphal { 512a0ae2562SFlorian Westphal .hook = ipv4_helper, 513a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 514a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN, 515a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_HELPER, 516a0ae2562SFlorian Westphal }, 517a0ae2562SFlorian Westphal { 518a0ae2562SFlorian Westphal .hook = ipv4_confirm, 519a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 520a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN, 521a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_CONFIRM, 522a0ae2562SFlorian Westphal }, 523a0ae2562SFlorian Westphal }; 524a0ae2562SFlorian Westphal 525a0ae2562SFlorian Westphal /* Fast function for those who don't want to parse /proc (and I don't 526a0ae2562SFlorian Westphal * blame them). 527a0ae2562SFlorian Westphal * Reversing the socket's dst/src point of view gives us the reply 528a0ae2562SFlorian Westphal * mapping. 529a0ae2562SFlorian Westphal */ 530a0ae2562SFlorian Westphal static int 531a0ae2562SFlorian Westphal getorigdst(struct sock *sk, int optval, void __user *user, int *len) 532a0ae2562SFlorian Westphal { 533a0ae2562SFlorian Westphal const struct inet_sock *inet = inet_sk(sk); 534a0ae2562SFlorian Westphal const struct nf_conntrack_tuple_hash *h; 535a0ae2562SFlorian Westphal struct nf_conntrack_tuple tuple; 536a0ae2562SFlorian Westphal 537a0ae2562SFlorian Westphal memset(&tuple, 0, sizeof(tuple)); 538a0ae2562SFlorian Westphal 539a0ae2562SFlorian Westphal lock_sock(sk); 540a0ae2562SFlorian Westphal tuple.src.u3.ip = inet->inet_rcv_saddr; 541a0ae2562SFlorian Westphal tuple.src.u.tcp.port = inet->inet_sport; 542a0ae2562SFlorian Westphal tuple.dst.u3.ip = inet->inet_daddr; 543a0ae2562SFlorian Westphal tuple.dst.u.tcp.port = inet->inet_dport; 544a0ae2562SFlorian Westphal tuple.src.l3num = PF_INET; 545a0ae2562SFlorian Westphal tuple.dst.protonum = sk->sk_protocol; 546a0ae2562SFlorian Westphal release_sock(sk); 547a0ae2562SFlorian Westphal 548a0ae2562SFlorian Westphal /* We only do TCP and SCTP at the moment: is there a better way? */ 549a0ae2562SFlorian Westphal if (tuple.dst.protonum != IPPROTO_TCP && 550a0ae2562SFlorian Westphal tuple.dst.protonum != IPPROTO_SCTP) { 551a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: Not a TCP/SCTP socket\n"); 552a0ae2562SFlorian Westphal return -ENOPROTOOPT; 553a0ae2562SFlorian Westphal } 554a0ae2562SFlorian Westphal 555a0ae2562SFlorian Westphal if ((unsigned int)*len < sizeof(struct sockaddr_in)) { 556a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: len %d not %zu\n", 557a0ae2562SFlorian Westphal *len, sizeof(struct sockaddr_in)); 558a0ae2562SFlorian Westphal return -EINVAL; 559a0ae2562SFlorian Westphal } 560a0ae2562SFlorian Westphal 561a0ae2562SFlorian Westphal h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple); 562a0ae2562SFlorian Westphal if (h) { 563a0ae2562SFlorian Westphal struct sockaddr_in sin; 564a0ae2562SFlorian Westphal struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); 565a0ae2562SFlorian Westphal 566a0ae2562SFlorian Westphal sin.sin_family = AF_INET; 567a0ae2562SFlorian Westphal sin.sin_port = ct->tuplehash[IP_CT_DIR_ORIGINAL] 568a0ae2562SFlorian Westphal .tuple.dst.u.tcp.port; 569a0ae2562SFlorian Westphal sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL] 570a0ae2562SFlorian Westphal .tuple.dst.u3.ip; 571a0ae2562SFlorian Westphal memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); 572a0ae2562SFlorian Westphal 573a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: %pI4 %u\n", 574a0ae2562SFlorian Westphal &sin.sin_addr.s_addr, ntohs(sin.sin_port)); 575a0ae2562SFlorian Westphal nf_ct_put(ct); 576a0ae2562SFlorian Westphal if (copy_to_user(user, &sin, sizeof(sin)) != 0) 577a0ae2562SFlorian Westphal return -EFAULT; 578a0ae2562SFlorian Westphal else 579a0ae2562SFlorian Westphal return 0; 580a0ae2562SFlorian Westphal } 581a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: Can't find %pI4/%u-%pI4/%u.\n", 582a0ae2562SFlorian Westphal &tuple.src.u3.ip, ntohs(tuple.src.u.tcp.port), 583a0ae2562SFlorian Westphal &tuple.dst.u3.ip, ntohs(tuple.dst.u.tcp.port)); 584a0ae2562SFlorian Westphal return -ENOENT; 585a0ae2562SFlorian Westphal } 586a0ae2562SFlorian Westphal 587a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst = { 588a0ae2562SFlorian Westphal .pf = PF_INET, 589a0ae2562SFlorian Westphal .get_optmin = SO_ORIGINAL_DST, 590a0ae2562SFlorian Westphal .get_optmax = SO_ORIGINAL_DST + 1, 591a0ae2562SFlorian Westphal .get = getorigdst, 592a0ae2562SFlorian Westphal .owner = THIS_MODULE, 593a0ae2562SFlorian Westphal }; 594a0ae2562SFlorian Westphal 595a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 596a0ae2562SFlorian Westphal static int 597a0ae2562SFlorian Westphal ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len) 598a0ae2562SFlorian Westphal { 599a0ae2562SFlorian Westphal struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 }; 600a0ae2562SFlorian Westphal const struct ipv6_pinfo *inet6 = inet6_sk(sk); 601a0ae2562SFlorian Westphal const struct inet_sock *inet = inet_sk(sk); 602a0ae2562SFlorian Westphal const struct nf_conntrack_tuple_hash *h; 603a0ae2562SFlorian Westphal struct sockaddr_in6 sin6; 604a0ae2562SFlorian Westphal struct nf_conn *ct; 605a0ae2562SFlorian Westphal __be32 flow_label; 606a0ae2562SFlorian Westphal int bound_dev_if; 607a0ae2562SFlorian Westphal 608a0ae2562SFlorian Westphal lock_sock(sk); 609a0ae2562SFlorian Westphal tuple.src.u3.in6 = sk->sk_v6_rcv_saddr; 610a0ae2562SFlorian Westphal tuple.src.u.tcp.port = inet->inet_sport; 611a0ae2562SFlorian Westphal tuple.dst.u3.in6 = sk->sk_v6_daddr; 612a0ae2562SFlorian Westphal tuple.dst.u.tcp.port = inet->inet_dport; 613a0ae2562SFlorian Westphal tuple.dst.protonum = sk->sk_protocol; 614a0ae2562SFlorian Westphal bound_dev_if = sk->sk_bound_dev_if; 615a0ae2562SFlorian Westphal flow_label = inet6->flow_label; 616a0ae2562SFlorian Westphal release_sock(sk); 617a0ae2562SFlorian Westphal 618a0ae2562SFlorian Westphal if (tuple.dst.protonum != IPPROTO_TCP && 619a0ae2562SFlorian Westphal tuple.dst.protonum != IPPROTO_SCTP) 620a0ae2562SFlorian Westphal return -ENOPROTOOPT; 621a0ae2562SFlorian Westphal 622a0ae2562SFlorian Westphal if (*len < 0 || (unsigned int)*len < sizeof(sin6)) 623a0ae2562SFlorian Westphal return -EINVAL; 624a0ae2562SFlorian Westphal 625a0ae2562SFlorian Westphal h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple); 626a0ae2562SFlorian Westphal if (!h) { 627a0ae2562SFlorian Westphal pr_debug("IP6T_SO_ORIGINAL_DST: Can't find %pI6c/%u-%pI6c/%u.\n", 628a0ae2562SFlorian Westphal &tuple.src.u3.ip6, ntohs(tuple.src.u.tcp.port), 629a0ae2562SFlorian Westphal &tuple.dst.u3.ip6, ntohs(tuple.dst.u.tcp.port)); 630a0ae2562SFlorian Westphal return -ENOENT; 631a0ae2562SFlorian Westphal } 632a0ae2562SFlorian Westphal 633a0ae2562SFlorian Westphal ct = nf_ct_tuplehash_to_ctrack(h); 634a0ae2562SFlorian Westphal 635a0ae2562SFlorian Westphal sin6.sin6_family = AF_INET6; 636a0ae2562SFlorian Westphal sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port; 637a0ae2562SFlorian Westphal sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK; 638a0ae2562SFlorian Westphal memcpy(&sin6.sin6_addr, 639a0ae2562SFlorian Westphal &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6, 640a0ae2562SFlorian Westphal sizeof(sin6.sin6_addr)); 641a0ae2562SFlorian Westphal 642a0ae2562SFlorian Westphal nf_ct_put(ct); 643a0ae2562SFlorian Westphal sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if); 644a0ae2562SFlorian Westphal return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0; 645a0ae2562SFlorian Westphal } 646a0ae2562SFlorian Westphal 647a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst6 = { 648a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 649a0ae2562SFlorian Westphal .get_optmin = IP6T_SO_ORIGINAL_DST, 650a0ae2562SFlorian Westphal .get_optmax = IP6T_SO_ORIGINAL_DST + 1, 651a0ae2562SFlorian Westphal .get = ipv6_getorigdst, 652a0ae2562SFlorian Westphal .owner = THIS_MODULE, 653a0ae2562SFlorian Westphal }; 654a0ae2562SFlorian Westphal 655a0ae2562SFlorian Westphal static unsigned int ipv6_confirm(void *priv, 656a0ae2562SFlorian Westphal struct sk_buff *skb, 657a0ae2562SFlorian Westphal const struct nf_hook_state *state) 658a0ae2562SFlorian Westphal { 659a0ae2562SFlorian Westphal struct nf_conn *ct; 660a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 661a0ae2562SFlorian Westphal unsigned char pnum = ipv6_hdr(skb)->nexthdr; 662a0ae2562SFlorian Westphal int protoff; 663a0ae2562SFlorian Westphal __be16 frag_off; 664a0ae2562SFlorian Westphal 665a0ae2562SFlorian Westphal ct = nf_ct_get(skb, &ctinfo); 666a0ae2562SFlorian Westphal if (!ct || ctinfo == IP_CT_RELATED_REPLY) 667a0ae2562SFlorian Westphal goto out; 668a0ae2562SFlorian Westphal 669a0ae2562SFlorian Westphal protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum, 670a0ae2562SFlorian Westphal &frag_off); 671a0ae2562SFlorian Westphal if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { 672a0ae2562SFlorian Westphal pr_debug("proto header not found\n"); 673a0ae2562SFlorian Westphal goto out; 674a0ae2562SFlorian Westphal } 675a0ae2562SFlorian Westphal 676a0ae2562SFlorian Westphal /* adjust seqs for loopback traffic only in outgoing direction */ 677a0ae2562SFlorian Westphal if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && 678a0ae2562SFlorian Westphal !nf_is_loopback_packet(skb)) { 679a0ae2562SFlorian Westphal if (!nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) { 680a0ae2562SFlorian Westphal NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); 681a0ae2562SFlorian Westphal return NF_DROP; 682a0ae2562SFlorian Westphal } 683a0ae2562SFlorian Westphal } 684a0ae2562SFlorian Westphal out: 685a0ae2562SFlorian Westphal /* We've seen it coming out the other side: confirm it */ 686a0ae2562SFlorian Westphal return nf_conntrack_confirm(skb); 687a0ae2562SFlorian Westphal } 688a0ae2562SFlorian Westphal 689a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_in(void *priv, 690a0ae2562SFlorian Westphal struct sk_buff *skb, 691a0ae2562SFlorian Westphal const struct nf_hook_state *state) 692a0ae2562SFlorian Westphal { 693a0ae2562SFlorian Westphal return nf_conntrack_in(state->net, PF_INET6, state->hook, skb); 694a0ae2562SFlorian Westphal } 695a0ae2562SFlorian Westphal 696a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_local(void *priv, 697a0ae2562SFlorian Westphal struct sk_buff *skb, 698a0ae2562SFlorian Westphal const struct nf_hook_state *state) 699a0ae2562SFlorian Westphal { 700a0ae2562SFlorian Westphal return nf_conntrack_in(state->net, PF_INET6, state->hook, skb); 701a0ae2562SFlorian Westphal } 702a0ae2562SFlorian Westphal 703a0ae2562SFlorian Westphal static unsigned int ipv6_helper(void *priv, 704a0ae2562SFlorian Westphal struct sk_buff *skb, 705a0ae2562SFlorian Westphal const struct nf_hook_state *state) 706a0ae2562SFlorian Westphal { 707a0ae2562SFlorian Westphal struct nf_conn *ct; 708a0ae2562SFlorian Westphal const struct nf_conn_help *help; 709a0ae2562SFlorian Westphal const struct nf_conntrack_helper *helper; 710a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 711a0ae2562SFlorian Westphal __be16 frag_off; 712a0ae2562SFlorian Westphal int protoff; 713a0ae2562SFlorian Westphal u8 nexthdr; 714a0ae2562SFlorian Westphal 715a0ae2562SFlorian Westphal /* This is where we call the helper: as the packet goes out. */ 716a0ae2562SFlorian Westphal ct = nf_ct_get(skb, &ctinfo); 717a0ae2562SFlorian Westphal if (!ct || ctinfo == IP_CT_RELATED_REPLY) 718a0ae2562SFlorian Westphal return NF_ACCEPT; 719a0ae2562SFlorian Westphal 720a0ae2562SFlorian Westphal help = nfct_help(ct); 721a0ae2562SFlorian Westphal if (!help) 722a0ae2562SFlorian Westphal return NF_ACCEPT; 723a0ae2562SFlorian Westphal /* rcu_read_lock()ed by nf_hook_thresh */ 724a0ae2562SFlorian Westphal helper = rcu_dereference(help->helper); 725a0ae2562SFlorian Westphal if (!helper) 726a0ae2562SFlorian Westphal return NF_ACCEPT; 727a0ae2562SFlorian Westphal 728a0ae2562SFlorian Westphal nexthdr = ipv6_hdr(skb)->nexthdr; 729a0ae2562SFlorian Westphal protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, 730a0ae2562SFlorian Westphal &frag_off); 731a0ae2562SFlorian Westphal if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { 732a0ae2562SFlorian Westphal pr_debug("proto header not found\n"); 733a0ae2562SFlorian Westphal return NF_ACCEPT; 734a0ae2562SFlorian Westphal } 735a0ae2562SFlorian Westphal 736a0ae2562SFlorian Westphal return helper->help(skb, protoff, ct, ctinfo); 737a0ae2562SFlorian Westphal } 738a0ae2562SFlorian Westphal 739a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv6_conntrack_ops[] = { 740a0ae2562SFlorian Westphal { 741a0ae2562SFlorian Westphal .hook = ipv6_conntrack_in, 742a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 743a0ae2562SFlorian Westphal .hooknum = NF_INET_PRE_ROUTING, 744a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK, 745a0ae2562SFlorian Westphal }, 746a0ae2562SFlorian Westphal { 747a0ae2562SFlorian Westphal .hook = ipv6_conntrack_local, 748a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 749a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_OUT, 750a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK, 751a0ae2562SFlorian Westphal }, 752a0ae2562SFlorian Westphal { 753a0ae2562SFlorian Westphal .hook = ipv6_helper, 754a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 755a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING, 756a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK_HELPER, 757a0ae2562SFlorian Westphal }, 758a0ae2562SFlorian Westphal { 759a0ae2562SFlorian Westphal .hook = ipv6_confirm, 760a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 761a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING, 762a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_LAST, 763a0ae2562SFlorian Westphal }, 764a0ae2562SFlorian Westphal { 765a0ae2562SFlorian Westphal .hook = ipv6_helper, 766a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 767a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN, 768a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK_HELPER, 769a0ae2562SFlorian Westphal }, 770a0ae2562SFlorian Westphal { 771a0ae2562SFlorian Westphal .hook = ipv6_confirm, 772a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 773a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN, 774a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_LAST - 1, 775a0ae2562SFlorian Westphal }, 776a0ae2562SFlorian Westphal }; 777a0ae2562SFlorian Westphal #endif 778a0ae2562SFlorian Westphal 779f94e6380SFlorian Westphal static int nf_ct_tcp_fixup(struct nf_conn *ct, void *_nfproto) 780f94e6380SFlorian Westphal { 781f94e6380SFlorian Westphal u8 nfproto = (unsigned long)_nfproto; 782f94e6380SFlorian Westphal 783f94e6380SFlorian Westphal if (nf_ct_l3num(ct) != nfproto) 784f94e6380SFlorian Westphal return 0; 785f94e6380SFlorian Westphal 786f94e6380SFlorian Westphal if (nf_ct_protonum(ct) == IPPROTO_TCP && 787f94e6380SFlorian Westphal ct->proto.tcp.state == TCP_CONNTRACK_ESTABLISHED) { 788f94e6380SFlorian Westphal ct->proto.tcp.seen[0].td_maxwin = 0; 789f94e6380SFlorian Westphal ct->proto.tcp.seen[1].td_maxwin = 0; 790f94e6380SFlorian Westphal } 791f94e6380SFlorian Westphal 792f94e6380SFlorian Westphal return 0; 793f94e6380SFlorian Westphal } 794f94e6380SFlorian Westphal 795a0ae2562SFlorian Westphal static int nf_ct_netns_do_get(struct net *net, u8 nfproto) 796a0ae2562SFlorian Westphal { 797a0ae2562SFlorian Westphal struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); 798f94e6380SFlorian Westphal bool fixup_needed = false; 799a0ae2562SFlorian Westphal int err = 0; 800a0ae2562SFlorian Westphal 801a0ae2562SFlorian Westphal mutex_lock(&nf_ct_proto_mutex); 802a0ae2562SFlorian Westphal 803a0ae2562SFlorian Westphal switch (nfproto) { 804a0ae2562SFlorian Westphal case NFPROTO_IPV4: 805a0ae2562SFlorian Westphal cnet->users4++; 806a0ae2562SFlorian Westphal if (cnet->users4 > 1) 807a0ae2562SFlorian Westphal goto out_unlock; 808a0ae2562SFlorian Westphal err = nf_defrag_ipv4_enable(net); 809a0ae2562SFlorian Westphal if (err) { 810a0ae2562SFlorian Westphal cnet->users4 = 0; 811a0ae2562SFlorian Westphal goto out_unlock; 812a0ae2562SFlorian Westphal } 813a0ae2562SFlorian Westphal 814a0ae2562SFlorian Westphal err = nf_register_net_hooks(net, ipv4_conntrack_ops, 815a0ae2562SFlorian Westphal ARRAY_SIZE(ipv4_conntrack_ops)); 816a0ae2562SFlorian Westphal if (err) 817a0ae2562SFlorian Westphal cnet->users4 = 0; 818f94e6380SFlorian Westphal else 819f94e6380SFlorian Westphal fixup_needed = true; 820a0ae2562SFlorian Westphal break; 821a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 822a0ae2562SFlorian Westphal case NFPROTO_IPV6: 823a0ae2562SFlorian Westphal cnet->users6++; 824a0ae2562SFlorian Westphal if (cnet->users6 > 1) 825a0ae2562SFlorian Westphal goto out_unlock; 826a0ae2562SFlorian Westphal err = nf_defrag_ipv6_enable(net); 827a0ae2562SFlorian Westphal if (err < 0) { 828a0ae2562SFlorian Westphal cnet->users6 = 0; 829a0ae2562SFlorian Westphal goto out_unlock; 830a0ae2562SFlorian Westphal } 831a0ae2562SFlorian Westphal 832a0ae2562SFlorian Westphal err = nf_register_net_hooks(net, ipv6_conntrack_ops, 833a0ae2562SFlorian Westphal ARRAY_SIZE(ipv6_conntrack_ops)); 834a0ae2562SFlorian Westphal if (err) 835a0ae2562SFlorian Westphal cnet->users6 = 0; 836f94e6380SFlorian Westphal else 837f94e6380SFlorian Westphal fixup_needed = true; 838a0ae2562SFlorian Westphal break; 839a0ae2562SFlorian Westphal #endif 840a0ae2562SFlorian Westphal default: 841a0ae2562SFlorian Westphal err = -EPROTO; 842a0ae2562SFlorian Westphal break; 843a0ae2562SFlorian Westphal } 844a0ae2562SFlorian Westphal out_unlock: 845a0ae2562SFlorian Westphal mutex_unlock(&nf_ct_proto_mutex); 846f94e6380SFlorian Westphal 847f94e6380SFlorian Westphal if (fixup_needed) 848f94e6380SFlorian Westphal nf_ct_iterate_cleanup_net(net, nf_ct_tcp_fixup, 849f94e6380SFlorian Westphal (void *)(unsigned long)nfproto, 0, 0); 850f94e6380SFlorian Westphal 851a0ae2562SFlorian Westphal return err; 852a0ae2562SFlorian Westphal } 853a0ae2562SFlorian Westphal 854a0ae2562SFlorian Westphal static void nf_ct_netns_do_put(struct net *net, u8 nfproto) 855a0ae2562SFlorian Westphal { 856a0ae2562SFlorian Westphal struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); 857a0ae2562SFlorian Westphal 858a0ae2562SFlorian Westphal mutex_lock(&nf_ct_proto_mutex); 859a0ae2562SFlorian Westphal switch (nfproto) { 860a0ae2562SFlorian Westphal case NFPROTO_IPV4: 861a0ae2562SFlorian Westphal if (cnet->users4 && (--cnet->users4 == 0)) 862a0ae2562SFlorian Westphal nf_unregister_net_hooks(net, ipv4_conntrack_ops, 863a0ae2562SFlorian Westphal ARRAY_SIZE(ipv4_conntrack_ops)); 864a0ae2562SFlorian Westphal break; 865a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 866a0ae2562SFlorian Westphal case NFPROTO_IPV6: 867a0ae2562SFlorian Westphal if (cnet->users6 && (--cnet->users6 == 0)) 868a0ae2562SFlorian Westphal nf_unregister_net_hooks(net, ipv6_conntrack_ops, 869a0ae2562SFlorian Westphal ARRAY_SIZE(ipv6_conntrack_ops)); 870a0ae2562SFlorian Westphal break; 871a0ae2562SFlorian Westphal #endif 872a0ae2562SFlorian Westphal } 873a0ae2562SFlorian Westphal 874a0ae2562SFlorian Westphal mutex_unlock(&nf_ct_proto_mutex); 875a0ae2562SFlorian Westphal } 876a0ae2562SFlorian Westphal 877a0ae2562SFlorian Westphal int nf_ct_netns_get(struct net *net, u8 nfproto) 878a0ae2562SFlorian Westphal { 879a0ae2562SFlorian Westphal int err; 880a0ae2562SFlorian Westphal 881a0ae2562SFlorian Westphal if (nfproto == NFPROTO_INET) { 882a0ae2562SFlorian Westphal err = nf_ct_netns_do_get(net, NFPROTO_IPV4); 883a0ae2562SFlorian Westphal if (err < 0) 884a0ae2562SFlorian Westphal goto err1; 885a0ae2562SFlorian Westphal err = nf_ct_netns_do_get(net, NFPROTO_IPV6); 886a0ae2562SFlorian Westphal if (err < 0) 887a0ae2562SFlorian Westphal goto err2; 888a0ae2562SFlorian Westphal } else { 889a0ae2562SFlorian Westphal err = nf_ct_netns_do_get(net, nfproto); 890a0ae2562SFlorian Westphal if (err < 0) 891a0ae2562SFlorian Westphal goto err1; 892a0ae2562SFlorian Westphal } 893a0ae2562SFlorian Westphal return 0; 894a0ae2562SFlorian Westphal 895a0ae2562SFlorian Westphal err2: 896a0ae2562SFlorian Westphal nf_ct_netns_put(net, NFPROTO_IPV4); 897a0ae2562SFlorian Westphal err1: 898a0ae2562SFlorian Westphal return err; 899a0ae2562SFlorian Westphal } 900a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_get); 901a0ae2562SFlorian Westphal 902a0ae2562SFlorian Westphal void nf_ct_netns_put(struct net *net, uint8_t nfproto) 903a0ae2562SFlorian Westphal { 904a0ae2562SFlorian Westphal if (nfproto == NFPROTO_INET) { 905a0ae2562SFlorian Westphal nf_ct_netns_do_put(net, NFPROTO_IPV4); 906a0ae2562SFlorian Westphal nf_ct_netns_do_put(net, NFPROTO_IPV6); 907a0ae2562SFlorian Westphal } else { 908a0ae2562SFlorian Westphal nf_ct_netns_do_put(net, nfproto); 909a0ae2562SFlorian Westphal } 910a0ae2562SFlorian Westphal } 911a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_put); 912a0ae2562SFlorian Westphal 913a0ae2562SFlorian Westphal static const struct nf_conntrack_l4proto * const builtin_l4proto[] = { 914a0ae2562SFlorian Westphal &nf_conntrack_l4proto_tcp4, 915a0ae2562SFlorian Westphal &nf_conntrack_l4proto_udp4, 916a0ae2562SFlorian Westphal &nf_conntrack_l4proto_icmp, 917a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_DCCP 918a0ae2562SFlorian Westphal &nf_conntrack_l4proto_dccp4, 919a0ae2562SFlorian Westphal #endif 920a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_SCTP 921a0ae2562SFlorian Westphal &nf_conntrack_l4proto_sctp4, 922a0ae2562SFlorian Westphal #endif 923a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_UDPLITE 924a0ae2562SFlorian Westphal &nf_conntrack_l4proto_udplite4, 925a0ae2562SFlorian Westphal #endif 926a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 927a0ae2562SFlorian Westphal &nf_conntrack_l4proto_tcp6, 928a0ae2562SFlorian Westphal &nf_conntrack_l4proto_udp6, 929a0ae2562SFlorian Westphal &nf_conntrack_l4proto_icmpv6, 930a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_DCCP 931a0ae2562SFlorian Westphal &nf_conntrack_l4proto_dccp6, 932a0ae2562SFlorian Westphal #endif 933a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_SCTP 934a0ae2562SFlorian Westphal &nf_conntrack_l4proto_sctp6, 935a0ae2562SFlorian Westphal #endif 936a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_UDPLITE 937a0ae2562SFlorian Westphal &nf_conntrack_l4proto_udplite6, 938a0ae2562SFlorian Westphal #endif 939a0ae2562SFlorian Westphal #endif /* CONFIG_IPV6 */ 940a0ae2562SFlorian Westphal }; 941a0ae2562SFlorian Westphal 942a0ae2562SFlorian Westphal int nf_conntrack_proto_init(void) 943a0ae2562SFlorian Westphal { 944a0ae2562SFlorian Westphal int ret = 0; 945a0ae2562SFlorian Westphal 946a0ae2562SFlorian Westphal ret = nf_register_sockopt(&so_getorigdst); 947a0ae2562SFlorian Westphal if (ret < 0) 948a0ae2562SFlorian Westphal return ret; 949a0ae2562SFlorian Westphal 950a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 951a0ae2562SFlorian Westphal ret = nf_register_sockopt(&so_getorigdst6); 952a0ae2562SFlorian Westphal if (ret < 0) 953a0ae2562SFlorian Westphal goto cleanup_sockopt; 954a0ae2562SFlorian Westphal #endif 955a0ae2562SFlorian Westphal ret = nf_ct_l4proto_register(builtin_l4proto, 956a0ae2562SFlorian Westphal ARRAY_SIZE(builtin_l4proto)); 957a0ae2562SFlorian Westphal if (ret < 0) 958a0ae2562SFlorian Westphal goto cleanup_sockopt2; 959a0ae2562SFlorian Westphal 960a0ae2562SFlorian Westphal return ret; 961a0ae2562SFlorian Westphal cleanup_sockopt2: 962a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst); 963a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 964a0ae2562SFlorian Westphal cleanup_sockopt: 965a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst6); 966a0ae2562SFlorian Westphal #endif 967a0ae2562SFlorian Westphal return ret; 968a0ae2562SFlorian Westphal } 969a0ae2562SFlorian Westphal 970a0ae2562SFlorian Westphal void nf_conntrack_proto_fini(void) 971a0ae2562SFlorian Westphal { 972a0ae2562SFlorian Westphal unsigned int i; 973a0ae2562SFlorian Westphal 974a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst); 975a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 976a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst6); 977a0ae2562SFlorian Westphal #endif 978020f6cc5SFlorian Westphal /* No need to call nf_ct_l4proto_unregister(), the register 979020f6cc5SFlorian Westphal * tables are free'd here anyway. 980020f6cc5SFlorian Westphal */ 981a0ae2562SFlorian Westphal for (i = 0; i < ARRAY_SIZE(nf_ct_protos); i++) 982a0ae2562SFlorian Westphal kfree(nf_ct_protos[i]); 983a0ae2562SFlorian Westphal } 984a0ae2562SFlorian Westphal 98504d87001SGao feng int nf_conntrack_proto_pernet_init(struct net *net) 986ac5357ebSPatrick McHardy { 987ac5357ebSPatrick McHardy int err; 988fa34fff5SGao feng struct nf_proto_net *pn = nf_ct_l4proto_net(net, 989fa34fff5SGao feng &nf_conntrack_l4proto_generic); 990fa34fff5SGao feng 991f1caad27SGao feng err = nf_conntrack_l4proto_generic.init_net(net, 992f1caad27SGao feng nf_conntrack_l4proto_generic.l3proto); 99315f585bdSGao feng if (err < 0) 99415f585bdSGao feng return err; 99515f585bdSGao feng err = nf_ct_l4proto_register_sysctl(net, 996fa34fff5SGao feng pn, 99715f585bdSGao feng &nf_conntrack_l4proto_generic); 998ac5357ebSPatrick McHardy if (err < 0) 999ac5357ebSPatrick McHardy return err; 1000ac5357ebSPatrick McHardy 1001a0ae2562SFlorian Westphal err = nf_ct_l4proto_pernet_register(net, builtin_l4proto, 1002a0ae2562SFlorian Westphal ARRAY_SIZE(builtin_l4proto)); 1003a0ae2562SFlorian Westphal if (err < 0) { 1004a0ae2562SFlorian Westphal nf_ct_l4proto_unregister_sysctl(net, pn, 1005a0ae2562SFlorian Westphal &nf_conntrack_l4proto_generic); 1006a0ae2562SFlorian Westphal return err; 1007a0ae2562SFlorian Westphal } 1008a0ae2562SFlorian Westphal 1009fa34fff5SGao feng pn->users++; 1010ac5357ebSPatrick McHardy return 0; 1011ac5357ebSPatrick McHardy } 1012ac5357ebSPatrick McHardy 101304d87001SGao feng void nf_conntrack_proto_pernet_fini(struct net *net) 1014ac5357ebSPatrick McHardy { 1015fa34fff5SGao feng struct nf_proto_net *pn = nf_ct_l4proto_net(net, 1016fa34fff5SGao feng &nf_conntrack_l4proto_generic); 1017fa34fff5SGao feng 1018a0ae2562SFlorian Westphal nf_ct_l4proto_pernet_unregister(net, builtin_l4proto, 1019a0ae2562SFlorian Westphal ARRAY_SIZE(builtin_l4proto)); 1020fa34fff5SGao feng pn->users--; 102115f585bdSGao feng nf_ct_l4proto_unregister_sysctl(net, 1022fa34fff5SGao feng pn, 102315f585bdSGao feng &nf_conntrack_l4proto_generic); 102404d87001SGao feng } 102504d87001SGao feng 102604d87001SGao feng 1027a0ae2562SFlorian Westphal module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, 1028a0ae2562SFlorian Westphal &nf_conntrack_htable_size, 0600); 1029a0ae2562SFlorian Westphal 1030a0ae2562SFlorian Westphal MODULE_ALIAS("ip_conntrack"); 1031a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET)); 1032a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); 1033a0ae2562SFlorian Westphal MODULE_LICENSE("GPL"); 1034