xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.bin/nc/netcat.c (revision 1696d8620f37e3e5dda80ac0278cc3ce76c4dab4)
103100a63Svk199839 /* $OpenBSD: netcat.c,v 1.89 2007/02/20 14:11:17 jmc Exp $ */
203100a63Svk199839 /*
303100a63Svk199839  * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
403100a63Svk199839  *
503100a63Svk199839  * Redistribution and use in source and binary forms, with or without
603100a63Svk199839  * modification, are permitted provided that the following conditions
703100a63Svk199839  * are met:
803100a63Svk199839  *
903100a63Svk199839  * 1. Redistributions of source code must retain the above copyright
1003100a63Svk199839  *   notice, this list of conditions and the following disclaimer.
1103100a63Svk199839  * 2. Redistributions in binary form must reproduce the above copyright
1203100a63Svk199839  *   notice, this list of conditions and the following disclaimer in the
1303100a63Svk199839  *   documentation and/or other materials provided with the distribution.
1403100a63Svk199839  * 3. The name of the author may not be used to endorse or promote products
1503100a63Svk199839  *   derived from this software without specific prior written permission.
1603100a63Svk199839  *
1703100a63Svk199839  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1803100a63Svk199839  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1903100a63Svk199839  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2003100a63Svk199839  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2103100a63Svk199839  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2203100a63Svk199839  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2303100a63Svk199839  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2403100a63Svk199839  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2503100a63Svk199839  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2603100a63Svk199839  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2703100a63Svk199839  */
2803100a63Svk199839 
2903100a63Svk199839 /*
3003100a63Svk199839  * Re-written nc(1) for OpenBSD. Original implementation by
3103100a63Svk199839  * *Hobbit* <hobbit@avian.org>.
3203100a63Svk199839  */
3303100a63Svk199839 
34f8c3982aSvk199839 /*
35f8c3982aSvk199839  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
36f8c3982aSvk199839  * Use is subject to license terms.
37f8c3982aSvk199839  */
38f8c3982aSvk199839 
392eef1f2bSErik Trauschke /*
402eef1f2bSErik Trauschke  * Portions Copyright 2008 Erik Trauschke
411edba515SAndy Fiddaman  * Copyright 2024 Oxide Computer Company
422eef1f2bSErik Trauschke  */
4303100a63Svk199839 
4403100a63Svk199839 #include <sys/types.h>
4503100a63Svk199839 #include <sys/socket.h>
4603100a63Svk199839 #include <sys/time.h>
4703100a63Svk199839 #include <sys/un.h>
4803100a63Svk199839 
4903100a63Svk199839 #include <netinet/in.h>
5003100a63Svk199839 #include <netinet/in_systm.h>
5103100a63Svk199839 #include <netinet/tcp.h>
5203100a63Svk199839 #include <netinet/ip.h>
5303100a63Svk199839 #include <arpa/telnet.h>
5403100a63Svk199839 
5503100a63Svk199839 #include <err.h>
5603100a63Svk199839 #include <errno.h>
5703100a63Svk199839 #include <netdb.h>
5803100a63Svk199839 #include <poll.h>
5903100a63Svk199839 #include <stdarg.h>
6003100a63Svk199839 #include <stdio.h>
6103100a63Svk199839 #include <stdlib.h>
6203100a63Svk199839 #include <string.h>
6303100a63Svk199839 #include <unistd.h>
6403100a63Svk199839 #include <fcntl.h>
6503100a63Svk199839 #include <limits.h>
6603100a63Svk199839 #include <signal.h>
6703100a63Svk199839 
6803100a63Svk199839 #include "atomicio.h"
6903100a63Svk199839 
7003100a63Svk199839 #ifndef	SUN_LEN
7103100a63Svk199839 #define	SUN_LEN(su) \
7203100a63Svk199839 	(sizeof (*(su)) - sizeof ((su)->sun_path) + strlen((su)->sun_path))
7303100a63Svk199839 #endif
7403100a63Svk199839 
7503100a63Svk199839 #define	PORT_MIN	1
7603100a63Svk199839 #define	PORT_MAX	65535
7703100a63Svk199839 #define	PORT_MAX_LEN	6
782eef1f2bSErik Trauschke #define	PLIST_SZ	32	/* initial capacity of the portlist */
7903100a63Svk199839 
8003100a63Svk199839 /* Command Line Options */
8103100a63Svk199839 int	dflag;		/* detached, no stdin */
8203100a63Svk199839 unsigned int iflag;	/* Interval Flag */
8303100a63Svk199839 int	kflag;		/* More than one connect */
8403100a63Svk199839 int	lflag;		/* Bind to local port */
8503100a63Svk199839 int	nflag;		/* Don't do name lookup */
86*1696d862SRobert Mustacchi const char *Pflag;		/* Proxy username */
8703100a63Svk199839 char	*pflag;		/* Localport flag */
8803100a63Svk199839 int	rflag;		/* Random ports flag */
89*1696d862SRobert Mustacchi const char *sflag;		/* Source Address */
9003100a63Svk199839 int	tflag;		/* Telnet Emulation */
9103100a63Svk199839 int	uflag;		/* UDP - Default to TCP */
9203100a63Svk199839 int	vflag;		/* Verbosity */
9303100a63Svk199839 int	xflag;		/* Socks proxy */
9403100a63Svk199839 int	Xflag;		/* indicator of Socks version set */
9503100a63Svk199839 int	zflag;		/* Port Scan Flag */
9603100a63Svk199839 int	Dflag;		/* sodebug */
971edba515SAndy Fiddaman int	Sflag;		/* TCP MD5 signature option */
9803100a63Svk199839 int	Tflag = -1;	/* IP Type of Service */
9903100a63Svk199839 
10003100a63Svk199839 int	timeout = -1;
10103100a63Svk199839 int	family = AF_UNSPEC;
102*1696d862SRobert Mustacchi int	ttl = -1;
103*1696d862SRobert Mustacchi int	minttl = -1;
1042eef1f2bSErik Trauschke 
1052eef1f2bSErik Trauschke /*
1062eef1f2bSErik Trauschke  * portlist structure
1072eef1f2bSErik Trauschke  * Used to store a list of ports given by the user and maintaining
1082eef1f2bSErik Trauschke  * information about the number of ports stored.
1092eef1f2bSErik Trauschke  */
1102eef1f2bSErik Trauschke struct {
1112eef1f2bSErik Trauschke 	uint16_t *list; /* list containing the ports */
1122eef1f2bSErik Trauschke 	uint_t listsize;   /* capacity of the list (number of entries) */
1132eef1f2bSErik Trauschke 	uint_t numports;   /* number of ports in the list */
1142eef1f2bSErik Trauschke } ports;
11503100a63Svk199839 
11603100a63Svk199839 void	atelnet(int, unsigned char *, unsigned int);
11703100a63Svk199839 void	build_ports(char *);
11803100a63Svk199839 void	help(void);
119*1696d862SRobert Mustacchi int	local_listen(const char *, const char *, struct addrinfo);
12003100a63Svk199839 void	readwrite(int);
12103100a63Svk199839 int	remote_connect(const char *, const char *, struct addrinfo);
12203100a63Svk199839 int	socks_connect(const char *, const char *,
12303100a63Svk199839 	    const char *, const char *, struct addrinfo, int, const char *);
12403100a63Svk199839 int	udptest(int);
125*1696d862SRobert Mustacchi int	unix_connect(const char *);
126*1696d862SRobert Mustacchi int	unix_listen(const char *);
127*1696d862SRobert Mustacchi void	set_common_sockopts(int, int);
128*1696d862SRobert Mustacchi int	parse_iptos(const char *);
12903100a63Svk199839 void	usage(int);
130*1696d862SRobert Mustacchi const char *print_addr(char *, size_t, struct sockaddr *, int, int);
13103100a63Svk199839 
13203100a63Svk199839 int
main(int argc,char * argv[])13303100a63Svk199839 main(int argc, char *argv[])
13403100a63Svk199839 {
13503100a63Svk199839 	int ch, s, ret, socksv;
13603100a63Svk199839 	char *host, *uport, *proxy;
13703100a63Svk199839 	struct addrinfo hints;
13803100a63Svk199839 	struct servent *sv;
13903100a63Svk199839 	socklen_t len;
14003100a63Svk199839 	struct sockaddr_storage cliaddr;
14103100a63Svk199839 	const char *errstr, *proxyhost = "", *proxyport = NULL;
14203100a63Svk199839 	struct addrinfo proxyhints;
1432eef1f2bSErik Trauschke 	char port[PORT_MAX_LEN];
14403100a63Svk199839 
14503100a63Svk199839 	ret = 1;
1462eef1f2bSErik Trauschke 	s = -1;
14703100a63Svk199839 	socksv = 5;
14803100a63Svk199839 	host = NULL;
14903100a63Svk199839 	uport = NULL;
15003100a63Svk199839 	sv = NULL;
15103100a63Svk199839 
15203100a63Svk199839 	while ((ch = getopt(argc, argv,
153*1696d862SRobert Mustacchi 	    "46Ddhi:klm:M:nP:p:rs:ST:tUuvw:X:x:z")) != -1) {
15403100a63Svk199839 		switch (ch) {
15503100a63Svk199839 		case '4':
15603100a63Svk199839 			family = AF_INET;
15703100a63Svk199839 			break;
15803100a63Svk199839 		case '6':
15903100a63Svk199839 			family = AF_INET6;
16003100a63Svk199839 			break;
16103100a63Svk199839 		case 'U':
16203100a63Svk199839 			family = AF_UNIX;
16303100a63Svk199839 			break;
16403100a63Svk199839 		case 'X':
16503100a63Svk199839 			Xflag = 1;
16603100a63Svk199839 			if (strcasecmp(optarg, "connect") == 0)
16703100a63Svk199839 				socksv = -1; /* HTTP proxy CONNECT */
16803100a63Svk199839 			else if (strcmp(optarg, "4") == 0)
16903100a63Svk199839 				socksv = 4; /* SOCKS v.4 */
17003100a63Svk199839 			else if (strcmp(optarg, "5") == 0)
17103100a63Svk199839 				socksv = 5; /* SOCKS v.5 */
17203100a63Svk199839 			else
17303100a63Svk199839 				errx(1, "unsupported proxy protocol");
17403100a63Svk199839 			break;
17503100a63Svk199839 		case 'd':
17603100a63Svk199839 			dflag = 1;
17703100a63Svk199839 			break;
17803100a63Svk199839 		case 'h':
17903100a63Svk199839 			help();
18003100a63Svk199839 			break;
18103100a63Svk199839 		case 'i':
18203100a63Svk199839 			iflag = strtonum(optarg, 0, UINT_MAX, &errstr);
18303100a63Svk199839 			if (errstr)
18403100a63Svk199839 				errx(1, "interval %s: %s", errstr, optarg);
18503100a63Svk199839 			break;
18603100a63Svk199839 		case 'k':
18703100a63Svk199839 			kflag = 1;
18803100a63Svk199839 			break;
189*1696d862SRobert Mustacchi 		case 'M':
190*1696d862SRobert Mustacchi 			ttl = strtonumx(optarg, 1, 255, &errstr, 0);
191*1696d862SRobert Mustacchi 			if (errstr != NULL) {
192*1696d862SRobert Mustacchi 				errx(1, "ttl is %s: %s, valid values are "
193*1696d862SRobert Mustacchi 				    "between 1 and 255", errstr, optarg);
194*1696d862SRobert Mustacchi 			}
195*1696d862SRobert Mustacchi 			break;
196*1696d862SRobert Mustacchi 		case 'm':
197*1696d862SRobert Mustacchi 			minttl = strtonumx(optarg, 0, 255, &errstr, 0);
198*1696d862SRobert Mustacchi 			if (errstr != NULL) {
199*1696d862SRobert Mustacchi 				errx(1, "minimum ttl is %s: %s, valid values "
200*1696d862SRobert Mustacchi 				    "are between 0 and 255", errstr, optarg);
201*1696d862SRobert Mustacchi 			}
202*1696d862SRobert Mustacchi 			break;
20303100a63Svk199839 		case 'l':
20403100a63Svk199839 			lflag = 1;
20503100a63Svk199839 			break;
20603100a63Svk199839 		case 'n':
20703100a63Svk199839 			nflag = 1;
20803100a63Svk199839 			break;
20903100a63Svk199839 		case 'P':
21003100a63Svk199839 			Pflag = optarg;
21103100a63Svk199839 			break;
21203100a63Svk199839 		case 'p':
21303100a63Svk199839 			pflag = optarg;
21403100a63Svk199839 			break;
21503100a63Svk199839 		case 'r':
21603100a63Svk199839 			rflag = 1;
21703100a63Svk199839 			break;
21803100a63Svk199839 		case 's':
21903100a63Svk199839 			sflag = optarg;
22003100a63Svk199839 			break;
22103100a63Svk199839 		case 't':
22203100a63Svk199839 			tflag = 1;
22303100a63Svk199839 			break;
22403100a63Svk199839 		case 'u':
22503100a63Svk199839 			uflag = 1;
22603100a63Svk199839 			break;
22703100a63Svk199839 		case 'v':
22803100a63Svk199839 			vflag = 1;
22903100a63Svk199839 			break;
23003100a63Svk199839 		case 'w':
23103100a63Svk199839 			timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr);
23203100a63Svk199839 			if (errstr)
23303100a63Svk199839 				errx(1, "timeout %s: %s", errstr, optarg);
23403100a63Svk199839 			timeout *= 1000;
23503100a63Svk199839 			break;
23603100a63Svk199839 		case 'x':
23703100a63Svk199839 			xflag = 1;
23803100a63Svk199839 			if ((proxy = strdup(optarg)) == NULL)
23903100a63Svk199839 				err(1, NULL);
24003100a63Svk199839 			break;
24103100a63Svk199839 		case 'z':
24203100a63Svk199839 			zflag = 1;
24303100a63Svk199839 			break;
24403100a63Svk199839 		case 'D':
24503100a63Svk199839 			Dflag = 1;
24603100a63Svk199839 			break;
2471edba515SAndy Fiddaman 		case 'S':
2481edba515SAndy Fiddaman 			Sflag = 1;
2491edba515SAndy Fiddaman 			break;
25003100a63Svk199839 		case 'T':
25103100a63Svk199839 			Tflag = parse_iptos(optarg);
25203100a63Svk199839 			break;
25303100a63Svk199839 		default:
25403100a63Svk199839 			usage(1);
25503100a63Svk199839 		}
25603100a63Svk199839 	}
25703100a63Svk199839 	argc -= optind;
25803100a63Svk199839 	argv += optind;
25903100a63Svk199839 
26003100a63Svk199839 	/* Cruft to make sure options are clean, and used properly. */
26103100a63Svk199839 	if (argv[0] && !argv[1] && family == AF_UNIX) {
26203100a63Svk199839 		if (uflag)
26303100a63Svk199839 			errx(1, "cannot use -u and -U");
26403100a63Svk199839 		host = argv[0];
26503100a63Svk199839 		uport = NULL;
26603100a63Svk199839 	} else if (argv[0] && !argv[1]) {
26703100a63Svk199839 		if (!lflag)
26803100a63Svk199839 			usage(1);
26903100a63Svk199839 		uport = argv[0];
27003100a63Svk199839 		host = NULL;
27103100a63Svk199839 	} else if (argv[0] && argv[1]) {
27203100a63Svk199839 		if (family == AF_UNIX)
27303100a63Svk199839 			usage(1);
27403100a63Svk199839 		host = argv[0];
27503100a63Svk199839 		uport = argv[1];
27603100a63Svk199839 	} else {
27703100a63Svk199839 		if (!(lflag && pflag))
27803100a63Svk199839 			usage(1);
27903100a63Svk199839 	}
28003100a63Svk199839 
28163c99f93Svk199839 	if (argc > 2)
28263c99f93Svk199839 		usage(1);
28363c99f93Svk199839 
28403100a63Svk199839 	if (lflag && sflag)
28503100a63Svk199839 		errx(1, "cannot use -s and -l");
28603100a63Svk199839 	if (lflag && rflag)
28703100a63Svk199839 		errx(1, "cannot use -r and -l");
28863c99f93Svk199839 	if (lflag && (timeout >= 0))
28963c99f93Svk199839 		warnx("-w has no effect with -l");
29003100a63Svk199839 	if (lflag && pflag) {
29103100a63Svk199839 		if (uport)
29203100a63Svk199839 			usage(1);
29303100a63Svk199839 		uport = pflag;
29403100a63Svk199839 	}
29503100a63Svk199839 	if (lflag && zflag)
29603100a63Svk199839 		errx(1, "cannot use -z and -l");
29703100a63Svk199839 	if (!lflag && kflag)
29803100a63Svk199839 		errx(1, "must use -l with -k");
29903100a63Svk199839 	if (lflag && (Pflag || xflag || Xflag))
30003100a63Svk199839 		errx(1, "cannot use -l with -P, -X or -x");
30103100a63Svk199839 
30203100a63Svk199839 	/* Initialize addrinfo structure. */
30303100a63Svk199839 	if (family != AF_UNIX) {
30403100a63Svk199839 		(void) memset(&hints, 0, sizeof (struct addrinfo));
30503100a63Svk199839 		hints.ai_family = family;
30603100a63Svk199839 		hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
30703100a63Svk199839 		hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
30803100a63Svk199839 		if (nflag)
30903100a63Svk199839 			hints.ai_flags |= AI_NUMERICHOST;
31003100a63Svk199839 	}
31103100a63Svk199839 
31203100a63Svk199839 	if (xflag) {
31303100a63Svk199839 		if (uflag)
31403100a63Svk199839 			errx(1, "no proxy support for UDP mode");
31503100a63Svk199839 
31603100a63Svk199839 		if (lflag)
31703100a63Svk199839 			errx(1, "no proxy support for listen");
31803100a63Svk199839 
31903100a63Svk199839 		if (family == AF_UNIX)
32003100a63Svk199839 			errx(1, "no proxy support for unix sockets");
32103100a63Svk199839 
32203100a63Svk199839 		if (family == AF_INET6)
32303100a63Svk199839 			errx(1, "no proxy support for IPv6");
32403100a63Svk199839 
32503100a63Svk199839 		if (sflag)
32603100a63Svk199839 			errx(1, "no proxy support for local source address");
32703100a63Svk199839 
32803100a63Svk199839 		if ((proxyhost = strtok(proxy, ":")) == NULL)
32903100a63Svk199839 			errx(1, "missing port specification");
33003100a63Svk199839 		proxyport = strtok(NULL, ":");
33103100a63Svk199839 
33203100a63Svk199839 		(void) memset(&proxyhints, 0, sizeof (struct addrinfo));
33303100a63Svk199839 		proxyhints.ai_family = family;
33403100a63Svk199839 		proxyhints.ai_socktype = SOCK_STREAM;
33503100a63Svk199839 		proxyhints.ai_protocol = IPPROTO_TCP;
33603100a63Svk199839 		if (nflag)
33703100a63Svk199839 			proxyhints.ai_flags |= AI_NUMERICHOST;
33803100a63Svk199839 	}
33903100a63Svk199839 
34003100a63Svk199839 	if (lflag) {
34103100a63Svk199839 		int connfd;
34203100a63Svk199839 		ret = 0;
34303100a63Svk199839 
3442eef1f2bSErik Trauschke 		if (family == AF_UNIX) {
3452eef1f2bSErik Trauschke 			if (host == NULL)
3462eef1f2bSErik Trauschke 				usage(1);
34703100a63Svk199839 			s = unix_listen(host);
3482eef1f2bSErik Trauschke 		}
34903100a63Svk199839 
35003100a63Svk199839 		/* Allow only one connection at a time, but stay alive. */
35103100a63Svk199839 		for (;;) {
3522eef1f2bSErik Trauschke 			if (family != AF_UNIX) {
3532eef1f2bSErik Trauschke 				/* check if uport is valid */
3542eef1f2bSErik Trauschke 				if (strtonum(uport, PORT_MIN, PORT_MAX,
3552eef1f2bSErik Trauschke 				    &errstr) == 0)
3562eef1f2bSErik Trauschke 					errx(1, "port number %s: %s",
3572eef1f2bSErik Trauschke 					    uport, errstr);
35803100a63Svk199839 				s = local_listen(host, uport, hints);
3592eef1f2bSErik Trauschke 			}
36003100a63Svk199839 			if (s < 0)
36103100a63Svk199839 				err(1, NULL);
36203100a63Svk199839 			/*
36303100a63Svk199839 			 * For UDP, we will use recvfrom() initially
36403100a63Svk199839 			 * to wait for a caller, then use the regular
36503100a63Svk199839 			 * functions to talk to the caller.
36603100a63Svk199839 			 */
36703100a63Svk199839 			if (uflag) {
36803100a63Svk199839 				int rv, plen;
36903100a63Svk199839 				char buf[8192];
37003100a63Svk199839 				struct sockaddr_storage z;
37103100a63Svk199839 
37203100a63Svk199839 				len = sizeof (z);
37303100a63Svk199839 				plen = 1024;
37403100a63Svk199839 				rv = recvfrom(s, buf, plen, MSG_PEEK,
37503100a63Svk199839 				    (struct sockaddr *)&z, &len);
37603100a63Svk199839 				if (rv < 0)
37703100a63Svk199839 					err(1, "recvfrom");
37803100a63Svk199839 
37903100a63Svk199839 				rv = connect(s, (struct sockaddr *)&z, len);
38003100a63Svk199839 				if (rv < 0)
38103100a63Svk199839 					err(1, "connect");
38203100a63Svk199839 
38303100a63Svk199839 				connfd = s;
38403100a63Svk199839 			} else {
38503100a63Svk199839 				len = sizeof (cliaddr);
38603100a63Svk199839 				connfd = accept(s, (struct sockaddr *)&cliaddr,
38703100a63Svk199839 				    &len);
388f8c3982aSvk199839 				if ((connfd != -1) && vflag) {
389f8c3982aSvk199839 					char ntop[NI_MAXHOST + NI_MAXSERV];
390f8c3982aSvk199839 					(void) fprintf(stderr,
391f8c3982aSvk199839 					    "Received connection from %s\n",
392f8c3982aSvk199839 					    print_addr(ntop, sizeof (ntop),
393f8c3982aSvk199839 					    (struct sockaddr *)&cliaddr, len,
394f8c3982aSvk199839 					    nflag ? NI_NUMERICHOST : 0));
395f8c3982aSvk199839 				}
39603100a63Svk199839 			}
39703100a63Svk199839 
39803100a63Svk199839 			readwrite(connfd);
39903100a63Svk199839 			(void) close(connfd);
40003100a63Svk199839 			if (family != AF_UNIX)
40103100a63Svk199839 				(void) close(s);
40203100a63Svk199839 
40303100a63Svk199839 			if (!kflag)
40403100a63Svk199839 				break;
40503100a63Svk199839 		}
40603100a63Svk199839 	} else if (family == AF_UNIX) {
40703100a63Svk199839 		ret = 0;
40803100a63Svk199839 
40903100a63Svk199839 		if ((s = unix_connect(host)) > 0 && !zflag) {
41003100a63Svk199839 			readwrite(s);
41103100a63Svk199839 			(void) close(s);
41203100a63Svk199839 		} else
41303100a63Svk199839 			ret = 1;
41403100a63Svk199839 
41503100a63Svk199839 		exit(ret);
41603100a63Svk199839 
41703100a63Svk199839 	} else {	/* AF_INET or AF_INET6 */
4182eef1f2bSErik Trauschke 		int i;
41903100a63Svk199839 
4202eef1f2bSErik Trauschke 		/* Construct the portlist. */
42103100a63Svk199839 		build_ports(uport);
42203100a63Svk199839 
42303100a63Svk199839 		/* Cycle through portlist, connecting to each port. */
4242eef1f2bSErik Trauschke 		for (i = 0; i < ports.numports; i++) {
4252eef1f2bSErik Trauschke 			(void) snprintf(port, sizeof (port), "%u",
4262eef1f2bSErik Trauschke 			    ports.list[i]);
4272eef1f2bSErik Trauschke 
4282eef1f2bSErik Trauschke 			if (s != -1)
42903100a63Svk199839 				(void) close(s);
43003100a63Svk199839 
43103100a63Svk199839 			if (xflag)
4322eef1f2bSErik Trauschke 				s = socks_connect(host, port,
43303100a63Svk199839 				    proxyhost, proxyport, proxyhints, socksv,
43403100a63Svk199839 				    Pflag);
43503100a63Svk199839 			else
4362eef1f2bSErik Trauschke 				s = remote_connect(host, port, hints);
43703100a63Svk199839 
43803100a63Svk199839 			if (s < 0)
43903100a63Svk199839 				continue;
44003100a63Svk199839 
44103100a63Svk199839 			ret = 0;
44203100a63Svk199839 			if (vflag || zflag) {
44303100a63Svk199839 				/* For UDP, make sure we are connected. */
44403100a63Svk199839 				if (uflag) {
44503100a63Svk199839 					if (udptest(s) == -1) {
44603100a63Svk199839 						ret = 1;
44703100a63Svk199839 						continue;
44803100a63Svk199839 					}
44903100a63Svk199839 				}
45003100a63Svk199839 
45103100a63Svk199839 				/* Don't look up port if -n. */
45203100a63Svk199839 				if (nflag)
45303100a63Svk199839 					sv = NULL;
45403100a63Svk199839 				else {
45503100a63Svk199839 					sv = getservbyport(
4562eef1f2bSErik Trauschke 					    ntohs(ports.list[i]),
45703100a63Svk199839 					    uflag ? "udp" : "tcp");
45803100a63Svk199839 				}
45903100a63Svk199839 
460f8c3982aSvk199839 				(void) fprintf(stderr, "Connection to %s %s "
46103100a63Svk199839 				    "port [%s/%s] succeeded!\n",
4622eef1f2bSErik Trauschke 				    host, port, uflag ? "udp" : "tcp",
46303100a63Svk199839 				    sv ? sv->s_name : "*");
46403100a63Svk199839 			}
46503100a63Svk199839 			if (!zflag)
46603100a63Svk199839 				readwrite(s);
46703100a63Svk199839 		}
4682eef1f2bSErik Trauschke 		free(ports.list);
46903100a63Svk199839 	}
47003100a63Svk199839 
4712eef1f2bSErik Trauschke 	if (s != -1)
47203100a63Svk199839 		(void) close(s);
47303100a63Svk199839 
47403100a63Svk199839 	return (ret);
47503100a63Svk199839 }
47603100a63Svk199839 
47703100a63Svk199839 /*
478f8c3982aSvk199839  * print IP address and (optionally) a port
479f8c3982aSvk199839  */
480*1696d862SRobert Mustacchi const char *
print_addr(char * ntop,size_t ntlen,struct sockaddr * addr,int len,int flags)481f8c3982aSvk199839 print_addr(char *ntop, size_t ntlen, struct sockaddr *addr, int len, int flags)
482f8c3982aSvk199839 {
483f8c3982aSvk199839 	char port[NI_MAXSERV];
484f8c3982aSvk199839 	int e;
485f8c3982aSvk199839 
486f8c3982aSvk199839 	/* print port always as number */
487f8c3982aSvk199839 	if ((e = getnameinfo(addr, len, ntop, ntlen,
488f8c3982aSvk199839 	    port, sizeof (port), flags|NI_NUMERICSERV)) != 0) {
489f8c3982aSvk199839 		return ((char *)gai_strerror(e));
490f8c3982aSvk199839 	}
491f8c3982aSvk199839 
492afa82053SToomas Soome 	(void) strlcat(ntop, " port ", ntlen);
493afa82053SToomas Soome 	(void) strlcat(ntop, port, ntlen);
494f8c3982aSvk199839 
495f8c3982aSvk199839 	return (ntop);
496f8c3982aSvk199839 }
497f8c3982aSvk199839 
498f8c3982aSvk199839 /*
49903100a63Svk199839  * unix_connect()
50003100a63Svk199839  * Returns a socket connected to a local unix socket. Returns -1 on failure.
50103100a63Svk199839  */
50203100a63Svk199839 int
unix_connect(const char * path)503*1696d862SRobert Mustacchi unix_connect(const char *path)
50403100a63Svk199839 {
50503100a63Svk199839 	struct sockaddr_un sunaddr;
50603100a63Svk199839 	int s;
50703100a63Svk199839 
50803100a63Svk199839 	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
50903100a63Svk199839 		return (-1);
51003100a63Svk199839 
51103100a63Svk199839 	(void) memset(&sunaddr, 0, sizeof (struct sockaddr_un));
51203100a63Svk199839 	sunaddr.sun_family = AF_UNIX;
51303100a63Svk199839 
51403100a63Svk199839 	if (strlcpy(sunaddr.sun_path, path, sizeof (sunaddr.sun_path)) >=
51503100a63Svk199839 	    sizeof (sunaddr.sun_path)) {
51603100a63Svk199839 		(void) close(s);
51703100a63Svk199839 		errno = ENAMETOOLONG;
51803100a63Svk199839 		return (-1);
51903100a63Svk199839 	}
52003100a63Svk199839 	if (connect(s, (struct sockaddr *)&sunaddr, SUN_LEN(&sunaddr)) < 0) {
52103100a63Svk199839 		(void) close(s);
52203100a63Svk199839 		return (-1);
52303100a63Svk199839 	}
52403100a63Svk199839 	return (s);
52503100a63Svk199839 }
52603100a63Svk199839 
52703100a63Svk199839 /*
52803100a63Svk199839  * unix_listen()
52903100a63Svk199839  * Create a unix domain socket, and listen on it.
53003100a63Svk199839  */
53103100a63Svk199839 int
unix_listen(const char * path)532*1696d862SRobert Mustacchi unix_listen(const char *path)
53303100a63Svk199839 {
53403100a63Svk199839 	struct sockaddr_un sunaddr;
53503100a63Svk199839 	int s;
53603100a63Svk199839 
53703100a63Svk199839 	/* Create unix domain socket. */
53803100a63Svk199839 	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
53903100a63Svk199839 		return (-1);
54003100a63Svk199839 
54103100a63Svk199839 	(void) memset(&sunaddr, 0, sizeof (struct sockaddr_un));
54203100a63Svk199839 	sunaddr.sun_family = AF_UNIX;
54303100a63Svk199839 
54403100a63Svk199839 	if (strlcpy(sunaddr.sun_path, path, sizeof (sunaddr.sun_path)) >=
54503100a63Svk199839 	    sizeof (sunaddr.sun_path)) {
54603100a63Svk199839 		(void) close(s);
54703100a63Svk199839 		errno = ENAMETOOLONG;
54803100a63Svk199839 		return (-1);
54903100a63Svk199839 	}
55003100a63Svk199839 
55103100a63Svk199839 	if (bind(s, (struct sockaddr *)&sunaddr, SUN_LEN(&sunaddr)) < 0) {
55203100a63Svk199839 		(void) close(s);
55303100a63Svk199839 		return (-1);
55403100a63Svk199839 	}
55503100a63Svk199839 
55603100a63Svk199839 	if (listen(s, 5) < 0) {
55703100a63Svk199839 		(void) close(s);
55803100a63Svk199839 		return (-1);
55903100a63Svk199839 	}
56003100a63Svk199839 	return (s);
56103100a63Svk199839 }
56203100a63Svk199839 
56303100a63Svk199839 /*
56403100a63Svk199839  * remote_connect()
56503100a63Svk199839  * Returns a socket connected to a remote host. Properly binds to a local
56603100a63Svk199839  * port or source address if needed. Returns -1 on failure.
56703100a63Svk199839  */
56803100a63Svk199839 int
remote_connect(const char * host,const char * port,struct addrinfo hints)56903100a63Svk199839 remote_connect(const char *host, const char *port, struct addrinfo hints)
57003100a63Svk199839 {
57103100a63Svk199839 	struct addrinfo *res, *res0;
57203100a63Svk199839 	int s, error;
57303100a63Svk199839 
57403100a63Svk199839 	if ((error = getaddrinfo(host, port, &hints, &res)))
57503100a63Svk199839 		errx(1, "getaddrinfo: %s", gai_strerror(error));
57603100a63Svk199839 
57703100a63Svk199839 	res0 = res;
57803100a63Svk199839 	do {
57903100a63Svk199839 		if ((s = socket(res0->ai_family, res0->ai_socktype,
58003100a63Svk199839 		    res0->ai_protocol)) < 0) {
58103100a63Svk199839 			warn("failed to create socket");
58203100a63Svk199839 			continue;
58303100a63Svk199839 		}
58403100a63Svk199839 
58503100a63Svk199839 		/* Bind to a local port or source address if specified. */
58603100a63Svk199839 		if (sflag || pflag) {
58703100a63Svk199839 			struct addrinfo ahints, *ares;
58803100a63Svk199839 
58903100a63Svk199839 			(void) memset(&ahints, 0, sizeof (struct addrinfo));
59003100a63Svk199839 			ahints.ai_family = res0->ai_family;
59103100a63Svk199839 			ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
59203100a63Svk199839 			ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
59303100a63Svk199839 			ahints.ai_flags = AI_PASSIVE;
59403100a63Svk199839 			if ((error = getaddrinfo(sflag, pflag, &ahints, &ares)))
59503100a63Svk199839 				errx(1, "getaddrinfo: %s", gai_strerror(error));
59603100a63Svk199839 
59703100a63Svk199839 			if (bind(s, (struct sockaddr *)ares->ai_addr,
59803100a63Svk199839 			    ares->ai_addrlen) < 0)
59903100a63Svk199839 				errx(1, "bind failed: %s", strerror(errno));
60003100a63Svk199839 			freeaddrinfo(ares);
601f8c3982aSvk199839 
602f8c3982aSvk199839 			if (vflag && !lflag) {
603f8c3982aSvk199839 				if (sflag != NULL)
604f8c3982aSvk199839 					(void) fprintf(stderr,
605f8c3982aSvk199839 					    "Using source address: %s\n",
606f8c3982aSvk199839 					    sflag);
607f8c3982aSvk199839 				if (pflag != NULL)
608f8c3982aSvk199839 					(void) fprintf(stderr,
609f8c3982aSvk199839 					    "Using source port: %s\n", pflag);
610f8c3982aSvk199839 			}
61103100a63Svk199839 		}
61203100a63Svk199839 
613*1696d862SRobert Mustacchi 		set_common_sockopts(s, res0->ai_family);
61403100a63Svk199839 
61503100a63Svk199839 		if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
61603100a63Svk199839 			break;
617f8c3982aSvk199839 		else if (vflag) {
618f8c3982aSvk199839 			char ntop[NI_MAXHOST + NI_MAXSERV];
619f8c3982aSvk199839 			warn("connect to %s [host %s] (%s) failed",
620f8c3982aSvk199839 			    print_addr(ntop, sizeof (ntop),
621f8c3982aSvk199839 			    res0->ai_addr, res0->ai_addrlen, NI_NUMERICHOST),
622f8c3982aSvk199839 			    host, uflag ? "udp" : "tcp");
623f8c3982aSvk199839 		}
62403100a63Svk199839 
62503100a63Svk199839 		(void) close(s);
62603100a63Svk199839 		s = -1;
62703100a63Svk199839 	} while ((res0 = res0->ai_next) != NULL);
62803100a63Svk199839 
62903100a63Svk199839 	freeaddrinfo(res);
63003100a63Svk199839 
63103100a63Svk199839 	return (s);
63203100a63Svk199839 }
63303100a63Svk199839 
63403100a63Svk199839 /*
63503100a63Svk199839  * local_listen()
63603100a63Svk199839  * Returns a socket listening on a local port, binds to specified source
63703100a63Svk199839  * address. Returns -1 on failure.
63803100a63Svk199839  */
63903100a63Svk199839 int
local_listen(const char * host,const char * port,struct addrinfo hints)640*1696d862SRobert Mustacchi local_listen(const char *host, const char *port, struct addrinfo hints)
64103100a63Svk199839 {
64203100a63Svk199839 	struct addrinfo *res, *res0;
64303100a63Svk199839 	int s, ret, x = 1;
64403100a63Svk199839 	int error;
64503100a63Svk199839 
64603100a63Svk199839 	/* Allow nodename to be null. */
64703100a63Svk199839 	hints.ai_flags |= AI_PASSIVE;
64803100a63Svk199839 
64903100a63Svk199839 	if ((error = getaddrinfo(host, port, &hints, &res)))
65003100a63Svk199839 		errx(1, "getaddrinfo: %s", gai_strerror(error));
65103100a63Svk199839 
65203100a63Svk199839 	res0 = res;
65303100a63Svk199839 	do {
65403100a63Svk199839 		if ((s = socket(res0->ai_family, res0->ai_socktype,
65503100a63Svk199839 		    res0->ai_protocol)) < 0) {
65603100a63Svk199839 			warn("failed to create socket");
65703100a63Svk199839 			continue;
65803100a63Svk199839 		}
65903100a63Svk199839 
66003100a63Svk199839 		ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x));
66103100a63Svk199839 		if (ret == -1)
66203100a63Svk199839 			err(1, NULL);
66303100a63Svk199839 
664*1696d862SRobert Mustacchi 		set_common_sockopts(s, res0->ai_family);
66503100a63Svk199839 
66603100a63Svk199839 		if (bind(s, (struct sockaddr *)res0->ai_addr,
66703100a63Svk199839 		    res0->ai_addrlen) == 0)
66803100a63Svk199839 			break;
66903100a63Svk199839 
67003100a63Svk199839 		(void) close(s);
67103100a63Svk199839 		s = -1;
67203100a63Svk199839 	} while ((res0 = res0->ai_next) != NULL);
67303100a63Svk199839 
67403100a63Svk199839 	if (!uflag && s != -1) {
67503100a63Svk199839 		if (listen(s, 1) < 0)
67603100a63Svk199839 			err(1, "listen");
67703100a63Svk199839 	}
67803100a63Svk199839 
67903100a63Svk199839 	freeaddrinfo(res);
68003100a63Svk199839 
68103100a63Svk199839 	return (s);
68203100a63Svk199839 }
68303100a63Svk199839 
68403100a63Svk199839 /*
68503100a63Svk199839  * readwrite()
68603100a63Svk199839  * Loop that polls on the network file descriptor and stdin.
68703100a63Svk199839  */
68803100a63Svk199839 void
readwrite(int nfd)68903100a63Svk199839 readwrite(int nfd)
69003100a63Svk199839 {
69103100a63Svk199839 	struct pollfd pfd[2];
69203100a63Svk199839 	unsigned char buf[8192];
69303100a63Svk199839 	int n, wfd = fileno(stdin);
69403100a63Svk199839 	int lfd = fileno(stdout);
69503100a63Svk199839 	int plen;
69603100a63Svk199839 
69703100a63Svk199839 	plen = 1024;
69803100a63Svk199839 
69903100a63Svk199839 	/* Setup Network FD */
70003100a63Svk199839 	pfd[0].fd = nfd;
70103100a63Svk199839 	pfd[0].events = POLLIN;
70203100a63Svk199839 
70303100a63Svk199839 	/* Set up STDIN FD. */
70403100a63Svk199839 	pfd[1].fd = wfd;
70503100a63Svk199839 	pfd[1].events = POLLIN;
70603100a63Svk199839 
70703100a63Svk199839 	while (pfd[0].fd != -1) {
70803100a63Svk199839 		if (iflag)
70903100a63Svk199839 			(void) sleep(iflag);
71003100a63Svk199839 
71103100a63Svk199839 		if ((n = poll(pfd, 2 - dflag, timeout)) < 0) {
71203100a63Svk199839 			(void) close(nfd);
71303100a63Svk199839 			err(1, "Polling Error");
71403100a63Svk199839 		}
71503100a63Svk199839 
71603100a63Svk199839 		if (n == 0)
71703100a63Svk199839 			return;
71803100a63Svk199839 
71903100a63Svk199839 		if (pfd[0].revents & (POLLIN|POLLHUP)) {
72003100a63Svk199839 			if ((n = read(nfd, buf, plen)) < 0)
72103100a63Svk199839 				return;
72203100a63Svk199839 			else if (n == 0) {
72303100a63Svk199839 				(void) shutdown(nfd, SHUT_RD);
72403100a63Svk199839 				pfd[0].fd = -1;
72503100a63Svk199839 				pfd[0].events = 0;
72603100a63Svk199839 			} else {
72703100a63Svk199839 				if (tflag)
72803100a63Svk199839 					atelnet(nfd, buf, n);
72903100a63Svk199839 				if (atomicio(vwrite, lfd, buf, n) != n)
73003100a63Svk199839 					return;
73103100a63Svk199839 			}
73203100a63Svk199839 		}
73303100a63Svk199839 
73403100a63Svk199839 		/*
73503100a63Svk199839 		 * handle the case of disconnected pipe: after pipe
73603100a63Svk199839 		 * is closed (indicated by POLLHUP) there may still
73703100a63Svk199839 		 * be some data lingering (POLLIN). After we read
73803100a63Svk199839 		 * the data, only POLLHUP remains, read() returns 0
73903100a63Svk199839 		 * and we are finished.
74003100a63Svk199839 		 */
74103100a63Svk199839 		if (!dflag && (pfd[1].revents & (POLLIN|POLLHUP))) {
74203100a63Svk199839 			if ((n = read(wfd, buf, plen)) < 0)
74303100a63Svk199839 				return;
74403100a63Svk199839 			else if (n == 0) {
74503100a63Svk199839 				(void) shutdown(nfd, SHUT_WR);
74603100a63Svk199839 				pfd[1].fd = -1;
74703100a63Svk199839 				pfd[1].events = 0;
74803100a63Svk199839 			} else {
74903100a63Svk199839 				if (atomicio(vwrite, nfd, buf, n) != n)
75003100a63Svk199839 					return;
75103100a63Svk199839 			}
75203100a63Svk199839 		}
75303100a63Svk199839 	}
75403100a63Svk199839 }
75503100a63Svk199839 
75603100a63Svk199839 /* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */
75703100a63Svk199839 void
atelnet(int nfd,unsigned char * buf,unsigned int size)75803100a63Svk199839 atelnet(int nfd, unsigned char *buf, unsigned int size)
75903100a63Svk199839 {
76003100a63Svk199839 	unsigned char *p, *end;
76103100a63Svk199839 	unsigned char obuf[4];
76203100a63Svk199839 
76303100a63Svk199839 	end = buf + size;
76403100a63Svk199839 	obuf[0] = '\0';
76503100a63Svk199839 
76603100a63Svk199839 	for (p = buf; p < end; p++) {
76703100a63Svk199839 		if (*p != IAC)
76803100a63Svk199839 			break;
76903100a63Svk199839 
77003100a63Svk199839 		obuf[0] = IAC;
77103100a63Svk199839 		obuf[1] = 0;
77203100a63Svk199839 		p++;
77303100a63Svk199839 		/* refuse all options */
77403100a63Svk199839 		if ((*p == WILL) || (*p == WONT))
77503100a63Svk199839 			obuf[1] = DONT;
77603100a63Svk199839 		if ((*p == DO) || (*p == DONT))
77703100a63Svk199839 			obuf[1] = WONT;
77803100a63Svk199839 		if (obuf[1]) {
77903100a63Svk199839 			p++;
78003100a63Svk199839 			obuf[2] = *p;
78103100a63Svk199839 			obuf[3] = '\0';
78203100a63Svk199839 			if (atomicio(vwrite, nfd, obuf, 3) != 3)
78303100a63Svk199839 				warn("Write Error!");
78403100a63Svk199839 			obuf[0] = '\0';
78503100a63Svk199839 		}
78603100a63Svk199839 	}
78703100a63Svk199839 }
78803100a63Svk199839 
78903100a63Svk199839 /*
79003100a63Svk199839  * build_ports()
7912eef1f2bSErik Trauschke  * Build an array of ports in ports.list[], listing each port
79203100a63Svk199839  * that we should try to connect to.
79303100a63Svk199839  */
79403100a63Svk199839 void
build_ports(char * p)79503100a63Svk199839 build_ports(char *p)
79603100a63Svk199839 {
79703100a63Svk199839 	const char *errstr;
7982eef1f2bSErik Trauschke 	const char *token;
79903100a63Svk199839 	char *n;
8002eef1f2bSErik Trauschke 	int lo, hi, cp;
8012eef1f2bSErik Trauschke 	int i;
80203100a63Svk199839 
8032eef1f2bSErik Trauschke 	/* Set up initial portlist. */
8042eef1f2bSErik Trauschke 	ports.list = malloc(PLIST_SZ * sizeof (uint16_t));
8052eef1f2bSErik Trauschke 	if (ports.list == NULL)
8062eef1f2bSErik Trauschke 		err(1, NULL);
8072eef1f2bSErik Trauschke 	ports.listsize = PLIST_SZ;
8082eef1f2bSErik Trauschke 	ports.numports = 0;
80903100a63Svk199839 
8102eef1f2bSErik Trauschke 	/* Cycle through list of given ports sep. by "," */
8112eef1f2bSErik Trauschke 	while ((token = strsep(&p, ",")) != NULL) {
8122eef1f2bSErik Trauschke 		if (*token == '\0')
8132eef1f2bSErik Trauschke 			errx(1, "Invalid port/portlist format: "
8142eef1f2bSErik Trauschke 			    "zero length port");
81503100a63Svk199839 
8162eef1f2bSErik Trauschke 		/* check if it is a range */
8172eef1f2bSErik Trauschke 		if ((n = strchr(token, '-')) != NULL)
8182eef1f2bSErik Trauschke 			*n++ = '\0';
8192eef1f2bSErik Trauschke 
8202eef1f2bSErik Trauschke 		lo = strtonum(token, PORT_MIN, PORT_MAX, &errstr);
8212eef1f2bSErik Trauschke 		if (errstr)
8222eef1f2bSErik Trauschke 			errx(1, "port number %s: %s", errstr, token);
8232eef1f2bSErik Trauschke 
8242eef1f2bSErik Trauschke 		if (n == NULL) {
8252eef1f2bSErik Trauschke 			hi = lo;
8262eef1f2bSErik Trauschke 		} else {
82703100a63Svk199839 			hi = strtonum(n, PORT_MIN, PORT_MAX, &errstr);
82803100a63Svk199839 			if (errstr)
82903100a63Svk199839 				errx(1, "port number %s: %s", errstr, n);
83003100a63Svk199839 			if (lo > hi) {
83103100a63Svk199839 				cp = hi;
83203100a63Svk199839 				hi = lo;
83303100a63Svk199839 				lo = cp;
83403100a63Svk199839 			}
8352eef1f2bSErik Trauschke 		}
8362eef1f2bSErik Trauschke 
8372eef1f2bSErik Trauschke 		/*
8382eef1f2bSErik Trauschke 		 * Grow the portlist if needed.
8392eef1f2bSErik Trauschke 		 * We double the size and add size of current range
8402eef1f2bSErik Trauschke 		 * to make sure we don't have to resize that often.
8412eef1f2bSErik Trauschke 		 */
8422eef1f2bSErik Trauschke 		if (hi - lo + ports.numports + 1 >= ports.listsize) {
8432eef1f2bSErik Trauschke 			ports.listsize = ports.listsize * 2 + hi - lo;
8442eef1f2bSErik Trauschke 			ports.list = realloc(ports.list,
8452eef1f2bSErik Trauschke 			    ports.listsize * sizeof (uint16_t));
8462eef1f2bSErik Trauschke 			if (ports.list == NULL)
8472eef1f2bSErik Trauschke 				err(1, NULL);
8482eef1f2bSErik Trauschke 		}
84903100a63Svk199839 
85003100a63Svk199839 		/* Load ports sequentially. */
8512eef1f2bSErik Trauschke 		for (i = lo; i <= hi; i++)
8522eef1f2bSErik Trauschke 			ports.list[ports.numports++] = i;
85303100a63Svk199839 	}
85403100a63Svk199839 
85503100a63Svk199839 	/* Randomly swap ports. */
85603100a63Svk199839 	if (rflag) {
85703100a63Svk199839 		int y;
8582eef1f2bSErik Trauschke 		uint16_t u;
85903100a63Svk199839 
8602eef1f2bSErik Trauschke 		if (ports.numports < 2) {
8612eef1f2bSErik Trauschke 			warnx("can not swap %d port randomly",
8622eef1f2bSErik Trauschke 			    ports.numports);
8632eef1f2bSErik Trauschke 			return;
86403100a63Svk199839 		}
8652eef1f2bSErik Trauschke 		srandom(time(NULL));
8662eef1f2bSErik Trauschke 		for (i = 0; i < ports.numports; i++) {
8672eef1f2bSErik Trauschke 			y = random() % (ports.numports - 1);
8682eef1f2bSErik Trauschke 			u = ports.list[i];
8692eef1f2bSErik Trauschke 			ports.list[i] = ports.list[y];
8702eef1f2bSErik Trauschke 			ports.list[y] = u;
87103100a63Svk199839 		}
87203100a63Svk199839 	}
87303100a63Svk199839 }
87403100a63Svk199839 
87503100a63Svk199839 /*
87603100a63Svk199839  * udptest()
87703100a63Svk199839  * Do a few writes to see if the UDP port is there.
87803100a63Svk199839  * XXX - Better way of doing this? Doesn't work for IPv6.
87903100a63Svk199839  * Also fails after around 100 ports checked.
88003100a63Svk199839  */
88103100a63Svk199839 int
udptest(int s)88203100a63Svk199839 udptest(int s)
88303100a63Svk199839 {
88403100a63Svk199839 	int i, ret;
88503100a63Svk199839 
88603100a63Svk199839 	for (i = 0; i <= 3; i++) {
88703100a63Svk199839 		if (write(s, "X", 1) == 1)
88803100a63Svk199839 			ret = 1;
88903100a63Svk199839 		else
89003100a63Svk199839 			ret = -1;
89103100a63Svk199839 	}
89203100a63Svk199839 	return (ret);
89303100a63Svk199839 }
89403100a63Svk199839 
89503100a63Svk199839 void
set_common_sockopts(int s,int af)896*1696d862SRobert Mustacchi set_common_sockopts(int s, int af)
89703100a63Svk199839 {
89803100a63Svk199839 	int x = 1;
89903100a63Svk199839 
9001edba515SAndy Fiddaman 	if (Sflag) {
9011edba515SAndy Fiddaman 		if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG,
9021edba515SAndy Fiddaman 		    &x, sizeof (x)) == -1) {
9031edba515SAndy Fiddaman 			err(1, NULL);
9041edba515SAndy Fiddaman 		}
9051edba515SAndy Fiddaman 	}
9061edba515SAndy Fiddaman 
90703100a63Svk199839 	if (Dflag) {
90803100a63Svk199839 		if (setsockopt(s, SOL_SOCKET, SO_DEBUG, &x, sizeof (x)) == -1)
90903100a63Svk199839 			err(1, NULL);
91003100a63Svk199839 	}
91103100a63Svk199839 	if (Tflag != -1) {
912*1696d862SRobert Mustacchi 		switch (af) {
913*1696d862SRobert Mustacchi 		case AF_INET:
91403100a63Svk199839 			if (setsockopt(s, IPPROTO_IP, IP_TOS, &Tflag,
915*1696d862SRobert Mustacchi 			    sizeof (Tflag)) == -1) {
916*1696d862SRobert Mustacchi 				err(1, "failed to set IP ToS socket option");
917*1696d862SRobert Mustacchi 			}
918*1696d862SRobert Mustacchi 			break;
919*1696d862SRobert Mustacchi 		case AF_INET6:
920*1696d862SRobert Mustacchi 			if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &Tflag,
921*1696d862SRobert Mustacchi 			    sizeof (Tflag)) == -1) {
922*1696d862SRobert Mustacchi 				err(1, "failed to set IPv6 traffic class "
923*1696d862SRobert Mustacchi 				    "socket option");
924*1696d862SRobert Mustacchi 			}
925*1696d862SRobert Mustacchi 			break;
926*1696d862SRobert Mustacchi 		default:
927*1696d862SRobert Mustacchi 			err(1, "cannot set TTL/Hops on unsupported socket "
928*1696d862SRobert Mustacchi 			    "family 0x%x", af);
92903100a63Svk199839 		}
93003100a63Svk199839 	}
93103100a63Svk199839 
932*1696d862SRobert Mustacchi 	if (ttl != -1) {
933*1696d862SRobert Mustacchi 		switch (af) {
934*1696d862SRobert Mustacchi 		case AF_INET:
935*1696d862SRobert Mustacchi 			if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl,
936*1696d862SRobert Mustacchi 			    sizeof (ttl)) != 0) {
937*1696d862SRobert Mustacchi 				err(1, "failed to set IP TTL socket option");
938*1696d862SRobert Mustacchi 			}
939*1696d862SRobert Mustacchi 			break;
940*1696d862SRobert Mustacchi 		case AF_INET6:
941*1696d862SRobert Mustacchi 			if (setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl,
942*1696d862SRobert Mustacchi 			    sizeof (ttl)) != 0) {
943*1696d862SRobert Mustacchi 				err(1, "failed to set IPv6 unicast hops socket "
944*1696d862SRobert Mustacchi 				    "option");
945*1696d862SRobert Mustacchi 			}
946*1696d862SRobert Mustacchi 			break;
947*1696d862SRobert Mustacchi 		default:
948*1696d862SRobert Mustacchi 			err(1, "cannot set TTL/Hops on unsupported socket "
949*1696d862SRobert Mustacchi 			    "family 0x%x", af);
950*1696d862SRobert Mustacchi 		}
951*1696d862SRobert Mustacchi 	}
952*1696d862SRobert Mustacchi 
953*1696d862SRobert Mustacchi 	if (minttl != -1) {
954*1696d862SRobert Mustacchi 		switch (af) {
955*1696d862SRobert Mustacchi 		case AF_INET:
956*1696d862SRobert Mustacchi 			if (setsockopt(s, IPPROTO_IP, IP_MINTTL, &minttl,
957*1696d862SRobert Mustacchi 			    sizeof (minttl)) != 0) {
958*1696d862SRobert Mustacchi 				err(1, "failed to set IP minimum TTL socket "
959*1696d862SRobert Mustacchi 				    "option");
960*1696d862SRobert Mustacchi 			}
961*1696d862SRobert Mustacchi 			break;
962*1696d862SRobert Mustacchi 		case AF_INET6:
963*1696d862SRobert Mustacchi 			if (setsockopt(s, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
964*1696d862SRobert Mustacchi 			    &minttl, sizeof (minttl)) != 0) {
965*1696d862SRobert Mustacchi 				err(1, "failed to set IPv6 minimum hop count "
966*1696d862SRobert Mustacchi 				    "socket option");
967*1696d862SRobert Mustacchi 			}
968*1696d862SRobert Mustacchi 			break;
969*1696d862SRobert Mustacchi 		default:
970*1696d862SRobert Mustacchi 			err(1, "cannot set minimum TTL/Hops on unsupported "
971*1696d862SRobert Mustacchi 			    "socket family 0x%x", af);
972*1696d862SRobert Mustacchi 		}
973*1696d862SRobert Mustacchi 	}
974*1696d862SRobert Mustacchi 
975*1696d862SRobert Mustacchi }
976*1696d862SRobert Mustacchi 
97703100a63Svk199839 int
parse_iptos(const char * s)978*1696d862SRobert Mustacchi parse_iptos(const char *s)
97903100a63Svk199839 {
980*1696d862SRobert Mustacchi 	int tos;
981*1696d862SRobert Mustacchi 	const char *errstr;
98203100a63Svk199839 
98303100a63Svk199839 	if (strcmp(s, "lowdelay") == 0)
98403100a63Svk199839 		return (IPTOS_LOWDELAY);
98503100a63Svk199839 	if (strcmp(s, "throughput") == 0)
98603100a63Svk199839 		return (IPTOS_THROUGHPUT);
98703100a63Svk199839 	if (strcmp(s, "reliability") == 0)
98803100a63Svk199839 		return (IPTOS_RELIABILITY);
98903100a63Svk199839 
990*1696d862SRobert Mustacchi 	tos = strtonumx(s, 0, 255, &errstr, 0);
991*1696d862SRobert Mustacchi 	if (errstr != NULL) {
992*1696d862SRobert Mustacchi 		errx(1, "IP ToS/IPv6 TC is %s: %s, valid values are "
993*1696d862SRobert Mustacchi 		    "between 0 and 255", errstr, optarg);
994*1696d862SRobert Mustacchi 	}
995*1696d862SRobert Mustacchi 
99603100a63Svk199839 	return (tos);
99703100a63Svk199839 }
99803100a63Svk199839 
99903100a63Svk199839 void
help(void)100003100a63Svk199839 help(void)
100103100a63Svk199839 {
100203100a63Svk199839 	usage(0);
100303100a63Svk199839 	(void) fprintf(stderr, "\tCommand Summary:\n\
100403100a63Svk199839 	\t-4		Use IPv4\n\
100503100a63Svk199839 	\t-6		Use IPv6\n\
100603100a63Svk199839 	\t-D		Enable the debug socket option\n\
100703100a63Svk199839 	\t-d		Detach from stdin\n\
100803100a63Svk199839 	\t-h		This help text\n\
100903100a63Svk199839 	\t-i secs\t	Delay interval for lines sent, ports scanned\n\
101003100a63Svk199839 	\t-k		Keep inbound sockets open for multiple connects\n\
101103100a63Svk199839 	\t-l		Listen mode, for inbound connects\n\
1012*1696d862SRobert Mustacchi 	\t-l		Listen mode, for inbound connects\n\
1013*1696d862SRobert Mustacchi 	\t-M ttl\t	Set the outbound IPv4 TTL / IPv6 Hop Limit\n\
1014*1696d862SRobert Mustacchi 	\t-m minttl	Set the inbound minimum IPv4 TTL / IPv6 Hop Limit\n\
101503100a63Svk199839 	\t-n		Suppress name/port resolutions\n\
101603100a63Svk199839 	\t-P proxyuser\tUsername for proxy authentication\n\
101703100a63Svk199839 	\t-p port\t	Specify local port or listen port\n\
101803100a63Svk199839 	\t-r		Randomize remote ports\n\
1019*1696d862SRobert Mustacchi 	\t-S		Enable TCP MD5 signature socket option\n\
102003100a63Svk199839 	\t-s addr\t	Local source address\n\
102103100a63Svk199839 	\t-T ToS\t	Set IP Type of Service\n\
102203100a63Svk199839 	\t-t		Answer TELNET negotiation\n\
102303100a63Svk199839 	\t-U		Use UNIX domain socket\n\
102403100a63Svk199839 	\t-u		UDP mode\n\
102503100a63Svk199839 	\t-v		Verbose\n\
102603100a63Svk199839 	\t-w secs\t	Timeout for connects and final net reads\n\
102703100a63Svk199839 	\t-X proto	Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\
102803100a63Svk199839 	\t-x addr[:port]\tSpecify proxy address and port\n\
102903100a63Svk199839 	\t-z		Zero-I/O mode [used for scanning]\n\
10302eef1f2bSErik Trauschke 	Port numbers can be individuals, ranges (lo-hi; inclusive) and\n\
10312eef1f2bSErik Trauschke 	combinations of both separated by comma (e.g. 10,22-25,80)\n");
103203100a63Svk199839 	exit(1);
103303100a63Svk199839 }
103403100a63Svk199839 
103503100a63Svk199839 void
usage(int ret)103603100a63Svk199839 usage(int ret)
103703100a63Svk199839 {
103803100a63Svk199839 	(void) fprintf(stderr,
1039*1696d862SRobert Mustacchi 	    "usage: nc [-46DdhklnrStUuvz] [-i interval] [-M ttl] [-m minttl]\n"
1040*1696d862SRobert Mustacchi 	    "\t  [-P proxy_username] [-p port] [-s source_ip_address] "
1041*1696d862SRobert Mustacchi 	    "[-T ToS]\n"
1042*1696d862SRobert Mustacchi 	    "\t  [-w timeout] [-X proxy_protocol] [-x proxy_address[:port]]\n"
1043*1696d862SRobert Mustacchi 	    "\t  [hostname] [port[s]]\n");
104403100a63Svk199839 	if (ret)
104503100a63Svk199839 		exit(1);
104603100a63Svk199839 }
1047