1 /*
2 * Copyright (c) 2021 BayLibre SAS
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define NET_LOG_LEVEL CONFIG_NET_PKT_FILTER_LOG_LEVEL
8
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(npf_test, NET_LOG_LEVEL);
11
12 #include <zephyr/types.h>
13 #include <stdbool.h>
14 #include <stddef.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <zephyr/sys/printk.h>
18
19 #include "ipv4.h"
20 #include "ipv6.h"
21
22 #include <zephyr/ztest.h>
23
24 #include <zephyr/net/net_if.h>
25 #include <zephyr/net/ethernet.h>
26 #include <zephyr/net/net_pkt_filter.h>
27
28 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
29 #define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
30 #else
31 #define DBG(fmt, ...)
32 #endif
33
34 #define ETH_SRC_ADDR \
35 (struct net_eth_addr){ { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 } }
36 #define ETH_DST_ADDR \
37 (struct net_eth_addr){ { 0x00, 0x66, 0x77, 0x88, 0x99, 0xaa } }
38
39 static const char dummy_data[] =
40 "The Zephyr Project is a scalable real-time operating system (RTOS) supporting\n"
41 "multiple hardware architectures, optimized for resource constrained devices,\n"
42 "and built with security in mind.\n"
43 "\n"
44 "The Zephyr OS is based on a small-footprint kernel designed for use on\n"
45 "resource-constrained systems: from simple embedded environmental sensors and\n"
46 "LED wearables to sophisticated smart watches and IoT wireless gateways.\n"
47 "\n"
48 "The Zephyr kernel supports multiple architectures, including ARM Cortex-M,\n"
49 "Intel x86, ARC, Nios II, Tensilica Xtensa, and RISC-V, and a large number of\n"
50 "`supported boards`_.\n";
51
52
build_test_pkt(int type,int size,struct net_if * iface)53 static struct net_pkt *build_test_pkt(int type, int size, struct net_if *iface)
54 {
55 struct net_pkt *pkt;
56 struct net_eth_hdr eth_hdr;
57 int ret;
58
59 pkt = net_pkt_rx_alloc_with_buffer(iface, size, AF_UNSPEC, 0, K_NO_WAIT);
60 zassert_not_null(pkt, "");
61
62 eth_hdr.src = ETH_SRC_ADDR;
63 eth_hdr.dst = ETH_DST_ADDR;
64 eth_hdr.type = htons(type);
65
66 ret = net_pkt_write(pkt, ð_hdr, sizeof(eth_hdr));
67 zassert_equal(ret, 0, "");
68
69 zassert_true(size >= sizeof(eth_hdr), "");
70 zassert_true((size - sizeof(eth_hdr)) <= sizeof(dummy_data), "");
71 ret = net_pkt_write(pkt, dummy_data, size - sizeof(eth_hdr));
72 zassert_equal(ret, 0, "");
73
74 DBG("pkt %p: iface %p size %d type 0x%04x\n", pkt, iface, size, type);
75 return pkt;
76 }
77
build_test_ip_pkt(void * src,void * dst,sa_family_t family,struct net_if * iface)78 static struct net_pkt *build_test_ip_pkt(void *src, void *dst,
79 sa_family_t family, struct net_if *iface)
80 {
81 struct net_pkt *pkt;
82 int ret = -1;
83 int size;
84
85 size = (family == AF_INET) ? sizeof(struct net_ipv4_hdr) :
86 (family == AF_INET6) ? sizeof(struct net_ipv6_hdr) : 0U;
87
88 pkt = net_pkt_rx_alloc_with_buffer(iface, size, family, 0, K_NO_WAIT);
89 zassert_not_null(pkt, "");
90
91 if (family == AF_INET) {
92 ret = net_ipv4_create(pkt, (struct in_addr *)src, (struct in_addr *)dst);
93 } else if (family == AF_INET6) {
94 ret = net_ipv6_create(pkt, (struct in6_addr *)src, (struct in6_addr *)dst);
95 }
96 zassert_equal(ret, 0, "Cannot create %s packet (%d)",
97 (family == AF_INET) ? "IPv4" : "IPv6", ret);
98
99 DBG("pkt %p: iface %p size %d sa_family %d\n", pkt, iface, size, family);
100 return pkt;
101 }
102
103 /*
104 * Declare some fake interfaces and test their filter conditions.
105 */
106
107 ETH_NET_DEVICE_INIT(dummy_iface_a, "dummy_a", NULL, NULL,
108 NULL, NULL, CONFIG_ETH_INIT_PRIORITY,
109 NULL, NET_ETH_MTU);
110 ETH_NET_DEVICE_INIT(dummy_iface_b, "dummy_b", NULL, NULL,
111 NULL, NULL, CONFIG_ETH_INIT_PRIORITY,
112 NULL, NET_ETH_MTU);
113 #define dummy_iface_a NET_IF_GET_NAME(dummy_iface_a, 0)[0]
114 #define dummy_iface_b NET_IF_GET_NAME(dummy_iface_b, 0)[0]
115
116 static NPF_IFACE_MATCH(match_iface_a, &dummy_iface_a);
117 static NPF_IFACE_UNMATCH(unmatch_iface_b, &dummy_iface_b);
118
119 static NPF_RULE(accept_iface_a, NET_OK, match_iface_a);
120 static NPF_RULE(accept_all_but_iface_b, NET_OK, unmatch_iface_b);
121
test_npf_iface(void)122 static void *test_npf_iface(void)
123 {
124 struct net_pkt *pkt_iface_a, *pkt_iface_b;
125
126 pkt_iface_a = build_test_pkt(0, 200, &dummy_iface_a);
127 pkt_iface_b = build_test_pkt(0, 200, &dummy_iface_b);
128
129 /* test with no rules */
130 zassert_true(net_pkt_filter_recv_ok(pkt_iface_a), "");
131 zassert_true(net_pkt_filter_recv_ok(pkt_iface_b), "");
132
133 /* install rules */
134 npf_append_recv_rule(&accept_iface_a);
135 npf_append_recv_rule(&npf_default_drop);
136
137 /* test with rules in place */
138 zassert_true(net_pkt_filter_recv_ok(pkt_iface_a), "");
139 zassert_false(net_pkt_filter_recv_ok(pkt_iface_b), "");
140
141 /* remove first iface rule */
142 zassert_true(npf_remove_recv_rule(&accept_iface_a), "");
143
144 /* fails if removed a second time */
145 zassert_false(npf_remove_recv_rule(&accept_iface_a), "");
146
147 /* test with only default drop rule in place */
148 zassert_false(net_pkt_filter_recv_ok(pkt_iface_a), "");
149 zassert_false(net_pkt_filter_recv_ok(pkt_iface_b), "");
150
151 /* insert second iface rule */
152 npf_insert_recv_rule(&accept_all_but_iface_b);
153
154 /* test with new rule in place */
155 zassert_true(net_pkt_filter_recv_ok(pkt_iface_a), "");
156 zassert_false(net_pkt_filter_recv_ok(pkt_iface_b), "");
157
158 /* remove all rules */
159 zassert_true(npf_remove_recv_rule(&accept_all_but_iface_b), "");
160 zassert_true(npf_remove_recv_rule(&npf_default_drop), "");
161
162 /* should accept any packets again */
163 zassert_true(net_pkt_filter_recv_ok(pkt_iface_a), "");
164 zassert_true(net_pkt_filter_recv_ok(pkt_iface_b), "");
165
166 net_pkt_unref(pkt_iface_a);
167 net_pkt_unref(pkt_iface_b);
168
169 return NULL;
170 }
171
172 /*
173 * Example 1 in NPF_RULE() documentation.
174 */
175
176 static NPF_SIZE_MAX(maxsize_200, 200);
177 static NPF_ETH_TYPE_MATCH(ip_packet, NET_ETH_PTYPE_IP);
178
179 static NPF_RULE(small_ip_pkt, NET_OK, ip_packet, maxsize_200);
180
test_npf_example_common(void)181 static void test_npf_example_common(void)
182 {
183 struct net_pkt *pkt;
184
185 /* test small IP packet */
186 pkt = build_test_pkt(NET_ETH_PTYPE_IP, 100, NULL);
187 zassert_true(net_pkt_filter_recv_ok(pkt), "");
188 net_pkt_unref(pkt);
189
190 /* test "big" IP packet */
191 pkt = build_test_pkt(NET_ETH_PTYPE_IP, 300, NULL);
192 zassert_false(net_pkt_filter_recv_ok(pkt), "");
193 net_pkt_unref(pkt);
194
195 /* test "small" non-IP packet */
196 pkt = build_test_pkt(NET_ETH_PTYPE_ARP, 100, NULL);
197 zassert_false(net_pkt_filter_recv_ok(pkt), "");
198 net_pkt_unref(pkt);
199
200 /* test "big" non-IP packet */
201 pkt = build_test_pkt(NET_ETH_PTYPE_ARP, 300, NULL);
202 zassert_false(net_pkt_filter_recv_ok(pkt), "");
203 net_pkt_unref(pkt);
204 }
205
ZTEST(net_pkt_filter_test_suite,test_npf_example1)206 ZTEST(net_pkt_filter_test_suite, test_npf_example1)
207 {
208 /* install filter rules */
209 npf_insert_recv_rule(&npf_default_drop);
210 npf_insert_recv_rule(&small_ip_pkt);
211
212 test_npf_example_common();
213
214 /* remove filter rules */
215 zassert_true(npf_remove_recv_rule(&npf_default_drop), "");
216 zassert_true(npf_remove_recv_rule(&small_ip_pkt), "");
217 }
218
219 /*
220 * Example 2 in NPF_RULE() documentation.
221 */
222
223 static NPF_SIZE_MIN(minsize_201, 201);
224 static NPF_ETH_TYPE_UNMATCH(not_ip_packet, NET_ETH_PTYPE_IP);
225
226 static NPF_RULE(reject_big_pkts, NET_DROP, minsize_201);
227 static NPF_RULE(reject_non_ip, NET_DROP, not_ip_packet);
228
ZTEST(net_pkt_filter_test_suite,test_npf_example2)229 ZTEST(net_pkt_filter_test_suite, test_npf_example2)
230 {
231 /* install filter rules */
232 npf_append_recv_rule(&reject_big_pkts);
233 npf_append_recv_rule(&reject_non_ip);
234 npf_append_recv_rule(&npf_default_ok);
235
236 test_npf_example_common();
237
238 /* remove filter rules */
239 zassert_true(npf_remove_all_recv_rules(), "");
240 zassert_false(npf_remove_all_recv_rules(), "");
241 }
242
243 /*
244 * Ethernet MAC address filtering
245 */
246
247 static struct net_eth_addr mac_address_list[4] = {
248 { { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 } },
249 { { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 } },
250 { { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33 } },
251 { { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 } },
252 };
253
254 static NPF_ETH_SRC_ADDR_MATCH(matched_src_addr, mac_address_list);
255 static NPF_ETH_DST_ADDR_MATCH(matched_dst_addr, mac_address_list);
256 static NPF_ETH_SRC_ADDR_UNMATCH(unmatched_src_addr, mac_address_list);
257 static NPF_ETH_DST_ADDR_UNMATCH(unmatched_dst_addr, mac_address_list);
258
259 static NPF_RULE(accept_matched_src_addr, NET_OK, matched_src_addr);
260 static NPF_RULE(accept_unmatched_src_addr, NET_OK, unmatched_src_addr);
261 static NPF_RULE(accept_matched_dst_addr, NET_OK, matched_dst_addr);
262 static NPF_RULE(accept_unmatched_dst_addr, NET_OK, unmatched_dst_addr);
263
test_npf_eth_mac_address(void)264 static void test_npf_eth_mac_address(void)
265 {
266 struct net_pkt *pkt = build_test_pkt(NET_ETH_PTYPE_IP, 100, NULL);
267
268 /* make sure pkt is initially accepted */
269 zassert_true(net_pkt_filter_recv_ok(pkt), "");
270
271 /* let's test "OK" cases by making "drop" the default */
272 npf_append_recv_rule(&npf_default_drop);
273
274 /* validate missing src address */
275 npf_insert_recv_rule(&accept_unmatched_src_addr);
276 npf_insert_recv_rule(&accept_matched_src_addr);
277 zassert_true(net_pkt_filter_recv_ok(pkt), "");
278 zassert_true(npf_remove_recv_rule(&accept_unmatched_src_addr), "");
279 zassert_false(net_pkt_filter_recv_ok(pkt), "");
280
281 /* insert known src address in the lot */
282 mac_address_list[1] = ETH_SRC_ADDR;
283 zassert_true(net_pkt_filter_recv_ok(pkt), "");
284 npf_insert_recv_rule(&accept_unmatched_src_addr);
285 zassert_true(net_pkt_filter_recv_ok(pkt), "");
286 zassert_true(npf_remove_recv_rule(&accept_matched_src_addr), "");
287 zassert_false(net_pkt_filter_recv_ok(pkt), "");
288 zassert_true(npf_remove_recv_rule(&accept_unmatched_src_addr), "");
289
290 /* validate missing dst address */
291 npf_insert_recv_rule(&accept_unmatched_dst_addr);
292 npf_insert_recv_rule(&accept_matched_dst_addr);
293 zassert_true(net_pkt_filter_recv_ok(pkt), "");
294 zassert_true(npf_remove_recv_rule(&accept_unmatched_dst_addr), "");
295 zassert_false(net_pkt_filter_recv_ok(pkt), "");
296
297 /* insert known dst address in the lot */
298 mac_address_list[2] = ETH_DST_ADDR;
299 zassert_true(net_pkt_filter_recv_ok(pkt), "");
300 npf_insert_recv_rule(&accept_unmatched_dst_addr);
301 zassert_true(net_pkt_filter_recv_ok(pkt), "");
302 zassert_true(npf_remove_recv_rule(&accept_matched_dst_addr), "");
303 zassert_false(net_pkt_filter_recv_ok(pkt), "");
304 zassert_true(npf_remove_recv_rule(&accept_unmatched_dst_addr), "");
305
306 net_pkt_unref(pkt);
307 }
308
309 static NPF_ETH_SRC_ADDR_MASK_MATCH(matched_src_addr_mask, mac_address_list,
310 0xff, 0xff, 0xff, 0xff, 0xff, 0x00);
311 static NPF_RULE(accept_matched_src_addr_mask, NET_OK, matched_src_addr_mask);
312
test_npf_eth_mac_addr_mask(void)313 static void test_npf_eth_mac_addr_mask(void)
314 {
315 struct net_pkt *pkt = build_test_pkt(NET_ETH_PTYPE_IP, 100, NULL);
316
317 /* test standard match rule from previous test */
318 npf_insert_recv_rule(&npf_default_drop);
319 npf_insert_recv_rule(&accept_matched_src_addr);
320 zassert_true(net_pkt_filter_recv_ok(pkt), "");
321
322 /* clobber one nibble of matching address from previous test */
323 mac_address_list[1].addr[5] = 0x00;
324 zassert_false(net_pkt_filter_recv_ok(pkt), "");
325
326 /* insert masked address match rule */
327 npf_insert_recv_rule(&accept_matched_src_addr_mask);
328 zassert_true(net_pkt_filter_recv_ok(pkt), "");
329
330 /* cleanup */
331 zassert_true(npf_remove_all_recv_rules(), "");
332
333 net_pkt_unref(pkt);
334 }
335
ZTEST(net_pkt_filter_test_suite,test_npf_address_mask)336 ZTEST(net_pkt_filter_test_suite, test_npf_address_mask)
337 {
338 test_npf_eth_mac_address();
339 test_npf_eth_mac_addr_mask();
340 }
341
342 /*
343 * IP address filtering
344 */
345
346 static struct in_addr ipv4_address_list[4] = {
347 { { { 192, 168, 1, 1 } } },
348 { { { 192, 0, 2, 1 } } },
349 { { { 172, 16, 0, 1 } } },
350 { { { 10, 49, 0, 252 } } }
351 };
352
353 static struct in6_addr ipv6_address_list[4] = {
354 { { { 0x20, 0x01, 0x0d, 0xb8, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } },
355 { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } },
356 { { { 0x20, 0x01, 0x0d, 0xb8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } },
357 { { { 0x20, 0x01, 0x0d, 0xb8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } },
358 };
359
360 static NPF_IP_SRC_ADDR_ALLOWLIST(allowlist_ipv4_src_addr, (void *)ipv4_address_list,
361 ARRAY_SIZE(ipv4_address_list), AF_INET);
362 static NPF_IP_SRC_ADDR_BLOCKLIST(blocklist_ipv4_src_addr, (void *)ipv4_address_list,
363 ARRAY_SIZE(ipv4_address_list), AF_INET);
364
365 static NPF_RULE(ipv4_allowlist, NET_OK, allowlist_ipv4_src_addr);
366 static NPF_RULE(ipv4_blocklist, NET_OK, blocklist_ipv4_src_addr);
367
ZTEST(net_pkt_filter_test_suite,test_npf_ipv4_address_filtering)368 ZTEST(net_pkt_filter_test_suite, test_npf_ipv4_address_filtering)
369 {
370 struct in_addr dst = { { { 192, 168, 2, 1 } } };
371 struct in_addr bad_addr = { { { 192, 168, 2, 3 } } };
372 struct net_pkt *pkt_v4 = build_test_ip_pkt(&ipv4_address_list[0], &dst, AF_INET,
373 &dummy_iface_a);
374 struct net_pkt *pkt_v6 = build_test_ip_pkt(&ipv6_address_list[0], &ipv6_address_list[1],
375 AF_INET6, &dummy_iface_a);
376
377 /* make sure pkt is initially accepted */
378 zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), "");
379 zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), "");
380
381 /* validate allowlist */
382 npf_insert_ipv4_recv_rule(&ipv4_allowlist);
383
384 for (int it = 0; it < ARRAY_SIZE(ipv4_address_list); it++) {
385 memcpy((struct in_addr *)NET_IPV4_HDR(pkt_v4)->src, &ipv4_address_list[it],
386 sizeof(struct in_addr));
387 zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), "");
388 }
389
390 /* And one not listed */
391 memcpy((struct in_addr *)NET_IPV4_HDR(pkt_v4)->src,
392 &bad_addr, sizeof(struct in_addr));
393 zassert_false(net_pkt_filter_ip_recv_ok(pkt_v4), "");
394 zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), "");
395
396 /* Prepare new test */
397 zassert_true(npf_remove_all_ipv4_recv_rules(), "");
398
399 /* make sure pkt is initially accepted */
400 zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), "");
401 zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), "");
402
403 /* validate blocklist */
404 npf_insert_ipv4_recv_rule(&ipv4_blocklist);
405
406 for (int it = 0; it < ARRAY_SIZE(ipv4_address_list); it++) {
407 memcpy((struct in_addr *)NET_IPV4_HDR(pkt_v4)->src, &ipv4_address_list[it],
408 sizeof(struct in_addr));
409 zassert_false(net_pkt_filter_ip_recv_ok(pkt_v4), "");
410 }
411
412 /* And one not listed */
413 memcpy((struct in_addr *)NET_IPV4_HDR(pkt_v4)->src,
414 &bad_addr, sizeof(struct in_addr));
415 zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), "");
416
417 zassert_true(npf_remove_all_ipv4_recv_rules(), "");
418 net_pkt_unref(pkt_v6);
419 net_pkt_unref(pkt_v4);
420 }
421
422 static NPF_IP_SRC_ADDR_ALLOWLIST(allowlist_ipv6_src_addr, (void *)ipv6_address_list,
423 ARRAY_SIZE(ipv6_address_list), AF_INET6);
424 static NPF_IP_SRC_ADDR_BLOCKLIST(blocklist_ipv6_src_addr, (void *)ipv6_address_list,
425 ARRAY_SIZE(ipv6_address_list), AF_INET6);
426
427 static NPF_RULE(ipv6_allowlist, NET_OK, allowlist_ipv6_src_addr);
428 static NPF_RULE(ipv6_blocklist, NET_OK, blocklist_ipv6_src_addr);
429
ZTEST(net_pkt_filter_test_suite,test_npf_ipv6_address_filtering)430 ZTEST(net_pkt_filter_test_suite, test_npf_ipv6_address_filtering)
431 {
432 struct in6_addr dst = { { { 0xfe, 0x80, 0x43, 0xb8, 0, 0, 0, 0,
433 0, 0, 0, 0xf2, 0xaa, 0x29, 0x02, 0x04 } } };
434 struct in6_addr bad_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 8, 0, 0, 0,
435 0, 0, 0, 0, 0, 0, 0, 0x1 } } };
436 struct net_pkt *pkt_v6 = build_test_ip_pkt(&ipv6_address_list[0], &dst, AF_INET6,
437 &dummy_iface_a);
438 struct net_pkt *pkt_v4 = build_test_ip_pkt(&ipv4_address_list[0], &ipv4_address_list[1],
439 AF_INET, &dummy_iface_a);
440
441 /* make sure pkt is initially accepted */
442 zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), "");
443 zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), "");
444
445 /* validate allowlist */
446 npf_insert_ipv6_recv_rule(&ipv6_allowlist);
447
448 for (int it = 0; it < ARRAY_SIZE(ipv6_address_list); it++) {
449 memcpy((struct in6_addr *)NET_IPV6_HDR(pkt_v6)->src,
450 &ipv6_address_list[it], sizeof(struct in6_addr));
451 zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), "");
452 }
453
454 /* And one not listed */
455 memcpy((struct in6_addr *)NET_IPV6_HDR(pkt_v6)->src,
456 &bad_addr, sizeof(struct in6_addr));
457 zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), "");
458 zassert_false(net_pkt_filter_ip_recv_ok(pkt_v6), "");
459
460 /* Prepare new test */
461 zassert_true(npf_remove_all_ipv6_recv_rules(), "");
462
463 /* make sure pkt is initially accepted */
464 zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), "");
465 zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), "");
466
467 /* validate blocklist */
468 npf_insert_ipv6_recv_rule(&ipv6_blocklist);
469
470 for (int it = 0; it < ARRAY_SIZE(ipv6_address_list); it++) {
471 memcpy((struct in6_addr *)NET_IPV6_HDR(pkt_v6)->src,
472 &ipv6_address_list[it], sizeof(struct in6_addr));
473 zassert_false(net_pkt_filter_ip_recv_ok(pkt_v6), "");
474 }
475
476 /* And one not listed */
477 memcpy((struct in6_addr *)NET_IPV4_HDR(pkt_v6)->src,
478 &bad_addr, sizeof(struct in6_addr));
479 zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), "");
480
481 zassert_true(npf_remove_all_ipv6_recv_rules(), "");
482 net_pkt_unref(pkt_v6);
483 net_pkt_unref(pkt_v4);
484 }
485
486 ZTEST_SUITE(net_pkt_filter_test_suite, NULL, test_npf_iface, NULL, NULL, NULL);
487