1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright Amazon.com Inc. or its affiliates. */ 3 4 #define _GNU_SOURCE 5 #include <sched.h> 6 #include <stdlib.h> 7 #include <net/if.h> 8 9 #include "test_progs.h" 10 #include "cgroup_helpers.h" 11 #include "network_helpers.h" 12 #include "test_tcp_custom_syncookie.skel.h" 13 14 static struct test_tcp_custom_syncookie_case { 15 int family, type; 16 char addr[16]; 17 char name[10]; 18 } test_cases[] = { 19 { 20 .name = "IPv4 TCP", 21 .family = AF_INET, 22 .type = SOCK_STREAM, 23 .addr = "127.0.0.1", 24 }, 25 { 26 .name = "IPv6 TCP", 27 .family = AF_INET6, 28 .type = SOCK_STREAM, 29 .addr = "::1", 30 }, 31 }; 32 33 static int setup_netns(void) 34 { 35 if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns")) 36 return -1; 37 38 if (!ASSERT_OK(system("ip link set dev lo up"), "ip")) 39 goto err; 40 41 if (!ASSERT_OK(write_sysctl("/proc/sys/net/ipv4/tcp_ecn", "1"), 42 "write_sysctl")) 43 goto err; 44 45 return 0; 46 err: 47 return -1; 48 } 49 50 static int setup_tc(struct test_tcp_custom_syncookie *skel) 51 { 52 LIBBPF_OPTS(bpf_tc_hook, qdisc_lo, .attach_point = BPF_TC_INGRESS); 53 LIBBPF_OPTS(bpf_tc_opts, tc_attach, 54 .prog_fd = bpf_program__fd(skel->progs.tcp_custom_syncookie)); 55 56 qdisc_lo.ifindex = if_nametoindex("lo"); 57 if (!ASSERT_OK(bpf_tc_hook_create(&qdisc_lo), "qdisc add dev lo clsact")) 58 goto err; 59 60 if (!ASSERT_OK(bpf_tc_attach(&qdisc_lo, &tc_attach), 61 "filter add dev lo ingress")) 62 goto err; 63 64 return 0; 65 err: 66 return -1; 67 } 68 69 #define msg "Hello World" 70 #define msglen 11 71 72 static void transfer_message(int sender, int receiver) 73 { 74 char buf[msglen]; 75 int ret; 76 77 ret = send(sender, msg, msglen, 0); 78 if (!ASSERT_EQ(ret, msglen, "send")) 79 return; 80 81 memset(buf, 0, sizeof(buf)); 82 83 ret = recv(receiver, buf, msglen, 0); 84 if (!ASSERT_EQ(ret, msglen, "recv")) 85 return; 86 87 ret = strncmp(buf, msg, msglen); 88 if (!ASSERT_EQ(ret, 0, "strncmp")) 89 return; 90 } 91 92 static void create_connection(struct test_tcp_custom_syncookie_case *test_case) 93 { 94 int server, client, child; 95 96 server = start_server(test_case->family, test_case->type, test_case->addr, 0, 0); 97 if (!ASSERT_NEQ(server, -1, "start_server")) 98 return; 99 100 client = connect_to_fd(server, 0); 101 if (!ASSERT_NEQ(client, -1, "connect_to_fd")) 102 goto close_server; 103 104 child = accept(server, NULL, 0); 105 if (!ASSERT_NEQ(child, -1, "accept")) 106 goto close_client; 107 108 transfer_message(client, child); 109 transfer_message(child, client); 110 111 close(child); 112 close_client: 113 close(client); 114 close_server: 115 close(server); 116 } 117 118 void test_tcp_custom_syncookie(void) 119 { 120 struct test_tcp_custom_syncookie *skel; 121 int i; 122 123 if (setup_netns()) 124 return; 125 126 skel = test_tcp_custom_syncookie__open_and_load(); 127 if (!ASSERT_OK_PTR(skel, "open_and_load")) 128 return; 129 130 if (setup_tc(skel)) 131 goto destroy_skel; 132 133 for (i = 0; i < ARRAY_SIZE(test_cases); i++) { 134 if (!test__start_subtest(test_cases[i].name)) 135 continue; 136 137 skel->bss->handled_syn = false; 138 skel->bss->handled_ack = false; 139 140 create_connection(&test_cases[i]); 141 142 ASSERT_EQ(skel->bss->handled_syn, true, "SYN is not handled at tc."); 143 ASSERT_EQ(skel->bss->handled_ack, true, "ACK is not handled at tc"); 144 } 145 146 destroy_skel: 147 system("tc qdisc del dev lo clsact"); 148 149 test_tcp_custom_syncookie__destroy(skel); 150 } 151