1 #include <linux/init.h>
2 #include <linux/kernel.h>
3 #include <linux/netdevice.h>
4 #include <net/net_namespace.h>
5 #include <net/netfilter/nf_tables.h>
6 #include <linux/netfilter_ipv4.h>
7 #include <linux/netfilter_ipv6.h>
8 #include <linux/netfilter_bridge.h>
9 #include <linux/netfilter_arp.h>
10 #include <net/netfilter/nf_tables_ipv4.h>
11 #include <net/netfilter/nf_tables_ipv6.h>
12
13 #ifdef CONFIG_NF_TABLES_IPV4
nft_do_chain_ipv4(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)14 static unsigned int nft_do_chain_ipv4(void *priv,
15 struct sk_buff *skb,
16 const struct nf_hook_state *state)
17 {
18 struct nft_pktinfo pkt;
19
20 nft_set_pktinfo(&pkt, skb, state);
21 nft_set_pktinfo_ipv4(&pkt);
22
23 return nft_do_chain(&pkt, priv);
24 }
25
26 static const struct nft_chain_type nft_chain_filter_ipv4 = {
27 .name = "filter",
28 .type = NFT_CHAIN_T_DEFAULT,
29 .family = NFPROTO_IPV4,
30 .hook_mask = (1 << NF_INET_LOCAL_IN) |
31 (1 << NF_INET_LOCAL_OUT) |
32 (1 << NF_INET_FORWARD) |
33 (1 << NF_INET_PRE_ROUTING) |
34 (1 << NF_INET_POST_ROUTING),
35 .hooks = {
36 [NF_INET_LOCAL_IN] = nft_do_chain_ipv4,
37 [NF_INET_LOCAL_OUT] = nft_do_chain_ipv4,
38 [NF_INET_FORWARD] = nft_do_chain_ipv4,
39 [NF_INET_PRE_ROUTING] = nft_do_chain_ipv4,
40 [NF_INET_POST_ROUTING] = nft_do_chain_ipv4,
41 },
42 };
43
nft_chain_filter_ipv4_init(void)44 static void nft_chain_filter_ipv4_init(void)
45 {
46 nft_register_chain_type(&nft_chain_filter_ipv4);
47 }
nft_chain_filter_ipv4_fini(void)48 static void nft_chain_filter_ipv4_fini(void)
49 {
50 nft_unregister_chain_type(&nft_chain_filter_ipv4);
51 }
52
53 #else
nft_chain_filter_ipv4_init(void)54 static inline void nft_chain_filter_ipv4_init(void) {}
nft_chain_filter_ipv4_fini(void)55 static inline void nft_chain_filter_ipv4_fini(void) {}
56 #endif /* CONFIG_NF_TABLES_IPV4 */
57
58 #ifdef CONFIG_NF_TABLES_ARP
nft_do_chain_arp(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)59 static unsigned int nft_do_chain_arp(void *priv, struct sk_buff *skb,
60 const struct nf_hook_state *state)
61 {
62 struct nft_pktinfo pkt;
63
64 nft_set_pktinfo(&pkt, skb, state);
65 nft_set_pktinfo_unspec(&pkt);
66
67 return nft_do_chain(&pkt, priv);
68 }
69
70 static const struct nft_chain_type nft_chain_filter_arp = {
71 .name = "filter",
72 .type = NFT_CHAIN_T_DEFAULT,
73 .family = NFPROTO_ARP,
74 .owner = THIS_MODULE,
75 .hook_mask = (1 << NF_ARP_IN) |
76 (1 << NF_ARP_OUT),
77 .hooks = {
78 [NF_ARP_IN] = nft_do_chain_arp,
79 [NF_ARP_OUT] = nft_do_chain_arp,
80 },
81 };
82
nft_chain_filter_arp_init(void)83 static void nft_chain_filter_arp_init(void)
84 {
85 nft_register_chain_type(&nft_chain_filter_arp);
86 }
87
nft_chain_filter_arp_fini(void)88 static void nft_chain_filter_arp_fini(void)
89 {
90 nft_unregister_chain_type(&nft_chain_filter_arp);
91 }
92 #else
nft_chain_filter_arp_init(void)93 static inline void nft_chain_filter_arp_init(void) {}
nft_chain_filter_arp_fini(void)94 static inline void nft_chain_filter_arp_fini(void) {}
95 #endif /* CONFIG_NF_TABLES_ARP */
96
97 #ifdef CONFIG_NF_TABLES_IPV6
nft_do_chain_ipv6(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)98 static unsigned int nft_do_chain_ipv6(void *priv,
99 struct sk_buff *skb,
100 const struct nf_hook_state *state)
101 {
102 struct nft_pktinfo pkt;
103
104 nft_set_pktinfo(&pkt, skb, state);
105 nft_set_pktinfo_ipv6(&pkt);
106
107 return nft_do_chain(&pkt, priv);
108 }
109
110 static const struct nft_chain_type nft_chain_filter_ipv6 = {
111 .name = "filter",
112 .type = NFT_CHAIN_T_DEFAULT,
113 .family = NFPROTO_IPV6,
114 .hook_mask = (1 << NF_INET_LOCAL_IN) |
115 (1 << NF_INET_LOCAL_OUT) |
116 (1 << NF_INET_FORWARD) |
117 (1 << NF_INET_PRE_ROUTING) |
118 (1 << NF_INET_POST_ROUTING),
119 .hooks = {
120 [NF_INET_LOCAL_IN] = nft_do_chain_ipv6,
121 [NF_INET_LOCAL_OUT] = nft_do_chain_ipv6,
122 [NF_INET_FORWARD] = nft_do_chain_ipv6,
123 [NF_INET_PRE_ROUTING] = nft_do_chain_ipv6,
124 [NF_INET_POST_ROUTING] = nft_do_chain_ipv6,
125 },
126 };
127
nft_chain_filter_ipv6_init(void)128 static void nft_chain_filter_ipv6_init(void)
129 {
130 nft_register_chain_type(&nft_chain_filter_ipv6);
131 }
132
nft_chain_filter_ipv6_fini(void)133 static void nft_chain_filter_ipv6_fini(void)
134 {
135 nft_unregister_chain_type(&nft_chain_filter_ipv6);
136 }
137 #else
nft_chain_filter_ipv6_init(void)138 static inline void nft_chain_filter_ipv6_init(void) {}
nft_chain_filter_ipv6_fini(void)139 static inline void nft_chain_filter_ipv6_fini(void) {}
140 #endif /* CONFIG_NF_TABLES_IPV6 */
141
142 #ifdef CONFIG_NF_TABLES_INET
nft_do_chain_inet(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)143 static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb,
144 const struct nf_hook_state *state)
145 {
146 struct nft_pktinfo pkt;
147
148 nft_set_pktinfo(&pkt, skb, state);
149
150 switch (state->pf) {
151 case NFPROTO_IPV4:
152 nft_set_pktinfo_ipv4(&pkt);
153 break;
154 case NFPROTO_IPV6:
155 nft_set_pktinfo_ipv6(&pkt);
156 break;
157 default:
158 break;
159 }
160
161 return nft_do_chain(&pkt, priv);
162 }
163
nft_do_chain_inet_ingress(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)164 static unsigned int nft_do_chain_inet_ingress(void *priv, struct sk_buff *skb,
165 const struct nf_hook_state *state)
166 {
167 struct nf_hook_state ingress_state = *state;
168 struct nft_pktinfo pkt;
169
170 switch (skb->protocol) {
171 case htons(ETH_P_IP):
172 /* Original hook is NFPROTO_NETDEV and NF_NETDEV_INGRESS. */
173 ingress_state.pf = NFPROTO_IPV4;
174 ingress_state.hook = NF_INET_INGRESS;
175 nft_set_pktinfo(&pkt, skb, &ingress_state);
176
177 if (nft_set_pktinfo_ipv4_ingress(&pkt) < 0)
178 return NF_DROP;
179 break;
180 case htons(ETH_P_IPV6):
181 ingress_state.pf = NFPROTO_IPV6;
182 ingress_state.hook = NF_INET_INGRESS;
183 nft_set_pktinfo(&pkt, skb, &ingress_state);
184
185 if (nft_set_pktinfo_ipv6_ingress(&pkt) < 0)
186 return NF_DROP;
187 break;
188 default:
189 return NF_ACCEPT;
190 }
191
192 return nft_do_chain(&pkt, priv);
193 }
194
195 static const struct nft_chain_type nft_chain_filter_inet = {
196 .name = "filter",
197 .type = NFT_CHAIN_T_DEFAULT,
198 .family = NFPROTO_INET,
199 .hook_mask = (1 << NF_INET_INGRESS) |
200 (1 << NF_INET_LOCAL_IN) |
201 (1 << NF_INET_LOCAL_OUT) |
202 (1 << NF_INET_FORWARD) |
203 (1 << NF_INET_PRE_ROUTING) |
204 (1 << NF_INET_POST_ROUTING),
205 .hooks = {
206 [NF_INET_INGRESS] = nft_do_chain_inet_ingress,
207 [NF_INET_LOCAL_IN] = nft_do_chain_inet,
208 [NF_INET_LOCAL_OUT] = nft_do_chain_inet,
209 [NF_INET_FORWARD] = nft_do_chain_inet,
210 [NF_INET_PRE_ROUTING] = nft_do_chain_inet,
211 [NF_INET_POST_ROUTING] = nft_do_chain_inet,
212 },
213 };
214
nft_chain_filter_inet_init(void)215 static void nft_chain_filter_inet_init(void)
216 {
217 nft_register_chain_type(&nft_chain_filter_inet);
218 }
219
nft_chain_filter_inet_fini(void)220 static void nft_chain_filter_inet_fini(void)
221 {
222 nft_unregister_chain_type(&nft_chain_filter_inet);
223 }
224 #else
nft_chain_filter_inet_init(void)225 static inline void nft_chain_filter_inet_init(void) {}
nft_chain_filter_inet_fini(void)226 static inline void nft_chain_filter_inet_fini(void) {}
227 #endif /* CONFIG_NF_TABLES_IPV6 */
228
229 #if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE)
230 static unsigned int
nft_do_chain_bridge(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)231 nft_do_chain_bridge(void *priv,
232 struct sk_buff *skb,
233 const struct nf_hook_state *state)
234 {
235 struct nft_pktinfo pkt;
236
237 nft_set_pktinfo(&pkt, skb, state);
238
239 switch (eth_hdr(skb)->h_proto) {
240 case htons(ETH_P_IP):
241 nft_set_pktinfo_ipv4_validate(&pkt);
242 break;
243 case htons(ETH_P_IPV6):
244 nft_set_pktinfo_ipv6_validate(&pkt);
245 break;
246 default:
247 nft_set_pktinfo_unspec(&pkt);
248 break;
249 }
250
251 return nft_do_chain(&pkt, priv);
252 }
253
254 static const struct nft_chain_type nft_chain_filter_bridge = {
255 .name = "filter",
256 .type = NFT_CHAIN_T_DEFAULT,
257 .family = NFPROTO_BRIDGE,
258 .hook_mask = (1 << NF_BR_PRE_ROUTING) |
259 (1 << NF_BR_LOCAL_IN) |
260 (1 << NF_BR_FORWARD) |
261 (1 << NF_BR_LOCAL_OUT) |
262 (1 << NF_BR_POST_ROUTING),
263 .hooks = {
264 [NF_BR_PRE_ROUTING] = nft_do_chain_bridge,
265 [NF_BR_LOCAL_IN] = nft_do_chain_bridge,
266 [NF_BR_FORWARD] = nft_do_chain_bridge,
267 [NF_BR_LOCAL_OUT] = nft_do_chain_bridge,
268 [NF_BR_POST_ROUTING] = nft_do_chain_bridge,
269 },
270 };
271
nft_chain_filter_bridge_init(void)272 static void nft_chain_filter_bridge_init(void)
273 {
274 nft_register_chain_type(&nft_chain_filter_bridge);
275 }
276
nft_chain_filter_bridge_fini(void)277 static void nft_chain_filter_bridge_fini(void)
278 {
279 nft_unregister_chain_type(&nft_chain_filter_bridge);
280 }
281 #else
nft_chain_filter_bridge_init(void)282 static inline void nft_chain_filter_bridge_init(void) {}
nft_chain_filter_bridge_fini(void)283 static inline void nft_chain_filter_bridge_fini(void) {}
284 #endif /* CONFIG_NF_TABLES_BRIDGE */
285
286 #ifdef CONFIG_NF_TABLES_NETDEV
nft_do_chain_netdev(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)287 static unsigned int nft_do_chain_netdev(void *priv, struct sk_buff *skb,
288 const struct nf_hook_state *state)
289 {
290 struct nft_pktinfo pkt;
291
292 nft_set_pktinfo(&pkt, skb, state);
293
294 switch (skb->protocol) {
295 case htons(ETH_P_IP):
296 nft_set_pktinfo_ipv4_validate(&pkt);
297 break;
298 case htons(ETH_P_IPV6):
299 nft_set_pktinfo_ipv6_validate(&pkt);
300 break;
301 default:
302 nft_set_pktinfo_unspec(&pkt);
303 break;
304 }
305
306 return nft_do_chain(&pkt, priv);
307 }
308
309 static const struct nft_chain_type nft_chain_filter_netdev = {
310 .name = "filter",
311 .type = NFT_CHAIN_T_DEFAULT,
312 .family = NFPROTO_NETDEV,
313 .hook_mask = (1 << NF_NETDEV_INGRESS) |
314 (1 << NF_NETDEV_EGRESS),
315 .hooks = {
316 [NF_NETDEV_INGRESS] = nft_do_chain_netdev,
317 [NF_NETDEV_EGRESS] = nft_do_chain_netdev,
318 },
319 };
320
nft_netdev_event(unsigned long event,struct net_device * dev,struct nft_base_chain * basechain,bool changename)321 static int nft_netdev_event(unsigned long event, struct net_device *dev,
322 struct nft_base_chain *basechain, bool changename)
323 {
324 struct nft_table *table = basechain->chain.table;
325 struct nf_hook_ops *ops;
326 struct nft_hook *hook;
327 bool match;
328
329 list_for_each_entry(hook, &basechain->hook_list, list) {
330 ops = nft_hook_find_ops(hook, dev);
331 match = !strncmp(hook->ifname, dev->name, hook->ifnamelen);
332
333 switch (event) {
334 case NETDEV_UNREGISTER:
335 /* NOP if not found or new name still matching */
336 if (!ops || (changename && match))
337 continue;
338
339 if (!(table->flags & NFT_TABLE_F_DORMANT))
340 nf_unregister_net_hook(dev_net(dev), ops);
341
342 list_del_rcu(&ops->list);
343 kfree_rcu(ops, rcu);
344 break;
345 case NETDEV_REGISTER:
346 /* NOP if not matching or already registered */
347 if (!match || (changename && ops))
348 continue;
349
350 ops = kmemdup(&basechain->ops,
351 sizeof(struct nf_hook_ops),
352 GFP_KERNEL_ACCOUNT);
353 if (!ops)
354 return 1;
355
356 ops->dev = dev;
357
358 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
359 nf_register_net_hook(dev_net(dev), ops)) {
360 kfree(ops);
361 return 1;
362 }
363 list_add_tail_rcu(&ops->list, &hook->ops_list);
364 break;
365 }
366 break;
367 }
368 return 0;
369 }
370
__nf_tables_netdev_event(unsigned long event,struct net_device * dev,bool changename)371 static int __nf_tables_netdev_event(unsigned long event,
372 struct net_device *dev,
373 bool changename)
374 {
375 struct nft_base_chain *basechain;
376 struct nftables_pernet *nft_net;
377 struct nft_chain *chain;
378 struct nft_table *table;
379
380 nft_net = nft_pernet(dev_net(dev));
381 list_for_each_entry(table, &nft_net->tables, list) {
382 if (table->family != NFPROTO_NETDEV &&
383 table->family != NFPROTO_INET)
384 continue;
385
386 list_for_each_entry(chain, &table->chains, list) {
387 if (!nft_is_base_chain(chain))
388 continue;
389
390 basechain = nft_base_chain(chain);
391 if (table->family == NFPROTO_INET &&
392 basechain->ops.hooknum != NF_INET_INGRESS)
393 continue;
394
395 if (nft_netdev_event(event, dev, basechain, changename))
396 return 1;
397 }
398 }
399 return 0;
400 }
401
nf_tables_netdev_event(struct notifier_block * this,unsigned long event,void * ptr)402 static int nf_tables_netdev_event(struct notifier_block *this,
403 unsigned long event, void *ptr)
404 {
405 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
406 struct nftables_pernet *nft_net;
407 int ret = NOTIFY_DONE;
408
409 if (event != NETDEV_REGISTER &&
410 event != NETDEV_UNREGISTER &&
411 event != NETDEV_CHANGENAME)
412 return NOTIFY_DONE;
413
414 nft_net = nft_pernet(dev_net(dev));
415 mutex_lock(&nft_net->commit_mutex);
416
417 if (event == NETDEV_CHANGENAME) {
418 if (__nf_tables_netdev_event(NETDEV_REGISTER, dev, true)) {
419 ret = NOTIFY_BAD;
420 goto out_unlock;
421 }
422 __nf_tables_netdev_event(NETDEV_UNREGISTER, dev, true);
423 } else if (__nf_tables_netdev_event(event, dev, false)) {
424 ret = NOTIFY_BAD;
425 }
426 out_unlock:
427 mutex_unlock(&nft_net->commit_mutex);
428 return ret;
429 }
430
431 static struct notifier_block nf_tables_netdev_notifier = {
432 .notifier_call = nf_tables_netdev_event,
433 };
434
nft_chain_filter_netdev_init(void)435 static int nft_chain_filter_netdev_init(void)
436 {
437 int err;
438
439 nft_register_chain_type(&nft_chain_filter_netdev);
440
441 err = register_netdevice_notifier(&nf_tables_netdev_notifier);
442 if (err)
443 goto err_register_netdevice_notifier;
444
445 return 0;
446
447 err_register_netdevice_notifier:
448 nft_unregister_chain_type(&nft_chain_filter_netdev);
449
450 return err;
451 }
452
nft_chain_filter_netdev_fini(void)453 static void nft_chain_filter_netdev_fini(void)
454 {
455 nft_unregister_chain_type(&nft_chain_filter_netdev);
456 unregister_netdevice_notifier(&nf_tables_netdev_notifier);
457 }
458 #else
nft_chain_filter_netdev_init(void)459 static inline int nft_chain_filter_netdev_init(void) { return 0; }
nft_chain_filter_netdev_fini(void)460 static inline void nft_chain_filter_netdev_fini(void) {}
461 #endif /* CONFIG_NF_TABLES_NETDEV */
462
nft_chain_filter_init(void)463 int __init nft_chain_filter_init(void)
464 {
465 int err;
466
467 err = nft_chain_filter_netdev_init();
468 if (err < 0)
469 return err;
470
471 nft_chain_filter_ipv4_init();
472 nft_chain_filter_ipv6_init();
473 nft_chain_filter_arp_init();
474 nft_chain_filter_inet_init();
475 nft_chain_filter_bridge_init();
476
477 return 0;
478 }
479
nft_chain_filter_fini(void)480 void nft_chain_filter_fini(void)
481 {
482 nft_chain_filter_bridge_fini();
483 nft_chain_filter_inet_fini();
484 nft_chain_filter_arp_fini();
485 nft_chain_filter_ipv6_fini();
486 nft_chain_filter_ipv4_fini();
487 nft_chain_filter_netdev_fini();
488 }
489