1 // SPDX-License-Identifier: GPL-2.0-only 2 #define _GNU_SOURCE 3 4 #include <errno.h> 5 #include <stdbool.h> 6 #include <stdio.h> 7 #include <string.h> 8 #include <unistd.h> 9 #include <sched.h> 10 11 #include <arpa/inet.h> 12 #include <sys/mount.h> 13 #include <sys/stat.h> 14 15 #include <linux/err.h> 16 #include <linux/in.h> 17 #include <linux/in6.h> 18 #include <linux/limits.h> 19 20 #include "bpf_util.h" 21 #include "network_helpers.h" 22 #include "test_progs.h" 23 24 #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 25 #define log_err(MSG, ...) ({ \ 26 int __save = errno; \ 27 fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", \ 28 __FILE__, __LINE__, clean_errno(), \ 29 ##__VA_ARGS__); \ 30 errno = __save; \ 31 }) 32 33 struct ipv4_packet pkt_v4 = { 34 .eth.h_proto = __bpf_constant_htons(ETH_P_IP), 35 .iph.ihl = 5, 36 .iph.protocol = IPPROTO_TCP, 37 .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES), 38 .tcp.urg_ptr = 123, 39 .tcp.doff = 5, 40 }; 41 42 struct ipv6_packet pkt_v6 = { 43 .eth.h_proto = __bpf_constant_htons(ETH_P_IPV6), 44 .iph.nexthdr = IPPROTO_TCP, 45 .iph.payload_len = __bpf_constant_htons(MAGIC_BYTES), 46 .tcp.urg_ptr = 123, 47 .tcp.doff = 5, 48 }; 49 50 int settimeo(int fd, int timeout_ms) 51 { 52 struct timeval timeout = { .tv_sec = 3 }; 53 54 if (timeout_ms > 0) { 55 timeout.tv_sec = timeout_ms / 1000; 56 timeout.tv_usec = (timeout_ms % 1000) * 1000; 57 } 58 59 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, 60 sizeof(timeout))) { 61 log_err("Failed to set SO_RCVTIMEO"); 62 return -1; 63 } 64 65 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, 66 sizeof(timeout))) { 67 log_err("Failed to set SO_SNDTIMEO"); 68 return -1; 69 } 70 71 return 0; 72 } 73 74 #define save_errno_close(fd) ({ int __save = errno; close(fd); errno = __save; }) 75 76 static int __start_server(int type, const struct sockaddr *addr, 77 socklen_t addrlen, int timeout_ms, bool reuseport) 78 { 79 int on = 1; 80 int fd; 81 82 fd = socket(addr->sa_family, type, 0); 83 if (fd < 0) { 84 log_err("Failed to create server socket"); 85 return -1; 86 } 87 88 if (settimeo(fd, timeout_ms)) 89 goto error_close; 90 91 if (reuseport && 92 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) { 93 log_err("Failed to set SO_REUSEPORT"); 94 return -1; 95 } 96 97 if (bind(fd, addr, addrlen) < 0) { 98 log_err("Failed to bind socket"); 99 goto error_close; 100 } 101 102 if (type == SOCK_STREAM) { 103 if (listen(fd, 1) < 0) { 104 log_err("Failed to listed on socket"); 105 goto error_close; 106 } 107 } 108 109 return fd; 110 111 error_close: 112 save_errno_close(fd); 113 return -1; 114 } 115 116 int start_server(int family, int type, const char *addr_str, __u16 port, 117 int timeout_ms) 118 { 119 struct sockaddr_storage addr; 120 socklen_t addrlen; 121 122 if (make_sockaddr(family, addr_str, port, &addr, &addrlen)) 123 return -1; 124 125 return __start_server(type, (struct sockaddr *)&addr, 126 addrlen, timeout_ms, false); 127 } 128 129 int *start_reuseport_server(int family, int type, const char *addr_str, 130 __u16 port, int timeout_ms, unsigned int nr_listens) 131 { 132 struct sockaddr_storage addr; 133 unsigned int nr_fds = 0; 134 socklen_t addrlen; 135 int *fds; 136 137 if (!nr_listens) 138 return NULL; 139 140 if (make_sockaddr(family, addr_str, port, &addr, &addrlen)) 141 return NULL; 142 143 fds = malloc(sizeof(*fds) * nr_listens); 144 if (!fds) 145 return NULL; 146 147 fds[0] = __start_server(type, (struct sockaddr *)&addr, addrlen, 148 timeout_ms, true); 149 if (fds[0] == -1) 150 goto close_fds; 151 nr_fds = 1; 152 153 if (getsockname(fds[0], (struct sockaddr *)&addr, &addrlen)) 154 goto close_fds; 155 156 for (; nr_fds < nr_listens; nr_fds++) { 157 fds[nr_fds] = __start_server(type, (struct sockaddr *)&addr, 158 addrlen, timeout_ms, true); 159 if (fds[nr_fds] == -1) 160 goto close_fds; 161 } 162 163 return fds; 164 165 close_fds: 166 free_fds(fds, nr_fds); 167 return NULL; 168 } 169 170 void free_fds(int *fds, unsigned int nr_close_fds) 171 { 172 if (fds) { 173 while (nr_close_fds) 174 close(fds[--nr_close_fds]); 175 free(fds); 176 } 177 } 178 179 int fastopen_connect(int server_fd, const char *data, unsigned int data_len, 180 int timeout_ms) 181 { 182 struct sockaddr_storage addr; 183 socklen_t addrlen = sizeof(addr); 184 struct sockaddr_in *addr_in; 185 int fd, ret; 186 187 if (getsockname(server_fd, (struct sockaddr *)&addr, &addrlen)) { 188 log_err("Failed to get server addr"); 189 return -1; 190 } 191 192 addr_in = (struct sockaddr_in *)&addr; 193 fd = socket(addr_in->sin_family, SOCK_STREAM, 0); 194 if (fd < 0) { 195 log_err("Failed to create client socket"); 196 return -1; 197 } 198 199 if (settimeo(fd, timeout_ms)) 200 goto error_close; 201 202 ret = sendto(fd, data, data_len, MSG_FASTOPEN, (struct sockaddr *)&addr, 203 addrlen); 204 if (ret != data_len) { 205 log_err("sendto(data, %u) != %d\n", data_len, ret); 206 goto error_close; 207 } 208 209 return fd; 210 211 error_close: 212 save_errno_close(fd); 213 return -1; 214 } 215 216 static int connect_fd_to_addr(int fd, 217 const struct sockaddr_storage *addr, 218 socklen_t addrlen, const bool must_fail) 219 { 220 int ret; 221 222 errno = 0; 223 ret = connect(fd, (const struct sockaddr *)addr, addrlen); 224 if (must_fail) { 225 if (!ret) { 226 log_err("Unexpected success to connect to server"); 227 return -1; 228 } 229 if (errno != EPERM) { 230 log_err("Unexpected error from connect to server"); 231 return -1; 232 } 233 } else { 234 if (ret) { 235 log_err("Failed to connect to server"); 236 return -1; 237 } 238 } 239 240 return 0; 241 } 242 243 static const struct network_helper_opts default_opts; 244 245 int connect_to_fd_opts(int server_fd, const struct network_helper_opts *opts) 246 { 247 struct sockaddr_storage addr; 248 struct sockaddr_in *addr_in; 249 socklen_t addrlen, optlen; 250 int fd, type; 251 252 if (!opts) 253 opts = &default_opts; 254 255 optlen = sizeof(type); 256 if (getsockopt(server_fd, SOL_SOCKET, SO_TYPE, &type, &optlen)) { 257 log_err("getsockopt(SOL_TYPE)"); 258 return -1; 259 } 260 261 addrlen = sizeof(addr); 262 if (getsockname(server_fd, (struct sockaddr *)&addr, &addrlen)) { 263 log_err("Failed to get server addr"); 264 return -1; 265 } 266 267 addr_in = (struct sockaddr_in *)&addr; 268 fd = socket(addr_in->sin_family, type, 0); 269 if (fd < 0) { 270 log_err("Failed to create client socket"); 271 return -1; 272 } 273 274 if (settimeo(fd, opts->timeout_ms)) 275 goto error_close; 276 277 if (opts->cc && opts->cc[0] && 278 setsockopt(fd, SOL_TCP, TCP_CONGESTION, opts->cc, 279 strlen(opts->cc) + 1)) 280 goto error_close; 281 282 if (connect_fd_to_addr(fd, &addr, addrlen, opts->must_fail)) 283 goto error_close; 284 285 return fd; 286 287 error_close: 288 save_errno_close(fd); 289 return -1; 290 } 291 292 int connect_to_fd(int server_fd, int timeout_ms) 293 { 294 struct network_helper_opts opts = { 295 .timeout_ms = timeout_ms, 296 }; 297 298 return connect_to_fd_opts(server_fd, &opts); 299 } 300 301 int connect_fd_to_fd(int client_fd, int server_fd, int timeout_ms) 302 { 303 struct sockaddr_storage addr; 304 socklen_t len = sizeof(addr); 305 306 if (settimeo(client_fd, timeout_ms)) 307 return -1; 308 309 if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) { 310 log_err("Failed to get server addr"); 311 return -1; 312 } 313 314 if (connect_fd_to_addr(client_fd, &addr, len, false)) 315 return -1; 316 317 return 0; 318 } 319 320 int make_sockaddr(int family, const char *addr_str, __u16 port, 321 struct sockaddr_storage *addr, socklen_t *len) 322 { 323 if (family == AF_INET) { 324 struct sockaddr_in *sin = (void *)addr; 325 326 memset(addr, 0, sizeof(*sin)); 327 sin->sin_family = AF_INET; 328 sin->sin_port = htons(port); 329 if (addr_str && 330 inet_pton(AF_INET, addr_str, &sin->sin_addr) != 1) { 331 log_err("inet_pton(AF_INET, %s)", addr_str); 332 return -1; 333 } 334 if (len) 335 *len = sizeof(*sin); 336 return 0; 337 } else if (family == AF_INET6) { 338 struct sockaddr_in6 *sin6 = (void *)addr; 339 340 memset(addr, 0, sizeof(*sin6)); 341 sin6->sin6_family = AF_INET6; 342 sin6->sin6_port = htons(port); 343 if (addr_str && 344 inet_pton(AF_INET6, addr_str, &sin6->sin6_addr) != 1) { 345 log_err("inet_pton(AF_INET6, %s)", addr_str); 346 return -1; 347 } 348 if (len) 349 *len = sizeof(*sin6); 350 return 0; 351 } 352 return -1; 353 } 354 355 char *ping_command(int family) 356 { 357 if (family == AF_INET6) { 358 /* On some systems 'ping' doesn't support IPv6, so use ping6 if it is present. */ 359 if (!system("which ping6 >/dev/null 2>&1")) 360 return "ping6"; 361 else 362 return "ping -6"; 363 } 364 return "ping"; 365 } 366 367 struct nstoken { 368 int orig_netns_fd; 369 }; 370 371 static int setns_by_fd(int nsfd) 372 { 373 int err; 374 375 err = setns(nsfd, CLONE_NEWNET); 376 close(nsfd); 377 378 if (!ASSERT_OK(err, "setns")) 379 return err; 380 381 /* Switch /sys to the new namespace so that e.g. /sys/class/net 382 * reflects the devices in the new namespace. 383 */ 384 err = unshare(CLONE_NEWNS); 385 if (!ASSERT_OK(err, "unshare")) 386 return err; 387 388 /* Make our /sys mount private, so the following umount won't 389 * trigger the global umount in case it's shared. 390 */ 391 err = mount("none", "/sys", NULL, MS_PRIVATE, NULL); 392 if (!ASSERT_OK(err, "remount private /sys")) 393 return err; 394 395 err = umount2("/sys", MNT_DETACH); 396 if (!ASSERT_OK(err, "umount2 /sys")) 397 return err; 398 399 err = mount("sysfs", "/sys", "sysfs", 0, NULL); 400 if (!ASSERT_OK(err, "mount /sys")) 401 return err; 402 403 err = mount("bpffs", "/sys/fs/bpf", "bpf", 0, NULL); 404 if (!ASSERT_OK(err, "mount /sys/fs/bpf")) 405 return err; 406 407 return 0; 408 } 409 410 struct nstoken *open_netns(const char *name) 411 { 412 int nsfd; 413 char nspath[PATH_MAX]; 414 int err; 415 struct nstoken *token; 416 417 token = malloc(sizeof(struct nstoken)); 418 if (!ASSERT_OK_PTR(token, "malloc token")) 419 return NULL; 420 421 token->orig_netns_fd = open("/proc/self/ns/net", O_RDONLY); 422 if (!ASSERT_GE(token->orig_netns_fd, 0, "open /proc/self/ns/net")) 423 goto fail; 424 425 snprintf(nspath, sizeof(nspath), "%s/%s", "/var/run/netns", name); 426 nsfd = open(nspath, O_RDONLY | O_CLOEXEC); 427 if (!ASSERT_GE(nsfd, 0, "open netns fd")) 428 goto fail; 429 430 err = setns_by_fd(nsfd); 431 if (!ASSERT_OK(err, "setns_by_fd")) 432 goto fail; 433 434 return token; 435 fail: 436 free(token); 437 return NULL; 438 } 439 440 void close_netns(struct nstoken *token) 441 { 442 ASSERT_OK(setns_by_fd(token->orig_netns_fd), "setns_by_fd"); 443 free(token); 444 } 445