GNU Linux-libre 4.19.314-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 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
185 static void nft_chain_filter_inet_init(void)
186 {
187         nft_register_chain_type(&nft_chain_filter_inet);
188 }
189
190 static void nft_chain_filter_inet_fini(void)
191 {
192         nft_unregister_chain_type(&nft_chain_filter_inet);
193 }
194 #else
195 static inline void nft_chain_filter_inet_init(void) {}
196 static inline void nft_chain_filter_inet_fini(void) {}
197 #endif /* CONFIG_NF_TABLES_IPV6 */
198
199 #ifdef CONFIG_NF_TABLES_BRIDGE
200 static unsigned int
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
242 static void nft_chain_filter_bridge_init(void)
243 {
244         nft_register_chain_type(&nft_chain_filter_bridge);
245 }
246
247 static void nft_chain_filter_bridge_fini(void)
248 {
249         nft_unregister_chain_type(&nft_chain_filter_bridge);
250 }
251 #else
252 static inline void nft_chain_filter_bridge_init(void) {}
253 static inline void nft_chain_filter_bridge_fini(void) {}
254 #endif /* CONFIG_NF_TABLES_BRIDGE */
255
256 #ifdef CONFIG_NF_TABLES_NETDEV
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
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                 /* UNREGISTER events are also happpening on netns exit.
300                  *
301                  * Altough nf_tables core releases all tables/chains, only
302                  * this event handler provides guarantee that
303                  * basechain.ops->dev is still accessible, so we cannot
304                  * skip exiting net namespaces.
305                  */
306                 __nft_release_basechain(ctx);
307                 break;
308         case NETDEV_CHANGENAME:
309                 if (dev->ifindex != basechain->ops.dev->ifindex)
310                         return;
311
312                 strncpy(basechain->dev_name, dev->name, IFNAMSIZ);
313                 break;
314         }
315 }
316
317 static int nf_tables_netdev_event(struct notifier_block *this,
318                                   unsigned long event, void *ptr)
319 {
320         struct net_device *dev = netdev_notifier_info_to_dev(ptr);
321         struct nftables_pernet *nft_net;
322         struct nft_table *table;
323         struct nft_chain *chain, *nr;
324         struct nft_ctx ctx = {
325                 .net    = dev_net(dev),
326         };
327
328         if (event != NETDEV_UNREGISTER &&
329             event != NETDEV_CHANGENAME)
330                 return NOTIFY_DONE;
331
332         nft_net = net_generic(ctx.net, nf_tables_net_id);
333         mutex_lock(&nft_net->commit_mutex);
334         list_for_each_entry(table, &nft_net->tables, list) {
335                 if (table->family != NFPROTO_NETDEV)
336                         continue;
337
338                 ctx.family = table->family;
339                 ctx.table = table;
340                 list_for_each_entry_safe(chain, nr, &table->chains, list) {
341                         if (!nft_is_base_chain(chain))
342                                 continue;
343
344                         ctx.chain = chain;
345                         nft_netdev_event(event, dev, &ctx);
346                 }
347         }
348         mutex_unlock(&nft_net->commit_mutex);
349
350         return NOTIFY_DONE;
351 }
352
353 static struct notifier_block nf_tables_netdev_notifier = {
354         .notifier_call  = nf_tables_netdev_event,
355 };
356
357 static int nft_chain_filter_netdev_init(void)
358 {
359         int err;
360
361         nft_register_chain_type(&nft_chain_filter_netdev);
362
363         err = register_netdevice_notifier(&nf_tables_netdev_notifier);
364         if (err)
365                 goto err_register_netdevice_notifier;
366
367         return 0;
368
369 err_register_netdevice_notifier:
370         nft_unregister_chain_type(&nft_chain_filter_netdev);
371
372         return err;
373 }
374
375 static void nft_chain_filter_netdev_fini(void)
376 {
377         nft_unregister_chain_type(&nft_chain_filter_netdev);
378         unregister_netdevice_notifier(&nf_tables_netdev_notifier);
379 }
380 #else
381 static inline int nft_chain_filter_netdev_init(void) { return 0; }
382 static inline void nft_chain_filter_netdev_fini(void) {}
383 #endif /* CONFIG_NF_TABLES_NETDEV */
384
385 int __init nft_chain_filter_init(void)
386 {
387         int err;
388
389         err = nft_chain_filter_netdev_init();
390         if (err < 0)
391                 return err;
392
393         nft_chain_filter_ipv4_init();
394         nft_chain_filter_ipv6_init();
395         nft_chain_filter_arp_init();
396         nft_chain_filter_inet_init();
397         nft_chain_filter_bridge_init();
398
399         return 0;
400 }
401
402 void nft_chain_filter_fini(void)
403 {
404         nft_chain_filter_bridge_fini();
405         nft_chain_filter_inet_fini();
406         nft_chain_filter_arp_fini();
407         nft_chain_filter_ipv6_fini();
408         nft_chain_filter_ipv4_fini();
409         nft_chain_filter_netdev_fini();
410 }