1*234e5132Sbluhm /*	$OpenBSD: bindconnect.c,v 1.5 2024/01/04 00:19:17 bluhm Exp $	*/
26dd7abcaSbluhm 
36dd7abcaSbluhm /*
4*234e5132Sbluhm  * Copyright (c) 2023-2024 Alexander Bluhm <bluhm@openbsd.org>
56dd7abcaSbluhm  *
66dd7abcaSbluhm  * Permission to use, copy, modify, and distribute this software for any
76dd7abcaSbluhm  * purpose with or without fee is hereby granted, provided that the above
86dd7abcaSbluhm  * copyright notice and this permission notice appear in all copies.
96dd7abcaSbluhm  *
106dd7abcaSbluhm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
116dd7abcaSbluhm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
126dd7abcaSbluhm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
136dd7abcaSbluhm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
146dd7abcaSbluhm  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
156dd7abcaSbluhm  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
166dd7abcaSbluhm  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176dd7abcaSbluhm  */
186dd7abcaSbluhm 
196dd7abcaSbluhm #include <sys/resource.h>
206dd7abcaSbluhm #include <sys/socket.h>
216dd7abcaSbluhm 
220d0a919fSbluhm #include <net/route.h>
236dd7abcaSbluhm #include <netinet/in.h>
240d0a919fSbluhm #include <arpa/inet.h>
256dd7abcaSbluhm 
266dd7abcaSbluhm #include <err.h>
276dd7abcaSbluhm #include <errno.h>
28ba17659fSbluhm #include <netdb.h>
296dd7abcaSbluhm #include <pthread.h>
306dd7abcaSbluhm #include <stdio.h>
316dd7abcaSbluhm #include <stdlib.h>
326dd7abcaSbluhm #include <string.h>
336dd7abcaSbluhm #include <unistd.h>
346dd7abcaSbluhm 
35ba17659fSbluhm #define MAXIMUM(a, b)	((a) > (b) ? (a) : (b))
366dd7abcaSbluhm 
37dd1c5868Sbluhm #define s6_addr8	__u6_addr.__u6_addr8
38dd1c5868Sbluhm #define s6_addr16	__u6_addr.__u6_addr16
39dd1c5868Sbluhm #define s6_addr32	__u6_addr.__u6_addr32
40dd1c5868Sbluhm 
41dd1c5868Sbluhm union sockaddr_union {
42dd1c5868Sbluhm 	struct sockaddr		su_sa;
43dd1c5868Sbluhm 	struct sockaddr_in	su_sin;
44dd1c5868Sbluhm 	struct sockaddr_in6	su_sin6;
45dd1c5868Sbluhm };
46dd1c5868Sbluhm 
47dd1c5868Sbluhm union inaddr_union {
48dd1c5868Sbluhm 	struct in_addr	au_inaddr;
49dd1c5868Sbluhm 	struct in6_addr	au_in6addr;
50dd1c5868Sbluhm };
51dd1c5868Sbluhm 
526dd7abcaSbluhm int fd_base;
530d0a919fSbluhm unsigned int fd_num = 128;
546dd7abcaSbluhm unsigned int run_time = 10;
550d0a919fSbluhm unsigned int socket_num = 1, close_num = 1, bind_num = 1, connect_num = 1,
560d0a919fSbluhm     delroute_num = 0;
570d0a919fSbluhm int reuse_port = 0;
58dd1c5868Sbluhm union inaddr_union addr, mask;
59ba17659fSbluhm int af = AF_INET, type, proto = IPPROTO_UDP, prefix = -1, route_sock = -1;
606dd7abcaSbluhm 
616dd7abcaSbluhm static void __dead
usage(void)626dd7abcaSbluhm usage(void)
636dd7abcaSbluhm {
646dd7abcaSbluhm 	fprintf(stderr,
65*234e5132Sbluhm 	    "bindconnect [-r] [-b bind] [-c connect] [-d delroute] "
66*234e5132Sbluhm 	    "[-f family] [-N addr/net] [-n num] [-o close] [-p proto] "
67*234e5132Sbluhm 	    "[-s socket] [-t time]\n"
686dd7abcaSbluhm 	    "    -b bind      threads binding sockets, default %u\n"
696dd7abcaSbluhm 	    "    -c connect   threads connecting sockets, default %u\n"
700d0a919fSbluhm 	    "    -d delroute  threads deleting cloned routes, default %u\n"
71ba17659fSbluhm 	    "    -f family    address family inet or inet6, default inet\n"
720d0a919fSbluhm 	    "    -N addr/net  connect to any address within network\n"
736dd7abcaSbluhm 	    "    -n num       number of file descriptors, default %u\n"
746dd7abcaSbluhm 	    "    -o close     threads closing sockets, default %u\n"
75ba17659fSbluhm 	    "    -p proto     protocol udp, tcp, name or number, default udp\n"
760d0a919fSbluhm 	    "    -r           set reuse port socket option\n"
776dd7abcaSbluhm 	    "    -s socket    threads creating sockets, default %u\n"
786dd7abcaSbluhm 	    "    -t time      run time in seconds, default %u\n",
79ba17659fSbluhm 	    bind_num, connect_num, delroute_num, fd_num, close_num,
80dd1c5868Sbluhm 	    socket_num, run_time);
816dd7abcaSbluhm 	exit(2);
826dd7abcaSbluhm }
836dd7abcaSbluhm 
840d0a919fSbluhm static void
in_prefixlen2mask(struct in_addr * maskp,int plen)850d0a919fSbluhm in_prefixlen2mask(struct in_addr *maskp, int plen)
860d0a919fSbluhm {
870d0a919fSbluhm 	if (plen == 0)
880d0a919fSbluhm 		maskp->s_addr = 0;
890d0a919fSbluhm 	else
900d0a919fSbluhm 		maskp->s_addr = htonl(0xffffffff << (32 - plen));
910d0a919fSbluhm }
920d0a919fSbluhm 
93dd1c5868Sbluhm static void
in6_prefixlen2mask(struct in6_addr * maskp,int len)94dd1c5868Sbluhm in6_prefixlen2mask(struct in6_addr *maskp, int len)
95dd1c5868Sbluhm {
96dd1c5868Sbluhm 	u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
97dd1c5868Sbluhm 	int bytelen, bitlen, i;
98dd1c5868Sbluhm 
99dd1c5868Sbluhm 	bzero(maskp, sizeof(*maskp));
100dd1c5868Sbluhm 	bytelen = len / 8;
101dd1c5868Sbluhm 	bitlen = len % 8;
102dd1c5868Sbluhm 	for (i = 0; i < bytelen; i++)
103dd1c5868Sbluhm 		maskp->s6_addr[i] = 0xff;
104dd1c5868Sbluhm 	/* len == 128 is ok because bitlen == 0 then */
105dd1c5868Sbluhm 	if (bitlen)
106dd1c5868Sbluhm 		maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
107dd1c5868Sbluhm }
108dd1c5868Sbluhm 
109dd1c5868Sbluhm static void
fill_sockaddr(union sockaddr_union * su)110dd1c5868Sbluhm fill_sockaddr(union sockaddr_union *su)
111dd1c5868Sbluhm {
112dd1c5868Sbluhm 	memset(su, 0, sizeof(*su));
113dd1c5868Sbluhm 	su->su_sa.sa_family = af;
114dd1c5868Sbluhm 	if (af == AF_INET) {
115dd1c5868Sbluhm 		su->su_sin.sin_len = sizeof(su->su_sin);
116dd1c5868Sbluhm 		if (prefix >= 0)
117dd1c5868Sbluhm 			su->su_sin.sin_addr = addr.au_inaddr;
118dd1c5868Sbluhm 		else
119dd1c5868Sbluhm 			su->su_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
120dd1c5868Sbluhm 	}
121dd1c5868Sbluhm 	if (af == AF_INET6) {
122dd1c5868Sbluhm 		su->su_sin6.sin6_len = sizeof(su->su_sin6);
123dd1c5868Sbluhm 		if (prefix >= 0)
124dd1c5868Sbluhm 			su->su_sin6.sin6_addr = addr.au_in6addr;
125dd1c5868Sbluhm 		else
126dd1c5868Sbluhm 			su->su_sin6.sin6_addr = in6addr_loopback;
127dd1c5868Sbluhm 	}
128dd1c5868Sbluhm }
129dd1c5868Sbluhm 
130dd1c5868Sbluhm static void
mask_sockaddr(union sockaddr_union * su)131dd1c5868Sbluhm mask_sockaddr(union sockaddr_union *su)
132dd1c5868Sbluhm {
133dd1c5868Sbluhm 	if (af == AF_INET) {
134dd1c5868Sbluhm 		if (prefix >=0 && prefix != 32) {
135dd1c5868Sbluhm 			su->su_sin.sin_addr.s_addr &=
136dd1c5868Sbluhm 			    mask.au_inaddr.s_addr;
137dd1c5868Sbluhm 			/* do only 8 bits variation, routes should be reused */
138dd1c5868Sbluhm 			su->su_sin.sin_addr.s_addr |= htonl(255) &
139dd1c5868Sbluhm 			    ~mask.au_inaddr.s_addr & arc4random();
140dd1c5868Sbluhm 		}
141dd1c5868Sbluhm 	}
142dd1c5868Sbluhm 	if (af == AF_INET6) {
143dd1c5868Sbluhm 		if (prefix >=0 && prefix != 128) {
144dd1c5868Sbluhm 			su->su_sin6.sin6_addr.s6_addr32[0] &=
145dd1c5868Sbluhm 			    mask.au_in6addr.s6_addr32[0];
146dd1c5868Sbluhm 			su->su_sin6.sin6_addr.s6_addr32[1] &=
147dd1c5868Sbluhm 			    mask.au_in6addr.s6_addr32[1];
148dd1c5868Sbluhm 			su->su_sin6.sin6_addr.s6_addr32[2] &=
149dd1c5868Sbluhm 			    mask.au_in6addr.s6_addr32[2];
150dd1c5868Sbluhm 			su->su_sin6.sin6_addr.s6_addr32[3] &=
151dd1c5868Sbluhm 			    mask.au_in6addr.s6_addr32[3];
152dd1c5868Sbluhm 			/* do only 8 bits variation, routes should be reused */
153dd1c5868Sbluhm 			su->su_sin6.sin6_addr.s6_addr32[3] |= htonl(255) &
154dd1c5868Sbluhm 			    ~mask.au_in6addr.s6_addr32[3] & arc4random();
155dd1c5868Sbluhm 		}
156dd1c5868Sbluhm 	}
157dd1c5868Sbluhm }
158dd1c5868Sbluhm 
1596dd7abcaSbluhm static void *
thread_socket(void * arg)1606dd7abcaSbluhm thread_socket(void *arg)
1616dd7abcaSbluhm {
1626dd7abcaSbluhm 	volatile int *run = arg;
1636dd7abcaSbluhm 	unsigned long count;
1640d0a919fSbluhm 	int fd;
1656dd7abcaSbluhm 
1666dd7abcaSbluhm 	for (count = 0; *run; count++) {
1670d0a919fSbluhm 		int opt;
1680d0a919fSbluhm 
169ba17659fSbluhm 		fd = socket(af, type | SOCK_NONBLOCK, proto);
1700d0a919fSbluhm 		if (fd < 0 || !reuse_port)
1710d0a919fSbluhm 			continue;
1720d0a919fSbluhm 		opt = 1;
1730d0a919fSbluhm 		setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
1746dd7abcaSbluhm 	}
1756dd7abcaSbluhm 
1766dd7abcaSbluhm 	return (void *)count;
1776dd7abcaSbluhm }
1786dd7abcaSbluhm 
1796dd7abcaSbluhm static void *
thread_close(void * arg)1806dd7abcaSbluhm thread_close(void *arg)
1816dd7abcaSbluhm {
1826dd7abcaSbluhm 	volatile int *run = arg;
1836dd7abcaSbluhm 	unsigned long count;
1846dd7abcaSbluhm 	int fd;
1856dd7abcaSbluhm 
1866dd7abcaSbluhm 	for (count = 0; *run; count++) {
1876dd7abcaSbluhm 		fd = fd_base + arc4random_uniform(fd_num);
1886dd7abcaSbluhm 		close(fd);
1896dd7abcaSbluhm 	}
1906dd7abcaSbluhm 
1916dd7abcaSbluhm 	return (void *)count;
1926dd7abcaSbluhm }
1936dd7abcaSbluhm 
1946dd7abcaSbluhm static void *
thread_bind(void * arg)1956dd7abcaSbluhm thread_bind(void *arg)
1966dd7abcaSbluhm {
1976dd7abcaSbluhm 	volatile int *run = arg;
1986dd7abcaSbluhm 	unsigned long count;
1996dd7abcaSbluhm 	int fd;
200dd1c5868Sbluhm 	union sockaddr_union su;
2016dd7abcaSbluhm 
202dd1c5868Sbluhm 	fill_sockaddr(&su);
2030d0a919fSbluhm 
2046dd7abcaSbluhm 	for (count = 0; *run; count++) {
2056dd7abcaSbluhm 		fd = fd_base + arc4random_uniform(fd_num);
206dd1c5868Sbluhm 		bind(fd, &su.su_sa, su.su_sa.sa_len);
2076dd7abcaSbluhm 	}
2086dd7abcaSbluhm 
2096dd7abcaSbluhm 	return (void *)count;
2106dd7abcaSbluhm }
2116dd7abcaSbluhm 
2126dd7abcaSbluhm static void *
thread_connect(void * arg)2136dd7abcaSbluhm thread_connect(void *arg)
2146dd7abcaSbluhm {
2156dd7abcaSbluhm 	volatile int *run = arg;
2166dd7abcaSbluhm 	unsigned long count;
2176dd7abcaSbluhm 	int fd;
218dd1c5868Sbluhm 	union sockaddr_union su;
2196dd7abcaSbluhm 
220dd1c5868Sbluhm 	fill_sockaddr(&su);
2216dd7abcaSbluhm 
2226dd7abcaSbluhm 	for (count = 0; *run; count++) {
2236dd7abcaSbluhm 		fd = fd_base + arc4random_uniform(fd_num);
224dd1c5868Sbluhm 		mask_sockaddr(&su);
225dd1c5868Sbluhm 		if (af == AF_INET)
226dd1c5868Sbluhm 			su.su_sin.sin_port = arc4random();
227dd1c5868Sbluhm 		if (af == AF_INET6)
228dd1c5868Sbluhm 			su.su_sin6.sin6_port = arc4random();
229dd1c5868Sbluhm 		connect(fd, &su.su_sa, su.su_sa.sa_len);
2306dd7abcaSbluhm 	}
2316dd7abcaSbluhm 
2326dd7abcaSbluhm 	return (void *)count;
2336dd7abcaSbluhm }
2346dd7abcaSbluhm 
2350d0a919fSbluhm static void *
thread_delroute(void * arg)2360d0a919fSbluhm thread_delroute(void *arg)
2370d0a919fSbluhm {
2380d0a919fSbluhm 	volatile int *run = arg;
2390d0a919fSbluhm 	unsigned long count;
2400d0a919fSbluhm 	int seq = 0;
2410d0a919fSbluhm 	struct {
2420d0a919fSbluhm 		struct rt_msghdr	m_rtm;
2430d0a919fSbluhm 		char			m_space[512];
2440d0a919fSbluhm 	} m_rtmsg;
245dd1c5868Sbluhm 	union sockaddr_union su;
2460d0a919fSbluhm 
2470d0a919fSbluhm #define rtm \
2480d0a919fSbluhm 	m_rtmsg.m_rtm
2490d0a919fSbluhm #define ROUNDUP(a) \
2500d0a919fSbluhm 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
2510d0a919fSbluhm #define ADVANCE(x, n) \
2520d0a919fSbluhm 	(x += ROUNDUP((n)->sa_len))
2530d0a919fSbluhm #define NEXTADDR(w, sa)				\
2540d0a919fSbluhm 	if (rtm.rtm_addrs & (w)) {		\
255dd1c5868Sbluhm 		int l = ROUNDUP((sa)->sa_len);	\
256dd1c5868Sbluhm 		memcpy(cp, (sa), l);		\
2570d0a919fSbluhm 		cp += l;			\
2580d0a919fSbluhm 	}
2590d0a919fSbluhm 
2600d0a919fSbluhm 	memset(&m_rtmsg, 0, sizeof(m_rtmsg));
2610d0a919fSbluhm 	rtm.rtm_type = RTM_DELETE;
2620d0a919fSbluhm 	rtm.rtm_flags = RTF_HOST;
2630d0a919fSbluhm 	rtm.rtm_version = RTM_VERSION;
2640d0a919fSbluhm 	rtm.rtm_addrs = RTA_DST;
2650d0a919fSbluhm 	rtm.rtm_hdrlen = sizeof(rtm);
2660d0a919fSbluhm 
267dd1c5868Sbluhm 	fill_sockaddr(&su);
2680d0a919fSbluhm 
2690d0a919fSbluhm 	for (count = 0; *run; count++) {
2700d0a919fSbluhm 		char *cp = m_rtmsg.m_space;
2710d0a919fSbluhm 
2720d0a919fSbluhm 		rtm.rtm_seq = ++seq;
273dd1c5868Sbluhm 		mask_sockaddr(&su);
274dd1c5868Sbluhm 		NEXTADDR(RTA_DST, &su.su_sa);
2750d0a919fSbluhm 		rtm.rtm_msglen = cp - (char *)&m_rtmsg;
2760d0a919fSbluhm 		write(route_sock, &m_rtmsg, rtm.rtm_msglen);
2770d0a919fSbluhm 	}
2780d0a919fSbluhm 
2790d0a919fSbluhm #undef rtm
2800d0a919fSbluhm #undef ROUNDUP
2810d0a919fSbluhm #undef ADVANCE
2820d0a919fSbluhm #undef NEXTADDR
2830d0a919fSbluhm 
2840d0a919fSbluhm 	return (void *)count;
2850d0a919fSbluhm }
2860d0a919fSbluhm 
2876dd7abcaSbluhm int
main(int argc,char * argv[])2886dd7abcaSbluhm main(int argc, char *argv[])
2896dd7abcaSbluhm {
2906dd7abcaSbluhm 	struct rlimit rlim;
291ba17659fSbluhm 	struct protoent *pent;
2920d0a919fSbluhm 	pthread_t *tsocket, *tclose, *tbind, *tconnect, *tdelroute;
2930d0a919fSbluhm 	const char *errstr, *addr_net = NULL;
294dd1c5868Sbluhm 	char buf[128], *p;
2956dd7abcaSbluhm 	int ch, run;
2966dd7abcaSbluhm 	unsigned int n;
2970d0a919fSbluhm 	unsigned long socket_count, close_count, bind_count, connect_count,
2980d0a919fSbluhm 	    delroute_count;
299dd1c5868Sbluhm 	union sockaddr_union su;
3006dd7abcaSbluhm 
301ba17659fSbluhm 	while ((ch = getopt(argc, argv, "b:c:d:f:N:n:o:p:rs:t:")) != -1) {
3026dd7abcaSbluhm 		switch (ch) {
3036dd7abcaSbluhm 		case 'b':
3046dd7abcaSbluhm 			bind_num = strtonum(optarg, 0, UINT_MAX, &errstr);
3056dd7abcaSbluhm 			if (errstr != NULL)
3066dd7abcaSbluhm 				errx(1, "bind is %s: %s", errstr, optarg);
3076dd7abcaSbluhm 			break;
3086dd7abcaSbluhm 		case 'c':
3096dd7abcaSbluhm 			connect_num = strtonum(optarg, 0, UINT_MAX, &errstr);
3106dd7abcaSbluhm 			if (errstr != NULL)
3116dd7abcaSbluhm 				errx(1, "connect is %s: %s", errstr, optarg);
3126dd7abcaSbluhm 			break;
3130d0a919fSbluhm 		case 'd':
3140d0a919fSbluhm 			delroute_num = strtonum(optarg, 0, UINT_MAX, &errstr);
3150d0a919fSbluhm 			if (errstr != NULL)
3160d0a919fSbluhm 				errx(1, "delroute is %s: %s", errstr, optarg);
3170d0a919fSbluhm 			break;
318dd1c5868Sbluhm 		case 'f':
319ba17659fSbluhm 			if (strcmp(optarg, "inet") == 0)
320ba17659fSbluhm 				af = AF_INET;
321ba17659fSbluhm 			else if (strcmp(optarg, "inet6") == 0)
322ba17659fSbluhm 				af = AF_INET6;
323ba17659fSbluhm 			else
324ba17659fSbluhm 				errx(1, "bad address family %s", optarg);
325dd1c5868Sbluhm 			break;
3260d0a919fSbluhm 		case 'N':
3270d0a919fSbluhm 			addr_net = optarg;
3280d0a919fSbluhm 			break;
3296dd7abcaSbluhm 		case 'n':
3300d0a919fSbluhm 			fd_num = strtonum(optarg, 1, INT_MAX, &errstr);
3316dd7abcaSbluhm 			if (errstr != NULL)
3326dd7abcaSbluhm 				errx(1, "num is %s: %s", errstr, optarg);
3336dd7abcaSbluhm 			break;
3346dd7abcaSbluhm 		case 'o':
3356dd7abcaSbluhm 			close_num = strtonum(optarg, 0, UINT_MAX, &errstr);
3366dd7abcaSbluhm 			if (errstr != NULL)
3376dd7abcaSbluhm 				errx(1, "close is %s: %s", errstr, optarg);
3386dd7abcaSbluhm 			break;
339ba17659fSbluhm 		case 'p':
340ba17659fSbluhm 			pent = getprotobyname(optarg);
341ba17659fSbluhm 			if (pent != NULL) {
342ba17659fSbluhm 				proto = pent->p_proto;
343ba17659fSbluhm 				break;
344ba17659fSbluhm 			}
345ba17659fSbluhm 			proto = strtonum(optarg, 0, IPPROTO_MAX -1 , &errstr);
346ba17659fSbluhm 			if (errstr != NULL)
347ba17659fSbluhm 				errx(1, "proto is %s: %s", errstr, optarg);
348ba17659fSbluhm 			break;
3490d0a919fSbluhm 		case 'r':
3500d0a919fSbluhm 			reuse_port = 1;
3510d0a919fSbluhm 			break;
3526dd7abcaSbluhm 		case 's':
3536dd7abcaSbluhm 			socket_num = strtonum(optarg, 0, UINT_MAX, &errstr);
3546dd7abcaSbluhm 			if (errstr != NULL)
3556dd7abcaSbluhm 				errx(1, "socket is %s: %s", errstr, optarg);
3566dd7abcaSbluhm 			break;
3576dd7abcaSbluhm 		case 't':
3586dd7abcaSbluhm 			run_time = strtonum(optarg, 0, UINT_MAX, &errstr);
3596dd7abcaSbluhm 			if (errstr != NULL)
3606dd7abcaSbluhm 				errx(1, "time is %s: %s", errstr, optarg);
3616dd7abcaSbluhm 			break;
3626dd7abcaSbluhm 		default:
3636dd7abcaSbluhm 			usage();
3646dd7abcaSbluhm 		}
3656dd7abcaSbluhm 	}
3666dd7abcaSbluhm 	argc -= optind;
3676dd7abcaSbluhm 	argv += optind;
3686dd7abcaSbluhm 	if (argc > 0)
3696dd7abcaSbluhm 		usage();
3706dd7abcaSbluhm 
371dd1c5868Sbluhm 	/* split addr/net into addr, mask, prefix */
3720d0a919fSbluhm 	if (addr_net != NULL) {
373dd1c5868Sbluhm 		prefix = inet_net_pton(af, addr_net, &addr, sizeof(addr));
3740d0a919fSbluhm 		if (prefix < 0)
3750d0a919fSbluhm 			err(1, "inet_net_pton %s", addr_net);
376dd1c5868Sbluhm 		if (af == AF_INET6) {
377dd1c5868Sbluhm 			/*
378dd1c5868Sbluhm 			 * Man page says inet_net_pton() preserves lower
379dd1c5868Sbluhm 			 * bits.  That is not true, call inet_pton() again.
380dd1c5868Sbluhm 			 */
381dd1c5868Sbluhm 			if (strlcpy(buf, addr_net, sizeof(buf)) >= sizeof(buf))
382dd1c5868Sbluhm 				err(1, "strlcpy %s", addr_net);
383dd1c5868Sbluhm 			p = strchr(buf, '/');
384dd1c5868Sbluhm 			if (p != NULL ) {
385dd1c5868Sbluhm 				*p = '\0';
386dd1c5868Sbluhm 				if (inet_pton(af, buf, &addr) < 0)
387dd1c5868Sbluhm 					err(1, "inet_pton %s", buf);
3880d0a919fSbluhm 			}
389dd1c5868Sbluhm 		}
390dd1c5868Sbluhm 		if (af == AF_INET)
391dd1c5868Sbluhm 			in_prefixlen2mask(&mask.au_inaddr, prefix);
392dd1c5868Sbluhm 		if (af == AF_INET6)
393dd1c5868Sbluhm 			in6_prefixlen2mask(&mask.au_in6addr, prefix);
394dd1c5868Sbluhm 	}
395dd1c5868Sbluhm 
396dd1c5868Sbluhm 	/* preopen route socket before file descriptor limits are set */
3970d0a919fSbluhm 	if (delroute_num > 0) {
3980d0a919fSbluhm 		if (prefix < 0 || prefix == 32)
3990d0a919fSbluhm 			errx(1, "delroute %u needs addr/net", delroute_num);
400dd1c5868Sbluhm 		route_sock = socket(AF_ROUTE, SOCK_RAW, af);
4010d0a919fSbluhm 		if (route_sock < 0)
4020d0a919fSbluhm 			err(1, "socket route");
4030d0a919fSbluhm 		if (shutdown(route_sock, SHUT_RD) < 0)
4040d0a919fSbluhm 			err(1, "shutdown read route");
4050d0a919fSbluhm 	}
4060d0a919fSbluhm 
407dd1c5868Sbluhm 	/* detect lowest file desciptor, test bind, close everything above */
408ba17659fSbluhm 	switch (proto) {
409ba17659fSbluhm 	case IPPROTO_TCP:
410ba17659fSbluhm 		type = SOCK_STREAM;
411ba17659fSbluhm 		break;
412ba17659fSbluhm 	case IPPROTO_UDP:
413ba17659fSbluhm 		type = SOCK_DGRAM;
414ba17659fSbluhm 		break;
415ba17659fSbluhm 	default:
416ba17659fSbluhm 		type = SOCK_RAW;
417ba17659fSbluhm 		break;
418ba17659fSbluhm 	}
419ba17659fSbluhm 	fd_base = socket(af, type, proto);
4200d0a919fSbluhm 	if (fd_base < 0)
4210d0a919fSbluhm 		err(1, "socket fd_base");
4220d0a919fSbluhm 	if (fd_base > INT_MAX - (int)fd_num)
4230d0a919fSbluhm 		err(1, "fd base %d and num %u overflow", fd_base, fd_num);
424dd1c5868Sbluhm 	fill_sockaddr(&su);
425dd1c5868Sbluhm 	if (bind(fd_base, &su.su_sa, su.su_sa.sa_len) < 0)
426dd1c5868Sbluhm 		err(1, "bind %s", inet_ntop(af, &addr, buf, sizeof(buf)));
4276dd7abcaSbluhm 	if (closefrom(fd_base) < 0)
4286dd7abcaSbluhm 		err(1, "closefrom %d", fd_base);
4296dd7abcaSbluhm 
4306dd7abcaSbluhm 	if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
4316dd7abcaSbluhm 		err(1, "getrlimit");
432ba17659fSbluhm 	rlim.rlim_max = MAXIMUM(rlim.rlim_max, fd_base + fd_num);
4336dd7abcaSbluhm 	rlim.rlim_cur = fd_base + fd_num;
4346dd7abcaSbluhm 	if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
4356dd7abcaSbluhm 		err(1, "setrlimit %llu", rlim.rlim_cur);
4366dd7abcaSbluhm 
4376dd7abcaSbluhm 	run = 1;
4380d0a919fSbluhm 
4396dd7abcaSbluhm 	tsocket = calloc(socket_num, sizeof(pthread_t));
4406dd7abcaSbluhm 	if (tsocket == NULL)
4416dd7abcaSbluhm 		err(1, "tsocket");
4426dd7abcaSbluhm 	for (n = 0; n < socket_num; n++) {
4436dd7abcaSbluhm 		errno = pthread_create(&tsocket[n], NULL, thread_socket, &run);
4446dd7abcaSbluhm 		if (errno)
4456dd7abcaSbluhm 			err(1, "pthread_create socket %u", n);
4466dd7abcaSbluhm 	}
4470d0a919fSbluhm 
4486dd7abcaSbluhm 	tclose = calloc(close_num, sizeof(pthread_t));
4496dd7abcaSbluhm 	if (tclose == NULL)
4506dd7abcaSbluhm 		err(1, "tclose");
4516dd7abcaSbluhm 	for (n = 0; n < close_num; n++) {
4526dd7abcaSbluhm 		errno = pthread_create(&tclose[n], NULL, thread_close, &run);
4536dd7abcaSbluhm 		if (errno)
4546dd7abcaSbluhm 			err(1, "pthread_create close %u", n);
4556dd7abcaSbluhm 	}
4560d0a919fSbluhm 
4576dd7abcaSbluhm 	tbind = calloc(bind_num, sizeof(pthread_t));
4586dd7abcaSbluhm 	if (tbind == NULL)
4596dd7abcaSbluhm 		err(1, "tbind");
4606dd7abcaSbluhm 	for (n = 0; n < bind_num; n++) {
4616dd7abcaSbluhm 		errno = pthread_create(&tbind[n], NULL, thread_bind, &run);
4626dd7abcaSbluhm 		if (errno)
4636dd7abcaSbluhm 			err(1, "pthread_create bind %u", n);
4646dd7abcaSbluhm 	}
4650d0a919fSbluhm 
4666dd7abcaSbluhm 	tconnect = calloc(connect_num, sizeof(pthread_t));
4676dd7abcaSbluhm 	if (tconnect == NULL)
4686dd7abcaSbluhm 		err(1, "tconnect");
4696dd7abcaSbluhm 	for (n = 0; n < connect_num; n++) {
4706dd7abcaSbluhm 		errno = pthread_create(&tconnect[n], NULL, thread_connect,
4716dd7abcaSbluhm 		    &run);
4726dd7abcaSbluhm 		if (errno)
4736dd7abcaSbluhm 			err(1, "pthread_create connect %u", n);
4746dd7abcaSbluhm 	}
4756dd7abcaSbluhm 
4760d0a919fSbluhm 	tdelroute = calloc(delroute_num, sizeof(pthread_t));
4770d0a919fSbluhm 	if (tdelroute == NULL)
4780d0a919fSbluhm 		err(1, "tdelroute");
4790d0a919fSbluhm 	for (n = 0; n < delroute_num; n++) {
4800d0a919fSbluhm 		errno = pthread_create(&tdelroute[n], NULL, thread_delroute,
4810d0a919fSbluhm 		    &run);
4820d0a919fSbluhm 		if (errno)
4830d0a919fSbluhm 			err(1, "pthread_create delroute %u", n);
4840d0a919fSbluhm 	}
4850d0a919fSbluhm 
4866dd7abcaSbluhm 	if (run_time > 0) {
4876dd7abcaSbluhm 		if (sleep(run_time) < 0)
4886dd7abcaSbluhm 			err(1, "sleep %u", run_time);
4896dd7abcaSbluhm 	}
4906dd7abcaSbluhm 
4916dd7abcaSbluhm 	run = 0;
4926dd7abcaSbluhm 	socket_count = 0;
4936dd7abcaSbluhm 	for (n = 0; n < socket_num; n++) {
4946dd7abcaSbluhm 		unsigned long count;
4956dd7abcaSbluhm 
4966dd7abcaSbluhm 		errno = pthread_join(tsocket[n], (void **)&count);
4976dd7abcaSbluhm 		if (errno)
4986dd7abcaSbluhm 			err(1, "pthread_join socket %u", n);
4996dd7abcaSbluhm 		socket_count += count;
5006dd7abcaSbluhm 	}
5010d0a919fSbluhm 	free(tsocket);
5020d0a919fSbluhm 
5036dd7abcaSbluhm 	close_count = 0;
5046dd7abcaSbluhm 	for (n = 0; n < close_num; n++) {
5056dd7abcaSbluhm 		unsigned long count;
5066dd7abcaSbluhm 
5076dd7abcaSbluhm 		errno = pthread_join(tclose[n], (void **)&count);
5086dd7abcaSbluhm 		if (errno)
5096dd7abcaSbluhm 			err(1, "pthread_join close %u", n);
5106dd7abcaSbluhm 		close_count += count;
5116dd7abcaSbluhm 	}
5120d0a919fSbluhm 	free(tclose);
5130d0a919fSbluhm 
5146dd7abcaSbluhm 	bind_count = 0;
5156dd7abcaSbluhm 	for (n = 0; n < bind_num; n++) {
5166dd7abcaSbluhm 		unsigned long count;
5176dd7abcaSbluhm 
5186dd7abcaSbluhm 		errno = pthread_join(tbind[n], (void **)&count);
5196dd7abcaSbluhm 		if (errno)
5206dd7abcaSbluhm 			err(1, "pthread_join bind %u", n);
5216dd7abcaSbluhm 		bind_count += count;
5226dd7abcaSbluhm 	}
5230d0a919fSbluhm 	free(tbind);
5240d0a919fSbluhm 
5256dd7abcaSbluhm 	connect_count = 0;
5266dd7abcaSbluhm 	for (n = 0; n < connect_num; n++) {
5276dd7abcaSbluhm 		unsigned long count;
5286dd7abcaSbluhm 
5296dd7abcaSbluhm 		errno = pthread_join(tconnect[n], (void **)&count);
5306dd7abcaSbluhm 		if (errno)
5316dd7abcaSbluhm 			err(1, "pthread_join connect %u", n);
5326dd7abcaSbluhm 		connect_count += count;
5336dd7abcaSbluhm 	}
5340d0a919fSbluhm 	free(tconnect);
5350d0a919fSbluhm 
5360d0a919fSbluhm 	delroute_count = 0;
5370d0a919fSbluhm 	for (n = 0; n < delroute_num; n++) {
5380d0a919fSbluhm 		unsigned long count;
5390d0a919fSbluhm 
5400d0a919fSbluhm 		errno = pthread_join(tdelroute[n], (void **)&count);
5410d0a919fSbluhm 		if (errno)
5420d0a919fSbluhm 			err(1, "pthread_join delroute %u", n);
5430d0a919fSbluhm 		delroute_count += count;
5440d0a919fSbluhm 	}
5450d0a919fSbluhm 	free(tdelroute);
5460d0a919fSbluhm 
5470d0a919fSbluhm 	printf("count: socket %lu, close %lu, bind %lu, connect %lu, "
5480d0a919fSbluhm 	    "delroute %lu\n",
5490d0a919fSbluhm 	    socket_count, close_count, bind_count, connect_count,
5500d0a919fSbluhm 	    delroute_count);
5516dd7abcaSbluhm 
5526dd7abcaSbluhm 	return 0;
5536dd7abcaSbluhm }
554