Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (c) 2018 Facebook
0003 // Copyright (c) 2019 Cloudflare
0004 // Copyright (c) 2020 Isovalent, Inc.
0005 /*
0006  * Test that the socket assign program is able to redirect traffic towards a
0007  * socket, regardless of whether the port or address destination of the traffic
0008  * matches the port.
0009  */
0010 
0011 #define _GNU_SOURCE
0012 #include <fcntl.h>
0013 #include <signal.h>
0014 #include <stdlib.h>
0015 #include <unistd.h>
0016 
0017 #include "test_progs.h"
0018 
0019 #define BIND_PORT 1234
0020 #define CONNECT_PORT 4321
0021 #define TEST_DADDR (0xC0A80203)
0022 #define NS_SELF "/proc/self/ns/net"
0023 #define SERVER_MAP_PATH "/sys/fs/bpf/tc/globals/server_map"
0024 
0025 static const struct timeval timeo_sec = { .tv_sec = 3 };
0026 static const size_t timeo_optlen = sizeof(timeo_sec);
0027 static int stop, duration;
0028 
0029 static bool
0030 configure_stack(void)
0031 {
0032     char tc_cmd[BUFSIZ];
0033 
0034     /* Move to a new networking namespace */
0035     if (CHECK_FAIL(unshare(CLONE_NEWNET)))
0036         return false;
0037 
0038     /* Configure necessary links, routes */
0039     if (CHECK_FAIL(system("ip link set dev lo up")))
0040         return false;
0041     if (CHECK_FAIL(system("ip route add local default dev lo")))
0042         return false;
0043     if (CHECK_FAIL(system("ip -6 route add local default dev lo")))
0044         return false;
0045 
0046     /* Load qdisc, BPF program */
0047     if (CHECK_FAIL(system("tc qdisc add dev lo clsact")))
0048         return false;
0049     sprintf(tc_cmd, "%s %s %s %s", "tc filter add dev lo ingress bpf",
0050                "direct-action object-file ./test_sk_assign.o",
0051                "section tc",
0052                (env.verbosity < VERBOSE_VERY) ? " 2>/dev/null" : "verbose");
0053     if (CHECK(system(tc_cmd), "BPF load failed;",
0054           "run with -vv for more info\n"))
0055         return false;
0056 
0057     return true;
0058 }
0059 
0060 static int
0061 start_server(const struct sockaddr *addr, socklen_t len, int type)
0062 {
0063     int fd;
0064 
0065     fd = socket(addr->sa_family, type, 0);
0066     if (CHECK_FAIL(fd == -1))
0067         goto out;
0068     if (CHECK_FAIL(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo_sec,
0069                   timeo_optlen)))
0070         goto close_out;
0071     if (CHECK_FAIL(bind(fd, addr, len) == -1))
0072         goto close_out;
0073     if (type == SOCK_STREAM && CHECK_FAIL(listen(fd, 128) == -1))
0074         goto close_out;
0075 
0076     goto out;
0077 close_out:
0078     close(fd);
0079     fd = -1;
0080 out:
0081     return fd;
0082 }
0083 
0084 static int
0085 connect_to_server(const struct sockaddr *addr, socklen_t len, int type)
0086 {
0087     int fd = -1;
0088 
0089     fd = socket(addr->sa_family, type, 0);
0090     if (CHECK_FAIL(fd == -1))
0091         goto out;
0092     if (CHECK_FAIL(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo_sec,
0093                   timeo_optlen)))
0094         goto close_out;
0095     if (CHECK_FAIL(connect(fd, addr, len)))
0096         goto close_out;
0097 
0098     goto out;
0099 close_out:
0100     close(fd);
0101     fd = -1;
0102 out:
0103     return fd;
0104 }
0105 
0106 static in_port_t
0107 get_port(int fd)
0108 {
0109     struct sockaddr_storage ss;
0110     socklen_t slen = sizeof(ss);
0111     in_port_t port = 0;
0112 
0113     if (CHECK_FAIL(getsockname(fd, (struct sockaddr *)&ss, &slen)))
0114         return port;
0115 
0116     switch (ss.ss_family) {
0117     case AF_INET:
0118         port = ((struct sockaddr_in *)&ss)->sin_port;
0119         break;
0120     case AF_INET6:
0121         port = ((struct sockaddr_in6 *)&ss)->sin6_port;
0122         break;
0123     default:
0124         CHECK(1, "Invalid address family", "%d\n", ss.ss_family);
0125     }
0126     return port;
0127 }
0128 
0129 static ssize_t
0130 rcv_msg(int srv_client, int type)
0131 {
0132     struct sockaddr_storage ss;
0133     char buf[BUFSIZ];
0134     socklen_t slen;
0135 
0136     if (type == SOCK_STREAM)
0137         return read(srv_client, &buf, sizeof(buf));
0138     else
0139         return recvfrom(srv_client, &buf, sizeof(buf), 0,
0140                 (struct sockaddr *)&ss, &slen);
0141 }
0142 
0143 static int
0144 run_test(int server_fd, const struct sockaddr *addr, socklen_t len, int type)
0145 {
0146     int client = -1, srv_client = -1;
0147     char buf[] = "testing";
0148     in_port_t port;
0149     int ret = 1;
0150 
0151     client = connect_to_server(addr, len, type);
0152     if (client == -1) {
0153         perror("Cannot connect to server");
0154         goto out;
0155     }
0156 
0157     if (type == SOCK_STREAM) {
0158         srv_client = accept(server_fd, NULL, NULL);
0159         if (CHECK_FAIL(srv_client == -1)) {
0160             perror("Can't accept connection");
0161             goto out;
0162         }
0163     } else {
0164         srv_client = server_fd;
0165     }
0166     if (CHECK_FAIL(write(client, buf, sizeof(buf)) != sizeof(buf))) {
0167         perror("Can't write on client");
0168         goto out;
0169     }
0170     if (CHECK_FAIL(rcv_msg(srv_client, type) != sizeof(buf))) {
0171         perror("Can't read on server");
0172         goto out;
0173     }
0174 
0175     port = get_port(srv_client);
0176     if (CHECK_FAIL(!port))
0177         goto out;
0178     /* SOCK_STREAM is connected via accept(), so the server's local address
0179      * will be the CONNECT_PORT rather than the BIND port that corresponds
0180      * to the listen socket. SOCK_DGRAM on the other hand is connectionless
0181      * so we can't really do the same check there; the server doesn't ever
0182      * create a socket with CONNECT_PORT.
0183      */
0184     if (type == SOCK_STREAM &&
0185         CHECK(port != htons(CONNECT_PORT), "Expected", "port %u but got %u",
0186           CONNECT_PORT, ntohs(port)))
0187         goto out;
0188     else if (type == SOCK_DGRAM &&
0189          CHECK(port != htons(BIND_PORT), "Expected",
0190                "port %u but got %u", BIND_PORT, ntohs(port)))
0191         goto out;
0192 
0193     ret = 0;
0194 out:
0195     close(client);
0196     if (srv_client != server_fd)
0197         close(srv_client);
0198     if (ret)
0199         WRITE_ONCE(stop, 1);
0200     return ret;
0201 }
0202 
0203 static void
0204 prepare_addr(struct sockaddr *addr, int family, __u16 port, bool rewrite_addr)
0205 {
0206     struct sockaddr_in *addr4;
0207     struct sockaddr_in6 *addr6;
0208 
0209     switch (family) {
0210     case AF_INET:
0211         addr4 = (struct sockaddr_in *)addr;
0212         memset(addr4, 0, sizeof(*addr4));
0213         addr4->sin_family = family;
0214         addr4->sin_port = htons(port);
0215         if (rewrite_addr)
0216             addr4->sin_addr.s_addr = htonl(TEST_DADDR);
0217         else
0218             addr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
0219         break;
0220     case AF_INET6:
0221         addr6 = (struct sockaddr_in6 *)addr;
0222         memset(addr6, 0, sizeof(*addr6));
0223         addr6->sin6_family = family;
0224         addr6->sin6_port = htons(port);
0225         addr6->sin6_addr = in6addr_loopback;
0226         if (rewrite_addr)
0227             addr6->sin6_addr.s6_addr32[3] = htonl(TEST_DADDR);
0228         break;
0229     default:
0230         fprintf(stderr, "Invalid family %d", family);
0231     }
0232 }
0233 
0234 struct test_sk_cfg {
0235     const char *name;
0236     int family;
0237     struct sockaddr *addr;
0238     socklen_t len;
0239     int type;
0240     bool rewrite_addr;
0241 };
0242 
0243 #define TEST(NAME, FAMILY, TYPE, REWRITE)               \
0244 {                                   \
0245     .name = NAME,                           \
0246     .family = FAMILY,                       \
0247     .addr = (FAMILY == AF_INET) ? (struct sockaddr *)&addr4     \
0248                     : (struct sockaddr *)&addr6,    \
0249     .len = (FAMILY == AF_INET) ? sizeof(addr4) : sizeof(addr6), \
0250     .type = TYPE,                           \
0251     .rewrite_addr = REWRITE,                    \
0252 }
0253 
0254 void test_sk_assign(void)
0255 {
0256     struct sockaddr_in addr4;
0257     struct sockaddr_in6 addr6;
0258     struct test_sk_cfg tests[] = {
0259         TEST("ipv4 tcp port redir", AF_INET, SOCK_STREAM, false),
0260         TEST("ipv4 tcp addr redir", AF_INET, SOCK_STREAM, true),
0261         TEST("ipv6 tcp port redir", AF_INET6, SOCK_STREAM, false),
0262         TEST("ipv6 tcp addr redir", AF_INET6, SOCK_STREAM, true),
0263         TEST("ipv4 udp port redir", AF_INET, SOCK_DGRAM, false),
0264         TEST("ipv4 udp addr redir", AF_INET, SOCK_DGRAM, true),
0265         TEST("ipv6 udp port redir", AF_INET6, SOCK_DGRAM, false),
0266         TEST("ipv6 udp addr redir", AF_INET6, SOCK_DGRAM, true),
0267     };
0268     __s64 server = -1;
0269     int server_map;
0270     int self_net;
0271     int i;
0272 
0273     self_net = open(NS_SELF, O_RDONLY);
0274     if (CHECK_FAIL(self_net < 0)) {
0275         perror("Unable to open "NS_SELF);
0276         return;
0277     }
0278 
0279     if (!configure_stack()) {
0280         perror("configure_stack");
0281         goto cleanup;
0282     }
0283 
0284     server_map = bpf_obj_get(SERVER_MAP_PATH);
0285     if (CHECK_FAIL(server_map < 0)) {
0286         perror("Unable to open " SERVER_MAP_PATH);
0287         goto cleanup;
0288     }
0289 
0290     for (i = 0; i < ARRAY_SIZE(tests) && !READ_ONCE(stop); i++) {
0291         struct test_sk_cfg *test = &tests[i];
0292         const struct sockaddr *addr;
0293         const int zero = 0;
0294         int err;
0295 
0296         if (!test__start_subtest(test->name))
0297             continue;
0298         prepare_addr(test->addr, test->family, BIND_PORT, false);
0299         addr = (const struct sockaddr *)test->addr;
0300         server = start_server(addr, test->len, test->type);
0301         if (server == -1)
0302             goto close;
0303 
0304         err = bpf_map_update_elem(server_map, &zero, &server, BPF_ANY);
0305         if (CHECK_FAIL(err)) {
0306             perror("Unable to update server_map");
0307             goto close;
0308         }
0309 
0310         /* connect to unbound ports */
0311         prepare_addr(test->addr, test->family, CONNECT_PORT,
0312                  test->rewrite_addr);
0313         if (run_test(server, addr, test->len, test->type))
0314             goto close;
0315 
0316         close(server);
0317         server = -1;
0318     }
0319 
0320 close:
0321     close(server);
0322     close(server_map);
0323 cleanup:
0324     if (CHECK_FAIL(unlink(SERVER_MAP_PATH)))
0325         perror("Unable to unlink " SERVER_MAP_PATH);
0326     if (CHECK_FAIL(setns(self_net, CLONE_NEWNET)))
0327         perror("Failed to setns("NS_SELF")");
0328     close(self_net);
0329 }