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 @@
11 #ifndef _NF_DEFRAG_IPV4_H
22 #define _NF_DEFRAG_IPV4_H
33
4−void nf_defrag_ipv4_enable(void);
4+struct net;
5+int nf_defrag_ipv4_enable(struct net *);
56
67 #endif /* _NF_DEFRAG_IPV4_H */
include/net/netfilter/ipv6/nf_defrag_ipv6.h+2−1
@@ -1,7 +1,8 @@
11 #ifndef _NF_DEFRAG_IPV6_H
22 #define _NF_DEFRAG_IPV6_H
33
4−void nf_defrag_ipv6_enable(void);
4+struct net;
5+int nf_defrag_ipv6_enable(struct net *);
56
67 int nf_ct_frag6_init(void);
78 void nf_ct_frag6_cleanup(void);
include/net/netns/netfilter.h+6−0
@@ -17,5 +17,11 @@ struct netns_nf { · 16 unmodified lines
1717 struct ctl_table_header *nf_log_dir_header;
1818 #endif
1919 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
2026 };
2127 #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
325325 if (cnet->users > 1)
326326 goto out_unlock;
327327
328+ err = nf_defrag_ipv4_enable(net);
329+ if (err) {
330+ cnet->users = 0;
331+ goto out_unlock;
332+ }
333+
328334 err = nf_register_net_hooks(net, ipv4_conntrack_ops,
329335 ARRAY_SIZE(ipv4_conntrack_ops));
330336
@@ -422,7 +428,6 @@ static int __init nf_conntrack_l3proto_ipv4_init(void) · 91 unmodified lines
422428 int ret = 0;
423429
424430 need_conntrack();
425− nf_defrag_ipv4_enable();
426431
427432 ret = nf_register_sockopt(&so_getorigdst);
428433 if (ret < 0) {
net/ipv4/netfilter/nf_defrag_ipv4.c+38−3
@@ -11,6 +11,7 @@ · 10 unmodified lines
1111 #include <linux/netfilter.h>
1212 #include <linux/module.h>
1313 #include <linux/skbuff.h>
14+#include <net/netns/generic.h>
1415 #include <net/route.h>
1516 #include <net/ip.h>
1617
@@ -22,6 +23,8 @@ · 5 unmodified lines
2223 #endif
2324 #include <net/netfilter/nf_conntrack_zones.h>
2425
26+static DEFINE_MUTEX(defrag4_mutex);
27+
2528 static int nf_ct_ipv4_gather_frags(struct net *net, struct sk_buff *skb,
2629 u_int32_t user)
2730 {
@@ -102,18 +105,50 @@ static struct nf_hook_ops ipv4_defrag_ops[] = { · 74 unmodified lines
102105 },
103106 };
104107
108+static 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+
117+static struct pernet_operations defrag4_net_ops = {
118+ .exit = defrag4_net_exit,
119+};
120+
105121 static int __init nf_defrag_init(void)
106122 {
107− return nf_register_hooks(ipv4_defrag_ops, ARRAY_SIZE(ipv4_defrag_ops));
123+ return register_pernet_subsys(&defrag4_net_ops);
108124 }
109125
110126 static void __exit nf_defrag_fini(void)
111127 {
112− nf_unregister_hooks(ipv4_defrag_ops, ARRAY_SIZE(ipv4_defrag_ops));
128+ unregister_pernet_subsys(&defrag4_net_ops);
113129 }
114130
115−void nf_defrag_ipv4_enable(void)
131+int nf_defrag_ipv4_enable(struct net *net)
116132 {
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;
117152 }
118153 EXPORT_SYMBOL_GPL(nf_defrag_ipv4_enable);
119154
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
325325 if (cnet->users > 1)
326326 goto out_unlock;
327327
328+ err = nf_defrag_ipv6_enable(net);
329+ if (err < 0) {
330+ cnet->users = 0;
331+ goto out_unlock;
332+ }
333+
328334 err = nf_register_net_hooks(net, ipv6_conntrack_ops,
329335 ARRAY_SIZE(ipv6_conntrack_ops));
330336 if (err)
@@ -427,7 +433,6 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) · 96 unmodified lines
427433 int ret = 0;
428434
429435 need_conntrack();
430− nf_defrag_ipv6_enable();
431436
432437 ret = nf_register_sockopt(&so_getorigdst6);
433438 if (ret < 0) {
net/ipv6/netfilter/nf_defrag_ipv6_hooks.c+38−4
@@ -30,6 +30,8 @@ · 29 unmodified lines
3030 #include <net/netfilter/nf_conntrack_zones.h>
3131 #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
3232
33+static DEFINE_MUTEX(defrag6_mutex);
34+
3335 static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
3436 struct sk_buff *skb)
3537 {
@@ -87,6 +89,19 @@ static struct nf_hook_ops ipv6_defrag_ops[] = { · 51 unmodified lines
8789 },
8890 };
8991
92+static 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+
101+static struct pernet_operations defrag6_net_ops = {
102+ .exit = defrag6_net_exit,
103+};
104+
90105 static int __init nf_defrag_init(void)
91106 {
92107 int ret = 0;
@@ -96,9 +111,9 @@ static int __init nf_defrag_init(void) · 3 unmodified lines
96111 pr_err("nf_defrag_ipv6: can't initialize frag6.\n");
97112 return ret;
98113 }
99− ret = nf_register_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops));
114+ ret = register_pernet_subsys(&defrag6_net_ops);
100115 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");
102117 goto cleanup_frag6;
103118 }
104119 return ret;
@@ -111,12 +126,31 @@ cleanup_frag6: · 6 unmodified lines
111126
112127 static void __exit nf_defrag_fini(void)
113128 {
114− nf_unregister_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops));
129+ unregister_pernet_subsys(&defrag6_net_ops);
115130 nf_ct_frag6_cleanup();
116131 }
117132
118−void nf_defrag_ipv6_enable(void)
133+int nf_defrag_ipv6_enable(struct net *net)
119134 {
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;
120154 }
121155 EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable);
122156
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
531531 static int tproxy_tg6_check(const struct xt_tgchk_param *par)
532532 {
533533 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;
534539
535540 if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP) &&
536541 !(i->invflags & IP6T_INV_PROTO))
@@ -545,6 +550,11 @@ static int tproxy_tg6_check(const struct xt_tgchk_param *par) · 8 unmodified lines
545550 static int tproxy_tg4_check(const struct xt_tgchk_param *par)
546551 {
547552 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;
548558
549559 if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
550560 && !(i->invflags & IPT_INV_PROTO))
@@ -596,11 +606,6 @@ static struct xt_target tproxy_tg_reg[] __read_mostly = { · 45 unmodified lines
596606
597607 static int __init tproxy_tg_init(void)
598608 {
599− nf_defrag_ipv4_enable();
600−#ifdef XT_TPROXY_HAVE_IPV6
601− nf_defrag_ipv6_enable();
602−#endif
603−
604609 return xt_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg));
605610 }
606611
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
147147 }
148148 #endif
149149
150+static 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+
150164 static int socket_mt_v1_check(const struct xt_mtchk_param *par)
151165 {
152166 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;
153172
154173 if (info->flags & ~XT_SOCKET_FLAGS_V1) {
155174 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
161180 static int socket_mt_v2_check(const struct xt_mtchk_param *par)
162181 {
163182 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;
164188
165189 if (info->flags & ~XT_SOCKET_FLAGS_V2) {
166190 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
173197 {
174198 const struct xt_socket_mtinfo3 *info =
175199 (struct xt_socket_mtinfo3 *)par->matchinfo;
200+ int err;
176201
202+ err = socket_mt_enable_defrag(par->net, par->family);
203+ if (err)
204+ return err;
177205 if (info->flags & ~XT_SOCKET_FLAGS_V3) {
178206 pr_info("unknown flags 0x%x\n",
179207 info->flags & ~XT_SOCKET_FLAGS_V3);
@@ -268,11 +296,6 @@ static struct xt_match socket_mt_reg[] __read_mostly = { · 88 unmodified lines
268296
269297 static int __init socket_mt_init(void)
270298 {
271− nf_defrag_ipv4_enable();
272−#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
273− nf_defrag_ipv6_enable();
274−#endif
275−
276299 return xt_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg));
277300 }
278301

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