GNU Linux-libre 5.10.217-gnu1
[releases.git] / net / netfilter / nft_chain_filter.c
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
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
47 static void nft_chain_filter_ipv4_init(void)
48 {
49         nft_register_chain_type(&nft_chain_filter_ipv4);
50 }
51 static void nft_chain_filter_ipv4_fini(void)
52 {
53         nft_unregister_chain_type(&nft_chain_filter_ipv4);
54 }
55
56 #else
57 static inline void nft_chain_filter_ipv4_init(void) {}
58 static inline void nft_chain_filter_ipv4_fini(void) {}
59 #endif /* CONFIG_NF_TABLES_IPV4 */
60
61 #ifdef CONFIG_NF_TABLES_ARP
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
86 static void nft_chain_filter_arp_init(void)
87 {
88         nft_register_chain_type(&nft_chain_filter_arp);
89 }
90
91 static void nft_chain_filter_arp_fini(void)
92 {
93         nft_unregister_chain_type(&nft_chain_filter_arp);
94 }
95 #else
96 static inline void nft_chain_filter_arp_init(void) {}
97 static inline void nft_chain_filter_arp_fini(void) {}
98 #endif /* CONFIG_NF_TABLES_ARP */
99
100 #ifdef CONFIG_NF_TABLES_IPV6
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
131 static void nft_chain_filter_ipv6_init(void)
132 {
133         nft_register_chain_type(&nft_chain_filter_ipv6);
134 }
135
136 static void nft_chain_filter_ipv6_fini(void)
137 {
138         nft_unregister_chain_type(&nft_chain_filter_ipv6);
139 }
140 #else
141 static inline void nft_chain_filter_ipv6_init(void) {}
142 static inline void nft_chain_filter_ipv6_fini(void) {}
143 #endif /* CONFIG_NF_TABLES_IPV6 */
144
145 #ifdef CONFIG_NF_TABLES_INET
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 unsigned int nft_do_chain_inet_ingress(void *priv, struct sk_buff *skb,
168                                               const struct nf_hook_state *state)
169 {
170         struct nf_hook_state ingress_state = *state;
171         struct nft_pktinfo pkt;
172
173         switch (skb->protocol) {
174         case htons(ETH_P_IP):
175                 /* Original hook is NFPROTO_NETDEV and NF_NETDEV_INGRESS. */
176                 ingress_state.pf = NFPROTO_IPV4;
177                 ingress_state.hook = NF_INET_INGRESS;
178                 nft_set_pktinfo(&pkt, skb, &ingress_state);
179
180                 if (nft_set_pktinfo_ipv4_ingress(&pkt, skb) < 0)
181                         return NF_DROP;
182                 break;
183         case htons(ETH_P_IPV6):
184                 ingress_state.pf = NFPROTO_IPV6;
185                 ingress_state.hook = NF_INET_INGRESS;
186                 nft_set_pktinfo(&pkt, skb, &ingress_state);
187
188                 if (nft_set_pktinfo_ipv6_ingress(&pkt, skb) < 0)
189                         return NF_DROP;
190                 break;
191         default:
192                 return NF_ACCEPT;
193         }
194
195         return nft_do_chain(&pkt, priv);
196 }
197
198 static const struct nft_chain_type nft_chain_filter_inet = {
199         .name           = "filter",
200         .type           = NFT_CHAIN_T_DEFAULT,
201         .family         = NFPROTO_INET,
202         .hook_mask      = (1 << NF_INET_INGRESS) |
203                           (1 << NF_INET_LOCAL_IN) |
204                           (1 << NF_INET_LOCAL_OUT) |
205                           (1 << NF_INET_FORWARD) |
206                           (1 << NF_INET_PRE_ROUTING) |
207                           (1 << NF_INET_POST_ROUTING),
208         .hooks          = {
209                 [NF_INET_INGRESS]       = nft_do_chain_inet_ingress,
210                 [NF_INET_LOCAL_IN]      = nft_do_chain_inet,
211                 [NF_INET_LOCAL_OUT]     = nft_do_chain_inet,
212                 [NF_INET_FORWARD]       = nft_do_chain_inet,
213                 [NF_INET_PRE_ROUTING]   = nft_do_chain_inet,
214                 [NF_INET_POST_ROUTING]  = nft_do_chain_inet,
215         },
216 };
217
218 static void nft_chain_filter_inet_init(void)
219 {
220         nft_register_chain_type(&nft_chain_filter_inet);
221 }
222
223 static void nft_chain_filter_inet_fini(void)
224 {
225         nft_unregister_chain_type(&nft_chain_filter_inet);
226 }
227 #else
228 static inline void nft_chain_filter_inet_init(void) {}
229 static inline void nft_chain_filter_inet_fini(void) {}
230 #endif /* CONFIG_NF_TABLES_IPV6 */
231
232 #if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE)
233 static unsigned int
234 nft_do_chain_bridge(void *priv,
235                     struct sk_buff *skb,
236                     const struct nf_hook_state *state)
237 {
238         struct nft_pktinfo pkt;
239
240         nft_set_pktinfo(&pkt, skb, state);
241
242         switch (eth_hdr(skb)->h_proto) {
243         case htons(ETH_P_IP):
244                 nft_set_pktinfo_ipv4_validate(&pkt, skb);
245                 break;
246         case htons(ETH_P_IPV6):
247                 nft_set_pktinfo_ipv6_validate(&pkt, skb);
248                 break;
249         default:
250                 nft_set_pktinfo_unspec(&pkt, skb);
251                 break;
252         }
253
254         return nft_do_chain(&pkt, priv);
255 }
256
257 static const struct nft_chain_type nft_chain_filter_bridge = {
258         .name           = "filter",
259         .type           = NFT_CHAIN_T_DEFAULT,
260         .family         = NFPROTO_BRIDGE,
261         .hook_mask      = (1 << NF_BR_PRE_ROUTING) |
262                           (1 << NF_BR_LOCAL_IN) |
263                           (1 << NF_BR_FORWARD) |
264                           (1 << NF_BR_LOCAL_OUT) |
265                           (1 << NF_BR_POST_ROUTING),
266         .hooks          = {
267                 [NF_BR_PRE_ROUTING]     = nft_do_chain_bridge,
268                 [NF_BR_LOCAL_IN]        = nft_do_chain_bridge,
269                 [NF_BR_FORWARD]         = nft_do_chain_bridge,
270                 [NF_BR_LOCAL_OUT]       = nft_do_chain_bridge,
271                 [NF_BR_POST_ROUTING]    = nft_do_chain_bridge,
272         },
273 };
274
275 static void nft_chain_filter_bridge_init(void)
276 {
277         nft_register_chain_type(&nft_chain_filter_bridge);
278 }
279
280 static void nft_chain_filter_bridge_fini(void)
281 {
282         nft_unregister_chain_type(&nft_chain_filter_bridge);
283 }
284 #else
285 static inline void nft_chain_filter_bridge_init(void) {}
286 static inline void nft_chain_filter_bridge_fini(void) {}
287 #endif /* CONFIG_NF_TABLES_BRIDGE */
288
289 #ifdef CONFIG_NF_TABLES_NETDEV
290 static unsigned int nft_do_chain_netdev(void *priv, struct sk_buff *skb,
291                                         const struct nf_hook_state *state)
292 {
293         struct nft_pktinfo pkt;
294
295         nft_set_pktinfo(&pkt, skb, state);
296
297         switch (skb->protocol) {
298         case htons(ETH_P_IP):
299                 nft_set_pktinfo_ipv4_validate(&pkt, skb);
300                 break;
301         case htons(ETH_P_IPV6):
302                 nft_set_pktinfo_ipv6_validate(&pkt, skb);
303                 break;
304         default:
305                 nft_set_pktinfo_unspec(&pkt, skb);
306                 break;
307         }
308
309         return nft_do_chain(&pkt, priv);
310 }
311
312 static const struct nft_chain_type nft_chain_filter_netdev = {
313         .name           = "filter",
314         .type           = NFT_CHAIN_T_DEFAULT,
315         .family         = NFPROTO_NETDEV,
316         .hook_mask      = (1 << NF_NETDEV_INGRESS),
317         .hooks          = {
318                 [NF_NETDEV_INGRESS]     = nft_do_chain_netdev,
319         },
320 };
321
322 static void nft_netdev_event(unsigned long event, struct net_device *dev,
323                              struct nft_ctx *ctx)
324 {
325         struct nft_base_chain *basechain = nft_base_chain(ctx->chain);
326         struct nft_hook *hook, *found = NULL;
327         int n = 0;
328
329         if (event != NETDEV_UNREGISTER)
330                 return;
331
332         list_for_each_entry(hook, &basechain->hook_list, list) {
333                 if (hook->ops.dev == dev)
334                         found = hook;
335
336                 n++;
337         }
338         if (!found)
339                 return;
340
341         if (n > 1) {
342                 if (!(ctx->chain->table->flags & NFT_TABLE_F_DORMANT))
343                         nf_unregister_net_hook(ctx->net, &found->ops);
344
345                 list_del_rcu(&found->list);
346                 kfree_rcu(found, rcu);
347                 return;
348         }
349
350         /* UNREGISTER events are also happening on netns exit.
351          *
352          * Although nf_tables core releases all tables/chains, only this event
353          * handler provides guarantee that hook->ops.dev is still accessible,
354          * so we cannot skip exiting net namespaces.
355          */
356         __nft_release_basechain(ctx);
357 }
358
359 static int nf_tables_netdev_event(struct notifier_block *this,
360                                   unsigned long event, void *ptr)
361 {
362         struct net_device *dev = netdev_notifier_info_to_dev(ptr);
363         struct nft_base_chain *basechain;
364         struct nftables_pernet *nft_net;
365         struct nft_chain *chain, *nr;
366         struct nft_table *table;
367         struct nft_ctx ctx = {
368                 .net    = dev_net(dev),
369         };
370
371         if (event != NETDEV_UNREGISTER &&
372             event != NETDEV_CHANGENAME)
373                 return NOTIFY_DONE;
374
375         nft_net = net_generic(ctx.net, nf_tables_net_id);
376         mutex_lock(&nft_net->commit_mutex);
377         list_for_each_entry(table, &nft_net->tables, list) {
378                 if (table->family != NFPROTO_NETDEV &&
379                     table->family != NFPROTO_INET)
380                         continue;
381
382                 ctx.family = table->family;
383                 ctx.table = table;
384                 list_for_each_entry_safe(chain, nr, &table->chains, list) {
385                         if (!nft_is_base_chain(chain))
386                                 continue;
387
388                         basechain = nft_base_chain(chain);
389                         if (table->family == NFPROTO_INET &&
390                             basechain->ops.hooknum != NF_INET_INGRESS)
391                                 continue;
392
393                         ctx.chain = chain;
394                         nft_netdev_event(event, dev, &ctx);
395                 }
396         }
397         mutex_unlock(&nft_net->commit_mutex);
398
399         return NOTIFY_DONE;
400 }
401
402 static struct notifier_block nf_tables_netdev_notifier = {
403         .notifier_call  = nf_tables_netdev_event,
404 };
405
406 static int nft_chain_filter_netdev_init(void)
407 {
408         int err;
409
410         nft_register_chain_type(&nft_chain_filter_netdev);
411
412         err = register_netdevice_notifier(&nf_tables_netdev_notifier);
413         if (err)
414                 goto err_register_netdevice_notifier;
415
416         return 0;
417
418 err_register_netdevice_notifier:
419         nft_unregister_chain_type(&nft_chain_filter_netdev);
420
421         return err;
422 }
423
424 static void nft_chain_filter_netdev_fini(void)
425 {
426         nft_unregister_chain_type(&nft_chain_filter_netdev);
427         unregister_netdevice_notifier(&nf_tables_netdev_notifier);
428 }
429 #else
430 static inline int nft_chain_filter_netdev_init(void) { return 0; }
431 static inline void nft_chain_filter_netdev_fini(void) {}
432 #endif /* CONFIG_NF_TABLES_NETDEV */
433
434 int __init nft_chain_filter_init(void)
435 {
436         int err;
437
438         err = nft_chain_filter_netdev_init();
439         if (err < 0)
440                 return err;
441
442         nft_chain_filter_ipv4_init();
443         nft_chain_filter_ipv6_init();
444         nft_chain_filter_arp_init();
445         nft_chain_filter_inet_init();
446         nft_chain_filter_bridge_init();
447
448         return 0;
449 }
450
451 void nft_chain_filter_fini(void)
452 {
453         nft_chain_filter_bridge_fini();
454         nft_chain_filter_inet_fini();
455         nft_chain_filter_arp_fini();
456         nft_chain_filter_ipv6_fini();
457         nft_chain_filter_ipv4_fini();
458         nft_chain_filter_netdev_fini();
459 }