1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2018 Facebook 3 // Copyright (c) 2019 Cloudflare 4 // Copyright (c) 2020 Isovalent, Inc. 5 /* 6 * Test that the socket assign program is able to redirect traffic towards a 7 * socket, regardless of whether the port or address destination of the traffic 8 * matches the port. 9 */ 10 11 #define _GNU_SOURCE 12 #include <fcntl.h> 13 #include <signal.h> 14 #include <stdlib.h> 15 #include <unistd.h> 16 17 #include "test_progs.h" 18 19 #define BIND_PORT 1234 20 #define CONNECT_PORT 4321 21 #define TEST_DADDR (0xC0A80203) 22 #define NS_SELF "/proc/self/ns/net" 23 24 static const struct timeval timeo_sec = { .tv_sec = 3 }; 25 static const size_t timeo_optlen = sizeof(timeo_sec); 26 static int stop, duration; 27 28 static bool 29 configure_stack(void) 30 { 31 char tc_cmd[BUFSIZ]; 32 33 /* Move to a new networking namespace */ 34 if (CHECK_FAIL(unshare(CLONE_NEWNET))) 35 return false; 36 37 /* Configure necessary links, routes */ 38 if (CHECK_FAIL(system("ip link set dev lo up"))) 39 return false; 40 if (CHECK_FAIL(system("ip route add local default dev lo"))) 41 return false; 42 if (CHECK_FAIL(system("ip -6 route add local default dev lo"))) 43 return false; 44 45 /* Load qdisc, BPF program */ 46 if (CHECK_FAIL(system("tc qdisc add dev lo clsact"))) 47 return false; 48 sprintf(tc_cmd, "%s %s %s %s", "tc filter add dev lo ingress bpf", 49 "direct-action object-file ./test_sk_assign.o", 50 "section classifier/sk_assign_test", 51 (env.verbosity < VERBOSE_VERY) ? " 2>/dev/null" : ""); 52 if (CHECK(system(tc_cmd), "BPF load failed;", 53 "run with -vv for more info\n")) 54 return false; 55 56 return true; 57 } 58 59 static int 60 start_server(const struct sockaddr *addr, socklen_t len, int type) 61 { 62 int fd; 63 64 fd = socket(addr->sa_family, type, 0); 65 if (CHECK_FAIL(fd == -1)) 66 goto out; 67 if (CHECK_FAIL(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo_sec, 68 timeo_optlen))) 69 goto close_out; 70 if (CHECK_FAIL(bind(fd, addr, len) == -1)) 71 goto close_out; 72 if (type == SOCK_STREAM && CHECK_FAIL(listen(fd, 128) == -1)) 73 goto close_out; 74 75 goto out; 76 close_out: 77 close(fd); 78 fd = -1; 79 out: 80 return fd; 81 } 82 83 static int 84 connect_to_server(const struct sockaddr *addr, socklen_t len, int type) 85 { 86 int fd = -1; 87 88 fd = socket(addr->sa_family, type, 0); 89 if (CHECK_FAIL(fd == -1)) 90 goto out; 91 if (CHECK_FAIL(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo_sec, 92 timeo_optlen))) 93 goto close_out; 94 if (CHECK_FAIL(connect(fd, addr, len))) 95 goto close_out; 96 97 goto out; 98 close_out: 99 close(fd); 100 fd = -1; 101 out: 102 return fd; 103 } 104 105 static in_port_t 106 get_port(int fd) 107 { 108 struct sockaddr_storage ss; 109 socklen_t slen = sizeof(ss); 110 in_port_t port = 0; 111 112 if (CHECK_FAIL(getsockname(fd, (struct sockaddr *)&ss, &slen))) 113 return port; 114 115 switch (ss.ss_family) { 116 case AF_INET: 117 port = ((struct sockaddr_in *)&ss)->sin_port; 118 break; 119 case AF_INET6: 120 port = ((struct sockaddr_in6 *)&ss)->sin6_port; 121 break; 122 default: 123 CHECK(1, "Invalid address family", "%d\n", ss.ss_family); 124 } 125 return port; 126 } 127 128 static ssize_t 129 rcv_msg(int srv_client, int type) 130 { 131 struct sockaddr_storage ss; 132 char buf[BUFSIZ]; 133 socklen_t slen; 134 135 if (type == SOCK_STREAM) 136 return read(srv_client, &buf, sizeof(buf)); 137 else 138 return recvfrom(srv_client, &buf, sizeof(buf), 0, 139 (struct sockaddr *)&ss, &slen); 140 } 141 142 static int 143 run_test(int server_fd, const struct sockaddr *addr, socklen_t len, int type) 144 { 145 int client = -1, srv_client = -1; 146 char buf[] = "testing"; 147 in_port_t port; 148 int ret = 1; 149 150 client = connect_to_server(addr, len, type); 151 if (client == -1) { 152 perror("Cannot connect to server"); 153 goto out; 154 } 155 156 if (type == SOCK_STREAM) { 157 srv_client = accept(server_fd, NULL, NULL); 158 if (CHECK_FAIL(srv_client == -1)) { 159 perror("Can't accept connection"); 160 goto out; 161 } 162 } else { 163 srv_client = server_fd; 164 } 165 if (CHECK_FAIL(write(client, buf, sizeof(buf)) != sizeof(buf))) { 166 perror("Can't write on client"); 167 goto out; 168 } 169 if (CHECK_FAIL(rcv_msg(srv_client, type) != sizeof(buf))) { 170 perror("Can't read on server"); 171 goto out; 172 } 173 174 port = get_port(srv_client); 175 if (CHECK_FAIL(!port)) 176 goto out; 177 /* SOCK_STREAM is connected via accept(), so the server's local address 178 * will be the CONNECT_PORT rather than the BIND port that corresponds 179 * to the listen socket. SOCK_DGRAM on the other hand is connectionless 180 * so we can't really do the same check there; the server doesn't ever 181 * create a socket with CONNECT_PORT. 182 */ 183 if (type == SOCK_STREAM && 184 CHECK(port != htons(CONNECT_PORT), "Expected", "port %u but got %u", 185 CONNECT_PORT, ntohs(port))) 186 goto out; 187 else if (type == SOCK_DGRAM && 188 CHECK(port != htons(BIND_PORT), "Expected", 189 "port %u but got %u", BIND_PORT, ntohs(port))) 190 goto out; 191 192 ret = 0; 193 out: 194 close(client); 195 if (srv_client != server_fd) 196 close(srv_client); 197 if (ret) 198 WRITE_ONCE(stop, 1); 199 return ret; 200 } 201 202 static void 203 prepare_addr(struct sockaddr *addr, int family, __u16 port, bool rewrite_addr) 204 { 205 struct sockaddr_in *addr4; 206 struct sockaddr_in6 *addr6; 207 208 switch (family) { 209 case AF_INET: 210 addr4 = (struct sockaddr_in *)addr; 211 memset(addr4, 0, sizeof(*addr4)); 212 addr4->sin_family = family; 213 addr4->sin_port = htons(port); 214 if (rewrite_addr) 215 addr4->sin_addr.s_addr = htonl(TEST_DADDR); 216 else 217 addr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 218 break; 219 case AF_INET6: 220 addr6 = (struct sockaddr_in6 *)addr; 221 memset(addr6, 0, sizeof(*addr6)); 222 addr6->sin6_family = family; 223 addr6->sin6_port = htons(port); 224 addr6->sin6_addr = in6addr_loopback; 225 if (rewrite_addr) 226 addr6->sin6_addr.s6_addr32[3] = htonl(TEST_DADDR); 227 break; 228 default: 229 fprintf(stderr, "Invalid family %d", family); 230 } 231 } 232 233 struct test_sk_cfg { 234 const char *name; 235 int family; 236 struct sockaddr *addr; 237 socklen_t len; 238 int type; 239 bool rewrite_addr; 240 }; 241 242 #define TEST(NAME, FAMILY, TYPE, REWRITE) \ 243 { \ 244 .name = NAME, \ 245 .family = FAMILY, \ 246 .addr = (FAMILY == AF_INET) ? (struct sockaddr *)&addr4 \ 247 : (struct sockaddr *)&addr6, \ 248 .len = (FAMILY == AF_INET) ? sizeof(addr4) : sizeof(addr6), \ 249 .type = TYPE, \ 250 .rewrite_addr = REWRITE, \ 251 } 252 253 void test_sk_assign(void) 254 { 255 struct sockaddr_in addr4; 256 struct sockaddr_in6 addr6; 257 struct test_sk_cfg tests[] = { 258 TEST("ipv4 tcp port redir", AF_INET, SOCK_STREAM, false), 259 TEST("ipv4 tcp addr redir", AF_INET, SOCK_STREAM, true), 260 TEST("ipv6 tcp port redir", AF_INET6, SOCK_STREAM, false), 261 TEST("ipv6 tcp addr redir", AF_INET6, SOCK_STREAM, true), 262 TEST("ipv4 udp port redir", AF_INET, SOCK_DGRAM, false), 263 TEST("ipv4 udp addr redir", AF_INET, SOCK_DGRAM, true), 264 TEST("ipv6 udp port redir", AF_INET6, SOCK_DGRAM, false), 265 TEST("ipv6 udp addr redir", AF_INET6, SOCK_DGRAM, true), 266 }; 267 int server = -1; 268 int self_net; 269 270 self_net = open(NS_SELF, O_RDONLY); 271 if (CHECK_FAIL(self_net < 0)) { 272 perror("Unable to open "NS_SELF); 273 return; 274 } 275 276 if (!configure_stack()) { 277 perror("configure_stack"); 278 goto cleanup; 279 } 280 281 for (int i = 0; i < ARRAY_SIZE(tests) && !READ_ONCE(stop); i++) { 282 struct test_sk_cfg *test = &tests[i]; 283 const struct sockaddr *addr; 284 285 if (!test__start_subtest(test->name)) 286 continue; 287 prepare_addr(test->addr, test->family, BIND_PORT, false); 288 addr = (const struct sockaddr *)test->addr; 289 server = start_server(addr, test->len, test->type); 290 if (server == -1) 291 goto cleanup; 292 293 /* connect to unbound ports */ 294 prepare_addr(test->addr, test->family, CONNECT_PORT, 295 test->rewrite_addr); 296 if (run_test(server, addr, test->len, test->type)) 297 goto close; 298 299 close(server); 300 server = -1; 301 } 302 303 close: 304 close(server); 305 cleanup: 306 if (CHECK_FAIL(setns(self_net, CLONE_NEWNET))) 307 perror("Failed to setns("NS_SELF")"); 308 close(self_net); 309 } 310