xref: /dflybsd-src/sys/net/wg/selftest/cookie.c (revision 9de0ba69cde8d11c54ac2307558fb628a3df7df9)
1 /* SPDX-License-Identifier: MIT
2  *
3  * Copyright (C) 2015-2021 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
4  * Copyright (C) 2019-2021 Matt Dunwoodie <ncon@noconroy.net>
5  */
6 
7 #define MESSAGE_LEN 64
8 #define T_FAILED_ITER(test) do {				\
9 	kprintf("%s %s: FAIL, iter: %d\n", __func__, test, i);	\
10 	goto cleanup;						\
11 } while (0)
12 #define T_FAILED(test) do {				\
13 	kprintf("%s %s: FAIL\n", __func__, test);	\
14 	goto cleanup;					\
15 } while (0)
16 #define T_PASSED kprintf("%s: pass\n", __func__)
17 
18 static const struct expected_results {
19 	int		result;
20 	uint64_t	sleep_time; /* nanoseconds */
21 } rl_expected[] = {
22 	[0 ... INITIATIONS_BURSTABLE - 1] = { 0, 0 },
23 	[INITIATIONS_BURSTABLE] = { ECONNREFUSED, 0 },
24 	[INITIATIONS_BURSTABLE + 1] = { 0, INITIATION_COST },
25 	[INITIATIONS_BURSTABLE + 2] = { ECONNREFUSED, 0 },
26 	[INITIATIONS_BURSTABLE + 3] = { 0, INITIATION_COST * 2 },
27 	[INITIATIONS_BURSTABLE + 4] = { 0, 0 },
28 	[INITIATIONS_BURSTABLE + 5] = { ECONNREFUSED, 0 }
29 };
30 
31 static struct ratelimit rl;
32 
33 static bool
34 cookie_ratelimit_timings_test(void)
35 {
36 	bool ret = false;
37 	struct sockaddr_in sin;
38 #ifdef INET6
39 	struct sockaddr_in6 sin6;
40 #endif
41 	uint64_t t;
42 	int i;
43 
44 	bzero(&rl, sizeof(rl));
45 	ratelimit_init(&rl);
46 
47 	sin.sin_family = AF_INET;
48 #ifdef INET6
49 	sin6.sin6_family = AF_INET6;
50 #endif
51 
52 	for (i = 0; i < sizeof(rl_expected)/sizeof(*rl_expected); i++) {
53 		if ((t = rl_expected[i].sleep_time) != 0)
54 			tsleep(&rl, 0, "rl", (int)(t * hz / NSEC_PER_SEC));
55 
56 		/* The first v4 ratelimit_allow is against a constant address,
57 		 * and should be indifferent to the port. */
58 		sin.sin_addr.s_addr = 0x01020304;
59 		sin.sin_port = karc4random();
60 
61 		if (ratelimit_allow(&rl, sintosa(&sin)) != rl_expected[i].result)
62 			T_FAILED_ITER("malicious v4");
63 
64 		/* The second ratelimit_allow is to test that an arbitrary
65 		 * address is still allowed. */
66 		sin.sin_addr.s_addr += i + 1;
67 		sin.sin_port = karc4random();
68 
69 		if (ratelimit_allow(&rl, sintosa(&sin)) != 0)
70 			T_FAILED_ITER("non-malicious v4");
71 
72 #ifdef INET6
73 		/* The first v6 ratelimit_allow is against a constant address,
74 		 * and should be indifferent to the port. We also mutate the
75 		 * lower 64 bits of the address as we want to ensure ratelimit
76 		 * occurs against the higher 64 bits (/64 network). */
77 		sin6.sin6_addr.s6_addr32[0] = 0x01020304;
78 		sin6.sin6_addr.s6_addr32[1] = 0x05060708;
79 		sin6.sin6_addr.s6_addr32[2] = i;
80 		sin6.sin6_addr.s6_addr32[3] = i;
81 		sin6.sin6_port = karc4random();
82 
83 		if (ratelimit_allow(&rl, sin6tosa(&sin6)) != rl_expected[i].result)
84 			T_FAILED_ITER("malicious v6");
85 
86 		/* Again, test that an address different to above is still
87 		 * allowed. */
88 		sin6.sin6_addr.s6_addr32[0] += i + 1;
89 		sin6.sin6_port = karc4random();
90 
91 		if (ratelimit_allow(&rl, sintosa(&sin)) != 0)
92 			T_FAILED_ITER("non-malicious v6");
93 #endif
94 	}
95 	T_PASSED;
96 	ret = true;
97 cleanup:
98 	ratelimit_deinit(&rl);
99 	return ret;
100 }
101 
102 static bool
103 cookie_ratelimit_capacity_test(void)
104 {
105 	struct sockaddr_in sin;
106 	int i;
107 	bool ret = false;
108 
109 	bzero(&rl, sizeof(rl));
110 	ratelimit_init(&rl);
111 
112 	sin.sin_family = AF_INET;
113 	sin.sin_port = 1234;
114 
115 	/* Here we test that the ratelimiter has an upper bound on the number
116 	 * of addresses to be limited */
117 	for (i = 0; i <= RATELIMIT_SIZE_MAX; i++) {
118 		sin.sin_addr.s_addr = i;
119 		if (i == RATELIMIT_SIZE_MAX) {
120 			if (ratelimit_allow(&rl, sintosa(&sin)) != ECONNREFUSED)
121 				T_FAILED_ITER("reject");
122 		} else {
123 			if (ratelimit_allow(&rl, sintosa(&sin)) != 0)
124 				T_FAILED_ITER("allow");
125 		}
126 	}
127 	T_PASSED;
128 	ret = true;
129 cleanup:
130 	ratelimit_deinit(&rl);
131 	return ret;
132 }
133 
134 static bool
135 cookie_ratelimit_gc_test(void)
136 {
137 	struct sockaddr_in sin;
138 	int i;
139 	bool ret = false;
140 
141 	bzero(&rl, sizeof(rl));
142 	ratelimit_init(&rl);
143 
144 	sin.sin_family = AF_INET;
145 	sin.sin_port = 1234;
146 
147 	/* Here we test that the garbage collect routine will run */
148 	if (rl.rl_table_num != 0)
149 		T_FAILED("init not empty");
150 
151 	for (i = 0; i < RATELIMIT_SIZE_MAX / 2; i++) {
152 		sin.sin_addr.s_addr = i;
153 		if (ratelimit_allow(&rl, sintosa(&sin)) != 0)
154 			T_FAILED_ITER("insert");
155 	}
156 
157 	if (rl.rl_table_num != RATELIMIT_SIZE_MAX / 2)
158 		T_FAILED("insert 1 not full");
159 
160 	tsleep(&rl, 0, "rl", ELEMENT_TIMEOUT * hz / 2);
161 
162 	for (i = 0; i < RATELIMIT_SIZE_MAX / 2; i++) {
163 		sin.sin_addr.s_addr = i;
164 		if (ratelimit_allow(&rl, sintosa(&sin)) != 0)
165 			T_FAILED_ITER("insert");
166 	}
167 
168 	if (rl.rl_table_num != RATELIMIT_SIZE_MAX / 2)
169 		T_FAILED("insert 2 not full");
170 
171 	tsleep(&rl, 0, "rl", ELEMENT_TIMEOUT * hz * 2);
172 
173 	if (rl.rl_table_num != 0)
174 		T_FAILED("gc");
175 	T_PASSED;
176 	ret = true;
177 cleanup:
178 	ratelimit_deinit(&rl);
179 	return ret;
180 }
181 
182 static bool
183 cookie_mac_test(void)
184 {
185 	struct cookie_checker checker;
186 	struct cookie_maker maker;
187 	struct cookie_macs cm;
188 	struct sockaddr_in sin;
189 	int res, i;
190 	bool ret = false;
191 
192 	uint8_t	nonce[COOKIE_NONCE_SIZE];
193 	uint8_t	cookie[COOKIE_ENCRYPTED_SIZE];
194 	uint8_t	shared[COOKIE_INPUT_SIZE];
195 	uint8_t message[MESSAGE_LEN];
196 
197 	karc4random_buf(shared, COOKIE_INPUT_SIZE);
198 	karc4random_buf(message, MESSAGE_LEN);
199 
200 	/* Init cookie_maker. */
201 	cookie_maker_init(&maker, shared);
202 
203 	cookie_checker_init(&checker);
204 	cookie_checker_update(&checker, shared);
205 
206 	/* Create dummy sockaddr */
207 	sin.sin_family = AF_INET;
208 	sin.sin_len = sizeof(sin);
209 	sin.sin_addr.s_addr = 1;
210 	sin.sin_port = 51820;
211 
212 	/* MAC message */
213 	cookie_maker_mac(&maker, &cm, message, MESSAGE_LEN);
214 
215 	/* Check we have a null mac2 */
216 	for (i = 0; i < sizeof(cm.mac2); i++)
217 		if (cm.mac2[i] != 0)
218 			T_FAILED("validate_macs_noload_mac2_zeroed");
219 
220 	/* Validate all bytes are checked in mac1 */
221 	for (i = 0; i < sizeof(cm.mac1); i++) {
222 		cm.mac1[i] = ~cm.mac1[i];
223 		if (cookie_checker_validate_macs(&checker, &cm, message,
224 		    MESSAGE_LEN, 0, sintosa(&sin)) != EINVAL)
225 			T_FAILED("validate_macs_noload_munge");
226 		cm.mac1[i] = ~cm.mac1[i];
227 	}
228 
229 	/* Check mac2 is zeroed */
230 	res = 0;
231 	for (i = 0; i < sizeof(cm.mac2); i++)
232 		res |= cm.mac2[i];
233 	if (res != 0)
234 		T_FAILED("validate_macs_mac2_checkzero");
235 
236 
237 	/* Check we can successfully validate the MAC */
238 	if (cookie_checker_validate_macs(&checker, &cm, message,
239 	    MESSAGE_LEN, 0, sintosa(&sin)) != 0)
240 		T_FAILED("validate_macs_noload_normal");
241 
242 	/* Check we get a EAGAIN if no mac2 and under load */
243 	if (cookie_checker_validate_macs(&checker, &cm, message,
244 	    MESSAGE_LEN, 1, sintosa(&sin)) != EAGAIN)
245 		T_FAILED("validate_macs_load_normal");
246 
247 	/* Simulate a cookie message */
248 	cookie_checker_create_payload(&checker, &cm, nonce, cookie, sintosa(&sin));
249 
250 	/* Validate all bytes are checked in cookie */
251 	for (i = 0; i < sizeof(cookie); i++) {
252 		cookie[i] = ~cookie[i];
253 		if (cookie_maker_consume_payload(&maker, nonce, cookie) != EINVAL)
254 			T_FAILED("consume_payload_munge");
255 		cookie[i] = ~cookie[i];
256 	}
257 
258 	/* Check we can actually consume the payload */
259 	if (cookie_maker_consume_payload(&maker, nonce, cookie) != 0)
260 		T_FAILED("consume_payload_normal");
261 
262 	/* Check replay isn't allowed */
263 	if (cookie_maker_consume_payload(&maker, nonce, cookie) != ETIMEDOUT)
264 		T_FAILED("consume_payload_normal_replay");
265 
266 	/* MAC message again, with MAC2 */
267 	cookie_maker_mac(&maker, &cm, message, MESSAGE_LEN);
268 
269 	/* Check we added a mac2 */
270 	res = 0;
271 	for (i = 0; i < sizeof(cm.mac2); i++)
272 		res |= cm.mac2[i];
273 	if (res == 0)
274 		T_FAILED("validate_macs_make_mac2");
275 
276 	/* Check we get OK if mac2 and under load */
277 	if (cookie_checker_validate_macs(&checker, &cm, message,
278 	    MESSAGE_LEN, 1, sintosa(&sin)) != 0)
279 		T_FAILED("validate_macs_load_normal_mac2");
280 
281 	sin.sin_addr.s_addr = ~sin.sin_addr.s_addr;
282 	/* Check we get EAGAIN if we munge the source IP */
283 	if (cookie_checker_validate_macs(&checker, &cm, message,
284 	    MESSAGE_LEN, 1, sintosa(&sin)) != EAGAIN)
285 		T_FAILED("validate_macs_load_spoofip_mac2");
286 	sin.sin_addr.s_addr = ~sin.sin_addr.s_addr;
287 
288 	/* Check we get OK if mac2 and under load */
289 	if (cookie_checker_validate_macs(&checker, &cm, message,
290 	    MESSAGE_LEN, 1, sintosa(&sin)) != 0)
291 		T_FAILED("validate_macs_load_normal_mac2_retry");
292 
293 	T_PASSED;
294 	ret = true;
295 cleanup:
296 	cookie_checker_free(&checker);
297 	cookie_maker_free(&maker);
298 	return ret;
299 }
300 
301 bool
302 cookie_selftest(void)
303 {
304 	bool ret = true;
305 	ret &= cookie_ratelimit_timings_test();
306 	ret &= cookie_ratelimit_capacity_test();
307 	ret &= cookie_ratelimit_gc_test();
308 	ret &= cookie_mac_test();
309 	return ret;
310 }
311