aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/netfilter/ipv4/nf_defrag_ipv4.h3
-rw-r--r--include/net/netfilter/ipv6/nf_defrag_ipv6.h3
-rw-r--r--include/net/netns/netfilter.h6
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c7
-rw-r--r--net/ipv4/netfilter/nf_defrag_ipv4.c41
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c7
-rw-r--r--net/ipv6/netfilter/nf_defrag_ipv6_hooks.c42
-rw-r--r--net/netfilter/xt_TPROXY.c15
-rw-r--r--net/netfilter/xt_socket.c33
9 files changed, 136 insertions, 21 deletions
diff --git a/include/net/netfilter/ipv4/nf_defrag_ipv4.h b/include/net/netfilter/ipv4/nf_defrag_ipv4.h
index f01ef208dff6..db405f70e538 100644
--- a/include/net/netfilter/ipv4/nf_defrag_ipv4.h
+++ b/include/net/netfilter/ipv4/nf_defrag_ipv4.h
@@ -1,6 +1,7 @@
1#ifndef _NF_DEFRAG_IPV4_H 1#ifndef _NF_DEFRAG_IPV4_H
2#define _NF_DEFRAG_IPV4_H 2#define _NF_DEFRAG_IPV4_H
3 3
4void nf_defrag_ipv4_enable(void); 4struct net;
5int nf_defrag_ipv4_enable(struct net *);
5 6
6#endif /* _NF_DEFRAG_IPV4_H */ 7#endif /* _NF_DEFRAG_IPV4_H */
diff --git a/include/net/netfilter/ipv6/nf_defrag_ipv6.h b/include/net/netfilter/ipv6/nf_defrag_ipv6.h
index ddf162f7966f..7664efe37974 100644
--- a/include/net/netfilter/ipv6/nf_defrag_ipv6.h
+++ b/include/net/netfilter/ipv6/nf_defrag_ipv6.h
@@ -1,7 +1,8 @@
1#ifndef _NF_DEFRAG_IPV6_H 1#ifndef _NF_DEFRAG_IPV6_H
2#define _NF_DEFRAG_IPV6_H 2#define _NF_DEFRAG_IPV6_H
3 3
4void nf_defrag_ipv6_enable(void); 4struct net;
5int nf_defrag_ipv6_enable(struct net *);
5 6
6int nf_ct_frag6_init(void); 7int nf_ct_frag6_init(void);
7void nf_ct_frag6_cleanup(void); 8void nf_ct_frag6_cleanup(void);
diff --git a/include/net/netns/netfilter.h b/include/net/netns/netfilter.h
index 58487b1cc99a..cea396b53a60 100644
--- a/include/net/netns/netfilter.h
+++ b/include/net/netns/netfilter.h
@@ -17,5 +17,11 @@ struct netns_nf {
17 struct ctl_table_header *nf_log_dir_header; 17 struct ctl_table_header *nf_log_dir_header;
18#endif 18#endif
19 struct nf_hook_entry __rcu *hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; 19 struct nf_hook_entry __rcu *hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
20#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
21 bool defrag_ipv4;
22#endif
23#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
24 bool defrag_ipv6;
25#endif
20}; 26};
21#endif 27#endif
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 6f375443a74b..fcfd071f4705 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -325,6 +325,12 @@ static int ipv4_hooks_register(struct net *net)
325 if (cnet->users > 1) 325 if (cnet->users > 1)
326 goto out_unlock; 326 goto out_unlock;
327 327
328 err = nf_defrag_ipv4_enable(net);
329 if (err) {
330 cnet->users = 0;
331 goto out_unlock;
332 }
333
328 err = nf_register_net_hooks(net, ipv4_conntrack_ops, 334 err = nf_register_net_hooks(net, ipv4_conntrack_ops,
329 ARRAY_SIZE(ipv4_conntrack_ops)); 335 ARRAY_SIZE(ipv4_conntrack_ops));
330 336
@@ -422,7 +428,6 @@ static int __init nf_conntrack_l3proto_ipv4_init(void)
422 int ret = 0; 428 int ret = 0;
423 429
424 need_conntrack(); 430 need_conntrack();
425 nf_defrag_ipv4_enable();
426 431
427 ret = nf_register_sockopt(&so_getorigdst); 432 ret = nf_register_sockopt(&so_getorigdst);
428 if (ret < 0) { 433 if (ret < 0) {
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
index d88da36b383c..49bd6a54404f 100644
--- a/net/ipv4/netfilter/nf_defrag_ipv4.c
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
@@ -11,6 +11,7 @@
11#include <linux/netfilter.h> 11#include <linux/netfilter.h>
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/skbuff.h> 13#include <linux/skbuff.h>
14#include <net/netns/generic.h>
14#include <net/route.h> 15#include <net/route.h>
15#include <net/ip.h> 16#include <net/ip.h>
16 17
@@ -22,6 +23,8 @@
22#endif 23#endif
23#include <net/netfilter/nf_conntrack_zones.h> 24#include <net/netfilter/nf_conntrack_zones.h>
24 25
26static DEFINE_MUTEX(defrag4_mutex);
27
25static int nf_ct_ipv4_gather_frags(struct net *net, struct sk_buff *skb, 28static int nf_ct_ipv4_gather_frags(struct net *net, struct sk_buff *skb,
26 u_int32_t user) 29 u_int32_t user)
27{ 30{
@@ -102,18 +105,50 @@ static struct nf_hook_ops ipv4_defrag_ops[] = {
102 }, 105 },
103}; 106};
104 107
108static void __net_exit defrag4_net_exit(struct net *net)
109{
110 if (net->nf.defrag_ipv4) {
111 nf_unregister_net_hooks(net, ipv4_defrag_ops,
112 ARRAY_SIZE(ipv4_defrag_ops));
113 net->nf.defrag_ipv4 = false;
114 }
115}
116
117static struct pernet_operations defrag4_net_ops = {
118 .exit = defrag4_net_exit,
119};
120
105static int __init nf_defrag_init(void) 121static int __init nf_defrag_init(void)
106{ 122{
107 return nf_register_hooks(ipv4_defrag_ops, ARRAY_SIZE(ipv4_defrag_ops)); 123 return register_pernet_subsys(&defrag4_net_ops);
108} 124}
109 125
110static void __exit nf_defrag_fini(void) 126static void __exit nf_defrag_fini(void)
111{ 127{
112 nf_unregister_hooks(ipv4_defrag_ops, ARRAY_SIZE(ipv4_defrag_ops)); 128 unregister_pernet_subsys(&defrag4_net_ops);
113} 129}
114 130
115void nf_defrag_ipv4_enable(void) 131int nf_defrag_ipv4_enable(struct net *net)
116{ 132{
133 int err = 0;
134
135 might_sleep();
136
137 if (net->nf.defrag_ipv4)
138 return 0;
139
140 mutex_lock(&defrag4_mutex);
141 if (net->nf.defrag_ipv4)
142 goto out_unlock;
143
144 err = nf_register_net_hooks(net, ipv4_defrag_ops,
145 ARRAY_SIZE(ipv4_defrag_ops));
146 if (err == 0)
147 net->nf.defrag_ipv4 = true;
148
149 out_unlock:
150 mutex_unlock(&defrag4_mutex);
151 return err;
117} 152}
118EXPORT_SYMBOL_GPL(nf_defrag_ipv4_enable); 153EXPORT_SYMBOL_GPL(nf_defrag_ipv4_enable);
119 154
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 72fe48075b7f..4e3402486833 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -325,6 +325,12 @@ static int ipv6_hooks_register(struct net *net)
325 if (cnet->users > 1) 325 if (cnet->users > 1)
326 goto out_unlock; 326 goto out_unlock;
327 327
328 err = nf_defrag_ipv6_enable(net);
329 if (err < 0) {
330 cnet->users = 0;
331 goto out_unlock;
332 }
333
328 err = nf_register_net_hooks(net, ipv6_conntrack_ops, 334 err = nf_register_net_hooks(net, ipv6_conntrack_ops,
329 ARRAY_SIZE(ipv6_conntrack_ops)); 335 ARRAY_SIZE(ipv6_conntrack_ops));
330 if (err) 336 if (err)
@@ -427,7 +433,6 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
427 int ret = 0; 433 int ret = 0;
428 434
429 need_conntrack(); 435 need_conntrack();
430 nf_defrag_ipv6_enable();
431 436
432 ret = nf_register_sockopt(&so_getorigdst6); 437 ret = nf_register_sockopt(&so_getorigdst6);
433 if (ret < 0) { 438 if (ret < 0) {
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
index f06b0471f39f..8e0bdd058787 100644
--- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
+++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
@@ -30,6 +30,8 @@
30#include <net/netfilter/nf_conntrack_zones.h> 30#include <net/netfilter/nf_conntrack_zones.h>
31#include <net/netfilter/ipv6/nf_defrag_ipv6.h> 31#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
32 32
33static DEFINE_MUTEX(defrag6_mutex);
34
33static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, 35static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
34 struct sk_buff *skb) 36 struct sk_buff *skb)
35{ 37{
@@ -87,6 +89,19 @@ static struct nf_hook_ops ipv6_defrag_ops[] = {
87 }, 89 },
88}; 90};
89 91
92static void __net_exit defrag6_net_exit(struct net *net)
93{
94 if (net->nf.defrag_ipv6) {
95 nf_unregister_net_hooks(net, ipv6_defrag_ops,
96 ARRAY_SIZE(ipv6_defrag_ops));
97 net->nf.defrag_ipv6 = false;
98 }
99}
100
101static struct pernet_operations defrag6_net_ops = {
102 .exit = defrag6_net_exit,
103};
104
90static int __init nf_defrag_init(void) 105static int __init nf_defrag_init(void)
91{ 106{
92 int ret = 0; 107 int ret = 0;
@@ -96,9 +111,9 @@ static int __init nf_defrag_init(void)
96 pr_err("nf_defrag_ipv6: can't initialize frag6.\n"); 111 pr_err("nf_defrag_ipv6: can't initialize frag6.\n");
97 return ret; 112 return ret;
98 } 113 }
99 ret = nf_register_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops)); 114 ret = register_pernet_subsys(&defrag6_net_ops);
100 if (ret < 0) { 115 if (ret < 0) {
101 pr_err("nf_defrag_ipv6: can't register hooks\n"); 116 pr_err("nf_defrag_ipv6: can't register pernet ops\n");
102 goto cleanup_frag6; 117 goto cleanup_frag6;
103 } 118 }
104 return ret; 119 return ret;
@@ -111,12 +126,31 @@ cleanup_frag6:
111 126
112static void __exit nf_defrag_fini(void) 127static void __exit nf_defrag_fini(void)
113{ 128{
114 nf_unregister_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops)); 129 unregister_pernet_subsys(&defrag6_net_ops);
115 nf_ct_frag6_cleanup(); 130 nf_ct_frag6_cleanup();
116} 131}
117 132
118void nf_defrag_ipv6_enable(void) 133int nf_defrag_ipv6_enable(struct net *net)
119{ 134{
135 int err = 0;
136
137 might_sleep();
138
139 if (net->nf.defrag_ipv6)
140 return 0;
141
142 mutex_lock(&defrag6_mutex);
143 if (net->nf.defrag_ipv6)
144 goto out_unlock;
145
146 err = nf_register_net_hooks(net, ipv6_defrag_ops,
147 ARRAY_SIZE(ipv6_defrag_ops));
148 if (err == 0)
149 net->nf.defrag_ipv6 = true;
150
151 out_unlock:
152 mutex_unlock(&defrag6_mutex);
153 return err;
120} 154}
121EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable); 155EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable);
122 156
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
index dbd72cc40e42..80cb7babeb64 100644
--- a/net/netfilter/xt_TPROXY.c
+++ b/net/netfilter/xt_TPROXY.c
@@ -531,6 +531,11 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
531static int tproxy_tg6_check(const struct xt_tgchk_param *par) 531static int tproxy_tg6_check(const struct xt_tgchk_param *par)
532{ 532{
533 const struct ip6t_ip6 *i = par->entryinfo; 533 const struct ip6t_ip6 *i = par->entryinfo;
534 int err;
535
536 err = nf_defrag_ipv6_enable(par->net);
537 if (err)
538 return err;
534 539
535 if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP) && 540 if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP) &&
536 !(i->invflags & IP6T_INV_PROTO)) 541 !(i->invflags & IP6T_INV_PROTO))
@@ -545,6 +550,11 @@ static int tproxy_tg6_check(const struct xt_tgchk_param *par)
545static int tproxy_tg4_check(const struct xt_tgchk_param *par) 550static int tproxy_tg4_check(const struct xt_tgchk_param *par)
546{ 551{
547 const struct ipt_ip *i = par->entryinfo; 552 const struct ipt_ip *i = par->entryinfo;
553 int err;
554
555 err = nf_defrag_ipv4_enable(par->net);
556 if (err)
557 return err;
548 558
549 if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP) 559 if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
550 && !(i->invflags & IPT_INV_PROTO)) 560 && !(i->invflags & IPT_INV_PROTO))
@@ -596,11 +606,6 @@ static struct xt_target tproxy_tg_reg[] __read_mostly = {
596 606
597static int __init tproxy_tg_init(void) 607static int __init tproxy_tg_init(void)
598{ 608{
599 nf_defrag_ipv4_enable();
600#ifdef XT_TPROXY_HAVE_IPV6
601 nf_defrag_ipv6_enable();
602#endif
603
604 return xt_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg)); 609 return xt_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg));
605} 610}
606 611
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index 2198914707f5..770bbec878f1 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -147,9 +147,28 @@ socket_mt6_v1_v2_v3(const struct sk_buff *skb, struct xt_action_param *par)
147} 147}
148#endif 148#endif
149 149
150static int socket_mt_enable_defrag(struct net *net, int family)
151{
152 switch (family) {
153 case NFPROTO_IPV4:
154 return nf_defrag_ipv4_enable(net);
155#ifdef XT_SOCKET_HAVE_IPV6
156 case NFPROTO_IPV6:
157 return nf_defrag_ipv6_enable(net);
158#endif
159 }
160 WARN_ONCE(1, "Unknown family %d\n", family);
161 return 0;
162}
163
150static int socket_mt_v1_check(const struct xt_mtchk_param *par) 164static int socket_mt_v1_check(const struct xt_mtchk_param *par)
151{ 165{
152 const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo; 166 const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
167 int err;
168
169 err = socket_mt_enable_defrag(par->net, par->family);
170 if (err)
171 return err;
153 172
154 if (info->flags & ~XT_SOCKET_FLAGS_V1) { 173 if (info->flags & ~XT_SOCKET_FLAGS_V1) {
155 pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V1); 174 pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V1);
@@ -161,6 +180,11 @@ static int socket_mt_v1_check(const struct xt_mtchk_param *par)
161static int socket_mt_v2_check(const struct xt_mtchk_param *par) 180static int socket_mt_v2_check(const struct xt_mtchk_param *par)
162{ 181{
163 const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo; 182 const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo;
183 int err;
184
185 err = socket_mt_enable_defrag(par->net, par->family);
186 if (err)
187 return err;
164 188
165 if (info->flags & ~XT_SOCKET_FLAGS_V2) { 189 if (info->flags & ~XT_SOCKET_FLAGS_V2) {
166 pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V2); 190 pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V2);
@@ -173,7 +197,11 @@ static int socket_mt_v3_check(const struct xt_mtchk_param *par)
173{ 197{
174 const struct xt_socket_mtinfo3 *info = 198 const struct xt_socket_mtinfo3 *info =
175 (struct xt_socket_mtinfo3 *)par->matchinfo; 199 (struct xt_socket_mtinfo3 *)par->matchinfo;
200 int err;
176 201
202 err = socket_mt_enable_defrag(par->net, par->family);
203 if (err)
204 return err;
177 if (info->flags & ~XT_SOCKET_FLAGS_V3) { 205 if (info->flags & ~XT_SOCKET_FLAGS_V3) {
178 pr_info("unknown flags 0x%x\n", 206 pr_info("unknown flags 0x%x\n",
179 info->flags & ~XT_SOCKET_FLAGS_V3); 207 info->flags & ~XT_SOCKET_FLAGS_V3);
@@ -268,11 +296,6 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
268 296
269static int __init socket_mt_init(void) 297static int __init socket_mt_init(void)
270{ 298{
271 nf_defrag_ipv4_enable();
272#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
273 nf_defrag_ipv6_enable();
274#endif
275
276 return xt_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg)); 299 return xt_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg));
277} 300}
278 301