xref: /freebsd-src/contrib/netcat/netcat.c (revision 04a3ca71ead61b4ced23a791d3a5e2633ca1ef72)
1100e2a06SXin LI /* $OpenBSD: netcat.c,v 1.130 2015/07/26 19:12:28 chl Exp $ */
28c384020SXin LI /*
38c384020SXin LI  * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
48c384020SXin LI  *
58c384020SXin LI  * Redistribution and use in source and binary forms, with or without
68c384020SXin LI  * modification, are permitted provided that the following conditions
78c384020SXin LI  * are met:
88c384020SXin LI  *
98c384020SXin LI  * 1. Redistributions of source code must retain the above copyright
108c384020SXin LI  *   notice, this list of conditions and the following disclaimer.
118c384020SXin LI  * 2. Redistributions in binary form must reproduce the above copyright
128c384020SXin LI  *   notice, this list of conditions and the following disclaimer in the
138c384020SXin LI  *   documentation and/or other materials provided with the distribution.
148c384020SXin LI  * 3. The name of the author may not be used to endorse or promote products
158c384020SXin LI  *   derived from this software without specific prior written permission.
168c384020SXin LI  *
178c384020SXin LI  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
188c384020SXin LI  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
198c384020SXin LI  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
208c384020SXin LI  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
218c384020SXin LI  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
228c384020SXin LI  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
238c384020SXin LI  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
248c384020SXin LI  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
258c384020SXin LI  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
268c384020SXin LI  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2704def624SXin LI  *
2804def624SXin LI  * $FreeBSD$
298c384020SXin LI  */
308c384020SXin LI 
318c384020SXin LI /*
328c384020SXin LI  * Re-written nc(1) for OpenBSD. Original implementation by
338c384020SXin LI  * *Hobbit* <hobbit@avian.org>.
348c384020SXin LI  */
358c384020SXin LI 
361e62ecedSEdward Tomasz Napierala #include <errno.h>
371e62ecedSEdward Tomasz Napierala #include <stdio.h>
381e62ecedSEdward Tomasz Napierala #include <sys/arb.h>
3904def624SXin LI #include <sys/limits.h>
408c384020SXin LI #include <sys/types.h>
411e62ecedSEdward Tomasz Napierala #include <sys/sbuf.h>
428c384020SXin LI #include <sys/socket.h>
432d5ea05aSXin LI #include <sys/sysctl.h>
441e62ecedSEdward Tomasz Napierala #include <sys/qmath.h>
451e62ecedSEdward Tomasz Napierala #include <sys/stats.h>
468c384020SXin LI #include <sys/time.h>
473ae0125aSXin LI #include <sys/uio.h>
488c384020SXin LI #include <sys/un.h>
498c384020SXin LI 
508c384020SXin LI #include <netinet/in.h>
5104def624SXin LI #ifdef IPSEC
528409aedfSGeorge V. Neville-Neil #include <netipsec/ipsec.h>
5304def624SXin LI #endif
548c384020SXin LI #include <netinet/tcp.h>
552440a458SXin LI #include <netinet/ip.h>
568c384020SXin LI #include <arpa/telnet.h>
578c384020SXin LI 
588c384020SXin LI #include <err.h>
597dcaa833SXin LI #include <getopt.h>
60100e2a06SXin LI #include <fcntl.h>
61100e2a06SXin LI #include <limits.h>
628c384020SXin LI #include <netdb.h>
638c384020SXin LI #include <poll.h>
64100e2a06SXin LI #include <signal.h>
658c384020SXin LI #include <stdarg.h>
668c384020SXin LI #include <stdlib.h>
678c384020SXin LI #include <string.h>
688c384020SXin LI #include <unistd.h>
692440a458SXin LI #include "atomicio.h"
708c384020SXin LI 
718c384020SXin LI #ifndef SUN_LEN
728c384020SXin LI #define SUN_LEN(su) \
738c384020SXin LI 	(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
748c384020SXin LI #endif
758c384020SXin LI 
768c384020SXin LI #define PORT_MAX	65535
778c384020SXin LI #define PORT_MAX_LEN	6
7859c7ad52SXin LI #define UNIX_DG_TMP_SOCKET_SIZE	19
798c384020SXin LI 
808c54dbfbSXin LI #define POLL_STDIN 0
818c54dbfbSXin LI #define POLL_NETOUT 1
828c54dbfbSXin LI #define POLL_NETIN 2
838c54dbfbSXin LI #define POLL_STDOUT 3
848c54dbfbSXin LI #define BUFSIZE 16384
858c54dbfbSXin LI 
868c384020SXin LI /* Command Line Options */
878c384020SXin LI int	dflag;					/* detached, no stdin */
883ae0125aSXin LI int	Fflag;					/* fdpass sock to stdout */
89bdb0aaa1SXin LI unsigned int iflag;				/* Interval Flag */
908c384020SXin LI int	kflag;					/* More than one connect */
918c384020SXin LI int	lflag;					/* Bind to local port */
92*04a3ca71SMark Johnston int	FreeBSD_lb;				/* Use SO_REUSEPORT_LB */
931e62ecedSEdward Tomasz Napierala int	FreeBSD_Mflag;				/* Measure using stats(3) */
940772266eSXin LI int	Nflag;					/* shutdown() network socket */
958c384020SXin LI int	nflag;					/* Don't do name look up */
967dcaa833SXin LI int	FreeBSD_Oflag;				/* Do not use TCP options */
97d0415892SMark Johnston int	FreeBSD_sctp;				/* Use SCTP */
98d4b3aefdSPietro Cerutti int	FreeBSD_crlf;				/* Convert LF to CRLF */
992440a458SXin LI char   *Pflag;					/* Proxy username */
1008c384020SXin LI char   *pflag;					/* Localport flag */
1018c384020SXin LI int	rflag;					/* Random ports flag */
1028c384020SXin LI char   *sflag;					/* Source Address */
1038c384020SXin LI int	tflag;					/* Telnet Emulation */
1048c384020SXin LI int	uflag;					/* UDP - Default to TCP */
1058c384020SXin LI int	vflag;					/* Verbosity */
1068c384020SXin LI int	xflag;					/* Socks proxy */
1078c384020SXin LI int	zflag;					/* Port Scan Flag */
1088c384020SXin LI int	Dflag;					/* sodebug */
1097dcaa833SXin LI int	Iflag;					/* TCP receive buffer size */
1107dcaa833SXin LI int	Oflag;					/* TCP send buffer size */
1118c384020SXin LI int	Sflag;					/* TCP MD5 signature option */
1122440a458SXin LI int	Tflag = -1;				/* IP Type of Service */
1133ae0125aSXin LI int	rtableid = -1;
1148c384020SXin LI 
1158c384020SXin LI int timeout = -1;
1168c384020SXin LI int family = AF_UNSPEC;
117cef7ab70STom Jones int tun_fd = -1;
1188c384020SXin LI char *portlist[PORT_MAX+1];
11959c7ad52SXin LI char *unix_dg_tmp_socket;
1208c384020SXin LI 
1218c384020SXin LI void	atelnet(int, unsigned char *, unsigned int);
1228c384020SXin LI void	build_ports(char *);
1238c384020SXin LI void	help(void);
1248c384020SXin LI int	local_listen(char *, char *, struct addrinfo);
1258c384020SXin LI void	readwrite(int);
1263ae0125aSXin LI void	fdpass(int nfd) __attribute__((noreturn));
1272440a458SXin LI int	remote_connect(const char *, const char *, struct addrinfo);
128ac3ea910SXin LI int	timeout_connect(int, const struct sockaddr *, socklen_t);
1292440a458SXin LI int	socks_connect(const char *, const char *, struct addrinfo,
1302440a458SXin LI 	    const char *, const char *, struct addrinfo, int, const char *);
1318c384020SXin LI int	udptest(int);
13259c7ad52SXin LI int	unix_bind(char *);
1338c384020SXin LI int	unix_connect(char *);
1348c384020SXin LI int	unix_listen(char *);
1351e62ecedSEdward Tomasz Napierala void	FreeBSD_stats_setup(int);
1361e62ecedSEdward Tomasz Napierala void	FreeBSD_stats_print(int);
1378c54dbfbSXin LI void	set_common_sockopts(int, int);
138ac3ea910SXin LI int	map_tos(char *, int *);
13952dba105SXin LI void	report_connect(const struct sockaddr *, socklen_t);
1408c384020SXin LI void	usage(int);
141d4b3aefdSPietro Cerutti ssize_t write_wrapper(int, const void *, size_t);
142d4b3aefdSPietro Cerutti ssize_t drainbuf(int, unsigned char *, size_t *, int);
1438c54dbfbSXin LI ssize_t fillbuf(int, unsigned char *, size_t *);
1448c384020SXin LI 
14504def624SXin LI #ifdef IPSEC
146fcf59617SAndrey V. Elsukov void	add_ipsec_policy(int, int, char *);
14704def624SXin LI 
14804def624SXin LI char	*ipsec_policy[2];
14904def624SXin LI #endif
15004def624SXin LI 
151cef7ab70STom Jones enum {
152cef7ab70STom Jones 	FREEBSD_TUN = CHAR_MAX,	/* avoid collision with return values from getopt */
153cef7ab70STom Jones };
154cef7ab70STom Jones 
1558c384020SXin LI int
1568c384020SXin LI main(int argc, char *argv[])
1578c384020SXin LI {
15804def624SXin LI 	int ch, s, ret, socksv, ipsec_count;
1592d5ea05aSXin LI 	int numfibs;
1602d5ea05aSXin LI 	size_t intsize = sizeof(int);
161bdb0aaa1SXin LI 	char *host, *uport;
1628c384020SXin LI 	struct addrinfo hints;
1638c384020SXin LI 	struct servent *sv;
1648c384020SXin LI 	socklen_t len;
1658c384020SXin LI 	struct sockaddr_storage cliaddr;
1668c384020SXin LI 	char *proxy;
167cef7ab70STom Jones 	const char *errstr, *proxyhost = "", *proxyport = NULL, *tundev = NULL;
1688c384020SXin LI 	struct addrinfo proxyhints;
16959c7ad52SXin LI 	char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE];
1707dcaa833SXin LI 	struct option longopts[] = {
171d4b3aefdSPietro Cerutti 		{ "crlf",	no_argument,	&FreeBSD_crlf,	1 },
172*04a3ca71SMark Johnston 		{ "lb",		no_argument,	&FreeBSD_lb, 1 },
1737dcaa833SXin LI 		{ "no-tcpopt",	no_argument,	&FreeBSD_Oflag,	1 },
174d0415892SMark Johnston 		{ "sctp",	no_argument,	&FreeBSD_sctp,	1 },
175cef7ab70STom Jones 		{ "tun",	required_argument,	NULL,	FREEBSD_TUN },
1767dcaa833SXin LI 		{ NULL,		0,		NULL,		0 }
1777dcaa833SXin LI 	};
1788c384020SXin LI 
1798c384020SXin LI 	ret = 1;
18004def624SXin LI 	ipsec_count = 0;
1818c384020SXin LI 	s = 0;
1828c384020SXin LI 	socksv = 5;
1838c384020SXin LI 	host = NULL;
1848c384020SXin LI 	uport = NULL;
1858c384020SXin LI 	sv = NULL;
1868c384020SXin LI 
187100e2a06SXin LI 	signal(SIGPIPE, SIG_IGN);
188100e2a06SXin LI 
1897dcaa833SXin LI 	while ((ch = getopt_long(argc, argv,
1901e62ecedSEdward Tomasz Napierala 	    "46DdEe:FhI:i:klMNnoO:P:p:rSs:tT:UuV:vw:X:x:z",
1917dcaa833SXin LI 	    longopts, NULL)) != -1) {
1928c384020SXin LI 		switch (ch) {
1938c384020SXin LI 		case '4':
1948c384020SXin LI 			family = AF_INET;
1958c384020SXin LI 			break;
1968c384020SXin LI 		case '6':
1978c384020SXin LI 			family = AF_INET6;
1988c384020SXin LI 			break;
1998c384020SXin LI 		case 'U':
2008c384020SXin LI 			family = AF_UNIX;
2018c384020SXin LI 			break;
2028c384020SXin LI 		case 'X':
2038c384020SXin LI 			if (strcasecmp(optarg, "connect") == 0)
2048c384020SXin LI 				socksv = -1; /* HTTP proxy CONNECT */
2058c384020SXin LI 			else if (strcmp(optarg, "4") == 0)
2068c384020SXin LI 				socksv = 4; /* SOCKS v.4 */
2078c384020SXin LI 			else if (strcmp(optarg, "5") == 0)
2088c384020SXin LI 				socksv = 5; /* SOCKS v.5 */
2098c384020SXin LI 			else
2108c384020SXin LI 				errx(1, "unsupported proxy protocol");
2118c384020SXin LI 			break;
2128c384020SXin LI 		case 'd':
2138c384020SXin LI 			dflag = 1;
2148c384020SXin LI 			break;
21504def624SXin LI 		case 'e':
21604def624SXin LI #ifdef IPSEC
21704def624SXin LI 			ipsec_policy[ipsec_count++ % 2] = optarg;
21804def624SXin LI #else
21904def624SXin LI 			errx(1, "IPsec support unavailable.");
22004def624SXin LI #endif
22104def624SXin LI 			break;
22204def624SXin LI 		case 'E':
22304def624SXin LI #ifdef IPSEC
22404def624SXin LI 			ipsec_policy[0] = "in  ipsec esp/transport//require";
22504def624SXin LI 			ipsec_policy[1] = "out ipsec esp/transport//require";
22604def624SXin LI #else
22704def624SXin LI 			errx(1, "IPsec support unavailable.");
22804def624SXin LI #endif
22904def624SXin LI 			break;
2303ae0125aSXin LI 		case 'F':
2313ae0125aSXin LI 			Fflag = 1;
2323ae0125aSXin LI 			break;
2338c384020SXin LI 		case 'h':
2348c384020SXin LI 			help();
2358c384020SXin LI 			break;
2368c384020SXin LI 		case 'i':
237bdb0aaa1SXin LI 			iflag = strtonum(optarg, 0, UINT_MAX, &errstr);
238bdb0aaa1SXin LI 			if (errstr)
239bdb0aaa1SXin LI 				errx(1, "interval %s: %s", errstr, optarg);
2408c384020SXin LI 			break;
2418c384020SXin LI 		case 'k':
2428c384020SXin LI 			kflag = 1;
2438c384020SXin LI 			break;
2448c384020SXin LI 		case 'l':
2458c384020SXin LI 			lflag = 1;
2468c384020SXin LI 			break;
2471e62ecedSEdward Tomasz Napierala 		case 'M':
2481e62ecedSEdward Tomasz Napierala #ifndef WITH_STATS
2491e62ecedSEdward Tomasz Napierala 			errx(1, "-M requires stats(3) support");
2501e62ecedSEdward Tomasz Napierala #else
2511e62ecedSEdward Tomasz Napierala 			FreeBSD_Mflag = 1;
2521e62ecedSEdward Tomasz Napierala #endif
2531e62ecedSEdward Tomasz Napierala 			break;
2540772266eSXin LI 		case 'N':
2550772266eSXin LI 			Nflag = 1;
2560772266eSXin LI 			break;
2578c384020SXin LI 		case 'n':
2588c384020SXin LI 			nflag = 1;
2598c384020SXin LI 			break;
26004def624SXin LI 		case 'o':
26155e99985SXin LI 			fprintf(stderr, "option -o is deprecated.\n");
26204def624SXin LI 			break;
2632440a458SXin LI 		case 'P':
2642440a458SXin LI 			Pflag = optarg;
2652440a458SXin LI 			break;
2668c384020SXin LI 		case 'p':
2678c384020SXin LI 			pflag = optarg;
2688c384020SXin LI 			break;
2698c384020SXin LI 		case 'r':
2708c384020SXin LI 			rflag = 1;
2718c384020SXin LI 			break;
2728c384020SXin LI 		case 's':
2738c384020SXin LI 			sflag = optarg;
2748c384020SXin LI 			break;
2758c384020SXin LI 		case 't':
2768c384020SXin LI 			tflag = 1;
2778c384020SXin LI 			break;
2788c384020SXin LI 		case 'u':
2798c384020SXin LI 			uflag = 1;
2808c384020SXin LI 			break;
2812d5ea05aSXin LI 		case 'V':
2822d5ea05aSXin LI 			if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1)
2832d5ea05aSXin LI 				errx(1, "Multiple FIBS not supported");
2843ae0125aSXin LI 			rtableid = (int)strtonum(optarg, 0,
2852d5ea05aSXin LI 			    numfibs - 1, &errstr);
2862d5ea05aSXin LI 			if (errstr)
2874f2bbc00SXin LI 				errx(1, "rtable %s: %s", errstr, optarg);
2882d5ea05aSXin LI 			break;
2898c384020SXin LI 		case 'v':
2908c384020SXin LI 			vflag = 1;
2918c384020SXin LI 			break;
2928c384020SXin LI 		case 'w':
293bdb0aaa1SXin LI 			timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr);
294bdb0aaa1SXin LI 			if (errstr)
295bdb0aaa1SXin LI 				errx(1, "timeout %s: %s", errstr, optarg);
2968c384020SXin LI 			timeout *= 1000;
2978c384020SXin LI 			break;
2988c384020SXin LI 		case 'x':
2998c384020SXin LI 			xflag = 1;
3008c384020SXin LI 			if ((proxy = strdup(optarg)) == NULL)
3018c384020SXin LI 				err(1, NULL);
3028c384020SXin LI 			break;
3038c384020SXin LI 		case 'z':
3048c384020SXin LI 			zflag = 1;
3058c384020SXin LI 			break;
3068c384020SXin LI 		case 'D':
3078c384020SXin LI 			Dflag = 1;
3088c384020SXin LI 			break;
3097dcaa833SXin LI 		case 'I':
3107dcaa833SXin LI 			Iflag = strtonum(optarg, 1, 65536 << 14, &errstr);
3117dcaa833SXin LI 			if (errstr != NULL)
3127dcaa833SXin LI 				errx(1, "TCP receive window %s: %s",
3137dcaa833SXin LI 				    errstr, optarg);
3147dcaa833SXin LI 			break;
3157dcaa833SXin LI 		case 'O':
3167dcaa833SXin LI 			Oflag = strtonum(optarg, 1, 65536 << 14, &errstr);
3177dcaa833SXin LI 			if (errstr != NULL) {
3187dcaa833SXin LI 			    if (strcmp(errstr, "invalid") != 0)
3197dcaa833SXin LI 				errx(1, "TCP send window %s: %s",
3207dcaa833SXin LI 				    errstr, optarg);
3217dcaa833SXin LI 			}
3227dcaa833SXin LI 			break;
3238c384020SXin LI 		case 'S':
3248c384020SXin LI 			Sflag = 1;
3258c384020SXin LI 			break;
3262440a458SXin LI 		case 'T':
327ac3ea910SXin LI 			errstr = NULL;
328ac3ea910SXin LI 			errno = 0;
329ac3ea910SXin LI 			if (map_tos(optarg, &Tflag))
330ac3ea910SXin LI 				break;
331ac3ea910SXin LI 			if (strlen(optarg) > 1 && optarg[0] == '0' &&
332ac3ea910SXin LI 			    optarg[1] == 'x')
333ac3ea910SXin LI 				Tflag = (int)strtol(optarg, NULL, 16);
334ac3ea910SXin LI 			else
335ac3ea910SXin LI 				Tflag = (int)strtonum(optarg, 0, 255,
336ac3ea910SXin LI 				    &errstr);
337ac3ea910SXin LI 			if (Tflag < 0 || Tflag > 255 || errstr || errno)
338ac3ea910SXin LI 				errx(1, "illegal tos value %s", optarg);
3392440a458SXin LI 			break;
340cef7ab70STom Jones 		case FREEBSD_TUN:
341cef7ab70STom Jones 			tundev = optarg;
342cef7ab70STom Jones 			break;
343d0415892SMark Johnston 		case 0:
344d0415892SMark Johnston 			/* Long option. */
345d0415892SMark Johnston 			break;
3468c384020SXin LI 		default:
3478c384020SXin LI 			usage(1);
3488c384020SXin LI 		}
3498c384020SXin LI 	}
3508c384020SXin LI 	argc -= optind;
3518c384020SXin LI 	argv += optind;
3528c384020SXin LI 
3538c384020SXin LI 	/* Cruft to make sure options are clean, and used properly. */
3548c384020SXin LI 	if (argv[0] && !argv[1] && family == AF_UNIX) {
3558c384020SXin LI 		host = argv[0];
3568c384020SXin LI 		uport = NULL;
3578c384020SXin LI 	} else if (argv[0] && !argv[1]) {
3588c384020SXin LI 		if  (!lflag)
3598c384020SXin LI 			usage(1);
3608c384020SXin LI 		uport = argv[0];
3618c384020SXin LI 		host = NULL;
3628c384020SXin LI 	} else if (argv[0] && argv[1]) {
3638c384020SXin LI 		host = argv[0];
3648c384020SXin LI 		uport = argv[1];
3658c384020SXin LI 	} else
3668c384020SXin LI 		usage(1);
3678c384020SXin LI 
3688c384020SXin LI 	if (lflag && sflag)
3698c384020SXin LI 		errx(1, "cannot use -s and -l");
3708c384020SXin LI 	if (lflag && pflag)
3718c384020SXin LI 		errx(1, "cannot use -p and -l");
3728c384020SXin LI 	if (lflag && zflag)
3738c384020SXin LI 		errx(1, "cannot use -z and -l");
3748c384020SXin LI 	if (!lflag && kflag)
3758c384020SXin LI 		errx(1, "must use -l with -k");
376*04a3ca71SMark Johnston 	if (!lflag && FreeBSD_lb)
377*04a3ca71SMark Johnston 		errx(1, "must use -l with --lb");
378d0415892SMark Johnston 	if (FreeBSD_sctp) {
379d0415892SMark Johnston 		if (uflag)
380d0415892SMark Johnston 			errx(1, "cannot use -u and --sctp");
381d0415892SMark Johnston 		if (family == AF_UNIX)
382d0415892SMark Johnston 			errx(1, "cannot use -U and --sctp");
383d0415892SMark Johnston 	}
384cef7ab70STom Jones 	if (tundev != NULL) {
385cef7ab70STom Jones 		if (!uflag)
386cef7ab70STom Jones 			errx(1, "must use --tun with -u");
387cef7ab70STom Jones 		tun_fd = open(tundev, O_RDWR);
388cef7ab70STom Jones 		if (tun_fd == -1)
389cef7ab70STom Jones 			errx(1, "unable to open tun device %s", tundev);
390cef7ab70STom Jones 	}
3918c384020SXin LI 
39259c7ad52SXin LI 	/* Get name of temporary socket for unix datagram client */
39359c7ad52SXin LI 	if ((family == AF_UNIX) && uflag && !lflag) {
39459c7ad52SXin LI 		if (sflag) {
39559c7ad52SXin LI 			unix_dg_tmp_socket = sflag;
39659c7ad52SXin LI 		} else {
39759c7ad52SXin LI 			strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX",
39859c7ad52SXin LI 				UNIX_DG_TMP_SOCKET_SIZE);
39959c7ad52SXin LI 			if (mktemp(unix_dg_tmp_socket_buf) == NULL)
40059c7ad52SXin LI 				err(1, "mktemp");
40159c7ad52SXin LI 			unix_dg_tmp_socket = unix_dg_tmp_socket_buf;
40259c7ad52SXin LI 		}
40359c7ad52SXin LI 	}
40459c7ad52SXin LI 
4058c384020SXin LI 	/* Initialize addrinfo structure. */
4068c384020SXin LI 	if (family != AF_UNIX) {
4078c384020SXin LI 		memset(&hints, 0, sizeof(struct addrinfo));
4088c384020SXin LI 		hints.ai_family = family;
4098c384020SXin LI 		hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
410d0415892SMark Johnston 		hints.ai_protocol = uflag ? IPPROTO_UDP :
411d0415892SMark Johnston 		    FreeBSD_sctp ? IPPROTO_SCTP : IPPROTO_TCP;
4128c384020SXin LI 		if (nflag)
4138c384020SXin LI 			hints.ai_flags |= AI_NUMERICHOST;
4148c384020SXin LI 	}
4158c384020SXin LI 
4168c384020SXin LI 	if (xflag) {
4178c384020SXin LI 		if (uflag)
4188c384020SXin LI 			errx(1, "no proxy support for UDP mode");
4198c384020SXin LI 
420d0415892SMark Johnston 		if (FreeBSD_sctp)
421d0415892SMark Johnston 			errx(1, "no proxy support for SCTP mode");
422d0415892SMark Johnston 
4238c384020SXin LI 		if (lflag)
4248c384020SXin LI 			errx(1, "no proxy support for listen");
4258c384020SXin LI 
4268c384020SXin LI 		if (family == AF_UNIX)
4278c384020SXin LI 			errx(1, "no proxy support for unix sockets");
4288c384020SXin LI 
4298c384020SXin LI 		/* XXX IPv6 transport to proxy would probably work */
4308c384020SXin LI 		if (family == AF_INET6)
4318c384020SXin LI 			errx(1, "no proxy support for IPv6");
4328c384020SXin LI 
4338c384020SXin LI 		if (sflag)
4348c384020SXin LI 			errx(1, "no proxy support for local source address");
4358c384020SXin LI 
4368c384020SXin LI 		proxyhost = strsep(&proxy, ":");
4378c384020SXin LI 		proxyport = proxy;
4388c384020SXin LI 
4398c384020SXin LI 		memset(&proxyhints, 0, sizeof(struct addrinfo));
4408c384020SXin LI 		proxyhints.ai_family = family;
4418c384020SXin LI 		proxyhints.ai_socktype = SOCK_STREAM;
4428c384020SXin LI 		proxyhints.ai_protocol = IPPROTO_TCP;
4438c384020SXin LI 		if (nflag)
4448c384020SXin LI 			proxyhints.ai_flags |= AI_NUMERICHOST;
4458c384020SXin LI 	}
4468c384020SXin LI 
4478c384020SXin LI 	if (lflag) {
4488c384020SXin LI 		int connfd;
4498c384020SXin LI 		ret = 0;
4508c384020SXin LI 
45159c7ad52SXin LI 		if (family == AF_UNIX) {
45259c7ad52SXin LI 			if (uflag)
45359c7ad52SXin LI 				s = unix_bind(host);
45459c7ad52SXin LI 			else
4558c384020SXin LI 				s = unix_listen(host);
45659c7ad52SXin LI 		}
4578c384020SXin LI 
4588c384020SXin LI 		/* Allow only one connection at a time, but stay alive. */
4598c384020SXin LI 		for (;;) {
4608c384020SXin LI 			if (family != AF_UNIX)
4618c384020SXin LI 				s = local_listen(host, uport, hints);
4628c384020SXin LI 			if (s < 0)
4638c384020SXin LI 				err(1, NULL);
4648c384020SXin LI 			/*
46552dba105SXin LI 			 * For UDP and -k, don't connect the socket, let it
46652dba105SXin LI 			 * receive datagrams from multiple socket pairs.
4678c384020SXin LI 			 */
46852dba105SXin LI 			if (uflag && kflag)
46952dba105SXin LI 				readwrite(s);
47052dba105SXin LI 			/*
47152dba105SXin LI 			 * For UDP and not -k, we will use recvfrom() initially
47252dba105SXin LI 			 * to wait for a caller, then use the regular functions
47352dba105SXin LI 			 * to talk to the caller.
47452dba105SXin LI 			 */
47552dba105SXin LI 			else if (uflag && !kflag) {
4762440a458SXin LI 				int rv, plen;
4774f2bbc00SXin LI 				char buf[16384];
4788c384020SXin LI 				struct sockaddr_storage z;
4798c384020SXin LI 
4808c384020SXin LI 				len = sizeof(z);
48152dba105SXin LI 				plen = 2048;
4822440a458SXin LI 				rv = recvfrom(s, buf, plen, MSG_PEEK,
4838c384020SXin LI 				    (struct sockaddr *)&z, &len);
4848c384020SXin LI 				if (rv < 0)
4858c384020SXin LI 					err(1, "recvfrom");
4868c384020SXin LI 
4878c384020SXin LI 				rv = connect(s, (struct sockaddr *)&z, len);
4888c384020SXin LI 				if (rv < 0)
4898c384020SXin LI 					err(1, "connect");
4908c384020SXin LI 
49152dba105SXin LI 				if (vflag)
49252dba105SXin LI 					report_connect((struct sockaddr *)&z, len);
49352dba105SXin LI 
49459c7ad52SXin LI 				readwrite(s);
4958c384020SXin LI 			} else {
4962440a458SXin LI 				len = sizeof(cliaddr);
4978c384020SXin LI 				connfd = accept(s, (struct sockaddr *)&cliaddr,
4988c384020SXin LI 				    &len);
4990772266eSXin LI 				if (connfd == -1) {
5000772266eSXin LI 					/* For now, all errnos are fatal */
50152dba105SXin LI 					err(1, "accept");
5020772266eSXin LI 				}
50352dba105SXin LI 				if (vflag)
50452dba105SXin LI 					report_connect((struct sockaddr *)&cliaddr, len);
50552dba105SXin LI 
5061e62ecedSEdward Tomasz Napierala 				if (FreeBSD_Mflag)
5071e62ecedSEdward Tomasz Napierala 					FreeBSD_stats_setup(connfd);
5088c384020SXin LI 				readwrite(connfd);
5098c384020SXin LI 				close(connfd);
51059c7ad52SXin LI 			}
51159c7ad52SXin LI 
5128c384020SXin LI 			if (family != AF_UNIX)
5138c384020SXin LI 				close(s);
51459c7ad52SXin LI 			else if (uflag) {
51559c7ad52SXin LI 				if (connect(s, NULL, 0) < 0)
51659c7ad52SXin LI 					err(1, "connect");
51759c7ad52SXin LI 			}
5188c384020SXin LI 
5198c384020SXin LI 			if (!kflag)
5208c384020SXin LI 				break;
5218c384020SXin LI 		}
5228c384020SXin LI 	} else if (family == AF_UNIX) {
5238c384020SXin LI 		ret = 0;
5248c384020SXin LI 
5258c384020SXin LI 		if ((s = unix_connect(host)) > 0 && !zflag) {
5268c384020SXin LI 			readwrite(s);
5278c384020SXin LI 			close(s);
5288c384020SXin LI 		} else
5298c384020SXin LI 			ret = 1;
5308c384020SXin LI 
53159c7ad52SXin LI 		if (uflag)
53259c7ad52SXin LI 			unlink(unix_dg_tmp_socket);
5338c384020SXin LI 		exit(ret);
5348c384020SXin LI 
5358c384020SXin LI 	} else {
5368c384020SXin LI 		int i = 0;
5378c384020SXin LI 
5388c384020SXin LI 		/* Construct the portlist[] array. */
5398c384020SXin LI 		build_ports(uport);
5408c384020SXin LI 
5418c384020SXin LI 		/* Cycle through portlist, connecting to each port. */
5428c384020SXin LI 		for (i = 0; portlist[i] != NULL; i++) {
5438c384020SXin LI 			if (s)
5448c384020SXin LI 				close(s);
5458c384020SXin LI 
5468c384020SXin LI 			if (xflag)
5478c384020SXin LI 				s = socks_connect(host, portlist[i], hints,
5482440a458SXin LI 				    proxyhost, proxyport, proxyhints, socksv,
5492440a458SXin LI 				    Pflag);
5508c384020SXin LI 			else
5518c384020SXin LI 				s = remote_connect(host, portlist[i], hints);
5528c384020SXin LI 
5538c384020SXin LI 			if (s < 0)
5548c384020SXin LI 				continue;
5558c384020SXin LI 
5568c384020SXin LI 			ret = 0;
5578c384020SXin LI 			if (vflag || zflag) {
5588c384020SXin LI 				/* For UDP, make sure we are connected. */
5598c384020SXin LI 				if (uflag) {
5608c384020SXin LI 					if (udptest(s) == -1) {
5618c384020SXin LI 						ret = 1;
5628c384020SXin LI 						continue;
5638c384020SXin LI 					}
5648c384020SXin LI 				}
5658c384020SXin LI 
5668c384020SXin LI 				/* Don't look up port if -n. */
5678c384020SXin LI 				if (nflag)
5688c384020SXin LI 					sv = NULL;
5698c384020SXin LI 				else {
5708c384020SXin LI 					sv = getservbyport(
5718c384020SXin LI 					    ntohs(atoi(portlist[i])),
5728c384020SXin LI 					    uflag ? "udp" : "tcp");
5738c384020SXin LI 				}
5748c384020SXin LI 
57526bf9c3bSXin LI 				fprintf(stderr,
57626bf9c3bSXin LI 				    "Connection to %s %s port [%s/%s] "
57726bf9c3bSXin LI 				    "succeeded!\n", host, portlist[i],
57826bf9c3bSXin LI 				    uflag ? "udp" : "tcp",
5798c384020SXin LI 				    sv ? sv->s_name : "*");
5808c384020SXin LI 			}
5813ae0125aSXin LI 			if (Fflag)
5823ae0125aSXin LI 				fdpass(s);
5833ae0125aSXin LI 			else if (!zflag)
5848c384020SXin LI 				readwrite(s);
5858c384020SXin LI 		}
5868c384020SXin LI 	}
5878c384020SXin LI 
5888c384020SXin LI 	if (s)
5898c384020SXin LI 		close(s);
590cef7ab70STom Jones 	if (tun_fd != -1)
591cef7ab70STom Jones 		close(tun_fd);
5928c384020SXin LI 
5938c384020SXin LI 	exit(ret);
5948c384020SXin LI }
5958c384020SXin LI 
5968c384020SXin LI /*
59759c7ad52SXin LI  * unix_bind()
59859c7ad52SXin LI  * Returns a unix socket bound to the given path
59959c7ad52SXin LI  */
60059c7ad52SXin LI int
60159c7ad52SXin LI unix_bind(char *path)
60259c7ad52SXin LI {
60359c7ad52SXin LI 	struct sockaddr_un sun;
60459c7ad52SXin LI 	int s;
60559c7ad52SXin LI 
60659c7ad52SXin LI 	/* Create unix domain socket. */
60759c7ad52SXin LI 	if ((s = socket(AF_UNIX, uflag ? SOCK_DGRAM : SOCK_STREAM,
60859c7ad52SXin LI 	     0)) < 0)
60959c7ad52SXin LI 		return (-1);
61059c7ad52SXin LI 
61159c7ad52SXin LI 	memset(&sun, 0, sizeof(struct sockaddr_un));
61259c7ad52SXin LI 	sun.sun_family = AF_UNIX;
61359c7ad52SXin LI 
61459c7ad52SXin LI 	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
61559c7ad52SXin LI 	    sizeof(sun.sun_path)) {
61659c7ad52SXin LI 		close(s);
61759c7ad52SXin LI 		errno = ENAMETOOLONG;
61859c7ad52SXin LI 		return (-1);
61959c7ad52SXin LI 	}
62059c7ad52SXin LI 
62159c7ad52SXin LI 	if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
62259c7ad52SXin LI 		close(s);
62359c7ad52SXin LI 		return (-1);
62459c7ad52SXin LI 	}
62559c7ad52SXin LI 	return (s);
62659c7ad52SXin LI }
62759c7ad52SXin LI 
62859c7ad52SXin LI /*
6298c384020SXin LI  * unix_connect()
6308c384020SXin LI  * Returns a socket connected to a local unix socket. Returns -1 on failure.
6318c384020SXin LI  */
6328c384020SXin LI int
6338c384020SXin LI unix_connect(char *path)
6348c384020SXin LI {
6358c384020SXin LI 	struct sockaddr_un sun;
6368c384020SXin LI 	int s;
6378c384020SXin LI 
63859c7ad52SXin LI 	if (uflag) {
63959c7ad52SXin LI 		if ((s = unix_bind(unix_dg_tmp_socket)) < 0)
64059c7ad52SXin LI 			return (-1);
64159c7ad52SXin LI 	} else {
6428c384020SXin LI 		if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
6438c384020SXin LI 			return (-1);
64459c7ad52SXin LI 	}
6455abd6fdcSXin LI 	(void)fcntl(s, F_SETFD, FD_CLOEXEC);
6468c384020SXin LI 
6478c384020SXin LI 	memset(&sun, 0, sizeof(struct sockaddr_un));
6488c384020SXin LI 	sun.sun_family = AF_UNIX;
6498c384020SXin LI 
6508c384020SXin LI 	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
6518c384020SXin LI 	    sizeof(sun.sun_path)) {
6528c384020SXin LI 		close(s);
6538c384020SXin LI 		errno = ENAMETOOLONG;
6548c384020SXin LI 		return (-1);
6558c384020SXin LI 	}
6568c384020SXin LI 	if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
6578c384020SXin LI 		close(s);
6588c384020SXin LI 		return (-1);
6598c384020SXin LI 	}
6608c384020SXin LI 	return (s);
6618c384020SXin LI 
6628c384020SXin LI }
6638c384020SXin LI 
6648c384020SXin LI /*
6658c384020SXin LI  * unix_listen()
6668c384020SXin LI  * Create a unix domain socket, and listen on it.
6678c384020SXin LI  */
6688c384020SXin LI int
6698c384020SXin LI unix_listen(char *path)
6708c384020SXin LI {
6718c384020SXin LI 	int s;
67259c7ad52SXin LI 	if ((s = unix_bind(path)) < 0)
6738c384020SXin LI 		return (-1);
6748c384020SXin LI 
6758c384020SXin LI 	if (listen(s, 5) < 0) {
6768c384020SXin LI 		close(s);
6778c384020SXin LI 		return (-1);
6788c384020SXin LI 	}
6798c384020SXin LI 	return (s);
6808c384020SXin LI }
6818c384020SXin LI 
6828c384020SXin LI /*
6838c384020SXin LI  * remote_connect()
6848c384020SXin LI  * Returns a socket connected to a remote host. Properly binds to a local
6858c384020SXin LI  * port or source address if needed. Returns -1 on failure.
6868c384020SXin LI  */
6878c384020SXin LI int
6882440a458SXin LI remote_connect(const char *host, const char *port, struct addrinfo hints)
6898c384020SXin LI {
6908c384020SXin LI 	struct addrinfo *res, *res0;
6917dcaa833SXin LI 	int s, error, on = 1;
6928c384020SXin LI 
6938c384020SXin LI 	if ((error = getaddrinfo(host, port, &hints, &res)))
6948c384020SXin LI 		errx(1, "getaddrinfo: %s", gai_strerror(error));
6958c384020SXin LI 
6968c384020SXin LI 	res0 = res;
6978c384020SXin LI 	do {
6988c384020SXin LI 		if ((s = socket(res0->ai_family, res0->ai_socktype,
6998c384020SXin LI 		    res0->ai_protocol)) < 0)
7008c384020SXin LI 			continue;
7018c384020SXin LI 
7023ae0125aSXin LI 		if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_SETFIB,
7033ae0125aSXin LI 		    &rtableid, sizeof(rtableid)) == -1))
7043ae0125aSXin LI 			err(1, "setsockopt SO_SETFIB");
7052d5ea05aSXin LI 
7068c384020SXin LI 		/* Bind to a local port or source address if specified. */
7078c384020SXin LI 		if (sflag || pflag) {
7088c384020SXin LI 			struct addrinfo ahints, *ares;
7098c384020SXin LI 
7106856a5e3SXin LI 			/* try IP_BINDANY, but don't insist */
7116856a5e3SXin LI 			setsockopt(s, IPPROTO_IP, IP_BINDANY, &on, sizeof(on));
7128c384020SXin LI 			memset(&ahints, 0, sizeof(struct addrinfo));
7138c384020SXin LI 			ahints.ai_family = res0->ai_family;
7148c384020SXin LI 			ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
7158c384020SXin LI 			ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
7168c384020SXin LI 			ahints.ai_flags = AI_PASSIVE;
7178c384020SXin LI 			if ((error = getaddrinfo(sflag, pflag, &ahints, &ares)))
7188c384020SXin LI 				errx(1, "getaddrinfo: %s", gai_strerror(error));
7198c384020SXin LI 
7208c384020SXin LI 			if (bind(s, (struct sockaddr *)ares->ai_addr,
7218c384020SXin LI 			    ares->ai_addrlen) < 0)
722a5570ae0SXin LI 				err(1, "bind failed");
7238c384020SXin LI 			freeaddrinfo(ares);
7248c384020SXin LI 		}
7252440a458SXin LI 
7268c54dbfbSXin LI 		set_common_sockopts(s, res0->ai_family);
7278c384020SXin LI 
728ac3ea910SXin LI 		if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
7298c384020SXin LI 			break;
7308c384020SXin LI 		else if (vflag)
7318c384020SXin LI 			warn("connect to %s port %s (%s) failed", host, port,
7328c384020SXin LI 			    uflag ? "udp" : "tcp");
7338c384020SXin LI 
7348c384020SXin LI 		close(s);
7358c384020SXin LI 		s = -1;
7368c384020SXin LI 	} while ((res0 = res0->ai_next) != NULL);
7378c384020SXin LI 
7388c384020SXin LI 	freeaddrinfo(res);
7398c384020SXin LI 
7408c384020SXin LI 	return (s);
7418c384020SXin LI }
7428c384020SXin LI 
743ac3ea910SXin LI int
744ac3ea910SXin LI timeout_connect(int s, const struct sockaddr *name, socklen_t namelen)
745ac3ea910SXin LI {
746ac3ea910SXin LI 	struct pollfd pfd;
747ac3ea910SXin LI 	socklen_t optlen;
748ac3ea910SXin LI 	int flags, optval;
749ac3ea910SXin LI 	int ret;
750ac3ea910SXin LI 
751ac3ea910SXin LI 	if (timeout != -1) {
752ac3ea910SXin LI 		flags = fcntl(s, F_GETFL, 0);
753ac3ea910SXin LI 		if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
754ac3ea910SXin LI 			err(1, "set non-blocking mode");
755ac3ea910SXin LI 	}
756ac3ea910SXin LI 
757ac3ea910SXin LI 	if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) {
758ac3ea910SXin LI 		pfd.fd = s;
759ac3ea910SXin LI 		pfd.events = POLLOUT;
760ac3ea910SXin LI 		if ((ret = poll(&pfd, 1, timeout)) == 1) {
761ac3ea910SXin LI 			optlen = sizeof(optval);
762ac3ea910SXin LI 			if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR,
763ac3ea910SXin LI 			    &optval, &optlen)) == 0) {
764ac3ea910SXin LI 				errno = optval;
765ac3ea910SXin LI 				ret = optval == 0 ? 0 : -1;
766ac3ea910SXin LI 			}
767ac3ea910SXin LI 		} else if (ret == 0) {
768ac3ea910SXin LI 			errno = ETIMEDOUT;
769ac3ea910SXin LI 			ret = -1;
770ac3ea910SXin LI 		} else
771ac3ea910SXin LI 			err(1, "poll failed");
772ac3ea910SXin LI 	}
773ac3ea910SXin LI 
774ac3ea910SXin LI 	if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1)
775ac3ea910SXin LI 		err(1, "restoring flags");
776ac3ea910SXin LI 
777ac3ea910SXin LI 	return (ret);
778ac3ea910SXin LI }
779ac3ea910SXin LI 
7808c384020SXin LI /*
7818c384020SXin LI  * local_listen()
7828c384020SXin LI  * Returns a socket listening on a local port, binds to specified source
7838c384020SXin LI  * address. Returns -1 on failure.
7848c384020SXin LI  */
7858c384020SXin LI int
7868c384020SXin LI local_listen(char *host, char *port, struct addrinfo hints)
7878c384020SXin LI {
7888c384020SXin LI 	struct addrinfo *res, *res0;
7898c384020SXin LI 	int s, ret, x = 1;
7908c384020SXin LI 	int error;
7918c384020SXin LI 
7928c384020SXin LI 	/* Allow nodename to be null. */
7938c384020SXin LI 	hints.ai_flags |= AI_PASSIVE;
7948c384020SXin LI 
7958c384020SXin LI 	/*
7968c384020SXin LI 	 * In the case of binding to a wildcard address
7978c384020SXin LI 	 * default to binding to an ipv4 address.
7988c384020SXin LI 	 */
7998c384020SXin LI 	if (host == NULL && hints.ai_family == AF_UNSPEC)
8008c384020SXin LI 		hints.ai_family = AF_INET;
8018c384020SXin LI 
8028c384020SXin LI 	if ((error = getaddrinfo(host, port, &hints, &res)))
8038c384020SXin LI 		errx(1, "getaddrinfo: %s", gai_strerror(error));
8048c384020SXin LI 
8058c384020SXin LI 	res0 = res;
8068c384020SXin LI 	do {
807*04a3ca71SMark Johnston 		int opt;
808*04a3ca71SMark Johnston 
8098c384020SXin LI 		if ((s = socket(res0->ai_family, res0->ai_socktype,
8102440a458SXin LI 		    res0->ai_protocol)) < 0)
8118c384020SXin LI 			continue;
8128c384020SXin LI 
813a5570ae0SXin LI 		if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_SETFIB,
8143ae0125aSXin LI 		    &rtableid, sizeof(rtableid)) == -1))
8153ae0125aSXin LI 			err(1, "setsockopt SO_SETFIB");
8162d5ea05aSXin LI 
817*04a3ca71SMark Johnston 		opt = FreeBSD_lb != 0 ? SO_REUSEPORT_LB : SO_REUSEPORT;
818*04a3ca71SMark Johnston 		ret = setsockopt(s, SOL_SOCKET, opt, &x, sizeof(x));
8198c384020SXin LI 		if (ret == -1)
8208c384020SXin LI 			err(1, NULL);
821fcf59617SAndrey V. Elsukov 
8227dcaa833SXin LI 		if (FreeBSD_Oflag) {
823bc38f653SBruce M Simpson 			if (setsockopt(s, IPPROTO_TCP, TCP_NOOPT,
8247dcaa833SXin LI 			    &FreeBSD_Oflag, sizeof(FreeBSD_Oflag)) == -1)
825bc38f653SBruce M Simpson 				err(1, "disable TCP options");
826bc38f653SBruce M Simpson 		}
8278c384020SXin LI 
8288c54dbfbSXin LI 		set_common_sockopts(s, res0->ai_family);
8298c54dbfbSXin LI 
8308c384020SXin LI 		if (bind(s, (struct sockaddr *)res0->ai_addr,
8318c384020SXin LI 		    res0->ai_addrlen) == 0)
8328c384020SXin LI 			break;
8338c384020SXin LI 
8348c384020SXin LI 		close(s);
8358c384020SXin LI 		s = -1;
8368c384020SXin LI 	} while ((res0 = res0->ai_next) != NULL);
8378c384020SXin LI 
8388c384020SXin LI 	if (!uflag && s != -1) {
8398c384020SXin LI 		if (listen(s, 1) < 0)
8408c384020SXin LI 			err(1, "listen");
8418c384020SXin LI 	}
8428c384020SXin LI 
8438c384020SXin LI 	freeaddrinfo(res);
8448c384020SXin LI 
8458c384020SXin LI 	return (s);
8468c384020SXin LI }
8478c384020SXin LI 
8488c384020SXin LI /*
8498c384020SXin LI  * readwrite()
8508c384020SXin LI  * Loop that polls on the network file descriptor and stdin.
8518c384020SXin LI  */
8528c384020SXin LI void
8538c54dbfbSXin LI readwrite(int net_fd)
8548c384020SXin LI {
8558c54dbfbSXin LI 	struct pollfd pfd[4];
8568c54dbfbSXin LI 	int stdin_fd = STDIN_FILENO;
8578c54dbfbSXin LI 	int stdout_fd = STDOUT_FILENO;
8588c54dbfbSXin LI 	unsigned char netinbuf[BUFSIZE];
8598c54dbfbSXin LI 	size_t netinbufpos = 0;
8608c54dbfbSXin LI 	unsigned char stdinbuf[BUFSIZE];
8618c54dbfbSXin LI 	size_t stdinbufpos = 0;
8628c54dbfbSXin LI 	int n, num_fds;
8631e62ecedSEdward Tomasz Napierala 	int stats_printed = 0;
8648c54dbfbSXin LI 	ssize_t ret;
8652440a458SXin LI 
8668c54dbfbSXin LI 	/* don't read from stdin if requested */
8678c54dbfbSXin LI 	if (dflag)
8688c54dbfbSXin LI 		stdin_fd = -1;
8698c384020SXin LI 
8708c54dbfbSXin LI 	/* stdin */
871cef7ab70STom Jones 	pfd[POLL_STDIN].fd = (tun_fd != -1) ? tun_fd : stdin_fd;
8728c54dbfbSXin LI 	pfd[POLL_STDIN].events = POLLIN;
8738c384020SXin LI 
8748c54dbfbSXin LI 	/* network out */
8758c54dbfbSXin LI 	pfd[POLL_NETOUT].fd = net_fd;
8768c54dbfbSXin LI 	pfd[POLL_NETOUT].events = 0;
8778c384020SXin LI 
8788c54dbfbSXin LI 	/* network in */
8798c54dbfbSXin LI 	pfd[POLL_NETIN].fd = net_fd;
8808c54dbfbSXin LI 	pfd[POLL_NETIN].events = POLLIN;
8818c54dbfbSXin LI 
8828c54dbfbSXin LI 	/* stdout */
883cef7ab70STom Jones 	pfd[POLL_STDOUT].fd = (tun_fd != -1) ? tun_fd : stdout_fd;
8848c54dbfbSXin LI 	pfd[POLL_STDOUT].events = 0;
8858c54dbfbSXin LI 
8868c54dbfbSXin LI 	while (1) {
8878c54dbfbSXin LI 		/* both inputs are gone, buffers are empty, we are done */
8888c54dbfbSXin LI 		if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1
8898c54dbfbSXin LI 		    && stdinbufpos == 0 && netinbufpos == 0) {
8901e62ecedSEdward Tomasz Napierala 			if (FreeBSD_Mflag && !stats_printed)
8911e62ecedSEdward Tomasz Napierala 				FreeBSD_stats_print(net_fd);
8928c54dbfbSXin LI 			close(net_fd);
8938c54dbfbSXin LI 			return;
8948c54dbfbSXin LI 		}
8958c54dbfbSXin LI 		/* both outputs are gone, we can't continue */
8968c54dbfbSXin LI 		if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) {
8971e62ecedSEdward Tomasz Napierala 			if (FreeBSD_Mflag && !stats_printed)
8981e62ecedSEdward Tomasz Napierala 				FreeBSD_stats_print(net_fd);
8998c54dbfbSXin LI 			close(net_fd);
9008c54dbfbSXin LI 			return;
9018c54dbfbSXin LI 		}
9028c54dbfbSXin LI 		/* listen and net in gone, queues empty, done */
9038c54dbfbSXin LI 		if (lflag && pfd[POLL_NETIN].fd == -1
9048c54dbfbSXin LI 		    && stdinbufpos == 0 && netinbufpos == 0) {
9051e62ecedSEdward Tomasz Napierala 			if (FreeBSD_Mflag && !stats_printed)
9061e62ecedSEdward Tomasz Napierala 				FreeBSD_stats_print(net_fd);
9078c54dbfbSXin LI 			close(net_fd);
9088c54dbfbSXin LI 			return;
9098c54dbfbSXin LI 		}
9108c54dbfbSXin LI 
9118c54dbfbSXin LI 		/* help says -i is for "wait between lines sent". We read and
9128c54dbfbSXin LI 		 * write arbitrary amounts of data, and we don't want to start
9138c54dbfbSXin LI 		 * scanning for newlines, so this is as good as it gets */
9148c384020SXin LI 		if (iflag)
9158c384020SXin LI 			sleep(iflag);
9168c384020SXin LI 
9178c54dbfbSXin LI 		/* poll */
9188c54dbfbSXin LI 		num_fds = poll(pfd, 4, timeout);
9198c54dbfbSXin LI 
9208c54dbfbSXin LI 		/* treat poll errors */
9218c54dbfbSXin LI 		if (num_fds == -1) {
9228c54dbfbSXin LI 			close(net_fd);
9238c54dbfbSXin LI 			err(1, "polling error");
9248c384020SXin LI 		}
9258c384020SXin LI 
9268c54dbfbSXin LI 		/* timeout happened */
9271e62ecedSEdward Tomasz Napierala 		if (num_fds == 0) {
9281e62ecedSEdward Tomasz Napierala 			if (FreeBSD_Mflag)
9291e62ecedSEdward Tomasz Napierala 				FreeBSD_stats_print(net_fd);
9308c384020SXin LI 			return;
9311e62ecedSEdward Tomasz Napierala 		}
9328c384020SXin LI 
9338c54dbfbSXin LI 		/* treat socket error conditions */
9348c54dbfbSXin LI 		for (n = 0; n < 4; n++) {
9358c54dbfbSXin LI 			if (pfd[n].revents & (POLLERR|POLLNVAL)) {
9368c54dbfbSXin LI 				pfd[n].fd = -1;
9378c384020SXin LI 			}
9388c384020SXin LI 		}
9398c54dbfbSXin LI 		/* reading is possible after HUP */
9408c54dbfbSXin LI 		if (pfd[POLL_STDIN].events & POLLIN &&
9418c54dbfbSXin LI 		    pfd[POLL_STDIN].revents & POLLHUP &&
9428c54dbfbSXin LI 		    ! (pfd[POLL_STDIN].revents & POLLIN))
9438c54dbfbSXin LI 				pfd[POLL_STDIN].fd = -1;
9448c384020SXin LI 
9458c54dbfbSXin LI 		if (pfd[POLL_NETIN].events & POLLIN &&
9468c54dbfbSXin LI 		    pfd[POLL_NETIN].revents & POLLHUP &&
9478c54dbfbSXin LI 		    ! (pfd[POLL_NETIN].revents & POLLIN))
9488c54dbfbSXin LI 				pfd[POLL_NETIN].fd = -1;
9498c54dbfbSXin LI 
9508c54dbfbSXin LI 		if (pfd[POLL_NETOUT].revents & POLLHUP) {
9510772266eSXin LI 			if (Nflag)
9528c54dbfbSXin LI 				shutdown(pfd[POLL_NETOUT].fd, SHUT_WR);
9538c54dbfbSXin LI 			pfd[POLL_NETOUT].fd = -1;
9548c54dbfbSXin LI 		}
9558c54dbfbSXin LI 		/* if HUP, stop watching stdout */
9568c54dbfbSXin LI 		if (pfd[POLL_STDOUT].revents & POLLHUP)
9578c54dbfbSXin LI 			pfd[POLL_STDOUT].fd = -1;
9588c54dbfbSXin LI 		/* if no net out, stop watching stdin */
9598c54dbfbSXin LI 		if (pfd[POLL_NETOUT].fd == -1)
9608c54dbfbSXin LI 			pfd[POLL_STDIN].fd = -1;
9618c54dbfbSXin LI 		/* if no stdout, stop watching net in */
9628c54dbfbSXin LI 		if (pfd[POLL_STDOUT].fd == -1) {
9638c54dbfbSXin LI 			if (pfd[POLL_NETIN].fd != -1)
9648c54dbfbSXin LI 				shutdown(pfd[POLL_NETIN].fd, SHUT_RD);
9658c54dbfbSXin LI 			pfd[POLL_NETIN].fd = -1;
9668c54dbfbSXin LI 		}
9678c54dbfbSXin LI 
9688c54dbfbSXin LI 		/* try to read from stdin */
9698c54dbfbSXin LI 		if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) {
9708c54dbfbSXin LI 			ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf,
9718c54dbfbSXin LI 			    &stdinbufpos);
9728c54dbfbSXin LI 			/* error or eof on stdin - remove from pfd */
9738c54dbfbSXin LI 			if (ret == 0 || ret == -1)
9748c54dbfbSXin LI 				pfd[POLL_STDIN].fd = -1;
9758c54dbfbSXin LI 			/* read something - poll net out */
9768c54dbfbSXin LI 			if (stdinbufpos > 0)
9778c54dbfbSXin LI 				pfd[POLL_NETOUT].events = POLLOUT;
9788c54dbfbSXin LI 			/* filled buffer - remove self from polling */
9798c54dbfbSXin LI 			if (stdinbufpos == BUFSIZE)
9808c54dbfbSXin LI 				pfd[POLL_STDIN].events = 0;
9818c54dbfbSXin LI 		}
9828c54dbfbSXin LI 		/* try to write to network */
9838c54dbfbSXin LI 		if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) {
9848c54dbfbSXin LI 			ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf,
985d4b3aefdSPietro Cerutti 			    &stdinbufpos, FreeBSD_crlf);
9868c54dbfbSXin LI 			if (ret == -1)
9878c54dbfbSXin LI 				pfd[POLL_NETOUT].fd = -1;
9888c54dbfbSXin LI 			/* buffer empty - remove self from polling */
9898c54dbfbSXin LI 			if (stdinbufpos == 0)
9908c54dbfbSXin LI 				pfd[POLL_NETOUT].events = 0;
9918c54dbfbSXin LI 			/* buffer no longer full - poll stdin again */
9928c54dbfbSXin LI 			if (stdinbufpos < BUFSIZE)
9938c54dbfbSXin LI 				pfd[POLL_STDIN].events = POLLIN;
9948c54dbfbSXin LI 		}
9958c54dbfbSXin LI 		/* try to read from network */
9968c54dbfbSXin LI 		if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) {
9978c54dbfbSXin LI 			ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf,
9988c54dbfbSXin LI 			    &netinbufpos);
9998c54dbfbSXin LI 			if (ret == -1)
10008c54dbfbSXin LI 				pfd[POLL_NETIN].fd = -1;
10018c54dbfbSXin LI 			/* eof on net in - remove from pfd */
10028c54dbfbSXin LI 			if (ret == 0) {
10038c54dbfbSXin LI 				shutdown(pfd[POLL_NETIN].fd, SHUT_RD);
10048c54dbfbSXin LI 				pfd[POLL_NETIN].fd = -1;
10058c54dbfbSXin LI 			}
10068c54dbfbSXin LI 			/* read something - poll stdout */
10078c54dbfbSXin LI 			if (netinbufpos > 0)
10088c54dbfbSXin LI 				pfd[POLL_STDOUT].events = POLLOUT;
10098c54dbfbSXin LI 			/* filled buffer - remove self from polling */
10108c54dbfbSXin LI 			if (netinbufpos == BUFSIZE)
10118c54dbfbSXin LI 				pfd[POLL_NETIN].events = 0;
10128c54dbfbSXin LI 			/* handle telnet */
10138c54dbfbSXin LI 			if (tflag)
10148c54dbfbSXin LI 				atelnet(pfd[POLL_NETIN].fd, netinbuf,
10158c54dbfbSXin LI 				    netinbufpos);
10168c54dbfbSXin LI 		}
10178c54dbfbSXin LI 		/* try to write to stdout */
10188c54dbfbSXin LI 		if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) {
10198c54dbfbSXin LI 			ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf,
1020d4b3aefdSPietro Cerutti 			    &netinbufpos, 0);
10218c54dbfbSXin LI 			if (ret == -1)
10228c54dbfbSXin LI 				pfd[POLL_STDOUT].fd = -1;
10238c54dbfbSXin LI 			/* buffer empty - remove self from polling */
10248c54dbfbSXin LI 			if (netinbufpos == 0)
10258c54dbfbSXin LI 				pfd[POLL_STDOUT].events = 0;
10268c54dbfbSXin LI 			/* buffer no longer full - poll net in again */
10278c54dbfbSXin LI 			if (netinbufpos < BUFSIZE)
10288c54dbfbSXin LI 				pfd[POLL_NETIN].events = POLLIN;
10298c54dbfbSXin LI 		}
10308c54dbfbSXin LI 
10318c54dbfbSXin LI 		/* stdin gone and queue empty? */
10328c54dbfbSXin LI 		if (pfd[POLL_STDIN].fd == -1 && stdinbufpos == 0) {
10331e62ecedSEdward Tomasz Napierala 			if (pfd[POLL_NETOUT].fd != -1 && Nflag) {
10341e62ecedSEdward Tomasz Napierala 				if (FreeBSD_Mflag) {
10351e62ecedSEdward Tomasz Napierala 					FreeBSD_stats_print(net_fd);
10361e62ecedSEdward Tomasz Napierala 					stats_printed = 1;
10371e62ecedSEdward Tomasz Napierala 				}
10388c54dbfbSXin LI 				shutdown(pfd[POLL_NETOUT].fd, SHUT_WR);
10391e62ecedSEdward Tomasz Napierala 			}
10408c54dbfbSXin LI 			pfd[POLL_NETOUT].fd = -1;
10418c54dbfbSXin LI 		}
10428c54dbfbSXin LI 		/* net in gone and queue empty? */
10438c54dbfbSXin LI 		if (pfd[POLL_NETIN].fd == -1 && netinbufpos == 0) {
10448c54dbfbSXin LI 			pfd[POLL_STDOUT].fd = -1;
10458c384020SXin LI 		}
10468c384020SXin LI 	}
10478c384020SXin LI }
10488c54dbfbSXin LI 
10498c54dbfbSXin LI ssize_t
1050d4b3aefdSPietro Cerutti write_wrapper(int fd, const void *buf, size_t buflen)
10518c54dbfbSXin LI {
1052d4b3aefdSPietro Cerutti 	ssize_t n = write(fd, buf, buflen);
10538c54dbfbSXin LI 	/* don't treat EAGAIN, EINTR as error */
1054d4b3aefdSPietro Cerutti 	return (n == -1 && (errno == EAGAIN || errno == EINTR)) ? -2 : n;
1055d4b3aefdSPietro Cerutti }
1056d4b3aefdSPietro Cerutti 
1057d4b3aefdSPietro Cerutti ssize_t
1058d4b3aefdSPietro Cerutti drainbuf(int fd, unsigned char *buf, size_t *bufpos, int crlf)
1059d4b3aefdSPietro Cerutti {
1060d4b3aefdSPietro Cerutti 	ssize_t n = *bufpos, n2 = 0;
1061d4b3aefdSPietro Cerutti 	ssize_t adjust;
1062d4b3aefdSPietro Cerutti 	unsigned char *lf = NULL;
1063d4b3aefdSPietro Cerutti 
1064d4b3aefdSPietro Cerutti 	if (crlf) {
1065d4b3aefdSPietro Cerutti 		lf = memchr(buf, '\n', *bufpos);
1066d4b3aefdSPietro Cerutti 		if (lf && (lf == buf || *(lf - 1) != '\r'))
1067d4b3aefdSPietro Cerutti 			n = lf - buf;
1068d4b3aefdSPietro Cerutti 		else
1069d4b3aefdSPietro Cerutti 			lf = NULL;
1070d4b3aefdSPietro Cerutti 	}
1071d4b3aefdSPietro Cerutti 
1072d4b3aefdSPietro Cerutti 	if (n != 0) {
1073d4b3aefdSPietro Cerutti 		n = write_wrapper(fd, buf, n);
10748c54dbfbSXin LI 		if (n <= 0)
10758c54dbfbSXin LI 			return n;
1076d4b3aefdSPietro Cerutti 	}
1077d4b3aefdSPietro Cerutti 
1078d4b3aefdSPietro Cerutti 	if (lf) {
1079d4b3aefdSPietro Cerutti 		n2 = write_wrapper(fd, "\r\n", 2);
1080d4b3aefdSPietro Cerutti 		if (n2 <= 0)
1081d4b3aefdSPietro Cerutti 			return n2;
1082d4b3aefdSPietro Cerutti 		n += 1;
1083d4b3aefdSPietro Cerutti 	}
1084d4b3aefdSPietro Cerutti 
10858c54dbfbSXin LI 	/* adjust buffer */
10868c54dbfbSXin LI 	adjust = *bufpos - n;
10878c54dbfbSXin LI 	if (adjust > 0)
10888c54dbfbSXin LI 		memmove(buf, buf + n, adjust);
10898c54dbfbSXin LI 	*bufpos -= n;
10908c54dbfbSXin LI 	return n;
10918c54dbfbSXin LI }
10928c54dbfbSXin LI 
10938c54dbfbSXin LI 
10948c54dbfbSXin LI ssize_t
10958c54dbfbSXin LI fillbuf(int fd, unsigned char *buf, size_t *bufpos)
10968c54dbfbSXin LI {
10978c54dbfbSXin LI 	size_t num = BUFSIZE - *bufpos;
10988c54dbfbSXin LI 	ssize_t n;
10998c54dbfbSXin LI 
11008c54dbfbSXin LI 	n = read(fd, buf + *bufpos, num);
11018c54dbfbSXin LI 	/* don't treat EAGAIN, EINTR as error */
11028c54dbfbSXin LI 	if (n == -1 && (errno == EAGAIN || errno == EINTR))
11038c54dbfbSXin LI 		n = -2;
11048c54dbfbSXin LI 	if (n <= 0)
11058c54dbfbSXin LI 		return n;
11068c54dbfbSXin LI 	*bufpos += n;
11078c54dbfbSXin LI 	return n;
11088c384020SXin LI }
11098c384020SXin LI 
11103ae0125aSXin LI /*
11113ae0125aSXin LI  * fdpass()
11123ae0125aSXin LI  * Pass the connected file descriptor to stdout and exit.
11133ae0125aSXin LI  */
11143ae0125aSXin LI void
11153ae0125aSXin LI fdpass(int nfd)
11163ae0125aSXin LI {
11173ae0125aSXin LI 	struct msghdr mh;
11183ae0125aSXin LI 	union {
11193ae0125aSXin LI 		struct cmsghdr hdr;
11203ae0125aSXin LI 		char buf[CMSG_SPACE(sizeof(int))];
11213ae0125aSXin LI 	} cmsgbuf;
11223ae0125aSXin LI 	struct cmsghdr *cmsg;
11233ae0125aSXin LI 	struct iovec iov;
11243ae0125aSXin LI 	char c = '\0';
11253ae0125aSXin LI 	ssize_t r;
11263ae0125aSXin LI 	struct pollfd pfd;
11273ae0125aSXin LI 
11283ae0125aSXin LI 	/* Avoid obvious stupidity */
11293ae0125aSXin LI 	if (isatty(STDOUT_FILENO))
11303ae0125aSXin LI 		errx(1, "Cannot pass file descriptor to tty");
11313ae0125aSXin LI 
11323ae0125aSXin LI 	bzero(&mh, sizeof(mh));
11333ae0125aSXin LI 	bzero(&cmsgbuf, sizeof(cmsgbuf));
11343ae0125aSXin LI 	bzero(&iov, sizeof(iov));
11353ae0125aSXin LI 
11363ae0125aSXin LI 	mh.msg_control = (caddr_t)&cmsgbuf.buf;
11373ae0125aSXin LI 	mh.msg_controllen = sizeof(cmsgbuf.buf);
11383ae0125aSXin LI 	cmsg = CMSG_FIRSTHDR(&mh);
11393ae0125aSXin LI 	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
11403ae0125aSXin LI 	cmsg->cmsg_level = SOL_SOCKET;
11413ae0125aSXin LI 	cmsg->cmsg_type = SCM_RIGHTS;
11423ae0125aSXin LI 	*(int *)CMSG_DATA(cmsg) = nfd;
11433ae0125aSXin LI 
11443ae0125aSXin LI 	iov.iov_base = &c;
11453ae0125aSXin LI 	iov.iov_len = 1;
11463ae0125aSXin LI 	mh.msg_iov = &iov;
11473ae0125aSXin LI 	mh.msg_iovlen = 1;
11483ae0125aSXin LI 
11493ae0125aSXin LI 	bzero(&pfd, sizeof(pfd));
11503ae0125aSXin LI 	pfd.fd = STDOUT_FILENO;
1151100e2a06SXin LI 	pfd.events = POLLOUT;
11523ae0125aSXin LI 	for (;;) {
11533ae0125aSXin LI 		r = sendmsg(STDOUT_FILENO, &mh, 0);
11543ae0125aSXin LI 		if (r == -1) {
11553ae0125aSXin LI 			if (errno == EAGAIN || errno == EINTR) {
11563ae0125aSXin LI 				if (poll(&pfd, 1, -1) == -1)
11573ae0125aSXin LI 					err(1, "poll");
11583ae0125aSXin LI 				continue;
11593ae0125aSXin LI 			}
11603ae0125aSXin LI 			err(1, "sendmsg");
1161100e2a06SXin LI 		} else if (r != 1)
11623ae0125aSXin LI 			errx(1, "sendmsg: unexpected return value %zd", r);
11633ae0125aSXin LI 		else
11643ae0125aSXin LI 			break;
11653ae0125aSXin LI 	}
11663ae0125aSXin LI 	exit(0);
11673ae0125aSXin LI }
11683ae0125aSXin LI 
11698c384020SXin LI /* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */
11708c384020SXin LI void
11718c384020SXin LI atelnet(int nfd, unsigned char *buf, unsigned int size)
11728c384020SXin LI {
11738c384020SXin LI 	unsigned char *p, *end;
11748c384020SXin LI 	unsigned char obuf[4];
11758c384020SXin LI 
117626bf9c3bSXin LI 	if (size < 3)
117726bf9c3bSXin LI 		return;
117826bf9c3bSXin LI 	end = buf + size - 2;
11798c384020SXin LI 
11808c384020SXin LI 	for (p = buf; p < end; p++) {
11818c384020SXin LI 		if (*p != IAC)
118226bf9c3bSXin LI 			continue;
11838c384020SXin LI 
11848c384020SXin LI 		obuf[0] = IAC;
11858c384020SXin LI 		p++;
11868c384020SXin LI 		if ((*p == WILL) || (*p == WONT))
11878c384020SXin LI 			obuf[1] = DONT;
118826bf9c3bSXin LI 		else if ((*p == DO) || (*p == DONT))
11898c384020SXin LI 			obuf[1] = WONT;
119026bf9c3bSXin LI 		else
119126bf9c3bSXin LI 			continue;
119226bf9c3bSXin LI 
11938c384020SXin LI 		p++;
11948c384020SXin LI 		obuf[2] = *p;
11952440a458SXin LI 		if (atomicio(vwrite, nfd, obuf, 3) != 3)
11962440a458SXin LI 			warn("Write Error!");
11978c384020SXin LI 	}
11988c384020SXin LI }
11998c384020SXin LI 
12008c384020SXin LI /*
12018c384020SXin LI  * build_ports()
1202ac3ea910SXin LI  * Build an array of ports in portlist[], listing each port
12038c384020SXin LI  * that we should try to connect to.
12048c384020SXin LI  */
12058c384020SXin LI void
12068c384020SXin LI build_ports(char *p)
12078c384020SXin LI {
1208bdb0aaa1SXin LI 	const char *errstr;
1209bdb0aaa1SXin LI 	char *n;
12108c384020SXin LI 	int hi, lo, cp;
12118c384020SXin LI 	int x = 0;
12128c384020SXin LI 
12138c384020SXin LI 	if ((n = strchr(p, '-')) != NULL) {
12148c384020SXin LI 		*n = '\0';
12158c384020SXin LI 		n++;
12168c384020SXin LI 
12178c384020SXin LI 		/* Make sure the ports are in order: lowest->highest. */
1218bdb0aaa1SXin LI 		hi = strtonum(n, 1, PORT_MAX, &errstr);
1219bdb0aaa1SXin LI 		if (errstr)
1220bdb0aaa1SXin LI 			errx(1, "port number %s: %s", errstr, n);
1221bdb0aaa1SXin LI 		lo = strtonum(p, 1, PORT_MAX, &errstr);
1222bdb0aaa1SXin LI 		if (errstr)
1223bdb0aaa1SXin LI 			errx(1, "port number %s: %s", errstr, p);
12248c384020SXin LI 
12258c384020SXin LI 		if (lo > hi) {
12268c384020SXin LI 			cp = hi;
12278c384020SXin LI 			hi = lo;
12288c384020SXin LI 			lo = cp;
12298c384020SXin LI 		}
12308c384020SXin LI 
12318c384020SXin LI 		/* Load ports sequentially. */
12328c384020SXin LI 		for (cp = lo; cp <= hi; cp++) {
12338c384020SXin LI 			portlist[x] = calloc(1, PORT_MAX_LEN);
12348c384020SXin LI 			if (portlist[x] == NULL)
12358c384020SXin LI 				err(1, NULL);
12368c384020SXin LI 			snprintf(portlist[x], PORT_MAX_LEN, "%d", cp);
12378c384020SXin LI 			x++;
12388c384020SXin LI 		}
12398c384020SXin LI 
12408c384020SXin LI 		/* Randomly swap ports. */
12418c384020SXin LI 		if (rflag) {
12428c384020SXin LI 			int y;
12438c384020SXin LI 			char *c;
12448c384020SXin LI 
12458c384020SXin LI 			for (x = 0; x <= (hi - lo); x++) {
12468c384020SXin LI 				y = (arc4random() & 0xFFFF) % (hi - lo);
12478c384020SXin LI 				c = portlist[x];
12488c384020SXin LI 				portlist[x] = portlist[y];
12498c384020SXin LI 				portlist[y] = c;
12508c384020SXin LI 			}
12518c384020SXin LI 		}
12528c384020SXin LI 	} else {
1253bdb0aaa1SXin LI 		hi = strtonum(p, 1, PORT_MAX, &errstr);
1254bdb0aaa1SXin LI 		if (errstr)
1255bdb0aaa1SXin LI 			errx(1, "port number %s: %s", errstr, p);
12564f2bbc00SXin LI 		portlist[0] = strdup(p);
12578c384020SXin LI 		if (portlist[0] == NULL)
12588c384020SXin LI 			err(1, NULL);
12598c384020SXin LI 	}
12608c384020SXin LI }
12618c384020SXin LI 
12628c384020SXin LI /*
12638c384020SXin LI  * udptest()
12648c384020SXin LI  * Do a few writes to see if the UDP port is there.
1265ac3ea910SXin LI  * Fails once PF state table is full.
12668c384020SXin LI  */
12678c384020SXin LI int
12688c384020SXin LI udptest(int s)
12698c384020SXin LI {
12708c384020SXin LI 	int i, ret;
12718c384020SXin LI 
12728c384020SXin LI 	for (i = 0; i <= 3; i++) {
12738c384020SXin LI 		if (write(s, "X", 1) == 1)
12748c384020SXin LI 			ret = 1;
12758c384020SXin LI 		else
12768c384020SXin LI 			ret = -1;
12778c384020SXin LI 	}
12788c384020SXin LI 	return (ret);
12798c384020SXin LI }
12808c384020SXin LI 
12818c384020SXin LI void
12821e62ecedSEdward Tomasz Napierala FreeBSD_stats_setup(int s)
12831e62ecedSEdward Tomasz Napierala {
12841e62ecedSEdward Tomasz Napierala 
12851e62ecedSEdward Tomasz Napierala 	if (setsockopt(s, IPPROTO_TCP, TCP_STATS,
12861e62ecedSEdward Tomasz Napierala 	    &FreeBSD_Mflag, sizeof(FreeBSD_Mflag)) == -1) {
12871e62ecedSEdward Tomasz Napierala 		if (errno == EOPNOTSUPP) {
12881e62ecedSEdward Tomasz Napierala 			warnx("getsockopt(TCP_STATS) failed; "
12891e62ecedSEdward Tomasz Napierala 			    "kernel built without \"options STATS\"?");
12901e62ecedSEdward Tomasz Napierala 		}
12911e62ecedSEdward Tomasz Napierala 		err(1, "enable TCP_STATS gathering");
12921e62ecedSEdward Tomasz Napierala 	}
12931e62ecedSEdward Tomasz Napierala }
12941e62ecedSEdward Tomasz Napierala 
12951e62ecedSEdward Tomasz Napierala void
12961e62ecedSEdward Tomasz Napierala FreeBSD_stats_print(int s)
12971e62ecedSEdward Tomasz Napierala {
12981e62ecedSEdward Tomasz Napierala #ifdef WITH_STATS
12991e62ecedSEdward Tomasz Napierala 	struct statsblob *statsb;
13001e62ecedSEdward Tomasz Napierala 	struct sbuf *sb;
13011e62ecedSEdward Tomasz Napierala 	socklen_t sockoptlen;
13021e62ecedSEdward Tomasz Napierala 	int error;
13031e62ecedSEdward Tomasz Napierala 
13041e62ecedSEdward Tomasz Napierala 	/*
13051e62ecedSEdward Tomasz Napierala 	 * This usleep is a workaround for TCP_STATS reporting
13061e62ecedSEdward Tomasz Napierala 	 * incorrect values for TXPB.
13071e62ecedSEdward Tomasz Napierala 	 */
13081e62ecedSEdward Tomasz Napierala 	usleep(100000);
13091e62ecedSEdward Tomasz Napierala 
13101e62ecedSEdward Tomasz Napierala 	sockoptlen = 2048;
13111e62ecedSEdward Tomasz Napierala 	statsb = malloc(sockoptlen);
13121e62ecedSEdward Tomasz Napierala 	if (statsb == NULL)
13131e62ecedSEdward Tomasz Napierala 		err(1, "malloc");
13141e62ecedSEdward Tomasz Napierala 	error = getsockopt(s, IPPROTO_TCP, TCP_STATS, statsb, &sockoptlen);
13151e62ecedSEdward Tomasz Napierala 	if (error != 0) {
13161e62ecedSEdward Tomasz Napierala 		if (errno == EOVERFLOW && statsb->cursz > sockoptlen) {
13171e62ecedSEdward Tomasz Napierala 			/* Retry with a larger size. */
13181e62ecedSEdward Tomasz Napierala 			sockoptlen = statsb->cursz;
13191e62ecedSEdward Tomasz Napierala 			statsb = realloc(statsb, sockoptlen);
13201e62ecedSEdward Tomasz Napierala 			if (statsb == NULL)
13211e62ecedSEdward Tomasz Napierala 				err(1, "realloc");
13221e62ecedSEdward Tomasz Napierala 			error = getsockopt(s, IPPROTO_TCP, TCP_STATS,
13231e62ecedSEdward Tomasz Napierala 			    statsb, &sockoptlen);
13241e62ecedSEdward Tomasz Napierala 		}
13251e62ecedSEdward Tomasz Napierala 		if (error != 0)
13261e62ecedSEdward Tomasz Napierala 			err(1, "getsockopt");
13271e62ecedSEdward Tomasz Napierala 	}
13281e62ecedSEdward Tomasz Napierala 
13291e62ecedSEdward Tomasz Napierala 	sb = sbuf_new_auto();
13301e62ecedSEdward Tomasz Napierala 	error = stats_blob_tostr(statsb, sb, SB_STRFMT_JSON, SB_TOSTR_META);
13311e62ecedSEdward Tomasz Napierala 	if (error != 0)
13321e62ecedSEdward Tomasz Napierala 		errc(1, error, "stats_blob_tostr");
13331e62ecedSEdward Tomasz Napierala 
13341e62ecedSEdward Tomasz Napierala 	error = sbuf_finish(sb);
13351e62ecedSEdward Tomasz Napierala 	if (error != 0)
13361e62ecedSEdward Tomasz Napierala 		err(1, "sbuf_finish");
13371e62ecedSEdward Tomasz Napierala 
13381e62ecedSEdward Tomasz Napierala 	fprintf(stderr, "%s\n", sbuf_data(sb));
13391e62ecedSEdward Tomasz Napierala #endif
13401e62ecedSEdward Tomasz Napierala }
13411e62ecedSEdward Tomasz Napierala 
13421e62ecedSEdward Tomasz Napierala void
13438c54dbfbSXin LI set_common_sockopts(int s, int af)
13442440a458SXin LI {
13452440a458SXin LI 	int x = 1;
13462440a458SXin LI 
13472440a458SXin LI 	if (Sflag) {
13482440a458SXin LI 		if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG,
13492440a458SXin LI 			&x, sizeof(x)) == -1)
13502440a458SXin LI 			err(1, NULL);
13512440a458SXin LI 	}
13522440a458SXin LI 	if (Dflag) {
13532440a458SXin LI 		if (setsockopt(s, SOL_SOCKET, SO_DEBUG,
13542440a458SXin LI 			&x, sizeof(x)) == -1)
13552440a458SXin LI 			err(1, NULL);
13562440a458SXin LI 	}
13572440a458SXin LI 	if (Tflag != -1) {
13588c54dbfbSXin LI 		int proto, option;
13598c54dbfbSXin LI 
13608c54dbfbSXin LI 		if (af == AF_INET6) {
13618c54dbfbSXin LI 			proto = IPPROTO_IPV6;
13628c54dbfbSXin LI 			option = IPV6_TCLASS;
13638c54dbfbSXin LI 		} else {
13648c54dbfbSXin LI 			proto = IPPROTO_IP;
13658c54dbfbSXin LI 			option = IP_TOS;
13668c54dbfbSXin LI 		}
13678c54dbfbSXin LI 
13688c54dbfbSXin LI 		if (setsockopt(s, proto, option, &Tflag, sizeof(Tflag)) == -1)
13692440a458SXin LI 			err(1, "set IP ToS");
13702440a458SXin LI 	}
13717dcaa833SXin LI 	if (Iflag) {
13727dcaa833SXin LI 		if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
13737dcaa833SXin LI 		    &Iflag, sizeof(Iflag)) == -1)
13747dcaa833SXin LI 			err(1, "set TCP receive buffer size");
13757dcaa833SXin LI 	}
1376bc38f653SBruce M Simpson 	if (Oflag) {
13777dcaa833SXin LI 		if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
1378bc38f653SBruce M Simpson 		    &Oflag, sizeof(Oflag)) == -1)
13797dcaa833SXin LI 			err(1, "set TCP send buffer size");
13807dcaa833SXin LI 	}
13817dcaa833SXin LI 	if (FreeBSD_Oflag) {
13827dcaa833SXin LI 		if (setsockopt(s, IPPROTO_TCP, TCP_NOOPT,
13837dcaa833SXin LI 		    &FreeBSD_Oflag, sizeof(FreeBSD_Oflag)) == -1)
1384bc38f653SBruce M Simpson 			err(1, "disable TCP options");
1385bc38f653SBruce M Simpson 	}
13861e62ecedSEdward Tomasz Napierala 	if (FreeBSD_Mflag)
13871e62ecedSEdward Tomasz Napierala 		FreeBSD_stats_setup(s);
1388fcf59617SAndrey V. Elsukov #ifdef IPSEC
1389fcf59617SAndrey V. Elsukov 	if (ipsec_policy[0] != NULL)
1390fcf59617SAndrey V. Elsukov 		add_ipsec_policy(s, af, ipsec_policy[0]);
1391fcf59617SAndrey V. Elsukov 	if (ipsec_policy[1] != NULL)
1392fcf59617SAndrey V. Elsukov 		add_ipsec_policy(s, af, ipsec_policy[1]);
1393fcf59617SAndrey V. Elsukov #endif
13942440a458SXin LI }
13952440a458SXin LI 
13962440a458SXin LI int
1397ac3ea910SXin LI map_tos(char *s, int *val)
13982440a458SXin LI {
1399ac3ea910SXin LI 	/* DiffServ Codepoints and other TOS mappings */
1400ac3ea910SXin LI 	const struct toskeywords {
1401ac3ea910SXin LI 		const char	*keyword;
1402ac3ea910SXin LI 		int		 val;
1403ac3ea910SXin LI 	} *t, toskeywords[] = {
1404ac3ea910SXin LI 		{ "af11",		IPTOS_DSCP_AF11 },
1405ac3ea910SXin LI 		{ "af12",		IPTOS_DSCP_AF12 },
1406ac3ea910SXin LI 		{ "af13",		IPTOS_DSCP_AF13 },
1407ac3ea910SXin LI 		{ "af21",		IPTOS_DSCP_AF21 },
1408ac3ea910SXin LI 		{ "af22",		IPTOS_DSCP_AF22 },
1409ac3ea910SXin LI 		{ "af23",		IPTOS_DSCP_AF23 },
1410ac3ea910SXin LI 		{ "af31",		IPTOS_DSCP_AF31 },
1411ac3ea910SXin LI 		{ "af32",		IPTOS_DSCP_AF32 },
1412ac3ea910SXin LI 		{ "af33",		IPTOS_DSCP_AF33 },
1413ac3ea910SXin LI 		{ "af41",		IPTOS_DSCP_AF41 },
1414ac3ea910SXin LI 		{ "af42",		IPTOS_DSCP_AF42 },
1415ac3ea910SXin LI 		{ "af43",		IPTOS_DSCP_AF43 },
1416ac3ea910SXin LI 		{ "critical",		IPTOS_PREC_CRITIC_ECP },
1417ac3ea910SXin LI 		{ "cs0",		IPTOS_DSCP_CS0 },
1418ac3ea910SXin LI 		{ "cs1",		IPTOS_DSCP_CS1 },
1419ac3ea910SXin LI 		{ "cs2",		IPTOS_DSCP_CS2 },
1420ac3ea910SXin LI 		{ "cs3",		IPTOS_DSCP_CS3 },
1421ac3ea910SXin LI 		{ "cs4",		IPTOS_DSCP_CS4 },
1422ac3ea910SXin LI 		{ "cs5",		IPTOS_DSCP_CS5 },
1423ac3ea910SXin LI 		{ "cs6",		IPTOS_DSCP_CS6 },
1424ac3ea910SXin LI 		{ "cs7",		IPTOS_DSCP_CS7 },
1425ac3ea910SXin LI 		{ "ef",			IPTOS_DSCP_EF },
1426ac3ea910SXin LI 		{ "inetcontrol",	IPTOS_PREC_INTERNETCONTROL },
1427ac3ea910SXin LI 		{ "lowdelay",		IPTOS_LOWDELAY },
1428ac3ea910SXin LI 		{ "netcontrol",		IPTOS_PREC_NETCONTROL },
1429ac3ea910SXin LI 		{ "reliability",	IPTOS_RELIABILITY },
1430ac3ea910SXin LI 		{ "throughput",		IPTOS_THROUGHPUT },
1431ac3ea910SXin LI 		{ NULL, 		-1 },
1432ac3ea910SXin LI 	};
14332440a458SXin LI 
1434ac3ea910SXin LI 	for (t = toskeywords; t->keyword != NULL; t++) {
1435ac3ea910SXin LI 		if (strcmp(s, t->keyword) == 0) {
1436ac3ea910SXin LI 			*val = t->val;
1437ac3ea910SXin LI 			return (1);
1438ac3ea910SXin LI 		}
1439ac3ea910SXin LI 	}
14402440a458SXin LI 
1441ac3ea910SXin LI 	return (0);
14422440a458SXin LI }
14432440a458SXin LI 
14442440a458SXin LI void
144552dba105SXin LI report_connect(const struct sockaddr *sa, socklen_t salen)
144652dba105SXin LI {
144752dba105SXin LI 	char remote_host[NI_MAXHOST];
144852dba105SXin LI 	char remote_port[NI_MAXSERV];
144952dba105SXin LI 	int herr;
145052dba105SXin LI 	int flags = NI_NUMERICSERV;
145152dba105SXin LI 
145252dba105SXin LI 	if (nflag)
145352dba105SXin LI 		flags |= NI_NUMERICHOST;
145452dba105SXin LI 
145552dba105SXin LI 	if ((herr = getnameinfo(sa, salen,
145652dba105SXin LI 	    remote_host, sizeof(remote_host),
145752dba105SXin LI 	    remote_port, sizeof(remote_port),
145852dba105SXin LI 	    flags)) != 0) {
145952dba105SXin LI 		if (herr == EAI_SYSTEM)
146052dba105SXin LI 			err(1, "getnameinfo");
146152dba105SXin LI 		else
146252dba105SXin LI 			errx(1, "getnameinfo: %s", gai_strerror(herr));
146352dba105SXin LI 	}
146452dba105SXin LI 
146552dba105SXin LI 	fprintf(stderr,
146652dba105SXin LI 	    "Connection from %s %s "
146752dba105SXin LI 	    "received!\n", remote_host, remote_port);
146852dba105SXin LI }
146952dba105SXin LI 
147052dba105SXin LI void
14718c384020SXin LI help(void)
14728c384020SXin LI {
14738c384020SXin LI 	usage(0);
14748c384020SXin LI 	fprintf(stderr, "\tCommand Summary:\n\
14758c384020SXin LI 	\t-4		Use IPv4\n\
1476b6642dadSAntoine Brodin 	\t-6		Use IPv6\n\
1477d4b3aefdSPietro Cerutti 	\t--crlf	Convert LF into CRLF when sending data over the network\n\
1478b6642dadSAntoine Brodin 	\t-D		Enable the debug socket option\n\
1479b6642dadSAntoine Brodin 	\t-d		Detach from stdin\n");
148004def624SXin LI #ifdef IPSEC
148104def624SXin LI 	fprintf(stderr, "\
1482b6642dadSAntoine Brodin 	\t-E		Use IPsec ESP\n\
1483b6642dadSAntoine Brodin 	\t-e policy	Use specified IPsec policy\n");
148404def624SXin LI #endif
148504def624SXin LI 	fprintf(stderr, "\
14863ae0125aSXin LI 	\t-F		Pass socket fd\n\
14878c384020SXin LI 	\t-h		This help text\n\
14887dcaa833SXin LI 	\t-I length	TCP receive buffer length\n\
14898c384020SXin LI 	\t-i secs\t	Delay interval for lines sent, ports scanned\n\
14908c384020SXin LI 	\t-k		Keep inbound sockets open for multiple connects\n\
14918c384020SXin LI 	\t-l		Listen mode, for inbound connects\n\
14920772266eSXin LI 	\t-N		Shutdown the network socket after EOF on stdin\n\
14938c384020SXin LI 	\t-n		Suppress name/port resolutions\n\
14947dcaa833SXin LI 	\t--no-tcpopt	Disable TCP options\n\
1495d0415892SMark Johnston 	\t--sctp\t	SCTP mode\n\
1496cef7ab70STom Jones 	\t--tun tundev	Use tun device rather than stdio\n\
14977dcaa833SXin LI 	\t-O length	TCP send buffer length\n\
14982440a458SXin LI 	\t-P proxyuser\tUsername for proxy authentication\n\
14998c384020SXin LI 	\t-p port\t	Specify local port for remote connects\n\
15008c384020SXin LI 	\t-r		Randomize remote ports\n\
15018c384020SXin LI 	\t-S		Enable the TCP MD5 signature option\n\
15028c384020SXin LI 	\t-s addr\t	Local source address\n\
1503ac3ea910SXin LI 	\t-T toskeyword\tSet IP Type of Service\n\
15048c384020SXin LI 	\t-t		Answer TELNET negotiation\n\
15058c384020SXin LI 	\t-U		Use UNIX domain socket\n\
15068c384020SXin LI 	\t-u		UDP mode\n\
15074f2bbc00SXin LI 	\t-V rtable	Specify alternate routing table\n\
15088c384020SXin LI 	\t-v		Verbose\n\
15098c384020SXin LI 	\t-w secs\t	Timeout for connects and final net reads\n\
15108c384020SXin LI 	\t-X proto	Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\
15118c384020SXin LI 	\t-x addr[:port]\tSpecify proxy address and port\n\
15128c384020SXin LI 	\t-z		Zero-I/O mode [used for scanning]\n\
15138c384020SXin LI 	Port numbers can be individual or ranges: lo-hi [inclusive]\n");
151404def624SXin LI #ifdef IPSEC
1515d0415892SMark Johnston 	fprintf(stderr, "\tSee ipsec_set_policy(3) for -e argument format\n");
151604def624SXin LI #endif
15178c384020SXin LI 	exit(1);
15188c384020SXin LI }
15198c384020SXin LI 
152004def624SXin LI #ifdef IPSEC
152104def624SXin LI void
1522fcf59617SAndrey V. Elsukov add_ipsec_policy(int s, int af, char *policy)
152304def624SXin LI {
152404def624SXin LI 	char *raw;
152504def624SXin LI 	int e;
152604def624SXin LI 
152704def624SXin LI 	raw = ipsec_set_policy(policy, strlen(policy));
152804def624SXin LI 	if (raw == NULL)
152904def624SXin LI 		errx(1, "ipsec_set_policy `%s': %s", policy,
153004def624SXin LI 		     ipsec_strerror());
1531fcf59617SAndrey V. Elsukov 	if (af == AF_INET)
153204def624SXin LI 		e = setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, raw,
153304def624SXin LI 		    ipsec_get_policylen(raw));
1534fcf59617SAndrey V. Elsukov 	if (af == AF_INET6)
1535fcf59617SAndrey V. Elsukov 		e = setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, raw,
1536fcf59617SAndrey V. Elsukov 		    ipsec_get_policylen(raw));
153704def624SXin LI 	if (e < 0)
153804def624SXin LI 		err(1, "ipsec policy cannot be configured");
153904def624SXin LI 	free(raw);
154004def624SXin LI 	if (vflag)
154104def624SXin LI 		fprintf(stderr, "ipsec policy configured: `%s'\n", policy);
154204def624SXin LI 	return;
154304def624SXin LI }
154404def624SXin LI #endif /* IPSEC */
154504def624SXin LI 
15468c384020SXin LI void
15478c384020SXin LI usage(int ret)
15488c384020SXin LI {
15491a9dc239SXin LI 	fprintf(stderr,
155004def624SXin LI #ifdef IPSEC
15513ae0125aSXin LI 	    "usage: nc [-46DdEFhklNnrStUuvz] [-e policy] [-I length] [-i interval] [-O length]\n"
155204def624SXin LI #else
15533ae0125aSXin LI 	    "usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n"
155404def624SXin LI #endif
1555d0415892SMark Johnston 	    "\t  [--no-tcpopt] [--sctp]\n"
155659c7ad52SXin LI 	    "\t  [-P proxy_username] [-p source_port] [-s source] [-T ToS]\n"
1557cef7ab70STom Jones 	    "\t  [--tun tundev] [-V rtable] [-w timeout] [-X proxy_protocol]\n"
155859c7ad52SXin LI 	    "\t  [-x proxy_address[:port]] [destination] [port]\n");
15598c384020SXin LI 	if (ret)
15608c384020SXin LI 		exit(1);
15618c384020SXin LI }
1562