Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
0002 /* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
0003 
0004 #define _GNU_SOURCE
0005 #include <test_progs.h>
0006 #include <network_helpers.h>
0007 #include <ctype.h>
0008 
0009 #define CMD_OUT_BUF_SIZE 1023
0010 
0011 #define SYS(cmd) ({ \
0012     if (!ASSERT_OK(system(cmd), (cmd))) \
0013         goto out; \
0014 })
0015 
0016 #define SYS_OUT(cmd, ...) ({ \
0017     char buf[1024]; \
0018     snprintf(buf, sizeof(buf), (cmd), ##__VA_ARGS__); \
0019     FILE *f = popen(buf, "r"); \
0020     if (!ASSERT_OK_PTR(f, buf)) \
0021         goto out; \
0022     f; \
0023 })
0024 
0025 /* out must be at least `size * 4 + 1` bytes long */
0026 static void escape_str(char *out, const char *in, size_t size)
0027 {
0028     static const char *hex = "0123456789ABCDEF";
0029     size_t i;
0030 
0031     for (i = 0; i < size; i++) {
0032         if (isprint(in[i]) && in[i] != '\\' && in[i] != '\'') {
0033             *out++ = in[i];
0034         } else {
0035             *out++ = '\\';
0036             *out++ = 'x';
0037             *out++ = hex[(in[i] >> 4) & 0xf];
0038             *out++ = hex[in[i] & 0xf];
0039         }
0040     }
0041     *out++ = '\0';
0042 }
0043 
0044 static bool expect_str(char *buf, size_t size, const char *str, const char *name)
0045 {
0046     static char escbuf_expected[CMD_OUT_BUF_SIZE * 4];
0047     static char escbuf_actual[CMD_OUT_BUF_SIZE * 4];
0048     static int duration = 0;
0049     bool ok;
0050 
0051     ok = size == strlen(str) && !memcmp(buf, str, size);
0052 
0053     if (!ok) {
0054         escape_str(escbuf_expected, str, strlen(str));
0055         escape_str(escbuf_actual, buf, size);
0056     }
0057     CHECK(!ok, name, "unexpected %s: actual '%s' != expected '%s'\n",
0058           name, escbuf_actual, escbuf_expected);
0059 
0060     return ok;
0061 }
0062 
0063 static void test_synproxy(bool xdp)
0064 {
0065     int server_fd = -1, client_fd = -1, accept_fd = -1;
0066     char *prog_id = NULL, *prog_id_end;
0067     struct nstoken *ns = NULL;
0068     FILE *ctrl_file = NULL;
0069     char buf[CMD_OUT_BUF_SIZE];
0070     size_t size;
0071 
0072     SYS("ip netns add synproxy");
0073 
0074     SYS("ip link add tmp0 type veth peer name tmp1");
0075     SYS("ip link set tmp1 netns synproxy");
0076     SYS("ip link set tmp0 up");
0077     SYS("ip addr replace 198.18.0.1/24 dev tmp0");
0078 
0079     /* When checksum offload is enabled, the XDP program sees wrong
0080      * checksums and drops packets.
0081      */
0082     SYS("ethtool -K tmp0 tx off");
0083     if (xdp)
0084         /* Workaround required for veth. */
0085         SYS("ip link set tmp0 xdp object xdp_dummy.o section xdp 2> /dev/null");
0086 
0087     ns = open_netns("synproxy");
0088     if (!ASSERT_OK_PTR(ns, "setns"))
0089         goto out;
0090 
0091     SYS("ip link set lo up");
0092     SYS("ip link set tmp1 up");
0093     SYS("ip addr replace 198.18.0.2/24 dev tmp1");
0094     SYS("sysctl -w net.ipv4.tcp_syncookies=2");
0095     SYS("sysctl -w net.ipv4.tcp_timestamps=1");
0096     SYS("sysctl -w net.netfilter.nf_conntrack_tcp_loose=0");
0097     SYS("iptables -t raw -I PREROUTING \
0098         -i tmp1 -p tcp -m tcp --syn --dport 8080 -j CT --notrack");
0099     SYS("iptables -t filter -A INPUT \
0100         -i tmp1 -p tcp -m tcp --dport 8080 -m state --state INVALID,UNTRACKED \
0101         -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460");
0102     SYS("iptables -t filter -A INPUT \
0103         -i tmp1 -m state --state INVALID -j DROP");
0104 
0105     ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --ports 8080 \
0106                 --single --mss4 1460 --mss6 1440 \
0107                 --wscale 7 --ttl 64%s", xdp ? "" : " --tc");
0108     size = fread(buf, 1, sizeof(buf), ctrl_file);
0109     pclose(ctrl_file);
0110     if (!expect_str(buf, size, "Total SYNACKs generated: 0\n",
0111             "initial SYNACKs"))
0112         goto out;
0113 
0114     if (!xdp) {
0115         ctrl_file = SYS_OUT("tc filter show dev tmp1 ingress");
0116         size = fread(buf, 1, sizeof(buf), ctrl_file);
0117         pclose(ctrl_file);
0118         prog_id = memmem(buf, size, " id ", 4);
0119         if (!ASSERT_OK_PTR(prog_id, "find prog id"))
0120             goto out;
0121         prog_id += 4;
0122         if (!ASSERT_LT(prog_id, buf + size, "find prog id begin"))
0123             goto out;
0124         prog_id_end = prog_id;
0125         while (prog_id_end < buf + size && *prog_id_end >= '0' &&
0126                *prog_id_end <= '9')
0127             prog_id_end++;
0128         if (!ASSERT_LT(prog_id_end, buf + size, "find prog id end"))
0129             goto out;
0130         *prog_id_end = '\0';
0131     }
0132 
0133     server_fd = start_server(AF_INET, SOCK_STREAM, "198.18.0.2", 8080, 0);
0134     if (!ASSERT_GE(server_fd, 0, "start_server"))
0135         goto out;
0136 
0137     close_netns(ns);
0138     ns = NULL;
0139 
0140     client_fd = connect_to_fd(server_fd, 10000);
0141     if (!ASSERT_GE(client_fd, 0, "connect_to_fd"))
0142         goto out;
0143 
0144     accept_fd = accept(server_fd, NULL, NULL);
0145     if (!ASSERT_GE(accept_fd, 0, "accept"))
0146         goto out;
0147 
0148     ns = open_netns("synproxy");
0149     if (!ASSERT_OK_PTR(ns, "setns"))
0150         goto out;
0151 
0152     if (xdp)
0153         ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --single");
0154     else
0155         ctrl_file = SYS_OUT("./xdp_synproxy --prog %s --single",
0156                     prog_id);
0157     size = fread(buf, 1, sizeof(buf), ctrl_file);
0158     pclose(ctrl_file);
0159     if (!expect_str(buf, size, "Total SYNACKs generated: 1\n",
0160             "SYNACKs after connection"))
0161         goto out;
0162 
0163 out:
0164     if (accept_fd >= 0)
0165         close(accept_fd);
0166     if (client_fd >= 0)
0167         close(client_fd);
0168     if (server_fd >= 0)
0169         close(server_fd);
0170     if (ns)
0171         close_netns(ns);
0172 
0173     system("ip link del tmp0");
0174     system("ip netns del synproxy");
0175 }
0176 
0177 void test_xdp_synproxy(void)
0178 {
0179     if (test__start_subtest("xdp"))
0180         test_synproxy(true);
0181     if (test__start_subtest("tc"))
0182         test_synproxy(false);
0183 }