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_ctx * ctx)321 static void nft_netdev_event(unsigned long event, struct net_device *dev,
322 			     struct nft_ctx *ctx)
323 {
324 	struct nft_base_chain *basechain = nft_base_chain(ctx->chain);
325 	struct nft_hook *hook, *found = NULL;
326 	int n = 0;
327 
328 	if (event != NETDEV_UNREGISTER)
329 		return;
330 
331 	list_for_each_entry(hook, &basechain->hook_list, list) {
332 		if (hook->ops.dev == dev)
333 			found = hook;
334 
335 		n++;
336 	}
337 	if (!found)
338 		return;
339 
340 	if (n > 1) {
341 		if (!(ctx->chain->table->flags & NFT_TABLE_F_DORMANT))
342 			nf_unregister_net_hook(ctx->net, &found->ops);
343 
344 		list_del_rcu(&found->list);
345 		kfree_rcu(found, rcu);
346 		return;
347 	}
348 
349 	/* UNREGISTER events are also happening on netns exit.
350 	 *
351 	 * Although nf_tables core releases all tables/chains, only this event
352 	 * handler provides guarantee that hook->ops.dev is still accessible,
353 	 * so we cannot skip exiting net namespaces.
354 	 */
355 	__nft_release_basechain(ctx);
356 }
357 
nf_tables_netdev_event(struct notifier_block * this,unsigned long event,void * ptr)358 static int nf_tables_netdev_event(struct notifier_block *this,
359 				  unsigned long event, void *ptr)
360 {
361 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
362 	struct nft_base_chain *basechain;
363 	struct nftables_pernet *nft_net;
364 	struct nft_chain *chain, *nr;
365 	struct nft_table *table;
366 	struct nft_ctx ctx = {
367 		.net	= dev_net(dev),
368 	};
369 
370 	if (event != NETDEV_UNREGISTER &&
371 	    event != NETDEV_CHANGENAME)
372 		return NOTIFY_DONE;
373 
374 	nft_net = nft_pernet(ctx.net);
375 	mutex_lock(&nft_net->commit_mutex);
376 	list_for_each_entry(table, &nft_net->tables, list) {
377 		if (table->family != NFPROTO_NETDEV &&
378 		    table->family != NFPROTO_INET)
379 			continue;
380 
381 		ctx.family = table->family;
382 		ctx.table = table;
383 		list_for_each_entry_safe(chain, nr, &table->chains, list) {
384 			if (!nft_is_base_chain(chain))
385 				continue;
386 
387 			basechain = nft_base_chain(chain);
388 			if (table->family == NFPROTO_INET &&
389 			    basechain->ops.hooknum != NF_INET_INGRESS)
390 				continue;
391 
392 			ctx.chain = chain;
393 			nft_netdev_event(event, dev, &ctx);
394 		}
395 	}
396 	mutex_unlock(&nft_net->commit_mutex);
397 
398 	return NOTIFY_DONE;
399 }
400 
401 static struct notifier_block nf_tables_netdev_notifier = {
402 	.notifier_call	= nf_tables_netdev_event,
403 };
404 
nft_chain_filter_netdev_init(void)405 static int nft_chain_filter_netdev_init(void)
406 {
407 	int err;
408 
409 	nft_register_chain_type(&nft_chain_filter_netdev);
410 
411 	err = register_netdevice_notifier(&nf_tables_netdev_notifier);
412 	if (err)
413 		goto err_register_netdevice_notifier;
414 
415 	return 0;
416 
417 err_register_netdevice_notifier:
418 	nft_unregister_chain_type(&nft_chain_filter_netdev);
419 
420 	return err;
421 }
422 
nft_chain_filter_netdev_fini(void)423 static void nft_chain_filter_netdev_fini(void)
424 {
425 	nft_unregister_chain_type(&nft_chain_filter_netdev);
426 	unregister_netdevice_notifier(&nf_tables_netdev_notifier);
427 }
428 #else
nft_chain_filter_netdev_init(void)429 static inline int nft_chain_filter_netdev_init(void) { return 0; }
nft_chain_filter_netdev_fini(void)430 static inline void nft_chain_filter_netdev_fini(void) {}
431 #endif /* CONFIG_NF_TABLES_NETDEV */
432 
nft_chain_filter_init(void)433 int __init nft_chain_filter_init(void)
434 {
435 	int err;
436 
437 	err = nft_chain_filter_netdev_init();
438 	if (err < 0)
439 		return err;
440 
441 	nft_chain_filter_ipv4_init();
442 	nft_chain_filter_ipv6_init();
443 	nft_chain_filter_arp_init();
444 	nft_chain_filter_inet_init();
445 	nft_chain_filter_bridge_init();
446 
447 	return 0;
448 }
449 
nft_chain_filter_fini(void)450 void nft_chain_filter_fini(void)
451 {
452 	nft_chain_filter_bridge_fini();
453 	nft_chain_filter_inet_fini();
454 	nft_chain_filter_arp_fini();
455 	nft_chain_filter_ipv6_fini();
456 	nft_chain_filter_ipv4_fini();
457 	nft_chain_filter_netdev_fini();
458 }
459