Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1// SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
  2/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
  3
  4#define _GNU_SOURCE
  5#include <test_progs.h>
  6#include <network_helpers.h>
  7#include <ctype.h>
  8
  9#define CMD_OUT_BUF_SIZE 1023
 10
 11#define SYS_OUT(cmd, ...) ({ \
 12	char buf[1024]; \
 13	snprintf(buf, sizeof(buf), (cmd), ##__VA_ARGS__); \
 14	FILE *f = popen(buf, "r"); \
 15	if (!ASSERT_OK_PTR(f, buf)) \
 16		goto out; \
 17	f; \
 18})
 19
 20/* out must be at least `size * 4 + 1` bytes long */
 21static void escape_str(char *out, const char *in, size_t size)
 22{
 23	static const char *hex = "0123456789ABCDEF";
 24	size_t i;
 25
 26	for (i = 0; i < size; i++) {
 27		if (isprint(in[i]) && in[i] != '\\' && in[i] != '\'') {
 28			*out++ = in[i];
 29		} else {
 30			*out++ = '\\';
 31			*out++ = 'x';
 32			*out++ = hex[(in[i] >> 4) & 0xf];
 33			*out++ = hex[in[i] & 0xf];
 34		}
 35	}
 36	*out++ = '\0';
 37}
 38
 39static bool expect_str(char *buf, size_t size, const char *str, const char *name)
 40{
 41	static char escbuf_expected[CMD_OUT_BUF_SIZE * 4];
 42	static char escbuf_actual[CMD_OUT_BUF_SIZE * 4];
 43	static int duration = 0;
 44	bool ok;
 45
 46	ok = size == strlen(str) && !memcmp(buf, str, size);
 47
 48	if (!ok) {
 49		escape_str(escbuf_expected, str, strlen(str));
 50		escape_str(escbuf_actual, buf, size);
 51	}
 52	CHECK(!ok, name, "unexpected %s: actual '%s' != expected '%s'\n",
 53	      name, escbuf_actual, escbuf_expected);
 54
 55	return ok;
 56}
 57
 58static void test_synproxy(bool xdp)
 59{
 60	int server_fd = -1, client_fd = -1, accept_fd = -1;
 61	char *prog_id = NULL, *prog_id_end;
 62	struct nstoken *ns = NULL;
 63	FILE *ctrl_file = NULL;
 64	char buf[CMD_OUT_BUF_SIZE];
 65	size_t size;
 66
 67	SYS(out, "ip netns add synproxy");
 68
 69	SYS(out, "ip link add tmp0 type veth peer name tmp1");
 70	SYS(out, "ip link set tmp1 netns synproxy");
 71	SYS(out, "ip link set tmp0 up");
 72	SYS(out, "ip addr replace 198.18.0.1/24 dev tmp0");
 73
 74	/* When checksum offload is enabled, the XDP program sees wrong
 75	 * checksums and drops packets.
 76	 */
 77	SYS(out, "ethtool -K tmp0 tx off");
 78	if (xdp)
 79		/* Workaround required for veth. */
 80		SYS(out, "ip link set tmp0 xdp object xdp_dummy.bpf.o section xdp 2> /dev/null");
 81
 82	ns = open_netns("synproxy");
 83	if (!ASSERT_OK_PTR(ns, "setns"))
 84		goto out;
 85
 86	SYS(out, "ip link set lo up");
 87	SYS(out, "ip link set tmp1 up");
 88	SYS(out, "ip addr replace 198.18.0.2/24 dev tmp1");
 89	SYS(out, "sysctl -w net.ipv4.tcp_syncookies=2");
 90	SYS(out, "sysctl -w net.ipv4.tcp_timestamps=1");
 91	SYS(out, "sysctl -w net.netfilter.nf_conntrack_tcp_loose=0");
 92	SYS(out, "iptables-legacy -t raw -I PREROUTING \
 93	    -i tmp1 -p tcp -m tcp --syn --dport 8080 -j CT --notrack");
 94	SYS(out, "iptables-legacy -t filter -A INPUT \
 95	    -i tmp1 -p tcp -m tcp --dport 8080 -m state --state INVALID,UNTRACKED \
 96	    -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460");
 97	SYS(out, "iptables-legacy -t filter -A INPUT \
 98	    -i tmp1 -m state --state INVALID -j DROP");
 99
100	ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --ports 8080 \
101			    --single --mss4 1460 --mss6 1440 \
102			    --wscale 7 --ttl 64%s", xdp ? "" : " --tc");
103	size = fread(buf, 1, sizeof(buf), ctrl_file);
104	pclose(ctrl_file);
105	if (!expect_str(buf, size, "Total SYNACKs generated: 0\n",
106			"initial SYNACKs"))
107		goto out;
108
109	if (!xdp) {
110		ctrl_file = SYS_OUT("tc filter show dev tmp1 ingress");
111		size = fread(buf, 1, sizeof(buf), ctrl_file);
112		pclose(ctrl_file);
113		prog_id = memmem(buf, size, " id ", 4);
114		if (!ASSERT_OK_PTR(prog_id, "find prog id"))
115			goto out;
116		prog_id += 4;
117		if (!ASSERT_LT(prog_id, buf + size, "find prog id begin"))
118			goto out;
119		prog_id_end = prog_id;
120		while (prog_id_end < buf + size && *prog_id_end >= '0' &&
121		       *prog_id_end <= '9')
122			prog_id_end++;
123		if (!ASSERT_LT(prog_id_end, buf + size, "find prog id end"))
124			goto out;
125		*prog_id_end = '\0';
126	}
127
128	server_fd = start_server(AF_INET, SOCK_STREAM, "198.18.0.2", 8080, 0);
129	if (!ASSERT_GE(server_fd, 0, "start_server"))
130		goto out;
131
132	close_netns(ns);
133	ns = NULL;
134
135	client_fd = connect_to_fd(server_fd, 10000);
136	if (!ASSERT_GE(client_fd, 0, "connect_to_fd"))
137		goto out;
138
139	accept_fd = accept(server_fd, NULL, NULL);
140	if (!ASSERT_GE(accept_fd, 0, "accept"))
141		goto out;
142
143	ns = open_netns("synproxy");
144	if (!ASSERT_OK_PTR(ns, "setns"))
145		goto out;
146
147	if (xdp)
148		ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --single");
149	else
150		ctrl_file = SYS_OUT("./xdp_synproxy --prog %s --single",
151				    prog_id);
152	size = fread(buf, 1, sizeof(buf), ctrl_file);
153	pclose(ctrl_file);
154	if (!expect_str(buf, size, "Total SYNACKs generated: 1\n",
155			"SYNACKs after connection"))
156		goto out;
157
158out:
159	if (accept_fd >= 0)
160		close(accept_fd);
161	if (client_fd >= 0)
162		close(client_fd);
163	if (server_fd >= 0)
164		close(server_fd);
165	if (ns)
166		close_netns(ns);
167
168	SYS_NOFAIL("ip link del tmp0");
169	SYS_NOFAIL("ip netns del synproxy");
170}
171
172void test_xdp_synproxy(void)
173{
174	if (test__start_subtest("xdp"))
175		test_synproxy(true);
176	if (test__start_subtest("tc"))
177		test_synproxy(false);
178}