xref: /dragonfly/sys/net/wg/selftest/cookie.c (revision 7485684f)
1 /*-
2  * SPDX-License-Identifier: MIT
3  *
4  * Copyright (C) 2015-2021 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
5  * Copyright (C) 2019-2021 Matt Dunwoodie <ncon@noconroy.net>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject
13  * to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  */
26 
27 #define T_MESSAGE_LEN 64
28 #define T_FAILED_ITER(test) do {				\
29 	kprintf("%s %s: FAIL, iter: %d\n", __func__, test, i);	\
30 	goto cleanup;						\
31 } while (0)
32 #define T_FAILED(test) do {				\
33 	kprintf("%s %s: FAIL\n", __func__, test);	\
34 	goto cleanup;					\
35 } while (0)
36 #define T_PASSED kprintf("%s: pass\n", __func__)
37 
38 static const struct expected_results {
39 	int		result;
40 	uint64_t	sleep_time; /* nanoseconds */
41 } rl_expected[] = {
42 	/* [0 ... INITIATIONS_BURSTABLE-1] entries are implied zero. */
43 	[INITIATIONS_BURSTABLE] = { ECONNREFUSED, 0 },
44 	[INITIATIONS_BURSTABLE + 1] = { 0, INITIATION_COST },
45 	[INITIATIONS_BURSTABLE + 2] = { ECONNREFUSED, 0 },
46 	[INITIATIONS_BURSTABLE + 3] = { 0, INITIATION_COST * 2 },
47 	[INITIATIONS_BURSTABLE + 4] = { 0, 0 },
48 	[INITIATIONS_BURSTABLE + 5] = { ECONNREFUSED, 0 },
49 };
50 
51 static struct ratelimit rl_test;
52 
53 static bool
54 cookie_ratelimit_timings_test(void)
55 {
56 	struct sockaddr_in sin = { .sin_family = AF_INET };
57 #ifdef INET6
58 	struct sockaddr_in6 sin6 = { .sin6_family = AF_INET6 };
59 #endif
60 	uint64_t t;
61 	int i;
62 	bool ret = false;
63 
64 	ratelimit_init(&rl_test);
65 
66 	for (i = 0; i < nitems(rl_expected); i++) {
67 		if ((t = rl_expected[i].sleep_time) != 0) {
68 			tsleep(&rl_test, 0, "rl_test",
69 			       (int)(t * hz / NSEC_PER_SEC));
70 		}
71 
72 		/*
73 		 * The first v4 ratelimit_allow is against a constant address,
74 		 * and should be indifferent to the port.
75 		 */
76 		sin.sin_addr.s_addr = 0x01020304;
77 		sin.sin_port = karc4random();
78 
79 		if (ratelimit_allow(&rl_test, sintosa(&sin))
80 		    != rl_expected[i].result)
81 			T_FAILED_ITER("malicious v4");
82 
83 		/*
84 		 * The second ratelimit_allow is to test that an arbitrary
85 		 * address is still allowed.
86 		 */
87 		sin.sin_addr.s_addr += i + 1;
88 		sin.sin_port = karc4random();
89 
90 		if (ratelimit_allow(&rl_test, sintosa(&sin)) != 0)
91 			T_FAILED_ITER("non-malicious v4");
92 
93 #ifdef INET6
94 		/*
95 		 * The first v6 ratelimit_allow is against a constant address,
96 		 * and should be indifferent to the port.  We also mutate the
97 		 * lower 64 bits of the address as we want to ensure ratelimit
98 		 * occurs against the higher 64 bits (/64 network).
99 		 */
100 		sin6.sin6_addr.s6_addr32[0] = 0x01020304;
101 		sin6.sin6_addr.s6_addr32[1] = 0x05060708;
102 		sin6.sin6_addr.s6_addr32[2] = i;
103 		sin6.sin6_addr.s6_addr32[3] = i;
104 		sin6.sin6_port = karc4random();
105 
106 		if (ratelimit_allow(&rl_test, sin6tosa(&sin6))
107 		    != rl_expected[i].result)
108 			T_FAILED_ITER("malicious v6");
109 
110 		/*
111 		 * Again, test that an address different to above is still
112 		 * allowed.
113 		 */
114 		sin6.sin6_addr.s6_addr32[0] += i + 1;
115 		sin6.sin6_port = karc4random();
116 
117 		if (ratelimit_allow(&rl_test, sintosa(&sin)) != 0)
118 			T_FAILED_ITER("non-malicious v6");
119 #endif
120 	}
121 	T_PASSED;
122 	ret = true;
123 
124 cleanup:
125 	ratelimit_deinit(&rl_test);
126 	return (ret);
127 }
128 
129 static bool
130 cookie_ratelimit_capacity_test(void)
131 {
132 	struct sockaddr_in sin;
133 	int i;
134 	bool ret = false;
135 
136 	ratelimit_init(&rl_test);
137 
138 	sin.sin_family = AF_INET;
139 	sin.sin_port = 1234;
140 
141 	/*
142 	 * Test that the ratelimiter has an upper bound on the number of
143 	 * addresses to be limited.
144 	 */
145 	for (i = 0; i <= RATELIMIT_SIZE_MAX; i++) {
146 		sin.sin_addr.s_addr = i;
147 		if (i == RATELIMIT_SIZE_MAX) {
148 			if (ratelimit_allow(&rl_test, sintosa(&sin))
149 			    != ECONNREFUSED)
150 				T_FAILED_ITER("reject");
151 		} else {
152 			if (ratelimit_allow(&rl_test, sintosa(&sin)) != 0)
153 				T_FAILED_ITER("allow");
154 		}
155 	}
156 	T_PASSED;
157 	ret = true;
158 
159 cleanup:
160 	ratelimit_deinit(&rl_test);
161 	return (ret);
162 }
163 
164 static bool
165 cookie_ratelimit_gc_test(void)
166 {
167 	struct sockaddr_in sin;
168 	int i;
169 	bool ret = false;
170 
171 	ratelimit_init(&rl_test);
172 
173 	sin.sin_family = AF_INET;
174 	sin.sin_port = 1234;
175 
176 	/* Test that the garbage collect routine will run. */
177 	if (rl_test.rl_table_num != 0)
178 		T_FAILED("init not empty");
179 
180 	for (i = 0; i < RATELIMIT_SIZE_MAX / 2; i++) {
181 		sin.sin_addr.s_addr = i;
182 		if (ratelimit_allow(&rl_test, sintosa(&sin)) != 0)
183 			T_FAILED_ITER("insert");
184 	}
185 
186 	if (rl_test.rl_table_num != RATELIMIT_SIZE_MAX / 2)
187 		T_FAILED("insert 1 not full");
188 
189 	tsleep(&rl_test, 0, "rl_test", ELEMENT_TIMEOUT * hz / 2);
190 
191 	for (i = 0; i < RATELIMIT_SIZE_MAX / 2; i++) {
192 		sin.sin_addr.s_addr = i;
193 		if (ratelimit_allow(&rl_test, sintosa(&sin)) != 0)
194 			T_FAILED_ITER("insert");
195 	}
196 
197 	if (rl_test.rl_table_num != RATELIMIT_SIZE_MAX / 2)
198 		T_FAILED("insert 2 not full");
199 
200 	tsleep(&rl_test, 0, "rl_test", ELEMENT_TIMEOUT * hz * 2);
201 
202 	if (rl_test.rl_table_num != 0)
203 		T_FAILED("gc");
204 
205 	T_PASSED;
206 	ret = true;
207 
208 cleanup:
209 	ratelimit_deinit(&rl_test);
210 	return (ret);
211 }
212 
213 static bool
214 cookie_mac_test(void)
215 {
216 	struct cookie_checker *checker;
217 	struct cookie_maker *maker;
218 	struct cookie_macs cm;
219 	struct sockaddr_in sin;
220 	uint8_t nonce[COOKIE_NONCE_SIZE];
221 	uint8_t cookie[COOKIE_ENCRYPTED_SIZE];
222 	uint8_t shared[COOKIE_INPUT_SIZE];
223 	uint8_t message[T_MESSAGE_LEN];
224 	int res, i;
225 	bool ret = false;
226 
227 	karc4random_buf(shared, COOKIE_INPUT_SIZE);
228 	karc4random_buf(message, T_MESSAGE_LEN);
229 
230 	/* Init cookie_maker. */
231 	maker = cookie_maker_alloc(shared);
232 
233 	checker = cookie_checker_alloc();
234 	cookie_checker_update(checker, shared);
235 
236 	/* Create dummy sockaddr. */
237 	sin.sin_family = AF_INET;
238 	sin.sin_len = sizeof(sin);
239 	sin.sin_addr.s_addr = 1;
240 	sin.sin_port = 51820;
241 
242 	/* MAC message. */
243 	cookie_maker_mac(maker, &cm, message, T_MESSAGE_LEN);
244 
245 	/* Check we have a null mac2. */
246 	for (i = 0; i < sizeof(cm.mac2); i++) {
247 		if (cm.mac2[i] != 0)
248 			T_FAILED("validate_macs_noload_mac2_zeroed");
249 	}
250 
251 	/* Validate all bytes are checked in mac1. */
252 	for (i = 0; i < sizeof(cm.mac1); i++) {
253 		cm.mac1[i] = ~cm.mac1[i];
254 		if (cookie_checker_validate_macs(checker, &cm, message,
255 						 T_MESSAGE_LEN, 0,
256 						 sintosa(&sin)) != EINVAL)
257 			T_FAILED("validate_macs_noload_munge");
258 		cm.mac1[i] = ~cm.mac1[i];
259 	}
260 
261 	/* Check mac2 is zeroed. */
262 	res = 0;
263 	for (i = 0; i < sizeof(cm.mac2); i++)
264 		res |= cm.mac2[i];
265 	if (res != 0)
266 		T_FAILED("validate_macs_mac2_checkzero");
267 
268 
269 	/* Check we can successfully validate the MAC. */
270 	if (cookie_checker_validate_macs(checker, &cm, message, T_MESSAGE_LEN,
271 					 0, sintosa(&sin)) != 0)
272 		T_FAILED("validate_macs_noload_normal");
273 
274 	/* Check we get a EAGAIN if no mac2 and under load. */
275 	if (cookie_checker_validate_macs(checker, &cm, message, T_MESSAGE_LEN,
276 					 1, sintosa(&sin)) != EAGAIN)
277 		T_FAILED("validate_macs_load_normal");
278 
279 	/* Simulate a cookie message. */
280 	cookie_checker_create_payload(checker, &cm, nonce, cookie,
281 				      sintosa(&sin));
282 
283 	/* Validate all bytes are checked in cookie. */
284 	for (i = 0; i < sizeof(cookie); i++) {
285 		cookie[i] = ~cookie[i];
286 		if (cookie_maker_consume_payload(maker, nonce, cookie)
287 		    != EINVAL)
288 			T_FAILED("consume_payload_munge");
289 		cookie[i] = ~cookie[i];
290 	}
291 
292 	/* Check we can actually consume the payload. */
293 	if (cookie_maker_consume_payload(maker, nonce, cookie) != 0)
294 		T_FAILED("consume_payload_normal");
295 
296 	/* Check replay isn't allowed. */
297 	if (cookie_maker_consume_payload(maker, nonce, cookie) != ETIMEDOUT)
298 		T_FAILED("consume_payload_normal_replay");
299 
300 	/* MAC message again, with MAC2. */
301 	cookie_maker_mac(maker, &cm, message, T_MESSAGE_LEN);
302 
303 	/* Check we added a mac2. */
304 	res = 0;
305 	for (i = 0; i < sizeof(cm.mac2); i++)
306 		res |= cm.mac2[i];
307 	if (res == 0)
308 		T_FAILED("validate_macs_make_mac2");
309 
310 	/* Check we get OK if mac2 and under load */
311 	if (cookie_checker_validate_macs(checker, &cm, message, T_MESSAGE_LEN,
312 					 1, sintosa(&sin)) != 0)
313 		T_FAILED("validate_macs_load_normal_mac2");
314 
315 	/* Check we get EAGAIN if we munge the source IP. */
316 	sin.sin_addr.s_addr = ~sin.sin_addr.s_addr;
317 	if (cookie_checker_validate_macs(checker, &cm, message, T_MESSAGE_LEN,
318 					 1, sintosa(&sin)) != EAGAIN)
319 		T_FAILED("validate_macs_load_spoofip_mac2");
320 	sin.sin_addr.s_addr = ~sin.sin_addr.s_addr;
321 
322 	/* Check we get OK if mac2 and under load */
323 	if (cookie_checker_validate_macs(checker, &cm, message, T_MESSAGE_LEN,
324 					 1, sintosa(&sin)) != 0)
325 		T_FAILED("validate_macs_load_normal_mac2_retry");
326 
327 	T_PASSED;
328 	ret = true;
329 
330 cleanup:
331 	cookie_checker_free(checker);
332 	cookie_maker_free(maker);
333 	return (ret);
334 }
335 
336 bool
337 cookie_selftest(void)
338 {
339 	bool ret = true;
340 
341 	ret &= cookie_ratelimit_timings_test();
342 	ret &= cookie_ratelimit_capacity_test();
343 	ret &= cookie_ratelimit_gc_test();
344 	ret &= cookie_mac_test();
345 
346 	kprintf("%s: %s\n", __func__, ret ? "pass" : "FAIL");
347 	return (ret);
348 }
349 
350 #undef T_MESSAGE_LEN
351 #undef T_FAILED_ITER
352 #undef T_FAILED
353 #undef T_PASSED
354