Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[NETFILTER]: ip_tables: per-netns FILTER/MANGLE/RAW tables for real

Commit 9335f047fe61587ec82ff12fbb1220bcfdd32006 aka
"[NETFILTER]: ip_tables: per-netns FILTER, MANGLE, RAW"
added per-netns _view_ of iptables rules. They were shown to user, but
ignored by filtering code. Now that it's possible to at least ping loopback,
per-netns tables can affect filtering decisions.

netns is taken in case of
PRE_ROUTING, LOCAL_IN -- from in device,
POST_ROUTING, LOCAL_OUT -- from out device,
FORWARD -- from in device which should be equal to out device's netns.
This code is relatively new, so BUG_ON was plugged.

Wrappers were added to a) keep code the same from CONFIG_NET_NS=n users
(overwhelming majority), b) consolidate code in one place -- similar
changes will be done in ipv6 and arp netfilter code.

Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru>
Signed-off-by: Patrick McHardy <kaber@trash.net>

authored by

Alexey Dobriyan and committed by
Patrick McHardy
666953df 36e2a1b0

+115 -13
+53 -1
include/linux/netfilter.h
··· 6 6 #include <linux/types.h> 7 7 #include <linux/skbuff.h> 8 8 #include <linux/net.h> 9 + #include <linux/netdevice.h> 9 10 #include <linux/if.h> 10 11 #include <linux/in.h> 11 12 #include <linux/in6.h> 12 13 #include <linux/wait.h> 13 14 #include <linux/list.h> 15 + #include <net/net_namespace.h> 14 16 #endif 15 17 #include <linux/compiler.h> 16 18 ··· 78 76 #define NF_MAX_HOOKS 8 79 77 80 78 struct sk_buff; 81 - struct net_device; 82 79 83 80 typedef unsigned int nf_hookfn(unsigned int hooknum, 84 81 struct sk_buff *skb, ··· 320 319 #else 321 320 static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} 322 321 #endif 322 + 323 + static inline struct net *nf_pre_routing_net(const struct net_device *in, 324 + const struct net_device *out) 325 + { 326 + #ifdef CONFIG_NET_NS 327 + return in->nd_net; 328 + #else 329 + return &init_net; 330 + #endif 331 + } 332 + 333 + static inline struct net *nf_local_in_net(const struct net_device *in, 334 + const struct net_device *out) 335 + { 336 + #ifdef CONFIG_NET_NS 337 + return in->nd_net; 338 + #else 339 + return &init_net; 340 + #endif 341 + } 342 + 343 + static inline struct net *nf_forward_net(const struct net_device *in, 344 + const struct net_device *out) 345 + { 346 + #ifdef CONFIG_NET_NS 347 + BUG_ON(in->nd_net != out->nd_net); 348 + return in->nd_net; 349 + #else 350 + return &init_net; 351 + #endif 352 + } 353 + 354 + static inline struct net *nf_local_out_net(const struct net_device *in, 355 + const struct net_device *out) 356 + { 357 + #ifdef CONFIG_NET_NS 358 + return out->nd_net; 359 + #else 360 + return &init_net; 361 + #endif 362 + } 363 + 364 + static inline struct net *nf_post_routing_net(const struct net_device *in, 365 + const struct net_device *out) 366 + { 367 + #ifdef CONFIG_NET_NS 368 + return out->nd_net; 369 + #else 370 + return &init_net; 371 + #endif 372 + } 323 373 324 374 #endif /*__KERNEL__*/ 325 375 #endif /*__LINUX_NETFILTER_H*/
+16 -3
net/ipv4/netfilter/iptable_filter.c
··· 63 63 64 64 /* The work comes in here from netfilter.c. */ 65 65 static unsigned int 66 + ipt_local_in_hook(unsigned int hook, 67 + struct sk_buff *skb, 68 + const struct net_device *in, 69 + const struct net_device *out, 70 + int (*okfn)(struct sk_buff *)) 71 + { 72 + return ipt_do_table(skb, hook, in, out, 73 + nf_local_in_net(in, out)->ipv4.iptable_filter); 74 + } 75 + 76 + static unsigned int 66 77 ipt_hook(unsigned int hook, 67 78 struct sk_buff *skb, 68 79 const struct net_device *in, 69 80 const struct net_device *out, 70 81 int (*okfn)(struct sk_buff *)) 71 82 { 72 - return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_filter); 83 + return ipt_do_table(skb, hook, in, out, 84 + nf_forward_net(in, out)->ipv4.iptable_filter); 73 85 } 74 86 75 87 static unsigned int ··· 100 88 return NF_ACCEPT; 101 89 } 102 90 103 - return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_filter); 91 + return ipt_do_table(skb, hook, in, out, 92 + nf_local_out_net(in, out)->ipv4.iptable_filter); 104 93 } 105 94 106 95 static struct nf_hook_ops ipt_ops[] __read_mostly = { 107 96 { 108 - .hook = ipt_hook, 97 + .hook = ipt_local_in_hook, 109 98 .owner = THIS_MODULE, 110 99 .pf = PF_INET, 111 100 .hooknum = NF_INET_LOCAL_IN,
+42 -7
net/ipv4/netfilter/iptable_mangle.c
··· 74 74 75 75 /* The work comes in here from netfilter.c. */ 76 76 static unsigned int 77 - ipt_route_hook(unsigned int hook, 77 + ipt_pre_routing_hook(unsigned int hook, 78 + struct sk_buff *skb, 79 + const struct net_device *in, 80 + const struct net_device *out, 81 + int (*okfn)(struct sk_buff *)) 82 + { 83 + return ipt_do_table(skb, hook, in, out, 84 + nf_pre_routing_net(in, out)->ipv4.iptable_mangle); 85 + } 86 + 87 + static unsigned int 88 + ipt_post_routing_hook(unsigned int hook, 89 + struct sk_buff *skb, 90 + const struct net_device *in, 91 + const struct net_device *out, 92 + int (*okfn)(struct sk_buff *)) 93 + { 94 + return ipt_do_table(skb, hook, in, out, 95 + nf_post_routing_net(in, out)->ipv4.iptable_mangle); 96 + } 97 + 98 + static unsigned int 99 + ipt_local_in_hook(unsigned int hook, 100 + struct sk_buff *skb, 101 + const struct net_device *in, 102 + const struct net_device *out, 103 + int (*okfn)(struct sk_buff *)) 104 + { 105 + return ipt_do_table(skb, hook, in, out, 106 + nf_local_in_net(in, out)->ipv4.iptable_mangle); 107 + } 108 + 109 + static unsigned int 110 + ipt_forward_hook(unsigned int hook, 78 111 struct sk_buff *skb, 79 112 const struct net_device *in, 80 113 const struct net_device *out, 81 114 int (*okfn)(struct sk_buff *)) 82 115 { 83 - return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_mangle); 116 + return ipt_do_table(skb, hook, in, out, 117 + nf_forward_net(in, out)->ipv4.iptable_mangle); 84 118 } 85 119 86 120 static unsigned int ··· 146 112 daddr = iph->daddr; 147 113 tos = iph->tos; 148 114 149 - ret = ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_mangle); 115 + ret = ipt_do_table(skb, hook, in, out, 116 + nf_local_out_net(in, out)->ipv4.iptable_mangle); 150 117 /* Reroute for ANY change. */ 151 118 if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE) { 152 119 iph = ip_hdr(skb); ··· 165 130 166 131 static struct nf_hook_ops ipt_ops[] __read_mostly = { 167 132 { 168 - .hook = ipt_route_hook, 133 + .hook = ipt_pre_routing_hook, 169 134 .owner = THIS_MODULE, 170 135 .pf = PF_INET, 171 136 .hooknum = NF_INET_PRE_ROUTING, 172 137 .priority = NF_IP_PRI_MANGLE, 173 138 }, 174 139 { 175 - .hook = ipt_route_hook, 140 + .hook = ipt_local_in_hook, 176 141 .owner = THIS_MODULE, 177 142 .pf = PF_INET, 178 143 .hooknum = NF_INET_LOCAL_IN, 179 144 .priority = NF_IP_PRI_MANGLE, 180 145 }, 181 146 { 182 - .hook = ipt_route_hook, 147 + .hook = ipt_forward_hook, 183 148 .owner = THIS_MODULE, 184 149 .pf = PF_INET, 185 150 .hooknum = NF_INET_FORWARD, ··· 193 158 .priority = NF_IP_PRI_MANGLE, 194 159 }, 195 160 { 196 - .hook = ipt_route_hook, 161 + .hook = ipt_post_routing_hook, 197 162 .owner = THIS_MODULE, 198 163 .pf = PF_INET, 199 164 .hooknum = NF_INET_POST_ROUTING,
+4 -2
net/ipv4/netfilter/iptable_raw.c
··· 52 52 const struct net_device *out, 53 53 int (*okfn)(struct sk_buff *)) 54 54 { 55 - return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_raw); 55 + return ipt_do_table(skb, hook, in, out, 56 + nf_pre_routing_net(in, out)->ipv4.iptable_raw); 56 57 } 57 58 58 59 static unsigned int ··· 71 70 "packet.\n"); 72 71 return NF_ACCEPT; 73 72 } 74 - return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_raw); 73 + return ipt_do_table(skb, hook, in, out, 74 + nf_local_out_net(in, out)->ipv4.iptable_raw); 75 75 } 76 76 77 77 /* 'raw' is the very first table. */