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 4693185c80SFlorian Westphal static struct nf_conntrack_l4proto __rcu *nf_ct_protos[MAX_NF_CT_PROTO + 1] __read_mostly; 478f03dea5SMartin Josefsson 48b19caa0cSPatrick McHardy static DEFINE_MUTEX(nf_ct_proto_mutex); 49d62f9ed4SPatrick McHardy 50b19caa0cSPatrick McHardy #ifdef CONFIG_SYSCTL 51d62f9ed4SPatrick McHardy static int 522c352f44SGao feng nf_ct_register_sysctl(struct net *net, 532c352f44SGao feng struct ctl_table_header **header, 542c352f44SGao feng const char *path, 55fa34fff5SGao feng struct ctl_table *table) 56d62f9ed4SPatrick McHardy { 57d62f9ed4SPatrick McHardy if (*header == NULL) { 582c352f44SGao feng *header = register_net_sysctl(net, path, table); 59d62f9ed4SPatrick McHardy if (*header == NULL) 60d62f9ed4SPatrick McHardy return -ENOMEM; 61d62f9ed4SPatrick McHardy } 622c352f44SGao feng 63d62f9ed4SPatrick McHardy return 0; 64d62f9ed4SPatrick McHardy } 65d62f9ed4SPatrick McHardy 66d62f9ed4SPatrick McHardy static void 67d62f9ed4SPatrick McHardy nf_ct_unregister_sysctl(struct ctl_table_header **header, 682c352f44SGao feng struct ctl_table **table, 69fa34fff5SGao feng unsigned int users) 70d62f9ed4SPatrick McHardy { 71fa34fff5SGao feng if (users > 0) 72d62f9ed4SPatrick McHardy return; 73b3fd3ffeSPavel Emelyanov 745dd3df10SEric W. Biederman unregister_net_sysctl_table(*header); 752c352f44SGao feng kfree(*table); 76d62f9ed4SPatrick McHardy *header = NULL; 772c352f44SGao feng *table = NULL; 78d62f9ed4SPatrick McHardy } 79c4f3db15SFlorian Westphal 80c4f3db15SFlorian Westphal __printf(5, 6) 81c4f3db15SFlorian Westphal void nf_l4proto_log_invalid(const struct sk_buff *skb, 82c4f3db15SFlorian Westphal struct net *net, 83c4f3db15SFlorian Westphal u16 pf, u8 protonum, 84c4f3db15SFlorian Westphal const char *fmt, ...) 85c4f3db15SFlorian Westphal { 86c4f3db15SFlorian Westphal struct va_format vaf; 87c4f3db15SFlorian Westphal va_list args; 88c4f3db15SFlorian Westphal 89c4f3db15SFlorian Westphal if (net->ct.sysctl_log_invalid != protonum || 90c4f3db15SFlorian Westphal net->ct.sysctl_log_invalid != IPPROTO_RAW) 91c4f3db15SFlorian Westphal return; 92c4f3db15SFlorian Westphal 93c4f3db15SFlorian Westphal va_start(args, fmt); 94c4f3db15SFlorian Westphal vaf.fmt = fmt; 95c4f3db15SFlorian Westphal vaf.va = &args; 96c4f3db15SFlorian Westphal 97c4f3db15SFlorian Westphal nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, 98c4f3db15SFlorian Westphal "nf_ct_proto_%d: %pV ", protonum, &vaf); 99c4f3db15SFlorian Westphal va_end(args); 100c4f3db15SFlorian Westphal } 101c4f3db15SFlorian Westphal EXPORT_SYMBOL_GPL(nf_l4proto_log_invalid); 1023d0b527bSFlorian Westphal 1033d0b527bSFlorian Westphal __printf(3, 4) 1043d0b527bSFlorian Westphal void nf_ct_l4proto_log_invalid(const struct sk_buff *skb, 1053d0b527bSFlorian Westphal const struct nf_conn *ct, 1063d0b527bSFlorian Westphal const char *fmt, ...) 1073d0b527bSFlorian Westphal { 1083d0b527bSFlorian Westphal struct va_format vaf; 1093d0b527bSFlorian Westphal struct net *net; 1103d0b527bSFlorian Westphal va_list args; 1113d0b527bSFlorian Westphal 1123d0b527bSFlorian Westphal net = nf_ct_net(ct); 1133d0b527bSFlorian Westphal if (likely(net->ct.sysctl_log_invalid == 0)) 1143d0b527bSFlorian Westphal return; 1153d0b527bSFlorian Westphal 1163d0b527bSFlorian Westphal va_start(args, fmt); 1173d0b527bSFlorian Westphal vaf.fmt = fmt; 1183d0b527bSFlorian Westphal vaf.va = &args; 1193d0b527bSFlorian Westphal 1203d0b527bSFlorian Westphal nf_l4proto_log_invalid(skb, net, nf_ct_l3num(ct), 1213d0b527bSFlorian Westphal nf_ct_protonum(ct), "%pV", &vaf); 1223d0b527bSFlorian Westphal va_end(args); 1233d0b527bSFlorian Westphal } 1243d0b527bSFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_l4proto_log_invalid); 125d62f9ed4SPatrick McHardy #endif 126d62f9ed4SPatrick McHardy 127dd2934a9SFlorian Westphal const struct nf_conntrack_l4proto *__nf_ct_l4proto_find(u8 l4proto) 1288f03dea5SMartin Josefsson { 129dd2934a9SFlorian Westphal if (unlikely(l4proto >= ARRAY_SIZE(nf_ct_protos))) 130605dcad6SMartin Josefsson return &nf_conntrack_l4proto_generic; 1318f03dea5SMartin Josefsson 132dd2934a9SFlorian Westphal return rcu_dereference(nf_ct_protos[l4proto]); 1338f03dea5SMartin Josefsson } 13413b18339SPatrick McHardy EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find); 1358f03dea5SMartin Josefsson 136dd2934a9SFlorian Westphal const struct nf_conntrack_l4proto *nf_ct_l4proto_find_get(u8 l4num) 137c1ebd7dfSPablo Neira Ayuso { 138b3480fe0SFlorian Westphal const struct nf_conntrack_l4proto *p; 139c1ebd7dfSPablo Neira Ayuso 140c1ebd7dfSPablo Neira Ayuso rcu_read_lock(); 141dd2934a9SFlorian Westphal p = __nf_ct_l4proto_find(l4num); 142c1ebd7dfSPablo Neira Ayuso if (!try_module_get(p->me)) 143c1ebd7dfSPablo Neira Ayuso p = &nf_conntrack_l4proto_generic; 144c1ebd7dfSPablo Neira Ayuso rcu_read_unlock(); 145c1ebd7dfSPablo Neira Ayuso 146c1ebd7dfSPablo Neira Ayuso return p; 147c1ebd7dfSPablo Neira Ayuso } 148c1ebd7dfSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get); 149c1ebd7dfSPablo Neira Ayuso 1502a04aabfSJulia Lawall void nf_ct_l4proto_put(const struct nf_conntrack_l4proto *p) 151c1ebd7dfSPablo Neira Ayuso { 152c1ebd7dfSPablo Neira Ayuso module_put(p->me); 153c1ebd7dfSPablo Neira Ayuso } 154c1ebd7dfSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_l4proto_put); 155c1ebd7dfSPablo Neira Ayuso 156605dcad6SMartin Josefsson static int kill_l4proto(struct nf_conn *i, void *data) 1578f03dea5SMartin Josefsson { 158b3480fe0SFlorian Westphal const struct nf_conntrack_l4proto *l4proto; 15968ad546aSsimran singhal l4proto = data; 160dd2934a9SFlorian Westphal return nf_ct_protonum(i) == l4proto->l4proto; 1618f03dea5SMartin Josefsson } 1628f03dea5SMartin Josefsson 1632c352f44SGao feng static struct nf_proto_net *nf_ct_l4proto_net(struct net *net, 1642a04aabfSJulia Lawall const struct nf_conntrack_l4proto *l4proto) 1652c352f44SGao feng { 16608911475SPablo Neira Ayuso if (l4proto->get_net_proto) { 16708911475SPablo Neira Ayuso /* statically built-in protocols use static per-net */ 16808911475SPablo Neira Ayuso return l4proto->get_net_proto(net); 16908911475SPablo Neira Ayuso } else if (l4proto->net_id) { 17008911475SPablo Neira Ayuso /* ... and loadable protocols use dynamic per-net */ 1712c352f44SGao feng return net_generic(net, *l4proto->net_id); 1722c352f44SGao feng } 17315f585bdSGao feng return NULL; 17415f585bdSGao feng } 1752c352f44SGao feng 1762c352f44SGao feng static 1772c352f44SGao feng int nf_ct_l4proto_register_sysctl(struct net *net, 178df7043beSYafang Shao struct nf_proto_net *pn) 179d62f9ed4SPatrick McHardy { 180d62f9ed4SPatrick McHardy int err = 0; 181d62f9ed4SPatrick McHardy 182d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 1832c352f44SGao feng if (pn->ctl_table != NULL) { 1842c352f44SGao feng err = nf_ct_register_sysctl(net, 1852c352f44SGao feng &pn->ctl_table_header, 186f99e8f71SEric W. Biederman "net/netfilter", 187fa34fff5SGao feng pn->ctl_table); 1882c352f44SGao feng if (err < 0) { 1892c352f44SGao feng if (!pn->users) { 1902c352f44SGao feng kfree(pn->ctl_table); 1912c352f44SGao feng pn->ctl_table = NULL; 1922c352f44SGao feng } 193d62f9ed4SPatrick McHardy } 1942c352f44SGao feng } 195933a41e7SPatrick McHardy #endif /* CONFIG_SYSCTL */ 196d62f9ed4SPatrick McHardy return err; 197d62f9ed4SPatrick McHardy } 198d62f9ed4SPatrick McHardy 1992c352f44SGao feng static 200df7043beSYafang Shao void nf_ct_l4proto_unregister_sysctl(struct nf_proto_net *pn) 201d62f9ed4SPatrick McHardy { 202d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 2032c352f44SGao feng if (pn->ctl_table_header != NULL) 2042c352f44SGao feng nf_ct_unregister_sysctl(&pn->ctl_table_header, 2052c352f44SGao feng &pn->ctl_table, 206fa34fff5SGao feng pn->users); 207933a41e7SPatrick McHardy #endif /* CONFIG_SYSCTL */ 208d62f9ed4SPatrick McHardy } 209d62f9ed4SPatrick McHardy 2108f03dea5SMartin Josefsson /* FIXME: Allow NULL functions and sub in pointers to generic for 2118f03dea5SMartin Josefsson them. --RR */ 212cd9ceafcSFlorian Westphal int nf_ct_l4proto_register_one(const struct nf_conntrack_l4proto *l4proto) 2138f03dea5SMartin Josefsson { 2148f03dea5SMartin Josefsson int ret = 0; 2158f03dea5SMartin Josefsson 21639215846SFlorian Westphal if ((l4proto->to_nlattr && l4proto->nlattr_size == 0) || 2170e54d217SDavide Caratti (l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size)) 218d0dba725SHolger Eitzenberger return -EINVAL; 219d0dba725SHolger Eitzenberger 220b19caa0cSPatrick McHardy mutex_lock(&nf_ct_proto_mutex); 221dd2934a9SFlorian Westphal if (rcu_dereference_protected( 222dd2934a9SFlorian Westphal nf_ct_protos[l4proto->l4proto], 2230e60ebe0SEric Dumazet lockdep_is_held(&nf_ct_proto_mutex) 2240e60ebe0SEric Dumazet ) != &nf_conntrack_l4proto_generic) { 225c6a1e615SPatrick McHardy ret = -EBUSY; 226c6a1e615SPatrick McHardy goto out_unlock; 2278f03dea5SMartin Josefsson } 2288f03dea5SMartin Josefsson 229dd2934a9SFlorian Westphal rcu_assign_pointer(nf_ct_protos[l4proto->l4proto], l4proto); 2308f03dea5SMartin Josefsson out_unlock: 231b19caa0cSPatrick McHardy mutex_unlock(&nf_ct_proto_mutex); 2328f03dea5SMartin Josefsson return ret; 2338f03dea5SMartin Josefsson } 2340e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_register_one); 2352c352f44SGao feng 2360e54d217SDavide Caratti int nf_ct_l4proto_pernet_register_one(struct net *net, 2372a04aabfSJulia Lawall const struct nf_conntrack_l4proto *l4proto) 2382c352f44SGao feng { 2392c352f44SGao feng int ret = 0; 240fa34fff5SGao feng struct nf_proto_net *pn = NULL; 2412c352f44SGao feng 242fa0f61f0SGao feng if (l4proto->init_net) { 243ca2ca6e1SFlorian Westphal ret = l4proto->init_net(net); 244fa0f61f0SGao feng if (ret < 0) 245fa34fff5SGao feng goto out; 246fa0f61f0SGao feng } 2472c352f44SGao feng 248fa34fff5SGao feng pn = nf_ct_l4proto_net(net, l4proto); 249fa34fff5SGao feng if (pn == NULL) 250fa34fff5SGao feng goto out; 251fa34fff5SGao feng 252df7043beSYafang Shao ret = nf_ct_l4proto_register_sysctl(net, pn); 2532c352f44SGao feng if (ret < 0) 254fa34fff5SGao feng goto out; 2552c352f44SGao feng 256fa34fff5SGao feng pn->users++; 257fa34fff5SGao feng out: 258fa0f61f0SGao feng return ret; 2592c352f44SGao feng } 2600e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register_one); 2618f03dea5SMartin Josefsson 2622a04aabfSJulia Lawall static void __nf_ct_l4proto_unregister_one(const struct nf_conntrack_l4proto *l4proto) 2632c41f33cSFlorian Westphal 2648f03dea5SMartin Josefsson { 265dd2934a9SFlorian Westphal BUG_ON(l4proto->l4proto >= ARRAY_SIZE(nf_ct_protos)); 266ae5718fbSMartin Josefsson 2670e60ebe0SEric Dumazet BUG_ON(rcu_dereference_protected( 268dd2934a9SFlorian Westphal nf_ct_protos[l4proto->l4proto], 2690e60ebe0SEric Dumazet lockdep_is_held(&nf_ct_proto_mutex) 2700e60ebe0SEric Dumazet ) != l4proto); 271dd2934a9SFlorian Westphal rcu_assign_pointer(nf_ct_protos[l4proto->l4proto], 272923f4902SPatrick McHardy &nf_conntrack_l4proto_generic); 2732c41f33cSFlorian Westphal } 2742c41f33cSFlorian Westphal 2752a04aabfSJulia Lawall void nf_ct_l4proto_unregister_one(const struct nf_conntrack_l4proto *l4proto) 2762c41f33cSFlorian Westphal { 2772c41f33cSFlorian Westphal mutex_lock(&nf_ct_proto_mutex); 2782c41f33cSFlorian Westphal __nf_ct_l4proto_unregister_one(l4proto); 2790661cca9SPatrick McHardy mutex_unlock(&nf_ct_proto_mutex); 2800661cca9SPatrick McHardy 2811c117d3bSFlorian Westphal synchronize_net(); 2821c117d3bSFlorian Westphal /* Remove all contrack entries for this protocol */ 2831c117d3bSFlorian Westphal nf_ct_iterate_destroy(kill_l4proto, (void *)l4proto); 2842c352f44SGao feng } 2850e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_unregister_one); 286d62f9ed4SPatrick McHardy 2870e54d217SDavide Caratti void nf_ct_l4proto_pernet_unregister_one(struct net *net, 2882a04aabfSJulia Lawall const struct nf_conntrack_l4proto *l4proto) 2892c352f44SGao feng { 290809c2d9aSAaron Conole struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto); 291fa34fff5SGao feng 292fa34fff5SGao feng if (pn == NULL) 293fa34fff5SGao feng return; 294fa34fff5SGao feng 295fa34fff5SGao feng pn->users--; 296df7043beSYafang Shao nf_ct_l4proto_unregister_sysctl(pn); 2978f03dea5SMartin Josefsson } 2980e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_unregister_one); 2990e54d217SDavide Caratti 300a0ae2562SFlorian Westphal static void 301a0ae2562SFlorian Westphal nf_ct_l4proto_unregister(const struct nf_conntrack_l4proto * const l4proto[], 302a0ae2562SFlorian Westphal unsigned int num_proto) 303a0ae2562SFlorian Westphal { 3041c117d3bSFlorian Westphal int i; 3051c117d3bSFlorian Westphal 306a0ae2562SFlorian Westphal mutex_lock(&nf_ct_proto_mutex); 3071c117d3bSFlorian Westphal for (i = 0; i < num_proto; i++) 3081c117d3bSFlorian Westphal __nf_ct_l4proto_unregister_one(l4proto[i]); 309a0ae2562SFlorian Westphal mutex_unlock(&nf_ct_proto_mutex); 310a0ae2562SFlorian Westphal 311a0ae2562SFlorian Westphal synchronize_net(); 3121c117d3bSFlorian Westphal 3131c117d3bSFlorian Westphal for (i = 0; i < num_proto; i++) 3141c117d3bSFlorian Westphal nf_ct_iterate_destroy(kill_l4proto, (void *)l4proto[i]); 315a0ae2562SFlorian Westphal } 316a0ae2562SFlorian Westphal 317a0ae2562SFlorian Westphal static int 318a0ae2562SFlorian Westphal nf_ct_l4proto_register(const struct nf_conntrack_l4proto * const l4proto[], 3190e54d217SDavide Caratti unsigned int num_proto) 3200e54d217SDavide Caratti { 321dd2934a9SFlorian Westphal int ret = -EINVAL; 3220e54d217SDavide Caratti unsigned int i; 3230e54d217SDavide Caratti 3240e54d217SDavide Caratti for (i = 0; i < num_proto; i++) { 3250e54d217SDavide Caratti ret = nf_ct_l4proto_register_one(l4proto[i]); 3260e54d217SDavide Caratti if (ret < 0) 3270e54d217SDavide Caratti break; 3280e54d217SDavide Caratti } 3290e54d217SDavide Caratti if (i != num_proto) { 330dd2934a9SFlorian Westphal pr_err("nf_conntrack: can't register l4 %d proto.\n", 331dd2934a9SFlorian Westphal l4proto[i]->l4proto); 3320e54d217SDavide Caratti nf_ct_l4proto_unregister(l4proto, i); 3330e54d217SDavide Caratti } 3340e54d217SDavide Caratti return ret; 3350e54d217SDavide Caratti } 3360e54d217SDavide Caratti 3370e54d217SDavide Caratti int nf_ct_l4proto_pernet_register(struct net *net, 338cd9ceafcSFlorian Westphal const struct nf_conntrack_l4proto *const l4proto[], 3390e54d217SDavide Caratti unsigned int num_proto) 3400e54d217SDavide Caratti { 3410e54d217SDavide Caratti int ret = -EINVAL; 3420e54d217SDavide Caratti unsigned int i; 3430e54d217SDavide Caratti 3440e54d217SDavide Caratti for (i = 0; i < num_proto; i++) { 3450e54d217SDavide Caratti ret = nf_ct_l4proto_pernet_register_one(net, l4proto[i]); 3460e54d217SDavide Caratti if (ret < 0) 3470e54d217SDavide Caratti break; 3480e54d217SDavide Caratti } 3490e54d217SDavide Caratti if (i != num_proto) { 350dd2934a9SFlorian Westphal pr_err("nf_conntrack %d: pernet registration failed\n", 351dd2934a9SFlorian Westphal l4proto[i]->l4proto); 3520e54d217SDavide Caratti nf_ct_l4proto_pernet_unregister(net, l4proto, i); 3530e54d217SDavide Caratti } 3540e54d217SDavide Caratti return ret; 3550e54d217SDavide Caratti } 3560e54d217SDavide Caratti EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register); 3570e54d217SDavide Caratti 3580e54d217SDavide Caratti void nf_ct_l4proto_pernet_unregister(struct net *net, 359cd9ceafcSFlorian Westphal const struct nf_conntrack_l4proto *const l4proto[], 3600e54d217SDavide Caratti unsigned int num_proto) 3610e54d217SDavide Caratti { 3620e54d217SDavide Caratti while (num_proto-- != 0) 3630e54d217SDavide Caratti nf_ct_l4proto_pernet_unregister_one(net, l4proto[num_proto]); 3640e54d217SDavide Caratti } 365c296bb4dSGao feng EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_unregister); 366ac5357ebSPatrick McHardy 367827318feSFlorian Westphal static unsigned int nf_confirm(struct sk_buff *skb, 368827318feSFlorian Westphal unsigned int protoff, 369827318feSFlorian Westphal struct nf_conn *ct, 370827318feSFlorian Westphal enum ip_conntrack_info ctinfo) 371a0ae2562SFlorian Westphal { 372a0ae2562SFlorian Westphal const struct nf_conn_help *help; 373a0ae2562SFlorian Westphal 374a0ae2562SFlorian Westphal help = nfct_help(ct); 375827318feSFlorian Westphal if (help) { 376827318feSFlorian Westphal const struct nf_conntrack_helper *helper; 377827318feSFlorian Westphal int ret; 378a0ae2562SFlorian Westphal 379a0ae2562SFlorian Westphal /* rcu_read_lock()ed by nf_hook_thresh */ 380a0ae2562SFlorian Westphal helper = rcu_dereference(help->helper); 381827318feSFlorian Westphal if (helper) { 382827318feSFlorian Westphal ret = helper->help(skb, 383827318feSFlorian Westphal protoff, 384a0ae2562SFlorian Westphal ct, ctinfo); 385827318feSFlorian Westphal if (ret != NF_ACCEPT) 386827318feSFlorian Westphal return ret; 387827318feSFlorian Westphal } 388827318feSFlorian Westphal } 389827318feSFlorian Westphal 390827318feSFlorian Westphal if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && 391827318feSFlorian Westphal !nf_is_loopback_packet(skb)) { 392827318feSFlorian Westphal if (!nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) { 393827318feSFlorian Westphal NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); 394827318feSFlorian Westphal return NF_DROP; 395827318feSFlorian Westphal } 396827318feSFlorian Westphal } 397827318feSFlorian Westphal 398827318feSFlorian Westphal /* We've seen it coming out the other side: confirm it */ 399827318feSFlorian Westphal return nf_conntrack_confirm(skb); 400a0ae2562SFlorian Westphal } 401a0ae2562SFlorian Westphal 402a0ae2562SFlorian Westphal static unsigned int ipv4_confirm(void *priv, 403a0ae2562SFlorian Westphal struct sk_buff *skb, 404a0ae2562SFlorian Westphal const struct nf_hook_state *state) 405a0ae2562SFlorian Westphal { 406a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 407827318feSFlorian Westphal struct nf_conn *ct; 408a0ae2562SFlorian Westphal 409a0ae2562SFlorian Westphal ct = nf_ct_get(skb, &ctinfo); 410a0ae2562SFlorian Westphal if (!ct || ctinfo == IP_CT_RELATED_REPLY) 411a0ae2562SFlorian Westphal return nf_conntrack_confirm(skb); 412827318feSFlorian Westphal 413827318feSFlorian Westphal return nf_confirm(skb, 414827318feSFlorian Westphal skb_network_offset(skb) + ip_hdrlen(skb), 415827318feSFlorian Westphal ct, ctinfo); 416a0ae2562SFlorian Westphal } 417a0ae2562SFlorian Westphal 418a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_in(void *priv, 419a0ae2562SFlorian Westphal struct sk_buff *skb, 420a0ae2562SFlorian Westphal const struct nf_hook_state *state) 421a0ae2562SFlorian Westphal { 42293e66024SFlorian Westphal return nf_conntrack_in(skb, state); 423a0ae2562SFlorian Westphal } 424a0ae2562SFlorian Westphal 425a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_local(void *priv, 426a0ae2562SFlorian Westphal struct sk_buff *skb, 427a0ae2562SFlorian Westphal const struct nf_hook_state *state) 428a0ae2562SFlorian Westphal { 429a0ae2562SFlorian Westphal if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */ 430a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 431a0ae2562SFlorian Westphal struct nf_conn *tmpl; 432a0ae2562SFlorian Westphal 433a0ae2562SFlorian Westphal tmpl = nf_ct_get(skb, &ctinfo); 434a0ae2562SFlorian Westphal if (tmpl && nf_ct_is_template(tmpl)) { 435a0ae2562SFlorian Westphal /* when skipping ct, clear templates to avoid fooling 436a0ae2562SFlorian Westphal * later targets/matches 437a0ae2562SFlorian Westphal */ 438a0ae2562SFlorian Westphal skb->_nfct = 0; 439a0ae2562SFlorian Westphal nf_ct_put(tmpl); 440a0ae2562SFlorian Westphal } 441a0ae2562SFlorian Westphal return NF_ACCEPT; 442a0ae2562SFlorian Westphal } 443a0ae2562SFlorian Westphal 44493e66024SFlorian Westphal return nf_conntrack_in(skb, state); 445a0ae2562SFlorian Westphal } 446a0ae2562SFlorian Westphal 447a0ae2562SFlorian Westphal /* Connection tracking may drop packets, but never alters them, so 448a0ae2562SFlorian Westphal * make it the first hook. 449a0ae2562SFlorian Westphal */ 450a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv4_conntrack_ops[] = { 451a0ae2562SFlorian Westphal { 452a0ae2562SFlorian Westphal .hook = ipv4_conntrack_in, 453a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 454a0ae2562SFlorian Westphal .hooknum = NF_INET_PRE_ROUTING, 455a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK, 456a0ae2562SFlorian Westphal }, 457a0ae2562SFlorian Westphal { 458a0ae2562SFlorian Westphal .hook = ipv4_conntrack_local, 459a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 460a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_OUT, 461a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK, 462a0ae2562SFlorian Westphal }, 463a0ae2562SFlorian Westphal { 464a0ae2562SFlorian Westphal .hook = ipv4_confirm, 465a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 466a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING, 467a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_CONFIRM, 468a0ae2562SFlorian Westphal }, 469a0ae2562SFlorian Westphal { 470a0ae2562SFlorian Westphal .hook = ipv4_confirm, 471a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4, 472a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN, 473a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_CONFIRM, 474a0ae2562SFlorian Westphal }, 475a0ae2562SFlorian Westphal }; 476a0ae2562SFlorian Westphal 477a0ae2562SFlorian Westphal /* Fast function for those who don't want to parse /proc (and I don't 478a0ae2562SFlorian Westphal * blame them). 479a0ae2562SFlorian Westphal * Reversing the socket's dst/src point of view gives us the reply 480a0ae2562SFlorian Westphal * mapping. 481a0ae2562SFlorian Westphal */ 482a0ae2562SFlorian Westphal static int 483a0ae2562SFlorian Westphal getorigdst(struct sock *sk, int optval, void __user *user, int *len) 484a0ae2562SFlorian Westphal { 485a0ae2562SFlorian Westphal const struct inet_sock *inet = inet_sk(sk); 486a0ae2562SFlorian Westphal const struct nf_conntrack_tuple_hash *h; 487a0ae2562SFlorian Westphal struct nf_conntrack_tuple tuple; 488a0ae2562SFlorian Westphal 489a0ae2562SFlorian Westphal memset(&tuple, 0, sizeof(tuple)); 490a0ae2562SFlorian Westphal 491a0ae2562SFlorian Westphal lock_sock(sk); 492a0ae2562SFlorian Westphal tuple.src.u3.ip = inet->inet_rcv_saddr; 493a0ae2562SFlorian Westphal tuple.src.u.tcp.port = inet->inet_sport; 494a0ae2562SFlorian Westphal tuple.dst.u3.ip = inet->inet_daddr; 495a0ae2562SFlorian Westphal tuple.dst.u.tcp.port = inet->inet_dport; 496a0ae2562SFlorian Westphal tuple.src.l3num = PF_INET; 497a0ae2562SFlorian Westphal tuple.dst.protonum = sk->sk_protocol; 498a0ae2562SFlorian Westphal release_sock(sk); 499a0ae2562SFlorian Westphal 500a0ae2562SFlorian Westphal /* We only do TCP and SCTP at the moment: is there a better way? */ 501a0ae2562SFlorian Westphal if (tuple.dst.protonum != IPPROTO_TCP && 502a0ae2562SFlorian Westphal tuple.dst.protonum != IPPROTO_SCTP) { 503a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: Not a TCP/SCTP socket\n"); 504a0ae2562SFlorian Westphal return -ENOPROTOOPT; 505a0ae2562SFlorian Westphal } 506a0ae2562SFlorian Westphal 507a0ae2562SFlorian Westphal if ((unsigned int)*len < sizeof(struct sockaddr_in)) { 508a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: len %d not %zu\n", 509a0ae2562SFlorian Westphal *len, sizeof(struct sockaddr_in)); 510a0ae2562SFlorian Westphal return -EINVAL; 511a0ae2562SFlorian Westphal } 512a0ae2562SFlorian Westphal 513a0ae2562SFlorian Westphal h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple); 514a0ae2562SFlorian Westphal if (h) { 515a0ae2562SFlorian Westphal struct sockaddr_in sin; 516a0ae2562SFlorian Westphal struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); 517a0ae2562SFlorian Westphal 518a0ae2562SFlorian Westphal sin.sin_family = AF_INET; 519a0ae2562SFlorian Westphal sin.sin_port = ct->tuplehash[IP_CT_DIR_ORIGINAL] 520a0ae2562SFlorian Westphal .tuple.dst.u.tcp.port; 521a0ae2562SFlorian Westphal sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL] 522a0ae2562SFlorian Westphal .tuple.dst.u3.ip; 523a0ae2562SFlorian Westphal memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); 524a0ae2562SFlorian Westphal 525a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: %pI4 %u\n", 526a0ae2562SFlorian Westphal &sin.sin_addr.s_addr, ntohs(sin.sin_port)); 527a0ae2562SFlorian Westphal nf_ct_put(ct); 528a0ae2562SFlorian Westphal if (copy_to_user(user, &sin, sizeof(sin)) != 0) 529a0ae2562SFlorian Westphal return -EFAULT; 530a0ae2562SFlorian Westphal else 531a0ae2562SFlorian Westphal return 0; 532a0ae2562SFlorian Westphal } 533a0ae2562SFlorian Westphal pr_debug("SO_ORIGINAL_DST: Can't find %pI4/%u-%pI4/%u.\n", 534a0ae2562SFlorian Westphal &tuple.src.u3.ip, ntohs(tuple.src.u.tcp.port), 535a0ae2562SFlorian Westphal &tuple.dst.u3.ip, ntohs(tuple.dst.u.tcp.port)); 536a0ae2562SFlorian Westphal return -ENOENT; 537a0ae2562SFlorian Westphal } 538a0ae2562SFlorian Westphal 539a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst = { 540a0ae2562SFlorian Westphal .pf = PF_INET, 541a0ae2562SFlorian Westphal .get_optmin = SO_ORIGINAL_DST, 542a0ae2562SFlorian Westphal .get_optmax = SO_ORIGINAL_DST + 1, 543a0ae2562SFlorian Westphal .get = getorigdst, 544a0ae2562SFlorian Westphal .owner = THIS_MODULE, 545a0ae2562SFlorian Westphal }; 546a0ae2562SFlorian Westphal 547a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 548a0ae2562SFlorian Westphal static int 549a0ae2562SFlorian Westphal ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len) 550a0ae2562SFlorian Westphal { 551a0ae2562SFlorian Westphal struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 }; 552a0ae2562SFlorian Westphal const struct ipv6_pinfo *inet6 = inet6_sk(sk); 553a0ae2562SFlorian Westphal const struct inet_sock *inet = inet_sk(sk); 554a0ae2562SFlorian Westphal const struct nf_conntrack_tuple_hash *h; 555a0ae2562SFlorian Westphal struct sockaddr_in6 sin6; 556a0ae2562SFlorian Westphal struct nf_conn *ct; 557a0ae2562SFlorian Westphal __be32 flow_label; 558a0ae2562SFlorian Westphal int bound_dev_if; 559a0ae2562SFlorian Westphal 560a0ae2562SFlorian Westphal lock_sock(sk); 561a0ae2562SFlorian Westphal tuple.src.u3.in6 = sk->sk_v6_rcv_saddr; 562a0ae2562SFlorian Westphal tuple.src.u.tcp.port = inet->inet_sport; 563a0ae2562SFlorian Westphal tuple.dst.u3.in6 = sk->sk_v6_daddr; 564a0ae2562SFlorian Westphal tuple.dst.u.tcp.port = inet->inet_dport; 565a0ae2562SFlorian Westphal tuple.dst.protonum = sk->sk_protocol; 566a0ae2562SFlorian Westphal bound_dev_if = sk->sk_bound_dev_if; 567a0ae2562SFlorian Westphal flow_label = inet6->flow_label; 568a0ae2562SFlorian Westphal release_sock(sk); 569a0ae2562SFlorian Westphal 570a0ae2562SFlorian Westphal if (tuple.dst.protonum != IPPROTO_TCP && 571a0ae2562SFlorian Westphal tuple.dst.protonum != IPPROTO_SCTP) 572a0ae2562SFlorian Westphal return -ENOPROTOOPT; 573a0ae2562SFlorian Westphal 574a0ae2562SFlorian Westphal if (*len < 0 || (unsigned int)*len < sizeof(sin6)) 575a0ae2562SFlorian Westphal return -EINVAL; 576a0ae2562SFlorian Westphal 577a0ae2562SFlorian Westphal h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple); 578a0ae2562SFlorian Westphal if (!h) { 579a0ae2562SFlorian Westphal pr_debug("IP6T_SO_ORIGINAL_DST: Can't find %pI6c/%u-%pI6c/%u.\n", 580a0ae2562SFlorian Westphal &tuple.src.u3.ip6, ntohs(tuple.src.u.tcp.port), 581a0ae2562SFlorian Westphal &tuple.dst.u3.ip6, ntohs(tuple.dst.u.tcp.port)); 582a0ae2562SFlorian Westphal return -ENOENT; 583a0ae2562SFlorian Westphal } 584a0ae2562SFlorian Westphal 585a0ae2562SFlorian Westphal ct = nf_ct_tuplehash_to_ctrack(h); 586a0ae2562SFlorian Westphal 587a0ae2562SFlorian Westphal sin6.sin6_family = AF_INET6; 588a0ae2562SFlorian Westphal sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port; 589a0ae2562SFlorian Westphal sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK; 590a0ae2562SFlorian Westphal memcpy(&sin6.sin6_addr, 591a0ae2562SFlorian Westphal &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6, 592a0ae2562SFlorian Westphal sizeof(sin6.sin6_addr)); 593a0ae2562SFlorian Westphal 594a0ae2562SFlorian Westphal nf_ct_put(ct); 595a0ae2562SFlorian Westphal sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if); 596a0ae2562SFlorian Westphal return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0; 597a0ae2562SFlorian Westphal } 598a0ae2562SFlorian Westphal 599a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst6 = { 600a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 601a0ae2562SFlorian Westphal .get_optmin = IP6T_SO_ORIGINAL_DST, 602a0ae2562SFlorian Westphal .get_optmax = IP6T_SO_ORIGINAL_DST + 1, 603a0ae2562SFlorian Westphal .get = ipv6_getorigdst, 604a0ae2562SFlorian Westphal .owner = THIS_MODULE, 605a0ae2562SFlorian Westphal }; 606a0ae2562SFlorian Westphal 607a0ae2562SFlorian Westphal static unsigned int ipv6_confirm(void *priv, 608a0ae2562SFlorian Westphal struct sk_buff *skb, 609a0ae2562SFlorian Westphal const struct nf_hook_state *state) 610a0ae2562SFlorian Westphal { 611a0ae2562SFlorian Westphal struct nf_conn *ct; 612a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo; 613a0ae2562SFlorian Westphal unsigned char pnum = ipv6_hdr(skb)->nexthdr; 614a0ae2562SFlorian Westphal __be16 frag_off; 615827318feSFlorian Westphal int protoff; 616a0ae2562SFlorian Westphal 617a0ae2562SFlorian Westphal ct = nf_ct_get(skb, &ctinfo); 618a0ae2562SFlorian Westphal if (!ct || ctinfo == IP_CT_RELATED_REPLY) 619827318feSFlorian Westphal return nf_conntrack_confirm(skb); 620a0ae2562SFlorian Westphal 621a0ae2562SFlorian Westphal protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum, 622a0ae2562SFlorian Westphal &frag_off); 623a0ae2562SFlorian Westphal if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { 624a0ae2562SFlorian Westphal pr_debug("proto header not found\n"); 625827318feSFlorian Westphal return nf_conntrack_confirm(skb); 626a0ae2562SFlorian Westphal } 627a0ae2562SFlorian Westphal 628827318feSFlorian Westphal return nf_confirm(skb, protoff, ct, ctinfo); 629a0ae2562SFlorian Westphal } 630a0ae2562SFlorian Westphal 631a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_in(void *priv, 632a0ae2562SFlorian Westphal struct sk_buff *skb, 633a0ae2562SFlorian Westphal const struct nf_hook_state *state) 634a0ae2562SFlorian Westphal { 63593e66024SFlorian Westphal return nf_conntrack_in(skb, state); 636a0ae2562SFlorian Westphal } 637a0ae2562SFlorian Westphal 638a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_local(void *priv, 639a0ae2562SFlorian Westphal struct sk_buff *skb, 640a0ae2562SFlorian Westphal const struct nf_hook_state *state) 641a0ae2562SFlorian Westphal { 64293e66024SFlorian Westphal return nf_conntrack_in(skb, state); 643a0ae2562SFlorian Westphal } 644a0ae2562SFlorian Westphal 645a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv6_conntrack_ops[] = { 646a0ae2562SFlorian Westphal { 647a0ae2562SFlorian Westphal .hook = ipv6_conntrack_in, 648a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 649a0ae2562SFlorian Westphal .hooknum = NF_INET_PRE_ROUTING, 650a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK, 651a0ae2562SFlorian Westphal }, 652a0ae2562SFlorian Westphal { 653a0ae2562SFlorian Westphal .hook = ipv6_conntrack_local, 654a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 655a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_OUT, 656a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK, 657a0ae2562SFlorian Westphal }, 658a0ae2562SFlorian Westphal { 659a0ae2562SFlorian Westphal .hook = ipv6_confirm, 660a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 661a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING, 662a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_LAST, 663a0ae2562SFlorian Westphal }, 664a0ae2562SFlorian Westphal { 665a0ae2562SFlorian Westphal .hook = ipv6_confirm, 666a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6, 667a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN, 668a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_LAST - 1, 669a0ae2562SFlorian Westphal }, 670a0ae2562SFlorian Westphal }; 671a0ae2562SFlorian Westphal #endif 672a0ae2562SFlorian Westphal 673f94e6380SFlorian Westphal static int nf_ct_tcp_fixup(struct nf_conn *ct, void *_nfproto) 674f94e6380SFlorian Westphal { 675f94e6380SFlorian Westphal u8 nfproto = (unsigned long)_nfproto; 676f94e6380SFlorian Westphal 677f94e6380SFlorian Westphal if (nf_ct_l3num(ct) != nfproto) 678f94e6380SFlorian Westphal return 0; 679f94e6380SFlorian Westphal 680f94e6380SFlorian Westphal if (nf_ct_protonum(ct) == IPPROTO_TCP && 681f94e6380SFlorian Westphal ct->proto.tcp.state == TCP_CONNTRACK_ESTABLISHED) { 682f94e6380SFlorian Westphal ct->proto.tcp.seen[0].td_maxwin = 0; 683f94e6380SFlorian Westphal ct->proto.tcp.seen[1].td_maxwin = 0; 684f94e6380SFlorian Westphal } 685f94e6380SFlorian Westphal 686f94e6380SFlorian Westphal return 0; 687f94e6380SFlorian Westphal } 688f94e6380SFlorian Westphal 689a0ae2562SFlorian Westphal static int nf_ct_netns_do_get(struct net *net, u8 nfproto) 690a0ae2562SFlorian Westphal { 691a0ae2562SFlorian Westphal struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); 692f94e6380SFlorian Westphal bool fixup_needed = false; 693a0ae2562SFlorian Westphal int err = 0; 694a0ae2562SFlorian Westphal 695a0ae2562SFlorian Westphal mutex_lock(&nf_ct_proto_mutex); 696a0ae2562SFlorian Westphal 697a0ae2562SFlorian Westphal switch (nfproto) { 698a0ae2562SFlorian Westphal case NFPROTO_IPV4: 699a0ae2562SFlorian Westphal cnet->users4++; 700a0ae2562SFlorian Westphal if (cnet->users4 > 1) 701a0ae2562SFlorian Westphal goto out_unlock; 702a0ae2562SFlorian Westphal err = nf_defrag_ipv4_enable(net); 703a0ae2562SFlorian Westphal if (err) { 704a0ae2562SFlorian Westphal cnet->users4 = 0; 705a0ae2562SFlorian Westphal goto out_unlock; 706a0ae2562SFlorian Westphal } 707a0ae2562SFlorian Westphal 708a0ae2562SFlorian Westphal err = nf_register_net_hooks(net, ipv4_conntrack_ops, 709a0ae2562SFlorian Westphal ARRAY_SIZE(ipv4_conntrack_ops)); 710a0ae2562SFlorian Westphal if (err) 711a0ae2562SFlorian Westphal cnet->users4 = 0; 712f94e6380SFlorian Westphal else 713f94e6380SFlorian Westphal fixup_needed = true; 714a0ae2562SFlorian Westphal break; 715a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 716a0ae2562SFlorian Westphal case NFPROTO_IPV6: 717a0ae2562SFlorian Westphal cnet->users6++; 718a0ae2562SFlorian Westphal if (cnet->users6 > 1) 719a0ae2562SFlorian Westphal goto out_unlock; 720a0ae2562SFlorian Westphal err = nf_defrag_ipv6_enable(net); 721a0ae2562SFlorian Westphal if (err < 0) { 722a0ae2562SFlorian Westphal cnet->users6 = 0; 723a0ae2562SFlorian Westphal goto out_unlock; 724a0ae2562SFlorian Westphal } 725a0ae2562SFlorian Westphal 726a0ae2562SFlorian Westphal err = nf_register_net_hooks(net, ipv6_conntrack_ops, 727a0ae2562SFlorian Westphal ARRAY_SIZE(ipv6_conntrack_ops)); 728a0ae2562SFlorian Westphal if (err) 729a0ae2562SFlorian Westphal cnet->users6 = 0; 730f94e6380SFlorian Westphal else 731f94e6380SFlorian Westphal fixup_needed = true; 732a0ae2562SFlorian Westphal break; 733a0ae2562SFlorian Westphal #endif 734a0ae2562SFlorian Westphal default: 735a0ae2562SFlorian Westphal err = -EPROTO; 736a0ae2562SFlorian Westphal break; 737a0ae2562SFlorian Westphal } 738a0ae2562SFlorian Westphal out_unlock: 739a0ae2562SFlorian Westphal mutex_unlock(&nf_ct_proto_mutex); 740f94e6380SFlorian Westphal 741f94e6380SFlorian Westphal if (fixup_needed) 742f94e6380SFlorian Westphal nf_ct_iterate_cleanup_net(net, nf_ct_tcp_fixup, 743f94e6380SFlorian Westphal (void *)(unsigned long)nfproto, 0, 0); 744f94e6380SFlorian Westphal 745a0ae2562SFlorian Westphal return err; 746a0ae2562SFlorian Westphal } 747a0ae2562SFlorian Westphal 748a0ae2562SFlorian Westphal static void nf_ct_netns_do_put(struct net *net, u8 nfproto) 749a0ae2562SFlorian Westphal { 750a0ae2562SFlorian Westphal struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); 751a0ae2562SFlorian Westphal 752a0ae2562SFlorian Westphal mutex_lock(&nf_ct_proto_mutex); 753a0ae2562SFlorian Westphal switch (nfproto) { 754a0ae2562SFlorian Westphal case NFPROTO_IPV4: 755a0ae2562SFlorian Westphal if (cnet->users4 && (--cnet->users4 == 0)) 756a0ae2562SFlorian Westphal nf_unregister_net_hooks(net, ipv4_conntrack_ops, 757a0ae2562SFlorian Westphal ARRAY_SIZE(ipv4_conntrack_ops)); 758a0ae2562SFlorian Westphal break; 759a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 760a0ae2562SFlorian Westphal case NFPROTO_IPV6: 761a0ae2562SFlorian Westphal if (cnet->users6 && (--cnet->users6 == 0)) 762a0ae2562SFlorian Westphal nf_unregister_net_hooks(net, ipv6_conntrack_ops, 763a0ae2562SFlorian Westphal ARRAY_SIZE(ipv6_conntrack_ops)); 764a0ae2562SFlorian Westphal break; 765a0ae2562SFlorian Westphal #endif 766a0ae2562SFlorian Westphal } 767a0ae2562SFlorian Westphal 768a0ae2562SFlorian Westphal mutex_unlock(&nf_ct_proto_mutex); 769a0ae2562SFlorian Westphal } 770a0ae2562SFlorian Westphal 771a0ae2562SFlorian Westphal int nf_ct_netns_get(struct net *net, u8 nfproto) 772a0ae2562SFlorian Westphal { 773a0ae2562SFlorian Westphal int err; 774a0ae2562SFlorian Westphal 775a0ae2562SFlorian Westphal if (nfproto == NFPROTO_INET) { 776a0ae2562SFlorian Westphal err = nf_ct_netns_do_get(net, NFPROTO_IPV4); 777a0ae2562SFlorian Westphal if (err < 0) 778a0ae2562SFlorian Westphal goto err1; 779a0ae2562SFlorian Westphal err = nf_ct_netns_do_get(net, NFPROTO_IPV6); 780a0ae2562SFlorian Westphal if (err < 0) 781a0ae2562SFlorian Westphal goto err2; 782a0ae2562SFlorian Westphal } else { 783a0ae2562SFlorian Westphal err = nf_ct_netns_do_get(net, nfproto); 784a0ae2562SFlorian Westphal if (err < 0) 785a0ae2562SFlorian Westphal goto err1; 786a0ae2562SFlorian Westphal } 787a0ae2562SFlorian Westphal return 0; 788a0ae2562SFlorian Westphal 789a0ae2562SFlorian Westphal err2: 790a0ae2562SFlorian Westphal nf_ct_netns_put(net, NFPROTO_IPV4); 791a0ae2562SFlorian Westphal err1: 792a0ae2562SFlorian Westphal return err; 793a0ae2562SFlorian Westphal } 794a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_get); 795a0ae2562SFlorian Westphal 796a0ae2562SFlorian Westphal void nf_ct_netns_put(struct net *net, uint8_t nfproto) 797a0ae2562SFlorian Westphal { 798a0ae2562SFlorian Westphal if (nfproto == NFPROTO_INET) { 799a0ae2562SFlorian Westphal nf_ct_netns_do_put(net, NFPROTO_IPV4); 800a0ae2562SFlorian Westphal nf_ct_netns_do_put(net, NFPROTO_IPV6); 801a0ae2562SFlorian Westphal } else { 802a0ae2562SFlorian Westphal nf_ct_netns_do_put(net, nfproto); 803a0ae2562SFlorian Westphal } 804a0ae2562SFlorian Westphal } 805a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_put); 806a0ae2562SFlorian Westphal 807a0ae2562SFlorian Westphal static const struct nf_conntrack_l4proto * const builtin_l4proto[] = { 808dd2934a9SFlorian Westphal &nf_conntrack_l4proto_tcp, 809dd2934a9SFlorian Westphal &nf_conntrack_l4proto_udp, 810a0ae2562SFlorian Westphal &nf_conntrack_l4proto_icmp, 811a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_DCCP 812dd2934a9SFlorian Westphal &nf_conntrack_l4proto_dccp, 813a0ae2562SFlorian Westphal #endif 814a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_SCTP 815dd2934a9SFlorian Westphal &nf_conntrack_l4proto_sctp, 816a0ae2562SFlorian Westphal #endif 817a0ae2562SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_UDPLITE 818dd2934a9SFlorian Westphal &nf_conntrack_l4proto_udplite, 819a0ae2562SFlorian Westphal #endif 820a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 821a0ae2562SFlorian Westphal &nf_conntrack_l4proto_icmpv6, 822a0ae2562SFlorian Westphal #endif /* CONFIG_IPV6 */ 823a0ae2562SFlorian Westphal }; 824a0ae2562SFlorian Westphal 825a0ae2562SFlorian Westphal int nf_conntrack_proto_init(void) 826a0ae2562SFlorian Westphal { 827dd2934a9SFlorian Westphal int ret = 0, i; 828a0ae2562SFlorian Westphal 829a0ae2562SFlorian Westphal ret = nf_register_sockopt(&so_getorigdst); 830a0ae2562SFlorian Westphal if (ret < 0) 831a0ae2562SFlorian Westphal return ret; 832a0ae2562SFlorian Westphal 833a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 834a0ae2562SFlorian Westphal ret = nf_register_sockopt(&so_getorigdst6); 835a0ae2562SFlorian Westphal if (ret < 0) 836a0ae2562SFlorian Westphal goto cleanup_sockopt; 837a0ae2562SFlorian Westphal #endif 838dd2934a9SFlorian Westphal 839dd2934a9SFlorian Westphal for (i = 0; i < ARRAY_SIZE(nf_ct_protos); i++) 840dd2934a9SFlorian Westphal RCU_INIT_POINTER(nf_ct_protos[i], 841dd2934a9SFlorian Westphal &nf_conntrack_l4proto_generic); 842dd2934a9SFlorian Westphal 843a0ae2562SFlorian Westphal ret = nf_ct_l4proto_register(builtin_l4proto, 844a0ae2562SFlorian Westphal ARRAY_SIZE(builtin_l4proto)); 845a0ae2562SFlorian Westphal if (ret < 0) 846a0ae2562SFlorian Westphal goto cleanup_sockopt2; 847a0ae2562SFlorian Westphal 848a0ae2562SFlorian Westphal return ret; 849a0ae2562SFlorian Westphal cleanup_sockopt2: 850a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst); 851a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 852a0ae2562SFlorian Westphal cleanup_sockopt: 853a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst6); 854a0ae2562SFlorian Westphal #endif 855a0ae2562SFlorian Westphal return ret; 856a0ae2562SFlorian Westphal } 857a0ae2562SFlorian Westphal 858a0ae2562SFlorian Westphal void nf_conntrack_proto_fini(void) 859a0ae2562SFlorian Westphal { 860a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst); 861a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 862a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst6); 863a0ae2562SFlorian Westphal #endif 864a0ae2562SFlorian Westphal } 865a0ae2562SFlorian Westphal 86604d87001SGao feng int nf_conntrack_proto_pernet_init(struct net *net) 867ac5357ebSPatrick McHardy { 868ac5357ebSPatrick McHardy int err; 869fa34fff5SGao feng struct nf_proto_net *pn = nf_ct_l4proto_net(net, 870fa34fff5SGao feng &nf_conntrack_l4proto_generic); 871fa34fff5SGao feng 872ca2ca6e1SFlorian Westphal err = nf_conntrack_l4proto_generic.init_net(net); 87315f585bdSGao feng if (err < 0) 87415f585bdSGao feng return err; 87515f585bdSGao feng err = nf_ct_l4proto_register_sysctl(net, 876df7043beSYafang Shao pn); 877ac5357ebSPatrick McHardy if (err < 0) 878ac5357ebSPatrick McHardy return err; 879ac5357ebSPatrick McHardy 880a0ae2562SFlorian Westphal err = nf_ct_l4proto_pernet_register(net, builtin_l4proto, 881a0ae2562SFlorian Westphal ARRAY_SIZE(builtin_l4proto)); 882a0ae2562SFlorian Westphal if (err < 0) { 883df7043beSYafang Shao nf_ct_l4proto_unregister_sysctl(pn); 884a0ae2562SFlorian Westphal return err; 885a0ae2562SFlorian Westphal } 886a0ae2562SFlorian Westphal 887fa34fff5SGao feng pn->users++; 888ac5357ebSPatrick McHardy return 0; 889ac5357ebSPatrick McHardy } 890ac5357ebSPatrick McHardy 89104d87001SGao feng void nf_conntrack_proto_pernet_fini(struct net *net) 892ac5357ebSPatrick McHardy { 893fa34fff5SGao feng struct nf_proto_net *pn = nf_ct_l4proto_net(net, 894fa34fff5SGao feng &nf_conntrack_l4proto_generic); 895fa34fff5SGao feng 896a0ae2562SFlorian Westphal nf_ct_l4proto_pernet_unregister(net, builtin_l4proto, 897a0ae2562SFlorian Westphal ARRAY_SIZE(builtin_l4proto)); 898fa34fff5SGao feng pn->users--; 899df7043beSYafang Shao nf_ct_l4proto_unregister_sysctl(pn); 90004d87001SGao feng } 90104d87001SGao feng 90204d87001SGao feng 903a0ae2562SFlorian Westphal module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, 904a0ae2562SFlorian Westphal &nf_conntrack_htable_size, 0600); 905a0ae2562SFlorian Westphal 906a0ae2562SFlorian Westphal MODULE_ALIAS("ip_conntrack"); 907a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET)); 908a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); 909a0ae2562SFlorian Westphal MODULE_LICENSE("GPL"); 910