1285031Sdes/* $OpenBSD: netcat.c,v 1.126 2014/10/30 16:08:31 tedu Exp $ */
2285031Sdes/*
3285031Sdes * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
4285031Sdes *
5285031Sdes * Redistribution and use in source and binary forms, with or without
6285031Sdes * modification, are permitted provided that the following conditions
7285031Sdes * are met:
8285031Sdes *
9285031Sdes * 1. Redistributions of source code must retain the above copyright
10285031Sdes *   notice, this list of conditions and the following disclaimer.
11285031Sdes * 2. Redistributions in binary form must reproduce the above copyright
12285031Sdes *   notice, this list of conditions and the following disclaimer in the
13285031Sdes *   documentation and/or other materials provided with the distribution.
14285031Sdes * 3. The name of the author may not be used to endorse or promote products
15285031Sdes *   derived from this software without specific prior written permission.
16285031Sdes *
17285031Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18285031Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19285031Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20285031Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21285031Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22285031Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23285031Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24285031Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25285031Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26285031Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27285031Sdes */
28285031Sdes
29285031Sdes/*
30285031Sdes * Re-written nc(1) for OpenBSD. Original implementation by
31285031Sdes * *Hobbit* <hobbit@avian.org>.
32285031Sdes */
33285031Sdes
34285031Sdes#include "includes.h"
35285031Sdes
36285031Sdes#include <sys/types.h>
37285031Sdes#include <sys/socket.h>
38285031Sdes#include <sys/time.h>
39285031Sdes#include <sys/uio.h>
40285031Sdes#include <sys/un.h>
41285031Sdes
42285031Sdes#include <netinet/in.h>
43285031Sdes#include <netinet/tcp.h>
44285031Sdes#include <netinet/ip.h>
45285031Sdes
46285031Sdes#include <errno.h>
47285031Sdes#include <netdb.h>
48285031Sdes#include <stdarg.h>
49285031Sdes#include <stdio.h>
50285031Sdes#include <stdlib.h>
51285031Sdes#include <string.h>
52285031Sdes#include <unistd.h>
53285031Sdes#include <fcntl.h>
54285031Sdes#include <limits.h>
55285031Sdes#include "atomicio.h"
56285031Sdes
57285031Sdes#ifdef HAVE_POLL_H
58285031Sdes#include <poll.h>
59285031Sdes#else
60285031Sdes# ifdef HAVE_SYS_POLL_H
61285031Sdes#  include <sys/poll.h>
62285031Sdes# endif
63285031Sdes#endif
64323124Sdes#ifdef HAVE_ERR_H
65323124Sdes# include <err.h>
66323124Sdes#endif
67285031Sdes
68295367Sdes/* Telnet options from arpa/telnet.h */
69295367Sdes#define IAC	255
70295367Sdes#define DONT	254
71295367Sdes#define DO	253
72295367Sdes#define WONT	252
73295367Sdes#define WILL	251
74295367Sdes
75285031Sdes#ifndef SUN_LEN
76285031Sdes#define SUN_LEN(su) \
77285031Sdes	(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
78285031Sdes#endif
79285031Sdes
80285031Sdes#define PORT_MAX	65535
81285031Sdes#define PORT_MAX_LEN	6
82285031Sdes#define UNIX_DG_TMP_SOCKET_SIZE	19
83285031Sdes
84285031Sdes#define POLL_STDIN 0
85285031Sdes#define POLL_NETOUT 1
86285031Sdes#define POLL_NETIN 2
87285031Sdes#define POLL_STDOUT 3
88285031Sdes#define BUFSIZE 16384
89285031Sdes
90285031Sdes/* Command Line Options */
91285031Sdesint	dflag;					/* detached, no stdin */
92285031Sdesint	Fflag;					/* fdpass sock to stdout */
93285031Sdesunsigned int iflag;				/* Interval Flag */
94285031Sdesint	kflag;					/* More than one connect */
95285031Sdesint	lflag;					/* Bind to local port */
96285031Sdesint	Nflag;					/* shutdown() network socket */
97285031Sdesint	nflag;					/* Don't do name look up */
98285031Sdeschar   *Pflag;					/* Proxy username */
99285031Sdeschar   *pflag;					/* Localport flag */
100285031Sdesint	rflag;					/* Random ports flag */
101285031Sdeschar   *sflag;					/* Source Address */
102285031Sdesint	tflag;					/* Telnet Emulation */
103285031Sdesint	uflag;					/* UDP - Default to TCP */
104285031Sdesint	vflag;					/* Verbosity */
105285031Sdesint	xflag;					/* Socks proxy */
106285031Sdesint	zflag;					/* Port Scan Flag */
107285031Sdesint	Dflag;					/* sodebug */
108285031Sdesint	Iflag;					/* TCP receive buffer size */
109285031Sdesint	Oflag;					/* TCP send buffer size */
110285031Sdesint	Sflag;					/* TCP MD5 signature option */
111285031Sdesint	Tflag = -1;				/* IP Type of Service */
112285031Sdesint	rtableid = -1;
113285031Sdes
114285031Sdesint timeout = -1;
115285031Sdesint family = AF_UNSPEC;
116285031Sdeschar *portlist[PORT_MAX+1];
117285031Sdeschar *unix_dg_tmp_socket;
118285031Sdes
119285031Sdesvoid	atelnet(int, unsigned char *, unsigned int);
120285031Sdesvoid	build_ports(char *);
121285031Sdesvoid	help(void);
122285031Sdesint	local_listen(char *, char *, struct addrinfo);
123285031Sdesvoid	readwrite(int);
124285031Sdesvoid	fdpass(int nfd) __attribute__((noreturn));
125285031Sdesint	remote_connect(const char *, const char *, struct addrinfo);
126285031Sdesint	timeout_connect(int, const struct sockaddr *, socklen_t);
127285031Sdesint	socks_connect(const char *, const char *, struct addrinfo,
128285031Sdes	    const char *, const char *, struct addrinfo, int, const char *);
129285031Sdesint	udptest(int);
130285031Sdesint	unix_bind(char *);
131285031Sdesint	unix_connect(char *);
132285031Sdesint	unix_listen(char *);
133285031Sdesvoid	set_common_sockopts(int);
134285031Sdesint	map_tos(char *, int *);
135285031Sdesvoid	report_connect(const struct sockaddr *, socklen_t);
136285031Sdesvoid	usage(int);
137285031Sdesssize_t drainbuf(int, unsigned char *, size_t *);
138285031Sdesssize_t fillbuf(int, unsigned char *, size_t *);
139285031Sdes
140285031Sdes
141285031Sdesint
142285031Sdesmain(int argc, char *argv[])
143285031Sdes{
144285031Sdes	int ch, s, ret, socksv;
145285031Sdes	char *host, *uport;
146285031Sdes	struct addrinfo hints;
147285031Sdes	struct servent *sv;
148285031Sdes	socklen_t len;
149285031Sdes	struct sockaddr_storage cliaddr;
150285031Sdes	char *proxy = NULL;
151285031Sdes	const char *errstr, *proxyhost = "", *proxyport = NULL;
152285031Sdes	struct addrinfo proxyhints;
153285031Sdes	char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE];
154285031Sdes
155285031Sdes	ret = 1;
156285031Sdes	s = 0;
157285031Sdes	socksv = 5;
158285031Sdes	host = NULL;
159285031Sdes	uport = NULL;
160285031Sdes	sv = NULL;
161285031Sdes
162285031Sdes	while ((ch = getopt(argc, argv,
163285031Sdes	    "46DdFhI:i:klNnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) {
164285031Sdes		switch (ch) {
165285031Sdes		case '4':
166285031Sdes			family = AF_INET;
167285031Sdes			break;
168285031Sdes		case '6':
169285031Sdes			family = AF_INET6;
170285031Sdes			break;
171285031Sdes		case 'U':
172285031Sdes			family = AF_UNIX;
173285031Sdes			break;
174285031Sdes		case 'X':
175285031Sdes			if (strcasecmp(optarg, "connect") == 0)
176285031Sdes				socksv = -1; /* HTTP proxy CONNECT */
177285031Sdes			else if (strcmp(optarg, "4") == 0)
178285031Sdes				socksv = 4; /* SOCKS v.4 */
179285031Sdes			else if (strcmp(optarg, "5") == 0)
180285031Sdes				socksv = 5; /* SOCKS v.5 */
181285031Sdes			else
182285031Sdes				errx(1, "unsupported proxy protocol");
183285031Sdes			break;
184285031Sdes		case 'd':
185285031Sdes			dflag = 1;
186285031Sdes			break;
187285031Sdes		case 'F':
188285031Sdes			Fflag = 1;
189285031Sdes			break;
190285031Sdes		case 'h':
191285031Sdes			help();
192285031Sdes			break;
193285031Sdes		case 'i':
194285031Sdes			iflag = strtonum(optarg, 0, UINT_MAX, &errstr);
195285031Sdes			if (errstr)
196285031Sdes				errx(1, "interval %s: %s", errstr, optarg);
197285031Sdes			break;
198285031Sdes		case 'k':
199285031Sdes			kflag = 1;
200285031Sdes			break;
201285031Sdes		case 'l':
202285031Sdes			lflag = 1;
203285031Sdes			break;
204285031Sdes		case 'N':
205285031Sdes			Nflag = 1;
206285031Sdes			break;
207285031Sdes		case 'n':
208285031Sdes			nflag = 1;
209285031Sdes			break;
210285031Sdes		case 'P':
211285031Sdes			Pflag = optarg;
212285031Sdes			break;
213285031Sdes		case 'p':
214285031Sdes			pflag = optarg;
215285031Sdes			break;
216285031Sdes		case 'r':
217285031Sdes			rflag = 1;
218285031Sdes			break;
219285031Sdes		case 's':
220285031Sdes			sflag = optarg;
221285031Sdes			break;
222285031Sdes		case 't':
223285031Sdes			tflag = 1;
224285031Sdes			break;
225285031Sdes		case 'u':
226285031Sdes			uflag = 1;
227285031Sdes			break;
228285031Sdes#ifdef SO_RTABLE
229285031Sdes		case 'V':
230285031Sdes			rtableid = (int)strtonum(optarg, 0,
231285031Sdes			    RT_TABLEID_MAX, &errstr);
232285031Sdes			if (errstr)
233285031Sdes				errx(1, "rtable %s: %s", errstr, optarg);
234285031Sdes			break;
235285031Sdes#endif
236285031Sdes		case 'v':
237285031Sdes			vflag = 1;
238285031Sdes			break;
239285031Sdes		case 'w':
240285031Sdes			timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr);
241285031Sdes			if (errstr)
242285031Sdes				errx(1, "timeout %s: %s", errstr, optarg);
243285031Sdes			timeout *= 1000;
244285031Sdes			break;
245285031Sdes		case 'x':
246285031Sdes			xflag = 1;
247285031Sdes			if ((proxy = strdup(optarg)) == NULL)
248285031Sdes				errx(1, "strdup");
249285031Sdes			break;
250285031Sdes		case 'z':
251285031Sdes			zflag = 1;
252285031Sdes			break;
253285031Sdes		case 'D':
254285031Sdes			Dflag = 1;
255285031Sdes			break;
256285031Sdes		case 'I':
257285031Sdes			Iflag = strtonum(optarg, 1, 65536 << 14, &errstr);
258285031Sdes			if (errstr != NULL)
259285031Sdes				errx(1, "TCP receive window %s: %s",
260285031Sdes				    errstr, optarg);
261285031Sdes			break;
262285031Sdes		case 'O':
263285031Sdes			Oflag = strtonum(optarg, 1, 65536 << 14, &errstr);
264285031Sdes			if (errstr != NULL)
265285031Sdes				errx(1, "TCP send window %s: %s",
266285031Sdes				    errstr, optarg);
267285031Sdes			break;
268285031Sdes		case 'S':
269285031Sdes			Sflag = 1;
270285031Sdes			break;
271285031Sdes		case 'T':
272285031Sdes			errstr = NULL;
273285031Sdes			errno = 0;
274285031Sdes			if (map_tos(optarg, &Tflag))
275285031Sdes				break;
276285031Sdes			if (strlen(optarg) > 1 && optarg[0] == '0' &&
277285031Sdes			    optarg[1] == 'x')
278285031Sdes				Tflag = (int)strtol(optarg, NULL, 16);
279285031Sdes			else
280285031Sdes				Tflag = (int)strtonum(optarg, 0, 255,
281285031Sdes				    &errstr);
282285031Sdes			if (Tflag < 0 || Tflag > 255 || errstr || errno)
283285031Sdes				errx(1, "illegal tos value %s", optarg);
284285031Sdes			break;
285285031Sdes		default:
286285031Sdes			usage(1);
287285031Sdes		}
288285031Sdes	}
289285031Sdes	argc -= optind;
290285031Sdes	argv += optind;
291285031Sdes
292285031Sdes	/* Cruft to make sure options are clean, and used properly. */
293285031Sdes	if (argv[0] && !argv[1] && family == AF_UNIX) {
294285031Sdes		host = argv[0];
295285031Sdes		uport = NULL;
296285031Sdes	} else if (argv[0] && !argv[1]) {
297285031Sdes		if  (!lflag)
298285031Sdes			usage(1);
299285031Sdes		uport = argv[0];
300285031Sdes		host = NULL;
301285031Sdes	} else if (argv[0] && argv[1]) {
302285031Sdes		host = argv[0];
303285031Sdes		uport = argv[1];
304285031Sdes	} else
305285031Sdes		usage(1);
306285031Sdes
307285031Sdes	if (lflag && sflag)
308285031Sdes		errx(1, "cannot use -s and -l");
309285031Sdes	if (lflag && pflag)
310285031Sdes		errx(1, "cannot use -p and -l");
311285031Sdes	if (lflag && zflag)
312285031Sdes		errx(1, "cannot use -z and -l");
313285031Sdes	if (!lflag && kflag)
314285031Sdes		errx(1, "must use -l with -k");
315285031Sdes
316285031Sdes	/* Get name of temporary socket for unix datagram client */
317285031Sdes	if ((family == AF_UNIX) && uflag && !lflag) {
318285031Sdes		if (sflag) {
319285031Sdes			unix_dg_tmp_socket = sflag;
320285031Sdes		} else {
321285031Sdes			strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX",
322285031Sdes				UNIX_DG_TMP_SOCKET_SIZE);
323285031Sdes			if (mktemp(unix_dg_tmp_socket_buf) == NULL)
324285031Sdes				err(1, "mktemp");
325285031Sdes			unix_dg_tmp_socket = unix_dg_tmp_socket_buf;
326285031Sdes		}
327285031Sdes	}
328285031Sdes
329285031Sdes	/* Initialize addrinfo structure. */
330285031Sdes	if (family != AF_UNIX) {
331285031Sdes		memset(&hints, 0, sizeof(struct addrinfo));
332285031Sdes		hints.ai_family = family;
333285031Sdes		hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
334285031Sdes		hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
335285031Sdes		if (nflag)
336285031Sdes			hints.ai_flags |= AI_NUMERICHOST;
337285031Sdes	}
338285031Sdes
339285031Sdes	if (xflag) {
340285031Sdes		if (uflag)
341285031Sdes			errx(1, "no proxy support for UDP mode");
342285031Sdes
343285031Sdes		if (lflag)
344285031Sdes			errx(1, "no proxy support for listen");
345285031Sdes
346285031Sdes		if (family == AF_UNIX)
347285031Sdes			errx(1, "no proxy support for unix sockets");
348285031Sdes
349285031Sdes		/* XXX IPv6 transport to proxy would probably work */
350285031Sdes		if (family == AF_INET6)
351285031Sdes			errx(1, "no proxy support for IPv6");
352285031Sdes
353285031Sdes		if (sflag)
354285031Sdes			errx(1, "no proxy support for local source address");
355285031Sdes
356285031Sdes		proxyhost = strsep(&proxy, ":");
357285031Sdes		proxyport = proxy;
358285031Sdes
359285031Sdes		memset(&proxyhints, 0, sizeof(struct addrinfo));
360285031Sdes		proxyhints.ai_family = family;
361285031Sdes		proxyhints.ai_socktype = SOCK_STREAM;
362285031Sdes		proxyhints.ai_protocol = IPPROTO_TCP;
363285031Sdes		if (nflag)
364285031Sdes			proxyhints.ai_flags |= AI_NUMERICHOST;
365285031Sdes	}
366285031Sdes
367285031Sdes	if (lflag) {
368285031Sdes		int connfd;
369285031Sdes		ret = 0;
370285031Sdes
371285031Sdes		if (family == AF_UNIX) {
372285031Sdes			if (uflag)
373285031Sdes				s = unix_bind(host);
374285031Sdes			else
375285031Sdes				s = unix_listen(host);
376285031Sdes		}
377285031Sdes
378285031Sdes		/* Allow only one connection at a time, but stay alive. */
379285031Sdes		for (;;) {
380285031Sdes			if (family != AF_UNIX)
381285031Sdes				s = local_listen(host, uport, hints);
382285031Sdes			if (s < 0)
383285031Sdes				err(1, "local_listen");
384285031Sdes			/*
385285031Sdes			 * For UDP and -k, don't connect the socket, let it
386285031Sdes			 * receive datagrams from multiple socket pairs.
387285031Sdes			 */
388285031Sdes			if (uflag && kflag)
389285031Sdes				readwrite(s);
390285031Sdes			/*
391285031Sdes			 * For UDP and not -k, we will use recvfrom() initially
392285031Sdes			 * to wait for a caller, then use the regular functions
393285031Sdes			 * to talk to the caller.
394285031Sdes			 */
395285031Sdes			else if (uflag && !kflag) {
396285031Sdes				int rv, plen;
397285031Sdes				char buf[16384];
398285031Sdes				struct sockaddr_storage z;
399285031Sdes
400285031Sdes				len = sizeof(z);
401285031Sdes				plen = 2048;
402285031Sdes				rv = recvfrom(s, buf, plen, MSG_PEEK,
403285031Sdes				    (struct sockaddr *)&z, &len);
404285031Sdes				if (rv < 0)
405285031Sdes					err(1, "recvfrom");
406285031Sdes
407285031Sdes				rv = connect(s, (struct sockaddr *)&z, len);
408285031Sdes				if (rv < 0)
409285031Sdes					err(1, "connect");
410285031Sdes
411285031Sdes				if (vflag)
412285031Sdes					report_connect((struct sockaddr *)&z, len);
413285031Sdes
414285031Sdes				readwrite(s);
415285031Sdes			} else {
416285031Sdes				len = sizeof(cliaddr);
417285031Sdes				connfd = accept(s, (struct sockaddr *)&cliaddr,
418285031Sdes				    &len);
419285031Sdes				if (connfd == -1) {
420285031Sdes					/* For now, all errnos are fatal */
421285031Sdes					err(1, "accept");
422285031Sdes				}
423285031Sdes				if (vflag)
424285031Sdes					report_connect((struct sockaddr *)&cliaddr, len);
425285031Sdes
426285031Sdes				readwrite(connfd);
427285031Sdes				close(connfd);
428285031Sdes			}
429285031Sdes
430285031Sdes			if (family != AF_UNIX)
431285031Sdes				close(s);
432285031Sdes			else if (uflag) {
433285031Sdes				if (connect(s, NULL, 0) < 0)
434285031Sdes					err(1, "connect");
435285031Sdes			}
436285031Sdes
437285031Sdes			if (!kflag)
438285031Sdes				break;
439285031Sdes		}
440285031Sdes	} else if (family == AF_UNIX) {
441285031Sdes		ret = 0;
442285031Sdes
443285031Sdes		if ((s = unix_connect(host)) > 0 && !zflag) {
444285031Sdes			readwrite(s);
445285031Sdes			close(s);
446285031Sdes		} else
447285031Sdes			ret = 1;
448285031Sdes
449285031Sdes		if (uflag)
450285031Sdes			unlink(unix_dg_tmp_socket);
451285031Sdes		exit(ret);
452285031Sdes
453285031Sdes	} else {
454285031Sdes		int i = 0;
455285031Sdes
456285031Sdes		/* Construct the portlist[] array. */
457285031Sdes		build_ports(uport);
458285031Sdes
459285031Sdes		/* Cycle through portlist, connecting to each port. */
460285031Sdes		for (i = 0; portlist[i] != NULL; i++) {
461285031Sdes			if (s)
462285031Sdes				close(s);
463285031Sdes
464285031Sdes			if (xflag)
465285031Sdes				s = socks_connect(host, portlist[i], hints,
466285031Sdes				    proxyhost, proxyport, proxyhints, socksv,
467285031Sdes				    Pflag);
468285031Sdes			else
469285031Sdes				s = remote_connect(host, portlist[i], hints);
470285031Sdes
471285031Sdes			if (s < 0)
472285031Sdes				continue;
473285031Sdes
474285031Sdes			ret = 0;
475285031Sdes			if (vflag || zflag) {
476285031Sdes				/* For UDP, make sure we are connected. */
477285031Sdes				if (uflag) {
478285031Sdes					if (udptest(s) == -1) {
479285031Sdes						ret = 1;
480285031Sdes						continue;
481285031Sdes					}
482285031Sdes				}
483285031Sdes
484285031Sdes				/* Don't look up port if -n. */
485285031Sdes				if (nflag)
486285031Sdes					sv = NULL;
487285031Sdes				else {
488285031Sdes					sv = getservbyport(
489285031Sdes					    ntohs(atoi(portlist[i])),
490285031Sdes					    uflag ? "udp" : "tcp");
491285031Sdes				}
492285031Sdes
493285031Sdes				fprintf(stderr,
494285031Sdes				    "Connection to %s %s port [%s/%s] "
495285031Sdes				    "succeeded!\n", host, portlist[i],
496285031Sdes				    uflag ? "udp" : "tcp",
497285031Sdes				    sv ? sv->s_name : "*");
498285031Sdes			}
499285031Sdes			if (Fflag)
500285031Sdes				fdpass(s);
501285031Sdes			else if (!zflag)
502285031Sdes				readwrite(s);
503285031Sdes		}
504285031Sdes	}
505285031Sdes
506285031Sdes	if (s)
507285031Sdes		close(s);
508285031Sdes
509285031Sdes	exit(ret);
510285031Sdes}
511285031Sdes
512285031Sdes/*
513285031Sdes * unix_bind()
514285031Sdes * Returns a unix socket bound to the given path
515285031Sdes */
516285031Sdesint
517285031Sdesunix_bind(char *path)
518285031Sdes{
519285031Sdes	struct sockaddr_un sun_sa;
520285031Sdes	int s;
521285031Sdes
522285031Sdes	/* Create unix domain socket. */
523285031Sdes	if ((s = socket(AF_UNIX, uflag ? SOCK_DGRAM : SOCK_STREAM,
524285031Sdes	     0)) < 0)
525285031Sdes		return (-1);
526285031Sdes
527285031Sdes	memset(&sun_sa, 0, sizeof(struct sockaddr_un));
528285031Sdes	sun_sa.sun_family = AF_UNIX;
529285031Sdes
530285031Sdes	if (strlcpy(sun_sa.sun_path, path, sizeof(sun_sa.sun_path)) >=
531285031Sdes	    sizeof(sun_sa.sun_path)) {
532285031Sdes		close(s);
533285031Sdes		errno = ENAMETOOLONG;
534285031Sdes		return (-1);
535285031Sdes	}
536285031Sdes
537285031Sdes	if (bind(s, (struct sockaddr *)&sun_sa, SUN_LEN(&sun_sa)) < 0) {
538285031Sdes		close(s);
539285031Sdes		return (-1);
540285031Sdes	}
541285031Sdes	return (s);
542285031Sdes}
543285031Sdes
544285031Sdes/*
545285031Sdes * unix_connect()
546285031Sdes * Returns a socket connected to a local unix socket. Returns -1 on failure.
547285031Sdes */
548285031Sdesint
549285031Sdesunix_connect(char *path)
550285031Sdes{
551285031Sdes	struct sockaddr_un sun_sa;
552285031Sdes	int s;
553285031Sdes
554285031Sdes	if (uflag) {
555285031Sdes		if ((s = unix_bind(unix_dg_tmp_socket)) < 0)
556285031Sdes			return (-1);
557285031Sdes	} else {
558285031Sdes		if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
559285031Sdes			return (-1);
560285031Sdes	}
561285031Sdes	(void)fcntl(s, F_SETFD, FD_CLOEXEC);
562285031Sdes
563285031Sdes	memset(&sun_sa, 0, sizeof(struct sockaddr_un));
564285031Sdes	sun_sa.sun_family = AF_UNIX;
565285031Sdes
566285031Sdes	if (strlcpy(sun_sa.sun_path, path, sizeof(sun_sa.sun_path)) >=
567285031Sdes	    sizeof(sun_sa.sun_path)) {
568285031Sdes		close(s);
569285031Sdes		errno = ENAMETOOLONG;
570285031Sdes		return (-1);
571285031Sdes	}
572285031Sdes	if (connect(s, (struct sockaddr *)&sun_sa, SUN_LEN(&sun_sa)) < 0) {
573285031Sdes		close(s);
574285031Sdes		return (-1);
575285031Sdes	}
576285031Sdes	return (s);
577285031Sdes
578285031Sdes}
579285031Sdes
580285031Sdes/*
581285031Sdes * unix_listen()
582285031Sdes * Create a unix domain socket, and listen on it.
583285031Sdes */
584285031Sdesint
585285031Sdesunix_listen(char *path)
586285031Sdes{
587285031Sdes	int s;
588285031Sdes	if ((s = unix_bind(path)) < 0)
589285031Sdes		return (-1);
590285031Sdes
591285031Sdes	if (listen(s, 5) < 0) {
592285031Sdes		close(s);
593285031Sdes		return (-1);
594285031Sdes	}
595285031Sdes	return (s);
596285031Sdes}
597285031Sdes
598285031Sdes/*
599285031Sdes * remote_connect()
600285031Sdes * Returns a socket connected to a remote host. Properly binds to a local
601285031Sdes * port or source address if needed. Returns -1 on failure.
602285031Sdes */
603285031Sdesint
604285031Sdesremote_connect(const char *host, const char *port, struct addrinfo hints)
605285031Sdes{
606285031Sdes	struct addrinfo *res, *res0;
607285031Sdes	int s, error;
608285031Sdes#if defined(SO_RTABLE) || defined(SO_BINDANY)
609285031Sdes	int on = 1;
610285031Sdes#endif
611285031Sdes
612285031Sdes	if ((error = getaddrinfo(host, port, &hints, &res)))
613285031Sdes		errx(1, "getaddrinfo: %s", gai_strerror(error));
614285031Sdes
615285031Sdes	res0 = res;
616285031Sdes	do {
617285031Sdes		if ((s = socket(res0->ai_family, res0->ai_socktype,
618285031Sdes		    res0->ai_protocol)) < 0)
619285031Sdes			continue;
620285031Sdes
621285031Sdes#ifdef SO_RTABLE
622285031Sdes		if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_RTABLE,
623285031Sdes		    &rtableid, sizeof(rtableid)) == -1))
624285031Sdes			err(1, "setsockopt SO_RTABLE");
625285031Sdes#endif
626285031Sdes		/* Bind to a local port or source address if specified. */
627285031Sdes		if (sflag || pflag) {
628285031Sdes			struct addrinfo ahints, *ares;
629285031Sdes
630285031Sdes#ifdef SO_BINDANY
631285031Sdes			/* try SO_BINDANY, but don't insist */
632285031Sdes			setsockopt(s, SOL_SOCKET, SO_BINDANY, &on, sizeof(on));
633285031Sdes#endif
634285031Sdes			memset(&ahints, 0, sizeof(struct addrinfo));
635285031Sdes			ahints.ai_family = res0->ai_family;
636285031Sdes			ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
637285031Sdes			ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
638285031Sdes			ahints.ai_flags = AI_PASSIVE;
639285031Sdes			if ((error = getaddrinfo(sflag, pflag, &ahints, &ares)))
640285031Sdes				errx(1, "getaddrinfo: %s", gai_strerror(error));
641285031Sdes
642285031Sdes			if (bind(s, (struct sockaddr *)ares->ai_addr,
643285031Sdes			    ares->ai_addrlen) < 0)
644285031Sdes				err(1, "bind failed");
645285031Sdes			freeaddrinfo(ares);
646285031Sdes		}
647285031Sdes
648285031Sdes		set_common_sockopts(s);
649285031Sdes
650285031Sdes		if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
651285031Sdes			break;
652285031Sdes		else if (vflag)
653285031Sdes			warn("connect to %s port %s (%s) failed", host, port,
654285031Sdes			    uflag ? "udp" : "tcp");
655285031Sdes
656285031Sdes		close(s);
657285031Sdes		s = -1;
658285031Sdes	} while ((res0 = res0->ai_next) != NULL);
659285031Sdes
660285031Sdes	freeaddrinfo(res);
661285031Sdes
662285031Sdes	return (s);
663285031Sdes}
664285031Sdes
665285031Sdesint
666285031Sdestimeout_connect(int s, const struct sockaddr *name, socklen_t namelen)
667285031Sdes{
668285031Sdes	struct pollfd pfd;
669285031Sdes	socklen_t optlen;
670285031Sdes	int flags = 0, optval;
671285031Sdes	int ret;
672285031Sdes
673285031Sdes	if (timeout != -1) {
674285031Sdes		flags = fcntl(s, F_GETFL, 0);
675285031Sdes		if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
676285031Sdes			err(1, "set non-blocking mode");
677285031Sdes	}
678285031Sdes
679285031Sdes	if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) {
680285031Sdes		pfd.fd = s;
681285031Sdes		pfd.events = POLLOUT;
682285031Sdes		if ((ret = poll(&pfd, 1, timeout)) == 1) {
683285031Sdes			optlen = sizeof(optval);
684285031Sdes			if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR,
685285031Sdes			    &optval, &optlen)) == 0) {
686285031Sdes				errno = optval;
687285031Sdes				ret = optval == 0 ? 0 : -1;
688285031Sdes			}
689285031Sdes		} else if (ret == 0) {
690285031Sdes			errno = ETIMEDOUT;
691285031Sdes			ret = -1;
692285031Sdes		} else
693285031Sdes			err(1, "poll failed");
694285031Sdes	}
695285031Sdes
696285031Sdes	if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1)
697285031Sdes		err(1, "restoring flags");
698285031Sdes
699285031Sdes	return (ret);
700285031Sdes}
701285031Sdes
702285031Sdes/*
703285031Sdes * local_listen()
704285031Sdes * Returns a socket listening on a local port, binds to specified source
705285031Sdes * address. Returns -1 on failure.
706285031Sdes */
707285031Sdesint
708285031Sdeslocal_listen(char *host, char *port, struct addrinfo hints)
709285031Sdes{
710285031Sdes	struct addrinfo *res, *res0;
711285031Sdes	int s, ret, x = 1;
712285031Sdes	int error;
713285031Sdes
714285031Sdes	/* Allow nodename to be null. */
715285031Sdes	hints.ai_flags |= AI_PASSIVE;
716285031Sdes
717285031Sdes	/*
718285031Sdes	 * In the case of binding to a wildcard address
719285031Sdes	 * default to binding to an ipv4 address.
720285031Sdes	 */
721285031Sdes	if (host == NULL && hints.ai_family == AF_UNSPEC)
722285031Sdes		hints.ai_family = AF_INET;
723285031Sdes
724285031Sdes	if ((error = getaddrinfo(host, port, &hints, &res)))
725285031Sdes		errx(1, "getaddrinfo: %s", gai_strerror(error));
726285031Sdes
727285031Sdes	res0 = res;
728285031Sdes	do {
729285031Sdes		if ((s = socket(res0->ai_family, res0->ai_socktype,
730285031Sdes		    res0->ai_protocol)) < 0)
731285031Sdes			continue;
732285031Sdes
733285031Sdes#ifdef SO_RTABLE
734285031Sdes		if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_RTABLE,
735285031Sdes		    &rtableid, sizeof(rtableid)) == -1))
736285031Sdes			err(1, "setsockopt SO_RTABLE");
737285031Sdes#endif
738285031Sdes#ifdef SO_REUSEPORT
739285031Sdes		ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));
740285031Sdes		if (ret == -1)
741285031Sdes			err(1, "setsockopt");
742285031Sdes#endif
743285031Sdes		set_common_sockopts(s);
744285031Sdes
745285031Sdes		if (bind(s, (struct sockaddr *)res0->ai_addr,
746285031Sdes		    res0->ai_addrlen) == 0)
747285031Sdes			break;
748285031Sdes
749285031Sdes		close(s);
750285031Sdes		s = -1;
751285031Sdes	} while ((res0 = res0->ai_next) != NULL);
752285031Sdes
753285031Sdes	if (!uflag && s != -1) {
754285031Sdes		if (listen(s, 1) < 0)
755285031Sdes			err(1, "listen");
756285031Sdes	}
757285031Sdes
758285031Sdes	freeaddrinfo(res);
759285031Sdes
760285031Sdes	return (s);
761285031Sdes}
762285031Sdes
763285031Sdes/*
764285031Sdes * readwrite()
765285031Sdes * Loop that polls on the network file descriptor and stdin.
766285031Sdes */
767285031Sdesvoid
768285031Sdesreadwrite(int net_fd)
769285031Sdes{
770285031Sdes	struct pollfd pfd[4];
771285031Sdes	int stdin_fd = STDIN_FILENO;
772285031Sdes	int stdout_fd = STDOUT_FILENO;
773285031Sdes	unsigned char netinbuf[BUFSIZE];
774285031Sdes	size_t netinbufpos = 0;
775285031Sdes	unsigned char stdinbuf[BUFSIZE];
776285031Sdes	size_t stdinbufpos = 0;
777285031Sdes	int n, num_fds;
778285031Sdes	ssize_t ret;
779285031Sdes
780285031Sdes	/* don't read from stdin if requested */
781285031Sdes	if (dflag)
782285031Sdes		stdin_fd = -1;
783285031Sdes
784285031Sdes	/* stdin */
785285031Sdes	pfd[POLL_STDIN].fd = stdin_fd;
786285031Sdes	pfd[POLL_STDIN].events = POLLIN;
787285031Sdes
788285031Sdes	/* network out */
789285031Sdes	pfd[POLL_NETOUT].fd = net_fd;
790285031Sdes	pfd[POLL_NETOUT].events = 0;
791285031Sdes
792285031Sdes	/* network in */
793285031Sdes	pfd[POLL_NETIN].fd = net_fd;
794285031Sdes	pfd[POLL_NETIN].events = POLLIN;
795285031Sdes
796285031Sdes	/* stdout */
797285031Sdes	pfd[POLL_STDOUT].fd = stdout_fd;
798285031Sdes	pfd[POLL_STDOUT].events = 0;
799285031Sdes
800285031Sdes	while (1) {
801285031Sdes		/* both inputs are gone, buffers are empty, we are done */
802285031Sdes		if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1
803285031Sdes		    && stdinbufpos == 0 && netinbufpos == 0) {
804285031Sdes			close(net_fd);
805285031Sdes			return;
806285031Sdes		}
807285031Sdes		/* both outputs are gone, we can't continue */
808285031Sdes		if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) {
809285031Sdes			close(net_fd);
810285031Sdes			return;
811285031Sdes		}
812285031Sdes		/* listen and net in gone, queues empty, done */
813285031Sdes		if (lflag && pfd[POLL_NETIN].fd == -1
814285031Sdes		    && stdinbufpos == 0 && netinbufpos == 0) {
815285031Sdes			close(net_fd);
816285031Sdes			return;
817285031Sdes		}
818285031Sdes
819285031Sdes		/* help says -i is for "wait between lines sent". We read and
820285031Sdes		 * write arbitrary amounts of data, and we don't want to start
821285031Sdes		 * scanning for newlines, so this is as good as it gets */
822285031Sdes		if (iflag)
823285031Sdes			sleep(iflag);
824285031Sdes
825285031Sdes		/* poll */
826285031Sdes		num_fds = poll(pfd, 4, timeout);
827285031Sdes
828285031Sdes		/* treat poll errors */
829285031Sdes		if (num_fds == -1) {
830285031Sdes			close(net_fd);
831285031Sdes			err(1, "polling error");
832285031Sdes		}
833285031Sdes
834285031Sdes		/* timeout happened */
835285031Sdes		if (num_fds == 0)
836285031Sdes			return;
837285031Sdes
838285031Sdes		/* treat socket error conditions */
839285031Sdes		for (n = 0; n < 4; n++) {
840285031Sdes			if (pfd[n].revents & (POLLERR|POLLNVAL)) {
841285031Sdes				pfd[n].fd = -1;
842285031Sdes			}
843285031Sdes		}
844285031Sdes		/* reading is possible after HUP */
845285031Sdes		if (pfd[POLL_STDIN].events & POLLIN &&
846285031Sdes		    pfd[POLL_STDIN].revents & POLLHUP &&
847285031Sdes		    ! (pfd[POLL_STDIN].revents & POLLIN))
848285031Sdes				pfd[POLL_STDIN].fd = -1;
849285031Sdes
850285031Sdes		if (pfd[POLL_NETIN].events & POLLIN &&
851285031Sdes		    pfd[POLL_NETIN].revents & POLLHUP &&
852285031Sdes		    ! (pfd[POLL_NETIN].revents & POLLIN))
853285031Sdes				pfd[POLL_NETIN].fd = -1;
854285031Sdes
855285031Sdes		if (pfd[POLL_NETOUT].revents & POLLHUP) {
856285031Sdes			if (Nflag)
857285031Sdes				shutdown(pfd[POLL_NETOUT].fd, SHUT_WR);
858285031Sdes			pfd[POLL_NETOUT].fd = -1;
859285031Sdes		}
860285031Sdes		/* if HUP, stop watching stdout */
861285031Sdes		if (pfd[POLL_STDOUT].revents & POLLHUP)
862285031Sdes			pfd[POLL_STDOUT].fd = -1;
863285031Sdes		/* if no net out, stop watching stdin */
864285031Sdes		if (pfd[POLL_NETOUT].fd == -1)
865285031Sdes			pfd[POLL_STDIN].fd = -1;
866285031Sdes		/* if no stdout, stop watching net in */
867285031Sdes		if (pfd[POLL_STDOUT].fd == -1) {
868285031Sdes			if (pfd[POLL_NETIN].fd != -1)
869285031Sdes				shutdown(pfd[POLL_NETIN].fd, SHUT_RD);
870285031Sdes			pfd[POLL_NETIN].fd = -1;
871285031Sdes		}
872285031Sdes
873285031Sdes		/* try to read from stdin */
874285031Sdes		if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) {
875285031Sdes			ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf,
876285031Sdes			    &stdinbufpos);
877285031Sdes			/* error or eof on stdin - remove from pfd */
878285031Sdes			if (ret == 0 || ret == -1)
879285031Sdes				pfd[POLL_STDIN].fd = -1;
880285031Sdes			/* read something - poll net out */
881285031Sdes			if (stdinbufpos > 0)
882285031Sdes				pfd[POLL_NETOUT].events = POLLOUT;
883285031Sdes			/* filled buffer - remove self from polling */
884285031Sdes			if (stdinbufpos == BUFSIZE)
885285031Sdes				pfd[POLL_STDIN].events = 0;
886285031Sdes		}
887285031Sdes		/* try to write to network */
888285031Sdes		if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) {
889285031Sdes			ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf,
890285031Sdes			    &stdinbufpos);
891285031Sdes			if (ret == -1)
892285031Sdes				pfd[POLL_NETOUT].fd = -1;
893285031Sdes			/* buffer empty - remove self from polling */
894285031Sdes			if (stdinbufpos == 0)
895285031Sdes				pfd[POLL_NETOUT].events = 0;
896285031Sdes			/* buffer no longer full - poll stdin again */
897285031Sdes			if (stdinbufpos < BUFSIZE)
898285031Sdes				pfd[POLL_STDIN].events = POLLIN;
899285031Sdes		}
900285031Sdes		/* try to read from network */
901285031Sdes		if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) {
902285031Sdes			ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf,
903285031Sdes			    &netinbufpos);
904285031Sdes			if (ret == -1)
905285031Sdes				pfd[POLL_NETIN].fd = -1;
906285031Sdes			/* eof on net in - remove from pfd */
907285031Sdes			if (ret == 0) {
908285031Sdes				shutdown(pfd[POLL_NETIN].fd, SHUT_RD);
909285031Sdes				pfd[POLL_NETIN].fd = -1;
910285031Sdes			}
911285031Sdes			/* read something - poll stdout */
912285031Sdes			if (netinbufpos > 0)
913285031Sdes				pfd[POLL_STDOUT].events = POLLOUT;
914285031Sdes			/* filled buffer - remove self from polling */
915285031Sdes			if (netinbufpos == BUFSIZE)
916285031Sdes				pfd[POLL_NETIN].events = 0;
917285031Sdes			/* handle telnet */
918285031Sdes			if (tflag)
919285031Sdes				atelnet(pfd[POLL_NETIN].fd, netinbuf,
920285031Sdes				    netinbufpos);
921285031Sdes		}
922285031Sdes		/* try to write to stdout */
923285031Sdes		if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) {
924285031Sdes			ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf,
925285031Sdes			    &netinbufpos);
926285031Sdes			if (ret == -1)
927285031Sdes				pfd[POLL_STDOUT].fd = -1;
928285031Sdes			/* buffer empty - remove self from polling */
929285031Sdes			if (netinbufpos == 0)
930285031Sdes				pfd[POLL_STDOUT].events = 0;
931285031Sdes			/* buffer no longer full - poll net in again */
932285031Sdes			if (netinbufpos < BUFSIZE)
933285031Sdes				pfd[POLL_NETIN].events = POLLIN;
934285031Sdes		}
935285031Sdes
936285031Sdes		/* stdin gone and queue empty? */
937285031Sdes		if (pfd[POLL_STDIN].fd == -1 && stdinbufpos == 0) {
938285031Sdes			if (pfd[POLL_NETOUT].fd != -1 && Nflag)
939285031Sdes				shutdown(pfd[POLL_NETOUT].fd, SHUT_WR);
940285031Sdes			pfd[POLL_NETOUT].fd = -1;
941285031Sdes		}
942285031Sdes		/* net in gone and queue empty? */
943285031Sdes		if (pfd[POLL_NETIN].fd == -1 && netinbufpos == 0) {
944285031Sdes			pfd[POLL_STDOUT].fd = -1;
945285031Sdes		}
946285031Sdes	}
947285031Sdes}
948285031Sdes
949285031Sdesssize_t
950285031Sdesdrainbuf(int fd, unsigned char *buf, size_t *bufpos)
951285031Sdes{
952285031Sdes	ssize_t n;
953285031Sdes	ssize_t adjust;
954285031Sdes
955285031Sdes	n = write(fd, buf, *bufpos);
956285031Sdes	/* don't treat EAGAIN, EINTR as error */
957285031Sdes	if (n == -1 && (errno == EAGAIN || errno == EINTR))
958285031Sdes		n = -2;
959285031Sdes	if (n <= 0)
960285031Sdes		return n;
961285031Sdes	/* adjust buffer */
962285031Sdes	adjust = *bufpos - n;
963285031Sdes	if (adjust > 0)
964285031Sdes		memmove(buf, buf + n, adjust);
965285031Sdes	*bufpos -= n;
966285031Sdes	return n;
967285031Sdes}
968285031Sdes
969285031Sdes
970285031Sdesssize_t
971285031Sdesfillbuf(int fd, unsigned char *buf, size_t *bufpos)
972285031Sdes{
973285031Sdes	size_t num = BUFSIZE - *bufpos;
974285031Sdes	ssize_t n;
975285031Sdes
976285031Sdes	n = read(fd, buf + *bufpos, num);
977285031Sdes	/* don't treat EAGAIN, EINTR as error */
978285031Sdes	if (n == -1 && (errno == EAGAIN || errno == EINTR))
979285031Sdes		n = -2;
980285031Sdes	if (n <= 0)
981285031Sdes		return n;
982285031Sdes	*bufpos += n;
983285031Sdes	return n;
984285031Sdes}
985285031Sdes
986285031Sdes/*
987285031Sdes * fdpass()
988285031Sdes * Pass the connected file descriptor to stdout and exit.
989285031Sdes */
990285031Sdesvoid
991285031Sdesfdpass(int nfd)
992285031Sdes{
993285031Sdes#if defined(HAVE_SENDMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR))
994285031Sdes	struct msghdr msg;
995285031Sdes#ifndef HAVE_ACCRIGHTS_IN_MSGHDR
996285031Sdes	union {
997285031Sdes		struct cmsghdr hdr;
998285031Sdes		char buf[CMSG_SPACE(sizeof(int))];
999285031Sdes	} cmsgbuf;
1000285031Sdes	struct cmsghdr *cmsg;
1001285031Sdes#endif
1002285031Sdes	struct iovec vec;
1003285031Sdes	char ch = '\0';
1004285031Sdes	struct pollfd pfd;
1005285031Sdes	ssize_t r;
1006285031Sdes
1007285031Sdes	memset(&msg, 0, sizeof(msg));
1008285031Sdes#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
1009285031Sdes	msg.msg_accrights = (caddr_t)&nfd;
1010285031Sdes	msg.msg_accrightslen = sizeof(nfd);
1011285031Sdes#else
1012285031Sdes	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
1013285031Sdes	msg.msg_control = (caddr_t)&cmsgbuf.buf;
1014285031Sdes	msg.msg_controllen = sizeof(cmsgbuf.buf);
1015285031Sdes	cmsg = CMSG_FIRSTHDR(&msg);
1016285031Sdes	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
1017285031Sdes	cmsg->cmsg_level = SOL_SOCKET;
1018285031Sdes	cmsg->cmsg_type = SCM_RIGHTS;
1019285031Sdes	*(int *)CMSG_DATA(cmsg) = nfd;
1020285031Sdes#endif
1021285031Sdes
1022285031Sdes	vec.iov_base = &ch;
1023285031Sdes	vec.iov_len = 1;
1024285031Sdes	msg.msg_iov = &vec;
1025285031Sdes	msg.msg_iovlen = 1;
1026285031Sdes
1027285031Sdes	bzero(&pfd, sizeof(pfd));
1028285031Sdes	pfd.fd = STDOUT_FILENO;
1029285031Sdes	for (;;) {
1030285031Sdes		r = sendmsg(STDOUT_FILENO, &msg, 0);
1031285031Sdes		if (r == -1) {
1032285031Sdes			if (errno == EAGAIN || errno == EINTR) {
1033285031Sdes				pfd.events = POLLOUT;
1034285031Sdes				if (poll(&pfd, 1, -1) == -1)
1035285031Sdes					err(1, "poll");
1036285031Sdes				continue;
1037285031Sdes			}
1038285031Sdes			err(1, "sendmsg");
1039285031Sdes		} else if (r == -1)
1040285031Sdes			errx(1, "sendmsg: unexpected return value %zd", r);
1041285031Sdes		else
1042285031Sdes			break;
1043285031Sdes	}
1044285031Sdes	exit(0);
1045285031Sdes#else
1046285031Sdes	errx(1, "%s: file descriptor passing not supported", __func__);
1047285031Sdes#endif
1048285031Sdes}
1049285031Sdes
1050285031Sdes/* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */
1051285031Sdesvoid
1052285031Sdesatelnet(int nfd, unsigned char *buf, unsigned int size)
1053285031Sdes{
1054285031Sdes	unsigned char *p, *end;
1055285031Sdes	unsigned char obuf[4];
1056285031Sdes
1057285031Sdes	if (size < 3)
1058285031Sdes		return;
1059285031Sdes	end = buf + size - 2;
1060285031Sdes
1061285031Sdes	for (p = buf; p < end; p++) {
1062285031Sdes		if (*p != IAC)
1063285031Sdes			continue;
1064285031Sdes
1065285031Sdes		obuf[0] = IAC;
1066285031Sdes		p++;
1067285031Sdes		if ((*p == WILL) || (*p == WONT))
1068285031Sdes			obuf[1] = DONT;
1069285031Sdes		else if ((*p == DO) || (*p == DONT))
1070285031Sdes			obuf[1] = WONT;
1071285031Sdes		else
1072285031Sdes			continue;
1073285031Sdes
1074285031Sdes		p++;
1075285031Sdes		obuf[2] = *p;
1076285031Sdes		if (atomicio(vwrite, nfd, obuf, 3) != 3)
1077285031Sdes			warn("Write Error!");
1078285031Sdes	}
1079285031Sdes}
1080285031Sdes
1081285031Sdes/*
1082285031Sdes * build_ports()
1083285031Sdes * Build an array of ports in portlist[], listing each port
1084285031Sdes * that we should try to connect to.
1085285031Sdes */
1086285031Sdesvoid
1087285031Sdesbuild_ports(char *p)
1088285031Sdes{
1089285031Sdes	const char *errstr;
1090285031Sdes	char *n;
1091285031Sdes	int hi, lo, cp;
1092285031Sdes	int x = 0;
1093285031Sdes
1094285031Sdes	if ((n = strchr(p, '-')) != NULL) {
1095285031Sdes		*n = '\0';
1096285031Sdes		n++;
1097285031Sdes
1098285031Sdes		/* Make sure the ports are in order: lowest->highest. */
1099285031Sdes		hi = strtonum(n, 1, PORT_MAX, &errstr);
1100285031Sdes		if (errstr)
1101285031Sdes			errx(1, "port number %s: %s", errstr, n);
1102285031Sdes		lo = strtonum(p, 1, PORT_MAX, &errstr);
1103285031Sdes		if (errstr)
1104285031Sdes			errx(1, "port number %s: %s", errstr, p);
1105285031Sdes
1106285031Sdes		if (lo > hi) {
1107285031Sdes			cp = hi;
1108285031Sdes			hi = lo;
1109285031Sdes			lo = cp;
1110285031Sdes		}
1111285031Sdes
1112285031Sdes		/* Load ports sequentially. */
1113285031Sdes		for (cp = lo; cp <= hi; cp++) {
1114285031Sdes			portlist[x] = calloc(1, PORT_MAX_LEN);
1115285031Sdes			if (portlist[x] == NULL)
1116285031Sdes				errx(1, "calloc");
1117285031Sdes			snprintf(portlist[x], PORT_MAX_LEN, "%d", cp);
1118285031Sdes			x++;
1119285031Sdes		}
1120285031Sdes
1121285031Sdes		/* Randomly swap ports. */
1122285031Sdes		if (rflag) {
1123285031Sdes			int y;
1124285031Sdes			char *c;
1125285031Sdes
1126285031Sdes			for (x = 0; x <= (hi - lo); x++) {
1127285031Sdes				y = (arc4random() & 0xFFFF) % (hi - lo);
1128285031Sdes				c = portlist[x];
1129285031Sdes				portlist[x] = portlist[y];
1130285031Sdes				portlist[y] = c;
1131285031Sdes			}
1132285031Sdes		}
1133285031Sdes	} else {
1134285031Sdes		hi = strtonum(p, 1, PORT_MAX, &errstr);
1135285031Sdes		if (errstr)
1136285031Sdes			errx(1, "port number %s: %s", errstr, p);
1137285031Sdes		portlist[0] = strdup(p);
1138285031Sdes		if (portlist[0] == NULL)
1139285031Sdes			errx(1, "strdup");
1140285031Sdes	}
1141285031Sdes}
1142285031Sdes
1143285031Sdes/*
1144285031Sdes * udptest()
1145285031Sdes * Do a few writes to see if the UDP port is there.
1146285031Sdes * Fails once PF state table is full.
1147285031Sdes */
1148285031Sdesint
1149285031Sdesudptest(int s)
1150285031Sdes{
1151285031Sdes	int i, ret;
1152285031Sdes
1153285031Sdes	for (i = 0; i <= 3; i++) {
1154285031Sdes		if (write(s, "X", 1) == 1)
1155285031Sdes			ret = 1;
1156285031Sdes		else
1157285031Sdes			ret = -1;
1158285031Sdes	}
1159285031Sdes	return (ret);
1160285031Sdes}
1161285031Sdes
1162285031Sdesvoid
1163285031Sdesset_common_sockopts(int s)
1164285031Sdes{
1165285031Sdes	int x = 1;
1166285031Sdes
1167285031Sdes#ifdef TCP_MD5SIG
1168285031Sdes	if (Sflag) {
1169285031Sdes		if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG,
1170285031Sdes			&x, sizeof(x)) == -1)
1171285031Sdes			err(1, "setsockopt");
1172285031Sdes	}
1173285031Sdes#endif
1174285031Sdes	if (Dflag) {
1175285031Sdes		if (setsockopt(s, SOL_SOCKET, SO_DEBUG,
1176285031Sdes			&x, sizeof(x)) == -1)
1177285031Sdes			err(1, "setsockopt");
1178285031Sdes	}
1179285031Sdes	if (Tflag != -1) {
1180285031Sdes		if (setsockopt(s, IPPROTO_IP, IP_TOS,
1181285031Sdes		    &Tflag, sizeof(Tflag)) == -1)
1182285031Sdes			err(1, "set IP ToS");
1183285031Sdes	}
1184285031Sdes	if (Iflag) {
1185285031Sdes		if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
1186285031Sdes		    &Iflag, sizeof(Iflag)) == -1)
1187285031Sdes			err(1, "set TCP receive buffer size");
1188285031Sdes	}
1189285031Sdes	if (Oflag) {
1190285031Sdes		if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
1191285031Sdes		    &Oflag, sizeof(Oflag)) == -1)
1192285031Sdes			err(1, "set TCP send buffer size");
1193285031Sdes	}
1194285031Sdes}
1195285031Sdes
1196285031Sdesint
1197285031Sdesmap_tos(char *s, int *val)
1198285031Sdes{
1199285031Sdes	/* DiffServ Codepoints and other TOS mappings */
1200285031Sdes	const struct toskeywords {
1201285031Sdes		const char	*keyword;
1202285031Sdes		int		 val;
1203285031Sdes	} *t, toskeywords[] = {
1204285031Sdes		{ "af11",		IPTOS_DSCP_AF11 },
1205285031Sdes		{ "af12",		IPTOS_DSCP_AF12 },
1206285031Sdes		{ "af13",		IPTOS_DSCP_AF13 },
1207285031Sdes		{ "af21",		IPTOS_DSCP_AF21 },
1208285031Sdes		{ "af22",		IPTOS_DSCP_AF22 },
1209285031Sdes		{ "af23",		IPTOS_DSCP_AF23 },
1210285031Sdes		{ "af31",		IPTOS_DSCP_AF31 },
1211285031Sdes		{ "af32",		IPTOS_DSCP_AF32 },
1212285031Sdes		{ "af33",		IPTOS_DSCP_AF33 },
1213285031Sdes		{ "af41",		IPTOS_DSCP_AF41 },
1214285031Sdes		{ "af42",		IPTOS_DSCP_AF42 },
1215285031Sdes		{ "af43",		IPTOS_DSCP_AF43 },
1216285031Sdes		{ "critical",		IPTOS_PREC_CRITIC_ECP },
1217285031Sdes		{ "cs0",		IPTOS_DSCP_CS0 },
1218285031Sdes		{ "cs1",		IPTOS_DSCP_CS1 },
1219285031Sdes		{ "cs2",		IPTOS_DSCP_CS2 },
1220285031Sdes		{ "cs3",		IPTOS_DSCP_CS3 },
1221285031Sdes		{ "cs4",		IPTOS_DSCP_CS4 },
1222285031Sdes		{ "cs5",		IPTOS_DSCP_CS5 },
1223285031Sdes		{ "cs6",		IPTOS_DSCP_CS6 },
1224285031Sdes		{ "cs7",		IPTOS_DSCP_CS7 },
1225285031Sdes		{ "ef",			IPTOS_DSCP_EF },
1226285031Sdes		{ "inetcontrol",	IPTOS_PREC_INTERNETCONTROL },
1227285031Sdes		{ "lowdelay",		IPTOS_LOWDELAY },
1228285031Sdes		{ "netcontrol",		IPTOS_PREC_NETCONTROL },
1229285031Sdes		{ "reliability",	IPTOS_RELIABILITY },
1230285031Sdes		{ "throughput",		IPTOS_THROUGHPUT },
1231285031Sdes		{ NULL, 		-1 },
1232285031Sdes	};
1233285031Sdes
1234285031Sdes	for (t = toskeywords; t->keyword != NULL; t++) {
1235285031Sdes		if (strcmp(s, t->keyword) == 0) {
1236285031Sdes			*val = t->val;
1237285031Sdes			return (1);
1238285031Sdes		}
1239285031Sdes	}
1240285031Sdes
1241285031Sdes	return (0);
1242285031Sdes}
1243285031Sdes
1244285031Sdesvoid
1245285031Sdesreport_connect(const struct sockaddr *sa, socklen_t salen)
1246285031Sdes{
1247285031Sdes	char remote_host[NI_MAXHOST];
1248285031Sdes	char remote_port[NI_MAXSERV];
1249285031Sdes	int herr;
1250285031Sdes	int flags = NI_NUMERICSERV;
1251285031Sdes
1252285031Sdes	if (nflag)
1253285031Sdes		flags |= NI_NUMERICHOST;
1254285031Sdes
1255285031Sdes	if ((herr = getnameinfo(sa, salen,
1256285031Sdes	    remote_host, sizeof(remote_host),
1257285031Sdes	    remote_port, sizeof(remote_port),
1258285031Sdes	    flags)) != 0) {
1259285031Sdes		if (herr == EAI_SYSTEM)
1260285031Sdes			err(1, "getnameinfo");
1261285031Sdes		else
1262285031Sdes			errx(1, "getnameinfo: %s", gai_strerror(herr));
1263285031Sdes	}
1264285031Sdes
1265285031Sdes	fprintf(stderr,
1266285031Sdes	    "Connection from %s %s "
1267285031Sdes	    "received!\n", remote_host, remote_port);
1268285031Sdes}
1269285031Sdes
1270285031Sdesvoid
1271285031Sdeshelp(void)
1272285031Sdes{
1273285031Sdes	usage(0);
1274285031Sdes	fprintf(stderr, "\tCommand Summary:\n\
1275285031Sdes	\t-4		Use IPv4\n\
1276285031Sdes	\t-6		Use IPv6\n\
1277285031Sdes	\t-D		Enable the debug socket option\n\
1278285031Sdes	\t-d		Detach from stdin\n\
1279285031Sdes	\t-F		Pass socket fd\n\
1280285031Sdes	\t-h		This help text\n\
1281285031Sdes	\t-I length	TCP receive buffer length\n\
1282285031Sdes	\t-i secs\t	Delay interval for lines sent, ports scanned\n\
1283285031Sdes	\t-k		Keep inbound sockets open for multiple connects\n\
1284285031Sdes	\t-l		Listen mode, for inbound connects\n\
1285285031Sdes	\t-N		Shutdown the network socket after EOF on stdin\n\
1286285031Sdes	\t-n		Suppress name/port resolutions\n\
1287285031Sdes	\t-O length	TCP send buffer length\n\
1288285031Sdes	\t-P proxyuser\tUsername for proxy authentication\n\
1289285031Sdes	\t-p port\t	Specify local port for remote connects\n\
1290285031Sdes	\t-r		Randomize remote ports\n\
1291285031Sdes	\t-S		Enable the TCP MD5 signature option\n\
1292285031Sdes	\t-s addr\t	Local source address\n\
1293285031Sdes	\t-T toskeyword\tSet IP Type of Service\n\
1294285031Sdes	\t-t		Answer TELNET negotiation\n\
1295285031Sdes	\t-U		Use UNIX domain socket\n\
1296285031Sdes	\t-u		UDP mode\n\
1297285031Sdes	\t-V rtable	Specify alternate routing table\n\
1298285031Sdes	\t-v		Verbose\n\
1299285031Sdes	\t-w secs\t	Timeout for connects and final net reads\n\
1300285031Sdes	\t-X proto	Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\
1301285031Sdes	\t-x addr[:port]\tSpecify proxy address and port\n\
1302285031Sdes	\t-z		Zero-I/O mode [used for scanning]\n\
1303285031Sdes	Port numbers can be individual or ranges: lo-hi [inclusive]\n");
1304285031Sdes	exit(1);
1305285031Sdes}
1306285031Sdes
1307285031Sdesvoid
1308285031Sdesusage(int ret)
1309285031Sdes{
1310285031Sdes	fprintf(stderr,
1311285031Sdes	    "usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n"
1312285031Sdes	    "\t  [-P proxy_username] [-p source_port] [-s source] [-T ToS]\n"
1313285031Sdes	    "\t  [-V rtable] [-w timeout] [-X proxy_protocol]\n"
1314285031Sdes	    "\t  [-x proxy_address[:port]] [destination] [port]\n");
1315285031Sdes	if (ret)
1316285031Sdes		exit(1);
1317285031Sdes}
1318285031Sdes
1319285031Sdes/* *** src/usr.bin/nc/socks.c *** */
1320285031Sdes
1321285031Sdes
1322285031Sdes/*	$OpenBSD: socks.c,v 1.20 2012/03/08 09:56:28 espie Exp $	*/
1323285031Sdes
1324285031Sdes/*
1325285031Sdes * Copyright (c) 1999 Niklas Hallqvist.  All rights reserved.
1326285031Sdes * Copyright (c) 2004, 2005 Damien Miller.  All rights reserved.
1327285031Sdes *
1328285031Sdes * Redistribution and use in source and binary forms, with or without
1329285031Sdes * modification, are permitted provided that the following conditions
1330285031Sdes * are met:
1331285031Sdes * 1. Redistributions of source code must retain the above copyright
1332285031Sdes *    notice, this list of conditions and the following disclaimer.
1333285031Sdes * 2. Redistributions in binary form must reproduce the above copyright
1334285031Sdes *    notice, this list of conditions and the following disclaimer in the
1335285031Sdes *    documentation and/or other materials provided with the distribution.
1336285031Sdes *
1337285031Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1338285031Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1339285031Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1340285031Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1341285031Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1342285031Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1343285031Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1344285031Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1345285031Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1346285031Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1347285031Sdes */
1348285031Sdes
1349285031Sdes#include <sys/types.h>
1350285031Sdes#include <sys/socket.h>
1351285031Sdes#include <netinet/in.h>
1352285031Sdes#include <arpa/inet.h>
1353285031Sdes
1354285031Sdes#include <errno.h>
1355285031Sdes#include <netdb.h>
1356285031Sdes#include <stdio.h>
1357285031Sdes#include <stdlib.h>
1358285031Sdes#include <string.h>
1359285031Sdes#include <unistd.h>
1360285031Sdes#include <resolv.h>
1361285031Sdes
1362285031Sdes#define SOCKS_PORT	"1080"
1363285031Sdes#define HTTP_PROXY_PORT	"3128"
1364285031Sdes#define HTTP_MAXHDRS	64
1365285031Sdes#define SOCKS_V5	5
1366285031Sdes#define SOCKS_V4	4
1367285031Sdes#define SOCKS_NOAUTH	0
1368285031Sdes#define SOCKS_NOMETHOD	0xff
1369285031Sdes#define SOCKS_CONNECT	1
1370285031Sdes#define SOCKS_IPV4	1
1371285031Sdes#define SOCKS_DOMAIN	3
1372285031Sdes#define SOCKS_IPV6	4
1373285031Sdes
1374285031Sdesint	remote_connect(const char *, const char *, struct addrinfo);
1375285031Sdesint	socks_connect(const char *, const char *, struct addrinfo,
1376285031Sdes	    const char *, const char *, struct addrinfo, int,
1377285031Sdes	    const char *);
1378285031Sdes
1379285031Sdesstatic int
1380285031Sdesdecode_addrport(const char *h, const char *p, struct sockaddr *addr,
1381285031Sdes    socklen_t addrlen, int v4only, int numeric)
1382285031Sdes{
1383285031Sdes	int r;
1384285031Sdes	struct addrinfo hints, *res;
1385285031Sdes
1386285031Sdes	bzero(&hints, sizeof(hints));
1387285031Sdes	hints.ai_family = v4only ? PF_INET : PF_UNSPEC;
1388285031Sdes	hints.ai_flags = numeric ? AI_NUMERICHOST : 0;
1389285031Sdes	hints.ai_socktype = SOCK_STREAM;
1390285031Sdes	r = getaddrinfo(h, p, &hints, &res);
1391285031Sdes	/* Don't fatal when attempting to convert a numeric address */
1392285031Sdes	if (r != 0) {
1393285031Sdes		if (!numeric) {
1394285031Sdes			errx(1, "getaddrinfo(\"%.64s\", \"%.64s\"): %s", h, p,
1395285031Sdes			    gai_strerror(r));
1396285031Sdes		}
1397285031Sdes		return (-1);
1398285031Sdes	}
1399285031Sdes	if (addrlen < res->ai_addrlen) {
1400285031Sdes		freeaddrinfo(res);
1401285031Sdes		errx(1, "internal error: addrlen < res->ai_addrlen");
1402285031Sdes	}
1403285031Sdes	memcpy(addr, res->ai_addr, res->ai_addrlen);
1404285031Sdes	freeaddrinfo(res);
1405285031Sdes	return (0);
1406285031Sdes}
1407285031Sdes
1408285031Sdesstatic int
1409285031Sdesproxy_read_line(int fd, char *buf, size_t bufsz)
1410285031Sdes{
1411285031Sdes	size_t off;
1412285031Sdes
1413285031Sdes	for(off = 0;;) {
1414285031Sdes		if (off >= bufsz)
1415285031Sdes			errx(1, "proxy read too long");
1416285031Sdes		if (atomicio(read, fd, buf + off, 1) != 1)
1417285031Sdes			err(1, "proxy read");
1418285031Sdes		/* Skip CR */
1419285031Sdes		if (buf[off] == '\r')
1420285031Sdes			continue;
1421285031Sdes		if (buf[off] == '\n') {
1422285031Sdes			buf[off] = '\0';
1423285031Sdes			break;
1424285031Sdes		}
1425285031Sdes		off++;
1426285031Sdes	}
1427285031Sdes	return (off);
1428285031Sdes}
1429285031Sdes
1430285031Sdesstatic const char *
1431285031Sdesgetproxypass(const char *proxyuser, const char *proxyhost)
1432285031Sdes{
1433285031Sdes	char prompt[512];
1434285031Sdes	static char pw[256];
1435285031Sdes
1436285031Sdes	snprintf(prompt, sizeof(prompt), "Proxy password for %s@%s: ",
1437285031Sdes	   proxyuser, proxyhost);
1438285031Sdes	if (readpassphrase(prompt, pw, sizeof(pw), RPP_REQUIRE_TTY) == NULL)
1439285031Sdes		errx(1, "Unable to read proxy passphrase");
1440285031Sdes	return (pw);
1441285031Sdes}
1442285031Sdes
1443285031Sdesint
1444285031Sdessocks_connect(const char *host, const char *port,
1445285031Sdes    struct addrinfo hints __attribute__ ((__unused__)),
1446285031Sdes    const char *proxyhost, const char *proxyport, struct addrinfo proxyhints,
1447285031Sdes    int socksv, const char *proxyuser)
1448285031Sdes{
1449285031Sdes	int proxyfd, r, authretry = 0;
1450285031Sdes	size_t hlen, wlen = 0;
1451285031Sdes	unsigned char buf[1024];
1452285031Sdes	size_t cnt;
1453285031Sdes	struct sockaddr_storage addr;
1454285031Sdes	struct sockaddr_in *in4 = (struct sockaddr_in *)&addr;
1455285031Sdes	struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr;
1456285031Sdes	in_port_t serverport;
1457285031Sdes	const char *proxypass = NULL;
1458285031Sdes
1459285031Sdes	if (proxyport == NULL)
1460285031Sdes		proxyport = (socksv == -1) ? HTTP_PROXY_PORT : SOCKS_PORT;
1461285031Sdes
1462285031Sdes	/* Abuse API to lookup port */
1463285031Sdes	if (decode_addrport("0.0.0.0", port, (struct sockaddr *)&addr,
1464285031Sdes	    sizeof(addr), 1, 1) == -1)
1465285031Sdes		errx(1, "unknown port \"%.64s\"", port);
1466285031Sdes	serverport = in4->sin_port;
1467285031Sdes
1468285031Sdes again:
1469285031Sdes	if (authretry++ > 3)
1470285031Sdes		errx(1, "Too many authentication failures");
1471285031Sdes
1472285031Sdes	proxyfd = remote_connect(proxyhost, proxyport, proxyhints);
1473285031Sdes
1474285031Sdes	if (proxyfd < 0)
1475285031Sdes		return (-1);
1476285031Sdes
1477285031Sdes	if (socksv == 5) {
1478285031Sdes		if (decode_addrport(host, port, (struct sockaddr *)&addr,
1479285031Sdes		    sizeof(addr), 0, 1) == -1)
1480285031Sdes			addr.ss_family = 0; /* used in switch below */
1481285031Sdes
1482285031Sdes		/* Version 5, one method: no authentication */
1483285031Sdes		buf[0] = SOCKS_V5;
1484285031Sdes		buf[1] = 1;
1485285031Sdes		buf[2] = SOCKS_NOAUTH;
1486285031Sdes		cnt = atomicio(vwrite, proxyfd, buf, 3);
1487285031Sdes		if (cnt != 3)
1488285031Sdes			err(1, "write failed (%zu/3)", cnt);
1489285031Sdes
1490285031Sdes		cnt = atomicio(read, proxyfd, buf, 2);
1491285031Sdes		if (cnt != 2)
1492285031Sdes			err(1, "read failed (%zu/3)", cnt);
1493285031Sdes
1494285031Sdes		if (buf[1] == SOCKS_NOMETHOD)
1495285031Sdes			errx(1, "authentication method negotiation failed");
1496285031Sdes
1497285031Sdes		switch (addr.ss_family) {
1498285031Sdes		case 0:
1499285031Sdes			/* Version 5, connect: domain name */
1500285031Sdes
1501285031Sdes			/* Max domain name length is 255 bytes */
1502285031Sdes			hlen = strlen(host);
1503285031Sdes			if (hlen > 255)
1504285031Sdes				errx(1, "host name too long for SOCKS5");
1505285031Sdes			buf[0] = SOCKS_V5;
1506285031Sdes			buf[1] = SOCKS_CONNECT;
1507285031Sdes			buf[2] = 0;
1508285031Sdes			buf[3] = SOCKS_DOMAIN;
1509285031Sdes			buf[4] = hlen;
1510285031Sdes			memcpy(buf + 5, host, hlen);
1511285031Sdes			memcpy(buf + 5 + hlen, &serverport, sizeof serverport);
1512285031Sdes			wlen = 7 + hlen;
1513285031Sdes			break;
1514285031Sdes		case AF_INET:
1515285031Sdes			/* Version 5, connect: IPv4 address */
1516285031Sdes			buf[0] = SOCKS_V5;
1517285031Sdes			buf[1] = SOCKS_CONNECT;
1518285031Sdes			buf[2] = 0;
1519285031Sdes			buf[3] = SOCKS_IPV4;
1520285031Sdes			memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr);
1521285031Sdes			memcpy(buf + 8, &in4->sin_port, sizeof in4->sin_port);
1522285031Sdes			wlen = 10;
1523285031Sdes			break;
1524285031Sdes		case AF_INET6:
1525285031Sdes			/* Version 5, connect: IPv6 address */
1526285031Sdes			buf[0] = SOCKS_V5;
1527285031Sdes			buf[1] = SOCKS_CONNECT;
1528285031Sdes			buf[2] = 0;
1529285031Sdes			buf[3] = SOCKS_IPV6;
1530285031Sdes			memcpy(buf + 4, &in6->sin6_addr, sizeof in6->sin6_addr);
1531285031Sdes			memcpy(buf + 20, &in6->sin6_port,
1532285031Sdes			    sizeof in6->sin6_port);
1533285031Sdes			wlen = 22;
1534285031Sdes			break;
1535285031Sdes		default:
1536285031Sdes			errx(1, "internal error: silly AF");
1537285031Sdes		}
1538285031Sdes
1539285031Sdes		cnt = atomicio(vwrite, proxyfd, buf, wlen);
1540285031Sdes		if (cnt != wlen)
1541285031Sdes			err(1, "write failed (%zu/%zu)", cnt, wlen);
1542285031Sdes
1543285031Sdes		cnt = atomicio(read, proxyfd, buf, 4);
1544285031Sdes		if (cnt != 4)
1545285031Sdes			err(1, "read failed (%zu/4)", cnt);
1546285031Sdes		if (buf[1] != 0)
1547285031Sdes			errx(1, "connection failed, SOCKS error %d", buf[1]);
1548285031Sdes		switch (buf[3]) {
1549285031Sdes		case SOCKS_IPV4:
1550285031Sdes			cnt = atomicio(read, proxyfd, buf + 4, 6);
1551285031Sdes			if (cnt != 6)
1552285031Sdes				err(1, "read failed (%zu/6)", cnt);
1553285031Sdes			break;
1554285031Sdes		case SOCKS_IPV6:
1555285031Sdes			cnt = atomicio(read, proxyfd, buf + 4, 18);
1556285031Sdes			if (cnt != 18)
1557285031Sdes				err(1, "read failed (%zu/18)", cnt);
1558285031Sdes			break;
1559285031Sdes		default:
1560285031Sdes			errx(1, "connection failed, unsupported address type");
1561285031Sdes		}
1562285031Sdes	} else if (socksv == 4) {
1563285031Sdes		/* This will exit on lookup failure */
1564285031Sdes		decode_addrport(host, port, (struct sockaddr *)&addr,
1565285031Sdes		    sizeof(addr), 1, 0);
1566285031Sdes
1567285031Sdes		/* Version 4 */
1568285031Sdes		buf[0] = SOCKS_V4;
1569285031Sdes		buf[1] = SOCKS_CONNECT;	/* connect */
1570285031Sdes		memcpy(buf + 2, &in4->sin_port, sizeof in4->sin_port);
1571285031Sdes		memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr);
1572285031Sdes		buf[8] = 0;	/* empty username */
1573285031Sdes		wlen = 9;
1574285031Sdes
1575285031Sdes		cnt = atomicio(vwrite, proxyfd, buf, wlen);
1576285031Sdes		if (cnt != wlen)
1577285031Sdes			err(1, "write failed (%zu/%zu)", cnt, wlen);
1578285031Sdes
1579285031Sdes		cnt = atomicio(read, proxyfd, buf, 8);
1580285031Sdes		if (cnt != 8)
1581285031Sdes			err(1, "read failed (%zu/8)", cnt);
1582285031Sdes		if (buf[1] != 90)
1583285031Sdes			errx(1, "connection failed, SOCKS error %d", buf[1]);
1584285031Sdes	} else if (socksv == -1) {
1585285031Sdes		/* HTTP proxy CONNECT */
1586285031Sdes
1587285031Sdes		/* Disallow bad chars in hostname */
1588285031Sdes		if (strcspn(host, "\r\n\t []:") != strlen(host))
1589285031Sdes			errx(1, "Invalid hostname");
1590285031Sdes
1591285031Sdes		/* Try to be sane about numeric IPv6 addresses */
1592285031Sdes		if (strchr(host, ':') != NULL) {
1593285031Sdes			r = snprintf(buf, sizeof(buf),
1594285031Sdes			    "CONNECT [%s]:%d HTTP/1.0\r\n",
1595285031Sdes			    host, ntohs(serverport));
1596285031Sdes		} else {
1597285031Sdes			r = snprintf(buf, sizeof(buf),
1598285031Sdes			    "CONNECT %s:%d HTTP/1.0\r\n",
1599285031Sdes			    host, ntohs(serverport));
1600285031Sdes		}
1601285031Sdes		if (r == -1 || (size_t)r >= sizeof(buf))
1602285031Sdes			errx(1, "hostname too long");
1603285031Sdes		r = strlen(buf);
1604285031Sdes
1605285031Sdes		cnt = atomicio(vwrite, proxyfd, buf, r);
1606285031Sdes		if (cnt != (size_t)r)
1607285031Sdes			err(1, "write failed (%zu/%d)", cnt, r);
1608285031Sdes
1609285031Sdes		if (authretry > 1) {
1610285031Sdes			char resp[1024];
1611285031Sdes
1612285031Sdes			proxypass = getproxypass(proxyuser, proxyhost);
1613285031Sdes			r = snprintf(buf, sizeof(buf), "%s:%s",
1614285031Sdes			    proxyuser, proxypass);
1615285031Sdes			if (r == -1 || (size_t)r >= sizeof(buf) ||
1616285031Sdes			    b64_ntop(buf, strlen(buf), resp,
1617285031Sdes			    sizeof(resp)) == -1)
1618285031Sdes				errx(1, "Proxy username/password too long");
1619285031Sdes			r = snprintf(buf, sizeof(buf), "Proxy-Authorization: "
1620285031Sdes			    "Basic %s\r\n", resp);
1621285031Sdes			if (r == -1 || (size_t)r >= sizeof(buf))
1622285031Sdes				errx(1, "Proxy auth response too long");
1623285031Sdes			r = strlen(buf);
1624285031Sdes			if ((cnt = atomicio(vwrite, proxyfd, buf, r)) != (size_t)r)
1625285031Sdes				err(1, "write failed (%zu/%d)", cnt, r);
1626285031Sdes		}
1627285031Sdes
1628285031Sdes		/* Terminate headers */
1629285031Sdes		if ((r = atomicio(vwrite, proxyfd, "\r\n", 2)) != 2)
1630285031Sdes			err(1, "write failed (2/%d)", r);
1631285031Sdes
1632285031Sdes		/* Read status reply */
1633285031Sdes		proxy_read_line(proxyfd, buf, sizeof(buf));
1634285031Sdes		if (proxyuser != NULL &&
1635285031Sdes		    strncmp(buf, "HTTP/1.0 407 ", 12) == 0) {
1636285031Sdes			if (authretry > 1) {
1637285031Sdes				fprintf(stderr, "Proxy authentication "
1638285031Sdes				    "failed\n");
1639285031Sdes			}
1640285031Sdes			close(proxyfd);
1641285031Sdes			goto again;
1642285031Sdes		} else if (strncmp(buf, "HTTP/1.0 200 ", 12) != 0 &&
1643285031Sdes		    strncmp(buf, "HTTP/1.1 200 ", 12) != 0)
1644285031Sdes			errx(1, "Proxy error: \"%s\"", buf);
1645285031Sdes
1646285031Sdes		/* Headers continue until we hit an empty line */
1647285031Sdes		for (r = 0; r < HTTP_MAXHDRS; r++) {
1648285031Sdes			proxy_read_line(proxyfd, buf, sizeof(buf));
1649285031Sdes			if (*buf == '\0')
1650285031Sdes				break;
1651285031Sdes		}
1652285031Sdes		if (*buf != '\0')
1653285031Sdes			errx(1, "Too many proxy headers received");
1654285031Sdes	} else
1655285031Sdes		errx(1, "Unknown proxy protocol %d", socksv);
1656285031Sdes
1657285031Sdes	return (proxyfd);
1658285031Sdes}
1659285031Sdes
1660