npf_table_test.c revision 1.9.12.2 1 /* $NetBSD: npf_table_test.c,v 1.9.12.2 2019/01/26 22:00:39 pgoyette Exp $ */
2
3 /*
4 * NPF tableset tests.
5 *
6 * Public Domain.
7 */
8
9 #ifdef _KERNEL
10 #include <sys/types.h>
11 #include <sys/kmem.h>
12 #endif
13
14 #ifdef __linux__
15 #include <endian.h>
16 #else
17 #include <sys/endian.h>
18 #endif
19
20 #include "npf_impl.h"
21 #include "npf_test.h"
22
23 static const char *ip_list[] = {
24 "192.168.1.1",
25 "10.0.0.1",
26 "192.168.2.1",
27 "10.1.0.1",
28 "192.168.100.253",
29 "10.0.5.1",
30 "192.168.128.127",
31 "10.0.0.2",
32 };
33
34 static const uint8_t ip6_list[][16] = {
35 {
36 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37 0x02, 0xa0, 0xc0, 0xff, 0xfe, 0x10, 0x12, 0x34
38 },
39 {
40 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41 0x02, 0xa0, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x00,
42 },
43 {
44 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
46 },
47 {
48 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0x02, 0xa0, 0xc0, 0xff, 0xfe, 0x10, 0x12, 0x30
50 }
51 };
52
53 #define CHECK_TRUE(x) \
54 if (!(x)) { printf("FAIL: %s line %d\n", __func__, __LINE__); return 0; }
55
56 #define IPSET_TID 0
57 #define IPSET_NAME "ipset-table"
58
59 #define LPM_TID 1
60 #define LPM_NAME "lpm-table"
61
62 #define CDB_TID 2
63 #define CDB_NAME "cdb-table"
64
65 #define IFADDR_TID 3
66 #define IFADDR_NAME ".ifaddr-eth0"
67
68 ///////////////////////////////////////////////////////////////////////////
69
70 static bool
71 check_ip4(const npf_addr_t *addr, const char *ipstr)
72 {
73 npf_addr_t addr_storage, *test_addr = &addr_storage;
74 const int alen = sizeof(struct in_addr);
75 test_addr->word32[0] = inet_addr(ipstr);
76 return memcmp(addr, test_addr, alen) == 0;
77 }
78
79 static bool
80 ip4list_insert_lookup(npf_table_t *t, unsigned i)
81 {
82 npf_addr_t addr_storage, *addr = &addr_storage;
83 const int alen = sizeof(struct in_addr);
84 int error;
85
86 addr->word32[0] = inet_addr(ip_list[i]);
87 error = npf_table_insert(t, alen, addr, NPF_NO_NETMASK);
88 CHECK_TRUE(error == 0);
89 error = npf_table_lookup(t, alen, addr);
90 CHECK_TRUE(error == 0);
91 return true;
92 }
93
94 static bool
95 fill_with_ip4(npf_tableset_t *tblset)
96 {
97 npf_addr_t addr_storage, *addr = &addr_storage;
98 const int alen = sizeof(struct in_addr);
99 const int nm = NPF_NO_NETMASK;
100
101 for (unsigned i = 0; i < __arraycount(ip_list); i++) {
102 npf_table_t *t;
103 int error;
104
105 addr->word32[0] = inet_addr(ip_list[i]);
106
107 t = npf_tableset_getbyname(tblset, IPSET_NAME);
108 error = npf_table_insert(t, alen, addr, nm);
109 CHECK_TRUE(error == 0);
110 error = npf_table_insert(t, alen, addr, nm);
111 CHECK_TRUE(error != 0); // duplicate
112
113 t = npf_tableset_getbyname(tblset, LPM_NAME);
114 error = npf_table_insert(t, alen, addr, nm);
115 CHECK_TRUE(error == 0);
116 error = npf_table_insert(t, alen, addr, nm);
117 CHECK_TRUE(error != 0); // duplicate
118 }
119 return true;
120 }
121
122 static bool
123 verify_ip4(npf_tableset_t *tblset)
124 {
125 npf_addr_t addr_storage, *addr = &addr_storage;
126 const size_t alen = sizeof(struct in_addr);
127 const int nm = NPF_NO_NETMASK;
128 npf_table_t *t;
129 int error;
130
131 /* Attempt to add duplicates - should fail. */
132 addr->word32[0] = inet_addr(ip_list[0]);
133
134 t = npf_tableset_getbyname(tblset, IPSET_NAME);
135 error = npf_table_insert(t, alen, addr, nm);
136 CHECK_TRUE(error != 0);
137
138 t = npf_tableset_getbyname(tblset, LPM_NAME);
139 error = npf_table_insert(t, alen, addr, nm);
140 CHECK_TRUE(error != 0);
141
142 /* Match (validate) each IP entry. */
143 for (unsigned i = 0; i < __arraycount(ip_list); i++) {
144 addr->word32[0] = inet_addr(ip_list[i]);
145
146 t = npf_tableset_getbyname(tblset, IPSET_NAME);
147 error = npf_table_lookup(t, alen, addr);
148 CHECK_TRUE(error == 0);
149
150 t = npf_tableset_getbyname(tblset, LPM_NAME);
151 error = npf_table_lookup(t, alen, addr);
152 CHECK_TRUE(error == 0);
153 }
154 return true;
155 }
156
157 static bool
158 clear_ip4(npf_tableset_t *tblset)
159 {
160 npf_addr_t addr_storage, *addr = &addr_storage;
161 const int alen = sizeof(struct in_addr);
162 const int nm = NPF_NO_NETMASK;
163
164 for (unsigned i = 0; i < __arraycount(ip_list); i++) {
165 npf_table_t *t;
166 int error;
167
168 addr->word32[0] = inet_addr(ip_list[i]);
169
170 t = npf_tableset_getbyname(tblset, IPSET_NAME);
171 error = npf_table_remove(t, alen, addr, nm);
172 CHECK_TRUE(error == 0);
173
174 error = npf_table_remove(t, alen, addr, nm);
175 CHECK_TRUE(error != 0);
176
177 t = npf_tableset_getbyname(tblset, LPM_NAME);
178 error = npf_table_remove(t, alen, addr, nm);
179 CHECK_TRUE(error == 0);
180
181 error = npf_table_remove(t, alen, addr, nm);
182 CHECK_TRUE(error != 0);
183 }
184 return true;
185 }
186
187 ///////////////////////////////////////////////////////////////////////////
188
189 static bool
190 test_basic(npf_tableset_t *tblset)
191 {
192 npf_addr_t addr_storage, *addr = &addr_storage;
193 const int alen = sizeof(struct in_addr);
194 npf_table_t *t;
195 int error;
196
197 /* Basic IP set. */
198 t = npf_table_create(IPSET_NAME, IPSET_TID, NPF_TABLE_IPSET, NULL, 0);
199 CHECK_TRUE(t != NULL);
200 error = npf_tableset_insert(tblset, t);
201 CHECK_TRUE(error == 0);
202
203 /* Check for double-insert. */
204 error = npf_tableset_insert(tblset, t);
205 CHECK_TRUE(error != 0);
206
207 /* Longest-prefix match (LPM). */
208 t = npf_table_create(LPM_NAME, LPM_TID, NPF_TABLE_LPM, NULL, 0);
209 CHECK_TRUE(t != NULL);
210 error = npf_tableset_insert(tblset, t);
211 CHECK_TRUE(error == 0);
212
213 /* Table for interface addresses. */
214 t = npf_table_create(IFADDR_NAME, IFADDR_TID, NPF_TABLE_IFADDR, NULL, 0);
215 CHECK_TRUE(t != NULL);
216 error = npf_tableset_insert(tblset, t);
217 CHECK_TRUE(error == 0);
218
219 /*
220 * Attempt to match some non-existing entries - should fail.
221 */
222 addr->word32[0] = inet_addr(ip_list[0]);
223
224 t = npf_tableset_getbyname(tblset, IPSET_NAME);
225 error = npf_table_lookup(t, alen, addr);
226 CHECK_TRUE(error != 0);
227
228 t = npf_tableset_getbyname(tblset, LPM_NAME);
229 error = npf_table_lookup(t, alen, addr);
230 CHECK_TRUE(error != 0);
231
232 return true;
233 }
234
235 static bool
236 test_nocopy(npf_tableset_t *tblset)
237 {
238 const int alen = sizeof(struct in_addr);
239 const char *tables[] = { IPSET_NAME, LPM_NAME, IFADDR_NAME };
240 npf_addr_t *addr, lookup_addr;
241
242 for (unsigned i = 0; i < __arraycount(tables); i++) {
243 npf_table_t *t;
244 int error;
245
246 addr = kmem_zalloc(sizeof(npf_addr_t), KM_SLEEP);
247 assert(addr != NULL);
248 addr->word32[0] = inet_addr("172.16.90.10");
249
250 t = npf_tableset_getbyname(tblset, tables[i]);
251 (void)npf_table_flush(t);
252
253 error = npf_table_insert(t, alen, addr, NPF_NO_NETMASK);
254 CHECK_TRUE(error == 0);
255
256 memcpy(&lookup_addr, addr, alen);
257 memset(addr, 0xa5, alen); // explicit memset
258
259 error = npf_table_lookup(t, alen, &lookup_addr);
260 CHECK_TRUE(error == 0);
261
262 CHECK_TRUE(*(volatile unsigned char *)addr == 0xa5);
263 kmem_free(addr, sizeof(npf_addr_t));
264 }
265 return true;
266 }
267
268 static bool
269 test_ip6(npf_tableset_t *tblset)
270 {
271 npf_addr_t addr_storage, *addr = &addr_storage;
272 const size_t alen = sizeof(struct in6_addr);
273 const int nm = NPF_NO_NETMASK;
274 npf_table_t *t;
275 int error;
276
277 /* IPv6 addresses. */
278 memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
279
280 t = npf_tableset_getbyname(tblset, IPSET_NAME);
281 error = npf_table_insert(t, alen, addr, nm);
282 CHECK_TRUE(error == 0);
283 error = npf_table_lookup(t, alen, addr);
284 CHECK_TRUE(error == 0);
285 error = npf_table_remove(t, alen, addr, nm);
286 CHECK_TRUE(error == 0);
287
288 t = npf_tableset_getbyname(tblset, LPM_NAME);
289 error = npf_table_insert(t, alen, addr, nm);
290 CHECK_TRUE(error == 0);
291 error = npf_table_lookup(t, alen, addr);
292 CHECK_TRUE(error == 0);
293 error = npf_table_remove(t, alen, addr, nm);
294 CHECK_TRUE(error == 0);
295
296 return true;
297 }
298
299 static bool
300 test_lpm_masks4(npf_tableset_t *tblset)
301 {
302 npf_table_t *t = npf_tableset_getbyname(tblset, LPM_NAME);
303 npf_addr_t addr_storage, *addr = &addr_storage;
304 const size_t alen = sizeof(struct in_addr);
305 int error;
306
307 addr->word32[0] = inet_addr("172.16.90.0");
308 error = npf_table_insert(t, alen, addr, 25);
309 CHECK_TRUE(error == 0);
310
311 addr->word32[0] = inet_addr("172.16.90.126");
312 error = npf_table_lookup(t, alen, addr);
313 CHECK_TRUE(error == 0);
314
315 addr->word32[0] = inet_addr("172.16.90.128");
316 error = npf_table_lookup(t, alen, addr);
317 CHECK_TRUE(error != 0);
318
319 return true;
320 }
321
322 static bool
323 test_lpm_masks6(npf_tableset_t *tblset)
324 {
325 npf_table_t *t = npf_tableset_getbyname(tblset, LPM_NAME);
326 npf_addr_t addr_storage, *addr = &addr_storage;
327 const size_t alen = sizeof(struct in6_addr);
328 int error;
329
330 /*
331 * 96
332 */
333 memcpy(addr, ip6_list[1], sizeof(ip6_list[1]));
334 error = npf_table_insert(t, alen, addr, 96);
335 CHECK_TRUE(error == 0);
336
337 memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
338 error = npf_table_lookup(t, alen, addr);
339 CHECK_TRUE(error == 0);
340
341 memcpy(addr, ip6_list[1], sizeof(ip6_list[1]));
342 error = npf_table_remove(t, alen, addr, 96);
343 CHECK_TRUE(error == 0);
344
345 /*
346 * 32
347 */
348 memcpy(addr, ip6_list[2], sizeof(ip6_list[2]));
349 error = npf_table_insert(t, alen, addr, 32);
350 CHECK_TRUE(error == 0);
351
352 memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
353 error = npf_table_lookup(t, alen, addr);
354 CHECK_TRUE(error == 0);
355
356 memcpy(addr, ip6_list[2], sizeof(ip6_list[2]));
357 error = npf_table_remove(t, alen, addr, 32);
358 CHECK_TRUE(error == 0);
359
360 /*
361 * 126
362 */
363 memcpy(addr, ip6_list[3], sizeof(ip6_list[3]));
364 error = npf_table_insert(t, alen, addr, 126);
365 CHECK_TRUE(error == 0);
366
367 memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
368 error = npf_table_lookup(t, alen, addr);
369 CHECK_TRUE(error != 0);
370
371 memcpy(addr, ip6_list[3], sizeof(ip6_list[3]));
372 error = npf_table_remove(t, alen, addr, 126);
373 CHECK_TRUE(error == 0);
374
375 return true;
376 }
377
378 static bool
379 test_const_table(npf_tableset_t *tblset, void *blob, size_t size)
380 {
381 npf_addr_t addr_storage, *addr = &addr_storage;
382 const int alen = sizeof(struct in_addr);
383 npf_table_t *t;
384 int error;
385
386 t = npf_table_create(CDB_NAME, CDB_TID, NPF_TABLE_CONST, blob, size);
387 CHECK_TRUE(t != NULL);
388
389 error = npf_tableset_insert(tblset, t);
390 CHECK_TRUE(error == 0);
391
392 addr->word32[0] = inet_addr(ip_list[0]);
393 error = npf_table_lookup(t, alen, addr);
394 CHECK_TRUE(error == 0);
395
396 for (unsigned i = 1; i < __arraycount(ip_list) - 1; i++) {
397 addr->word32[0] = inet_addr(ip_list[i]);
398 error = npf_table_lookup(t, alen, addr);
399 CHECK_TRUE(error != 0);
400 }
401 return true;
402 }
403
404 static bool
405 test_ifaddr_table(npf_tableset_t *tblset)
406 {
407 npf_addr_t addr_storage, *addr = &addr_storage;
408 npf_table_t *t = npf_tableset_getbyname(tblset, IFADDR_NAME);
409 int error;
410 bool ok;
411
412 /* Two IPv4 addresses. */
413 ok = ip4list_insert_lookup(t, 0);
414 CHECK_TRUE(ok);
415
416 ok = ip4list_insert_lookup(t, 1);
417 CHECK_TRUE(ok);
418
419 /* And one IPv6 address. */
420 memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
421 error = npf_table_insert(t, sizeof(struct in6_addr), addr, NPF_NO_NETMASK);
422 CHECK_TRUE(error == 0);
423
424 /*
425 * Get IPv4 addresses.
426 */
427 addr = npf_table_getsome(t, sizeof(struct in_addr), 0);
428 ok = check_ip4(addr, "192.168.1.1");
429 CHECK_TRUE(ok);
430
431 addr = npf_table_getsome(t, sizeof(struct in_addr), 1);
432 ok = check_ip4(addr, "10.0.0.1");
433 CHECK_TRUE(ok);
434
435 addr = npf_table_getsome(t, sizeof(struct in_addr), 2);
436 ok = check_ip4(addr, "192.168.1.1");
437 CHECK_TRUE(ok);
438
439 return true;
440 }
441
442 static void
443 test_ipset_gc(npf_tableset_t *tblset)
444 {
445 npf_table_t *t = npf_tableset_getbyname(tblset, IPSET_NAME);
446 npf_t *npf = npf_getkernctx();
447
448 npf_config_enter(npf);
449 npf_table_gc(npf, t);
450 npf_table_flush(t);
451 npf_config_exit(npf);
452 }
453
454 bool
455 npf_table_test(bool verbose, void *blob, size_t size)
456 {
457 npf_tableset_t *tblset;
458 bool ok;
459
460 (void)verbose;
461
462 tblset = npf_tableset_create(4);
463 CHECK_TRUE(tblset != NULL);
464
465 ok = test_basic(tblset);
466 CHECK_TRUE(ok);
467
468 /*
469 * Fill IPSET and LPM tables with IPv4 addresses.
470 * Keep them in the table during the other tests.
471 */
472 ok = fill_with_ip4(tblset);
473 CHECK_TRUE(ok);
474
475 ok = verify_ip4(tblset);
476 CHECK_TRUE(ok);
477
478 ok = test_ip6(tblset);
479 CHECK_TRUE(ok);
480
481 ok = test_lpm_masks4(tblset);
482 CHECK_TRUE(ok);
483
484 ok = test_lpm_masks6(tblset);
485 CHECK_TRUE(ok);
486
487 ok = test_const_table(tblset, blob, size);
488 CHECK_TRUE(ok);
489
490 ok = test_ifaddr_table(tblset);
491 CHECK_TRUE(ok);
492
493 /*
494 * Remove the above IPv4 addresses -- they must have been untouched.
495 */
496 ok = clear_ip4(tblset);
497 CHECK_TRUE(ok);
498
499 ok = test_nocopy(tblset);
500 CHECK_TRUE(ok);
501
502 test_ipset_gc(tblset);
503
504 npf_tableset_destroy(tblset);
505 return true;
506 }
507