1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2020 Facebook */
3 
4 #define _GNU_SOURCE
5 #include <sched.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <sys/socket.h>
9 #include <linux/compiler.h>
10 
11 #include "test_progs.h"
12 #include "cgroup_helpers.h"
13 #include "network_helpers.h"
14 #include "test_tcp_hdr_options.h"
15 #include "test_tcp_hdr_options.skel.h"
16 #include "test_misc_tcp_hdr_options.skel.h"
17 
18 #define LO_ADDR6 "::eB9F"
19 #define CG_NAME "/tcpbpf-hdr-opt-test"
20 
21 struct bpf_test_option exp_passive_estab_in;
22 struct bpf_test_option exp_active_estab_in;
23 struct bpf_test_option exp_passive_fin_in;
24 struct bpf_test_option exp_active_fin_in;
25 struct hdr_stg exp_passive_hdr_stg;
26 struct hdr_stg exp_active_hdr_stg = { .active = true, };
27 
28 static struct test_misc_tcp_hdr_options *misc_skel;
29 static struct test_tcp_hdr_options *skel;
30 static int lport_linum_map_fd;
31 static int hdr_stg_map_fd;
32 static __u32 duration;
33 static int cg_fd;
34 
35 struct sk_fds {
36 	int srv_fd;
37 	int passive_fd;
38 	int active_fd;
39 	int passive_lport;
40 	int active_lport;
41 };
42 
43 static int add_lo_addr(void)
44 {
45 	char ip_addr_cmd[256];
46 	int cmdlen;
47 
48 	cmdlen = snprintf(ip_addr_cmd, sizeof(ip_addr_cmd),
49 			  "ip -6 addr add %s/128 dev lo scope host",
50 			  LO_ADDR6);
51 
52 	if (CHECK(cmdlen >= sizeof(ip_addr_cmd), "compile ip cmd",
53 		  "failed to add host addr %s to lo. ip cmdlen is too long\n",
54 		  LO_ADDR6))
55 		return -1;
56 
57 	if (CHECK(system(ip_addr_cmd), "run ip cmd",
58 		  "failed to add host addr %s to lo\n", LO_ADDR6))
59 		return -1;
60 
61 	return 0;
62 }
63 
64 static int create_netns(void)
65 {
66 	if (CHECK(unshare(CLONE_NEWNET), "create netns",
67 		  "unshare(CLONE_NEWNET): %s (%d)",
68 		  strerror(errno), errno))
69 		return -1;
70 
71 	if (CHECK(system("ip link set dev lo up"), "run ip cmd",
72 		  "failed to bring lo link up\n"))
73 		return -1;
74 
75 	if (add_lo_addr())
76 		return -1;
77 
78 	return 0;
79 }
80 
81 static int write_sysctl(const char *sysctl, const char *value)
82 {
83 	int fd, err, len;
84 
85 	fd = open(sysctl, O_WRONLY);
86 	if (CHECK(fd == -1, "open sysctl", "open(%s): %s (%d)\n",
87 		  sysctl, strerror(errno), errno))
88 		return -1;
89 
90 	len = strlen(value);
91 	err = write(fd, value, len);
92 	close(fd);
93 	if (CHECK(err != len, "write sysctl",
94 		  "write(%s, %s): err:%d %s (%d)\n",
95 		  sysctl, value, err, strerror(errno), errno))
96 		return -1;
97 
98 	return 0;
99 }
100 
101 static void print_hdr_stg(const struct hdr_stg *hdr_stg, const char *prefix)
102 {
103 	fprintf(stderr, "%s{active:%u, resend_syn:%u, syncookie:%u, fastopen:%u}\n",
104 		prefix ? : "", hdr_stg->active, hdr_stg->resend_syn,
105 		hdr_stg->syncookie, hdr_stg->fastopen);
106 }
107 
108 static void print_option(const struct bpf_test_option *opt, const char *prefix)
109 {
110 	fprintf(stderr, "%s{flags:0x%x, max_delack_ms:%u, rand:0x%x}\n",
111 		prefix ? : "", opt->flags, opt->max_delack_ms, opt->rand);
112 }
113 
114 static void sk_fds_close(struct sk_fds *sk_fds)
115 {
116 	close(sk_fds->srv_fd);
117 	close(sk_fds->passive_fd);
118 	close(sk_fds->active_fd);
119 }
120 
121 static int sk_fds_shutdown(struct sk_fds *sk_fds)
122 {
123 	int ret, abyte;
124 
125 	shutdown(sk_fds->active_fd, SHUT_WR);
126 	ret = read(sk_fds->passive_fd, &abyte, sizeof(abyte));
127 	if (CHECK(ret != 0, "read-after-shutdown(passive_fd):",
128 		  "ret:%d %s (%d)\n",
129 		  ret, strerror(errno), errno))
130 		return -1;
131 
132 	shutdown(sk_fds->passive_fd, SHUT_WR);
133 	ret = read(sk_fds->active_fd, &abyte, sizeof(abyte));
134 	if (CHECK(ret != 0, "read-after-shutdown(active_fd):",
135 		  "ret:%d %s (%d)\n",
136 		  ret, strerror(errno), errno))
137 		return -1;
138 
139 	return 0;
140 }
141 
142 static int sk_fds_connect(struct sk_fds *sk_fds, bool fast_open)
143 {
144 	const char fast[] = "FAST!!!";
145 	struct sockaddr_in6 addr6;
146 	socklen_t len;
147 
148 	sk_fds->srv_fd = start_server(AF_INET6, SOCK_STREAM, LO_ADDR6, 0, 0);
149 	if (CHECK(sk_fds->srv_fd == -1, "start_server", "%s (%d)\n",
150 		  strerror(errno), errno))
151 		goto error;
152 
153 	if (fast_open)
154 		sk_fds->active_fd = fastopen_connect(sk_fds->srv_fd, fast,
155 						     sizeof(fast), 0);
156 	else
157 		sk_fds->active_fd = connect_to_fd(sk_fds->srv_fd, 0);
158 
159 	if (CHECK_FAIL(sk_fds->active_fd == -1)) {
160 		close(sk_fds->srv_fd);
161 		goto error;
162 	}
163 
164 	len = sizeof(addr6);
165 	if (CHECK(getsockname(sk_fds->srv_fd, (struct sockaddr *)&addr6,
166 			      &len), "getsockname(srv_fd)", "%s (%d)\n",
167 		  strerror(errno), errno))
168 		goto error_close;
169 	sk_fds->passive_lport = ntohs(addr6.sin6_port);
170 
171 	len = sizeof(addr6);
172 	if (CHECK(getsockname(sk_fds->active_fd, (struct sockaddr *)&addr6,
173 			      &len), "getsockname(active_fd)", "%s (%d)\n",
174 		  strerror(errno), errno))
175 		goto error_close;
176 	sk_fds->active_lport = ntohs(addr6.sin6_port);
177 
178 	sk_fds->passive_fd = accept(sk_fds->srv_fd, NULL, 0);
179 	if (CHECK(sk_fds->passive_fd == -1, "accept(srv_fd)", "%s (%d)\n",
180 		  strerror(errno), errno))
181 		goto error_close;
182 
183 	if (fast_open) {
184 		char bytes_in[sizeof(fast)];
185 		int ret;
186 
187 		ret = read(sk_fds->passive_fd, bytes_in, sizeof(bytes_in));
188 		if (CHECK(ret != sizeof(fast), "read fastopen syn data",
189 			  "expected=%lu actual=%d\n", sizeof(fast), ret)) {
190 			close(sk_fds->passive_fd);
191 			goto error_close;
192 		}
193 	}
194 
195 	return 0;
196 
197 error_close:
198 	close(sk_fds->active_fd);
199 	close(sk_fds->srv_fd);
200 
201 error:
202 	memset(sk_fds, -1, sizeof(*sk_fds));
203 	return -1;
204 }
205 
206 static int check_hdr_opt(const struct bpf_test_option *exp,
207 			 const struct bpf_test_option *act,
208 			 const char *hdr_desc)
209 {
210 	if (CHECK(memcmp(exp, act, sizeof(*exp)),
211 		  "expected-vs-actual", "unexpected %s\n", hdr_desc)) {
212 		print_option(exp, "expected: ");
213 		print_option(act, "  actual: ");
214 		return -1;
215 	}
216 
217 	return 0;
218 }
219 
220 static int check_hdr_stg(const struct hdr_stg *exp, int fd,
221 			 const char *stg_desc)
222 {
223 	struct hdr_stg act;
224 
225 	if (CHECK(bpf_map_lookup_elem(hdr_stg_map_fd, &fd, &act),
226 		  "map_lookup(hdr_stg_map_fd)", "%s %s (%d)\n",
227 		  stg_desc, strerror(errno), errno))
228 		return -1;
229 
230 	if (CHECK(memcmp(exp, &act, sizeof(*exp)),
231 		  "expected-vs-actual", "unexpected %s\n", stg_desc)) {
232 		print_hdr_stg(exp, "expected: ");
233 		print_hdr_stg(&act, "  actual: ");
234 		return -1;
235 	}
236 
237 	return 0;
238 }
239 
240 static int check_error_linum(const struct sk_fds *sk_fds)
241 {
242 	unsigned int nr_errors = 0;
243 	struct linum_err linum_err;
244 	int lport;
245 
246 	lport = sk_fds->passive_lport;
247 	if (!bpf_map_lookup_elem(lport_linum_map_fd, &lport, &linum_err)) {
248 		fprintf(stderr,
249 			"bpf prog error out at lport:passive(%d), linum:%u err:%d\n",
250 			lport, linum_err.linum, linum_err.err);
251 		nr_errors++;
252 	}
253 
254 	lport = sk_fds->active_lport;
255 	if (!bpf_map_lookup_elem(lport_linum_map_fd, &lport, &linum_err)) {
256 		fprintf(stderr,
257 			"bpf prog error out at lport:active(%d), linum:%u err:%d\n",
258 			lport, linum_err.linum, linum_err.err);
259 		nr_errors++;
260 	}
261 
262 	return nr_errors;
263 }
264 
265 static void check_hdr_and_close_fds(struct sk_fds *sk_fds)
266 {
267 	if (sk_fds_shutdown(sk_fds))
268 		goto check_linum;
269 
270 	if (check_hdr_stg(&exp_passive_hdr_stg, sk_fds->passive_fd,
271 			  "passive_hdr_stg"))
272 		goto check_linum;
273 
274 	if (check_hdr_stg(&exp_active_hdr_stg, sk_fds->active_fd,
275 			  "active_hdr_stg"))
276 		goto check_linum;
277 
278 	if (check_hdr_opt(&exp_passive_estab_in, &skel->bss->passive_estab_in,
279 			  "passive_estab_in"))
280 		goto check_linum;
281 
282 	if (check_hdr_opt(&exp_active_estab_in, &skel->bss->active_estab_in,
283 			  "active_estab_in"))
284 		goto check_linum;
285 
286 	if (check_hdr_opt(&exp_passive_fin_in, &skel->bss->passive_fin_in,
287 			  "passive_fin_in"))
288 		goto check_linum;
289 
290 	check_hdr_opt(&exp_active_fin_in, &skel->bss->active_fin_in,
291 		      "active_fin_in");
292 
293 check_linum:
294 	CHECK_FAIL(check_error_linum(sk_fds));
295 	sk_fds_close(sk_fds);
296 }
297 
298 static void prepare_out(void)
299 {
300 	skel->bss->active_syn_out = exp_passive_estab_in;
301 	skel->bss->passive_synack_out = exp_active_estab_in;
302 
303 	skel->bss->active_fin_out = exp_passive_fin_in;
304 	skel->bss->passive_fin_out = exp_active_fin_in;
305 }
306 
307 static void reset_test(void)
308 {
309 	size_t optsize = sizeof(struct bpf_test_option);
310 	int lport, err;
311 
312 	memset(&skel->bss->passive_synack_out, 0, optsize);
313 	memset(&skel->bss->passive_fin_out, 0, optsize);
314 
315 	memset(&skel->bss->passive_estab_in, 0, optsize);
316 	memset(&skel->bss->passive_fin_in, 0, optsize);
317 
318 	memset(&skel->bss->active_syn_out, 0, optsize);
319 	memset(&skel->bss->active_fin_out, 0, optsize);
320 
321 	memset(&skel->bss->active_estab_in, 0, optsize);
322 	memset(&skel->bss->active_fin_in, 0, optsize);
323 
324 	skel->data->test_kind = TCPOPT_EXP;
325 	skel->data->test_magic = 0xeB9F;
326 
327 	memset(&exp_passive_estab_in, 0, optsize);
328 	memset(&exp_active_estab_in, 0, optsize);
329 	memset(&exp_passive_fin_in, 0, optsize);
330 	memset(&exp_active_fin_in, 0, optsize);
331 
332 	memset(&exp_passive_hdr_stg, 0, sizeof(exp_passive_hdr_stg));
333 	memset(&exp_active_hdr_stg, 0, sizeof(exp_active_hdr_stg));
334 	exp_active_hdr_stg.active = true;
335 
336 	err = bpf_map_get_next_key(lport_linum_map_fd, NULL, &lport);
337 	while (!err) {
338 		bpf_map_delete_elem(lport_linum_map_fd, &lport);
339 		err = bpf_map_get_next_key(lport_linum_map_fd, &lport, &lport);
340 	}
341 }
342 
343 static void fastopen_estab(void)
344 {
345 	struct bpf_link *link;
346 	struct sk_fds sk_fds;
347 
348 	hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
349 	lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
350 
351 	exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
352 	exp_passive_estab_in.rand = 0xfa;
353 	exp_passive_estab_in.max_delack_ms = 11;
354 
355 	exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
356 	exp_active_estab_in.rand = 0xce;
357 	exp_active_estab_in.max_delack_ms = 22;
358 
359 	exp_passive_hdr_stg.fastopen = true;
360 
361 	prepare_out();
362 
363 	/* Allow fastopen without fastopen cookie */
364 	if (write_sysctl("/proc/sys/net/ipv4/tcp_fastopen", "1543"))
365 		return;
366 
367 	link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
368 	if (CHECK(IS_ERR(link), "attach_cgroup(estab)", "err: %ld\n",
369 		  PTR_ERR(link)))
370 		return;
371 
372 	if (sk_fds_connect(&sk_fds, true)) {
373 		bpf_link__destroy(link);
374 		return;
375 	}
376 
377 	check_hdr_and_close_fds(&sk_fds);
378 	bpf_link__destroy(link);
379 }
380 
381 static void syncookie_estab(void)
382 {
383 	struct bpf_link *link;
384 	struct sk_fds sk_fds;
385 
386 	hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
387 	lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
388 
389 	exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
390 	exp_passive_estab_in.rand = 0xfa;
391 	exp_passive_estab_in.max_delack_ms = 11;
392 
393 	exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS |
394 					OPTION_F_RESEND;
395 	exp_active_estab_in.rand = 0xce;
396 	exp_active_estab_in.max_delack_ms = 22;
397 
398 	exp_passive_hdr_stg.syncookie = true;
399 	exp_active_hdr_stg.resend_syn = true,
400 
401 	prepare_out();
402 
403 	/* Clear the RESEND to ensure the bpf prog can learn
404 	 * want_cookie and set the RESEND by itself.
405 	 */
406 	skel->bss->passive_synack_out.flags &= ~OPTION_F_RESEND;
407 
408 	/* Enforce syncookie mode */
409 	if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "2"))
410 		return;
411 
412 	link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
413 	if (CHECK(IS_ERR(link), "attach_cgroup(estab)", "err: %ld\n",
414 		  PTR_ERR(link)))
415 		return;
416 
417 	if (sk_fds_connect(&sk_fds, false)) {
418 		bpf_link__destroy(link);
419 		return;
420 	}
421 
422 	check_hdr_and_close_fds(&sk_fds);
423 	bpf_link__destroy(link);
424 }
425 
426 static void fin(void)
427 {
428 	struct bpf_link *link;
429 	struct sk_fds sk_fds;
430 
431 	hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
432 	lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
433 
434 	exp_passive_fin_in.flags = OPTION_F_RAND;
435 	exp_passive_fin_in.rand = 0xfa;
436 
437 	exp_active_fin_in.flags = OPTION_F_RAND;
438 	exp_active_fin_in.rand = 0xce;
439 
440 	prepare_out();
441 
442 	if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
443 		return;
444 
445 	link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
446 	if (CHECK(IS_ERR(link), "attach_cgroup(estab)", "err: %ld\n",
447 		  PTR_ERR(link)))
448 		return;
449 
450 	if (sk_fds_connect(&sk_fds, false)) {
451 		bpf_link__destroy(link);
452 		return;
453 	}
454 
455 	check_hdr_and_close_fds(&sk_fds);
456 	bpf_link__destroy(link);
457 }
458 
459 static void __simple_estab(bool exprm)
460 {
461 	struct bpf_link *link;
462 	struct sk_fds sk_fds;
463 
464 	hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
465 	lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
466 
467 	exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
468 	exp_passive_estab_in.rand = 0xfa;
469 	exp_passive_estab_in.max_delack_ms = 11;
470 
471 	exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
472 	exp_active_estab_in.rand = 0xce;
473 	exp_active_estab_in.max_delack_ms = 22;
474 
475 	prepare_out();
476 
477 	if (!exprm) {
478 		skel->data->test_kind = 0xB9;
479 		skel->data->test_magic = 0;
480 	}
481 
482 	if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
483 		return;
484 
485 	link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
486 	if (CHECK(IS_ERR(link), "attach_cgroup(estab)", "err: %ld\n",
487 		  PTR_ERR(link)))
488 		return;
489 
490 	if (sk_fds_connect(&sk_fds, false)) {
491 		bpf_link__destroy(link);
492 		return;
493 	}
494 
495 	check_hdr_and_close_fds(&sk_fds);
496 	bpf_link__destroy(link);
497 }
498 
499 static void no_exprm_estab(void)
500 {
501 	__simple_estab(false);
502 }
503 
504 static void simple_estab(void)
505 {
506 	__simple_estab(true);
507 }
508 
509 static void misc(void)
510 {
511 	const char send_msg[] = "MISC!!!";
512 	char recv_msg[sizeof(send_msg)];
513 	const unsigned int nr_data = 2;
514 	struct bpf_link *link;
515 	struct sk_fds sk_fds;
516 	int i, ret;
517 
518 	lport_linum_map_fd = bpf_map__fd(misc_skel->maps.lport_linum_map);
519 
520 	if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
521 		return;
522 
523 	link = bpf_program__attach_cgroup(misc_skel->progs.misc_estab, cg_fd);
524 	if (CHECK(IS_ERR(link), "attach_cgroup(misc_estab)", "err: %ld\n",
525 		  PTR_ERR(link)))
526 		return;
527 
528 	if (sk_fds_connect(&sk_fds, false)) {
529 		bpf_link__destroy(link);
530 		return;
531 	}
532 
533 	for (i = 0; i < nr_data; i++) {
534 		/* MSG_EOR to ensure skb will not be combined */
535 		ret = send(sk_fds.active_fd, send_msg, sizeof(send_msg),
536 			   MSG_EOR);
537 		if (CHECK(ret != sizeof(send_msg), "send(msg)", "ret:%d\n",
538 			  ret))
539 			goto check_linum;
540 
541 		ret = read(sk_fds.passive_fd, recv_msg, sizeof(recv_msg));
542 		if (CHECK(ret != sizeof(send_msg), "read(msg)", "ret:%d\n",
543 			  ret))
544 			goto check_linum;
545 	}
546 
547 	if (sk_fds_shutdown(&sk_fds))
548 		goto check_linum;
549 
550 	CHECK(misc_skel->bss->nr_syn != 1, "unexpected nr_syn",
551 	      "expected (1) != actual (%u)\n",
552 		misc_skel->bss->nr_syn);
553 
554 	CHECK(misc_skel->bss->nr_data != nr_data, "unexpected nr_data",
555 	      "expected (%u) != actual (%u)\n",
556 	      nr_data, misc_skel->bss->nr_data);
557 
558 	/* The last ACK may have been delayed, so it is either 1 or 2. */
559 	CHECK(misc_skel->bss->nr_pure_ack != 1 &&
560 	      misc_skel->bss->nr_pure_ack != 2,
561 	      "unexpected nr_pure_ack",
562 	      "expected (1 or 2) != actual (%u)\n",
563 		misc_skel->bss->nr_pure_ack);
564 
565 	CHECK(misc_skel->bss->nr_fin != 1, "unexpected nr_fin",
566 	      "expected (1) != actual (%u)\n",
567 	      misc_skel->bss->nr_fin);
568 
569 check_linum:
570 	CHECK_FAIL(check_error_linum(&sk_fds));
571 	sk_fds_close(&sk_fds);
572 	bpf_link__destroy(link);
573 }
574 
575 struct test {
576 	const char *desc;
577 	void (*run)(void);
578 };
579 
580 #define DEF_TEST(name) { #name, name }
581 static struct test tests[] = {
582 	DEF_TEST(simple_estab),
583 	DEF_TEST(no_exprm_estab),
584 	DEF_TEST(syncookie_estab),
585 	DEF_TEST(fastopen_estab),
586 	DEF_TEST(fin),
587 	DEF_TEST(misc),
588 };
589 
590 void test_tcp_hdr_options(void)
591 {
592 	int i;
593 
594 	skel = test_tcp_hdr_options__open_and_load();
595 	if (CHECK(!skel, "open and load skel", "failed"))
596 		return;
597 
598 	misc_skel = test_misc_tcp_hdr_options__open_and_load();
599 	if (CHECK(!misc_skel, "open and load misc test skel", "failed"))
600 		goto skel_destroy;
601 
602 	cg_fd = test__join_cgroup(CG_NAME);
603 	if (CHECK_FAIL(cg_fd < 0))
604 		goto skel_destroy;
605 
606 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
607 		if (!test__start_subtest(tests[i].desc))
608 			continue;
609 
610 		if (create_netns())
611 			break;
612 
613 		tests[i].run();
614 
615 		reset_test();
616 	}
617 
618 	close(cg_fd);
619 skel_destroy:
620 	test_misc_tcp_hdr_options__destroy(misc_skel);
621 	test_tcp_hdr_options__destroy(skel);
622 }
623