// SPDX-License-Identifier: GPL-2.0 /* Copyright Amazon.com Inc. or its affiliates. */ #define _GNU_SOURCE #include #include #include #include "test_progs.h" #include "cgroup_helpers.h" #include "network_helpers.h" #include "test_tcp_custom_syncookie.skel.h" static struct test_tcp_custom_syncookie_case { int family, type; char addr[16]; char name[10]; } test_cases[] = { { .name = "IPv4 TCP", .family = AF_INET, .type = SOCK_STREAM, .addr = "127.0.0.1", }, { .name = "IPv6 TCP", .family = AF_INET6, .type = SOCK_STREAM, .addr = "::1", }, }; static int setup_netns(void) { if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns")) return -1; if (!ASSERT_OK(system("ip link set dev lo up"), "ip")) goto err; if (!ASSERT_OK(write_sysctl("/proc/sys/net/ipv4/tcp_ecn", "1"), "write_sysctl")) goto err; return 0; err: return -1; } static int setup_tc(struct test_tcp_custom_syncookie *skel) { LIBBPF_OPTS(bpf_tc_hook, qdisc_lo, .attach_point = BPF_TC_INGRESS); LIBBPF_OPTS(bpf_tc_opts, tc_attach, .prog_fd = bpf_program__fd(skel->progs.tcp_custom_syncookie)); qdisc_lo.ifindex = if_nametoindex("lo"); if (!ASSERT_OK(bpf_tc_hook_create(&qdisc_lo), "qdisc add dev lo clsact")) goto err; if (!ASSERT_OK(bpf_tc_attach(&qdisc_lo, &tc_attach), "filter add dev lo ingress")) goto err; return 0; err: return -1; } #define msg "Hello World" #define msglen 11 static void transfer_message(int sender, int receiver) { char buf[msglen]; int ret; ret = send(sender, msg, msglen, 0); if (!ASSERT_EQ(ret, msglen, "send")) return; memset(buf, 0, sizeof(buf)); ret = recv(receiver, buf, msglen, 0); if (!ASSERT_EQ(ret, msglen, "recv")) return; ret = strncmp(buf, msg, msglen); if (!ASSERT_EQ(ret, 0, "strncmp")) return; } static void create_connection(struct test_tcp_custom_syncookie_case *test_case) { int server, client, child; server = start_server(test_case->family, test_case->type, test_case->addr, 0, 0); if (!ASSERT_NEQ(server, -1, "start_server")) return; client = connect_to_fd(server, 0); if (!ASSERT_NEQ(client, -1, "connect_to_fd")) goto close_server; child = accept(server, NULL, 0); if (!ASSERT_NEQ(child, -1, "accept")) goto close_client; transfer_message(client, child); transfer_message(child, client); close(child); close_client: close(client); close_server: close(server); } void test_tcp_custom_syncookie(void) { struct test_tcp_custom_syncookie *skel; int i; if (setup_netns()) return; skel = test_tcp_custom_syncookie__open_and_load(); if (!ASSERT_OK_PTR(skel, "open_and_load")) return; if (setup_tc(skel)) goto destroy_skel; for (i = 0; i < ARRAY_SIZE(test_cases); i++) { if (!test__start_subtest(test_cases[i].name)) continue; skel->bss->handled_syn = false; skel->bss->handled_ack = false; create_connection(&test_cases[i]); ASSERT_EQ(skel->bss->handled_syn, true, "SYN is not handled at tc."); ASSERT_EQ(skel->bss->handled_ack, true, "ACK is not handled at tc"); } destroy_skel: system("tc qdisc del dev lo clsact"); test_tcp_custom_syncookie__destroy(skel); }