History

netfilter: defrag: only register defrag functionality if needed

nf_defrag modules for ipv4 and ipv6 export an empty stub function. Any module that needs the defragmentation hooks registered simply 'calls' this empty function to create a phony module dependency -- modprobe will then load the defrag module too. This extends netfilter ipv4/ipv6 defragmentation modules to delay the hook registration until the functionality is requested within a network namespace instead of module load time for all namespaces. Hooks are only un-registered on module unload or when a namespace that used such defrag functionality exits. We have to use struct net for this as the register hooks can be called before netns initialization here from the ipv4/ipv6 conntrack module init path. There is no unregister functionality support, defrag will always be active once it was requested inside a net namespace. The reason is that defrag has impact on nft and iptables rulesets (without defrag we might see framents).

Florian Westphal committed 10 years ago

Commit 834184b1 parent 481fa379 files · +136 −21Browse files

Unified · Split

9 files
  1. include/net/netfilter/ipv4/nf_defrag_ipv4.h +2 −1
  2. include/net/netfilter/ipv6/nf_defrag_ipv6.h +2 −1
  3. include/net/netns/netfilter.h +6 −0
  4. net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +6 −1
  5. net/ipv4/netfilter/nf_defrag_ipv4.c +38 −3
  6. net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +6 −1
  7. net/ipv6/netfilter/nf_defrag_ipv6_hooks.c +38 −4
  8. net/netfilter/xt_TPROXY.c +10 −5
  9. net/netfilter/xt_socket.c +28 −5
include/net/netfilter/ipv4/nf_defrag_ipv4.h+2−1
@@ -1,6 +1,7 @@
1#ifndef _NF_DEFRAG_IPV4_H1#ifndef _NF_DEFRAG_IPV4_H
2#define _NF_DEFRAG_IPV4_H2#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 */
include/net/netfilter/ipv6/nf_defrag_ipv6.h+2−1
@@ -1,7 +1,8 @@
1#ifndef _NF_DEFRAG_IPV6_H1#ifndef _NF_DEFRAG_IPV6_H
2#define _NF_DEFRAG_IPV6_H2#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);
include/net/netns/netfilter.h+6−0
@@ -17,5 +17,11 @@ struct netns_nf { · 16 unmodified lines
17 struct ctl_table_header *nf_log_dir_header;17 struct ctl_table_header *nf_log_dir_header;
18#endif18#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#endif27#endif
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c+6−1
@@ -325,6 +325,12 @@ static int ipv4_hooks_register(struct net *net) · 324 unmodified lines
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) · 91 unmodified lines
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) {
net/ipv4/netfilter/nf_defrag_ipv4.c+38−3
@@ -11,6 +11,7 @@ · 10 unmodified lines
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 @@ · 5 unmodified lines
22#endif23#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[] = { · 74 unmodified lines
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
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c+6−1
@@ -325,6 +325,12 @@ static int ipv6_hooks_register(struct net *net) · 324 unmodified lines
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) · 96 unmodified lines
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) {
net/ipv6/netfilter/nf_defrag_ipv6_hooks.c+38−4
@@ -30,6 +30,8 @@ · 29 unmodified lines
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[] = { · 51 unmodified lines
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) · 3 unmodified lines
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: · 6 unmodified lines
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
net/netfilter/xt_TPROXY.c+10−5
@@ -531,6 +531,11 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par) · 530 unmodified lines
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) · 8 unmodified lines
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 = { · 45 unmodified lines
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
net/netfilter/xt_socket.c+28−5
@@ -147,9 +147,28 @@ socket_mt6_v1_v2_v3(const struct sk_buff *skb, struct xt_action_param *par) · 146 unmodified lines
147}147}
148#endif148#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) · 5 unmodified lines
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) · 6 unmodified lines
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 = { · 88 unmodified lines
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

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t