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