1264911Sdelphij/* $OpenBSD: netcat.c,v 1.117 2013/10/26 21:33:29 sthen Exp $ */
2141261Sdelphij/*
3141261Sdelphij * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
4141261Sdelphij *
5141261Sdelphij * Redistribution and use in source and binary forms, with or without
6141261Sdelphij * modification, are permitted provided that the following conditions
7141261Sdelphij * are met:
8141261Sdelphij *
9141261Sdelphij * 1. Redistributions of source code must retain the above copyright
10141261Sdelphij *   notice, this list of conditions and the following disclaimer.
11141261Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
12141261Sdelphij *   notice, this list of conditions and the following disclaimer in the
13141261Sdelphij *   documentation and/or other materials provided with the distribution.
14141261Sdelphij * 3. The name of the author may not be used to endorse or promote products
15141261Sdelphij *   derived from this software without specific prior written permission.
16141261Sdelphij *
17141261Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18141261Sdelphij * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19141261Sdelphij * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20141261Sdelphij * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21141261Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22141261Sdelphij * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23141261Sdelphij * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24141261Sdelphij * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25141261Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26141261Sdelphij * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27141394Sdelphij *
28141394Sdelphij * $FreeBSD$
29141261Sdelphij */
30141261Sdelphij
31141261Sdelphij/*
32141261Sdelphij * Re-written nc(1) for OpenBSD. Original implementation by
33141261Sdelphij * *Hobbit* <hobbit@avian.org>.
34141261Sdelphij */
35141261Sdelphij
36141394Sdelphij#include <sys/limits.h>
37141261Sdelphij#include <sys/types.h>
38141261Sdelphij#include <sys/socket.h>
39202640Sdelphij#include <sys/sysctl.h>
40141261Sdelphij#include <sys/time.h>
41264911Sdelphij#include <sys/uio.h>
42141261Sdelphij#include <sys/un.h>
43141261Sdelphij
44141261Sdelphij#include <netinet/in.h>
45158798Sdelphij#include <netinet/in_systm.h>
46141394Sdelphij#ifdef IPSEC
47171135Sgnn#include <netipsec/ipsec.h>
48141394Sdelphij#endif
49141261Sdelphij#include <netinet/tcp.h>
50158798Sdelphij#include <netinet/ip.h>
51141261Sdelphij#include <arpa/telnet.h>
52141261Sdelphij
53141261Sdelphij#include <err.h>
54141261Sdelphij#include <errno.h>
55186343Sdelphij#include <getopt.h>
56141261Sdelphij#include <netdb.h>
57141261Sdelphij#include <poll.h>
58141261Sdelphij#include <stdarg.h>
59141261Sdelphij#include <stdio.h>
60141261Sdelphij#include <stdlib.h>
61141261Sdelphij#include <string.h>
62141261Sdelphij#include <unistd.h>
63141261Sdelphij#include <fcntl.h>
64158798Sdelphij#include <limits.h>
65158798Sdelphij#include "atomicio.h"
66141261Sdelphij
67141261Sdelphij#ifndef SUN_LEN
68141261Sdelphij#define SUN_LEN(su) \
69141261Sdelphij	(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
70141261Sdelphij#endif
71141261Sdelphij
72141261Sdelphij#define PORT_MAX	65535
73141261Sdelphij#define PORT_MAX_LEN	6
74221793Sdelphij#define UNIX_DG_TMP_SOCKET_SIZE	19
75141261Sdelphij
76141261Sdelphij/* Command Line Options */
77141261Sdelphijint	dflag;					/* detached, no stdin */
78264911Sdelphijint	Fflag;					/* fdpass sock to stdout */
79167964Sdelphijunsigned int iflag;				/* Interval Flag */
80141261Sdelphijint	kflag;					/* More than one connect */
81141261Sdelphijint	lflag;					/* Bind to local port */
82249499Sdelphijint	Nflag;					/* shutdown() network socket */
83141261Sdelphijint	nflag;					/* Don't do name look up */
84186343Sdelphijint	FreeBSD_Oflag;				/* Do not use TCP options */
85158798Sdelphijchar   *Pflag;					/* Proxy username */
86141261Sdelphijchar   *pflag;					/* Localport flag */
87141261Sdelphijint	rflag;					/* Random ports flag */
88141261Sdelphijchar   *sflag;					/* Source Address */
89141261Sdelphijint	tflag;					/* Telnet Emulation */
90141261Sdelphijint	uflag;					/* UDP - Default to TCP */
91141261Sdelphijint	vflag;					/* Verbosity */
92141261Sdelphijint	xflag;					/* Socks proxy */
93141261Sdelphijint	zflag;					/* Port Scan Flag */
94141261Sdelphijint	Dflag;					/* sodebug */
95186343Sdelphijint	Iflag;					/* TCP receive buffer size */
96186343Sdelphijint	Oflag;					/* TCP send buffer size */
97141261Sdelphijint	Sflag;					/* TCP MD5 signature option */
98158798Sdelphijint	Tflag = -1;				/* IP Type of Service */
99264911Sdelphijint	rtableid = -1;
100141261Sdelphij
101141261Sdelphijint timeout = -1;
102141261Sdelphijint family = AF_UNSPEC;
103141261Sdelphijchar *portlist[PORT_MAX+1];
104221793Sdelphijchar *unix_dg_tmp_socket;
105141261Sdelphij
106141261Sdelphijvoid	atelnet(int, unsigned char *, unsigned int);
107141261Sdelphijvoid	build_ports(char *);
108141261Sdelphijvoid	help(void);
109141261Sdelphijint	local_listen(char *, char *, struct addrinfo);
110141261Sdelphijvoid	readwrite(int);
111264911Sdelphijvoid	fdpass(int nfd) __attribute__((noreturn));
112158798Sdelphijint	remote_connect(const char *, const char *, struct addrinfo);
113235037Sdelphijint	timeout_connect(int, const struct sockaddr *, socklen_t);
114158798Sdelphijint	socks_connect(const char *, const char *, struct addrinfo,
115158798Sdelphij	    const char *, const char *, struct addrinfo, int, const char *);
116141261Sdelphijint	udptest(int);
117221793Sdelphijint	unix_bind(char *);
118141261Sdelphijint	unix_connect(char *);
119141261Sdelphijint	unix_listen(char *);
120158798Sdelphijvoid	set_common_sockopts(int);
121235037Sdelphijint	map_tos(char *, int *);
122241906Sdelphijvoid	report_connect(const struct sockaddr *, socklen_t);
123141261Sdelphijvoid	usage(int);
124141261Sdelphij
125141394Sdelphij#ifdef IPSEC
126141394Sdelphijvoid	add_ipsec_policy(int, char *);
127141394Sdelphij
128141394Sdelphijchar	*ipsec_policy[2];
129141394Sdelphij#endif
130141394Sdelphij
131141261Sdelphijint
132141261Sdelphijmain(int argc, char *argv[])
133141261Sdelphij{
134141394Sdelphij	int ch, s, ret, socksv, ipsec_count;
135202640Sdelphij	int numfibs;
136202640Sdelphij	size_t intsize = sizeof(int);
137167964Sdelphij	char *host, *uport;
138141261Sdelphij	struct addrinfo hints;
139141261Sdelphij	struct servent *sv;
140141261Sdelphij	socklen_t len;
141141261Sdelphij	struct sockaddr_storage cliaddr;
142141261Sdelphij	char *proxy;
143167964Sdelphij	const char *errstr, *proxyhost = "", *proxyport = NULL;
144141261Sdelphij	struct addrinfo proxyhints;
145221793Sdelphij	char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE];
146186343Sdelphij	struct option longopts[] = {
147186343Sdelphij		{ "no-tcpopt",	no_argument,	&FreeBSD_Oflag,	1 },
148186343Sdelphij		{ NULL,		0,		NULL,		0 }
149186343Sdelphij	};
150141261Sdelphij
151141261Sdelphij	ret = 1;
152141394Sdelphij	ipsec_count = 0;
153141261Sdelphij	s = 0;
154141261Sdelphij	socksv = 5;
155141261Sdelphij	host = NULL;
156141261Sdelphij	uport = NULL;
157141261Sdelphij	sv = NULL;
158264911Sdelphij#if 0
159264911Sdelphij	rtableid = getrtable();
160264911Sdelphij#endif
161141261Sdelphij
162186343Sdelphij	while ((ch = getopt_long(argc, argv,
163264911Sdelphij	    "46DdEe:FhI:i:klNnoO:P:p:rSs:tT:UuV:vw:X:x:z",
164186343Sdelphij	    longopts, NULL)) != -1) {
165141261Sdelphij		switch (ch) {
166141261Sdelphij		case '4':
167141261Sdelphij			family = AF_INET;
168141261Sdelphij			break;
169141261Sdelphij		case '6':
170141261Sdelphij			family = AF_INET6;
171141261Sdelphij			break;
172141261Sdelphij		case 'U':
173141261Sdelphij			family = AF_UNIX;
174141261Sdelphij			break;
175141261Sdelphij		case 'X':
176141261Sdelphij			if (strcasecmp(optarg, "connect") == 0)
177141261Sdelphij				socksv = -1; /* HTTP proxy CONNECT */
178141261Sdelphij			else if (strcmp(optarg, "4") == 0)
179141261Sdelphij				socksv = 4; /* SOCKS v.4 */
180141261Sdelphij			else if (strcmp(optarg, "5") == 0)
181141261Sdelphij				socksv = 5; /* SOCKS v.5 */
182141261Sdelphij			else
183141261Sdelphij				errx(1, "unsupported proxy protocol");
184141261Sdelphij			break;
185141261Sdelphij		case 'd':
186141261Sdelphij			dflag = 1;
187141261Sdelphij			break;
188141394Sdelphij		case 'e':
189141394Sdelphij#ifdef IPSEC
190141394Sdelphij			ipsec_policy[ipsec_count++ % 2] = optarg;
191141394Sdelphij#else
192141394Sdelphij			errx(1, "IPsec support unavailable.");
193141394Sdelphij#endif
194141394Sdelphij			break;
195141394Sdelphij		case 'E':
196141394Sdelphij#ifdef IPSEC
197141394Sdelphij			ipsec_policy[0] = "in  ipsec esp/transport//require";
198141394Sdelphij			ipsec_policy[1] = "out ipsec esp/transport//require";
199141394Sdelphij#else
200141394Sdelphij			errx(1, "IPsec support unavailable.");
201141394Sdelphij#endif
202141394Sdelphij			break;
203264911Sdelphij		case 'F':
204264911Sdelphij			Fflag = 1;
205264911Sdelphij			break;
206141261Sdelphij		case 'h':
207141261Sdelphij			help();
208141261Sdelphij			break;
209141261Sdelphij		case 'i':
210167964Sdelphij			iflag = strtonum(optarg, 0, UINT_MAX, &errstr);
211167964Sdelphij			if (errstr)
212167964Sdelphij				errx(1, "interval %s: %s", errstr, optarg);
213141261Sdelphij			break;
214141261Sdelphij		case 'k':
215141261Sdelphij			kflag = 1;
216141261Sdelphij			break;
217141261Sdelphij		case 'l':
218141261Sdelphij			lflag = 1;
219141261Sdelphij			break;
220249499Sdelphij		case 'N':
221249499Sdelphij			Nflag = 1;
222249499Sdelphij			break;
223141261Sdelphij		case 'n':
224141261Sdelphij			nflag = 1;
225141261Sdelphij			break;
226141394Sdelphij		case 'o':
227206675Sdelphij			fprintf(stderr, "option -o is deprecated.\n");
228141394Sdelphij			break;
229158798Sdelphij		case 'P':
230158798Sdelphij			Pflag = optarg;
231158798Sdelphij			break;
232141261Sdelphij		case 'p':
233141261Sdelphij			pflag = optarg;
234141261Sdelphij			break;
235141261Sdelphij		case 'r':
236141261Sdelphij			rflag = 1;
237141261Sdelphij			break;
238141261Sdelphij		case 's':
239141261Sdelphij			sflag = optarg;
240141261Sdelphij			break;
241141261Sdelphij		case 't':
242141261Sdelphij			tflag = 1;
243141261Sdelphij			break;
244141261Sdelphij		case 'u':
245141261Sdelphij			uflag = 1;
246141261Sdelphij			break;
247202640Sdelphij		case 'V':
248202640Sdelphij			if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1)
249202640Sdelphij				errx(1, "Multiple FIBS not supported");
250264911Sdelphij			rtableid = (int)strtonum(optarg, 0,
251202640Sdelphij			    numfibs - 1, &errstr);
252202640Sdelphij			if (errstr)
253214047Sdelphij				errx(1, "rtable %s: %s", errstr, optarg);
254202640Sdelphij			break;
255141261Sdelphij		case 'v':
256141261Sdelphij			vflag = 1;
257141261Sdelphij			break;
258141261Sdelphij		case 'w':
259167964Sdelphij			timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr);
260167964Sdelphij			if (errstr)
261167964Sdelphij				errx(1, "timeout %s: %s", errstr, optarg);
262141261Sdelphij			timeout *= 1000;
263141261Sdelphij			break;
264141261Sdelphij		case 'x':
265141261Sdelphij			xflag = 1;
266141261Sdelphij			if ((proxy = strdup(optarg)) == NULL)
267141261Sdelphij				err(1, NULL);
268141261Sdelphij			break;
269141261Sdelphij		case 'z':
270141261Sdelphij			zflag = 1;
271141261Sdelphij			break;
272141261Sdelphij		case 'D':
273141261Sdelphij			Dflag = 1;
274141261Sdelphij			break;
275186343Sdelphij		case 'I':
276186343Sdelphij			Iflag = strtonum(optarg, 1, 65536 << 14, &errstr);
277186343Sdelphij			if (errstr != NULL)
278186343Sdelphij				errx(1, "TCP receive window %s: %s",
279186343Sdelphij				    errstr, optarg);
280186343Sdelphij			break;
281186343Sdelphij		case 'O':
282186343Sdelphij			Oflag = strtonum(optarg, 1, 65536 << 14, &errstr);
283186343Sdelphij			if (errstr != NULL) {
284186343Sdelphij			    if (strcmp(errstr, "invalid") != 0)
285186343Sdelphij				errx(1, "TCP send window %s: %s",
286186343Sdelphij				    errstr, optarg);
287186343Sdelphij			}
288186343Sdelphij			break;
289141261Sdelphij		case 'S':
290141261Sdelphij			Sflag = 1;
291141261Sdelphij			break;
292158798Sdelphij		case 'T':
293235037Sdelphij			errstr = NULL;
294235037Sdelphij			errno = 0;
295235037Sdelphij			if (map_tos(optarg, &Tflag))
296235037Sdelphij				break;
297235037Sdelphij			if (strlen(optarg) > 1 && optarg[0] == '0' &&
298235037Sdelphij			    optarg[1] == 'x')
299235037Sdelphij				Tflag = (int)strtol(optarg, NULL, 16);
300235037Sdelphij			else
301235037Sdelphij				Tflag = (int)strtonum(optarg, 0, 255,
302235037Sdelphij				    &errstr);
303235037Sdelphij			if (Tflag < 0 || Tflag > 255 || errstr || errno)
304235037Sdelphij				errx(1, "illegal tos value %s", optarg);
305158798Sdelphij			break;
306141261Sdelphij		default:
307141261Sdelphij			usage(1);
308141261Sdelphij		}
309141261Sdelphij	}
310141261Sdelphij	argc -= optind;
311141261Sdelphij	argv += optind;
312141261Sdelphij
313141261Sdelphij	/* Cruft to make sure options are clean, and used properly. */
314141261Sdelphij	if (argv[0] && !argv[1] && family == AF_UNIX) {
315141261Sdelphij		host = argv[0];
316141261Sdelphij		uport = NULL;
317141261Sdelphij	} else if (argv[0] && !argv[1]) {
318141261Sdelphij		if  (!lflag)
319141261Sdelphij			usage(1);
320141261Sdelphij		uport = argv[0];
321141261Sdelphij		host = NULL;
322141261Sdelphij	} else if (argv[0] && argv[1]) {
323141261Sdelphij		host = argv[0];
324141261Sdelphij		uport = argv[1];
325141261Sdelphij	} else
326141261Sdelphij		usage(1);
327141261Sdelphij
328141261Sdelphij	if (lflag && sflag)
329141261Sdelphij		errx(1, "cannot use -s and -l");
330141261Sdelphij	if (lflag && pflag)
331141261Sdelphij		errx(1, "cannot use -p and -l");
332141261Sdelphij	if (lflag && zflag)
333141261Sdelphij		errx(1, "cannot use -z and -l");
334141261Sdelphij	if (!lflag && kflag)
335141261Sdelphij		errx(1, "must use -l with -k");
336141261Sdelphij
337221793Sdelphij	/* Get name of temporary socket for unix datagram client */
338221793Sdelphij	if ((family == AF_UNIX) && uflag && !lflag) {
339221793Sdelphij		if (sflag) {
340221793Sdelphij			unix_dg_tmp_socket = sflag;
341221793Sdelphij		} else {
342221793Sdelphij			strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX",
343221793Sdelphij				UNIX_DG_TMP_SOCKET_SIZE);
344221793Sdelphij			if (mktemp(unix_dg_tmp_socket_buf) == NULL)
345221793Sdelphij				err(1, "mktemp");
346221793Sdelphij			unix_dg_tmp_socket = unix_dg_tmp_socket_buf;
347221793Sdelphij		}
348221793Sdelphij	}
349221793Sdelphij
350141261Sdelphij	/* Initialize addrinfo structure. */
351141261Sdelphij	if (family != AF_UNIX) {
352141261Sdelphij		memset(&hints, 0, sizeof(struct addrinfo));
353141261Sdelphij		hints.ai_family = family;
354141261Sdelphij		hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
355141261Sdelphij		hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
356141261Sdelphij		if (nflag)
357141261Sdelphij			hints.ai_flags |= AI_NUMERICHOST;
358141261Sdelphij	}
359141261Sdelphij
360141261Sdelphij	if (xflag) {
361141261Sdelphij		if (uflag)
362141261Sdelphij			errx(1, "no proxy support for UDP mode");
363141261Sdelphij
364141261Sdelphij		if (lflag)
365141261Sdelphij			errx(1, "no proxy support for listen");
366141261Sdelphij
367141261Sdelphij		if (family == AF_UNIX)
368141261Sdelphij			errx(1, "no proxy support for unix sockets");
369141261Sdelphij
370141261Sdelphij		/* XXX IPv6 transport to proxy would probably work */
371141261Sdelphij		if (family == AF_INET6)
372141261Sdelphij			errx(1, "no proxy support for IPv6");
373141261Sdelphij
374141261Sdelphij		if (sflag)
375141261Sdelphij			errx(1, "no proxy support for local source address");
376141261Sdelphij
377141261Sdelphij		proxyhost = strsep(&proxy, ":");
378141261Sdelphij		proxyport = proxy;
379141261Sdelphij
380141261Sdelphij		memset(&proxyhints, 0, sizeof(struct addrinfo));
381141261Sdelphij		proxyhints.ai_family = family;
382141261Sdelphij		proxyhints.ai_socktype = SOCK_STREAM;
383141261Sdelphij		proxyhints.ai_protocol = IPPROTO_TCP;
384141261Sdelphij		if (nflag)
385141261Sdelphij			proxyhints.ai_flags |= AI_NUMERICHOST;
386141261Sdelphij	}
387141261Sdelphij
388141261Sdelphij	if (lflag) {
389141261Sdelphij		int connfd;
390141261Sdelphij		ret = 0;
391141261Sdelphij
392221793Sdelphij		if (family == AF_UNIX) {
393221793Sdelphij			if (uflag)
394221793Sdelphij				s = unix_bind(host);
395221793Sdelphij			else
396221793Sdelphij				s = unix_listen(host);
397221793Sdelphij		}
398141261Sdelphij
399141261Sdelphij		/* Allow only one connection at a time, but stay alive. */
400141261Sdelphij		for (;;) {
401141261Sdelphij			if (family != AF_UNIX)
402141261Sdelphij				s = local_listen(host, uport, hints);
403141261Sdelphij			if (s < 0)
404141261Sdelphij				err(1, NULL);
405141261Sdelphij			/*
406241906Sdelphij			 * For UDP and -k, don't connect the socket, let it
407241906Sdelphij			 * receive datagrams from multiple socket pairs.
408141261Sdelphij			 */
409241906Sdelphij			if (uflag && kflag)
410241906Sdelphij				readwrite(s);
411241906Sdelphij			/*
412241906Sdelphij			 * For UDP and not -k, we will use recvfrom() initially
413241906Sdelphij			 * to wait for a caller, then use the regular functions
414241906Sdelphij			 * to talk to the caller.
415241906Sdelphij			 */
416241906Sdelphij			else if (uflag && !kflag) {
417158798Sdelphij				int rv, plen;
418214047Sdelphij				char buf[16384];
419141261Sdelphij				struct sockaddr_storage z;
420141261Sdelphij
421141261Sdelphij				len = sizeof(z);
422241906Sdelphij				plen = 2048;
423158798Sdelphij				rv = recvfrom(s, buf, plen, MSG_PEEK,
424141261Sdelphij				    (struct sockaddr *)&z, &len);
425141261Sdelphij				if (rv < 0)
426141261Sdelphij					err(1, "recvfrom");
427141261Sdelphij
428141261Sdelphij				rv = connect(s, (struct sockaddr *)&z, len);
429141261Sdelphij				if (rv < 0)
430141261Sdelphij					err(1, "connect");
431141261Sdelphij
432241906Sdelphij				if (vflag)
433241906Sdelphij					report_connect((struct sockaddr *)&z, len);
434241906Sdelphij
435221793Sdelphij				readwrite(s);
436141261Sdelphij			} else {
437158798Sdelphij				len = sizeof(cliaddr);
438141261Sdelphij				connfd = accept(s, (struct sockaddr *)&cliaddr,
439141261Sdelphij				    &len);
440249499Sdelphij				if (connfd == -1) {
441249499Sdelphij					/* For now, all errnos are fatal */
442249499Sdelphij   					err(1, "accept");
443249499Sdelphij				}
444241906Sdelphij				if (vflag)
445241906Sdelphij					report_connect((struct sockaddr *)&cliaddr, len);
446241906Sdelphij
447221793Sdelphij				readwrite(connfd);
448221793Sdelphij				close(connfd);
449141261Sdelphij			}
450141261Sdelphij
451141261Sdelphij			if (family != AF_UNIX)
452141261Sdelphij				close(s);
453221793Sdelphij			else if (uflag) {
454221793Sdelphij				if (connect(s, NULL, 0) < 0)
455221793Sdelphij					err(1, "connect");
456221793Sdelphij			}
457141261Sdelphij
458141261Sdelphij			if (!kflag)
459141261Sdelphij				break;
460141261Sdelphij		}
461141261Sdelphij	} else if (family == AF_UNIX) {
462141261Sdelphij		ret = 0;
463141261Sdelphij
464141261Sdelphij		if ((s = unix_connect(host)) > 0 && !zflag) {
465141261Sdelphij			readwrite(s);
466141261Sdelphij			close(s);
467141261Sdelphij		} else
468141261Sdelphij			ret = 1;
469141261Sdelphij
470221793Sdelphij		if (uflag)
471221793Sdelphij			unlink(unix_dg_tmp_socket);
472141261Sdelphij		exit(ret);
473141261Sdelphij
474141261Sdelphij	} else {
475141261Sdelphij		int i = 0;
476141261Sdelphij
477141261Sdelphij		/* Construct the portlist[] array. */
478141261Sdelphij		build_ports(uport);
479141261Sdelphij
480141261Sdelphij		/* Cycle through portlist, connecting to each port. */
481141261Sdelphij		for (i = 0; portlist[i] != NULL; i++) {
482141261Sdelphij			if (s)
483141261Sdelphij				close(s);
484141261Sdelphij
485141261Sdelphij			if (xflag)
486141261Sdelphij				s = socks_connect(host, portlist[i], hints,
487158798Sdelphij				    proxyhost, proxyport, proxyhints, socksv,
488158798Sdelphij				    Pflag);
489141261Sdelphij			else
490141261Sdelphij				s = remote_connect(host, portlist[i], hints);
491141261Sdelphij
492141261Sdelphij			if (s < 0)
493141261Sdelphij				continue;
494141261Sdelphij
495141261Sdelphij			ret = 0;
496141261Sdelphij			if (vflag || zflag) {
497141261Sdelphij				/* For UDP, make sure we are connected. */
498141261Sdelphij				if (uflag) {
499141261Sdelphij					if (udptest(s) == -1) {
500141261Sdelphij						ret = 1;
501141261Sdelphij						continue;
502141261Sdelphij					}
503141261Sdelphij				}
504141261Sdelphij
505141261Sdelphij				/* Don't look up port if -n. */
506141261Sdelphij				if (nflag)
507141261Sdelphij					sv = NULL;
508141261Sdelphij				else {
509141261Sdelphij					sv = getservbyport(
510141261Sdelphij					    ntohs(atoi(portlist[i])),
511141261Sdelphij					    uflag ? "udp" : "tcp");
512141261Sdelphij				}
513141261Sdelphij
514205561Sdelphij				fprintf(stderr,
515205561Sdelphij				    "Connection to %s %s port [%s/%s] "
516205561Sdelphij				    "succeeded!\n", host, portlist[i],
517205561Sdelphij				    uflag ? "udp" : "tcp",
518141261Sdelphij				    sv ? sv->s_name : "*");
519141261Sdelphij			}
520264911Sdelphij			if (Fflag)
521264911Sdelphij				fdpass(s);
522264911Sdelphij			else if (!zflag)
523141261Sdelphij				readwrite(s);
524141261Sdelphij		}
525141261Sdelphij	}
526141261Sdelphij
527141261Sdelphij	if (s)
528141261Sdelphij		close(s);
529141261Sdelphij
530141261Sdelphij	exit(ret);
531141261Sdelphij}
532141261Sdelphij
533141261Sdelphij/*
534221793Sdelphij * unix_bind()
535221793Sdelphij * Returns a unix socket bound to the given path
536141261Sdelphij */
537141261Sdelphijint
538221793Sdelphijunix_bind(char *path)
539141261Sdelphij{
540141261Sdelphij	struct sockaddr_un sun;
541141261Sdelphij	int s;
542141261Sdelphij
543221793Sdelphij	/* Create unix domain socket. */
544221793Sdelphij	if ((s = socket(AF_UNIX, uflag ? SOCK_DGRAM : SOCK_STREAM,
545221793Sdelphij	     0)) < 0)
546141261Sdelphij		return (-1);
547141261Sdelphij
548141261Sdelphij	memset(&sun, 0, sizeof(struct sockaddr_un));
549141261Sdelphij	sun.sun_family = AF_UNIX;
550141261Sdelphij
551141261Sdelphij	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
552141261Sdelphij	    sizeof(sun.sun_path)) {
553141261Sdelphij		close(s);
554141261Sdelphij		errno = ENAMETOOLONG;
555141261Sdelphij		return (-1);
556141261Sdelphij	}
557221793Sdelphij
558221793Sdelphij	if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
559141261Sdelphij		close(s);
560141261Sdelphij		return (-1);
561141261Sdelphij	}
562141261Sdelphij	return (s);
563141261Sdelphij}
564141261Sdelphij
565141261Sdelphij/*
566221793Sdelphij * unix_connect()
567221793Sdelphij * Returns a socket connected to a local unix socket. Returns -1 on failure.
568141261Sdelphij */
569141261Sdelphijint
570221793Sdelphijunix_connect(char *path)
571141261Sdelphij{
572141261Sdelphij	struct sockaddr_un sun;
573141261Sdelphij	int s;
574141261Sdelphij
575221793Sdelphij	if (uflag) {
576221793Sdelphij		if ((s = unix_bind(unix_dg_tmp_socket)) < 0)
577221793Sdelphij			return (-1);
578221793Sdelphij	} else {
579221793Sdelphij		if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
580221793Sdelphij			return (-1);
581221793Sdelphij	}
582264911Sdelphij	(void)fcntl(s, F_SETFD, FD_CLOEXEC);
583141261Sdelphij
584141261Sdelphij	memset(&sun, 0, sizeof(struct sockaddr_un));
585141261Sdelphij	sun.sun_family = AF_UNIX;
586141261Sdelphij
587141261Sdelphij	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
588141261Sdelphij	    sizeof(sun.sun_path)) {
589141261Sdelphij		close(s);
590141261Sdelphij		errno = ENAMETOOLONG;
591141261Sdelphij		return (-1);
592141261Sdelphij	}
593221793Sdelphij	if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
594141261Sdelphij		close(s);
595141261Sdelphij		return (-1);
596141261Sdelphij	}
597221793Sdelphij	return (s);
598141261Sdelphij
599221793Sdelphij}
600221793Sdelphij
601221793Sdelphij/*
602221793Sdelphij * unix_listen()
603221793Sdelphij * Create a unix domain socket, and listen on it.
604221793Sdelphij */
605221793Sdelphijint
606221793Sdelphijunix_listen(char *path)
607221793Sdelphij{
608221793Sdelphij	int s;
609221793Sdelphij	if ((s = unix_bind(path)) < 0)
610221793Sdelphij		return (-1);
611221793Sdelphij
612141261Sdelphij	if (listen(s, 5) < 0) {
613141261Sdelphij		close(s);
614141261Sdelphij		return (-1);
615141261Sdelphij	}
616141261Sdelphij	return (s);
617141261Sdelphij}
618141261Sdelphij
619141261Sdelphij/*
620141261Sdelphij * remote_connect()
621141261Sdelphij * Returns a socket connected to a remote host. Properly binds to a local
622141261Sdelphij * port or source address if needed. Returns -1 on failure.
623141261Sdelphij */
624141261Sdelphijint
625158798Sdelphijremote_connect(const char *host, const char *port, struct addrinfo hints)
626141261Sdelphij{
627141261Sdelphij	struct addrinfo *res, *res0;
628186343Sdelphij	int s, error, on = 1;
629141261Sdelphij
630141261Sdelphij	if ((error = getaddrinfo(host, port, &hints, &res)))
631141261Sdelphij		errx(1, "getaddrinfo: %s", gai_strerror(error));
632141261Sdelphij
633141261Sdelphij	res0 = res;
634141261Sdelphij	do {
635141261Sdelphij		if ((s = socket(res0->ai_family, res0->ai_socktype,
636141261Sdelphij		    res0->ai_protocol)) < 0)
637141261Sdelphij			continue;
638141394Sdelphij#ifdef IPSEC
639141394Sdelphij		if (ipsec_policy[0] != NULL)
640141394Sdelphij			add_ipsec_policy(s, ipsec_policy[0]);
641141394Sdelphij		if (ipsec_policy[1] != NULL)
642141394Sdelphij			add_ipsec_policy(s, ipsec_policy[1]);
643141394Sdelphij#endif
644141261Sdelphij
645264911Sdelphij		if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_SETFIB,
646264911Sdelphij		    &rtableid, sizeof(rtableid)) == -1))
647264911Sdelphij			err(1, "setsockopt SO_SETFIB");
648202640Sdelphij
649141261Sdelphij		/* Bind to a local port or source address if specified. */
650141261Sdelphij		if (sflag || pflag) {
651141261Sdelphij			struct addrinfo ahints, *ares;
652141261Sdelphij
653206689Sdelphij			/* try IP_BINDANY, but don't insist */
654206689Sdelphij			setsockopt(s, IPPROTO_IP, IP_BINDANY, &on, sizeof(on));
655141261Sdelphij			memset(&ahints, 0, sizeof(struct addrinfo));
656141261Sdelphij			ahints.ai_family = res0->ai_family;
657141261Sdelphij			ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
658141261Sdelphij			ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
659141261Sdelphij			ahints.ai_flags = AI_PASSIVE;
660141261Sdelphij			if ((error = getaddrinfo(sflag, pflag, &ahints, &ares)))
661141261Sdelphij				errx(1, "getaddrinfo: %s", gai_strerror(error));
662141261Sdelphij
663141261Sdelphij			if (bind(s, (struct sockaddr *)ares->ai_addr,
664141261Sdelphij			    ares->ai_addrlen) < 0)
665141261Sdelphij				errx(1, "bind failed: %s", strerror(errno));
666141261Sdelphij			freeaddrinfo(ares);
667141261Sdelphij		}
668141261Sdelphij
669158798Sdelphij		set_common_sockopts(s);
670158798Sdelphij
671235037Sdelphij		if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
672141261Sdelphij			break;
673141261Sdelphij		else if (vflag)
674141261Sdelphij			warn("connect to %s port %s (%s) failed", host, port,
675141261Sdelphij			    uflag ? "udp" : "tcp");
676141261Sdelphij
677141261Sdelphij		close(s);
678141261Sdelphij		s = -1;
679141261Sdelphij	} while ((res0 = res0->ai_next) != NULL);
680141261Sdelphij
681141261Sdelphij	freeaddrinfo(res);
682141261Sdelphij
683141261Sdelphij	return (s);
684141261Sdelphij}
685141261Sdelphij
686235037Sdelphijint
687235037Sdelphijtimeout_connect(int s, const struct sockaddr *name, socklen_t namelen)
688235037Sdelphij{
689235037Sdelphij	struct pollfd pfd;
690235037Sdelphij	socklen_t optlen;
691235037Sdelphij	int flags, optval;
692235037Sdelphij	int ret;
693235037Sdelphij
694235037Sdelphij	if (timeout != -1) {
695235037Sdelphij		flags = fcntl(s, F_GETFL, 0);
696235037Sdelphij		if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
697235037Sdelphij			err(1, "set non-blocking mode");
698235037Sdelphij	}
699235037Sdelphij
700235037Sdelphij	if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) {
701235037Sdelphij		pfd.fd = s;
702235037Sdelphij		pfd.events = POLLOUT;
703235037Sdelphij		if ((ret = poll(&pfd, 1, timeout)) == 1) {
704235037Sdelphij			optlen = sizeof(optval);
705235037Sdelphij			if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR,
706235037Sdelphij			    &optval, &optlen)) == 0) {
707235037Sdelphij				errno = optval;
708235037Sdelphij				ret = optval == 0 ? 0 : -1;
709235037Sdelphij			}
710235037Sdelphij		} else if (ret == 0) {
711235037Sdelphij			errno = ETIMEDOUT;
712235037Sdelphij			ret = -1;
713235037Sdelphij		} else
714235037Sdelphij			err(1, "poll failed");
715235037Sdelphij	}
716235037Sdelphij
717235037Sdelphij	if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1)
718235037Sdelphij		err(1, "restoring flags");
719235037Sdelphij
720235037Sdelphij	return (ret);
721235037Sdelphij}
722235037Sdelphij
723141261Sdelphij/*
724141261Sdelphij * local_listen()
725141261Sdelphij * Returns a socket listening on a local port, binds to specified source
726141261Sdelphij * address. Returns -1 on failure.
727141261Sdelphij */
728141261Sdelphijint
729141261Sdelphijlocal_listen(char *host, char *port, struct addrinfo hints)
730141261Sdelphij{
731141261Sdelphij	struct addrinfo *res, *res0;
732141261Sdelphij	int s, ret, x = 1;
733141261Sdelphij	int error;
734141261Sdelphij
735141261Sdelphij	/* Allow nodename to be null. */
736141261Sdelphij	hints.ai_flags |= AI_PASSIVE;
737141261Sdelphij
738141261Sdelphij	/*
739141261Sdelphij	 * In the case of binding to a wildcard address
740141261Sdelphij	 * default to binding to an ipv4 address.
741141261Sdelphij	 */
742141261Sdelphij	if (host == NULL && hints.ai_family == AF_UNSPEC)
743141261Sdelphij		hints.ai_family = AF_INET;
744141261Sdelphij
745141261Sdelphij	if ((error = getaddrinfo(host, port, &hints, &res)))
746141261Sdelphij		errx(1, "getaddrinfo: %s", gai_strerror(error));
747141261Sdelphij
748141261Sdelphij	res0 = res;
749141261Sdelphij	do {
750141261Sdelphij		if ((s = socket(res0->ai_family, res0->ai_socktype,
751158798Sdelphij		    res0->ai_protocol)) < 0)
752141261Sdelphij			continue;
753141261Sdelphij
754264911Sdelphij		if (rtableid >= 0 && (setsockopt(s, IPPROTO_IP, SO_SETFIB,
755264911Sdelphij		    &rtableid, sizeof(rtableid)) == -1))
756264911Sdelphij			err(1, "setsockopt SO_SETFIB");
757202640Sdelphij
758141261Sdelphij		ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));
759141261Sdelphij		if (ret == -1)
760141261Sdelphij			err(1, NULL);
761141394Sdelphij#ifdef IPSEC
762141394Sdelphij		if (ipsec_policy[0] != NULL)
763141394Sdelphij			add_ipsec_policy(s, ipsec_policy[0]);
764141394Sdelphij		if (ipsec_policy[1] != NULL)
765141394Sdelphij			add_ipsec_policy(s, ipsec_policy[1]);
766141394Sdelphij#endif
767186343Sdelphij		if (FreeBSD_Oflag) {
768177837Sbms			if (setsockopt(s, IPPROTO_TCP, TCP_NOOPT,
769186343Sdelphij			    &FreeBSD_Oflag, sizeof(FreeBSD_Oflag)) == -1)
770177837Sbms				err(1, "disable TCP options");
771177837Sbms		}
772141261Sdelphij
773141261Sdelphij		if (bind(s, (struct sockaddr *)res0->ai_addr,
774141261Sdelphij		    res0->ai_addrlen) == 0)
775141261Sdelphij			break;
776141261Sdelphij
777141261Sdelphij		close(s);
778141261Sdelphij		s = -1;
779141261Sdelphij	} while ((res0 = res0->ai_next) != NULL);
780141261Sdelphij
781141261Sdelphij	if (!uflag && s != -1) {
782141261Sdelphij		if (listen(s, 1) < 0)
783141261Sdelphij			err(1, "listen");
784141261Sdelphij	}
785141261Sdelphij
786141261Sdelphij	freeaddrinfo(res);
787141261Sdelphij
788141261Sdelphij	return (s);
789141261Sdelphij}
790141261Sdelphij
791141261Sdelphij/*
792141261Sdelphij * readwrite()
793141261Sdelphij * Loop that polls on the network file descriptor and stdin.
794141261Sdelphij */
795141261Sdelphijvoid
796141261Sdelphijreadwrite(int nfd)
797141261Sdelphij{
798141261Sdelphij	struct pollfd pfd[2];
799214047Sdelphij	unsigned char buf[16384];
800158798Sdelphij	int n, wfd = fileno(stdin);
801141261Sdelphij	int lfd = fileno(stdout);
802158798Sdelphij	int plen;
803141261Sdelphij
804241906Sdelphij	plen = 2048;
805158798Sdelphij
806141261Sdelphij	/* Setup Network FD */
807141261Sdelphij	pfd[0].fd = nfd;
808141261Sdelphij	pfd[0].events = POLLIN;
809141261Sdelphij
810141261Sdelphij	/* Set up STDIN FD. */
811141261Sdelphij	pfd[1].fd = wfd;
812141261Sdelphij	pfd[1].events = POLLIN;
813141261Sdelphij
814141261Sdelphij	while (pfd[0].fd != -1) {
815141261Sdelphij		if (iflag)
816141261Sdelphij			sleep(iflag);
817141261Sdelphij
818141261Sdelphij		if ((n = poll(pfd, 2 - dflag, timeout)) < 0) {
819141261Sdelphij			close(nfd);
820141261Sdelphij			err(1, "Polling Error");
821141261Sdelphij		}
822141261Sdelphij
823141261Sdelphij		if (n == 0)
824141261Sdelphij			return;
825141261Sdelphij
826141261Sdelphij		if (pfd[0].revents & POLLIN) {
827158798Sdelphij			if ((n = read(nfd, buf, plen)) < 0)
828141261Sdelphij				return;
829141261Sdelphij			else if (n == 0) {
830141261Sdelphij				shutdown(nfd, SHUT_RD);
831141261Sdelphij				pfd[0].fd = -1;
832141261Sdelphij				pfd[0].events = 0;
833141261Sdelphij			} else {
834141261Sdelphij				if (tflag)
835141261Sdelphij					atelnet(nfd, buf, n);
836158798Sdelphij				if (atomicio(vwrite, lfd, buf, n) != n)
837141261Sdelphij					return;
838141261Sdelphij			}
839141261Sdelphij		}
840141261Sdelphij
841141261Sdelphij		if (!dflag && pfd[1].revents & POLLIN) {
842206675Sdelphij			if ((n = read(wfd, buf, plen)) < 0)
843141261Sdelphij				return;
844206675Sdelphij			else if (n == 0) {
845249499Sdelphij				if (Nflag)
846249499Sdelphij					shutdown(nfd, SHUT_WR);
847141261Sdelphij				pfd[1].fd = -1;
848141261Sdelphij				pfd[1].events = 0;
849141261Sdelphij			} else {
850158798Sdelphij				if (atomicio(vwrite, nfd, buf, n) != n)
851141261Sdelphij					return;
852141261Sdelphij			}
853141261Sdelphij		}
854141261Sdelphij	}
855141261Sdelphij}
856141261Sdelphij
857264911Sdelphij/*
858264911Sdelphij * fdpass()
859264911Sdelphij * Pass the connected file descriptor to stdout and exit.
860264911Sdelphij */
861264911Sdelphijvoid
862264911Sdelphijfdpass(int nfd)
863264911Sdelphij{
864264911Sdelphij	struct msghdr mh;
865264911Sdelphij	union {
866264911Sdelphij		struct cmsghdr hdr;
867264911Sdelphij		char buf[CMSG_SPACE(sizeof(int))];
868264911Sdelphij	} cmsgbuf;
869264911Sdelphij	struct cmsghdr *cmsg;
870264911Sdelphij	struct iovec iov;
871264911Sdelphij	char c = '\0';
872264911Sdelphij	ssize_t r;
873264911Sdelphij	struct pollfd pfd;
874264911Sdelphij
875264911Sdelphij	/* Avoid obvious stupidity */
876264911Sdelphij	if (isatty(STDOUT_FILENO))
877264911Sdelphij		errx(1, "Cannot pass file descriptor to tty");
878264911Sdelphij
879264911Sdelphij	bzero(&mh, sizeof(mh));
880264911Sdelphij	bzero(&cmsgbuf, sizeof(cmsgbuf));
881264911Sdelphij	bzero(&iov, sizeof(iov));
882264911Sdelphij	bzero(&pfd, sizeof(pfd));
883264911Sdelphij
884264911Sdelphij	mh.msg_control = (caddr_t)&cmsgbuf.buf;
885264911Sdelphij	mh.msg_controllen = sizeof(cmsgbuf.buf);
886264911Sdelphij	cmsg = CMSG_FIRSTHDR(&mh);
887264911Sdelphij	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
888264911Sdelphij	cmsg->cmsg_level = SOL_SOCKET;
889264911Sdelphij	cmsg->cmsg_type = SCM_RIGHTS;
890264911Sdelphij	*(int *)CMSG_DATA(cmsg) = nfd;
891264911Sdelphij
892264911Sdelphij	iov.iov_base = &c;
893264911Sdelphij	iov.iov_len = 1;
894264911Sdelphij	mh.msg_iov = &iov;
895264911Sdelphij	mh.msg_iovlen = 1;
896264911Sdelphij
897264911Sdelphij	bzero(&pfd, sizeof(pfd));
898264911Sdelphij	pfd.fd = STDOUT_FILENO;
899264911Sdelphij	for (;;) {
900264911Sdelphij		r = sendmsg(STDOUT_FILENO, &mh, 0);
901264911Sdelphij		if (r == -1) {
902264911Sdelphij			if (errno == EAGAIN || errno == EINTR) {
903264911Sdelphij				pfd.events = POLLOUT;
904264911Sdelphij				if (poll(&pfd, 1, -1) == -1)
905264911Sdelphij					err(1, "poll");
906264911Sdelphij				continue;
907264911Sdelphij			}
908264911Sdelphij			err(1, "sendmsg");
909264911Sdelphij		} else if (r == -1)
910264911Sdelphij			errx(1, "sendmsg: unexpected return value %zd", r);
911264911Sdelphij		else
912264911Sdelphij			break;
913264911Sdelphij	}
914264911Sdelphij	exit(0);
915264911Sdelphij}
916264911Sdelphij
917141261Sdelphij/* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */
918141261Sdelphijvoid
919141261Sdelphijatelnet(int nfd, unsigned char *buf, unsigned int size)
920141261Sdelphij{
921141261Sdelphij	unsigned char *p, *end;
922141261Sdelphij	unsigned char obuf[4];
923141261Sdelphij
924205561Sdelphij	if (size < 3)
925205561Sdelphij		return;
926205561Sdelphij	end = buf + size - 2;
927141261Sdelphij
928141261Sdelphij	for (p = buf; p < end; p++) {
929141261Sdelphij		if (*p != IAC)
930205561Sdelphij			continue;
931141261Sdelphij
932141261Sdelphij		obuf[0] = IAC;
933141261Sdelphij		p++;
934141261Sdelphij		if ((*p == WILL) || (*p == WONT))
935141261Sdelphij			obuf[1] = DONT;
936205561Sdelphij		else if ((*p == DO) || (*p == DONT))
937141261Sdelphij			obuf[1] = WONT;
938205561Sdelphij		else
939205561Sdelphij			continue;
940205561Sdelphij
941205561Sdelphij		p++;
942205561Sdelphij		obuf[2] = *p;
943205561Sdelphij		if (atomicio(vwrite, nfd, obuf, 3) != 3)
944205561Sdelphij			warn("Write Error!");
945141261Sdelphij	}
946141261Sdelphij}
947141261Sdelphij
948141261Sdelphij/*
949141261Sdelphij * build_ports()
950235037Sdelphij * Build an array of ports in portlist[], listing each port
951141261Sdelphij * that we should try to connect to.
952141261Sdelphij */
953141261Sdelphijvoid
954141261Sdelphijbuild_ports(char *p)
955141261Sdelphij{
956167964Sdelphij	const char *errstr;
957167964Sdelphij	char *n;
958141261Sdelphij	int hi, lo, cp;
959141261Sdelphij	int x = 0;
960141261Sdelphij
961141261Sdelphij	if ((n = strchr(p, '-')) != NULL) {
962141261Sdelphij		*n = '\0';
963141261Sdelphij		n++;
964141261Sdelphij
965141261Sdelphij		/* Make sure the ports are in order: lowest->highest. */
966167964Sdelphij		hi = strtonum(n, 1, PORT_MAX, &errstr);
967167964Sdelphij		if (errstr)
968167964Sdelphij			errx(1, "port number %s: %s", errstr, n);
969167964Sdelphij		lo = strtonum(p, 1, PORT_MAX, &errstr);
970167964Sdelphij		if (errstr)
971167964Sdelphij			errx(1, "port number %s: %s", errstr, p);
972141261Sdelphij
973141261Sdelphij		if (lo > hi) {
974141261Sdelphij			cp = hi;
975141261Sdelphij			hi = lo;
976141261Sdelphij			lo = cp;
977141261Sdelphij		}
978141261Sdelphij
979141261Sdelphij		/* Load ports sequentially. */
980141261Sdelphij		for (cp = lo; cp <= hi; cp++) {
981141261Sdelphij			portlist[x] = calloc(1, PORT_MAX_LEN);
982141261Sdelphij			if (portlist[x] == NULL)
983141261Sdelphij				err(1, NULL);
984141261Sdelphij			snprintf(portlist[x], PORT_MAX_LEN, "%d", cp);
985141261Sdelphij			x++;
986141261Sdelphij		}
987141261Sdelphij
988141261Sdelphij		/* Randomly swap ports. */
989141261Sdelphij		if (rflag) {
990141261Sdelphij			int y;
991141261Sdelphij			char *c;
992141261Sdelphij
993141261Sdelphij			for (x = 0; x <= (hi - lo); x++) {
994141261Sdelphij				y = (arc4random() & 0xFFFF) % (hi - lo);
995141261Sdelphij				c = portlist[x];
996141261Sdelphij				portlist[x] = portlist[y];
997141261Sdelphij				portlist[y] = c;
998141261Sdelphij			}
999141261Sdelphij		}
1000141261Sdelphij	} else {
1001167964Sdelphij		hi = strtonum(p, 1, PORT_MAX, &errstr);
1002167964Sdelphij		if (errstr)
1003167964Sdelphij			errx(1, "port number %s: %s", errstr, p);
1004214047Sdelphij		portlist[0] = strdup(p);
1005141261Sdelphij		if (portlist[0] == NULL)
1006141261Sdelphij			err(1, NULL);
1007141261Sdelphij	}
1008141261Sdelphij}
1009141261Sdelphij
1010141261Sdelphij/*
1011141261Sdelphij * udptest()
1012141261Sdelphij * Do a few writes to see if the UDP port is there.
1013235037Sdelphij * Fails once PF state table is full.
1014141261Sdelphij */
1015141261Sdelphijint
1016141261Sdelphijudptest(int s)
1017141261Sdelphij{
1018141261Sdelphij	int i, ret;
1019141261Sdelphij
1020141261Sdelphij	for (i = 0; i <= 3; i++) {
1021141261Sdelphij		if (write(s, "X", 1) == 1)
1022141261Sdelphij			ret = 1;
1023141261Sdelphij		else
1024141261Sdelphij			ret = -1;
1025141261Sdelphij	}
1026141261Sdelphij	return (ret);
1027141261Sdelphij}
1028141261Sdelphij
1029141261Sdelphijvoid
1030158798Sdelphijset_common_sockopts(int s)
1031158798Sdelphij{
1032158798Sdelphij	int x = 1;
1033158798Sdelphij
1034158798Sdelphij	if (Sflag) {
1035158798Sdelphij		if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG,
1036158798Sdelphij			&x, sizeof(x)) == -1)
1037158798Sdelphij			err(1, NULL);
1038158798Sdelphij	}
1039158798Sdelphij	if (Dflag) {
1040158798Sdelphij		if (setsockopt(s, SOL_SOCKET, SO_DEBUG,
1041158798Sdelphij			&x, sizeof(x)) == -1)
1042158798Sdelphij			err(1, NULL);
1043158798Sdelphij	}
1044158798Sdelphij	if (Tflag != -1) {
1045158798Sdelphij		if (setsockopt(s, IPPROTO_IP, IP_TOS,
1046158798Sdelphij		    &Tflag, sizeof(Tflag)) == -1)
1047158798Sdelphij			err(1, "set IP ToS");
1048158798Sdelphij	}
1049186343Sdelphij	if (Iflag) {
1050186343Sdelphij		if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
1051186343Sdelphij		    &Iflag, sizeof(Iflag)) == -1)
1052186343Sdelphij			err(1, "set TCP receive buffer size");
1053186343Sdelphij	}
1054177837Sbms	if (Oflag) {
1055186343Sdelphij		if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
1056186343Sdelphij		    &Oflag, sizeof(Oflag)) == -1)
1057186343Sdelphij			err(1, "set TCP send buffer size");
1058186343Sdelphij	}
1059186343Sdelphij	if (FreeBSD_Oflag) {
1060177837Sbms		if (setsockopt(s, IPPROTO_TCP, TCP_NOOPT,
1061186343Sdelphij		    &FreeBSD_Oflag, sizeof(FreeBSD_Oflag)) == -1)
1062177837Sbms			err(1, "disable TCP options");
1063177837Sbms	}
1064158798Sdelphij}
1065158798Sdelphij
1066158798Sdelphijint
1067235037Sdelphijmap_tos(char *s, int *val)
1068158798Sdelphij{
1069235037Sdelphij	/* DiffServ Codepoints and other TOS mappings */
1070235037Sdelphij	const struct toskeywords {
1071235037Sdelphij		const char	*keyword;
1072235037Sdelphij		int		 val;
1073235037Sdelphij	} *t, toskeywords[] = {
1074235037Sdelphij		{ "af11",		IPTOS_DSCP_AF11 },
1075235037Sdelphij		{ "af12",		IPTOS_DSCP_AF12 },
1076235037Sdelphij		{ "af13",		IPTOS_DSCP_AF13 },
1077235037Sdelphij		{ "af21",		IPTOS_DSCP_AF21 },
1078235037Sdelphij		{ "af22",		IPTOS_DSCP_AF22 },
1079235037Sdelphij		{ "af23",		IPTOS_DSCP_AF23 },
1080235037Sdelphij		{ "af31",		IPTOS_DSCP_AF31 },
1081235037Sdelphij		{ "af32",		IPTOS_DSCP_AF32 },
1082235037Sdelphij		{ "af33",		IPTOS_DSCP_AF33 },
1083235037Sdelphij		{ "af41",		IPTOS_DSCP_AF41 },
1084235037Sdelphij		{ "af42",		IPTOS_DSCP_AF42 },
1085235037Sdelphij		{ "af43",		IPTOS_DSCP_AF43 },
1086235037Sdelphij		{ "critical",		IPTOS_PREC_CRITIC_ECP },
1087235037Sdelphij		{ "cs0",		IPTOS_DSCP_CS0 },
1088235037Sdelphij		{ "cs1",		IPTOS_DSCP_CS1 },
1089235037Sdelphij		{ "cs2",		IPTOS_DSCP_CS2 },
1090235037Sdelphij		{ "cs3",		IPTOS_DSCP_CS3 },
1091235037Sdelphij		{ "cs4",		IPTOS_DSCP_CS4 },
1092235037Sdelphij		{ "cs5",		IPTOS_DSCP_CS5 },
1093235037Sdelphij		{ "cs6",		IPTOS_DSCP_CS6 },
1094235037Sdelphij		{ "cs7",		IPTOS_DSCP_CS7 },
1095235037Sdelphij		{ "ef",			IPTOS_DSCP_EF },
1096235037Sdelphij		{ "inetcontrol",	IPTOS_PREC_INTERNETCONTROL },
1097235037Sdelphij		{ "lowdelay",		IPTOS_LOWDELAY },
1098235037Sdelphij		{ "netcontrol",		IPTOS_PREC_NETCONTROL },
1099235037Sdelphij		{ "reliability",	IPTOS_RELIABILITY },
1100235037Sdelphij		{ "throughput",		IPTOS_THROUGHPUT },
1101235037Sdelphij		{ NULL, 		-1 },
1102235037Sdelphij	};
1103158798Sdelphij
1104235037Sdelphij	for (t = toskeywords; t->keyword != NULL; t++) {
1105235037Sdelphij		if (strcmp(s, t->keyword) == 0) {
1106235037Sdelphij			*val = t->val;
1107235037Sdelphij			return (1);
1108235037Sdelphij		}
1109235037Sdelphij	}
1110158798Sdelphij
1111235037Sdelphij	return (0);
1112158798Sdelphij}
1113158798Sdelphij
1114158798Sdelphijvoid
1115241906Sdelphijreport_connect(const struct sockaddr *sa, socklen_t salen)
1116241906Sdelphij{
1117241906Sdelphij	char remote_host[NI_MAXHOST];
1118241906Sdelphij	char remote_port[NI_MAXSERV];
1119241906Sdelphij	int herr;
1120241906Sdelphij	int flags = NI_NUMERICSERV;
1121241906Sdelphij
1122241906Sdelphij	if (nflag)
1123241906Sdelphij		flags |= NI_NUMERICHOST;
1124241906Sdelphij
1125241906Sdelphij	if ((herr = getnameinfo(sa, salen,
1126241906Sdelphij	    remote_host, sizeof(remote_host),
1127241906Sdelphij	    remote_port, sizeof(remote_port),
1128241906Sdelphij	    flags)) != 0) {
1129241906Sdelphij		if (herr == EAI_SYSTEM)
1130241906Sdelphij			err(1, "getnameinfo");
1131241906Sdelphij		else
1132241906Sdelphij			errx(1, "getnameinfo: %s", gai_strerror(herr));
1133241906Sdelphij	}
1134241906Sdelphij
1135241906Sdelphij	fprintf(stderr,
1136241906Sdelphij	    "Connection from %s %s "
1137241906Sdelphij	    "received!\n", remote_host, remote_port);
1138241906Sdelphij}
1139241906Sdelphij
1140241906Sdelphijvoid
1141141261Sdelphijhelp(void)
1142141261Sdelphij{
1143141261Sdelphij	usage(0);
1144141261Sdelphij	fprintf(stderr, "\tCommand Summary:\n\
1145141261Sdelphij	\t-4		Use IPv4\n\
1146178927Santoine	\t-6		Use IPv6\n\
1147178927Santoine	\t-D		Enable the debug socket option\n\
1148178927Santoine	\t-d		Detach from stdin\n");
1149141394Sdelphij#ifdef IPSEC
1150141394Sdelphij	fprintf(stderr, "\
1151178927Santoine	\t-E		Use IPsec ESP\n\
1152178927Santoine	\t-e policy	Use specified IPsec policy\n");
1153141394Sdelphij#endif
1154141394Sdelphij	fprintf(stderr, "\
1155264911Sdelphij	\t-F		Pass socket fd\n\
1156141261Sdelphij	\t-h		This help text\n\
1157186343Sdelphij	\t-I length	TCP receive buffer length\n\
1158141261Sdelphij	\t-i secs\t	Delay interval for lines sent, ports scanned\n\
1159141261Sdelphij	\t-k		Keep inbound sockets open for multiple connects\n\
1160141261Sdelphij	\t-l		Listen mode, for inbound connects\n\
1161249499Sdelphij	\t-N		Shutdown the network socket after EOF on stdin\n\
1162141261Sdelphij	\t-n		Suppress name/port resolutions\n\
1163186343Sdelphij	\t--no-tcpopt	Disable TCP options\n\
1164186343Sdelphij	\t-O length	TCP send buffer length\n\
1165158798Sdelphij	\t-P proxyuser\tUsername for proxy authentication\n\
1166141261Sdelphij	\t-p port\t	Specify local port for remote connects\n\
1167141261Sdelphij	\t-r		Randomize remote ports\n\
1168141261Sdelphij	\t-S		Enable the TCP MD5 signature option\n\
1169141261Sdelphij	\t-s addr\t	Local source address\n\
1170235037Sdelphij	\t-T toskeyword\tSet IP Type of Service\n\
1171141261Sdelphij	\t-t		Answer TELNET negotiation\n\
1172141261Sdelphij	\t-U		Use UNIX domain socket\n\
1173141261Sdelphij	\t-u		UDP mode\n\
1174214047Sdelphij	\t-V rtable	Specify alternate routing table\n\
1175141261Sdelphij	\t-v		Verbose\n\
1176141261Sdelphij	\t-w secs\t	Timeout for connects and final net reads\n\
1177141261Sdelphij	\t-X proto	Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\
1178141261Sdelphij	\t-x addr[:port]\tSpecify proxy address and port\n\
1179141261Sdelphij	\t-z		Zero-I/O mode [used for scanning]\n\
1180141261Sdelphij	Port numbers can be individual or ranges: lo-hi [inclusive]\n");
1181141394Sdelphij#ifdef IPSEC
1182141394Sdelphij	fprintf(stderr, "See ipsec_set_policy(3) for -e argument format\n");
1183141394Sdelphij#endif
1184141261Sdelphij	exit(1);
1185141261Sdelphij}
1186141261Sdelphij
1187141394Sdelphij#ifdef IPSEC
1188141261Sdelphijvoid
1189141394Sdelphijadd_ipsec_policy(int s, char *policy)
1190141394Sdelphij{
1191141394Sdelphij	char *raw;
1192141394Sdelphij	int e;
1193141394Sdelphij
1194141394Sdelphij	raw = ipsec_set_policy(policy, strlen(policy));
1195141394Sdelphij	if (raw == NULL)
1196141394Sdelphij		errx(1, "ipsec_set_policy `%s': %s", policy,
1197141394Sdelphij		     ipsec_strerror());
1198141394Sdelphij	e = setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, raw,
1199141394Sdelphij			ipsec_get_policylen(raw));
1200141394Sdelphij	if (e < 0)
1201141394Sdelphij		err(1, "ipsec policy cannot be configured");
1202141394Sdelphij	free(raw);
1203141394Sdelphij	if (vflag)
1204141394Sdelphij		fprintf(stderr, "ipsec policy configured: `%s'\n", policy);
1205141394Sdelphij	return;
1206141394Sdelphij}
1207141394Sdelphij#endif /* IPSEC */
1208141394Sdelphij
1209141394Sdelphijvoid
1210141261Sdelphijusage(int ret)
1211141261Sdelphij{
1212193008Sdelphij	fprintf(stderr,
1213141394Sdelphij#ifdef IPSEC
1214264911Sdelphij	    "usage: nc [-46DdEFhklNnrStUuvz] [-e policy] [-I length] [-i interval] [-O length]\n"
1215141394Sdelphij#else
1216264911Sdelphij	    "usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n"
1217141394Sdelphij#endif
1218221793Sdelphij	    "\t  [-P proxy_username] [-p source_port] [-s source] [-T ToS]\n"
1219214047Sdelphij	    "\t  [-V rtable] [-w timeout] [-X proxy_protocol]\n"
1220221793Sdelphij	    "\t  [-x proxy_address[:port]] [destination] [port]\n");
1221141261Sdelphij	if (ret)
1222141261Sdelphij		exit(1);
1223141261Sdelphij}
1224