Loading...
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
14static 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
33static 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;
46err:
47 return -1;
48}
49
50static 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;
65err:
66 return -1;
67}
68
69#define msg "Hello World"
70#define msglen 11
71
72static 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
92static 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);
112close_client:
113 close(client);
114close_server:
115 close(server);
116}
117
118void 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
146destroy_skel:
147 system("tc qdisc del dev lo clsact");
148
149 test_tcp_custom_syncookie__destroy(skel);
150}