xref: /netbsd-src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: npf_table_test.c,v 1.9 2016/12/26 23:05:05 christos Exp $	*/
2 
3 /*
4  * NPF tableset test.
5  *
6  * Public Domain.
7  */
8 
9 #ifdef _KERNEL
10 #include <sys/types.h>
11 #include <sys/malloc.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 #if __BYTE_ORDER == __LITTLE_ENDIAN
35 #define	U16_TO_LE(x)	((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
36 #else
37 #define	U16_TO_LE(x)	(x)
38 #endif
39 
40 static const uint16_t ip6_list[][8] = {
41 	{
42 	    U16_TO_LE(0xfe80), 0x0, 0x0, 0x0,
43 	    U16_TO_LE(0x2a0), U16_TO_LE(0xc0ff),
44 	    U16_TO_LE(0xfe10), U16_TO_LE(0x1234)
45 	},
46 	{
47 	    U16_TO_LE(0xfe80), 0x0, 0x0, 0x0,
48 	    U16_TO_LE(0x2a0), U16_TO_LE(0xc0ff), 0x00, 0x0
49 	},
50 	{
51 	    U16_TO_LE(0xfe80), 0x0, 0x0, 0x0,
52 	    0x0, 0x0, 0x0, 0x0
53 	},
54 	{
55 	    U16_TO_LE(0xfe80), 0x0, 0x0, 0x0,
56 	    U16_TO_LE(0x2a0), U16_TO_LE(0xc0ff),
57 	    U16_TO_LE(0xfe10), U16_TO_LE(0x1230)
58 	}
59 };
60 
61 #define	check_ok(x)	\
62     ((x) ? true : (printf("fail at line %d\n", __LINE__), false))
63 
64 #define	HASH_TID		"hash-table"
65 #define	TREE_TID		"tree-table"
66 #define	CDB_TID			"cdb-table"
67 
68 static bool
69 npf_table_test_fill4(npf_tableset_t *tblset, npf_addr_t *addr)
70 {
71 	const int alen = sizeof(struct in_addr);
72 	const int nm = NPF_NO_NETMASK;
73 	bool fail = false;
74 
75 	/* Fill both tables with IP addresses. */
76 	for (unsigned i = 0; i < __arraycount(ip_list); i++) {
77 		npf_table_t *t;
78 		int error;
79 
80 		addr->word32[0] = inet_addr(ip_list[i]);
81 
82 		t = npf_tableset_getbyname(tblset, HASH_TID);
83 		error = npf_table_insert(t, alen, addr, nm);
84 		fail |= !check_ok(error == 0);
85 		error = npf_table_insert(t, alen, addr, nm);
86 		fail |= !check_ok(error != 0);
87 
88 		t = npf_tableset_getbyname(tblset, TREE_TID);
89 		error = npf_table_insert(t, alen, addr, nm);
90 		fail |= !check_ok(error == 0);
91 		error = npf_table_insert(t, alen, addr, nm);
92 		fail |= !check_ok(error != 0);
93 	}
94 	return fail;
95 }
96 
97 bool
98 npf_table_test(bool verbose, void *blob, size_t size)
99 {
100 	npf_addr_t addr_storage, *addr = &addr_storage;
101 	const int nm = NPF_NO_NETMASK;
102 	npf_table_t *t, *t1, *t2, *t3;
103 	npf_tableset_t *tblset;
104 	int error, alen;
105 	bool fail = false;
106 	void *cdb;
107 	u_int i;
108 
109 	tblset = npf_tableset_create(3);
110 	fail |= !check_ok(tblset != NULL);
111 
112 	/* Table ID 1, using hash table with 256 lists. */
113 	t1 = npf_table_create(HASH_TID, 0, NPF_TABLE_HASH, NULL, 256);
114 	fail |= !check_ok(t1 != NULL);
115 	error = npf_tableset_insert(tblset, t1);
116 	fail |= !check_ok(error == 0);
117 
118 	/* Check for double-insert. */
119 	error = npf_tableset_insert(tblset, t1);
120 	fail |= !check_ok(error != 0);
121 
122 	/* Table ID 2, using a prefix tree. */
123 	t2 = npf_table_create(TREE_TID, 1, NPF_TABLE_TREE, NULL, 0);
124 	fail |= !(t2 != NULL);
125 	error = npf_tableset_insert(tblset, t2);
126 	fail |= !check_ok(error == 0);
127 
128 	/* Table ID 3, using a CDB. */
129 	cdb = malloc(size, M_TEMP, M_WAITOK);
130 	memcpy(cdb, blob, size);
131 
132 	t3 = npf_table_create(CDB_TID, 2, NPF_TABLE_CDB, cdb, size);
133 	fail |= !(t3 != NULL);
134 	error = npf_tableset_insert(tblset, t3);
135 	fail |= !check_ok(error == 0);
136 
137 	/* Attempt to match non-existing entries - should fail. */
138 	addr->word32[0] = inet_addr(ip_list[0]);
139 	alen = sizeof(struct in_addr);
140 
141 	t = npf_tableset_getbyname(tblset, HASH_TID);
142 	error = npf_table_lookup(t, alen, addr);
143 	fail |= !check_ok(error != 0);
144 
145 	t = npf_tableset_getbyname(tblset, TREE_TID);
146 	error = npf_table_lookup(t, alen, addr);
147 	fail |= !check_ok(error != 0);
148 
149 	/* Fill both tables with IP addresses. */
150 	fail |= npf_table_test_fill4(tblset, addr);
151 
152 	/* Attempt to add duplicates - should fail. */
153 	addr->word32[0] = inet_addr(ip_list[0]);
154 	alen = sizeof(struct in_addr);
155 
156 	t = npf_tableset_getbyname(tblset, HASH_TID);
157 	error = npf_table_insert(t, alen, addr, nm);
158 	fail |= !check_ok(error != 0);
159 
160 	t = npf_tableset_getbyname(tblset, TREE_TID);
161 	error = npf_table_insert(t, alen, addr, nm);
162 	fail |= !check_ok(error != 0);
163 
164 	/* Match (validate) each IP entry. */
165 	for (i = 0; i < __arraycount(ip_list); i++) {
166 		addr->word32[0] = inet_addr(ip_list[i]);
167 
168 		t = npf_tableset_getbyname(tblset, HASH_TID);
169 		error = npf_table_lookup(t, alen, addr);
170 		fail |= !check_ok(error == 0);
171 
172 		t = npf_tableset_getbyname(tblset, TREE_TID);
173 		error = npf_table_lookup(t, alen, addr);
174 		fail |= !check_ok(error == 0);
175 	}
176 
177 	/* IPv6 addresses. */
178 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
179 	alen = sizeof(struct in6_addr);
180 
181 	t = npf_tableset_getbyname(tblset, HASH_TID);
182 	error = npf_table_insert(t, alen, addr, nm);
183 	fail |= !check_ok(error == 0);
184 	error = npf_table_lookup(t, alen, addr);
185 	fail |= !check_ok(error == 0);
186 	error = npf_table_remove(t, alen, addr, nm);
187 	fail |= !check_ok(error == 0);
188 
189 	t = npf_tableset_getbyname(tblset, TREE_TID);
190 	error = npf_table_insert(t, alen, addr, nm);
191 	fail |= !check_ok(error == 0);
192 	error = npf_table_lookup(t, alen, addr);
193 	fail |= !check_ok(error == 0);
194 	error = npf_table_remove(t, alen, addr, nm);
195 	fail |= !check_ok(error == 0);
196 
197 	/*
198 	 * Masking: 96, 32, 127.
199 	 */
200 
201 	memcpy(addr, ip6_list[1], sizeof(ip6_list[1]));
202 	error = npf_table_insert(t, alen, addr, 96);
203 	fail |= !check_ok(error == 0);
204 
205 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
206 	error = npf_table_lookup(t, alen, addr);
207 	fail |= !check_ok(error == 0);
208 
209 	memcpy(addr, ip6_list[1], sizeof(ip6_list[1]));
210 	error = npf_table_remove(t, alen, addr, 96);
211 	fail |= !check_ok(error == 0);
212 
213 
214 	memcpy(addr, ip6_list[2], sizeof(ip6_list[2]));
215 	error = npf_table_insert(t, alen, addr, 32);
216 	fail |= !check_ok(error == 0);
217 
218 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
219 	error = npf_table_lookup(t, alen, addr);
220 	fail |= !check_ok(error == 0);
221 
222 	memcpy(addr, ip6_list[2], sizeof(ip6_list[2]));
223 	error = npf_table_remove(t, alen, addr, 32);
224 	fail |= !check_ok(error == 0);
225 
226 
227 	memcpy(addr, ip6_list[3], sizeof(ip6_list[3]));
228 	error = npf_table_insert(t, alen, addr, 126);
229 	fail |= !check_ok(error == 0);
230 
231 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
232 	error = npf_table_lookup(t, alen, addr);
233 	fail |= !check_ok(error != 0);
234 
235 	memcpy(addr, ip6_list[3], sizeof(ip6_list[3]));
236 	error = npf_table_remove(t, alen, addr, 126);
237 	fail |= !check_ok(error == 0);
238 
239 
240 	alen = sizeof(struct in_addr);
241 
242 	/* Remove all IPv4 entries. */
243 	for (i = 0; i < __arraycount(ip_list); i++) {
244 		addr->word32[0] = inet_addr(ip_list[i]);
245 
246 		t = npf_tableset_getbyname(tblset, HASH_TID);
247 		error = npf_table_remove(t, alen, addr, nm);
248 		fail |= !check_ok(error == 0);
249 
250 		t = npf_tableset_getbyname(tblset, TREE_TID);
251 		error = npf_table_remove(t, alen, addr, nm);
252 		fail |= !check_ok(error == 0);
253 	}
254 
255 	/* Test CDB. */
256 	addr->word32[0] = inet_addr(ip_list[0]);
257 	alen = sizeof(struct in_addr);
258 	error = npf_table_lookup(t3, alen, addr);
259 	fail |= !check_ok(error == 0);
260 
261 	for (i = 1; i < __arraycount(ip_list) - 1; i++) {
262 		addr->word32[0] = inet_addr(ip_list[i]);
263 		alen = sizeof(struct in_addr);
264 		error = npf_table_lookup(t3, alen, addr);
265 		fail |= !check_ok(error != 0);
266 	}
267 
268 	npf_tableset_destroy(tblset);
269 
270 	return !fail;
271 }
272