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 3150661cca9SPatrick McHardy synchronize_rcu(); 3162c352f44SGao feng } 3170e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_unregister_one); 318d62f9ed4SPatrick McHardy 3190e54d217SDavide Caratti void nf_ct_l4proto_pernet_unregister_one(struct net *net, 3202a04aabfSJulia Lawall const struct nf_conntrack_l4proto *l4proto) 3212c352f44SGao feng { 322809c2d9aSAaron Conole struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto); 323fa34fff5SGao feng 324fa34fff5SGao feng if (pn == NULL) 325fa34fff5SGao feng return; 326fa34fff5SGao feng 327fa34fff5SGao feng pn->users--; 328fa34fff5SGao feng nf_ct_l4proto_unregister_sysctl(net, pn, l4proto); 3298f03dea5SMartin Josefsson } 3300e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_unregister_one); 3310e54d217SDavide Caratti 332a0ae2562SFlorian Westphal static void 333a0ae2562SFlorian Westphal nf_ct_l4proto_unregister(const struct nf_conntrack_l4proto * const l4proto[], 334a0ae2562SFlorian Westphal unsigned int num_proto) 335a0ae2562SFlorian Westphal { 336a0ae2562SFlorian Westphal mutex_lock(&nf_ct_proto_mutex); 337a0ae2562SFlorian Westphal while (num_proto-- != 0) 338a0ae2562SFlorian Westphal __nf_ct_l4proto_unregister_one(l4proto[num_proto]); 339a0ae2562SFlorian Westphal mutex_unlock(&nf_ct_proto_mutex); 340a0ae2562SFlorian Westphal 341a0ae2562SFlorian Westphal synchronize_net(); 342a0ae2562SFlorian Westphal /* Remove all contrack entries for this protocol */ 343a0ae2562SFlorian Westphal nf_ct_iterate_destroy(kill_l4proto, (void *)l4proto); 344a0ae2562SFlorian Westphal } 345a0ae2562SFlorian Westphal 346a0ae2562SFlorian Westphal static int 347a0ae2562SFlorian Westphal nf_ct_l4proto_register(const struct nf_conntrack_l4proto * const l4proto[], 3480e54d217SDavide Caratti unsigned int num_proto) 3490e54d217SDavide Caratti { 3500e54d217SDavide Caratti int ret = -EINVAL, ver; 3510e54d217SDavide Caratti unsigned int i; 3520e54d217SDavide Caratti 3530e54d217SDavide Caratti for (i = 0; i < num_proto; i++) { 3540e54d217SDavide Caratti ret = nf_ct_l4proto_register_one(l4proto[i]); 3550e54d217SDavide Caratti if (ret < 0) 3560e54d217SDavide Caratti break; 3570e54d217SDavide Caratti } 3580e54d217SDavide Caratti if (i != num_proto) { 3590e54d217SDavide Caratti ver = l4proto[i]->l3proto == PF_INET6 ? 6 : 4; 36009ec82f5SFlorian Westphal pr_err("nf_conntrack_ipv%d: can't register l4 %d proto.\n", 36109ec82f5SFlorian Westphal ver, l4proto[i]->l4proto); 3620e54d217SDavide Caratti nf_ct_l4proto_unregister(l4proto, i); 3630e54d217SDavide Caratti } 3640e54d217SDavide Caratti return ret; 3650e54d217SDavide Caratti } 3660e54d217SDavide Caratti 3670e54d217SDavide Caratti int nf_ct_l4proto_pernet_register(struct net *net, 368cd9ceafcSFlorian Westphal const struct nf_conntrack_l4proto *const l4proto[], 3690e54d217SDavide Caratti unsigned int num_proto) 3700e54d217SDavide Caratti { 3710e54d217SDavide Caratti int ret = -EINVAL; 3720e54d217SDavide Caratti unsigned int i; 3730e54d217SDavide Caratti 3740e54d217SDavide Caratti for (i = 0; i < num_proto; i++) { 3750e54d217SDavide Caratti ret = nf_ct_l4proto_pernet_register_one(net, l4proto[i]); 3760e54d217SDavide Caratti if (ret < 0) 3770e54d217SDavide Caratti break; 3780e54d217SDavide Caratti } 3790e54d217SDavide Caratti if (i != num_proto) { 38009ec82f5SFlorian Westphal pr_err("nf_conntrack_proto_%d %d: pernet registration failed\n", 38109ec82f5SFlorian Westphal l4proto[i]->l4proto, 3820e54d217SDavide Caratti l4proto[i]->l3proto == PF_INET6 ? 6 : 4); 3830e54d217SDavide Caratti nf_ct_l4proto_pernet_unregister(net, l4proto, i); 3840e54d217SDavide Caratti } 3850e54d217SDavide Caratti return ret; 3860e54d217SDavide Caratti } 3870e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register); 3880e54d217SDavide Caratti 3890e54d217SDavide Caratti void nf_ct_l4proto_pernet_unregister(struct net *net, 390cd9ceafcSFlorian Westphal const struct nf_conntrack_l4proto *const l4proto[], 3910e54d217SDavide Caratti unsigned int num_proto) 3920e54d217SDavide Caratti { 3930e54d217SDavide Caratti while (num_proto-- != 0) 3940e54d217SDavide Caratti nf_ct_l4proto_pernet_unregister_one(net, l4proto[num_proto]); 3950e54d217SDavide Caratti } 396c296bb4dSGao feng EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_unregister); 397ac5357ebSPatrick McHardy 398a0ae2562SFlorian Westphal static unsigned int ipv4_helper(void *priv, 399a0ae2562SFlorian Westphal struct sk_buff *skb, 400a0ae2562SFlorian Westphal const struct nf_hook_state *state) 401a0ae2562SFlorian Westphal { 402a0ae2562SFlorian Westphal struct nf_conn *ct; 403a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 404a0ae2562SFlorian Westphal const struct nf_conn_help *help; 405a0ae2562SFlorian Westphal const struct nf_conntrack_helper *helper; 406a0ae2562SFlorian Westphal 407a0ae2562SFlorian Westphal /* This is where we call the helper: as the packet goes out. */ 408a0ae2562SFlorian Westphal ct = nf_ct_get(skb, &ctinfo); 409a0ae2562SFlorian Westphal if (!ct || ctinfo == IP_CT_RELATED_REPLY) 410a0ae2562SFlorian Westphal return NF_ACCEPT; 411a0ae2562SFlorian Westphal 412a0ae2562SFlorian Westphal help = nfct_help(ct); 413a0ae2562SFlorian Westphal if (!help) 414a0ae2562SFlorian Westphal return NF_ACCEPT; 415a0ae2562SFlorian Westphal 416a0ae2562SFlorian Westphal /* rcu_read_lock()ed by nf_hook_thresh */ 417a0ae2562SFlorian Westphal helper = rcu_dereference(help->helper); 418a0ae2562SFlorian Westphal if (!helper) 419a0ae2562SFlorian Westphal return NF_ACCEPT; 420a0ae2562SFlorian Westphal 421a0ae2562SFlorian Westphal return helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), 422a0ae2562SFlorian Westphal ct, ctinfo); 423a0ae2562SFlorian Westphal } 424a0ae2562SFlorian Westphal 425a0ae2562SFlorian Westphal static unsigned int ipv4_confirm(void *priv, 426a0ae2562SFlorian Westphal struct sk_buff *skb, 427a0ae2562SFlorian Westphal const struct nf_hook_state *state) 428a0ae2562SFlorian Westphal { 429a0ae2562SFlorian Westphal struct nf_conn *ct; 430a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 431a0ae2562SFlorian Westphal 432a0ae2562SFlorian Westphal ct = nf_ct_get(skb, &ctinfo); 433a0ae2562SFlorian Westphal if (!ct || ctinfo == IP_CT_RELATED_REPLY) 434a0ae2562SFlorian Westphal goto out; 435a0ae2562SFlorian Westphal 436a0ae2562SFlorian Westphal /* adjust seqs for loopback traffic only in outgoing direction */ 437a0ae2562SFlorian Westphal if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && 438a0ae2562SFlorian Westphal !nf_is_loopback_packet(skb)) { 439a0ae2562SFlorian Westphal if (!nf_ct_seq_adjust(skb, ct, ctinfo, ip_hdrlen(skb))) { 440a0ae2562SFlorian Westphal NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); 441a0ae2562SFlorian Westphal return NF_DROP; 442a0ae2562SFlorian Westphal } 443a0ae2562SFlorian Westphal } 444a0ae2562SFlorian Westphal out: 445a0ae2562SFlorian Westphal /* We've seen it coming out the other side: confirm it */ 446a0ae2562SFlorian Westphal return nf_conntrack_confirm(skb); 447a0ae2562SFlorian Westphal } 448a0ae2562SFlorian Westphal 449a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_in(void *priv, 450a0ae2562SFlorian Westphal struct sk_buff *skb, 451a0ae2562SFlorian Westphal const struct nf_hook_state *state) 452a0ae2562SFlorian Westphal { 453a0ae2562SFlorian Westphal return nf_conntrack_in(state->net, PF_INET, state->hook, skb); 454a0ae2562SFlorian Westphal } 455a0ae2562SFlorian Westphal 456a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_local(void *priv, 457a0ae2562SFlorian Westphal struct sk_buff *skb, 458a0ae2562SFlorian Westphal const struct nf_hook_state *state) 459a0ae2562SFlorian Westphal { 460a0ae2562SFlorian Westphal if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */ 461a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 462a0ae2562SFlorian Westphal struct nf_conn *tmpl; 463a0ae2562SFlorian Westphal 464a0ae2562SFlorian Westphal tmpl = nf_ct_get(skb, &ctinfo); 465a0ae2562SFlorian Westphal if (tmpl && nf_ct_is_template(tmpl)) { 466a0ae2562SFlorian Westphal /* when skipping ct, clear templates to avoid fooling 467a0ae2562SFlorian Westphal * later targets/matches 468a0ae2562SFlorian Westphal */ 469a0ae2562SFlorian Westphal skb->_nfct = 0; 470a0ae2562SFlorian Westphal nf_ct_put(tmpl); 471a0ae2562SFlorian Westphal } 472a0ae2562SFlorian Westphal return NF_ACCEPT; 473a0ae2562SFlorian Westphal } 474a0ae2562SFlorian Westphal 475a0ae2562SFlorian Westphal return nf_conntrack_in(state->net, PF_INET, state->hook, skb); 476a0ae2562SFlorian Westphal } 477a0ae2562SFlorian Westphal 478a0ae2562SFlorian Westphal /* Connection tracking may drop packets, but never alters them, so 479a0ae2562SFlorian Westphal * make it the first hook. 480a0ae2562SFlorian Westphal */ 481a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv4_conntrack_ops[] = { 482a0ae2562SFlorian Westphal { 483a0ae2562SFlorian Westphal .hook = ipv4_conntrack_in, 484a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 485a0ae2562SFlorian Westphal .hooknum = NF_INET_PRE_ROUTING, 486a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK, 487a0ae2562SFlorian Westphal }, 488a0ae2562SFlorian Westphal { 489a0ae2562SFlorian Westphal .hook = ipv4_conntrack_local, 490a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 491a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_OUT, 492a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK, 493a0ae2562SFlorian Westphal }, 494a0ae2562SFlorian Westphal { 495a0ae2562SFlorian Westphal .hook = ipv4_helper, 496a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 497a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING, 498a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_HELPER, 499a0ae2562SFlorian Westphal }, 500a0ae2562SFlorian Westphal { 501a0ae2562SFlorian Westphal .hook = ipv4_confirm, 502a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 503a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING, 504a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_CONFIRM, 505a0ae2562SFlorian Westphal }, 506a0ae2562SFlorian Westphal { 507a0ae2562SFlorian Westphal .hook = ipv4_helper, 508a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 509a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN, 510a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_HELPER, 511a0ae2562SFlorian Westphal }, 512a0ae2562SFlorian Westphal { 513a0ae2562SFlorian Westphal .hook = ipv4_confirm, 514a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 515a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN, 516a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_CONFIRM, 517a0ae2562SFlorian Westphal }, 518a0ae2562SFlorian Westphal }; 519a0ae2562SFlorian Westphal 520a0ae2562SFlorian Westphal /* Fast function for those who don't want to parse /proc (and I don't 521a0ae2562SFlorian Westphal * blame them). 522a0ae2562SFlorian Westphal * Reversing the socket's dst/src point of view gives us the reply 523a0ae2562SFlorian Westphal * mapping. 524a0ae2562SFlorian Westphal */ 525a0ae2562SFlorian Westphal static int 526a0ae2562SFlorian Westphal getorigdst(struct sock *sk, int optval, void __user *user, int *len) 527a0ae2562SFlorian Westphal { 528a0ae2562SFlorian Westphal const struct inet_sock *inet = inet_sk(sk); 529a0ae2562SFlorian Westphal const struct nf_conntrack_tuple_hash *h; 530a0ae2562SFlorian Westphal struct nf_conntrack_tuple tuple; 531a0ae2562SFlorian Westphal 532a0ae2562SFlorian Westphal memset(&tuple, 0, sizeof(tuple)); 533a0ae2562SFlorian Westphal 534a0ae2562SFlorian Westphal lock_sock(sk); 535a0ae2562SFlorian Westphal tuple.src.u3.ip = inet->inet_rcv_saddr; 536a0ae2562SFlorian Westphal tuple.src.u.tcp.port = inet->inet_sport; 537a0ae2562SFlorian Westphal tuple.dst.u3.ip = inet->inet_daddr; 538a0ae2562SFlorian Westphal tuple.dst.u.tcp.port = inet->inet_dport; 539a0ae2562SFlorian Westphal tuple.src.l3num = PF_INET; 540a0ae2562SFlorian Westphal tuple.dst.protonum = sk->sk_protocol; 541a0ae2562SFlorian Westphal release_sock(sk); 542a0ae2562SFlorian Westphal 543a0ae2562SFlorian Westphal /* We only do TCP and SCTP at the moment: is there a better way? */ 544a0ae2562SFlorian Westphal if (tuple.dst.protonum != IPPROTO_TCP && 545a0ae2562SFlorian Westphal tuple.dst.protonum != IPPROTO_SCTP) { 546a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: Not a TCP/SCTP socket\n"); 547a0ae2562SFlorian Westphal return -ENOPROTOOPT; 548a0ae2562SFlorian Westphal } 549a0ae2562SFlorian Westphal 550a0ae2562SFlorian Westphal if ((unsigned int)*len < sizeof(struct sockaddr_in)) { 551a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: len %d not %zu\n", 552a0ae2562SFlorian Westphal *len, sizeof(struct sockaddr_in)); 553a0ae2562SFlorian Westphal return -EINVAL; 554a0ae2562SFlorian Westphal } 555a0ae2562SFlorian Westphal 556a0ae2562SFlorian Westphal h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple); 557a0ae2562SFlorian Westphal if (h) { 558a0ae2562SFlorian Westphal struct sockaddr_in sin; 559a0ae2562SFlorian Westphal struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); 560a0ae2562SFlorian Westphal 561a0ae2562SFlorian Westphal sin.sin_family = AF_INET; 562a0ae2562SFlorian Westphal sin.sin_port = ct->tuplehash[IP_CT_DIR_ORIGINAL] 563a0ae2562SFlorian Westphal .tuple.dst.u.tcp.port; 564a0ae2562SFlorian Westphal sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL] 565a0ae2562SFlorian Westphal .tuple.dst.u3.ip; 566a0ae2562SFlorian Westphal memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); 567a0ae2562SFlorian Westphal 568a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: %pI4 %u\n", 569a0ae2562SFlorian Westphal &sin.sin_addr.s_addr, ntohs(sin.sin_port)); 570a0ae2562SFlorian Westphal nf_ct_put(ct); 571a0ae2562SFlorian Westphal if (copy_to_user(user, &sin, sizeof(sin)) != 0) 572a0ae2562SFlorian Westphal return -EFAULT; 573a0ae2562SFlorian Westphal else 574a0ae2562SFlorian Westphal return 0; 575a0ae2562SFlorian Westphal } 576a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: Can't find %pI4/%u-%pI4/%u.\n", 577a0ae2562SFlorian Westphal &tuple.src.u3.ip, ntohs(tuple.src.u.tcp.port), 578a0ae2562SFlorian Westphal &tuple.dst.u3.ip, ntohs(tuple.dst.u.tcp.port)); 579a0ae2562SFlorian Westphal return -ENOENT; 580a0ae2562SFlorian Westphal } 581a0ae2562SFlorian Westphal 582a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst = { 583a0ae2562SFlorian Westphal .pf = PF_INET, 584a0ae2562SFlorian Westphal .get_optmin = SO_ORIGINAL_DST, 585a0ae2562SFlorian Westphal .get_optmax = SO_ORIGINAL_DST + 1, 586a0ae2562SFlorian Westphal .get = getorigdst, 587a0ae2562SFlorian Westphal .owner = THIS_MODULE, 588a0ae2562SFlorian Westphal }; 589a0ae2562SFlorian Westphal 590a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 591a0ae2562SFlorian Westphal static int 592a0ae2562SFlorian Westphal ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len) 593a0ae2562SFlorian Westphal { 594a0ae2562SFlorian Westphal struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 }; 595a0ae2562SFlorian Westphal const struct ipv6_pinfo *inet6 = inet6_sk(sk); 596a0ae2562SFlorian Westphal const struct inet_sock *inet = inet_sk(sk); 597a0ae2562SFlorian Westphal const struct nf_conntrack_tuple_hash *h; 598a0ae2562SFlorian Westphal struct sockaddr_in6 sin6; 599a0ae2562SFlorian Westphal struct nf_conn *ct; 600a0ae2562SFlorian Westphal __be32 flow_label; 601a0ae2562SFlorian Westphal int bound_dev_if; 602a0ae2562SFlorian Westphal 603a0ae2562SFlorian Westphal lock_sock(sk); 604a0ae2562SFlorian Westphal tuple.src.u3.in6 = sk->sk_v6_rcv_saddr; 605a0ae2562SFlorian Westphal tuple.src.u.tcp.port = inet->inet_sport; 606a0ae2562SFlorian Westphal tuple.dst.u3.in6 = sk->sk_v6_daddr; 607a0ae2562SFlorian Westphal tuple.dst.u.tcp.port = inet->inet_dport; 608a0ae2562SFlorian Westphal tuple.dst.protonum = sk->sk_protocol; 609a0ae2562SFlorian Westphal bound_dev_if = sk->sk_bound_dev_if; 610a0ae2562SFlorian Westphal flow_label = inet6->flow_label; 611a0ae2562SFlorian Westphal release_sock(sk); 612a0ae2562SFlorian Westphal 613a0ae2562SFlorian Westphal if (tuple.dst.protonum != IPPROTO_TCP && 614a0ae2562SFlorian Westphal tuple.dst.protonum != IPPROTO_SCTP) 615a0ae2562SFlorian Westphal return -ENOPROTOOPT; 616a0ae2562SFlorian Westphal 617a0ae2562SFlorian Westphal if (*len < 0 || (unsigned int)*len < sizeof(sin6)) 618a0ae2562SFlorian Westphal return -EINVAL; 619a0ae2562SFlorian Westphal 620a0ae2562SFlorian Westphal h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple); 621a0ae2562SFlorian Westphal if (!h) { 622a0ae2562SFlorian Westphal pr_debug("IP6T_SO_ORIGINAL_DST: Can't find %pI6c/%u-%pI6c/%u.\n", 623a0ae2562SFlorian Westphal &tuple.src.u3.ip6, ntohs(tuple.src.u.tcp.port), 624a0ae2562SFlorian Westphal &tuple.dst.u3.ip6, ntohs(tuple.dst.u.tcp.port)); 625a0ae2562SFlorian Westphal return -ENOENT; 626a0ae2562SFlorian Westphal } 627a0ae2562SFlorian Westphal 628a0ae2562SFlorian Westphal ct = nf_ct_tuplehash_to_ctrack(h); 629a0ae2562SFlorian Westphal 630a0ae2562SFlorian Westphal sin6.sin6_family = AF_INET6; 631a0ae2562SFlorian Westphal sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port; 632a0ae2562SFlorian Westphal sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK; 633a0ae2562SFlorian Westphal memcpy(&sin6.sin6_addr, 634a0ae2562SFlorian Westphal &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6, 635a0ae2562SFlorian Westphal sizeof(sin6.sin6_addr)); 636a0ae2562SFlorian Westphal 637a0ae2562SFlorian Westphal nf_ct_put(ct); 638a0ae2562SFlorian Westphal sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if); 639a0ae2562SFlorian Westphal return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0; 640a0ae2562SFlorian Westphal } 641a0ae2562SFlorian Westphal 642a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst6 = { 643a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 644a0ae2562SFlorian Westphal .get_optmin = IP6T_SO_ORIGINAL_DST, 645a0ae2562SFlorian Westphal .get_optmax = IP6T_SO_ORIGINAL_DST + 1, 646a0ae2562SFlorian Westphal .get = ipv6_getorigdst, 647a0ae2562SFlorian Westphal .owner = THIS_MODULE, 648a0ae2562SFlorian Westphal }; 649a0ae2562SFlorian Westphal 650a0ae2562SFlorian Westphal static unsigned int ipv6_confirm(void *priv, 651a0ae2562SFlorian Westphal struct sk_buff *skb, 652a0ae2562SFlorian Westphal const struct nf_hook_state *state) 653a0ae2562SFlorian Westphal { 654a0ae2562SFlorian Westphal struct nf_conn *ct; 655a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 656a0ae2562SFlorian Westphal unsigned char pnum = ipv6_hdr(skb)->nexthdr; 657a0ae2562SFlorian Westphal int protoff; 658a0ae2562SFlorian Westphal __be16 frag_off; 659a0ae2562SFlorian Westphal 660a0ae2562SFlorian Westphal ct = nf_ct_get(skb, &ctinfo); 661a0ae2562SFlorian Westphal if (!ct || ctinfo == IP_CT_RELATED_REPLY) 662a0ae2562SFlorian Westphal goto out; 663a0ae2562SFlorian Westphal 664a0ae2562SFlorian Westphal protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum, 665a0ae2562SFlorian Westphal &frag_off); 666a0ae2562SFlorian Westphal if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { 667a0ae2562SFlorian Westphal pr_debug("proto header not found\n"); 668a0ae2562SFlorian Westphal goto out; 669a0ae2562SFlorian Westphal } 670a0ae2562SFlorian Westphal 671a0ae2562SFlorian Westphal /* adjust seqs for loopback traffic only in outgoing direction */ 672a0ae2562SFlorian Westphal if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && 673a0ae2562SFlorian Westphal !nf_is_loopback_packet(skb)) { 674a0ae2562SFlorian Westphal if (!nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) { 675a0ae2562SFlorian Westphal NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); 676a0ae2562SFlorian Westphal return NF_DROP; 677a0ae2562SFlorian Westphal } 678a0ae2562SFlorian Westphal } 679a0ae2562SFlorian Westphal out: 680a0ae2562SFlorian Westphal /* We've seen it coming out the other side: confirm it */ 681a0ae2562SFlorian Westphal return nf_conntrack_confirm(skb); 682a0ae2562SFlorian Westphal } 683a0ae2562SFlorian Westphal 684a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_in(void *priv, 685a0ae2562SFlorian Westphal struct sk_buff *skb, 686a0ae2562SFlorian Westphal const struct nf_hook_state *state) 687a0ae2562SFlorian Westphal { 688a0ae2562SFlorian Westphal return nf_conntrack_in(state->net, PF_INET6, state->hook, skb); 689a0ae2562SFlorian Westphal } 690a0ae2562SFlorian Westphal 691a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_local(void *priv, 692a0ae2562SFlorian Westphal struct sk_buff *skb, 693a0ae2562SFlorian Westphal const struct nf_hook_state *state) 694a0ae2562SFlorian Westphal { 695a0ae2562SFlorian Westphal return nf_conntrack_in(state->net, PF_INET6, state->hook, skb); 696a0ae2562SFlorian Westphal } 697a0ae2562SFlorian Westphal 698a0ae2562SFlorian Westphal static unsigned int ipv6_helper(void *priv, 699a0ae2562SFlorian Westphal struct sk_buff *skb, 700a0ae2562SFlorian Westphal const struct nf_hook_state *state) 701a0ae2562SFlorian Westphal { 702a0ae2562SFlorian Westphal struct nf_conn *ct; 703a0ae2562SFlorian Westphal const struct nf_conn_help *help; 704a0ae2562SFlorian Westphal const struct nf_conntrack_helper *helper; 705a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 706a0ae2562SFlorian Westphal __be16 frag_off; 707a0ae2562SFlorian Westphal int protoff; 708a0ae2562SFlorian Westphal u8 nexthdr; 709a0ae2562SFlorian Westphal 710a0ae2562SFlorian Westphal /* This is where we call the helper: as the packet goes out. */ 711a0ae2562SFlorian Westphal ct = nf_ct_get(skb, &ctinfo); 712a0ae2562SFlorian Westphal if (!ct || ctinfo == IP_CT_RELATED_REPLY) 713a0ae2562SFlorian Westphal return NF_ACCEPT; 714a0ae2562SFlorian Westphal 715a0ae2562SFlorian Westphal help = nfct_help(ct); 716a0ae2562SFlorian Westphal if (!help) 717a0ae2562SFlorian Westphal return NF_ACCEPT; 718a0ae2562SFlorian Westphal /* rcu_read_lock()ed by nf_hook_thresh */ 719a0ae2562SFlorian Westphal helper = rcu_dereference(help->helper); 720a0ae2562SFlorian Westphal if (!helper) 721a0ae2562SFlorian Westphal return NF_ACCEPT; 722a0ae2562SFlorian Westphal 723a0ae2562SFlorian Westphal nexthdr = ipv6_hdr(skb)->nexthdr; 724a0ae2562SFlorian Westphal protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, 725a0ae2562SFlorian Westphal &frag_off); 726a0ae2562SFlorian Westphal if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { 727a0ae2562SFlorian Westphal pr_debug("proto header not found\n"); 728a0ae2562SFlorian Westphal return NF_ACCEPT; 729a0ae2562SFlorian Westphal } 730a0ae2562SFlorian Westphal 731a0ae2562SFlorian Westphal return helper->help(skb, protoff, ct, ctinfo); 732a0ae2562SFlorian Westphal } 733a0ae2562SFlorian Westphal 734a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv6_conntrack_ops[] = { 735a0ae2562SFlorian Westphal { 736a0ae2562SFlorian Westphal .hook = ipv6_conntrack_in, 737a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 738a0ae2562SFlorian Westphal .hooknum = NF_INET_PRE_ROUTING, 739a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK, 740a0ae2562SFlorian Westphal }, 741a0ae2562SFlorian Westphal { 742a0ae2562SFlorian Westphal .hook = ipv6_conntrack_local, 743a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 744a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_OUT, 745a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK, 746a0ae2562SFlorian Westphal }, 747a0ae2562SFlorian Westphal { 748a0ae2562SFlorian Westphal .hook = ipv6_helper, 749a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 750a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING, 751a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK_HELPER, 752a0ae2562SFlorian Westphal }, 753a0ae2562SFlorian Westphal { 754a0ae2562SFlorian Westphal .hook = ipv6_confirm, 755a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 756a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING, 757a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_LAST, 758a0ae2562SFlorian Westphal }, 759a0ae2562SFlorian Westphal { 760a0ae2562SFlorian Westphal .hook = ipv6_helper, 761a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 762a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN, 763a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK_HELPER, 764a0ae2562SFlorian Westphal }, 765a0ae2562SFlorian Westphal { 766a0ae2562SFlorian Westphal .hook = ipv6_confirm, 767a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 768a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN, 769a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_LAST - 1, 770a0ae2562SFlorian Westphal }, 771a0ae2562SFlorian Westphal }; 772a0ae2562SFlorian Westphal #endif 773a0ae2562SFlorian Westphal 774a0ae2562SFlorian Westphal static int nf_ct_netns_do_get(struct net *net, u8 nfproto) 775a0ae2562SFlorian Westphal { 776a0ae2562SFlorian Westphal struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); 777a0ae2562SFlorian Westphal int err = 0; 778a0ae2562SFlorian Westphal 779a0ae2562SFlorian Westphal mutex_lock(&nf_ct_proto_mutex); 780a0ae2562SFlorian Westphal 781a0ae2562SFlorian Westphal switch (nfproto) { 782a0ae2562SFlorian Westphal case NFPROTO_IPV4: 783a0ae2562SFlorian Westphal cnet->users4++; 784a0ae2562SFlorian Westphal if (cnet->users4 > 1) 785a0ae2562SFlorian Westphal goto out_unlock; 786a0ae2562SFlorian Westphal err = nf_defrag_ipv4_enable(net); 787a0ae2562SFlorian Westphal if (err) { 788a0ae2562SFlorian Westphal cnet->users4 = 0; 789a0ae2562SFlorian Westphal goto out_unlock; 790a0ae2562SFlorian Westphal } 791a0ae2562SFlorian Westphal 792a0ae2562SFlorian Westphal err = nf_register_net_hooks(net, ipv4_conntrack_ops, 793a0ae2562SFlorian Westphal ARRAY_SIZE(ipv4_conntrack_ops)); 794a0ae2562SFlorian Westphal if (err) 795a0ae2562SFlorian Westphal cnet->users4 = 0; 796a0ae2562SFlorian Westphal break; 797a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 798a0ae2562SFlorian Westphal case NFPROTO_IPV6: 799a0ae2562SFlorian Westphal cnet->users6++; 800a0ae2562SFlorian Westphal if (cnet->users6 > 1) 801a0ae2562SFlorian Westphal goto out_unlock; 802a0ae2562SFlorian Westphal err = nf_defrag_ipv6_enable(net); 803a0ae2562SFlorian Westphal if (err < 0) { 804a0ae2562SFlorian Westphal cnet->users6 = 0; 805a0ae2562SFlorian Westphal goto out_unlock; 806a0ae2562SFlorian Westphal } 807a0ae2562SFlorian Westphal 808a0ae2562SFlorian Westphal err = nf_register_net_hooks(net, ipv6_conntrack_ops, 809a0ae2562SFlorian Westphal ARRAY_SIZE(ipv6_conntrack_ops)); 810a0ae2562SFlorian Westphal if (err) 811a0ae2562SFlorian Westphal cnet->users6 = 0; 812a0ae2562SFlorian Westphal break; 813a0ae2562SFlorian Westphal #endif 814a0ae2562SFlorian Westphal default: 815a0ae2562SFlorian Westphal err = -EPROTO; 816a0ae2562SFlorian Westphal break; 817a0ae2562SFlorian Westphal } 818a0ae2562SFlorian Westphal out_unlock: 819a0ae2562SFlorian Westphal mutex_unlock(&nf_ct_proto_mutex); 820a0ae2562SFlorian Westphal return err; 821a0ae2562SFlorian Westphal } 822a0ae2562SFlorian Westphal 823a0ae2562SFlorian Westphal static void nf_ct_netns_do_put(struct net *net, u8 nfproto) 824a0ae2562SFlorian Westphal { 825a0ae2562SFlorian Westphal struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); 826a0ae2562SFlorian Westphal 827a0ae2562SFlorian Westphal mutex_lock(&nf_ct_proto_mutex); 828a0ae2562SFlorian Westphal switch (nfproto) { 829a0ae2562SFlorian Westphal case NFPROTO_IPV4: 830a0ae2562SFlorian Westphal if (cnet->users4 && (--cnet->users4 == 0)) 831a0ae2562SFlorian Westphal nf_unregister_net_hooks(net, ipv4_conntrack_ops, 832a0ae2562SFlorian Westphal ARRAY_SIZE(ipv4_conntrack_ops)); 833a0ae2562SFlorian Westphal break; 834a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 835a0ae2562SFlorian Westphal case NFPROTO_IPV6: 836a0ae2562SFlorian Westphal if (cnet->users6 && (--cnet->users6 == 0)) 837a0ae2562SFlorian Westphal nf_unregister_net_hooks(net, ipv6_conntrack_ops, 838a0ae2562SFlorian Westphal ARRAY_SIZE(ipv6_conntrack_ops)); 839a0ae2562SFlorian Westphal break; 840a0ae2562SFlorian Westphal #endif 841a0ae2562SFlorian Westphal } 842a0ae2562SFlorian Westphal 843a0ae2562SFlorian Westphal mutex_unlock(&nf_ct_proto_mutex); 844a0ae2562SFlorian Westphal } 845a0ae2562SFlorian Westphal 846a0ae2562SFlorian Westphal int nf_ct_netns_get(struct net *net, u8 nfproto) 847a0ae2562SFlorian Westphal { 848a0ae2562SFlorian Westphal int err; 849a0ae2562SFlorian Westphal 850a0ae2562SFlorian Westphal if (nfproto == NFPROTO_INET) { 851a0ae2562SFlorian Westphal err = nf_ct_netns_do_get(net, NFPROTO_IPV4); 852a0ae2562SFlorian Westphal if (err < 0) 853a0ae2562SFlorian Westphal goto err1; 854a0ae2562SFlorian Westphal err = nf_ct_netns_do_get(net, NFPROTO_IPV6); 855a0ae2562SFlorian Westphal if (err < 0) 856a0ae2562SFlorian Westphal goto err2; 857a0ae2562SFlorian Westphal } else { 858a0ae2562SFlorian Westphal err = nf_ct_netns_do_get(net, nfproto); 859a0ae2562SFlorian Westphal if (err < 0) 860a0ae2562SFlorian Westphal goto err1; 861a0ae2562SFlorian Westphal } 862a0ae2562SFlorian Westphal return 0; 863a0ae2562SFlorian Westphal 864a0ae2562SFlorian Westphal err2: 865a0ae2562SFlorian Westphal nf_ct_netns_put(net, NFPROTO_IPV4); 866a0ae2562SFlorian Westphal err1: 867a0ae2562SFlorian Westphal return err; 868a0ae2562SFlorian Westphal } 869a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_get); 870a0ae2562SFlorian Westphal 871a0ae2562SFlorian Westphal void nf_ct_netns_put(struct net *net, uint8_t nfproto) 872a0ae2562SFlorian Westphal { 873a0ae2562SFlorian Westphal if (nfproto == NFPROTO_INET) { 874a0ae2562SFlorian Westphal nf_ct_netns_do_put(net, NFPROTO_IPV4); 875a0ae2562SFlorian Westphal nf_ct_netns_do_put(net, NFPROTO_IPV6); 876a0ae2562SFlorian Westphal } else { 877a0ae2562SFlorian Westphal nf_ct_netns_do_put(net, nfproto); 878a0ae2562SFlorian Westphal } 879a0ae2562SFlorian Westphal } 880a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_put); 881a0ae2562SFlorian Westphal 882a0ae2562SFlorian Westphal static const struct nf_conntrack_l4proto * const builtin_l4proto[] = { 883a0ae2562SFlorian Westphal &nf_conntrack_l4proto_tcp4, 884a0ae2562SFlorian Westphal &nf_conntrack_l4proto_udp4, 885a0ae2562SFlorian Westphal &nf_conntrack_l4proto_icmp, 886a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_DCCP 887a0ae2562SFlorian Westphal &nf_conntrack_l4proto_dccp4, 888a0ae2562SFlorian Westphal #endif 889a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_SCTP 890a0ae2562SFlorian Westphal &nf_conntrack_l4proto_sctp4, 891a0ae2562SFlorian Westphal #endif 892a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_UDPLITE 893a0ae2562SFlorian Westphal &nf_conntrack_l4proto_udplite4, 894a0ae2562SFlorian Westphal #endif 895a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 896a0ae2562SFlorian Westphal &nf_conntrack_l4proto_tcp6, 897a0ae2562SFlorian Westphal &nf_conntrack_l4proto_udp6, 898a0ae2562SFlorian Westphal &nf_conntrack_l4proto_icmpv6, 899a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_DCCP 900a0ae2562SFlorian Westphal &nf_conntrack_l4proto_dccp6, 901a0ae2562SFlorian Westphal #endif 902a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_SCTP 903a0ae2562SFlorian Westphal &nf_conntrack_l4proto_sctp6, 904a0ae2562SFlorian Westphal #endif 905a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_UDPLITE 906a0ae2562SFlorian Westphal &nf_conntrack_l4proto_udplite6, 907a0ae2562SFlorian Westphal #endif 908a0ae2562SFlorian Westphal #endif /* CONFIG_IPV6 */ 909a0ae2562SFlorian Westphal }; 910a0ae2562SFlorian Westphal 911a0ae2562SFlorian Westphal int nf_conntrack_proto_init(void) 912a0ae2562SFlorian Westphal { 913a0ae2562SFlorian Westphal int ret = 0; 914a0ae2562SFlorian Westphal 915a0ae2562SFlorian Westphal ret = nf_register_sockopt(&so_getorigdst); 916a0ae2562SFlorian Westphal if (ret < 0) 917a0ae2562SFlorian Westphal return ret; 918a0ae2562SFlorian Westphal 919a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 920a0ae2562SFlorian Westphal ret = nf_register_sockopt(&so_getorigdst6); 921a0ae2562SFlorian Westphal if (ret < 0) 922a0ae2562SFlorian Westphal goto cleanup_sockopt; 923a0ae2562SFlorian Westphal #endif 924a0ae2562SFlorian Westphal ret = nf_ct_l4proto_register(builtin_l4proto, 925a0ae2562SFlorian Westphal ARRAY_SIZE(builtin_l4proto)); 926a0ae2562SFlorian Westphal if (ret < 0) 927a0ae2562SFlorian Westphal goto cleanup_sockopt2; 928a0ae2562SFlorian Westphal 929a0ae2562SFlorian Westphal return ret; 930a0ae2562SFlorian Westphal cleanup_sockopt2: 931a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst); 932a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 933a0ae2562SFlorian Westphal cleanup_sockopt: 934a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst6); 935a0ae2562SFlorian Westphal #endif 936a0ae2562SFlorian Westphal return ret; 937a0ae2562SFlorian Westphal } 938a0ae2562SFlorian Westphal 939a0ae2562SFlorian Westphal void nf_conntrack_proto_fini(void) 940a0ae2562SFlorian Westphal { 941a0ae2562SFlorian Westphal unsigned int i; 942a0ae2562SFlorian Westphal 943a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst); 944a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 945a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst6); 946a0ae2562SFlorian Westphal #endif 947020f6cc5SFlorian Westphal /* No need to call nf_ct_l4proto_unregister(), the register 948020f6cc5SFlorian Westphal * tables are free'd here anyway. 949020f6cc5SFlorian Westphal */ 950a0ae2562SFlorian Westphal for (i = 0; i < ARRAY_SIZE(nf_ct_protos); i++) 951a0ae2562SFlorian Westphal kfree(nf_ct_protos[i]); 952a0ae2562SFlorian Westphal } 953a0ae2562SFlorian Westphal 95404d87001SGao feng int nf_conntrack_proto_pernet_init(struct net *net) 955ac5357ebSPatrick McHardy { 956ac5357ebSPatrick McHardy int err; 957fa34fff5SGao feng struct nf_proto_net *pn = nf_ct_l4proto_net(net, 958fa34fff5SGao feng &nf_conntrack_l4proto_generic); 959fa34fff5SGao feng 960f1caad27SGao feng err = nf_conntrack_l4proto_generic.init_net(net, 961f1caad27SGao feng nf_conntrack_l4proto_generic.l3proto); 96215f585bdSGao feng if (err < 0) 96315f585bdSGao feng return err; 96415f585bdSGao feng err = nf_ct_l4proto_register_sysctl(net, 965fa34fff5SGao feng pn, 96615f585bdSGao feng &nf_conntrack_l4proto_generic); 967ac5357ebSPatrick McHardy if (err < 0) 968ac5357ebSPatrick McHardy return err; 969ac5357ebSPatrick McHardy 970a0ae2562SFlorian Westphal err = nf_ct_l4proto_pernet_register(net, builtin_l4proto, 971a0ae2562SFlorian Westphal ARRAY_SIZE(builtin_l4proto)); 972a0ae2562SFlorian Westphal if (err < 0) { 973a0ae2562SFlorian Westphal nf_ct_l4proto_unregister_sysctl(net, pn, 974a0ae2562SFlorian Westphal &nf_conntrack_l4proto_generic); 975a0ae2562SFlorian Westphal return err; 976a0ae2562SFlorian Westphal } 977a0ae2562SFlorian Westphal 978fa34fff5SGao feng pn->users++; 979ac5357ebSPatrick McHardy return 0; 980ac5357ebSPatrick McHardy } 981ac5357ebSPatrick McHardy 98204d87001SGao feng void nf_conntrack_proto_pernet_fini(struct net *net) 983ac5357ebSPatrick McHardy { 984fa34fff5SGao feng struct nf_proto_net *pn = nf_ct_l4proto_net(net, 985fa34fff5SGao feng &nf_conntrack_l4proto_generic); 986fa34fff5SGao feng 987a0ae2562SFlorian Westphal nf_ct_l4proto_pernet_unregister(net, builtin_l4proto, 988a0ae2562SFlorian Westphal ARRAY_SIZE(builtin_l4proto)); 989fa34fff5SGao feng pn->users--; 99015f585bdSGao feng nf_ct_l4proto_unregister_sysctl(net, 991fa34fff5SGao feng pn, 99215f585bdSGao feng &nf_conntrack_l4proto_generic); 99304d87001SGao feng } 99404d87001SGao feng 99504d87001SGao feng 996a0ae2562SFlorian Westphal module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, 997a0ae2562SFlorian Westphal &nf_conntrack_htable_size, 0600); 998a0ae2562SFlorian Westphal 999a0ae2562SFlorian Westphal MODULE_ALIAS("ip_conntrack"); 1000a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET)); 1001a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); 1002a0ae2562SFlorian Westphal MODULE_LICENSE("GPL"); 1003