1 #include <linux/init.h>
2 #include <linux/kernel.h>
3 #include <linux/netdevice.h>
4 #include <net/net_namespace.h>
5 #include <net/netns/generic.h>
6 #include <net/netfilter/nf_tables.h>
7 #include <linux/netfilter_ipv4.h>
8 #include <linux/netfilter_ipv6.h>
9 #include <linux/netfilter_bridge.h>
10 #include <linux/netfilter_arp.h>
11 #include <net/netfilter/nf_tables_ipv4.h>
12 #include <net/netfilter/nf_tables_ipv6.h>
13
14 extern unsigned int nf_tables_net_id;
15
16 #ifdef CONFIG_NF_TABLES_IPV4
nft_do_chain_ipv4(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)17 static unsigned int nft_do_chain_ipv4(void *priv,
18 struct sk_buff *skb,
19 const struct nf_hook_state *state)
20 {
21 struct nft_pktinfo pkt;
22
23 nft_set_pktinfo(&pkt, skb, state);
24 nft_set_pktinfo_ipv4(&pkt, skb);
25
26 return nft_do_chain(&pkt, priv);
27 }
28
29 static const struct nft_chain_type nft_chain_filter_ipv4 = {
30 .name = "filter",
31 .type = NFT_CHAIN_T_DEFAULT,
32 .family = NFPROTO_IPV4,
33 .hook_mask = (1 << NF_INET_LOCAL_IN) |
34 (1 << NF_INET_LOCAL_OUT) |
35 (1 << NF_INET_FORWARD) |
36 (1 << NF_INET_PRE_ROUTING) |
37 (1 << NF_INET_POST_ROUTING),
38 .hooks = {
39 [NF_INET_LOCAL_IN] = nft_do_chain_ipv4,
40 [NF_INET_LOCAL_OUT] = nft_do_chain_ipv4,
41 [NF_INET_FORWARD] = nft_do_chain_ipv4,
42 [NF_INET_PRE_ROUTING] = nft_do_chain_ipv4,
43 [NF_INET_POST_ROUTING] = nft_do_chain_ipv4,
44 },
45 };
46
nft_chain_filter_ipv4_init(void)47 static void nft_chain_filter_ipv4_init(void)
48 {
49 nft_register_chain_type(&nft_chain_filter_ipv4);
50 }
nft_chain_filter_ipv4_fini(void)51 static void nft_chain_filter_ipv4_fini(void)
52 {
53 nft_unregister_chain_type(&nft_chain_filter_ipv4);
54 }
55
56 #else
nft_chain_filter_ipv4_init(void)57 static inline void nft_chain_filter_ipv4_init(void) {}
nft_chain_filter_ipv4_fini(void)58 static inline void nft_chain_filter_ipv4_fini(void) {}
59 #endif /* CONFIG_NF_TABLES_IPV4 */
60
61 #ifdef CONFIG_NF_TABLES_ARP
nft_do_chain_arp(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)62 static unsigned int nft_do_chain_arp(void *priv, struct sk_buff *skb,
63 const struct nf_hook_state *state)
64 {
65 struct nft_pktinfo pkt;
66
67 nft_set_pktinfo(&pkt, skb, state);
68 nft_set_pktinfo_unspec(&pkt, skb);
69
70 return nft_do_chain(&pkt, priv);
71 }
72
73 static const struct nft_chain_type nft_chain_filter_arp = {
74 .name = "filter",
75 .type = NFT_CHAIN_T_DEFAULT,
76 .family = NFPROTO_ARP,
77 .owner = THIS_MODULE,
78 .hook_mask = (1 << NF_ARP_IN) |
79 (1 << NF_ARP_OUT),
80 .hooks = {
81 [NF_ARP_IN] = nft_do_chain_arp,
82 [NF_ARP_OUT] = nft_do_chain_arp,
83 },
84 };
85
nft_chain_filter_arp_init(void)86 static void nft_chain_filter_arp_init(void)
87 {
88 nft_register_chain_type(&nft_chain_filter_arp);
89 }
90
nft_chain_filter_arp_fini(void)91 static void nft_chain_filter_arp_fini(void)
92 {
93 nft_unregister_chain_type(&nft_chain_filter_arp);
94 }
95 #else
nft_chain_filter_arp_init(void)96 static inline void nft_chain_filter_arp_init(void) {}
nft_chain_filter_arp_fini(void)97 static inline void nft_chain_filter_arp_fini(void) {}
98 #endif /* CONFIG_NF_TABLES_ARP */
99
100 #ifdef CONFIG_NF_TABLES_IPV6
nft_do_chain_ipv6(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)101 static unsigned int nft_do_chain_ipv6(void *priv,
102 struct sk_buff *skb,
103 const struct nf_hook_state *state)
104 {
105 struct nft_pktinfo pkt;
106
107 nft_set_pktinfo(&pkt, skb, state);
108 nft_set_pktinfo_ipv6(&pkt, skb);
109
110 return nft_do_chain(&pkt, priv);
111 }
112
113 static const struct nft_chain_type nft_chain_filter_ipv6 = {
114 .name = "filter",
115 .type = NFT_CHAIN_T_DEFAULT,
116 .family = NFPROTO_IPV6,
117 .hook_mask = (1 << NF_INET_LOCAL_IN) |
118 (1 << NF_INET_LOCAL_OUT) |
119 (1 << NF_INET_FORWARD) |
120 (1 << NF_INET_PRE_ROUTING) |
121 (1 << NF_INET_POST_ROUTING),
122 .hooks = {
123 [NF_INET_LOCAL_IN] = nft_do_chain_ipv6,
124 [NF_INET_LOCAL_OUT] = nft_do_chain_ipv6,
125 [NF_INET_FORWARD] = nft_do_chain_ipv6,
126 [NF_INET_PRE_ROUTING] = nft_do_chain_ipv6,
127 [NF_INET_POST_ROUTING] = nft_do_chain_ipv6,
128 },
129 };
130
nft_chain_filter_ipv6_init(void)131 static void nft_chain_filter_ipv6_init(void)
132 {
133 nft_register_chain_type(&nft_chain_filter_ipv6);
134 }
135
nft_chain_filter_ipv6_fini(void)136 static void nft_chain_filter_ipv6_fini(void)
137 {
138 nft_unregister_chain_type(&nft_chain_filter_ipv6);
139 }
140 #else
nft_chain_filter_ipv6_init(void)141 static inline void nft_chain_filter_ipv6_init(void) {}
nft_chain_filter_ipv6_fini(void)142 static inline void nft_chain_filter_ipv6_fini(void) {}
143 #endif /* CONFIG_NF_TABLES_IPV6 */
144
145 #ifdef CONFIG_NF_TABLES_INET
nft_do_chain_inet(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)146 static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb,
147 const struct nf_hook_state *state)
148 {
149 struct nft_pktinfo pkt;
150
151 nft_set_pktinfo(&pkt, skb, state);
152
153 switch (state->pf) {
154 case NFPROTO_IPV4:
155 nft_set_pktinfo_ipv4(&pkt, skb);
156 break;
157 case NFPROTO_IPV6:
158 nft_set_pktinfo_ipv6(&pkt, skb);
159 break;
160 default:
161 break;
162 }
163
164 return nft_do_chain(&pkt, priv);
165 }
166
167 static const struct nft_chain_type nft_chain_filter_inet = {
168 .name = "filter",
169 .type = NFT_CHAIN_T_DEFAULT,
170 .family = NFPROTO_INET,
171 .hook_mask = (1 << NF_INET_LOCAL_IN) |
172 (1 << NF_INET_LOCAL_OUT) |
173 (1 << NF_INET_FORWARD) |
174 (1 << NF_INET_PRE_ROUTING) |
175 (1 << NF_INET_POST_ROUTING),
176 .hooks = {
177 [NF_INET_LOCAL_IN] = nft_do_chain_inet,
178 [NF_INET_LOCAL_OUT] = nft_do_chain_inet,
179 [NF_INET_FORWARD] = nft_do_chain_inet,
180 [NF_INET_PRE_ROUTING] = nft_do_chain_inet,
181 [NF_INET_POST_ROUTING] = nft_do_chain_inet,
182 },
183 };
184
nft_chain_filter_inet_init(void)185 static void nft_chain_filter_inet_init(void)
186 {
187 nft_register_chain_type(&nft_chain_filter_inet);
188 }
189
nft_chain_filter_inet_fini(void)190 static void nft_chain_filter_inet_fini(void)
191 {
192 nft_unregister_chain_type(&nft_chain_filter_inet);
193 }
194 #else
nft_chain_filter_inet_init(void)195 static inline void nft_chain_filter_inet_init(void) {}
nft_chain_filter_inet_fini(void)196 static inline void nft_chain_filter_inet_fini(void) {}
197 #endif /* CONFIG_NF_TABLES_IPV6 */
198
199 #if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE)
200 static unsigned int
nft_do_chain_bridge(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)201 nft_do_chain_bridge(void *priv,
202 struct sk_buff *skb,
203 const struct nf_hook_state *state)
204 {
205 struct nft_pktinfo pkt;
206
207 nft_set_pktinfo(&pkt, skb, state);
208
209 switch (eth_hdr(skb)->h_proto) {
210 case htons(ETH_P_IP):
211 nft_set_pktinfo_ipv4_validate(&pkt, skb);
212 break;
213 case htons(ETH_P_IPV6):
214 nft_set_pktinfo_ipv6_validate(&pkt, skb);
215 break;
216 default:
217 nft_set_pktinfo_unspec(&pkt, skb);
218 break;
219 }
220
221 return nft_do_chain(&pkt, priv);
222 }
223
224 static const struct nft_chain_type nft_chain_filter_bridge = {
225 .name = "filter",
226 .type = NFT_CHAIN_T_DEFAULT,
227 .family = NFPROTO_BRIDGE,
228 .hook_mask = (1 << NF_BR_PRE_ROUTING) |
229 (1 << NF_BR_LOCAL_IN) |
230 (1 << NF_BR_FORWARD) |
231 (1 << NF_BR_LOCAL_OUT) |
232 (1 << NF_BR_POST_ROUTING),
233 .hooks = {
234 [NF_BR_PRE_ROUTING] = nft_do_chain_bridge,
235 [NF_BR_LOCAL_IN] = nft_do_chain_bridge,
236 [NF_BR_FORWARD] = nft_do_chain_bridge,
237 [NF_BR_LOCAL_OUT] = nft_do_chain_bridge,
238 [NF_BR_POST_ROUTING] = nft_do_chain_bridge,
239 },
240 };
241
nft_chain_filter_bridge_init(void)242 static void nft_chain_filter_bridge_init(void)
243 {
244 nft_register_chain_type(&nft_chain_filter_bridge);
245 }
246
nft_chain_filter_bridge_fini(void)247 static void nft_chain_filter_bridge_fini(void)
248 {
249 nft_unregister_chain_type(&nft_chain_filter_bridge);
250 }
251 #else
nft_chain_filter_bridge_init(void)252 static inline void nft_chain_filter_bridge_init(void) {}
nft_chain_filter_bridge_fini(void)253 static inline void nft_chain_filter_bridge_fini(void) {}
254 #endif /* CONFIG_NF_TABLES_BRIDGE */
255
256 #ifdef CONFIG_NF_TABLES_NETDEV
nft_do_chain_netdev(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)257 static unsigned int nft_do_chain_netdev(void *priv, struct sk_buff *skb,
258 const struct nf_hook_state *state)
259 {
260 struct nft_pktinfo pkt;
261
262 nft_set_pktinfo(&pkt, skb, state);
263
264 switch (skb->protocol) {
265 case htons(ETH_P_IP):
266 nft_set_pktinfo_ipv4_validate(&pkt, skb);
267 break;
268 case htons(ETH_P_IPV6):
269 nft_set_pktinfo_ipv6_validate(&pkt, skb);
270 break;
271 default:
272 nft_set_pktinfo_unspec(&pkt, skb);
273 break;
274 }
275
276 return nft_do_chain(&pkt, priv);
277 }
278
279 static const struct nft_chain_type nft_chain_filter_netdev = {
280 .name = "filter",
281 .type = NFT_CHAIN_T_DEFAULT,
282 .family = NFPROTO_NETDEV,
283 .hook_mask = (1 << NF_NETDEV_INGRESS),
284 .hooks = {
285 [NF_NETDEV_INGRESS] = nft_do_chain_netdev,
286 },
287 };
288
nft_netdev_event(unsigned long event,struct net_device * dev,struct nft_ctx * ctx)289 static void nft_netdev_event(unsigned long event, struct net_device *dev,
290 struct nft_ctx *ctx)
291 {
292 struct nft_base_chain *basechain = nft_base_chain(ctx->chain);
293
294 switch (event) {
295 case NETDEV_UNREGISTER:
296 if (strcmp(basechain->dev_name, dev->name) != 0)
297 return;
298
299 if (!basechain->ops.dev)
300 return;
301
302 /* UNREGISTER events are also happpening on netns exit.
303 *
304 * Altough nf_tables core releases all tables/chains, only
305 * this event handler provides guarantee that
306 * basechain.ops->dev is still accessible, so we cannot
307 * skip exiting net namespaces.
308 */
309 __nft_release_basechain(ctx);
310 break;
311 case NETDEV_CHANGENAME:
312 if (dev->ifindex != basechain->ops.dev->ifindex)
313 return;
314
315 strncpy(basechain->dev_name, dev->name, IFNAMSIZ);
316 break;
317 }
318 }
319
nf_tables_netdev_event(struct notifier_block * this,unsigned long event,void * ptr)320 static int nf_tables_netdev_event(struct notifier_block *this,
321 unsigned long event, void *ptr)
322 {
323 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
324 struct nftables_pernet *nft_net;
325 struct nft_table *table;
326 struct nft_chain *chain, *nr;
327 struct nft_ctx ctx = {
328 .net = dev_net(dev),
329 };
330
331 if (event != NETDEV_UNREGISTER &&
332 event != NETDEV_CHANGENAME)
333 return NOTIFY_DONE;
334
335 nft_net = net_generic(ctx.net, nf_tables_net_id);
336 mutex_lock(&nft_net->commit_mutex);
337 list_for_each_entry(table, &nft_net->tables, list) {
338 if (table->family != NFPROTO_NETDEV)
339 continue;
340
341 ctx.family = table->family;
342 ctx.table = table;
343 list_for_each_entry_safe(chain, nr, &table->chains, list) {
344 if (!nft_is_base_chain(chain))
345 continue;
346
347 ctx.chain = chain;
348 nft_netdev_event(event, dev, &ctx);
349 }
350 }
351 mutex_unlock(&nft_net->commit_mutex);
352
353 return NOTIFY_DONE;
354 }
355
356 static struct notifier_block nf_tables_netdev_notifier = {
357 .notifier_call = nf_tables_netdev_event,
358 };
359
nft_chain_filter_netdev_init(void)360 static int nft_chain_filter_netdev_init(void)
361 {
362 int err;
363
364 nft_register_chain_type(&nft_chain_filter_netdev);
365
366 err = register_netdevice_notifier(&nf_tables_netdev_notifier);
367 if (err)
368 goto err_register_netdevice_notifier;
369
370 return 0;
371
372 err_register_netdevice_notifier:
373 nft_unregister_chain_type(&nft_chain_filter_netdev);
374
375 return err;
376 }
377
nft_chain_filter_netdev_fini(void)378 static void nft_chain_filter_netdev_fini(void)
379 {
380 nft_unregister_chain_type(&nft_chain_filter_netdev);
381 unregister_netdevice_notifier(&nf_tables_netdev_notifier);
382 }
383 #else
nft_chain_filter_netdev_init(void)384 static inline int nft_chain_filter_netdev_init(void) { return 0; }
nft_chain_filter_netdev_fini(void)385 static inline void nft_chain_filter_netdev_fini(void) {}
386 #endif /* CONFIG_NF_TABLES_NETDEV */
387
nft_chain_filter_init(void)388 int __init nft_chain_filter_init(void)
389 {
390 int err;
391
392 err = nft_chain_filter_netdev_init();
393 if (err < 0)
394 return err;
395
396 nft_chain_filter_ipv4_init();
397 nft_chain_filter_ipv6_init();
398 nft_chain_filter_arp_init();
399 nft_chain_filter_inet_init();
400 nft_chain_filter_bridge_init();
401
402 return 0;
403 }
404
nft_chain_filter_fini(void)405 void nft_chain_filter_fini(void)
406 {
407 nft_chain_filter_bridge_fini();
408 nft_chain_filter_inet_fini();
409 nft_chain_filter_arp_fini();
410 nft_chain_filter_ipv6_fini();
411 nft_chain_filter_ipv4_fini();
412 nft_chain_filter_netdev_fini();
413 }
414