xref: /openbmc/linux/tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1fb5cd0ceSMaxim Mikityanskiy // SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
2fb5cd0ceSMaxim Mikityanskiy /* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
3fb5cd0ceSMaxim Mikityanskiy 
4784d5dc0SMaxim Mikityanskiy #define _GNU_SOURCE
5fb5cd0ceSMaxim Mikityanskiy #include <test_progs.h>
6fb5cd0ceSMaxim Mikityanskiy #include <network_helpers.h>
7fb5cd0ceSMaxim Mikityanskiy #include <ctype.h>
8fb5cd0ceSMaxim Mikityanskiy 
9fb5cd0ceSMaxim Mikityanskiy #define CMD_OUT_BUF_SIZE 1023
10fb5cd0ceSMaxim Mikityanskiy 
11784d5dc0SMaxim Mikityanskiy #define SYS_OUT(cmd, ...) ({ \
12784d5dc0SMaxim Mikityanskiy 	char buf[1024]; \
13784d5dc0SMaxim Mikityanskiy 	snprintf(buf, sizeof(buf), (cmd), ##__VA_ARGS__); \
14784d5dc0SMaxim Mikityanskiy 	FILE *f = popen(buf, "r"); \
15784d5dc0SMaxim Mikityanskiy 	if (!ASSERT_OK_PTR(f, buf)) \
16fb5cd0ceSMaxim Mikityanskiy 		goto out; \
17fb5cd0ceSMaxim Mikityanskiy 	f; \
18fb5cd0ceSMaxim Mikityanskiy })
19fb5cd0ceSMaxim Mikityanskiy 
20fb5cd0ceSMaxim Mikityanskiy /* out must be at least `size * 4 + 1` bytes long */
escape_str(char * out,const char * in,size_t size)21fb5cd0ceSMaxim Mikityanskiy static void escape_str(char *out, const char *in, size_t size)
22fb5cd0ceSMaxim Mikityanskiy {
23fb5cd0ceSMaxim Mikityanskiy 	static const char *hex = "0123456789ABCDEF";
24fb5cd0ceSMaxim Mikityanskiy 	size_t i;
25fb5cd0ceSMaxim Mikityanskiy 
26fb5cd0ceSMaxim Mikityanskiy 	for (i = 0; i < size; i++) {
27fb5cd0ceSMaxim Mikityanskiy 		if (isprint(in[i]) && in[i] != '\\' && in[i] != '\'') {
28fb5cd0ceSMaxim Mikityanskiy 			*out++ = in[i];
29fb5cd0ceSMaxim Mikityanskiy 		} else {
30fb5cd0ceSMaxim Mikityanskiy 			*out++ = '\\';
31fb5cd0ceSMaxim Mikityanskiy 			*out++ = 'x';
32fb5cd0ceSMaxim Mikityanskiy 			*out++ = hex[(in[i] >> 4) & 0xf];
33fb5cd0ceSMaxim Mikityanskiy 			*out++ = hex[in[i] & 0xf];
34fb5cd0ceSMaxim Mikityanskiy 		}
35fb5cd0ceSMaxim Mikityanskiy 	}
36fb5cd0ceSMaxim Mikityanskiy 	*out++ = '\0';
37fb5cd0ceSMaxim Mikityanskiy }
38fb5cd0ceSMaxim Mikityanskiy 
expect_str(char * buf,size_t size,const char * str,const char * name)39fb5cd0ceSMaxim Mikityanskiy static bool expect_str(char *buf, size_t size, const char *str, const char *name)
40fb5cd0ceSMaxim Mikityanskiy {
41fb5cd0ceSMaxim Mikityanskiy 	static char escbuf_expected[CMD_OUT_BUF_SIZE * 4];
42fb5cd0ceSMaxim Mikityanskiy 	static char escbuf_actual[CMD_OUT_BUF_SIZE * 4];
43fb5cd0ceSMaxim Mikityanskiy 	static int duration = 0;
44fb5cd0ceSMaxim Mikityanskiy 	bool ok;
45fb5cd0ceSMaxim Mikityanskiy 
46fb5cd0ceSMaxim Mikityanskiy 	ok = size == strlen(str) && !memcmp(buf, str, size);
47fb5cd0ceSMaxim Mikityanskiy 
48fb5cd0ceSMaxim Mikityanskiy 	if (!ok) {
49fb5cd0ceSMaxim Mikityanskiy 		escape_str(escbuf_expected, str, strlen(str));
50fb5cd0ceSMaxim Mikityanskiy 		escape_str(escbuf_actual, buf, size);
51fb5cd0ceSMaxim Mikityanskiy 	}
52fb5cd0ceSMaxim Mikityanskiy 	CHECK(!ok, name, "unexpected %s: actual '%s' != expected '%s'\n",
53fb5cd0ceSMaxim Mikityanskiy 	      name, escbuf_actual, escbuf_expected);
54fb5cd0ceSMaxim Mikityanskiy 
55fb5cd0ceSMaxim Mikityanskiy 	return ok;
56fb5cd0ceSMaxim Mikityanskiy }
57fb5cd0ceSMaxim Mikityanskiy 
test_synproxy(bool xdp)58784d5dc0SMaxim Mikityanskiy static void test_synproxy(bool xdp)
59fb5cd0ceSMaxim Mikityanskiy {
60fb5cd0ceSMaxim Mikityanskiy 	int server_fd = -1, client_fd = -1, accept_fd = -1;
61c46a1220SAndrii Nakryiko 	char *prog_id = NULL, *prog_id_end;
62fb5cd0ceSMaxim Mikityanskiy 	struct nstoken *ns = NULL;
63fb5cd0ceSMaxim Mikityanskiy 	FILE *ctrl_file = NULL;
64fb5cd0ceSMaxim Mikityanskiy 	char buf[CMD_OUT_BUF_SIZE];
65fb5cd0ceSMaxim Mikityanskiy 	size_t size;
66fb5cd0ceSMaxim Mikityanskiy 
67*b61987d3SHangbin Liu 	SYS(out, "ip netns add synproxy");
68fb5cd0ceSMaxim Mikityanskiy 
69*b61987d3SHangbin Liu 	SYS(out, "ip link add tmp0 type veth peer name tmp1");
70*b61987d3SHangbin Liu 	SYS(out, "ip link set tmp1 netns synproxy");
71*b61987d3SHangbin Liu 	SYS(out, "ip link set tmp0 up");
72*b61987d3SHangbin Liu 	SYS(out, "ip addr replace 198.18.0.1/24 dev tmp0");
73fb5cd0ceSMaxim Mikityanskiy 
74fb5cd0ceSMaxim Mikityanskiy 	/* When checksum offload is enabled, the XDP program sees wrong
75fb5cd0ceSMaxim Mikityanskiy 	 * checksums and drops packets.
76fb5cd0ceSMaxim Mikityanskiy 	 */
77*b61987d3SHangbin Liu 	SYS(out, "ethtool -K tmp0 tx off");
78784d5dc0SMaxim Mikityanskiy 	if (xdp)
79fb5cd0ceSMaxim Mikityanskiy 		/* Workaround required for veth. */
80*b61987d3SHangbin Liu 		SYS(out, "ip link set tmp0 xdp object xdp_dummy.bpf.o section xdp 2> /dev/null");
81fb5cd0ceSMaxim Mikityanskiy 
82fb5cd0ceSMaxim Mikityanskiy 	ns = open_netns("synproxy");
83fb5cd0ceSMaxim Mikityanskiy 	if (!ASSERT_OK_PTR(ns, "setns"))
84fb5cd0ceSMaxim Mikityanskiy 		goto out;
85fb5cd0ceSMaxim Mikityanskiy 
86*b61987d3SHangbin Liu 	SYS(out, "ip link set lo up");
87*b61987d3SHangbin Liu 	SYS(out, "ip link set tmp1 up");
88*b61987d3SHangbin Liu 	SYS(out, "ip addr replace 198.18.0.2/24 dev tmp1");
89*b61987d3SHangbin Liu 	SYS(out, "sysctl -w net.ipv4.tcp_syncookies=2");
90*b61987d3SHangbin Liu 	SYS(out, "sysctl -w net.ipv4.tcp_timestamps=1");
91*b61987d3SHangbin Liu 	SYS(out, "sysctl -w net.netfilter.nf_conntrack_tcp_loose=0");
92*b61987d3SHangbin Liu 	SYS(out, "iptables-legacy -t raw -I PREROUTING \
93fb5cd0ceSMaxim Mikityanskiy 	    -i tmp1 -p tcp -m tcp --syn --dport 8080 -j CT --notrack");
94*b61987d3SHangbin Liu 	SYS(out, "iptables-legacy -t filter -A INPUT \
95fb5cd0ceSMaxim Mikityanskiy 	    -i tmp1 -p tcp -m tcp --dport 8080 -m state --state INVALID,UNTRACKED \
96fb5cd0ceSMaxim Mikityanskiy 	    -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460");
97*b61987d3SHangbin Liu 	SYS(out, "iptables-legacy -t filter -A INPUT \
98fb5cd0ceSMaxim Mikityanskiy 	    -i tmp1 -m state --state INVALID -j DROP");
99fb5cd0ceSMaxim Mikityanskiy 
100784d5dc0SMaxim Mikityanskiy 	ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --ports 8080 \
101784d5dc0SMaxim Mikityanskiy 			    --single --mss4 1460 --mss6 1440 \
102784d5dc0SMaxim Mikityanskiy 			    --wscale 7 --ttl 64%s", xdp ? "" : " --tc");
103fb5cd0ceSMaxim Mikityanskiy 	size = fread(buf, 1, sizeof(buf), ctrl_file);
104fb5cd0ceSMaxim Mikityanskiy 	pclose(ctrl_file);
105fb5cd0ceSMaxim Mikityanskiy 	if (!expect_str(buf, size, "Total SYNACKs generated: 0\n",
106fb5cd0ceSMaxim Mikityanskiy 			"initial SYNACKs"))
107fb5cd0ceSMaxim Mikityanskiy 		goto out;
108fb5cd0ceSMaxim Mikityanskiy 
109784d5dc0SMaxim Mikityanskiy 	if (!xdp) {
110784d5dc0SMaxim Mikityanskiy 		ctrl_file = SYS_OUT("tc filter show dev tmp1 ingress");
111784d5dc0SMaxim Mikityanskiy 		size = fread(buf, 1, sizeof(buf), ctrl_file);
112784d5dc0SMaxim Mikityanskiy 		pclose(ctrl_file);
113784d5dc0SMaxim Mikityanskiy 		prog_id = memmem(buf, size, " id ", 4);
114784d5dc0SMaxim Mikityanskiy 		if (!ASSERT_OK_PTR(prog_id, "find prog id"))
115784d5dc0SMaxim Mikityanskiy 			goto out;
116784d5dc0SMaxim Mikityanskiy 		prog_id += 4;
117784d5dc0SMaxim Mikityanskiy 		if (!ASSERT_LT(prog_id, buf + size, "find prog id begin"))
118784d5dc0SMaxim Mikityanskiy 			goto out;
119784d5dc0SMaxim Mikityanskiy 		prog_id_end = prog_id;
120784d5dc0SMaxim Mikityanskiy 		while (prog_id_end < buf + size && *prog_id_end >= '0' &&
121784d5dc0SMaxim Mikityanskiy 		       *prog_id_end <= '9')
122784d5dc0SMaxim Mikityanskiy 			prog_id_end++;
123784d5dc0SMaxim Mikityanskiy 		if (!ASSERT_LT(prog_id_end, buf + size, "find prog id end"))
124784d5dc0SMaxim Mikityanskiy 			goto out;
125784d5dc0SMaxim Mikityanskiy 		*prog_id_end = '\0';
126784d5dc0SMaxim Mikityanskiy 	}
127784d5dc0SMaxim Mikityanskiy 
128fb5cd0ceSMaxim Mikityanskiy 	server_fd = start_server(AF_INET, SOCK_STREAM, "198.18.0.2", 8080, 0);
129fb5cd0ceSMaxim Mikityanskiy 	if (!ASSERT_GE(server_fd, 0, "start_server"))
130fb5cd0ceSMaxim Mikityanskiy 		goto out;
131fb5cd0ceSMaxim Mikityanskiy 
132fb5cd0ceSMaxim Mikityanskiy 	close_netns(ns);
133fb5cd0ceSMaxim Mikityanskiy 	ns = NULL;
134fb5cd0ceSMaxim Mikityanskiy 
135fb5cd0ceSMaxim Mikityanskiy 	client_fd = connect_to_fd(server_fd, 10000);
136fb5cd0ceSMaxim Mikityanskiy 	if (!ASSERT_GE(client_fd, 0, "connect_to_fd"))
137fb5cd0ceSMaxim Mikityanskiy 		goto out;
138fb5cd0ceSMaxim Mikityanskiy 
139fb5cd0ceSMaxim Mikityanskiy 	accept_fd = accept(server_fd, NULL, NULL);
140fb5cd0ceSMaxim Mikityanskiy 	if (!ASSERT_GE(accept_fd, 0, "accept"))
141fb5cd0ceSMaxim Mikityanskiy 		goto out;
142fb5cd0ceSMaxim Mikityanskiy 
143fb5cd0ceSMaxim Mikityanskiy 	ns = open_netns("synproxy");
144fb5cd0ceSMaxim Mikityanskiy 	if (!ASSERT_OK_PTR(ns, "setns"))
145fb5cd0ceSMaxim Mikityanskiy 		goto out;
146fb5cd0ceSMaxim Mikityanskiy 
147784d5dc0SMaxim Mikityanskiy 	if (xdp)
148fb5cd0ceSMaxim Mikityanskiy 		ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --single");
149784d5dc0SMaxim Mikityanskiy 	else
150784d5dc0SMaxim Mikityanskiy 		ctrl_file = SYS_OUT("./xdp_synproxy --prog %s --single",
151784d5dc0SMaxim Mikityanskiy 				    prog_id);
152fb5cd0ceSMaxim Mikityanskiy 	size = fread(buf, 1, sizeof(buf), ctrl_file);
153fb5cd0ceSMaxim Mikityanskiy 	pclose(ctrl_file);
154fb5cd0ceSMaxim Mikityanskiy 	if (!expect_str(buf, size, "Total SYNACKs generated: 1\n",
155fb5cd0ceSMaxim Mikityanskiy 			"SYNACKs after connection"))
156fb5cd0ceSMaxim Mikityanskiy 		goto out;
157fb5cd0ceSMaxim Mikityanskiy 
158fb5cd0ceSMaxim Mikityanskiy out:
159fb5cd0ceSMaxim Mikityanskiy 	if (accept_fd >= 0)
160fb5cd0ceSMaxim Mikityanskiy 		close(accept_fd);
161fb5cd0ceSMaxim Mikityanskiy 	if (client_fd >= 0)
162fb5cd0ceSMaxim Mikityanskiy 		close(client_fd);
163fb5cd0ceSMaxim Mikityanskiy 	if (server_fd >= 0)
164fb5cd0ceSMaxim Mikityanskiy 		close(server_fd);
165fb5cd0ceSMaxim Mikityanskiy 	if (ns)
166fb5cd0ceSMaxim Mikityanskiy 		close_netns(ns);
167fb5cd0ceSMaxim Mikityanskiy 
168*b61987d3SHangbin Liu 	SYS_NOFAIL("ip link del tmp0");
169*b61987d3SHangbin Liu 	SYS_NOFAIL("ip netns del synproxy");
170fb5cd0ceSMaxim Mikityanskiy }
171784d5dc0SMaxim Mikityanskiy 
test_xdp_synproxy(void)1729b6a7773SMartin KaFai Lau void test_xdp_synproxy(void)
173784d5dc0SMaxim Mikityanskiy {
174784d5dc0SMaxim Mikityanskiy 	if (test__start_subtest("xdp"))
175784d5dc0SMaxim Mikityanskiy 		test_synproxy(true);
176784d5dc0SMaxim Mikityanskiy 	if (test__start_subtest("tc"))
177784d5dc0SMaxim Mikityanskiy 		test_synproxy(false);
178784d5dc0SMaxim Mikityanskiy }
179