179 lines · c
1// SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause2/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */3 4#define _GNU_SOURCE5#include <test_progs.h>6#include <network_helpers.h>7#include <ctype.h>8 9#define CMD_OUT_BUF_SIZE 102310 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 wrong75 * 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 else150 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}179