xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.bin/nc/netcat.c (revision 8414:6fda3f6ec7b5)
15570Svk199839 /* $OpenBSD: netcat.c,v 1.89 2007/02/20 14:11:17 jmc Exp $ */
25570Svk199839 /*
35570Svk199839  * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
45570Svk199839  *
55570Svk199839  * Redistribution and use in source and binary forms, with or without
65570Svk199839  * modification, are permitted provided that the following conditions
75570Svk199839  * are met:
85570Svk199839  *
95570Svk199839  * 1. Redistributions of source code must retain the above copyright
105570Svk199839  *   notice, this list of conditions and the following disclaimer.
115570Svk199839  * 2. Redistributions in binary form must reproduce the above copyright
125570Svk199839  *   notice, this list of conditions and the following disclaimer in the
135570Svk199839  *   documentation and/or other materials provided with the distribution.
145570Svk199839  * 3. The name of the author may not be used to endorse or promote products
155570Svk199839  *   derived from this software without specific prior written permission.
165570Svk199839  *
175570Svk199839  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
185570Svk199839  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
195570Svk199839  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
205570Svk199839  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
215570Svk199839  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
225570Svk199839  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235570Svk199839  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245570Svk199839  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255570Svk199839  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
265570Svk199839  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275570Svk199839  */
285570Svk199839 
295570Svk199839 /*
305570Svk199839  * Re-written nc(1) for OpenBSD. Original implementation by
315570Svk199839  * *Hobbit* <hobbit@avian.org>.
325570Svk199839  */
335570Svk199839 
345830Svk199839 /*
355830Svk199839  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
365830Svk199839  * Use is subject to license terms.
375830Svk199839  */
385830Svk199839 
39*8414Serik.trauschke@freenet.de /*
40*8414Serik.trauschke@freenet.de  * Portions Copyright 2008 Erik Trauschke
41*8414Serik.trauschke@freenet.de  */
425570Svk199839 
435570Svk199839 #include <sys/types.h>
445570Svk199839 #include <sys/socket.h>
455570Svk199839 #include <sys/time.h>
465570Svk199839 #include <sys/un.h>
475570Svk199839 
485570Svk199839 #include <netinet/in.h>
495570Svk199839 #include <netinet/in_systm.h>
505570Svk199839 #include <netinet/tcp.h>
515570Svk199839 #include <netinet/ip.h>
525570Svk199839 #include <arpa/telnet.h>
535570Svk199839 
545570Svk199839 #include <err.h>
555570Svk199839 #include <errno.h>
565570Svk199839 #include <netdb.h>
575570Svk199839 #include <poll.h>
585570Svk199839 #include <stdarg.h>
595570Svk199839 #include <stdio.h>
605570Svk199839 #include <stdlib.h>
615570Svk199839 #include <string.h>
625570Svk199839 #include <unistd.h>
635570Svk199839 #include <fcntl.h>
645570Svk199839 #include <limits.h>
655570Svk199839 #include <signal.h>
665570Svk199839 
675570Svk199839 #include "atomicio.h"
685570Svk199839 #include "strtonum.h"
695570Svk199839 
705570Svk199839 #ifndef	SUN_LEN
715570Svk199839 #define	SUN_LEN(su) \
725570Svk199839 	(sizeof (*(su)) - sizeof ((su)->sun_path) + strlen((su)->sun_path))
735570Svk199839 #endif
745570Svk199839 
755570Svk199839 #define	PORT_MIN	1
765570Svk199839 #define	PORT_MAX	65535
775570Svk199839 #define	PORT_MAX_LEN	6
78*8414Serik.trauschke@freenet.de #define	PLIST_SZ	32	/* initial capacity of the portlist */
795570Svk199839 
805570Svk199839 /* Command Line Options */
815570Svk199839 int	dflag;		/* detached, no stdin */
825570Svk199839 unsigned int iflag;	/* Interval Flag */
835570Svk199839 int	kflag;		/* More than one connect */
845570Svk199839 int	lflag;		/* Bind to local port */
855570Svk199839 int	nflag;		/* Don't do name lookup */
865570Svk199839 char	*Pflag;		/* Proxy username */
875570Svk199839 char	*pflag;		/* Localport flag */
885570Svk199839 int	rflag;		/* Random ports flag */
895570Svk199839 char	*sflag;		/* Source Address */
905570Svk199839 int	tflag;		/* Telnet Emulation */
915570Svk199839 int	uflag;		/* UDP - Default to TCP */
925570Svk199839 int	vflag;		/* Verbosity */
935570Svk199839 int	xflag;		/* Socks proxy */
945570Svk199839 int	Xflag;		/* indicator of Socks version set */
955570Svk199839 int	zflag;		/* Port Scan Flag */
965570Svk199839 int	Dflag;		/* sodebug */
975570Svk199839 int	Tflag = -1;	/* IP Type of Service */
985570Svk199839 
995570Svk199839 int	timeout = -1;
1005570Svk199839 int	family = AF_UNSPEC;
101*8414Serik.trauschke@freenet.de 
102*8414Serik.trauschke@freenet.de /*
103*8414Serik.trauschke@freenet.de  * portlist structure
104*8414Serik.trauschke@freenet.de  * Used to store a list of ports given by the user and maintaining
105*8414Serik.trauschke@freenet.de  * information about the number of ports stored.
106*8414Serik.trauschke@freenet.de  */
107*8414Serik.trauschke@freenet.de struct {
108*8414Serik.trauschke@freenet.de 	uint16_t *list; /* list containing the ports */
109*8414Serik.trauschke@freenet.de 	uint_t listsize;   /* capacity of the list (number of entries) */
110*8414Serik.trauschke@freenet.de 	uint_t numports;   /* number of ports in the list */
111*8414Serik.trauschke@freenet.de } ports;
1125570Svk199839 
1135570Svk199839 void	atelnet(int, unsigned char *, unsigned int);
1145570Svk199839 void	build_ports(char *);
1155570Svk199839 void	help(void);
1165570Svk199839 int	local_listen(char *, char *, struct addrinfo);
1175570Svk199839 void	readwrite(int);
1185570Svk199839 int	remote_connect(const char *, const char *, struct addrinfo);
1195570Svk199839 int	socks_connect(const char *, const char *,
1205570Svk199839 	    const char *, const char *, struct addrinfo, int, const char *);
1215570Svk199839 int	udptest(int);
1225570Svk199839 int	unix_connect(char *);
1235570Svk199839 int	unix_listen(char *);
1245570Svk199839 void	set_common_sockopts(int);
1255570Svk199839 int	parse_iptos(char *);
1265570Svk199839 void	usage(int);
1275830Svk199839 char	*print_addr(char *, size_t, struct sockaddr *, int, int);
1285570Svk199839 
1295570Svk199839 int
main(int argc,char * argv[])1305570Svk199839 main(int argc, char *argv[])
1315570Svk199839 {
1325570Svk199839 	int ch, s, ret, socksv;
1335570Svk199839 	char *host, *uport, *proxy;
1345570Svk199839 	struct addrinfo hints;
1355570Svk199839 	struct servent *sv;
1365570Svk199839 	socklen_t len;
1375570Svk199839 	struct sockaddr_storage cliaddr;
1385570Svk199839 	const char *errstr, *proxyhost = "", *proxyport = NULL;
1395570Svk199839 	struct addrinfo proxyhints;
140*8414Serik.trauschke@freenet.de 	char port[PORT_MAX_LEN];
1415570Svk199839 
1425570Svk199839 	ret = 1;
143*8414Serik.trauschke@freenet.de 	s = -1;
1445570Svk199839 	socksv = 5;
1455570Svk199839 	host = NULL;
1465570Svk199839 	uport = NULL;
1475570Svk199839 	sv = NULL;
1485570Svk199839 
1495570Svk199839 	while ((ch = getopt(argc, argv,
1505570Svk199839 	    "46Ddhi:klnP:p:rs:T:tUuvw:X:x:z")) != -1) {
1515570Svk199839 		switch (ch) {
1525570Svk199839 		case '4':
1535570Svk199839 			family = AF_INET;
1545570Svk199839 			break;
1555570Svk199839 		case '6':
1565570Svk199839 			family = AF_INET6;
1575570Svk199839 			break;
1585570Svk199839 		case 'U':
1595570Svk199839 			family = AF_UNIX;
1605570Svk199839 			break;
1615570Svk199839 		case 'X':
1625570Svk199839 			Xflag = 1;
1635570Svk199839 			if (strcasecmp(optarg, "connect") == 0)
1645570Svk199839 				socksv = -1; /* HTTP proxy CONNECT */
1655570Svk199839 			else if (strcmp(optarg, "4") == 0)
1665570Svk199839 				socksv = 4; /* SOCKS v.4 */
1675570Svk199839 			else if (strcmp(optarg, "5") == 0)
1685570Svk199839 				socksv = 5; /* SOCKS v.5 */
1695570Svk199839 			else
1705570Svk199839 				errx(1, "unsupported proxy protocol");
1715570Svk199839 			break;
1725570Svk199839 		case 'd':
1735570Svk199839 			dflag = 1;
1745570Svk199839 			break;
1755570Svk199839 		case 'h':
1765570Svk199839 			help();
1775570Svk199839 			break;
1785570Svk199839 		case 'i':
1795570Svk199839 			iflag = strtonum(optarg, 0, UINT_MAX, &errstr);
1805570Svk199839 			if (errstr)
1815570Svk199839 				errx(1, "interval %s: %s", errstr, optarg);
1825570Svk199839 			break;
1835570Svk199839 		case 'k':
1845570Svk199839 			kflag = 1;
1855570Svk199839 			break;
1865570Svk199839 		case 'l':
1875570Svk199839 			lflag = 1;
1885570Svk199839 			break;
1895570Svk199839 		case 'n':
1905570Svk199839 			nflag = 1;
1915570Svk199839 			break;
1925570Svk199839 		case 'P':
1935570Svk199839 			Pflag = optarg;
1945570Svk199839 			break;
1955570Svk199839 		case 'p':
1965570Svk199839 			pflag = optarg;
1975570Svk199839 			break;
1985570Svk199839 		case 'r':
1995570Svk199839 			rflag = 1;
2005570Svk199839 			break;
2015570Svk199839 		case 's':
2025570Svk199839 			sflag = optarg;
2035570Svk199839 			break;
2045570Svk199839 		case 't':
2055570Svk199839 			tflag = 1;
2065570Svk199839 			break;
2075570Svk199839 		case 'u':
2085570Svk199839 			uflag = 1;
2095570Svk199839 			break;
2105570Svk199839 		case 'v':
2115570Svk199839 			vflag = 1;
2125570Svk199839 			break;
2135570Svk199839 		case 'w':
2145570Svk199839 			timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr);
2155570Svk199839 			if (errstr)
2165570Svk199839 				errx(1, "timeout %s: %s", errstr, optarg);
2175570Svk199839 			timeout *= 1000;
2185570Svk199839 			break;
2195570Svk199839 		case 'x':
2205570Svk199839 			xflag = 1;
2215570Svk199839 			if ((proxy = strdup(optarg)) == NULL)
2225570Svk199839 				err(1, NULL);
2235570Svk199839 			break;
2245570Svk199839 		case 'z':
2255570Svk199839 			zflag = 1;
2265570Svk199839 			break;
2275570Svk199839 		case 'D':
2285570Svk199839 			Dflag = 1;
2295570Svk199839 			break;
2305570Svk199839 		case 'T':
2315570Svk199839 			Tflag = parse_iptos(optarg);
2325570Svk199839 			break;
2335570Svk199839 		default:
2345570Svk199839 			usage(1);
2355570Svk199839 		}
2365570Svk199839 	}
2375570Svk199839 	argc -= optind;
2385570Svk199839 	argv += optind;
2395570Svk199839 
2405570Svk199839 	/* Cruft to make sure options are clean, and used properly. */
2415570Svk199839 	if (argv[0] && !argv[1] && family == AF_UNIX) {
2425570Svk199839 		if (uflag)
2435570Svk199839 			errx(1, "cannot use -u and -U");
2445570Svk199839 		host = argv[0];
2455570Svk199839 		uport = NULL;
2465570Svk199839 	} else if (argv[0] && !argv[1]) {
2475570Svk199839 		if (!lflag)
2485570Svk199839 			usage(1);
2495570Svk199839 		uport = argv[0];
2505570Svk199839 		host = NULL;
2515570Svk199839 	} else if (argv[0] && argv[1]) {
2525570Svk199839 		if (family == AF_UNIX)
2535570Svk199839 			usage(1);
2545570Svk199839 		host = argv[0];
2555570Svk199839 		uport = argv[1];
2565570Svk199839 	} else {
2575570Svk199839 		if (!(lflag && pflag))
2585570Svk199839 			usage(1);
2595570Svk199839 	}
2605570Svk199839 
2616581Svk199839 	if (argc > 2)
2626581Svk199839 		usage(1);
2636581Svk199839 
2645570Svk199839 	if (lflag && sflag)
2655570Svk199839 		errx(1, "cannot use -s and -l");
2665570Svk199839 	if (lflag && rflag)
2675570Svk199839 		errx(1, "cannot use -r and -l");
2686581Svk199839 	if (lflag && (timeout >= 0))
2696581Svk199839 		warnx("-w has no effect with -l");
2705570Svk199839 	if (lflag && pflag) {
2715570Svk199839 		if (uport)
2725570Svk199839 			usage(1);
2735570Svk199839 		uport = pflag;
2745570Svk199839 	}
2755570Svk199839 	if (lflag && zflag)
2765570Svk199839 		errx(1, "cannot use -z and -l");
2775570Svk199839 	if (!lflag && kflag)
2785570Svk199839 		errx(1, "must use -l with -k");
2795570Svk199839 	if (lflag && (Pflag || xflag || Xflag))
2805570Svk199839 		errx(1, "cannot use -l with -P, -X or -x");
2815570Svk199839 
2825570Svk199839 	/* Initialize addrinfo structure. */
2835570Svk199839 	if (family != AF_UNIX) {
2845570Svk199839 		(void) memset(&hints, 0, sizeof (struct addrinfo));
2855570Svk199839 		hints.ai_family = family;
2865570Svk199839 		hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
2875570Svk199839 		hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
2885570Svk199839 		if (nflag)
2895570Svk199839 			hints.ai_flags |= AI_NUMERICHOST;
2905570Svk199839 	}
2915570Svk199839 
2925570Svk199839 	if (xflag) {
2935570Svk199839 		if (uflag)
2945570Svk199839 			errx(1, "no proxy support for UDP mode");
2955570Svk199839 
2965570Svk199839 		if (lflag)
2975570Svk199839 			errx(1, "no proxy support for listen");
2985570Svk199839 
2995570Svk199839 		if (family == AF_UNIX)
3005570Svk199839 			errx(1, "no proxy support for unix sockets");
3015570Svk199839 
3025570Svk199839 		if (family == AF_INET6)
3035570Svk199839 			errx(1, "no proxy support for IPv6");
3045570Svk199839 
3055570Svk199839 		if (sflag)
3065570Svk199839 			errx(1, "no proxy support for local source address");
3075570Svk199839 
3085570Svk199839 		if ((proxyhost = strtok(proxy, ":")) == NULL)
3095570Svk199839 			errx(1, "missing port specification");
3105570Svk199839 		proxyport = strtok(NULL, ":");
3115570Svk199839 
3125570Svk199839 		(void) memset(&proxyhints, 0, sizeof (struct addrinfo));
3135570Svk199839 		proxyhints.ai_family = family;
3145570Svk199839 		proxyhints.ai_socktype = SOCK_STREAM;
3155570Svk199839 		proxyhints.ai_protocol = IPPROTO_TCP;
3165570Svk199839 		if (nflag)
3175570Svk199839 			proxyhints.ai_flags |= AI_NUMERICHOST;
3185570Svk199839 	}
3195570Svk199839 
3205570Svk199839 	if (lflag) {
3215570Svk199839 		int connfd;
3225570Svk199839 		ret = 0;
3235570Svk199839 
324*8414Serik.trauschke@freenet.de 		if (family == AF_UNIX) {
325*8414Serik.trauschke@freenet.de 			if (host == NULL)
326*8414Serik.trauschke@freenet.de 				usage(1);
3275570Svk199839 			s = unix_listen(host);
328*8414Serik.trauschke@freenet.de 		}
3295570Svk199839 
3305570Svk199839 		/* Allow only one connection at a time, but stay alive. */
3315570Svk199839 		for (;;) {
332*8414Serik.trauschke@freenet.de 			if (family != AF_UNIX) {
333*8414Serik.trauschke@freenet.de 				/* check if uport is valid */
334*8414Serik.trauschke@freenet.de 				if (strtonum(uport, PORT_MIN, PORT_MAX,
335*8414Serik.trauschke@freenet.de 				    &errstr) == 0)
336*8414Serik.trauschke@freenet.de 					errx(1, "port number %s: %s",
337*8414Serik.trauschke@freenet.de 					    uport, errstr);
3385570Svk199839 				s = local_listen(host, uport, hints);
339*8414Serik.trauschke@freenet.de 			}
3405570Svk199839 			if (s < 0)
3415570Svk199839 				err(1, NULL);
3425570Svk199839 			/*
3435570Svk199839 			 * For UDP, we will use recvfrom() initially
3445570Svk199839 			 * to wait for a caller, then use the regular
3455570Svk199839 			 * functions to talk to the caller.
3465570Svk199839 			 */
3475570Svk199839 			if (uflag) {
3485570Svk199839 				int rv, plen;
3495570Svk199839 				char buf[8192];
3505570Svk199839 				struct sockaddr_storage z;
3515570Svk199839 
3525570Svk199839 				len = sizeof (z);
3535570Svk199839 				plen = 1024;
3545570Svk199839 				rv = recvfrom(s, buf, plen, MSG_PEEK,
3555570Svk199839 				    (struct sockaddr *)&z, &len);
3565570Svk199839 				if (rv < 0)
3575570Svk199839 					err(1, "recvfrom");
3585570Svk199839 
3595570Svk199839 				rv = connect(s, (struct sockaddr *)&z, len);
3605570Svk199839 				if (rv < 0)
3615570Svk199839 					err(1, "connect");
3625570Svk199839 
3635570Svk199839 				connfd = s;
3645570Svk199839 			} else {
3655570Svk199839 				len = sizeof (cliaddr);
3665570Svk199839 				connfd = accept(s, (struct sockaddr *)&cliaddr,
3675570Svk199839 				    &len);
3685830Svk199839 				if ((connfd != -1) && vflag) {
3695830Svk199839 					char ntop[NI_MAXHOST + NI_MAXSERV];
3705830Svk199839 					(void) fprintf(stderr,
3715830Svk199839 					    "Received connection from %s\n",
3725830Svk199839 					    print_addr(ntop, sizeof (ntop),
3735830Svk199839 					    (struct sockaddr *)&cliaddr, len,
3745830Svk199839 					    nflag ? NI_NUMERICHOST : 0));
3755830Svk199839 				}
3765570Svk199839 			}
3775570Svk199839 
3785570Svk199839 			readwrite(connfd);
3795570Svk199839 			(void) close(connfd);
3805570Svk199839 			if (family != AF_UNIX)
3815570Svk199839 				(void) close(s);
3825570Svk199839 
3835570Svk199839 			if (!kflag)
3845570Svk199839 				break;
3855570Svk199839 		}
3865570Svk199839 	} else if (family == AF_UNIX) {
3875570Svk199839 		ret = 0;
3885570Svk199839 
3895570Svk199839 		if ((s = unix_connect(host)) > 0 && !zflag) {
3905570Svk199839 			readwrite(s);
3915570Svk199839 			(void) close(s);
3925570Svk199839 		} else
3935570Svk199839 			ret = 1;
3945570Svk199839 
3955570Svk199839 		exit(ret);
3965570Svk199839 
3975570Svk199839 	} else {	/* AF_INET or AF_INET6 */
398*8414Serik.trauschke@freenet.de 		int i;
3995570Svk199839 
400*8414Serik.trauschke@freenet.de 		/* Construct the portlist. */
4015570Svk199839 		build_ports(uport);
4025570Svk199839 
4035570Svk199839 		/* Cycle through portlist, connecting to each port. */
404*8414Serik.trauschke@freenet.de 		for (i = 0; i < ports.numports; i++) {
405*8414Serik.trauschke@freenet.de 			(void) snprintf(port, sizeof (port), "%u",
406*8414Serik.trauschke@freenet.de 			    ports.list[i]);
407*8414Serik.trauschke@freenet.de 
408*8414Serik.trauschke@freenet.de 			if (s != -1)
4095570Svk199839 				(void) close(s);
4105570Svk199839 
4115570Svk199839 			if (xflag)
412*8414Serik.trauschke@freenet.de 				s = socks_connect(host, port,
4135570Svk199839 				    proxyhost, proxyport, proxyhints, socksv,
4145570Svk199839 				    Pflag);
4155570Svk199839 			else
416*8414Serik.trauschke@freenet.de 				s = remote_connect(host, port, hints);
4175570Svk199839 
4185570Svk199839 			if (s < 0)
4195570Svk199839 				continue;
4205570Svk199839 
4215570Svk199839 			ret = 0;
4225570Svk199839 			if (vflag || zflag) {
4235570Svk199839 				/* For UDP, make sure we are connected. */
4245570Svk199839 				if (uflag) {
4255570Svk199839 					if (udptest(s) == -1) {
4265570Svk199839 						ret = 1;
4275570Svk199839 						continue;
4285570Svk199839 					}
4295570Svk199839 				}
4305570Svk199839 
4315570Svk199839 				/* Don't look up port if -n. */
4325570Svk199839 				if (nflag)
4335570Svk199839 					sv = NULL;
4345570Svk199839 				else {
4355570Svk199839 					sv = getservbyport(
436*8414Serik.trauschke@freenet.de 					    ntohs(ports.list[i]),
4375570Svk199839 					    uflag ? "udp" : "tcp");
4385570Svk199839 				}
4395570Svk199839 
4405830Svk199839 				(void) fprintf(stderr, "Connection to %s %s "
4415570Svk199839 				    "port [%s/%s] succeeded!\n",
442*8414Serik.trauschke@freenet.de 				    host, port, uflag ? "udp" : "tcp",
4435570Svk199839 				    sv ? sv->s_name : "*");
4445570Svk199839 			}
4455570Svk199839 			if (!zflag)
4465570Svk199839 				readwrite(s);
4475570Svk199839 		}
448*8414Serik.trauschke@freenet.de 		free(ports.list);
4495570Svk199839 	}
4505570Svk199839 
451*8414Serik.trauschke@freenet.de 	if (s != -1)
4525570Svk199839 		(void) close(s);
4535570Svk199839 
4545570Svk199839 	return (ret);
4555570Svk199839 }
4565570Svk199839 
4575570Svk199839 /*
4585830Svk199839  * print IP address and (optionally) a port
4595830Svk199839  */
4605830Svk199839 char *
print_addr(char * ntop,size_t ntlen,struct sockaddr * addr,int len,int flags)4615830Svk199839 print_addr(char *ntop, size_t ntlen, struct sockaddr *addr, int len, int flags)
4625830Svk199839 {
4635830Svk199839 	char port[NI_MAXSERV];
4645830Svk199839 	int e;
4655830Svk199839 
4665830Svk199839 	/* print port always as number */
4675830Svk199839 	if ((e = getnameinfo(addr, len, ntop, ntlen,
4685830Svk199839 	    port, sizeof (port), flags|NI_NUMERICSERV)) != 0) {
4695830Svk199839 		return ((char *)gai_strerror(e));
4705830Svk199839 	}
4715830Svk199839 
4725830Svk199839 	(void) snprintf(ntop, ntlen, "%s port %s", ntop, port);
4735830Svk199839 
4745830Svk199839 	return (ntop);
4755830Svk199839 }
4765830Svk199839 
4775830Svk199839 /*
4785570Svk199839  * unix_connect()
4795570Svk199839  * Returns a socket connected to a local unix socket. Returns -1 on failure.
4805570Svk199839  */
4815570Svk199839 int
unix_connect(char * path)4825570Svk199839 unix_connect(char *path)
4835570Svk199839 {
4845570Svk199839 	struct sockaddr_un sunaddr;
4855570Svk199839 	int s;
4865570Svk199839 
4875570Svk199839 	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
4885570Svk199839 		return (-1);
4895570Svk199839 
4905570Svk199839 	(void) memset(&sunaddr, 0, sizeof (struct sockaddr_un));
4915570Svk199839 	sunaddr.sun_family = AF_UNIX;
4925570Svk199839 
4935570Svk199839 	if (strlcpy(sunaddr.sun_path, path, sizeof (sunaddr.sun_path)) >=
4945570Svk199839 	    sizeof (sunaddr.sun_path)) {
4955570Svk199839 		(void) close(s);
4965570Svk199839 		errno = ENAMETOOLONG;
4975570Svk199839 		return (-1);
4985570Svk199839 	}
4995570Svk199839 	if (connect(s, (struct sockaddr *)&sunaddr, SUN_LEN(&sunaddr)) < 0) {
5005570Svk199839 		(void) close(s);
5015570Svk199839 		return (-1);
5025570Svk199839 	}
5035570Svk199839 	return (s);
5045570Svk199839 }
5055570Svk199839 
5065570Svk199839 /*
5075570Svk199839  * unix_listen()
5085570Svk199839  * Create a unix domain socket, and listen on it.
5095570Svk199839  */
5105570Svk199839 int
unix_listen(char * path)5115570Svk199839 unix_listen(char *path)
5125570Svk199839 {
5135570Svk199839 	struct sockaddr_un sunaddr;
5145570Svk199839 	int s;
5155570Svk199839 
5165570Svk199839 	/* Create unix domain socket. */
5175570Svk199839 	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
5185570Svk199839 		return (-1);
5195570Svk199839 
5205570Svk199839 	(void) memset(&sunaddr, 0, sizeof (struct sockaddr_un));
5215570Svk199839 	sunaddr.sun_family = AF_UNIX;
5225570Svk199839 
5235570Svk199839 	if (strlcpy(sunaddr.sun_path, path, sizeof (sunaddr.sun_path)) >=
5245570Svk199839 	    sizeof (sunaddr.sun_path)) {
5255570Svk199839 		(void) close(s);
5265570Svk199839 		errno = ENAMETOOLONG;
5275570Svk199839 		return (-1);
5285570Svk199839 	}
5295570Svk199839 
5305570Svk199839 	if (bind(s, (struct sockaddr *)&sunaddr, SUN_LEN(&sunaddr)) < 0) {
5315570Svk199839 		(void) close(s);
5325570Svk199839 		return (-1);
5335570Svk199839 	}
5345570Svk199839 
5355570Svk199839 	if (listen(s, 5) < 0) {
5365570Svk199839 		(void) close(s);
5375570Svk199839 		return (-1);
5385570Svk199839 	}
5395570Svk199839 	return (s);
5405570Svk199839 }
5415570Svk199839 
5425570Svk199839 /*
5435570Svk199839  * remote_connect()
5445570Svk199839  * Returns a socket connected to a remote host. Properly binds to a local
5455570Svk199839  * port or source address if needed. Returns -1 on failure.
5465570Svk199839  */
5475570Svk199839 int
remote_connect(const char * host,const char * port,struct addrinfo hints)5485570Svk199839 remote_connect(const char *host, const char *port, struct addrinfo hints)
5495570Svk199839 {
5505570Svk199839 	struct addrinfo *res, *res0;
5515570Svk199839 	int s, error;
5525570Svk199839 
5535570Svk199839 	if ((error = getaddrinfo(host, port, &hints, &res)))
5545570Svk199839 		errx(1, "getaddrinfo: %s", gai_strerror(error));
5555570Svk199839 
5565570Svk199839 	res0 = res;
5575570Svk199839 	do {
5585570Svk199839 		if ((s = socket(res0->ai_family, res0->ai_socktype,
5595570Svk199839 		    res0->ai_protocol)) < 0) {
5605570Svk199839 			warn("failed to create socket");
5615570Svk199839 			continue;
5625570Svk199839 		}
5635570Svk199839 
5645570Svk199839 		/* Bind to a local port or source address if specified. */
5655570Svk199839 		if (sflag || pflag) {
5665570Svk199839 			struct addrinfo ahints, *ares;
5675570Svk199839 
5685570Svk199839 			(void) memset(&ahints, 0, sizeof (struct addrinfo));
5695570Svk199839 			ahints.ai_family = res0->ai_family;
5705570Svk199839 			ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
5715570Svk199839 			ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
5725570Svk199839 			ahints.ai_flags = AI_PASSIVE;
5735570Svk199839 			if ((error = getaddrinfo(sflag, pflag, &ahints, &ares)))
5745570Svk199839 				errx(1, "getaddrinfo: %s", gai_strerror(error));
5755570Svk199839 
5765570Svk199839 			if (bind(s, (struct sockaddr *)ares->ai_addr,
5775570Svk199839 			    ares->ai_addrlen) < 0)
5785570Svk199839 				errx(1, "bind failed: %s", strerror(errno));
5795570Svk199839 			freeaddrinfo(ares);
5805830Svk199839 
5815830Svk199839 			if (vflag && !lflag) {
5825830Svk199839 				if (sflag != NULL)
5835830Svk199839 					(void) fprintf(stderr,
5845830Svk199839 					    "Using source address: %s\n",
5855830Svk199839 					    sflag);
5865830Svk199839 				if (pflag != NULL)
5875830Svk199839 					(void) fprintf(stderr,
5885830Svk199839 					    "Using source port: %s\n", pflag);
5895830Svk199839 			}
5905570Svk199839 		}
5915570Svk199839 
5925570Svk199839 		set_common_sockopts(s);
5935570Svk199839 
5945570Svk199839 		if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
5955570Svk199839 			break;
5965830Svk199839 		else if (vflag) {
5975830Svk199839 			char ntop[NI_MAXHOST + NI_MAXSERV];
5985830Svk199839 			warn("connect to %s [host %s] (%s) failed",
5995830Svk199839 			    print_addr(ntop, sizeof (ntop),
6005830Svk199839 			    res0->ai_addr, res0->ai_addrlen, NI_NUMERICHOST),
6015830Svk199839 			    host, uflag ? "udp" : "tcp");
6025830Svk199839 		}
6035570Svk199839 
6045570Svk199839 		(void) close(s);
6055570Svk199839 		s = -1;
6065570Svk199839 	} while ((res0 = res0->ai_next) != NULL);
6075570Svk199839 
6085570Svk199839 	freeaddrinfo(res);
6095570Svk199839 
6105570Svk199839 	return (s);
6115570Svk199839 }
6125570Svk199839 
6135570Svk199839 /*
6145570Svk199839  * local_listen()
6155570Svk199839  * Returns a socket listening on a local port, binds to specified source
6165570Svk199839  * address. Returns -1 on failure.
6175570Svk199839  */
6185570Svk199839 int
local_listen(char * host,char * port,struct addrinfo hints)6195570Svk199839 local_listen(char *host, char *port, struct addrinfo hints)
6205570Svk199839 {
6215570Svk199839 	struct addrinfo *res, *res0;
6225570Svk199839 	int s, ret, x = 1;
6235570Svk199839 	int error;
6245570Svk199839 
6255570Svk199839 	/* Allow nodename to be null. */
6265570Svk199839 	hints.ai_flags |= AI_PASSIVE;
6275570Svk199839 
6285570Svk199839 	if ((error = getaddrinfo(host, port, &hints, &res)))
6295570Svk199839 		errx(1, "getaddrinfo: %s", gai_strerror(error));
6305570Svk199839 
6315570Svk199839 	res0 = res;
6325570Svk199839 	do {
6335570Svk199839 		if ((s = socket(res0->ai_family, res0->ai_socktype,
6345570Svk199839 		    res0->ai_protocol)) < 0) {
6355570Svk199839 			warn("failed to create socket");
6365570Svk199839 			continue;
6375570Svk199839 		}
6385570Svk199839 
6395570Svk199839 		ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x));
6405570Svk199839 		if (ret == -1)
6415570Svk199839 			err(1, NULL);
6425570Svk199839 
6435570Svk199839 		set_common_sockopts(s);
6445570Svk199839 
6455570Svk199839 		if (bind(s, (struct sockaddr *)res0->ai_addr,
6465570Svk199839 		    res0->ai_addrlen) == 0)
6475570Svk199839 			break;
6485570Svk199839 
6495570Svk199839 		(void) close(s);
6505570Svk199839 		s = -1;
6515570Svk199839 	} while ((res0 = res0->ai_next) != NULL);
6525570Svk199839 
6535570Svk199839 	if (!uflag && s != -1) {
6545570Svk199839 		if (listen(s, 1) < 0)
6555570Svk199839 			err(1, "listen");
6565570Svk199839 	}
6575570Svk199839 
6585570Svk199839 	freeaddrinfo(res);
6595570Svk199839 
6605570Svk199839 	return (s);
6615570Svk199839 }
6625570Svk199839 
6635570Svk199839 /*
6645570Svk199839  * readwrite()
6655570Svk199839  * Loop that polls on the network file descriptor and stdin.
6665570Svk199839  */
6675570Svk199839 void
readwrite(int nfd)6685570Svk199839 readwrite(int nfd)
6695570Svk199839 {
6705570Svk199839 	struct pollfd pfd[2];
6715570Svk199839 	unsigned char buf[8192];
6725570Svk199839 	int n, wfd = fileno(stdin);
6735570Svk199839 	int lfd = fileno(stdout);
6745570Svk199839 	int plen;
6755570Svk199839 
6765570Svk199839 	plen = 1024;
6775570Svk199839 
6785570Svk199839 	/* Setup Network FD */
6795570Svk199839 	pfd[0].fd = nfd;
6805570Svk199839 	pfd[0].events = POLLIN;
6815570Svk199839 
6825570Svk199839 	/* Set up STDIN FD. */
6835570Svk199839 	pfd[1].fd = wfd;
6845570Svk199839 	pfd[1].events = POLLIN;
6855570Svk199839 
6865570Svk199839 	while (pfd[0].fd != -1) {
6875570Svk199839 		if (iflag)
6885570Svk199839 			(void) sleep(iflag);
6895570Svk199839 
6905570Svk199839 		if ((n = poll(pfd, 2 - dflag, timeout)) < 0) {
6915570Svk199839 			(void) close(nfd);
6925570Svk199839 			err(1, "Polling Error");
6935570Svk199839 		}
6945570Svk199839 
6955570Svk199839 		if (n == 0)
6965570Svk199839 			return;
6975570Svk199839 
6985570Svk199839 		if (pfd[0].revents & (POLLIN|POLLHUP)) {
6995570Svk199839 			if ((n = read(nfd, buf, plen)) < 0)
7005570Svk199839 				return;
7015570Svk199839 			else if (n == 0) {
7025570Svk199839 				(void) shutdown(nfd, SHUT_RD);
7035570Svk199839 				pfd[0].fd = -1;
7045570Svk199839 				pfd[0].events = 0;
7055570Svk199839 			} else {
7065570Svk199839 				if (tflag)
7075570Svk199839 					atelnet(nfd, buf, n);
7085570Svk199839 				if (atomicio(vwrite, lfd, buf, n) != n)
7095570Svk199839 					return;
7105570Svk199839 			}
7115570Svk199839 		}
7125570Svk199839 
7135570Svk199839 		/*
7145570Svk199839 		 * handle the case of disconnected pipe: after pipe
7155570Svk199839 		 * is closed (indicated by POLLHUP) there may still
7165570Svk199839 		 * be some data lingering (POLLIN). After we read
7175570Svk199839 		 * the data, only POLLHUP remains, read() returns 0
7185570Svk199839 		 * and we are finished.
7195570Svk199839 		 */
7205570Svk199839 		if (!dflag && (pfd[1].revents & (POLLIN|POLLHUP))) {
7215570Svk199839 			if ((n = read(wfd, buf, plen)) < 0)
7225570Svk199839 				return;
7235570Svk199839 			else if (n == 0) {
7245570Svk199839 				(void) shutdown(nfd, SHUT_WR);
7255570Svk199839 				pfd[1].fd = -1;
7265570Svk199839 				pfd[1].events = 0;
7275570Svk199839 			} else {
7285570Svk199839 				if (atomicio(vwrite, nfd, buf, n) != n)
7295570Svk199839 					return;
7305570Svk199839 			}
7315570Svk199839 		}
7325570Svk199839 	}
7335570Svk199839 }
7345570Svk199839 
7355570Svk199839 /* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */
7365570Svk199839 void
atelnet(int nfd,unsigned char * buf,unsigned int size)7375570Svk199839 atelnet(int nfd, unsigned char *buf, unsigned int size)
7385570Svk199839 {
7395570Svk199839 	unsigned char *p, *end;
7405570Svk199839 	unsigned char obuf[4];
7415570Svk199839 
7425570Svk199839 	end = buf + size;
7435570Svk199839 	obuf[0] = '\0';
7445570Svk199839 
7455570Svk199839 	for (p = buf; p < end; p++) {
7465570Svk199839 		if (*p != IAC)
7475570Svk199839 			break;
7485570Svk199839 
7495570Svk199839 		obuf[0] = IAC;
7505570Svk199839 		obuf[1] = 0;
7515570Svk199839 		p++;
7525570Svk199839 		/* refuse all options */
7535570Svk199839 		if ((*p == WILL) || (*p == WONT))
7545570Svk199839 			obuf[1] = DONT;
7555570Svk199839 		if ((*p == DO) || (*p == DONT))
7565570Svk199839 			obuf[1] = WONT;
7575570Svk199839 		if (obuf[1]) {
7585570Svk199839 			p++;
7595570Svk199839 			obuf[2] = *p;
7605570Svk199839 			obuf[3] = '\0';
7615570Svk199839 			if (atomicio(vwrite, nfd, obuf, 3) != 3)
7625570Svk199839 				warn("Write Error!");
7635570Svk199839 			obuf[0] = '\0';
7645570Svk199839 		}
7655570Svk199839 	}
7665570Svk199839 }
7675570Svk199839 
7685570Svk199839 /*
7695570Svk199839  * build_ports()
770*8414Serik.trauschke@freenet.de  * Build an array of ports in ports.list[], listing each port
7715570Svk199839  * that we should try to connect to.
7725570Svk199839  */
7735570Svk199839 void
build_ports(char * p)7745570Svk199839 build_ports(char *p)
7755570Svk199839 {
7765570Svk199839 	const char *errstr;
777*8414Serik.trauschke@freenet.de 	const char *token;
7785570Svk199839 	char *n;
779*8414Serik.trauschke@freenet.de 	int lo, hi, cp;
780*8414Serik.trauschke@freenet.de 	int i;
7815570Svk199839 
782*8414Serik.trauschke@freenet.de 	/* Set up initial portlist. */
783*8414Serik.trauschke@freenet.de 	ports.list = malloc(PLIST_SZ * sizeof (uint16_t));
784*8414Serik.trauschke@freenet.de 	if (ports.list == NULL)
785*8414Serik.trauschke@freenet.de 		err(1, NULL);
786*8414Serik.trauschke@freenet.de 	ports.listsize = PLIST_SZ;
787*8414Serik.trauschke@freenet.de 	ports.numports = 0;
7885570Svk199839 
789*8414Serik.trauschke@freenet.de 	/* Cycle through list of given ports sep. by "," */
790*8414Serik.trauschke@freenet.de 	while ((token = strsep(&p, ",")) != NULL) {
791*8414Serik.trauschke@freenet.de 		if (*token == '\0')
792*8414Serik.trauschke@freenet.de 			errx(1, "Invalid port/portlist format: "
793*8414Serik.trauschke@freenet.de 			    "zero length port");
794*8414Serik.trauschke@freenet.de 
795*8414Serik.trauschke@freenet.de 		/* check if it is a range */
796*8414Serik.trauschke@freenet.de 		if ((n = strchr(token, '-')) != NULL)
797*8414Serik.trauschke@freenet.de 			*n++ = '\0';
7985570Svk199839 
799*8414Serik.trauschke@freenet.de 		lo = strtonum(token, PORT_MIN, PORT_MAX, &errstr);
8005570Svk199839 		if (errstr)
801*8414Serik.trauschke@freenet.de 			errx(1, "port number %s: %s", errstr, token);
8025570Svk199839 
803*8414Serik.trauschke@freenet.de 		if (n == NULL) {
8045570Svk199839 			hi = lo;
805*8414Serik.trauschke@freenet.de 		} else {
806*8414Serik.trauschke@freenet.de 			hi = strtonum(n, PORT_MIN, PORT_MAX, &errstr);
807*8414Serik.trauschke@freenet.de 			if (errstr)
808*8414Serik.trauschke@freenet.de 				errx(1, "port number %s: %s", errstr, n);
809*8414Serik.trauschke@freenet.de 			if (lo > hi) {
810*8414Serik.trauschke@freenet.de 				cp = hi;
811*8414Serik.trauschke@freenet.de 				hi = lo;
812*8414Serik.trauschke@freenet.de 				lo = cp;
813*8414Serik.trauschke@freenet.de 			}
814*8414Serik.trauschke@freenet.de 		}
815*8414Serik.trauschke@freenet.de 
816*8414Serik.trauschke@freenet.de 		/*
817*8414Serik.trauschke@freenet.de 		 * Grow the portlist if needed.
818*8414Serik.trauschke@freenet.de 		 * We double the size and add size of current range
819*8414Serik.trauschke@freenet.de 		 * to make sure we don't have to resize that often.
820*8414Serik.trauschke@freenet.de 		 */
821*8414Serik.trauschke@freenet.de 		if (hi - lo + ports.numports + 1 >= ports.listsize) {
822*8414Serik.trauschke@freenet.de 			ports.listsize = ports.listsize * 2 + hi - lo;
823*8414Serik.trauschke@freenet.de 			ports.list = realloc(ports.list,
824*8414Serik.trauschke@freenet.de 			    ports.listsize * sizeof (uint16_t));
825*8414Serik.trauschke@freenet.de 			if (ports.list == NULL)
826*8414Serik.trauschke@freenet.de 				err(1, NULL);
8275570Svk199839 		}
8285570Svk199839 
8295570Svk199839 		/* Load ports sequentially. */
830*8414Serik.trauschke@freenet.de 		for (i = lo; i <= hi; i++)
831*8414Serik.trauschke@freenet.de 			ports.list[ports.numports++] = i;
832*8414Serik.trauschke@freenet.de 	}
8335570Svk199839 
834*8414Serik.trauschke@freenet.de 	/* Randomly swap ports. */
835*8414Serik.trauschke@freenet.de 	if (rflag) {
836*8414Serik.trauschke@freenet.de 		int y;
837*8414Serik.trauschke@freenet.de 		uint16_t u;
8385570Svk199839 
839*8414Serik.trauschke@freenet.de 		if (ports.numports < 2) {
840*8414Serik.trauschke@freenet.de 			warnx("can not swap %d port randomly",
841*8414Serik.trauschke@freenet.de 			    ports.numports);
842*8414Serik.trauschke@freenet.de 			return;
8435570Svk199839 		}
844*8414Serik.trauschke@freenet.de 		srandom(time(NULL));
845*8414Serik.trauschke@freenet.de 		for (i = 0; i < ports.numports; i++) {
846*8414Serik.trauschke@freenet.de 			y = random() % (ports.numports - 1);
847*8414Serik.trauschke@freenet.de 			u = ports.list[i];
848*8414Serik.trauschke@freenet.de 			ports.list[i] = ports.list[y];
849*8414Serik.trauschke@freenet.de 			ports.list[y] = u;
850*8414Serik.trauschke@freenet.de 		}
8515570Svk199839 	}
8525570Svk199839 }
8535570Svk199839 
8545570Svk199839 /*
8555570Svk199839  * udptest()
8565570Svk199839  * Do a few writes to see if the UDP port is there.
8575570Svk199839  * XXX - Better way of doing this? Doesn't work for IPv6.
8585570Svk199839  * Also fails after around 100 ports checked.
8595570Svk199839  */
8605570Svk199839 int
udptest(int s)8615570Svk199839 udptest(int s)
8625570Svk199839 {
8635570Svk199839 	int i, ret;
8645570Svk199839 
8655570Svk199839 	for (i = 0; i <= 3; i++) {
8665570Svk199839 		if (write(s, "X", 1) == 1)
8675570Svk199839 			ret = 1;
8685570Svk199839 		else
8695570Svk199839 			ret = -1;
8705570Svk199839 	}
8715570Svk199839 	return (ret);
8725570Svk199839 }
8735570Svk199839 
8745570Svk199839 void
set_common_sockopts(int s)8755570Svk199839 set_common_sockopts(int s)
8765570Svk199839 {
8775570Svk199839 	int x = 1;
8785570Svk199839 
8795570Svk199839 	if (Dflag) {
8805570Svk199839 		if (setsockopt(s, SOL_SOCKET, SO_DEBUG, &x, sizeof (x)) == -1)
8815570Svk199839 			err(1, NULL);
8825570Svk199839 	}
8835570Svk199839 	if (Tflag != -1) {
8845570Svk199839 		if (setsockopt(s, IPPROTO_IP, IP_TOS, &Tflag,
8855570Svk199839 		    sizeof (Tflag)) == -1)
8865570Svk199839 			err(1, "set IP ToS");
8875570Svk199839 	}
8885570Svk199839 }
8895570Svk199839 
8905570Svk199839 int
parse_iptos(char * s)8915570Svk199839 parse_iptos(char *s)
8925570Svk199839 {
8935570Svk199839 	int tos = -1;
8945570Svk199839 
8955570Svk199839 	if (strcmp(s, "lowdelay") == 0)
8965570Svk199839 		return (IPTOS_LOWDELAY);
8975570Svk199839 	if (strcmp(s, "throughput") == 0)
8985570Svk199839 		return (IPTOS_THROUGHPUT);
8995570Svk199839 	if (strcmp(s, "reliability") == 0)
9005570Svk199839 		return (IPTOS_RELIABILITY);
9015570Svk199839 
9025570Svk199839 	if (sscanf(s, "0x%x", (unsigned int *) &tos) != 1 ||
9035570Svk199839 	    tos < 0 || tos > 0xff)
9045570Svk199839 		errx(1, "invalid IP Type of Service");
9055570Svk199839 	return (tos);
9065570Svk199839 }
9075570Svk199839 
9085570Svk199839 void
help(void)9095570Svk199839 help(void)
9105570Svk199839 {
9115570Svk199839 	usage(0);
9125570Svk199839 	(void) fprintf(stderr, "\tCommand Summary:\n\
9135570Svk199839 	\t-4		Use IPv4\n\
9145570Svk199839 	\t-6		Use IPv6\n\
9155570Svk199839 	\t-D		Enable the debug socket option\n\
9165570Svk199839 	\t-d		Detach from stdin\n\
9175570Svk199839 	\t-h		This help text\n\
9185570Svk199839 	\t-i secs\t	Delay interval for lines sent, ports scanned\n\
9195570Svk199839 	\t-k		Keep inbound sockets open for multiple connects\n\
9205570Svk199839 	\t-l		Listen mode, for inbound connects\n\
9215570Svk199839 	\t-n		Suppress name/port resolutions\n\
9225570Svk199839 	\t-P proxyuser\tUsername for proxy authentication\n\
9235570Svk199839 	\t-p port\t	Specify local port or listen port\n\
9245570Svk199839 	\t-r		Randomize remote ports\n\
9255570Svk199839 	\t-s addr\t	Local source address\n\
9265570Svk199839 	\t-T ToS\t	Set IP Type of Service\n\
9275570Svk199839 	\t-t		Answer TELNET negotiation\n\
9285570Svk199839 	\t-U		Use UNIX domain socket\n\
9295570Svk199839 	\t-u		UDP mode\n\
9305570Svk199839 	\t-v		Verbose\n\
9315570Svk199839 	\t-w secs\t	Timeout for connects and final net reads\n\
9325570Svk199839 	\t-X proto	Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\
9335570Svk199839 	\t-x addr[:port]\tSpecify proxy address and port\n\
9345570Svk199839 	\t-z		Zero-I/O mode [used for scanning]\n\
935*8414Serik.trauschke@freenet.de 	Port numbers can be individuals, ranges (lo-hi; inclusive) and\n\
936*8414Serik.trauschke@freenet.de 	combinations of both separated by comma (e.g. 10,22-25,80)\n");
9375570Svk199839 	exit(1);
9385570Svk199839 }
9395570Svk199839 
9405570Svk199839 void
usage(int ret)9415570Svk199839 usage(int ret)
9425570Svk199839 {
9435570Svk199839 	(void) fprintf(stderr,
9445570Svk199839 	    "usage: nc [-46DdhklnrtUuvz] [-i interval] [-P proxy_username]"
9455570Svk199839 	    " [-p port]\n");
9465570Svk199839 	(void) fprintf(stderr,
9475570Svk199839 	    "\t  [-s source_ip_address] [-T ToS] [-w timeout]"
9485570Svk199839 	    " [-X proxy_protocol]\n");
9495570Svk199839 	(void) fprintf(stderr,
9505570Svk199839 	    "\t  [-x proxy_address[:port]] [hostname]"
9515570Svk199839 	    " [port[s]]\n");
9525570Svk199839 	if (ret)
9535570Svk199839 		exit(1);
9545570Svk199839 }
955