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