1 /*
2  * Copyright (c) 2021 BayLibre SAS
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(npf_base, CONFIG_NET_PKT_FILTER_LOG_LEVEL);
9 
10 #include <zephyr/net/net_core.h>
11 #include <zephyr/net/net_pkt_filter.h>
12 #include <zephyr/spinlock.h>
13 
14 /*
15  * Our actual rule lists for supported test points
16  */
17 
18 struct npf_rule_list npf_send_rules = {
19 	.rule_head = SYS_SLIST_STATIC_INIT(&send_rules.rule_head),
20 	.lock = { },
21 };
22 
23 struct npf_rule_list npf_recv_rules = {
24 	.rule_head = SYS_SLIST_STATIC_INIT(&recv_rules.rule_head),
25 	.lock = { },
26 };
27 
28 #ifdef CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK
29 struct npf_rule_list npf_local_in_recv_rules = {
30 	.rule_head = SYS_SLIST_STATIC_INIT(&local_in_recv_rules.rule_head),
31 	.lock = { },
32 };
33 #endif /* CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK */
34 
35 #ifdef CONFIG_NET_PKT_FILTER_IPV4_HOOK
36 struct npf_rule_list npf_ipv4_recv_rules = {
37 	.rule_head = SYS_SLIST_STATIC_INIT(&ipv4_recv_rules.rule_head),
38 	.lock = { },
39 };
40 #endif /* CONFIG_NET_PKT_FILTER_IPV4_HOOK */
41 
42 #ifdef CONFIG_NET_PKT_FILTER_IPV6_HOOK
43 struct npf_rule_list npf_ipv6_recv_rules = {
44 	.rule_head = SYS_SLIST_STATIC_INIT(&ipv6_recv_rules.rule_head),
45 	.lock = { },
46 };
47 #endif /* CONFIG_NET_PKT_FILTER_IPV6_HOOK */
48 
49 /*
50  * Helper function
51  */
52 #if defined(CONFIG_NET_PKT_FILTER_IPV4_HOOK) || defined(CONFIG_NET_PKT_FILTER_IPV6_HOOK)
get_ip_rules(uint8_t pf)53 static struct npf_rule_list *get_ip_rules(uint8_t pf)
54 {
55 	switch (pf) {
56 	case NET_PF_INET:
57 #ifdef CONFIG_NET_PKT_FILTER_IPV4_HOOK
58 		return &npf_ipv4_recv_rules;
59 #endif
60 		break;
61 	case NET_PF_INET6:
62 #ifdef CONFIG_NET_PKT_FILTER_IPV6_HOOK
63 		return &npf_ipv6_recv_rules;
64 #endif
65 		break;
66 	default:
67 		return NULL;
68 	}
69 
70 	return NULL;
71 }
72 #endif /* CONFIG_NET_PKT_FILTER_IPV4_HOOK || CONFIG_NET_PKT_FILTER_IPV6_HOOK */
73 /*
74  * Rule application
75  */
76 
77 /*
78  * All tests must be true to return true.
79  * If no tests then it is true.
80  */
apply_tests(struct npf_rule * rule,struct net_pkt * pkt)81 static bool apply_tests(struct npf_rule *rule, struct net_pkt *pkt)
82 {
83 	struct npf_test *test;
84 	unsigned int i;
85 	bool result;
86 
87 	for (i = 0; i < rule->nb_tests; i++) {
88 		test = rule->tests[i];
89 		result = test->fn(test, pkt);
90 		NET_DBG("test %s (%p) result %d",
91 			COND_CODE_1(NPF_TEST_ENABLE_NAME, (test->name), ("")),
92 			test, result);
93 		if (result == false) {
94 			return false;
95 		}
96 	}
97 
98 	return true;
99 }
100 
101 /*
102  * We return the specified result for the first rule whose tests are all true.
103  */
evaluate(sys_slist_t * rule_head,struct net_pkt * pkt)104 static enum net_verdict evaluate(sys_slist_t *rule_head, struct net_pkt *pkt)
105 {
106 	struct npf_rule *rule;
107 
108 	NET_DBG("rule_head %p on pkt %p", rule_head, pkt);
109 
110 	if (sys_slist_is_empty(rule_head)) {
111 		NET_DBG("no rules");
112 		return NET_OK;
113 	}
114 
115 	SYS_SLIST_FOR_EACH_CONTAINER(rule_head, rule, node) {
116 		if (apply_tests(rule, pkt) == true) {
117 			if (rule->result == NET_CONTINUE) {
118 				net_pkt_set_priority(pkt, rule->priority);
119 				continue;
120 			}
121 			return rule->result;
122 		}
123 	}
124 
125 	NET_DBG("no matching rules from rule_head %p", rule_head);
126 	return NET_DROP;
127 }
128 
lock_evaluate(struct npf_rule_list * rules,struct net_pkt * pkt)129 static enum net_verdict lock_evaluate(struct npf_rule_list *rules, struct net_pkt *pkt)
130 {
131 	k_spinlock_key_t key = k_spin_lock(&rules->lock);
132 	enum net_verdict result = evaluate(&rules->rule_head, pkt);
133 
134 	k_spin_unlock(&rules->lock, key);
135 	return result;
136 }
137 
net_pkt_filter_send_ok(struct net_pkt * pkt)138 bool net_pkt_filter_send_ok(struct net_pkt *pkt)
139 {
140 	enum net_verdict result = lock_evaluate(&npf_send_rules, pkt);
141 
142 	return result == NET_OK;
143 }
144 
net_pkt_filter_recv_ok(struct net_pkt * pkt)145 bool net_pkt_filter_recv_ok(struct net_pkt *pkt)
146 {
147 	enum net_verdict result = lock_evaluate(&npf_recv_rules, pkt);
148 
149 	return result == NET_OK;
150 }
151 
152 #ifdef CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK
net_pkt_filter_local_in_recv_ok(struct net_pkt * pkt)153 bool net_pkt_filter_local_in_recv_ok(struct net_pkt *pkt)
154 {
155 	enum net_verdict result = lock_evaluate(&npf_local_in_recv_rules, pkt);
156 
157 	return result == NET_OK;
158 }
159 #endif /* CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK */
160 
161 #if defined(CONFIG_NET_PKT_FILTER_IPV4_HOOK) || defined(CONFIG_NET_PKT_FILTER_IPV6_HOOK)
net_pkt_filter_ip_recv_ok(struct net_pkt * pkt)162 bool net_pkt_filter_ip_recv_ok(struct net_pkt *pkt)
163 {
164 	struct npf_rule_list *rules = get_ip_rules(net_pkt_family(pkt));
165 
166 	if (!rules) {
167 		NET_DBG("no rules");
168 		return true;
169 	}
170 
171 	enum net_verdict result = lock_evaluate(rules, pkt);
172 
173 	return result == NET_OK;
174 }
175 #endif /* CONFIG_NET_PKT_FILTER_IPV4_HOOK || CONFIG_NET_PKT_FILTER_IPV6_HOOK */
176 
177 /*
178  * Rule management
179  */
180 
npf_insert_rule(struct npf_rule_list * rules,struct npf_rule * rule)181 void npf_insert_rule(struct npf_rule_list *rules, struct npf_rule *rule)
182 {
183 	k_spinlock_key_t key = k_spin_lock(&rules->lock);
184 
185 	NET_DBG("inserting rule %p into %p", rule, rules);
186 	sys_slist_prepend(&rules->rule_head, &rule->node);
187 
188 	k_spin_unlock(&rules->lock, key);
189 }
190 
npf_append_rule(struct npf_rule_list * rules,struct npf_rule * rule)191 void npf_append_rule(struct npf_rule_list *rules, struct npf_rule *rule)
192 {
193 	__ASSERT(sys_slist_peek_tail(&rules->rule_head) != &npf_default_ok.node, "");
194 	__ASSERT(sys_slist_peek_tail(&rules->rule_head) != &npf_default_drop.node, "");
195 
196 	k_spinlock_key_t key = k_spin_lock(&rules->lock);
197 
198 	NET_DBG("appending rule %p into %p", rule, rules);
199 	sys_slist_append(&rules->rule_head, &rule->node);
200 
201 	k_spin_unlock(&rules->lock, key);
202 }
203 
npf_remove_rule(struct npf_rule_list * rules,struct npf_rule * rule)204 bool npf_remove_rule(struct npf_rule_list *rules, struct npf_rule *rule)
205 {
206 	k_spinlock_key_t key = k_spin_lock(&rules->lock);
207 	bool result = sys_slist_find_and_remove(&rules->rule_head, &rule->node);
208 
209 	k_spin_unlock(&rules->lock, key);
210 	NET_DBG("removing rule %p from %p: %d", rule, rules, result);
211 	return result;
212 }
213 
npf_remove_all_rules(struct npf_rule_list * rules)214 bool npf_remove_all_rules(struct npf_rule_list *rules)
215 {
216 	k_spinlock_key_t key = k_spin_lock(&rules->lock);
217 	bool result = !sys_slist_is_empty(&rules->rule_head);
218 
219 	if (result) {
220 		sys_slist_init(&rules->rule_head);
221 		NET_DBG("removing all rules from %p", rules);
222 	}
223 
224 	k_spin_unlock(&rules->lock, key);
225 	return result;
226 }
227 
228 /*
229  * Default rule list terminations.
230  */
231 
232 struct npf_rule npf_default_ok = {
233 	.result = NET_OK,
234 };
235 
236 struct npf_rule npf_default_drop = {
237 	.result = NET_DROP,
238 };
239 
240 /*
241  * Some simple generic conditions
242  */
243 
npf_iface_match(struct npf_test * test,struct net_pkt * pkt)244 bool npf_iface_match(struct npf_test *test, struct net_pkt *pkt)
245 {
246 	struct npf_test_iface *test_iface =
247 			CONTAINER_OF(test, struct npf_test_iface, test);
248 
249 	NET_DBG("iface %d pkt %d",
250 		net_if_get_by_iface(test_iface->iface),
251 		net_if_get_by_iface(net_pkt_iface(pkt)));
252 
253 	return test_iface->iface == net_pkt_iface(pkt);
254 }
255 
npf_iface_unmatch(struct npf_test * test,struct net_pkt * pkt)256 bool npf_iface_unmatch(struct npf_test *test, struct net_pkt *pkt)
257 {
258 	return !npf_iface_match(test, pkt);
259 }
260 
npf_orig_iface_match(struct npf_test * test,struct net_pkt * pkt)261 bool npf_orig_iface_match(struct npf_test *test, struct net_pkt *pkt)
262 {
263 	struct npf_test_iface *test_iface =
264 			CONTAINER_OF(test, struct npf_test_iface, test);
265 
266 	NET_DBG("orig iface %d pkt %d",
267 		net_if_get_by_iface(test_iface->iface),
268 		net_if_get_by_iface(net_pkt_orig_iface(pkt)));
269 
270 	return test_iface->iface == net_pkt_orig_iface(pkt);
271 }
272 
npf_orig_iface_unmatch(struct npf_test * test,struct net_pkt * pkt)273 bool npf_orig_iface_unmatch(struct npf_test *test, struct net_pkt *pkt)
274 {
275 	return !npf_orig_iface_match(test, pkt);
276 }
277 
npf_size_inbounds(struct npf_test * test,struct net_pkt * pkt)278 bool npf_size_inbounds(struct npf_test *test, struct net_pkt *pkt)
279 {
280 	struct npf_test_size_bounds *bounds =
281 			CONTAINER_OF(test, struct npf_test_size_bounds, test);
282 	size_t pkt_size = net_pkt_get_len(pkt);
283 
284 	NET_DBG("pkt_size %zu min %zu max %zu",
285 		pkt_size, bounds->min, bounds->max);
286 
287 	return pkt_size >= bounds->min && pkt_size <= bounds->max;
288 }
289 
npf_ip_src_addr_match(struct npf_test * test,struct net_pkt * pkt)290 bool npf_ip_src_addr_match(struct npf_test *test, struct net_pkt *pkt)
291 {
292 	struct npf_test_ip *test_ip =
293 			CONTAINER_OF(test, struct npf_test_ip, test);
294 	uint8_t pkt_family = net_pkt_family(pkt);
295 
296 	for (uint32_t ip_it = 0; ip_it < test_ip->ipaddr_num; ip_it++) {
297 		if (IS_ENABLED(CONFIG_NET_IPV4) && pkt_family == NET_AF_INET) {
298 			struct net_in_addr *addr = (struct net_in_addr *)NET_IPV4_HDR(pkt)->src;
299 
300 			if (net_ipv4_addr_cmp(addr,
301 					      &((struct net_in_addr *)test_ip->ipaddr)[ip_it])) {
302 				return true;
303 			}
304 		} else if (IS_ENABLED(CONFIG_NET_IPV6) && pkt_family == NET_AF_INET6) {
305 			struct net_in6_addr *addr = (struct net_in6_addr *)NET_IPV6_HDR(pkt)->src;
306 
307 			if (net_ipv6_addr_cmp(addr,
308 					      &((struct net_in6_addr *)test_ip->ipaddr)[ip_it])) {
309 				return true;
310 			}
311 		}
312 	}
313 	return false;
314 }
315 
npf_ip_src_addr_unmatch(struct npf_test * test,struct net_pkt * pkt)316 bool npf_ip_src_addr_unmatch(struct npf_test *test, struct net_pkt *pkt)
317 {
318 	return !npf_ip_src_addr_match(test, pkt);
319 }
320 
rules_cb(struct npf_rule_list * rules,enum npf_rule_type type,npf_rule_cb_t cb,void * user_data)321 static void rules_cb(struct npf_rule_list *rules, enum npf_rule_type type,
322 		     npf_rule_cb_t cb, void *user_data)
323 {
324 	struct npf_rule *rule;
325 
326 	SYS_SLIST_FOR_EACH_CONTAINER(&rules->rule_head, rule, node) {
327 		cb(rule, type, user_data);
328 	}
329 }
330 
331 #ifdef CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK
npf_local_in_match(struct npf_test * test,struct net_pkt * pkt)332 bool npf_local_in_match(struct npf_test *test, struct net_pkt *pkt)
333 {
334 	struct npf_test_local_in *test_local_in =
335 			CONTAINER_OF(test, struct npf_test_local_in, test);
336 
337 	if (test_local_in->fn == NULL) {
338 		return true;
339 	}
340 
341 	return test_local_in->fn(pkt, test_local_in->user_data);
342 }
343 #endif /* CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK */
344 
npf_rules_foreach(npf_rule_cb_t cb,void * user_data)345 void npf_rules_foreach(npf_rule_cb_t cb, void *user_data)
346 {
347 	rules_cb(&npf_send_rules, NPF_RULE_TYPE_SEND, cb, user_data);
348 	rules_cb(&npf_recv_rules, NPF_RULE_TYPE_RECV, cb, user_data);
349 
350 #ifdef CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK
351 	rules_cb(&npf_local_in_recv_rules, NPF_RULE_TYPE_LOCAL_IN_RECV, cb, user_data);
352 #endif /* CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK */
353 
354 #ifdef CONFIG_NET_PKT_FILTER_IPV4_HOOK
355 	rules_cb(&npf_ipv4_recv_rules, NPF_RULE_TYPE_IPV4_RECV, cb, user_data);
356 #endif /* CONFIG_NET_PKT_FILTER_IPV4_HOOK */
357 
358 #ifdef CONFIG_NET_PKT_FILTER_IPV6_HOOK
359 	rules_cb(&npf_ipv6_recv_rules, NPF_RULE_TYPE_IPV6_RECV, cb, user_data);
360 #endif /* CONFIG_NET_PKT_FILTER_IPV6_HOOK */
361 }
362 
363 #include "net_private.h" /* for net_sprint_addr() */
364 
npf_test_get_str(struct npf_test * test,char * buf,size_t len)365 const char *npf_test_get_str(struct npf_test *test, char *buf, size_t len)
366 {
367 #if defined(CONFIG_NET_SHELL_PKT_FILTER_SUPPORTED)
368 	if (test->type == NPF_TEST_TYPE_IFACE_MATCH ||
369 	    test->type == NPF_TEST_TYPE_IFACE_UNMATCH ||
370 	    test->type == NPF_TEST_TYPE_ORIG_IFACE_MATCH ||
371 	    test->type == NPF_TEST_TYPE_ORIG_IFACE_UNMATCH) {
372 		struct npf_test_iface *test_iface =
373 			CONTAINER_OF(test, struct npf_test_iface, test);
374 
375 		snprintk(buf, len, "[%d]", net_if_get_by_iface(test_iface->iface));
376 
377 	} else if (test->type == NPF_TEST_TYPE_SIZE_BOUNDS ||
378 		   test->type == NPF_TEST_TYPE_SIZE_MIN ||
379 		   test->type == NPF_TEST_TYPE_SIZE_MAX) {
380 		struct npf_test_size_bounds *bounds =
381 			CONTAINER_OF(test, struct npf_test_size_bounds, test);
382 
383 		if (test->type == NPF_TEST_TYPE_SIZE_MIN ||
384 		    test->type == NPF_TEST_TYPE_SIZE_MAX) {
385 			snprintk(buf, len, "[%zu]",
386 				 test->type == NPF_TEST_TYPE_SIZE_MIN ?
387 				 bounds->min :  bounds->max);
388 		} else {
389 			snprintk(buf, len, "[%zu-%zu]", bounds->min, bounds->max);
390 		}
391 
392 	} else if (test->type == NPF_TEST_TYPE_IP_SRC_ADDR_ALLOWLIST ||
393 		   test->type == NPF_TEST_TYPE_IP_SRC_ADDR_BLOCKLIST) {
394 		struct npf_test_ip *test_ip =
395 			CONTAINER_OF(test, struct npf_test_ip, test);
396 		int pos = 1;
397 
398 		if (len < 2) {
399 			goto out;
400 		}
401 
402 		if (test_ip->ipaddr_num == 0) {
403 			snprintk(buf, len, "[]");
404 			goto out;
405 		}
406 
407 		buf[0] = '[';
408 
409 		for (uint32_t i = 0; i < test_ip->ipaddr_num; i++) {
410 			if (IS_ENABLED(CONFIG_NET_IPV4) &&
411 			    test_ip->addr_family == NET_AF_INET) {
412 				struct net_in_addr *addr =
413 					&((struct net_in_addr *)test_ip->ipaddr)[i];
414 
415 				pos += snprintk(buf + pos, len - pos,
416 						"%s%s", pos > 1 ? "," : "",
417 						net_sprint_ipv4_addr(addr));
418 
419 			} else if (IS_ENABLED(CONFIG_NET_IPV6) &&
420 				   test_ip->addr_family == NET_AF_INET6) {
421 				struct net_in6_addr *addr =
422 					&((struct net_in6_addr *)test_ip->ipaddr)[i];
423 
424 				pos += snprintk(buf + pos, len - pos,
425 						"%s%s", pos > 1 ? "," : "",
426 						net_sprint_ipv6_addr(addr));
427 			}
428 		}
429 
430 		if (pos >= len) {
431 			goto out;
432 		}
433 
434 		buf[pos] = ']';
435 
436 	} else if (test->type == NPF_TEST_TYPE_ETH_SRC_ADDR_MATCH ||
437 		   test->type == NPF_TEST_TYPE_ETH_SRC_ADDR_UNMATCH ||
438 		   test->type == NPF_TEST_TYPE_ETH_DST_ADDR_MATCH ||
439 		   test->type == NPF_TEST_TYPE_ETH_DST_ADDR_UNMATCH ||
440 		   test->type == NPF_TEST_TYPE_ETH_SRC_ADDR_MASK_MATCH ||
441 		   test->type == NPF_TEST_TYPE_ETH_DST_ADDR_MASK_MATCH) {
442 		struct npf_test_eth_addr *test_eth =
443 			CONTAINER_OF(test, struct npf_test_eth_addr, test);
444 		int pos = 1;
445 
446 		if (len < 2) {
447 			goto out;
448 		}
449 
450 		if (test_eth->nb_addresses == 0) {
451 			snprintk(buf, len, "[]");
452 			goto out;
453 		}
454 
455 		buf[0] = '[';
456 
457 		for (uint32_t i = 0; i < test_eth->nb_addresses; i++) {
458 			pos += snprintk(buf + pos, len - pos,
459 					"%s%s", pos > 1 ? "," : "",
460 					net_sprint_ll_addr(
461 						(const uint8_t *)(&test_eth->addresses[i]),
462 						NET_ETH_ADDR_LEN));
463 		}
464 
465 		if (pos >= len) {
466 			goto out;
467 		}
468 
469 		buf[pos] = ']';
470 
471 	} else if (test->type == NPF_TEST_TYPE_ETH_TYPE_MATCH ||
472 		   test->type == NPF_TEST_TYPE_ETH_TYPE_UNMATCH ||
473 		   test->type == NPF_TEST_TYPE_ETH_VLAN_TYPE_MATCH ||
474 		   test->type == NPF_TEST_TYPE_ETH_VLAN_TYPE_UNMATCH) {
475 		struct npf_test_eth_type *test_eth =
476 			CONTAINER_OF(test, struct npf_test_eth_type, test);
477 
478 		snprintk(buf, len, "[0x%04x]", net_ntohs(test_eth->type));
479 
480 	} else if (test->type == NPF_TEST_TYPE_LOCAL_IN_MATCH) {
481 		struct npf_test_local_in *test_local_in =
482 			CONTAINER_OF(test, struct npf_test_local_in, test);
483 
484 		snprintk(buf, len, "[fn=%p, data=%p]",
485 			 test_local_in->fn, test_local_in->user_data);
486 	}
487 
488 out:
489 	return test->name;
490 #else
491 	return "<UNKNOWN>";
492 #endif
493 }
494