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