1 /* $OpenBSD: bindconnect.c,v 1.5 2024/01/04 00:19:17 bluhm Exp $ */ 2 3 /* 4 * Copyright (c) 2023-2024 Alexander Bluhm <bluhm@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/resource.h> 20 #include <sys/socket.h> 21 22 #include <net/route.h> 23 #include <netinet/in.h> 24 #include <arpa/inet.h> 25 26 #include <err.h> 27 #include <errno.h> 28 #include <netdb.h> 29 #include <pthread.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 35 #define MAXIMUM(a, b) ((a) > (b) ? (a) : (b)) 36 37 #define s6_addr8 __u6_addr.__u6_addr8 38 #define s6_addr16 __u6_addr.__u6_addr16 39 #define s6_addr32 __u6_addr.__u6_addr32 40 41 union sockaddr_union { 42 struct sockaddr su_sa; 43 struct sockaddr_in su_sin; 44 struct sockaddr_in6 su_sin6; 45 }; 46 47 union inaddr_union { 48 struct in_addr au_inaddr; 49 struct in6_addr au_in6addr; 50 }; 51 52 int fd_base; 53 unsigned int fd_num = 128; 54 unsigned int run_time = 10; 55 unsigned int socket_num = 1, close_num = 1, bind_num = 1, connect_num = 1, 56 delroute_num = 0; 57 int reuse_port = 0; 58 union inaddr_union addr, mask; 59 int af = AF_INET, type, proto = IPPROTO_UDP, prefix = -1, route_sock = -1; 60 61 static void __dead 62 usage(void) 63 { 64 fprintf(stderr, 65 "bindconnect [-r] [-b bind] [-c connect] [-d delroute] " 66 "[-f family] [-N addr/net] [-n num] [-o close] [-p proto] " 67 "[-s socket] [-t time]\n" 68 " -b bind threads binding sockets, default %u\n" 69 " -c connect threads connecting sockets, default %u\n" 70 " -d delroute threads deleting cloned routes, default %u\n" 71 " -f family address family inet or inet6, default inet\n" 72 " -N addr/net connect to any address within network\n" 73 " -n num number of file descriptors, default %u\n" 74 " -o close threads closing sockets, default %u\n" 75 " -p proto protocol udp, tcp, name or number, default udp\n" 76 " -r set reuse port socket option\n" 77 " -s socket threads creating sockets, default %u\n" 78 " -t time run time in seconds, default %u\n", 79 bind_num, connect_num, delroute_num, fd_num, close_num, 80 socket_num, run_time); 81 exit(2); 82 } 83 84 static void 85 in_prefixlen2mask(struct in_addr *maskp, int plen) 86 { 87 if (plen == 0) 88 maskp->s_addr = 0; 89 else 90 maskp->s_addr = htonl(0xffffffff << (32 - plen)); 91 } 92 93 static void 94 in6_prefixlen2mask(struct in6_addr *maskp, int len) 95 { 96 u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; 97 int bytelen, bitlen, i; 98 99 bzero(maskp, sizeof(*maskp)); 100 bytelen = len / 8; 101 bitlen = len % 8; 102 for (i = 0; i < bytelen; i++) 103 maskp->s6_addr[i] = 0xff; 104 /* len == 128 is ok because bitlen == 0 then */ 105 if (bitlen) 106 maskp->s6_addr[bytelen] = maskarray[bitlen - 1]; 107 } 108 109 static void 110 fill_sockaddr(union sockaddr_union *su) 111 { 112 memset(su, 0, sizeof(*su)); 113 su->su_sa.sa_family = af; 114 if (af == AF_INET) { 115 su->su_sin.sin_len = sizeof(su->su_sin); 116 if (prefix >= 0) 117 su->su_sin.sin_addr = addr.au_inaddr; 118 else 119 su->su_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 120 } 121 if (af == AF_INET6) { 122 su->su_sin6.sin6_len = sizeof(su->su_sin6); 123 if (prefix >= 0) 124 su->su_sin6.sin6_addr = addr.au_in6addr; 125 else 126 su->su_sin6.sin6_addr = in6addr_loopback; 127 } 128 } 129 130 static void 131 mask_sockaddr(union sockaddr_union *su) 132 { 133 if (af == AF_INET) { 134 if (prefix >=0 && prefix != 32) { 135 su->su_sin.sin_addr.s_addr &= 136 mask.au_inaddr.s_addr; 137 /* do only 8 bits variation, routes should be reused */ 138 su->su_sin.sin_addr.s_addr |= htonl(255) & 139 ~mask.au_inaddr.s_addr & arc4random(); 140 } 141 } 142 if (af == AF_INET6) { 143 if (prefix >=0 && prefix != 128) { 144 su->su_sin6.sin6_addr.s6_addr32[0] &= 145 mask.au_in6addr.s6_addr32[0]; 146 su->su_sin6.sin6_addr.s6_addr32[1] &= 147 mask.au_in6addr.s6_addr32[1]; 148 su->su_sin6.sin6_addr.s6_addr32[2] &= 149 mask.au_in6addr.s6_addr32[2]; 150 su->su_sin6.sin6_addr.s6_addr32[3] &= 151 mask.au_in6addr.s6_addr32[3]; 152 /* do only 8 bits variation, routes should be reused */ 153 su->su_sin6.sin6_addr.s6_addr32[3] |= htonl(255) & 154 ~mask.au_in6addr.s6_addr32[3] & arc4random(); 155 } 156 } 157 } 158 159 static void * 160 thread_socket(void *arg) 161 { 162 volatile int *run = arg; 163 unsigned long count; 164 int fd; 165 166 for (count = 0; *run; count++) { 167 int opt; 168 169 fd = socket(af, type | SOCK_NONBLOCK, proto); 170 if (fd < 0 || !reuse_port) 171 continue; 172 opt = 1; 173 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)); 174 } 175 176 return (void *)count; 177 } 178 179 static void * 180 thread_close(void *arg) 181 { 182 volatile int *run = arg; 183 unsigned long count; 184 int fd; 185 186 for (count = 0; *run; count++) { 187 fd = fd_base + arc4random_uniform(fd_num); 188 close(fd); 189 } 190 191 return (void *)count; 192 } 193 194 static void * 195 thread_bind(void *arg) 196 { 197 volatile int *run = arg; 198 unsigned long count; 199 int fd; 200 union sockaddr_union su; 201 202 fill_sockaddr(&su); 203 204 for (count = 0; *run; count++) { 205 fd = fd_base + arc4random_uniform(fd_num); 206 bind(fd, &su.su_sa, su.su_sa.sa_len); 207 } 208 209 return (void *)count; 210 } 211 212 static void * 213 thread_connect(void *arg) 214 { 215 volatile int *run = arg; 216 unsigned long count; 217 int fd; 218 union sockaddr_union su; 219 220 fill_sockaddr(&su); 221 222 for (count = 0; *run; count++) { 223 fd = fd_base + arc4random_uniform(fd_num); 224 mask_sockaddr(&su); 225 if (af == AF_INET) 226 su.su_sin.sin_port = arc4random(); 227 if (af == AF_INET6) 228 su.su_sin6.sin6_port = arc4random(); 229 connect(fd, &su.su_sa, su.su_sa.sa_len); 230 } 231 232 return (void *)count; 233 } 234 235 static void * 236 thread_delroute(void *arg) 237 { 238 volatile int *run = arg; 239 unsigned long count; 240 int seq = 0; 241 struct { 242 struct rt_msghdr m_rtm; 243 char m_space[512]; 244 } m_rtmsg; 245 union sockaddr_union su; 246 247 #define rtm \ 248 m_rtmsg.m_rtm 249 #define ROUNDUP(a) \ 250 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 251 #define ADVANCE(x, n) \ 252 (x += ROUNDUP((n)->sa_len)) 253 #define NEXTADDR(w, sa) \ 254 if (rtm.rtm_addrs & (w)) { \ 255 int l = ROUNDUP((sa)->sa_len); \ 256 memcpy(cp, (sa), l); \ 257 cp += l; \ 258 } 259 260 memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 261 rtm.rtm_type = RTM_DELETE; 262 rtm.rtm_flags = RTF_HOST; 263 rtm.rtm_version = RTM_VERSION; 264 rtm.rtm_addrs = RTA_DST; 265 rtm.rtm_hdrlen = sizeof(rtm); 266 267 fill_sockaddr(&su); 268 269 for (count = 0; *run; count++) { 270 char *cp = m_rtmsg.m_space; 271 272 rtm.rtm_seq = ++seq; 273 mask_sockaddr(&su); 274 NEXTADDR(RTA_DST, &su.su_sa); 275 rtm.rtm_msglen = cp - (char *)&m_rtmsg; 276 write(route_sock, &m_rtmsg, rtm.rtm_msglen); 277 } 278 279 #undef rtm 280 #undef ROUNDUP 281 #undef ADVANCE 282 #undef NEXTADDR 283 284 return (void *)count; 285 } 286 287 int 288 main(int argc, char *argv[]) 289 { 290 struct rlimit rlim; 291 struct protoent *pent; 292 pthread_t *tsocket, *tclose, *tbind, *tconnect, *tdelroute; 293 const char *errstr, *addr_net = NULL; 294 char buf[128], *p; 295 int ch, run; 296 unsigned int n; 297 unsigned long socket_count, close_count, bind_count, connect_count, 298 delroute_count; 299 union sockaddr_union su; 300 301 while ((ch = getopt(argc, argv, "b:c:d:f:N:n:o:p:rs:t:")) != -1) { 302 switch (ch) { 303 case 'b': 304 bind_num = strtonum(optarg, 0, UINT_MAX, &errstr); 305 if (errstr != NULL) 306 errx(1, "bind is %s: %s", errstr, optarg); 307 break; 308 case 'c': 309 connect_num = strtonum(optarg, 0, UINT_MAX, &errstr); 310 if (errstr != NULL) 311 errx(1, "connect is %s: %s", errstr, optarg); 312 break; 313 case 'd': 314 delroute_num = strtonum(optarg, 0, UINT_MAX, &errstr); 315 if (errstr != NULL) 316 errx(1, "delroute is %s: %s", errstr, optarg); 317 break; 318 case 'f': 319 if (strcmp(optarg, "inet") == 0) 320 af = AF_INET; 321 else if (strcmp(optarg, "inet6") == 0) 322 af = AF_INET6; 323 else 324 errx(1, "bad address family %s", optarg); 325 break; 326 case 'N': 327 addr_net = optarg; 328 break; 329 case 'n': 330 fd_num = strtonum(optarg, 1, INT_MAX, &errstr); 331 if (errstr != NULL) 332 errx(1, "num is %s: %s", errstr, optarg); 333 break; 334 case 'o': 335 close_num = strtonum(optarg, 0, UINT_MAX, &errstr); 336 if (errstr != NULL) 337 errx(1, "close is %s: %s", errstr, optarg); 338 break; 339 case 'p': 340 pent = getprotobyname(optarg); 341 if (pent != NULL) { 342 proto = pent->p_proto; 343 break; 344 } 345 proto = strtonum(optarg, 0, IPPROTO_MAX -1 , &errstr); 346 if (errstr != NULL) 347 errx(1, "proto is %s: %s", errstr, optarg); 348 break; 349 case 'r': 350 reuse_port = 1; 351 break; 352 case 's': 353 socket_num = strtonum(optarg, 0, UINT_MAX, &errstr); 354 if (errstr != NULL) 355 errx(1, "socket is %s: %s", errstr, optarg); 356 break; 357 case 't': 358 run_time = strtonum(optarg, 0, UINT_MAX, &errstr); 359 if (errstr != NULL) 360 errx(1, "time is %s: %s", errstr, optarg); 361 break; 362 default: 363 usage(); 364 } 365 } 366 argc -= optind; 367 argv += optind; 368 if (argc > 0) 369 usage(); 370 371 /* split addr/net into addr, mask, prefix */ 372 if (addr_net != NULL) { 373 prefix = inet_net_pton(af, addr_net, &addr, sizeof(addr)); 374 if (prefix < 0) 375 err(1, "inet_net_pton %s", addr_net); 376 if (af == AF_INET6) { 377 /* 378 * Man page says inet_net_pton() preserves lower 379 * bits. That is not true, call inet_pton() again. 380 */ 381 if (strlcpy(buf, addr_net, sizeof(buf)) >= sizeof(buf)) 382 err(1, "strlcpy %s", addr_net); 383 p = strchr(buf, '/'); 384 if (p != NULL ) { 385 *p = '\0'; 386 if (inet_pton(af, buf, &addr) < 0) 387 err(1, "inet_pton %s", buf); 388 } 389 } 390 if (af == AF_INET) 391 in_prefixlen2mask(&mask.au_inaddr, prefix); 392 if (af == AF_INET6) 393 in6_prefixlen2mask(&mask.au_in6addr, prefix); 394 } 395 396 /* preopen route socket before file descriptor limits are set */ 397 if (delroute_num > 0) { 398 if (prefix < 0 || prefix == 32) 399 errx(1, "delroute %u needs addr/net", delroute_num); 400 route_sock = socket(AF_ROUTE, SOCK_RAW, af); 401 if (route_sock < 0) 402 err(1, "socket route"); 403 if (shutdown(route_sock, SHUT_RD) < 0) 404 err(1, "shutdown read route"); 405 } 406 407 /* detect lowest file desciptor, test bind, close everything above */ 408 switch (proto) { 409 case IPPROTO_TCP: 410 type = SOCK_STREAM; 411 break; 412 case IPPROTO_UDP: 413 type = SOCK_DGRAM; 414 break; 415 default: 416 type = SOCK_RAW; 417 break; 418 } 419 fd_base = socket(af, type, proto); 420 if (fd_base < 0) 421 err(1, "socket fd_base"); 422 if (fd_base > INT_MAX - (int)fd_num) 423 err(1, "fd base %d and num %u overflow", fd_base, fd_num); 424 fill_sockaddr(&su); 425 if (bind(fd_base, &su.su_sa, su.su_sa.sa_len) < 0) 426 err(1, "bind %s", inet_ntop(af, &addr, buf, sizeof(buf))); 427 if (closefrom(fd_base) < 0) 428 err(1, "closefrom %d", fd_base); 429 430 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) 431 err(1, "getrlimit"); 432 rlim.rlim_max = MAXIMUM(rlim.rlim_max, fd_base + fd_num); 433 rlim.rlim_cur = fd_base + fd_num; 434 if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) 435 err(1, "setrlimit %llu", rlim.rlim_cur); 436 437 run = 1; 438 439 tsocket = calloc(socket_num, sizeof(pthread_t)); 440 if (tsocket == NULL) 441 err(1, "tsocket"); 442 for (n = 0; n < socket_num; n++) { 443 errno = pthread_create(&tsocket[n], NULL, thread_socket, &run); 444 if (errno) 445 err(1, "pthread_create socket %u", n); 446 } 447 448 tclose = calloc(close_num, sizeof(pthread_t)); 449 if (tclose == NULL) 450 err(1, "tclose"); 451 for (n = 0; n < close_num; n++) { 452 errno = pthread_create(&tclose[n], NULL, thread_close, &run); 453 if (errno) 454 err(1, "pthread_create close %u", n); 455 } 456 457 tbind = calloc(bind_num, sizeof(pthread_t)); 458 if (tbind == NULL) 459 err(1, "tbind"); 460 for (n = 0; n < bind_num; n++) { 461 errno = pthread_create(&tbind[n], NULL, thread_bind, &run); 462 if (errno) 463 err(1, "pthread_create bind %u", n); 464 } 465 466 tconnect = calloc(connect_num, sizeof(pthread_t)); 467 if (tconnect == NULL) 468 err(1, "tconnect"); 469 for (n = 0; n < connect_num; n++) { 470 errno = pthread_create(&tconnect[n], NULL, thread_connect, 471 &run); 472 if (errno) 473 err(1, "pthread_create connect %u", n); 474 } 475 476 tdelroute = calloc(delroute_num, sizeof(pthread_t)); 477 if (tdelroute == NULL) 478 err(1, "tdelroute"); 479 for (n = 0; n < delroute_num; n++) { 480 errno = pthread_create(&tdelroute[n], NULL, thread_delroute, 481 &run); 482 if (errno) 483 err(1, "pthread_create delroute %u", n); 484 } 485 486 if (run_time > 0) { 487 if (sleep(run_time) < 0) 488 err(1, "sleep %u", run_time); 489 } 490 491 run = 0; 492 socket_count = 0; 493 for (n = 0; n < socket_num; n++) { 494 unsigned long count; 495 496 errno = pthread_join(tsocket[n], (void **)&count); 497 if (errno) 498 err(1, "pthread_join socket %u", n); 499 socket_count += count; 500 } 501 free(tsocket); 502 503 close_count = 0; 504 for (n = 0; n < close_num; n++) { 505 unsigned long count; 506 507 errno = pthread_join(tclose[n], (void **)&count); 508 if (errno) 509 err(1, "pthread_join close %u", n); 510 close_count += count; 511 } 512 free(tclose); 513 514 bind_count = 0; 515 for (n = 0; n < bind_num; n++) { 516 unsigned long count; 517 518 errno = pthread_join(tbind[n], (void **)&count); 519 if (errno) 520 err(1, "pthread_join bind %u", n); 521 bind_count += count; 522 } 523 free(tbind); 524 525 connect_count = 0; 526 for (n = 0; n < connect_num; n++) { 527 unsigned long count; 528 529 errno = pthread_join(tconnect[n], (void **)&count); 530 if (errno) 531 err(1, "pthread_join connect %u", n); 532 connect_count += count; 533 } 534 free(tconnect); 535 536 delroute_count = 0; 537 for (n = 0; n < delroute_num; n++) { 538 unsigned long count; 539 540 errno = pthread_join(tdelroute[n], (void **)&count); 541 if (errno) 542 err(1, "pthread_join delroute %u", n); 543 delroute_count += count; 544 } 545 free(tdelroute); 546 547 printf("count: socket %lu, close %lu, bind %lu, connect %lu, " 548 "delroute %lu\n", 549 socket_count, close_count, bind_count, connect_count, 550 delroute_count); 551 552 return 0; 553 } 554