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