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
usage(void)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
in_prefixlen2mask(struct in_addr * maskp,int plen)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
in6_prefixlen2mask(struct in6_addr * maskp,int len)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
fill_sockaddr(union sockaddr_union * su)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
mask_sockaddr(union sockaddr_union * su)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 *
thread_socket(void * arg)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 *
thread_close(void * arg)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 *
thread_bind(void * arg)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 *
thread_connect(void * arg)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 *
thread_delroute(void * arg)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
main(int argc,char * argv[])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