xref: /freebsd/crypto/openssh/regress/netcat.c (revision 19261079b74319502c6ffa1249920079f0f69a72)
1*19261079SEd Maste /* $OpenBSD: netcat.c,v 1.131 2015/09/03 23:06:28 sobrado Exp $ */
2bc5531deSDag-Erling Smørgrav /*
3bc5531deSDag-Erling Smørgrav  * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
4bc5531deSDag-Erling Smørgrav  *
5bc5531deSDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
6bc5531deSDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
7bc5531deSDag-Erling Smørgrav  * are met:
8bc5531deSDag-Erling Smørgrav  *
9bc5531deSDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
10bc5531deSDag-Erling Smørgrav  *   notice, this list of conditions and the following disclaimer.
11bc5531deSDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
12bc5531deSDag-Erling Smørgrav  *   notice, this list of conditions and the following disclaimer in the
13bc5531deSDag-Erling Smørgrav  *   documentation and/or other materials provided with the distribution.
14bc5531deSDag-Erling Smørgrav  * 3. The name of the author may not be used to endorse or promote products
15bc5531deSDag-Erling Smørgrav  *   derived from this software without specific prior written permission.
16bc5531deSDag-Erling Smørgrav  *
17bc5531deSDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18bc5531deSDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19bc5531deSDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20bc5531deSDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21bc5531deSDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22bc5531deSDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23bc5531deSDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24bc5531deSDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25bc5531deSDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26bc5531deSDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27bc5531deSDag-Erling Smørgrav  */
28bc5531deSDag-Erling Smørgrav 
29bc5531deSDag-Erling Smørgrav /*
30bc5531deSDag-Erling Smørgrav  * Re-written nc(1) for OpenBSD. Original implementation by
31bc5531deSDag-Erling Smørgrav  * *Hobbit* <hobbit@avian.org>.
32bc5531deSDag-Erling Smørgrav  */
33bc5531deSDag-Erling Smørgrav 
34bc5531deSDag-Erling Smørgrav #include "includes.h"
35bc5531deSDag-Erling Smørgrav 
36bc5531deSDag-Erling Smørgrav #include <sys/types.h>
37bc5531deSDag-Erling Smørgrav #include <sys/socket.h>
38bc5531deSDag-Erling Smørgrav #include <sys/time.h>
39bc5531deSDag-Erling Smørgrav #include <sys/uio.h>
40bc5531deSDag-Erling Smørgrav #include <sys/un.h>
41bc5531deSDag-Erling Smørgrav 
42bc5531deSDag-Erling Smørgrav #include <netinet/in.h>
43bc5531deSDag-Erling Smørgrav #include <netinet/tcp.h>
44bc5531deSDag-Erling Smørgrav #include <netinet/ip.h>
45bc5531deSDag-Erling Smørgrav 
46bc5531deSDag-Erling Smørgrav #include <errno.h>
47*19261079SEd Maste #include <fcntl.h>
48*19261079SEd Maste #include <limits.h>
49bc5531deSDag-Erling Smørgrav #include <netdb.h>
50*19261079SEd Maste #include <signal.h>
51bc5531deSDag-Erling Smørgrav #include <stdarg.h>
52bc5531deSDag-Erling Smørgrav #include <stdio.h>
53bc5531deSDag-Erling Smørgrav #include <stdlib.h>
54bc5531deSDag-Erling Smørgrav #include <string.h>
55bc5531deSDag-Erling Smørgrav #include <unistd.h>
56bc5531deSDag-Erling Smørgrav #include "atomicio.h"
57bc5531deSDag-Erling Smørgrav 
58bc5531deSDag-Erling Smørgrav #ifdef HAVE_POLL_H
59bc5531deSDag-Erling Smørgrav #include <poll.h>
60bc5531deSDag-Erling Smørgrav #else
61bc5531deSDag-Erling Smørgrav # ifdef HAVE_SYS_POLL_H
62bc5531deSDag-Erling Smørgrav #  include <sys/poll.h>
63bc5531deSDag-Erling Smørgrav # endif
64bc5531deSDag-Erling Smørgrav #endif
65076ad2f8SDag-Erling Smørgrav #ifdef HAVE_ERR_H
66076ad2f8SDag-Erling Smørgrav # include <err.h>
67076ad2f8SDag-Erling Smørgrav #endif
68*19261079SEd Maste #ifdef HAVE_SYS_BYTEORDER_H
69*19261079SEd Maste # include <sys/byteorder.h>
70*19261079SEd Maste #endif
71*19261079SEd Maste 
72*19261079SEd Maste /* rename to avoid collision in libssh */
73*19261079SEd Maste #define timeout_connect netcat_timeout_connect
74bc5531deSDag-Erling Smørgrav 
75557f75e5SDag-Erling Smørgrav /* Telnet options from arpa/telnet.h */
76557f75e5SDag-Erling Smørgrav #define IAC	255
77557f75e5SDag-Erling Smørgrav #define DONT	254
78557f75e5SDag-Erling Smørgrav #define DO	253
79557f75e5SDag-Erling Smørgrav #define WONT	252
80557f75e5SDag-Erling Smørgrav #define WILL	251
81557f75e5SDag-Erling Smørgrav 
82bc5531deSDag-Erling Smørgrav #ifndef SUN_LEN
83bc5531deSDag-Erling Smørgrav #define SUN_LEN(su) \
84bc5531deSDag-Erling Smørgrav 	(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
85bc5531deSDag-Erling Smørgrav #endif
86bc5531deSDag-Erling Smørgrav 
87bc5531deSDag-Erling Smørgrav #define PORT_MAX	65535
88bc5531deSDag-Erling Smørgrav #define PORT_MAX_LEN	6
89bc5531deSDag-Erling Smørgrav #define UNIX_DG_TMP_SOCKET_SIZE	19
90bc5531deSDag-Erling Smørgrav 
91bc5531deSDag-Erling Smørgrav #define POLL_STDIN 0
92bc5531deSDag-Erling Smørgrav #define POLL_NETOUT 1
93bc5531deSDag-Erling Smørgrav #define POLL_NETIN 2
94bc5531deSDag-Erling Smørgrav #define POLL_STDOUT 3
95bc5531deSDag-Erling Smørgrav #define BUFSIZE 16384
96bc5531deSDag-Erling Smørgrav 
97bc5531deSDag-Erling Smørgrav /* Command Line Options */
98bc5531deSDag-Erling Smørgrav int	dflag;					/* detached, no stdin */
99bc5531deSDag-Erling Smørgrav int	Fflag;					/* fdpass sock to stdout */
100bc5531deSDag-Erling Smørgrav unsigned int iflag;				/* Interval Flag */
101bc5531deSDag-Erling Smørgrav int	kflag;					/* More than one connect */
102bc5531deSDag-Erling Smørgrav int	lflag;					/* Bind to local port */
103bc5531deSDag-Erling Smørgrav int	Nflag;					/* shutdown() network socket */
104bc5531deSDag-Erling Smørgrav int	nflag;					/* Don't do name look up */
105bc5531deSDag-Erling Smørgrav char   *Pflag;					/* Proxy username */
106bc5531deSDag-Erling Smørgrav char   *pflag;					/* Localport flag */
107bc5531deSDag-Erling Smørgrav int	rflag;					/* Random ports flag */
108bc5531deSDag-Erling Smørgrav char   *sflag;					/* Source Address */
109bc5531deSDag-Erling Smørgrav int	tflag;					/* Telnet Emulation */
110bc5531deSDag-Erling Smørgrav int	uflag;					/* UDP - Default to TCP */
111bc5531deSDag-Erling Smørgrav int	vflag;					/* Verbosity */
112bc5531deSDag-Erling Smørgrav int	xflag;					/* Socks proxy */
113bc5531deSDag-Erling Smørgrav int	zflag;					/* Port Scan Flag */
114bc5531deSDag-Erling Smørgrav int	Dflag;					/* sodebug */
115bc5531deSDag-Erling Smørgrav int	Iflag;					/* TCP receive buffer size */
116bc5531deSDag-Erling Smørgrav int	Oflag;					/* TCP send buffer size */
117bc5531deSDag-Erling Smørgrav int	Sflag;					/* TCP MD5 signature option */
118bc5531deSDag-Erling Smørgrav int	Tflag = -1;				/* IP Type of Service */
119bc5531deSDag-Erling Smørgrav int	rtableid = -1;
120bc5531deSDag-Erling Smørgrav 
121bc5531deSDag-Erling Smørgrav int timeout = -1;
122bc5531deSDag-Erling Smørgrav int family = AF_UNSPEC;
123bc5531deSDag-Erling Smørgrav char *portlist[PORT_MAX+1];
124bc5531deSDag-Erling Smørgrav char *unix_dg_tmp_socket;
125bc5531deSDag-Erling Smørgrav 
126bc5531deSDag-Erling Smørgrav void	atelnet(int, unsigned char *, unsigned int);
127bc5531deSDag-Erling Smørgrav void	build_ports(char *);
128bc5531deSDag-Erling Smørgrav void	help(void);
129bc5531deSDag-Erling Smørgrav int	local_listen(char *, char *, struct addrinfo);
130bc5531deSDag-Erling Smørgrav void	readwrite(int);
131bc5531deSDag-Erling Smørgrav void	fdpass(int nfd) __attribute__((noreturn));
132bc5531deSDag-Erling Smørgrav int	remote_connect(const char *, const char *, struct addrinfo);
133bc5531deSDag-Erling Smørgrav int	timeout_connect(int, const struct sockaddr *, socklen_t);
134bc5531deSDag-Erling Smørgrav int	socks_connect(const char *, const char *, struct addrinfo,
135bc5531deSDag-Erling Smørgrav 	    const char *, const char *, struct addrinfo, int, const char *);
136bc5531deSDag-Erling Smørgrav int	udptest(int);
137bc5531deSDag-Erling Smørgrav int	unix_bind(char *);
138bc5531deSDag-Erling Smørgrav int	unix_connect(char *);
139bc5531deSDag-Erling Smørgrav int	unix_listen(char *);
140*19261079SEd Maste void	set_common_sockopts(int, int);
141bc5531deSDag-Erling Smørgrav int	map_tos(char *, int *);
142bc5531deSDag-Erling Smørgrav void	report_connect(const struct sockaddr *, socklen_t);
143bc5531deSDag-Erling Smørgrav void	usage(int);
144bc5531deSDag-Erling Smørgrav ssize_t drainbuf(int, unsigned char *, size_t *);
145bc5531deSDag-Erling Smørgrav ssize_t fillbuf(int, unsigned char *, size_t *);
146bc5531deSDag-Erling Smørgrav 
147bc5531deSDag-Erling Smørgrav 
148bc5531deSDag-Erling Smørgrav int
main(int argc,char * argv[])149bc5531deSDag-Erling Smørgrav main(int argc, char *argv[])
150bc5531deSDag-Erling Smørgrav {
151bc5531deSDag-Erling Smørgrav 	int ch, s, ret, socksv;
152bc5531deSDag-Erling Smørgrav 	char *host, *uport;
153bc5531deSDag-Erling Smørgrav 	struct addrinfo hints;
154bc5531deSDag-Erling Smørgrav 	struct servent *sv;
155bc5531deSDag-Erling Smørgrav 	socklen_t len;
156bc5531deSDag-Erling Smørgrav 	struct sockaddr_storage cliaddr;
157bc5531deSDag-Erling Smørgrav 	char *proxy = NULL;
158bc5531deSDag-Erling Smørgrav 	const char *errstr, *proxyhost = "", *proxyport = NULL;
159bc5531deSDag-Erling Smørgrav 	struct addrinfo proxyhints;
160bc5531deSDag-Erling Smørgrav 	char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE];
161bc5531deSDag-Erling Smørgrav 
162bc5531deSDag-Erling Smørgrav 	ret = 1;
163bc5531deSDag-Erling Smørgrav 	s = 0;
164bc5531deSDag-Erling Smørgrav 	socksv = 5;
165bc5531deSDag-Erling Smørgrav 	host = NULL;
166bc5531deSDag-Erling Smørgrav 	uport = NULL;
167bc5531deSDag-Erling Smørgrav 	sv = NULL;
168bc5531deSDag-Erling Smørgrav 
169*19261079SEd Maste 	signal(SIGPIPE, SIG_IGN);
170*19261079SEd Maste 
171bc5531deSDag-Erling Smørgrav 	while ((ch = getopt(argc, argv,
172bc5531deSDag-Erling Smørgrav 	    "46DdFhI:i:klNnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) {
173bc5531deSDag-Erling Smørgrav 		switch (ch) {
174bc5531deSDag-Erling Smørgrav 		case '4':
175bc5531deSDag-Erling Smørgrav 			family = AF_INET;
176bc5531deSDag-Erling Smørgrav 			break;
177bc5531deSDag-Erling Smørgrav 		case '6':
178bc5531deSDag-Erling Smørgrav 			family = AF_INET6;
179bc5531deSDag-Erling Smørgrav 			break;
180bc5531deSDag-Erling Smørgrav 		case 'U':
181bc5531deSDag-Erling Smørgrav 			family = AF_UNIX;
182bc5531deSDag-Erling Smørgrav 			break;
183bc5531deSDag-Erling Smørgrav 		case 'X':
184bc5531deSDag-Erling Smørgrav 			if (strcasecmp(optarg, "connect") == 0)
185bc5531deSDag-Erling Smørgrav 				socksv = -1; /* HTTP proxy CONNECT */
186bc5531deSDag-Erling Smørgrav 			else if (strcmp(optarg, "4") == 0)
187bc5531deSDag-Erling Smørgrav 				socksv = 4; /* SOCKS v.4 */
188bc5531deSDag-Erling Smørgrav 			else if (strcmp(optarg, "5") == 0)
189bc5531deSDag-Erling Smørgrav 				socksv = 5; /* SOCKS v.5 */
190bc5531deSDag-Erling Smørgrav 			else
191bc5531deSDag-Erling Smørgrav 				errx(1, "unsupported proxy protocol");
192bc5531deSDag-Erling Smørgrav 			break;
193bc5531deSDag-Erling Smørgrav 		case 'd':
194bc5531deSDag-Erling Smørgrav 			dflag = 1;
195bc5531deSDag-Erling Smørgrav 			break;
196bc5531deSDag-Erling Smørgrav 		case 'F':
197bc5531deSDag-Erling Smørgrav 			Fflag = 1;
198bc5531deSDag-Erling Smørgrav 			break;
199bc5531deSDag-Erling Smørgrav 		case 'h':
200bc5531deSDag-Erling Smørgrav 			help();
201bc5531deSDag-Erling Smørgrav 			break;
202bc5531deSDag-Erling Smørgrav 		case 'i':
203bc5531deSDag-Erling Smørgrav 			iflag = strtonum(optarg, 0, UINT_MAX, &errstr);
204bc5531deSDag-Erling Smørgrav 			if (errstr)
205bc5531deSDag-Erling Smørgrav 				errx(1, "interval %s: %s", errstr, optarg);
206bc5531deSDag-Erling Smørgrav 			break;
207bc5531deSDag-Erling Smørgrav 		case 'k':
208bc5531deSDag-Erling Smørgrav 			kflag = 1;
209bc5531deSDag-Erling Smørgrav 			break;
210bc5531deSDag-Erling Smørgrav 		case 'l':
211bc5531deSDag-Erling Smørgrav 			lflag = 1;
212bc5531deSDag-Erling Smørgrav 			break;
213bc5531deSDag-Erling Smørgrav 		case 'N':
214bc5531deSDag-Erling Smørgrav 			Nflag = 1;
215bc5531deSDag-Erling Smørgrav 			break;
216bc5531deSDag-Erling Smørgrav 		case 'n':
217bc5531deSDag-Erling Smørgrav 			nflag = 1;
218bc5531deSDag-Erling Smørgrav 			break;
219bc5531deSDag-Erling Smørgrav 		case 'P':
220bc5531deSDag-Erling Smørgrav 			Pflag = optarg;
221bc5531deSDag-Erling Smørgrav 			break;
222bc5531deSDag-Erling Smørgrav 		case 'p':
223bc5531deSDag-Erling Smørgrav 			pflag = optarg;
224bc5531deSDag-Erling Smørgrav 			break;
225bc5531deSDag-Erling Smørgrav 		case 'r':
226bc5531deSDag-Erling Smørgrav 			rflag = 1;
227bc5531deSDag-Erling Smørgrav 			break;
228bc5531deSDag-Erling Smørgrav 		case 's':
229bc5531deSDag-Erling Smørgrav 			sflag = optarg;
230bc5531deSDag-Erling Smørgrav 			break;
231bc5531deSDag-Erling Smørgrav 		case 't':
232bc5531deSDag-Erling Smørgrav 			tflag = 1;
233bc5531deSDag-Erling Smørgrav 			break;
234bc5531deSDag-Erling Smørgrav 		case 'u':
235bc5531deSDag-Erling Smørgrav 			uflag = 1;
236bc5531deSDag-Erling Smørgrav 			break;
237bc5531deSDag-Erling Smørgrav #ifdef SO_RTABLE
238bc5531deSDag-Erling Smørgrav 		case 'V':
239bc5531deSDag-Erling Smørgrav 			rtableid = (int)strtonum(optarg, 0,
240bc5531deSDag-Erling Smørgrav 			    RT_TABLEID_MAX, &errstr);
241bc5531deSDag-Erling Smørgrav 			if (errstr)
242bc5531deSDag-Erling Smørgrav 				errx(1, "rtable %s: %s", errstr, optarg);
243bc5531deSDag-Erling Smørgrav 			break;
244bc5531deSDag-Erling Smørgrav #endif
245bc5531deSDag-Erling Smørgrav 		case 'v':
246bc5531deSDag-Erling Smørgrav 			vflag = 1;
247bc5531deSDag-Erling Smørgrav 			break;
248bc5531deSDag-Erling Smørgrav 		case 'w':
249bc5531deSDag-Erling Smørgrav 			timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr);
250bc5531deSDag-Erling Smørgrav 			if (errstr)
251bc5531deSDag-Erling Smørgrav 				errx(1, "timeout %s: %s", errstr, optarg);
252bc5531deSDag-Erling Smørgrav 			timeout *= 1000;
253bc5531deSDag-Erling Smørgrav 			break;
254bc5531deSDag-Erling Smørgrav 		case 'x':
255bc5531deSDag-Erling Smørgrav 			xflag = 1;
256bc5531deSDag-Erling Smørgrav 			if ((proxy = strdup(optarg)) == NULL)
257bc5531deSDag-Erling Smørgrav 				errx(1, "strdup");
258bc5531deSDag-Erling Smørgrav 			break;
259bc5531deSDag-Erling Smørgrav 		case 'z':
260bc5531deSDag-Erling Smørgrav 			zflag = 1;
261bc5531deSDag-Erling Smørgrav 			break;
262bc5531deSDag-Erling Smørgrav 		case 'D':
263bc5531deSDag-Erling Smørgrav 			Dflag = 1;
264bc5531deSDag-Erling Smørgrav 			break;
265bc5531deSDag-Erling Smørgrav 		case 'I':
266bc5531deSDag-Erling Smørgrav 			Iflag = strtonum(optarg, 1, 65536 << 14, &errstr);
267bc5531deSDag-Erling Smørgrav 			if (errstr != NULL)
268bc5531deSDag-Erling Smørgrav 				errx(1, "TCP receive window %s: %s",
269bc5531deSDag-Erling Smørgrav 				    errstr, optarg);
270bc5531deSDag-Erling Smørgrav 			break;
271bc5531deSDag-Erling Smørgrav 		case 'O':
272bc5531deSDag-Erling Smørgrav 			Oflag = strtonum(optarg, 1, 65536 << 14, &errstr);
273bc5531deSDag-Erling Smørgrav 			if (errstr != NULL)
274bc5531deSDag-Erling Smørgrav 				errx(1, "TCP send window %s: %s",
275bc5531deSDag-Erling Smørgrav 				    errstr, optarg);
276bc5531deSDag-Erling Smørgrav 			break;
277bc5531deSDag-Erling Smørgrav 		case 'S':
278bc5531deSDag-Erling Smørgrav 			Sflag = 1;
279bc5531deSDag-Erling Smørgrav 			break;
280bc5531deSDag-Erling Smørgrav 		case 'T':
281bc5531deSDag-Erling Smørgrav 			errstr = NULL;
282bc5531deSDag-Erling Smørgrav 			errno = 0;
283bc5531deSDag-Erling Smørgrav 			if (map_tos(optarg, &Tflag))
284bc5531deSDag-Erling Smørgrav 				break;
285bc5531deSDag-Erling Smørgrav 			if (strlen(optarg) > 1 && optarg[0] == '0' &&
286bc5531deSDag-Erling Smørgrav 			    optarg[1] == 'x')
287bc5531deSDag-Erling Smørgrav 				Tflag = (int)strtol(optarg, NULL, 16);
288bc5531deSDag-Erling Smørgrav 			else
289bc5531deSDag-Erling Smørgrav 				Tflag = (int)strtonum(optarg, 0, 255,
290bc5531deSDag-Erling Smørgrav 				    &errstr);
291bc5531deSDag-Erling Smørgrav 			if (Tflag < 0 || Tflag > 255 || errstr || errno)
292bc5531deSDag-Erling Smørgrav 				errx(1, "illegal tos value %s", optarg);
293bc5531deSDag-Erling Smørgrav 			break;
294bc5531deSDag-Erling Smørgrav 		default:
295bc5531deSDag-Erling Smørgrav 			usage(1);
296bc5531deSDag-Erling Smørgrav 		}
297bc5531deSDag-Erling Smørgrav 	}
298bc5531deSDag-Erling Smørgrav 	argc -= optind;
299bc5531deSDag-Erling Smørgrav 	argv += optind;
300bc5531deSDag-Erling Smørgrav 
301bc5531deSDag-Erling Smørgrav 	/* Cruft to make sure options are clean, and used properly. */
302bc5531deSDag-Erling Smørgrav 	if (argv[0] && !argv[1] && family == AF_UNIX) {
303bc5531deSDag-Erling Smørgrav 		host = argv[0];
304bc5531deSDag-Erling Smørgrav 		uport = NULL;
305bc5531deSDag-Erling Smørgrav 	} else if (argv[0] && !argv[1]) {
306bc5531deSDag-Erling Smørgrav 		if  (!lflag)
307bc5531deSDag-Erling Smørgrav 			usage(1);
308bc5531deSDag-Erling Smørgrav 		uport = argv[0];
309bc5531deSDag-Erling Smørgrav 		host = NULL;
310bc5531deSDag-Erling Smørgrav 	} else if (argv[0] && argv[1]) {
311bc5531deSDag-Erling Smørgrav 		host = argv[0];
312bc5531deSDag-Erling Smørgrav 		uport = argv[1];
313bc5531deSDag-Erling Smørgrav 	} else
314bc5531deSDag-Erling Smørgrav 		usage(1);
315bc5531deSDag-Erling Smørgrav 
316bc5531deSDag-Erling Smørgrav 	if (lflag && sflag)
317bc5531deSDag-Erling Smørgrav 		errx(1, "cannot use -s and -l");
318bc5531deSDag-Erling Smørgrav 	if (lflag && pflag)
319bc5531deSDag-Erling Smørgrav 		errx(1, "cannot use -p and -l");
320bc5531deSDag-Erling Smørgrav 	if (lflag && zflag)
321bc5531deSDag-Erling Smørgrav 		errx(1, "cannot use -z and -l");
322bc5531deSDag-Erling Smørgrav 	if (!lflag && kflag)
323bc5531deSDag-Erling Smørgrav 		errx(1, "must use -l with -k");
324bc5531deSDag-Erling Smørgrav 
325bc5531deSDag-Erling Smørgrav 	/* Get name of temporary socket for unix datagram client */
326bc5531deSDag-Erling Smørgrav 	if ((family == AF_UNIX) && uflag && !lflag) {
327bc5531deSDag-Erling Smørgrav 		if (sflag) {
328bc5531deSDag-Erling Smørgrav 			unix_dg_tmp_socket = sflag;
329bc5531deSDag-Erling Smørgrav 		} else {
330bc5531deSDag-Erling Smørgrav 			strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX",
331bc5531deSDag-Erling Smørgrav 				UNIX_DG_TMP_SOCKET_SIZE);
332bc5531deSDag-Erling Smørgrav 			if (mktemp(unix_dg_tmp_socket_buf) == NULL)
333bc5531deSDag-Erling Smørgrav 				err(1, "mktemp");
334bc5531deSDag-Erling Smørgrav 			unix_dg_tmp_socket = unix_dg_tmp_socket_buf;
335bc5531deSDag-Erling Smørgrav 		}
336bc5531deSDag-Erling Smørgrav 	}
337bc5531deSDag-Erling Smørgrav 
338bc5531deSDag-Erling Smørgrav 	/* Initialize addrinfo structure. */
339bc5531deSDag-Erling Smørgrav 	if (family != AF_UNIX) {
340bc5531deSDag-Erling Smørgrav 		memset(&hints, 0, sizeof(struct addrinfo));
341bc5531deSDag-Erling Smørgrav 		hints.ai_family = family;
342bc5531deSDag-Erling Smørgrav 		hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
343bc5531deSDag-Erling Smørgrav 		hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
344bc5531deSDag-Erling Smørgrav 		if (nflag)
345bc5531deSDag-Erling Smørgrav 			hints.ai_flags |= AI_NUMERICHOST;
346bc5531deSDag-Erling Smørgrav 	}
347bc5531deSDag-Erling Smørgrav 
348bc5531deSDag-Erling Smørgrav 	if (xflag) {
349bc5531deSDag-Erling Smørgrav 		if (uflag)
350bc5531deSDag-Erling Smørgrav 			errx(1, "no proxy support for UDP mode");
351bc5531deSDag-Erling Smørgrav 
352bc5531deSDag-Erling Smørgrav 		if (lflag)
353bc5531deSDag-Erling Smørgrav 			errx(1, "no proxy support for listen");
354bc5531deSDag-Erling Smørgrav 
355bc5531deSDag-Erling Smørgrav 		if (family == AF_UNIX)
356bc5531deSDag-Erling Smørgrav 			errx(1, "no proxy support for unix sockets");
357bc5531deSDag-Erling Smørgrav 
358bc5531deSDag-Erling Smørgrav 		/* XXX IPv6 transport to proxy would probably work */
359bc5531deSDag-Erling Smørgrav 		if (family == AF_INET6)
360bc5531deSDag-Erling Smørgrav 			errx(1, "no proxy support for IPv6");
361bc5531deSDag-Erling Smørgrav 
362bc5531deSDag-Erling Smørgrav 		if (sflag)
363bc5531deSDag-Erling Smørgrav 			errx(1, "no proxy support for local source address");
364bc5531deSDag-Erling Smørgrav 
365bc5531deSDag-Erling Smørgrav 		proxyhost = strsep(&proxy, ":");
366bc5531deSDag-Erling Smørgrav 		proxyport = proxy;
367bc5531deSDag-Erling Smørgrav 
368bc5531deSDag-Erling Smørgrav 		memset(&proxyhints, 0, sizeof(struct addrinfo));
369bc5531deSDag-Erling Smørgrav 		proxyhints.ai_family = family;
370bc5531deSDag-Erling Smørgrav 		proxyhints.ai_socktype = SOCK_STREAM;
371bc5531deSDag-Erling Smørgrav 		proxyhints.ai_protocol = IPPROTO_TCP;
372bc5531deSDag-Erling Smørgrav 		if (nflag)
373bc5531deSDag-Erling Smørgrav 			proxyhints.ai_flags |= AI_NUMERICHOST;
374bc5531deSDag-Erling Smørgrav 	}
375bc5531deSDag-Erling Smørgrav 
376bc5531deSDag-Erling Smørgrav 	if (lflag) {
377bc5531deSDag-Erling Smørgrav 		int connfd;
378bc5531deSDag-Erling Smørgrav 		ret = 0;
379bc5531deSDag-Erling Smørgrav 
380bc5531deSDag-Erling Smørgrav 		if (family == AF_UNIX) {
381bc5531deSDag-Erling Smørgrav 			if (uflag)
382bc5531deSDag-Erling Smørgrav 				s = unix_bind(host);
383bc5531deSDag-Erling Smørgrav 			else
384bc5531deSDag-Erling Smørgrav 				s = unix_listen(host);
385bc5531deSDag-Erling Smørgrav 		}
386bc5531deSDag-Erling Smørgrav 
387bc5531deSDag-Erling Smørgrav 		/* Allow only one connection at a time, but stay alive. */
388bc5531deSDag-Erling Smørgrav 		for (;;) {
389bc5531deSDag-Erling Smørgrav 			if (family != AF_UNIX)
390bc5531deSDag-Erling Smørgrav 				s = local_listen(host, uport, hints);
391bc5531deSDag-Erling Smørgrav 			if (s < 0)
392bc5531deSDag-Erling Smørgrav 				err(1, "local_listen");
393bc5531deSDag-Erling Smørgrav 			/*
394bc5531deSDag-Erling Smørgrav 			 * For UDP and -k, don't connect the socket, let it
395bc5531deSDag-Erling Smørgrav 			 * receive datagrams from multiple socket pairs.
396bc5531deSDag-Erling Smørgrav 			 */
397bc5531deSDag-Erling Smørgrav 			if (uflag && kflag)
398bc5531deSDag-Erling Smørgrav 				readwrite(s);
399bc5531deSDag-Erling Smørgrav 			/*
400bc5531deSDag-Erling Smørgrav 			 * For UDP and not -k, we will use recvfrom() initially
401bc5531deSDag-Erling Smørgrav 			 * to wait for a caller, then use the regular functions
402bc5531deSDag-Erling Smørgrav 			 * to talk to the caller.
403bc5531deSDag-Erling Smørgrav 			 */
404bc5531deSDag-Erling Smørgrav 			else if (uflag && !kflag) {
405bc5531deSDag-Erling Smørgrav 				int rv, plen;
406bc5531deSDag-Erling Smørgrav 				char buf[16384];
407bc5531deSDag-Erling Smørgrav 				struct sockaddr_storage z;
408bc5531deSDag-Erling Smørgrav 
409bc5531deSDag-Erling Smørgrav 				len = sizeof(z);
410bc5531deSDag-Erling Smørgrav 				plen = 2048;
411bc5531deSDag-Erling Smørgrav 				rv = recvfrom(s, buf, plen, MSG_PEEK,
412bc5531deSDag-Erling Smørgrav 				    (struct sockaddr *)&z, &len);
413bc5531deSDag-Erling Smørgrav 				if (rv < 0)
414bc5531deSDag-Erling Smørgrav 					err(1, "recvfrom");
415bc5531deSDag-Erling Smørgrav 
416bc5531deSDag-Erling Smørgrav 				rv = connect(s, (struct sockaddr *)&z, len);
417bc5531deSDag-Erling Smørgrav 				if (rv < 0)
418bc5531deSDag-Erling Smørgrav 					err(1, "connect");
419bc5531deSDag-Erling Smørgrav 
420bc5531deSDag-Erling Smørgrav 				if (vflag)
421bc5531deSDag-Erling Smørgrav 					report_connect((struct sockaddr *)&z, len);
422bc5531deSDag-Erling Smørgrav 
423bc5531deSDag-Erling Smørgrav 				readwrite(s);
424bc5531deSDag-Erling Smørgrav 			} else {
425bc5531deSDag-Erling Smørgrav 				len = sizeof(cliaddr);
426bc5531deSDag-Erling Smørgrav 				connfd = accept(s, (struct sockaddr *)&cliaddr,
427bc5531deSDag-Erling Smørgrav 				    &len);
428bc5531deSDag-Erling Smørgrav 				if (connfd == -1) {
429bc5531deSDag-Erling Smørgrav 					/* For now, all errnos are fatal */
430bc5531deSDag-Erling Smørgrav 					err(1, "accept");
431bc5531deSDag-Erling Smørgrav 				}
432bc5531deSDag-Erling Smørgrav 				if (vflag)
433bc5531deSDag-Erling Smørgrav 					report_connect((struct sockaddr *)&cliaddr, len);
434bc5531deSDag-Erling Smørgrav 
435bc5531deSDag-Erling Smørgrav 				readwrite(connfd);
436bc5531deSDag-Erling Smørgrav 				close(connfd);
437bc5531deSDag-Erling Smørgrav 			}
438bc5531deSDag-Erling Smørgrav 
439bc5531deSDag-Erling Smørgrav 			if (family != AF_UNIX)
440bc5531deSDag-Erling Smørgrav 				close(s);
441bc5531deSDag-Erling Smørgrav 			else if (uflag) {
442bc5531deSDag-Erling Smørgrav 				if (connect(s, NULL, 0) < 0)
443bc5531deSDag-Erling Smørgrav 					err(1, "connect");
444bc5531deSDag-Erling Smørgrav 			}
445bc5531deSDag-Erling Smørgrav 
446bc5531deSDag-Erling Smørgrav 			if (!kflag)
447bc5531deSDag-Erling Smørgrav 				break;
448bc5531deSDag-Erling Smørgrav 		}
449bc5531deSDag-Erling Smørgrav 	} else if (family == AF_UNIX) {
450bc5531deSDag-Erling Smørgrav 		ret = 0;
451bc5531deSDag-Erling Smørgrav 
452bc5531deSDag-Erling Smørgrav 		if ((s = unix_connect(host)) > 0 && !zflag) {
453bc5531deSDag-Erling Smørgrav 			readwrite(s);
454bc5531deSDag-Erling Smørgrav 			close(s);
455bc5531deSDag-Erling Smørgrav 		} else
456bc5531deSDag-Erling Smørgrav 			ret = 1;
457bc5531deSDag-Erling Smørgrav 
458bc5531deSDag-Erling Smørgrav 		if (uflag)
459bc5531deSDag-Erling Smørgrav 			unlink(unix_dg_tmp_socket);
460bc5531deSDag-Erling Smørgrav 		exit(ret);
461bc5531deSDag-Erling Smørgrav 
462bc5531deSDag-Erling Smørgrav 	} else {
463bc5531deSDag-Erling Smørgrav 		int i = 0;
464bc5531deSDag-Erling Smørgrav 
465bc5531deSDag-Erling Smørgrav 		/* Construct the portlist[] array. */
466bc5531deSDag-Erling Smørgrav 		build_ports(uport);
467bc5531deSDag-Erling Smørgrav 
468bc5531deSDag-Erling Smørgrav 		/* Cycle through portlist, connecting to each port. */
469bc5531deSDag-Erling Smørgrav 		for (i = 0; portlist[i] != NULL; i++) {
470bc5531deSDag-Erling Smørgrav 			if (s)
471bc5531deSDag-Erling Smørgrav 				close(s);
472bc5531deSDag-Erling Smørgrav 
473bc5531deSDag-Erling Smørgrav 			if (xflag)
474bc5531deSDag-Erling Smørgrav 				s = socks_connect(host, portlist[i], hints,
475bc5531deSDag-Erling Smørgrav 				    proxyhost, proxyport, proxyhints, socksv,
476bc5531deSDag-Erling Smørgrav 				    Pflag);
477bc5531deSDag-Erling Smørgrav 			else
478bc5531deSDag-Erling Smørgrav 				s = remote_connect(host, portlist[i], hints);
479bc5531deSDag-Erling Smørgrav 
480bc5531deSDag-Erling Smørgrav 			if (s < 0)
481bc5531deSDag-Erling Smørgrav 				continue;
482bc5531deSDag-Erling Smørgrav 
483bc5531deSDag-Erling Smørgrav 			ret = 0;
484bc5531deSDag-Erling Smørgrav 			if (vflag || zflag) {
485bc5531deSDag-Erling Smørgrav 				/* For UDP, make sure we are connected. */
486bc5531deSDag-Erling Smørgrav 				if (uflag) {
487bc5531deSDag-Erling Smørgrav 					if (udptest(s) == -1) {
488bc5531deSDag-Erling Smørgrav 						ret = 1;
489bc5531deSDag-Erling Smørgrav 						continue;
490bc5531deSDag-Erling Smørgrav 					}
491bc5531deSDag-Erling Smørgrav 				}
492bc5531deSDag-Erling Smørgrav 
493bc5531deSDag-Erling Smørgrav 				/* Don't look up port if -n. */
494bc5531deSDag-Erling Smørgrav 				if (nflag)
495bc5531deSDag-Erling Smørgrav 					sv = NULL;
496bc5531deSDag-Erling Smørgrav 				else {
497bc5531deSDag-Erling Smørgrav 					sv = getservbyport(
498bc5531deSDag-Erling Smørgrav 					    ntohs(atoi(portlist[i])),
499bc5531deSDag-Erling Smørgrav 					    uflag ? "udp" : "tcp");
500bc5531deSDag-Erling Smørgrav 				}
501bc5531deSDag-Erling Smørgrav 
502bc5531deSDag-Erling Smørgrav 				fprintf(stderr,
503bc5531deSDag-Erling Smørgrav 				    "Connection to %s %s port [%s/%s] "
504bc5531deSDag-Erling Smørgrav 				    "succeeded!\n", host, portlist[i],
505bc5531deSDag-Erling Smørgrav 				    uflag ? "udp" : "tcp",
506bc5531deSDag-Erling Smørgrav 				    sv ? sv->s_name : "*");
507bc5531deSDag-Erling Smørgrav 			}
508bc5531deSDag-Erling Smørgrav 			if (Fflag)
509bc5531deSDag-Erling Smørgrav 				fdpass(s);
510bc5531deSDag-Erling Smørgrav 			else if (!zflag)
511bc5531deSDag-Erling Smørgrav 				readwrite(s);
512bc5531deSDag-Erling Smørgrav 		}
513bc5531deSDag-Erling Smørgrav 	}
514bc5531deSDag-Erling Smørgrav 
515bc5531deSDag-Erling Smørgrav 	if (s)
516bc5531deSDag-Erling Smørgrav 		close(s);
517bc5531deSDag-Erling Smørgrav 
518bc5531deSDag-Erling Smørgrav 	exit(ret);
519bc5531deSDag-Erling Smørgrav }
520bc5531deSDag-Erling Smørgrav 
521bc5531deSDag-Erling Smørgrav /*
522bc5531deSDag-Erling Smørgrav  * unix_bind()
523bc5531deSDag-Erling Smørgrav  * Returns a unix socket bound to the given path
524bc5531deSDag-Erling Smørgrav  */
525bc5531deSDag-Erling Smørgrav int
unix_bind(char * path)526bc5531deSDag-Erling Smørgrav unix_bind(char *path)
527bc5531deSDag-Erling Smørgrav {
528bc5531deSDag-Erling Smørgrav 	struct sockaddr_un sun_sa;
529bc5531deSDag-Erling Smørgrav 	int s;
530bc5531deSDag-Erling Smørgrav 
531bc5531deSDag-Erling Smørgrav 	/* Create unix domain socket. */
532bc5531deSDag-Erling Smørgrav 	if ((s = socket(AF_UNIX, uflag ? SOCK_DGRAM : SOCK_STREAM,
533bc5531deSDag-Erling Smørgrav 	     0)) < 0)
534bc5531deSDag-Erling Smørgrav 		return (-1);
535bc5531deSDag-Erling Smørgrav 
536bc5531deSDag-Erling Smørgrav 	memset(&sun_sa, 0, sizeof(struct sockaddr_un));
537bc5531deSDag-Erling Smørgrav 	sun_sa.sun_family = AF_UNIX;
538bc5531deSDag-Erling Smørgrav 
539bc5531deSDag-Erling Smørgrav 	if (strlcpy(sun_sa.sun_path, path, sizeof(sun_sa.sun_path)) >=
540bc5531deSDag-Erling Smørgrav 	    sizeof(sun_sa.sun_path)) {
541bc5531deSDag-Erling Smørgrav 		close(s);
542bc5531deSDag-Erling Smørgrav 		errno = ENAMETOOLONG;
543bc5531deSDag-Erling Smørgrav 		return (-1);
544bc5531deSDag-Erling Smørgrav 	}
545bc5531deSDag-Erling Smørgrav 
546bc5531deSDag-Erling Smørgrav 	if (bind(s, (struct sockaddr *)&sun_sa, SUN_LEN(&sun_sa)) < 0) {
547bc5531deSDag-Erling Smørgrav 		close(s);
548bc5531deSDag-Erling Smørgrav 		return (-1);
549bc5531deSDag-Erling Smørgrav 	}
550bc5531deSDag-Erling Smørgrav 	return (s);
551bc5531deSDag-Erling Smørgrav }
552bc5531deSDag-Erling Smørgrav 
553bc5531deSDag-Erling Smørgrav /*
554bc5531deSDag-Erling Smørgrav  * unix_connect()
555bc5531deSDag-Erling Smørgrav  * Returns a socket connected to a local unix socket. Returns -1 on failure.
556bc5531deSDag-Erling Smørgrav  */
557bc5531deSDag-Erling Smørgrav int
unix_connect(char * path)558bc5531deSDag-Erling Smørgrav unix_connect(char *path)
559bc5531deSDag-Erling Smørgrav {
560bc5531deSDag-Erling Smørgrav 	struct sockaddr_un sun_sa;
561bc5531deSDag-Erling Smørgrav 	int s;
562bc5531deSDag-Erling Smørgrav 
563bc5531deSDag-Erling Smørgrav 	if (uflag) {
564bc5531deSDag-Erling Smørgrav 		if ((s = unix_bind(unix_dg_tmp_socket)) < 0)
565bc5531deSDag-Erling Smørgrav 			return (-1);
566bc5531deSDag-Erling Smørgrav 	} else {
567bc5531deSDag-Erling Smørgrav 		if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
568bc5531deSDag-Erling Smørgrav 			return (-1);
569bc5531deSDag-Erling Smørgrav 	}
570bc5531deSDag-Erling Smørgrav 	(void)fcntl(s, F_SETFD, FD_CLOEXEC);
571bc5531deSDag-Erling Smørgrav 
572bc5531deSDag-Erling Smørgrav 	memset(&sun_sa, 0, sizeof(struct sockaddr_un));
573bc5531deSDag-Erling Smørgrav 	sun_sa.sun_family = AF_UNIX;
574bc5531deSDag-Erling Smørgrav 
575bc5531deSDag-Erling Smørgrav 	if (strlcpy(sun_sa.sun_path, path, sizeof(sun_sa.sun_path)) >=
576bc5531deSDag-Erling Smørgrav 	    sizeof(sun_sa.sun_path)) {
577bc5531deSDag-Erling Smørgrav 		close(s);
578bc5531deSDag-Erling Smørgrav 		errno = ENAMETOOLONG;
579bc5531deSDag-Erling Smørgrav 		return (-1);
580bc5531deSDag-Erling Smørgrav 	}
581bc5531deSDag-Erling Smørgrav 	if (connect(s, (struct sockaddr *)&sun_sa, SUN_LEN(&sun_sa)) < 0) {
582bc5531deSDag-Erling Smørgrav 		close(s);
583bc5531deSDag-Erling Smørgrav 		return (-1);
584bc5531deSDag-Erling Smørgrav 	}
585bc5531deSDag-Erling Smørgrav 	return (s);
586bc5531deSDag-Erling Smørgrav 
587bc5531deSDag-Erling Smørgrav }
588bc5531deSDag-Erling Smørgrav 
589bc5531deSDag-Erling Smørgrav /*
590bc5531deSDag-Erling Smørgrav  * unix_listen()
591bc5531deSDag-Erling Smørgrav  * Create a unix domain socket, and listen on it.
592bc5531deSDag-Erling Smørgrav  */
593bc5531deSDag-Erling Smørgrav int
unix_listen(char * path)594bc5531deSDag-Erling Smørgrav unix_listen(char *path)
595bc5531deSDag-Erling Smørgrav {
596bc5531deSDag-Erling Smørgrav 	int s;
597bc5531deSDag-Erling Smørgrav 	if ((s = unix_bind(path)) < 0)
598bc5531deSDag-Erling Smørgrav 		return (-1);
599bc5531deSDag-Erling Smørgrav 
600bc5531deSDag-Erling Smørgrav 	if (listen(s, 5) < 0) {
601bc5531deSDag-Erling Smørgrav 		close(s);
602bc5531deSDag-Erling Smørgrav 		return (-1);
603bc5531deSDag-Erling Smørgrav 	}
604bc5531deSDag-Erling Smørgrav 	return (s);
605bc5531deSDag-Erling Smørgrav }
606bc5531deSDag-Erling Smørgrav 
607bc5531deSDag-Erling Smørgrav /*
608bc5531deSDag-Erling Smørgrav  * remote_connect()
609bc5531deSDag-Erling Smørgrav  * Returns a socket connected to a remote host. Properly binds to a local
610bc5531deSDag-Erling Smørgrav  * port or source address if needed. Returns -1 on failure.
611bc5531deSDag-Erling Smørgrav  */
612bc5531deSDag-Erling Smørgrav int
remote_connect(const char * host,const char * port,struct addrinfo hints)613bc5531deSDag-Erling Smørgrav remote_connect(const char *host, const char *port, struct addrinfo hints)
614bc5531deSDag-Erling Smørgrav {
615bc5531deSDag-Erling Smørgrav 	struct addrinfo *res, *res0;
616bc5531deSDag-Erling Smørgrav 	int s, error;
617bc5531deSDag-Erling Smørgrav #if defined(SO_RTABLE) || defined(SO_BINDANY)
618bc5531deSDag-Erling Smørgrav 	int on = 1;
619bc5531deSDag-Erling Smørgrav #endif
620bc5531deSDag-Erling Smørgrav 
621bc5531deSDag-Erling Smørgrav 	if ((error = getaddrinfo(host, port, &hints, &res)))
622bc5531deSDag-Erling Smørgrav 		errx(1, "getaddrinfo: %s", gai_strerror(error));
623bc5531deSDag-Erling Smørgrav 
624bc5531deSDag-Erling Smørgrav 	res0 = res;
625bc5531deSDag-Erling Smørgrav 	do {
626bc5531deSDag-Erling Smørgrav 		if ((s = socket(res0->ai_family, res0->ai_socktype,
627bc5531deSDag-Erling Smørgrav 		    res0->ai_protocol)) < 0)
628bc5531deSDag-Erling Smørgrav 			continue;
629bc5531deSDag-Erling Smørgrav 
630bc5531deSDag-Erling Smørgrav #ifdef SO_RTABLE
631bc5531deSDag-Erling Smørgrav 		if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_RTABLE,
632bc5531deSDag-Erling Smørgrav 		    &rtableid, sizeof(rtableid)) == -1))
633bc5531deSDag-Erling Smørgrav 			err(1, "setsockopt SO_RTABLE");
634bc5531deSDag-Erling Smørgrav #endif
635bc5531deSDag-Erling Smørgrav 		/* Bind to a local port or source address if specified. */
636bc5531deSDag-Erling Smørgrav 		if (sflag || pflag) {
637bc5531deSDag-Erling Smørgrav 			struct addrinfo ahints, *ares;
638bc5531deSDag-Erling Smørgrav 
639bc5531deSDag-Erling Smørgrav #ifdef SO_BINDANY
640bc5531deSDag-Erling Smørgrav 			/* try SO_BINDANY, but don't insist */
641bc5531deSDag-Erling Smørgrav 			setsockopt(s, SOL_SOCKET, SO_BINDANY, &on, sizeof(on));
642bc5531deSDag-Erling Smørgrav #endif
643bc5531deSDag-Erling Smørgrav 			memset(&ahints, 0, sizeof(struct addrinfo));
644bc5531deSDag-Erling Smørgrav 			ahints.ai_family = res0->ai_family;
645bc5531deSDag-Erling Smørgrav 			ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
646bc5531deSDag-Erling Smørgrav 			ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
647bc5531deSDag-Erling Smørgrav 			ahints.ai_flags = AI_PASSIVE;
648bc5531deSDag-Erling Smørgrav 			if ((error = getaddrinfo(sflag, pflag, &ahints, &ares)))
649bc5531deSDag-Erling Smørgrav 				errx(1, "getaddrinfo: %s", gai_strerror(error));
650bc5531deSDag-Erling Smørgrav 
651bc5531deSDag-Erling Smørgrav 			if (bind(s, (struct sockaddr *)ares->ai_addr,
652bc5531deSDag-Erling Smørgrav 			    ares->ai_addrlen) < 0)
653bc5531deSDag-Erling Smørgrav 				err(1, "bind failed");
654bc5531deSDag-Erling Smørgrav 			freeaddrinfo(ares);
655bc5531deSDag-Erling Smørgrav 		}
656bc5531deSDag-Erling Smørgrav 
657*19261079SEd Maste 		set_common_sockopts(s, res0->ai_family);
658bc5531deSDag-Erling Smørgrav 
659bc5531deSDag-Erling Smørgrav 		if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
660bc5531deSDag-Erling Smørgrav 			break;
661bc5531deSDag-Erling Smørgrav 		else if (vflag)
662bc5531deSDag-Erling Smørgrav 			warn("connect to %s port %s (%s) failed", host, port,
663bc5531deSDag-Erling Smørgrav 			    uflag ? "udp" : "tcp");
664bc5531deSDag-Erling Smørgrav 
665bc5531deSDag-Erling Smørgrav 		close(s);
666bc5531deSDag-Erling Smørgrav 		s = -1;
667bc5531deSDag-Erling Smørgrav 	} while ((res0 = res0->ai_next) != NULL);
668bc5531deSDag-Erling Smørgrav 
669bc5531deSDag-Erling Smørgrav 	freeaddrinfo(res);
670bc5531deSDag-Erling Smørgrav 
671bc5531deSDag-Erling Smørgrav 	return (s);
672bc5531deSDag-Erling Smørgrav }
673bc5531deSDag-Erling Smørgrav 
674bc5531deSDag-Erling Smørgrav int
timeout_connect(int s,const struct sockaddr * name,socklen_t namelen)675bc5531deSDag-Erling Smørgrav timeout_connect(int s, const struct sockaddr *name, socklen_t namelen)
676bc5531deSDag-Erling Smørgrav {
677bc5531deSDag-Erling Smørgrav 	struct pollfd pfd;
678bc5531deSDag-Erling Smørgrav 	socklen_t optlen;
679bc5531deSDag-Erling Smørgrav 	int flags = 0, optval;
680bc5531deSDag-Erling Smørgrav 	int ret;
681bc5531deSDag-Erling Smørgrav 
682bc5531deSDag-Erling Smørgrav 	if (timeout != -1) {
683bc5531deSDag-Erling Smørgrav 		flags = fcntl(s, F_GETFL, 0);
684bc5531deSDag-Erling Smørgrav 		if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
685bc5531deSDag-Erling Smørgrav 			err(1, "set non-blocking mode");
686bc5531deSDag-Erling Smørgrav 	}
687bc5531deSDag-Erling Smørgrav 
688bc5531deSDag-Erling Smørgrav 	if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) {
689bc5531deSDag-Erling Smørgrav 		pfd.fd = s;
690bc5531deSDag-Erling Smørgrav 		pfd.events = POLLOUT;
691bc5531deSDag-Erling Smørgrav 		if ((ret = poll(&pfd, 1, timeout)) == 1) {
692bc5531deSDag-Erling Smørgrav 			optlen = sizeof(optval);
693bc5531deSDag-Erling Smørgrav 			if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR,
694bc5531deSDag-Erling Smørgrav 			    &optval, &optlen)) == 0) {
695bc5531deSDag-Erling Smørgrav 				errno = optval;
696bc5531deSDag-Erling Smørgrav 				ret = optval == 0 ? 0 : -1;
697bc5531deSDag-Erling Smørgrav 			}
698bc5531deSDag-Erling Smørgrav 		} else if (ret == 0) {
699bc5531deSDag-Erling Smørgrav 			errno = ETIMEDOUT;
700bc5531deSDag-Erling Smørgrav 			ret = -1;
701bc5531deSDag-Erling Smørgrav 		} else
702bc5531deSDag-Erling Smørgrav 			err(1, "poll failed");
703bc5531deSDag-Erling Smørgrav 	}
704bc5531deSDag-Erling Smørgrav 
705bc5531deSDag-Erling Smørgrav 	if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1)
706bc5531deSDag-Erling Smørgrav 		err(1, "restoring flags");
707bc5531deSDag-Erling Smørgrav 
708bc5531deSDag-Erling Smørgrav 	return (ret);
709bc5531deSDag-Erling Smørgrav }
710bc5531deSDag-Erling Smørgrav 
711bc5531deSDag-Erling Smørgrav /*
712bc5531deSDag-Erling Smørgrav  * local_listen()
713bc5531deSDag-Erling Smørgrav  * Returns a socket listening on a local port, binds to specified source
714bc5531deSDag-Erling Smørgrav  * address. Returns -1 on failure.
715bc5531deSDag-Erling Smørgrav  */
716bc5531deSDag-Erling Smørgrav int
local_listen(char * host,char * port,struct addrinfo hints)717bc5531deSDag-Erling Smørgrav local_listen(char *host, char *port, struct addrinfo hints)
718bc5531deSDag-Erling Smørgrav {
719bc5531deSDag-Erling Smørgrav 	struct addrinfo *res, *res0;
720bc5531deSDag-Erling Smørgrav 	int s, ret, x = 1;
721bc5531deSDag-Erling Smørgrav 	int error;
722bc5531deSDag-Erling Smørgrav 
723bc5531deSDag-Erling Smørgrav 	/* Allow nodename to be null. */
724bc5531deSDag-Erling Smørgrav 	hints.ai_flags |= AI_PASSIVE;
725bc5531deSDag-Erling Smørgrav 
726bc5531deSDag-Erling Smørgrav 	/*
727bc5531deSDag-Erling Smørgrav 	 * In the case of binding to a wildcard address
728bc5531deSDag-Erling Smørgrav 	 * default to binding to an ipv4 address.
729bc5531deSDag-Erling Smørgrav 	 */
730bc5531deSDag-Erling Smørgrav 	if (host == NULL && hints.ai_family == AF_UNSPEC)
731bc5531deSDag-Erling Smørgrav 		hints.ai_family = AF_INET;
732bc5531deSDag-Erling Smørgrav 
733bc5531deSDag-Erling Smørgrav 	if ((error = getaddrinfo(host, port, &hints, &res)))
734bc5531deSDag-Erling Smørgrav 		errx(1, "getaddrinfo: %s", gai_strerror(error));
735bc5531deSDag-Erling Smørgrav 
736bc5531deSDag-Erling Smørgrav 	res0 = res;
737bc5531deSDag-Erling Smørgrav 	do {
738bc5531deSDag-Erling Smørgrav 		if ((s = socket(res0->ai_family, res0->ai_socktype,
739bc5531deSDag-Erling Smørgrav 		    res0->ai_protocol)) < 0)
740bc5531deSDag-Erling Smørgrav 			continue;
741bc5531deSDag-Erling Smørgrav 
742bc5531deSDag-Erling Smørgrav #ifdef SO_RTABLE
743bc5531deSDag-Erling Smørgrav 		if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_RTABLE,
744bc5531deSDag-Erling Smørgrav 		    &rtableid, sizeof(rtableid)) == -1))
745bc5531deSDag-Erling Smørgrav 			err(1, "setsockopt SO_RTABLE");
746bc5531deSDag-Erling Smørgrav #endif
747bc5531deSDag-Erling Smørgrav #ifdef SO_REUSEPORT
748bc5531deSDag-Erling Smørgrav 		ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));
749bc5531deSDag-Erling Smørgrav 		if (ret == -1)
75047dd1d1bSDag-Erling Smørgrav 			err(1, "setsockopt SO_REUSEPORT");
75147dd1d1bSDag-Erling Smørgrav #endif
75247dd1d1bSDag-Erling Smørgrav #ifdef SO_REUSEADDR
75347dd1d1bSDag-Erling Smørgrav 		ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
75447dd1d1bSDag-Erling Smørgrav 		if (ret == -1)
75547dd1d1bSDag-Erling Smørgrav 			err(1, "setsockopt SO_REUSEADDR");
756bc5531deSDag-Erling Smørgrav #endif
757*19261079SEd Maste 		set_common_sockopts(s, res0->ai_family);
758bc5531deSDag-Erling Smørgrav 
759bc5531deSDag-Erling Smørgrav 		if (bind(s, (struct sockaddr *)res0->ai_addr,
760bc5531deSDag-Erling Smørgrav 		    res0->ai_addrlen) == 0)
761bc5531deSDag-Erling Smørgrav 			break;
762bc5531deSDag-Erling Smørgrav 
763bc5531deSDag-Erling Smørgrav 		close(s);
764bc5531deSDag-Erling Smørgrav 		s = -1;
765bc5531deSDag-Erling Smørgrav 	} while ((res0 = res0->ai_next) != NULL);
766bc5531deSDag-Erling Smørgrav 
767bc5531deSDag-Erling Smørgrav 	if (!uflag && s != -1) {
768bc5531deSDag-Erling Smørgrav 		if (listen(s, 1) < 0)
769bc5531deSDag-Erling Smørgrav 			err(1, "listen");
770bc5531deSDag-Erling Smørgrav 	}
771bc5531deSDag-Erling Smørgrav 
772bc5531deSDag-Erling Smørgrav 	freeaddrinfo(res);
773bc5531deSDag-Erling Smørgrav 
774bc5531deSDag-Erling Smørgrav 	return (s);
775bc5531deSDag-Erling Smørgrav }
776bc5531deSDag-Erling Smørgrav 
777bc5531deSDag-Erling Smørgrav /*
778bc5531deSDag-Erling Smørgrav  * readwrite()
779bc5531deSDag-Erling Smørgrav  * Loop that polls on the network file descriptor and stdin.
780bc5531deSDag-Erling Smørgrav  */
781bc5531deSDag-Erling Smørgrav void
readwrite(int net_fd)782bc5531deSDag-Erling Smørgrav readwrite(int net_fd)
783bc5531deSDag-Erling Smørgrav {
784bc5531deSDag-Erling Smørgrav 	struct pollfd pfd[4];
785bc5531deSDag-Erling Smørgrav 	int stdin_fd = STDIN_FILENO;
786bc5531deSDag-Erling Smørgrav 	int stdout_fd = STDOUT_FILENO;
787bc5531deSDag-Erling Smørgrav 	unsigned char netinbuf[BUFSIZE];
788bc5531deSDag-Erling Smørgrav 	size_t netinbufpos = 0;
789bc5531deSDag-Erling Smørgrav 	unsigned char stdinbuf[BUFSIZE];
790bc5531deSDag-Erling Smørgrav 	size_t stdinbufpos = 0;
791bc5531deSDag-Erling Smørgrav 	int n, num_fds;
792bc5531deSDag-Erling Smørgrav 	ssize_t ret;
793bc5531deSDag-Erling Smørgrav 
794bc5531deSDag-Erling Smørgrav 	/* don't read from stdin if requested */
795bc5531deSDag-Erling Smørgrav 	if (dflag)
796bc5531deSDag-Erling Smørgrav 		stdin_fd = -1;
797bc5531deSDag-Erling Smørgrav 
798bc5531deSDag-Erling Smørgrav 	/* stdin */
799bc5531deSDag-Erling Smørgrav 	pfd[POLL_STDIN].fd = stdin_fd;
800bc5531deSDag-Erling Smørgrav 	pfd[POLL_STDIN].events = POLLIN;
801bc5531deSDag-Erling Smørgrav 
802bc5531deSDag-Erling Smørgrav 	/* network out */
803bc5531deSDag-Erling Smørgrav 	pfd[POLL_NETOUT].fd = net_fd;
804bc5531deSDag-Erling Smørgrav 	pfd[POLL_NETOUT].events = 0;
805bc5531deSDag-Erling Smørgrav 
806bc5531deSDag-Erling Smørgrav 	/* network in */
807bc5531deSDag-Erling Smørgrav 	pfd[POLL_NETIN].fd = net_fd;
808bc5531deSDag-Erling Smørgrav 	pfd[POLL_NETIN].events = POLLIN;
809bc5531deSDag-Erling Smørgrav 
810bc5531deSDag-Erling Smørgrav 	/* stdout */
811bc5531deSDag-Erling Smørgrav 	pfd[POLL_STDOUT].fd = stdout_fd;
812bc5531deSDag-Erling Smørgrav 	pfd[POLL_STDOUT].events = 0;
813bc5531deSDag-Erling Smørgrav 
814bc5531deSDag-Erling Smørgrav 	while (1) {
815bc5531deSDag-Erling Smørgrav 		/* both inputs are gone, buffers are empty, we are done */
816bc5531deSDag-Erling Smørgrav 		if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1
817bc5531deSDag-Erling Smørgrav 		    && stdinbufpos == 0 && netinbufpos == 0) {
818bc5531deSDag-Erling Smørgrav 			close(net_fd);
819bc5531deSDag-Erling Smørgrav 			return;
820bc5531deSDag-Erling Smørgrav 		}
821bc5531deSDag-Erling Smørgrav 		/* both outputs are gone, we can't continue */
822bc5531deSDag-Erling Smørgrav 		if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) {
823bc5531deSDag-Erling Smørgrav 			close(net_fd);
824bc5531deSDag-Erling Smørgrav 			return;
825bc5531deSDag-Erling Smørgrav 		}
826bc5531deSDag-Erling Smørgrav 		/* listen and net in gone, queues empty, done */
827bc5531deSDag-Erling Smørgrav 		if (lflag && pfd[POLL_NETIN].fd == -1
828bc5531deSDag-Erling Smørgrav 		    && stdinbufpos == 0 && netinbufpos == 0) {
829bc5531deSDag-Erling Smørgrav 			close(net_fd);
830bc5531deSDag-Erling Smørgrav 			return;
831bc5531deSDag-Erling Smørgrav 		}
832bc5531deSDag-Erling Smørgrav 
833bc5531deSDag-Erling Smørgrav 		/* help says -i is for "wait between lines sent". We read and
834bc5531deSDag-Erling Smørgrav 		 * write arbitrary amounts of data, and we don't want to start
835bc5531deSDag-Erling Smørgrav 		 * scanning for newlines, so this is as good as it gets */
836bc5531deSDag-Erling Smørgrav 		if (iflag)
837bc5531deSDag-Erling Smørgrav 			sleep(iflag);
838bc5531deSDag-Erling Smørgrav 
839bc5531deSDag-Erling Smørgrav 		/* poll */
840bc5531deSDag-Erling Smørgrav 		num_fds = poll(pfd, 4, timeout);
841bc5531deSDag-Erling Smørgrav 
842bc5531deSDag-Erling Smørgrav 		/* treat poll errors */
843bc5531deSDag-Erling Smørgrav 		if (num_fds == -1) {
844bc5531deSDag-Erling Smørgrav 			close(net_fd);
845bc5531deSDag-Erling Smørgrav 			err(1, "polling error");
846bc5531deSDag-Erling Smørgrav 		}
847bc5531deSDag-Erling Smørgrav 
848bc5531deSDag-Erling Smørgrav 		/* timeout happened */
849bc5531deSDag-Erling Smørgrav 		if (num_fds == 0)
850bc5531deSDag-Erling Smørgrav 			return;
851bc5531deSDag-Erling Smørgrav 
852bc5531deSDag-Erling Smørgrav 		/* treat socket error conditions */
853bc5531deSDag-Erling Smørgrav 		for (n = 0; n < 4; n++) {
854bc5531deSDag-Erling Smørgrav 			if (pfd[n].revents & (POLLERR|POLLNVAL)) {
855bc5531deSDag-Erling Smørgrav 				pfd[n].fd = -1;
856bc5531deSDag-Erling Smørgrav 			}
857bc5531deSDag-Erling Smørgrav 		}
858bc5531deSDag-Erling Smørgrav 		/* reading is possible after HUP */
859bc5531deSDag-Erling Smørgrav 		if (pfd[POLL_STDIN].events & POLLIN &&
860bc5531deSDag-Erling Smørgrav 		    pfd[POLL_STDIN].revents & POLLHUP &&
861bc5531deSDag-Erling Smørgrav 		    ! (pfd[POLL_STDIN].revents & POLLIN))
862bc5531deSDag-Erling Smørgrav 				pfd[POLL_STDIN].fd = -1;
863bc5531deSDag-Erling Smørgrav 
864bc5531deSDag-Erling Smørgrav 		if (pfd[POLL_NETIN].events & POLLIN &&
865bc5531deSDag-Erling Smørgrav 		    pfd[POLL_NETIN].revents & POLLHUP &&
866bc5531deSDag-Erling Smørgrav 		    ! (pfd[POLL_NETIN].revents & POLLIN))
867bc5531deSDag-Erling Smørgrav 				pfd[POLL_NETIN].fd = -1;
868bc5531deSDag-Erling Smørgrav 
869bc5531deSDag-Erling Smørgrav 		if (pfd[POLL_NETOUT].revents & POLLHUP) {
870bc5531deSDag-Erling Smørgrav 			if (Nflag)
871bc5531deSDag-Erling Smørgrav 				shutdown(pfd[POLL_NETOUT].fd, SHUT_WR);
872bc5531deSDag-Erling Smørgrav 			pfd[POLL_NETOUT].fd = -1;
873bc5531deSDag-Erling Smørgrav 		}
874bc5531deSDag-Erling Smørgrav 		/* if HUP, stop watching stdout */
875bc5531deSDag-Erling Smørgrav 		if (pfd[POLL_STDOUT].revents & POLLHUP)
876bc5531deSDag-Erling Smørgrav 			pfd[POLL_STDOUT].fd = -1;
877bc5531deSDag-Erling Smørgrav 		/* if no net out, stop watching stdin */
878bc5531deSDag-Erling Smørgrav 		if (pfd[POLL_NETOUT].fd == -1)
879bc5531deSDag-Erling Smørgrav 			pfd[POLL_STDIN].fd = -1;
880bc5531deSDag-Erling Smørgrav 		/* if no stdout, stop watching net in */
881bc5531deSDag-Erling Smørgrav 		if (pfd[POLL_STDOUT].fd == -1) {
882bc5531deSDag-Erling Smørgrav 			if (pfd[POLL_NETIN].fd != -1)
883bc5531deSDag-Erling Smørgrav 				shutdown(pfd[POLL_NETIN].fd, SHUT_RD);
884bc5531deSDag-Erling Smørgrav 			pfd[POLL_NETIN].fd = -1;
885bc5531deSDag-Erling Smørgrav 		}
886bc5531deSDag-Erling Smørgrav 
887bc5531deSDag-Erling Smørgrav 		/* try to read from stdin */
888bc5531deSDag-Erling Smørgrav 		if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) {
889bc5531deSDag-Erling Smørgrav 			ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf,
890bc5531deSDag-Erling Smørgrav 			    &stdinbufpos);
891bc5531deSDag-Erling Smørgrav 			/* error or eof on stdin - remove from pfd */
892bc5531deSDag-Erling Smørgrav 			if (ret == 0 || ret == -1)
893bc5531deSDag-Erling Smørgrav 				pfd[POLL_STDIN].fd = -1;
894bc5531deSDag-Erling Smørgrav 			/* read something - poll net out */
895bc5531deSDag-Erling Smørgrav 			if (stdinbufpos > 0)
896bc5531deSDag-Erling Smørgrav 				pfd[POLL_NETOUT].events = POLLOUT;
897bc5531deSDag-Erling Smørgrav 			/* filled buffer - remove self from polling */
898bc5531deSDag-Erling Smørgrav 			if (stdinbufpos == BUFSIZE)
899bc5531deSDag-Erling Smørgrav 				pfd[POLL_STDIN].events = 0;
900bc5531deSDag-Erling Smørgrav 		}
901bc5531deSDag-Erling Smørgrav 		/* try to write to network */
902bc5531deSDag-Erling Smørgrav 		if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) {
903bc5531deSDag-Erling Smørgrav 			ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf,
904bc5531deSDag-Erling Smørgrav 			    &stdinbufpos);
905bc5531deSDag-Erling Smørgrav 			if (ret == -1)
906bc5531deSDag-Erling Smørgrav 				pfd[POLL_NETOUT].fd = -1;
907bc5531deSDag-Erling Smørgrav 			/* buffer empty - remove self from polling */
908bc5531deSDag-Erling Smørgrav 			if (stdinbufpos == 0)
909bc5531deSDag-Erling Smørgrav 				pfd[POLL_NETOUT].events = 0;
910bc5531deSDag-Erling Smørgrav 			/* buffer no longer full - poll stdin again */
911bc5531deSDag-Erling Smørgrav 			if (stdinbufpos < BUFSIZE)
912bc5531deSDag-Erling Smørgrav 				pfd[POLL_STDIN].events = POLLIN;
913bc5531deSDag-Erling Smørgrav 		}
914bc5531deSDag-Erling Smørgrav 		/* try to read from network */
915bc5531deSDag-Erling Smørgrav 		if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) {
916bc5531deSDag-Erling Smørgrav 			ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf,
917bc5531deSDag-Erling Smørgrav 			    &netinbufpos);
918bc5531deSDag-Erling Smørgrav 			if (ret == -1)
919bc5531deSDag-Erling Smørgrav 				pfd[POLL_NETIN].fd = -1;
920bc5531deSDag-Erling Smørgrav 			/* eof on net in - remove from pfd */
921bc5531deSDag-Erling Smørgrav 			if (ret == 0) {
922bc5531deSDag-Erling Smørgrav 				shutdown(pfd[POLL_NETIN].fd, SHUT_RD);
923bc5531deSDag-Erling Smørgrav 				pfd[POLL_NETIN].fd = -1;
924bc5531deSDag-Erling Smørgrav 			}
925bc5531deSDag-Erling Smørgrav 			/* read something - poll stdout */
926bc5531deSDag-Erling Smørgrav 			if (netinbufpos > 0)
927bc5531deSDag-Erling Smørgrav 				pfd[POLL_STDOUT].events = POLLOUT;
928bc5531deSDag-Erling Smørgrav 			/* filled buffer - remove self from polling */
929bc5531deSDag-Erling Smørgrav 			if (netinbufpos == BUFSIZE)
930bc5531deSDag-Erling Smørgrav 				pfd[POLL_NETIN].events = 0;
931bc5531deSDag-Erling Smørgrav 			/* handle telnet */
932bc5531deSDag-Erling Smørgrav 			if (tflag)
933bc5531deSDag-Erling Smørgrav 				atelnet(pfd[POLL_NETIN].fd, netinbuf,
934bc5531deSDag-Erling Smørgrav 				    netinbufpos);
935bc5531deSDag-Erling Smørgrav 		}
936bc5531deSDag-Erling Smørgrav 		/* try to write to stdout */
937bc5531deSDag-Erling Smørgrav 		if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) {
938bc5531deSDag-Erling Smørgrav 			ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf,
939bc5531deSDag-Erling Smørgrav 			    &netinbufpos);
940bc5531deSDag-Erling Smørgrav 			if (ret == -1)
941bc5531deSDag-Erling Smørgrav 				pfd[POLL_STDOUT].fd = -1;
942bc5531deSDag-Erling Smørgrav 			/* buffer empty - remove self from polling */
943bc5531deSDag-Erling Smørgrav 			if (netinbufpos == 0)
944bc5531deSDag-Erling Smørgrav 				pfd[POLL_STDOUT].events = 0;
945bc5531deSDag-Erling Smørgrav 			/* buffer no longer full - poll net in again */
946bc5531deSDag-Erling Smørgrav 			if (netinbufpos < BUFSIZE)
947bc5531deSDag-Erling Smørgrav 				pfd[POLL_NETIN].events = POLLIN;
948bc5531deSDag-Erling Smørgrav 		}
949bc5531deSDag-Erling Smørgrav 
950bc5531deSDag-Erling Smørgrav 		/* stdin gone and queue empty? */
951bc5531deSDag-Erling Smørgrav 		if (pfd[POLL_STDIN].fd == -1 && stdinbufpos == 0) {
952bc5531deSDag-Erling Smørgrav 			if (pfd[POLL_NETOUT].fd != -1 && Nflag)
953bc5531deSDag-Erling Smørgrav 				shutdown(pfd[POLL_NETOUT].fd, SHUT_WR);
954bc5531deSDag-Erling Smørgrav 			pfd[POLL_NETOUT].fd = -1;
955bc5531deSDag-Erling Smørgrav 		}
956bc5531deSDag-Erling Smørgrav 		/* net in gone and queue empty? */
957bc5531deSDag-Erling Smørgrav 		if (pfd[POLL_NETIN].fd == -1 && netinbufpos == 0) {
958bc5531deSDag-Erling Smørgrav 			pfd[POLL_STDOUT].fd = -1;
959bc5531deSDag-Erling Smørgrav 		}
960bc5531deSDag-Erling Smørgrav 	}
961bc5531deSDag-Erling Smørgrav }
962bc5531deSDag-Erling Smørgrav 
963bc5531deSDag-Erling Smørgrav ssize_t
drainbuf(int fd,unsigned char * buf,size_t * bufpos)964bc5531deSDag-Erling Smørgrav drainbuf(int fd, unsigned char *buf, size_t *bufpos)
965bc5531deSDag-Erling Smørgrav {
966bc5531deSDag-Erling Smørgrav 	ssize_t n;
967bc5531deSDag-Erling Smørgrav 	ssize_t adjust;
968bc5531deSDag-Erling Smørgrav 
969bc5531deSDag-Erling Smørgrav 	n = write(fd, buf, *bufpos);
970bc5531deSDag-Erling Smørgrav 	/* don't treat EAGAIN, EINTR as error */
971bc5531deSDag-Erling Smørgrav 	if (n == -1 && (errno == EAGAIN || errno == EINTR))
972bc5531deSDag-Erling Smørgrav 		n = -2;
973bc5531deSDag-Erling Smørgrav 	if (n <= 0)
974bc5531deSDag-Erling Smørgrav 		return n;
975bc5531deSDag-Erling Smørgrav 	/* adjust buffer */
976bc5531deSDag-Erling Smørgrav 	adjust = *bufpos - n;
977bc5531deSDag-Erling Smørgrav 	if (adjust > 0)
978bc5531deSDag-Erling Smørgrav 		memmove(buf, buf + n, adjust);
979bc5531deSDag-Erling Smørgrav 	*bufpos -= n;
980bc5531deSDag-Erling Smørgrav 	return n;
981bc5531deSDag-Erling Smørgrav }
982bc5531deSDag-Erling Smørgrav 
983bc5531deSDag-Erling Smørgrav 
984bc5531deSDag-Erling Smørgrav ssize_t
fillbuf(int fd,unsigned char * buf,size_t * bufpos)985bc5531deSDag-Erling Smørgrav fillbuf(int fd, unsigned char *buf, size_t *bufpos)
986bc5531deSDag-Erling Smørgrav {
987bc5531deSDag-Erling Smørgrav 	size_t num = BUFSIZE - *bufpos;
988bc5531deSDag-Erling Smørgrav 	ssize_t n;
989bc5531deSDag-Erling Smørgrav 
990bc5531deSDag-Erling Smørgrav 	n = read(fd, buf + *bufpos, num);
991bc5531deSDag-Erling Smørgrav 	/* don't treat EAGAIN, EINTR as error */
992bc5531deSDag-Erling Smørgrav 	if (n == -1 && (errno == EAGAIN || errno == EINTR))
993bc5531deSDag-Erling Smørgrav 		n = -2;
994bc5531deSDag-Erling Smørgrav 	if (n <= 0)
995bc5531deSDag-Erling Smørgrav 		return n;
996bc5531deSDag-Erling Smørgrav 	*bufpos += n;
997bc5531deSDag-Erling Smørgrav 	return n;
998bc5531deSDag-Erling Smørgrav }
999bc5531deSDag-Erling Smørgrav 
1000bc5531deSDag-Erling Smørgrav /*
1001bc5531deSDag-Erling Smørgrav  * fdpass()
1002bc5531deSDag-Erling Smørgrav  * Pass the connected file descriptor to stdout and exit.
1003bc5531deSDag-Erling Smørgrav  */
1004bc5531deSDag-Erling Smørgrav void
fdpass(int nfd)1005bc5531deSDag-Erling Smørgrav fdpass(int nfd)
1006bc5531deSDag-Erling Smørgrav {
1007bc5531deSDag-Erling Smørgrav #if defined(HAVE_SENDMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR))
1008bc5531deSDag-Erling Smørgrav 	struct msghdr msg;
1009bc5531deSDag-Erling Smørgrav #ifndef HAVE_ACCRIGHTS_IN_MSGHDR
1010bc5531deSDag-Erling Smørgrav 	union {
1011bc5531deSDag-Erling Smørgrav 		struct cmsghdr hdr;
1012bc5531deSDag-Erling Smørgrav 		char buf[CMSG_SPACE(sizeof(int))];
1013bc5531deSDag-Erling Smørgrav 	} cmsgbuf;
1014bc5531deSDag-Erling Smørgrav 	struct cmsghdr *cmsg;
1015bc5531deSDag-Erling Smørgrav #endif
1016bc5531deSDag-Erling Smørgrav 	struct iovec vec;
1017bc5531deSDag-Erling Smørgrav 	char ch = '\0';
1018bc5531deSDag-Erling Smørgrav 	struct pollfd pfd;
1019bc5531deSDag-Erling Smørgrav 	ssize_t r;
1020bc5531deSDag-Erling Smørgrav 
1021bc5531deSDag-Erling Smørgrav 	memset(&msg, 0, sizeof(msg));
1022bc5531deSDag-Erling Smørgrav #ifdef HAVE_ACCRIGHTS_IN_MSGHDR
1023bc5531deSDag-Erling Smørgrav 	msg.msg_accrights = (caddr_t)&nfd;
1024bc5531deSDag-Erling Smørgrav 	msg.msg_accrightslen = sizeof(nfd);
1025bc5531deSDag-Erling Smørgrav #else
1026bc5531deSDag-Erling Smørgrav 	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
1027bc5531deSDag-Erling Smørgrav 	msg.msg_control = (caddr_t)&cmsgbuf.buf;
1028bc5531deSDag-Erling Smørgrav 	msg.msg_controllen = sizeof(cmsgbuf.buf);
1029bc5531deSDag-Erling Smørgrav 	cmsg = CMSG_FIRSTHDR(&msg);
1030bc5531deSDag-Erling Smørgrav 	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
1031bc5531deSDag-Erling Smørgrav 	cmsg->cmsg_level = SOL_SOCKET;
1032bc5531deSDag-Erling Smørgrav 	cmsg->cmsg_type = SCM_RIGHTS;
1033bc5531deSDag-Erling Smørgrav 	*(int *)CMSG_DATA(cmsg) = nfd;
1034bc5531deSDag-Erling Smørgrav #endif
1035bc5531deSDag-Erling Smørgrav 
1036bc5531deSDag-Erling Smørgrav 	vec.iov_base = &ch;
1037bc5531deSDag-Erling Smørgrav 	vec.iov_len = 1;
1038bc5531deSDag-Erling Smørgrav 	msg.msg_iov = &vec;
1039bc5531deSDag-Erling Smørgrav 	msg.msg_iovlen = 1;
1040bc5531deSDag-Erling Smørgrav 
1041bc5531deSDag-Erling Smørgrav 	bzero(&pfd, sizeof(pfd));
1042bc5531deSDag-Erling Smørgrav 	pfd.fd = STDOUT_FILENO;
1043*19261079SEd Maste 	pfd.events = POLLOUT;
1044bc5531deSDag-Erling Smørgrav 	for (;;) {
1045bc5531deSDag-Erling Smørgrav 		r = sendmsg(STDOUT_FILENO, &msg, 0);
1046bc5531deSDag-Erling Smørgrav 		if (r == -1) {
1047bc5531deSDag-Erling Smørgrav 			if (errno == EAGAIN || errno == EINTR) {
1048bc5531deSDag-Erling Smørgrav 				if (poll(&pfd, 1, -1) == -1)
1049bc5531deSDag-Erling Smørgrav 					err(1, "poll");
1050bc5531deSDag-Erling Smørgrav 				continue;
1051bc5531deSDag-Erling Smørgrav 			}
1052bc5531deSDag-Erling Smørgrav 			err(1, "sendmsg");
1053*19261079SEd Maste 		} else if (r != 1)
1054bc5531deSDag-Erling Smørgrav 			errx(1, "sendmsg: unexpected return value %zd", r);
1055bc5531deSDag-Erling Smørgrav 		else
1056bc5531deSDag-Erling Smørgrav 			break;
1057bc5531deSDag-Erling Smørgrav 	}
1058bc5531deSDag-Erling Smørgrav 	exit(0);
1059bc5531deSDag-Erling Smørgrav #else
1060bc5531deSDag-Erling Smørgrav 	errx(1, "%s: file descriptor passing not supported", __func__);
1061bc5531deSDag-Erling Smørgrav #endif
1062bc5531deSDag-Erling Smørgrav }
1063bc5531deSDag-Erling Smørgrav 
1064bc5531deSDag-Erling Smørgrav /* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */
1065bc5531deSDag-Erling Smørgrav void
atelnet(int nfd,unsigned char * buf,unsigned int size)1066bc5531deSDag-Erling Smørgrav atelnet(int nfd, unsigned char *buf, unsigned int size)
1067bc5531deSDag-Erling Smørgrav {
1068bc5531deSDag-Erling Smørgrav 	unsigned char *p, *end;
1069bc5531deSDag-Erling Smørgrav 	unsigned char obuf[4];
1070bc5531deSDag-Erling Smørgrav 
1071bc5531deSDag-Erling Smørgrav 	if (size < 3)
1072bc5531deSDag-Erling Smørgrav 		return;
1073bc5531deSDag-Erling Smørgrav 	end = buf + size - 2;
1074bc5531deSDag-Erling Smørgrav 
1075bc5531deSDag-Erling Smørgrav 	for (p = buf; p < end; p++) {
1076bc5531deSDag-Erling Smørgrav 		if (*p != IAC)
1077bc5531deSDag-Erling Smørgrav 			continue;
1078bc5531deSDag-Erling Smørgrav 
1079bc5531deSDag-Erling Smørgrav 		obuf[0] = IAC;
1080bc5531deSDag-Erling Smørgrav 		p++;
1081bc5531deSDag-Erling Smørgrav 		if ((*p == WILL) || (*p == WONT))
1082bc5531deSDag-Erling Smørgrav 			obuf[1] = DONT;
1083bc5531deSDag-Erling Smørgrav 		else if ((*p == DO) || (*p == DONT))
1084bc5531deSDag-Erling Smørgrav 			obuf[1] = WONT;
1085bc5531deSDag-Erling Smørgrav 		else
1086bc5531deSDag-Erling Smørgrav 			continue;
1087bc5531deSDag-Erling Smørgrav 
1088bc5531deSDag-Erling Smørgrav 		p++;
1089bc5531deSDag-Erling Smørgrav 		obuf[2] = *p;
1090bc5531deSDag-Erling Smørgrav 		if (atomicio(vwrite, nfd, obuf, 3) != 3)
1091bc5531deSDag-Erling Smørgrav 			warn("Write Error!");
1092bc5531deSDag-Erling Smørgrav 	}
1093bc5531deSDag-Erling Smørgrav }
1094bc5531deSDag-Erling Smørgrav 
1095bc5531deSDag-Erling Smørgrav /*
1096bc5531deSDag-Erling Smørgrav  * build_ports()
1097bc5531deSDag-Erling Smørgrav  * Build an array of ports in portlist[], listing each port
1098bc5531deSDag-Erling Smørgrav  * that we should try to connect to.
1099bc5531deSDag-Erling Smørgrav  */
1100bc5531deSDag-Erling Smørgrav void
build_ports(char * p)1101bc5531deSDag-Erling Smørgrav build_ports(char *p)
1102bc5531deSDag-Erling Smørgrav {
1103bc5531deSDag-Erling Smørgrav 	const char *errstr;
1104bc5531deSDag-Erling Smørgrav 	char *n;
1105bc5531deSDag-Erling Smørgrav 	int hi, lo, cp;
1106bc5531deSDag-Erling Smørgrav 	int x = 0;
1107bc5531deSDag-Erling Smørgrav 
1108bc5531deSDag-Erling Smørgrav 	if ((n = strchr(p, '-')) != NULL) {
1109bc5531deSDag-Erling Smørgrav 		*n = '\0';
1110bc5531deSDag-Erling Smørgrav 		n++;
1111bc5531deSDag-Erling Smørgrav 
1112bc5531deSDag-Erling Smørgrav 		/* Make sure the ports are in order: lowest->highest. */
1113bc5531deSDag-Erling Smørgrav 		hi = strtonum(n, 1, PORT_MAX, &errstr);
1114bc5531deSDag-Erling Smørgrav 		if (errstr)
1115bc5531deSDag-Erling Smørgrav 			errx(1, "port number %s: %s", errstr, n);
1116bc5531deSDag-Erling Smørgrav 		lo = strtonum(p, 1, PORT_MAX, &errstr);
1117bc5531deSDag-Erling Smørgrav 		if (errstr)
1118bc5531deSDag-Erling Smørgrav 			errx(1, "port number %s: %s", errstr, p);
1119bc5531deSDag-Erling Smørgrav 
1120bc5531deSDag-Erling Smørgrav 		if (lo > hi) {
1121bc5531deSDag-Erling Smørgrav 			cp = hi;
1122bc5531deSDag-Erling Smørgrav 			hi = lo;
1123bc5531deSDag-Erling Smørgrav 			lo = cp;
1124bc5531deSDag-Erling Smørgrav 		}
1125bc5531deSDag-Erling Smørgrav 
1126bc5531deSDag-Erling Smørgrav 		/* Load ports sequentially. */
1127bc5531deSDag-Erling Smørgrav 		for (cp = lo; cp <= hi; cp++) {
1128bc5531deSDag-Erling Smørgrav 			portlist[x] = calloc(1, PORT_MAX_LEN);
1129bc5531deSDag-Erling Smørgrav 			if (portlist[x] == NULL)
1130bc5531deSDag-Erling Smørgrav 				errx(1, "calloc");
1131bc5531deSDag-Erling Smørgrav 			snprintf(portlist[x], PORT_MAX_LEN, "%d", cp);
1132bc5531deSDag-Erling Smørgrav 			x++;
1133bc5531deSDag-Erling Smørgrav 		}
1134bc5531deSDag-Erling Smørgrav 
1135bc5531deSDag-Erling Smørgrav 		/* Randomly swap ports. */
1136bc5531deSDag-Erling Smørgrav 		if (rflag) {
1137bc5531deSDag-Erling Smørgrav 			int y;
1138bc5531deSDag-Erling Smørgrav 			char *c;
1139bc5531deSDag-Erling Smørgrav 
1140bc5531deSDag-Erling Smørgrav 			for (x = 0; x <= (hi - lo); x++) {
1141bc5531deSDag-Erling Smørgrav 				y = (arc4random() & 0xFFFF) % (hi - lo);
1142bc5531deSDag-Erling Smørgrav 				c = portlist[x];
1143bc5531deSDag-Erling Smørgrav 				portlist[x] = portlist[y];
1144bc5531deSDag-Erling Smørgrav 				portlist[y] = c;
1145bc5531deSDag-Erling Smørgrav 			}
1146bc5531deSDag-Erling Smørgrav 		}
1147bc5531deSDag-Erling Smørgrav 	} else {
1148bc5531deSDag-Erling Smørgrav 		hi = strtonum(p, 1, PORT_MAX, &errstr);
1149bc5531deSDag-Erling Smørgrav 		if (errstr)
1150bc5531deSDag-Erling Smørgrav 			errx(1, "port number %s: %s", errstr, p);
1151bc5531deSDag-Erling Smørgrav 		portlist[0] = strdup(p);
1152bc5531deSDag-Erling Smørgrav 		if (portlist[0] == NULL)
1153bc5531deSDag-Erling Smørgrav 			errx(1, "strdup");
1154bc5531deSDag-Erling Smørgrav 	}
1155bc5531deSDag-Erling Smørgrav }
1156bc5531deSDag-Erling Smørgrav 
1157bc5531deSDag-Erling Smørgrav /*
1158bc5531deSDag-Erling Smørgrav  * udptest()
1159bc5531deSDag-Erling Smørgrav  * Do a few writes to see if the UDP port is there.
1160bc5531deSDag-Erling Smørgrav  * Fails once PF state table is full.
1161bc5531deSDag-Erling Smørgrav  */
1162bc5531deSDag-Erling Smørgrav int
udptest(int s)1163bc5531deSDag-Erling Smørgrav udptest(int s)
1164bc5531deSDag-Erling Smørgrav {
1165bc5531deSDag-Erling Smørgrav 	int i, ret;
1166bc5531deSDag-Erling Smørgrav 
1167bc5531deSDag-Erling Smørgrav 	for (i = 0; i <= 3; i++) {
1168bc5531deSDag-Erling Smørgrav 		if (write(s, "X", 1) == 1)
1169bc5531deSDag-Erling Smørgrav 			ret = 1;
1170bc5531deSDag-Erling Smørgrav 		else
1171bc5531deSDag-Erling Smørgrav 			ret = -1;
1172bc5531deSDag-Erling Smørgrav 	}
1173bc5531deSDag-Erling Smørgrav 	return (ret);
1174bc5531deSDag-Erling Smørgrav }
1175bc5531deSDag-Erling Smørgrav 
1176bc5531deSDag-Erling Smørgrav void
set_common_sockopts(int s,int af)1177*19261079SEd Maste set_common_sockopts(int s, int af)
1178bc5531deSDag-Erling Smørgrav {
1179bc5531deSDag-Erling Smørgrav 	int x = 1;
1180bc5531deSDag-Erling Smørgrav 
1181bc5531deSDag-Erling Smørgrav #ifdef TCP_MD5SIG
1182bc5531deSDag-Erling Smørgrav 	if (Sflag) {
1183bc5531deSDag-Erling Smørgrav 		if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG,
1184bc5531deSDag-Erling Smørgrav 			&x, sizeof(x)) == -1)
1185bc5531deSDag-Erling Smørgrav 			err(1, "setsockopt");
1186bc5531deSDag-Erling Smørgrav 	}
1187bc5531deSDag-Erling Smørgrav #endif
1188bc5531deSDag-Erling Smørgrav 	if (Dflag) {
1189bc5531deSDag-Erling Smørgrav 		if (setsockopt(s, SOL_SOCKET, SO_DEBUG,
1190bc5531deSDag-Erling Smørgrav 			&x, sizeof(x)) == -1)
1191bc5531deSDag-Erling Smørgrav 			err(1, "setsockopt");
1192bc5531deSDag-Erling Smørgrav 	}
1193*19261079SEd Maste #if defined(IP_TOS) && defined(IPV6_TCLASS)
1194bc5531deSDag-Erling Smørgrav 	if (Tflag != -1) {
1195*19261079SEd Maste 		int proto, option;
1196*19261079SEd Maste 
1197*19261079SEd Maste 		if (af == AF_INET6) {
1198*19261079SEd Maste 			proto = IPPROTO_IPV6;
1199*19261079SEd Maste 			option = IPV6_TCLASS;
1200*19261079SEd Maste 		} else {
1201*19261079SEd Maste 			proto = IPPROTO_IP;
1202*19261079SEd Maste 			option = IP_TOS;
1203*19261079SEd Maste 		}
1204*19261079SEd Maste 
1205*19261079SEd Maste 		if (setsockopt(s, proto, option, &Tflag, sizeof(Tflag)) == -1)
1206bc5531deSDag-Erling Smørgrav 			err(1, "set IP ToS");
1207bc5531deSDag-Erling Smørgrav 	}
1208*19261079SEd Maste #endif
1209bc5531deSDag-Erling Smørgrav 	if (Iflag) {
1210bc5531deSDag-Erling Smørgrav 		if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
1211bc5531deSDag-Erling Smørgrav 		    &Iflag, sizeof(Iflag)) == -1)
1212bc5531deSDag-Erling Smørgrav 			err(1, "set TCP receive buffer size");
1213bc5531deSDag-Erling Smørgrav 	}
1214bc5531deSDag-Erling Smørgrav 	if (Oflag) {
1215bc5531deSDag-Erling Smørgrav 		if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
1216bc5531deSDag-Erling Smørgrav 		    &Oflag, sizeof(Oflag)) == -1)
1217bc5531deSDag-Erling Smørgrav 			err(1, "set TCP send buffer size");
1218bc5531deSDag-Erling Smørgrav 	}
1219bc5531deSDag-Erling Smørgrav }
1220bc5531deSDag-Erling Smørgrav 
1221bc5531deSDag-Erling Smørgrav int
map_tos(char * s,int * val)1222bc5531deSDag-Erling Smørgrav map_tos(char *s, int *val)
1223bc5531deSDag-Erling Smørgrav {
1224*19261079SEd Maste #ifdef IP_TOS
1225bc5531deSDag-Erling Smørgrav 	/* DiffServ Codepoints and other TOS mappings */
1226bc5531deSDag-Erling Smørgrav 	const struct toskeywords {
1227bc5531deSDag-Erling Smørgrav 		const char	*keyword;
1228bc5531deSDag-Erling Smørgrav 		int		 val;
1229bc5531deSDag-Erling Smørgrav 	} *t, toskeywords[] = {
1230bc5531deSDag-Erling Smørgrav 		{ "af11",		IPTOS_DSCP_AF11 },
1231bc5531deSDag-Erling Smørgrav 		{ "af12",		IPTOS_DSCP_AF12 },
1232bc5531deSDag-Erling Smørgrav 		{ "af13",		IPTOS_DSCP_AF13 },
1233bc5531deSDag-Erling Smørgrav 		{ "af21",		IPTOS_DSCP_AF21 },
1234bc5531deSDag-Erling Smørgrav 		{ "af22",		IPTOS_DSCP_AF22 },
1235bc5531deSDag-Erling Smørgrav 		{ "af23",		IPTOS_DSCP_AF23 },
1236bc5531deSDag-Erling Smørgrav 		{ "af31",		IPTOS_DSCP_AF31 },
1237bc5531deSDag-Erling Smørgrav 		{ "af32",		IPTOS_DSCP_AF32 },
1238bc5531deSDag-Erling Smørgrav 		{ "af33",		IPTOS_DSCP_AF33 },
1239bc5531deSDag-Erling Smørgrav 		{ "af41",		IPTOS_DSCP_AF41 },
1240bc5531deSDag-Erling Smørgrav 		{ "af42",		IPTOS_DSCP_AF42 },
1241bc5531deSDag-Erling Smørgrav 		{ "af43",		IPTOS_DSCP_AF43 },
1242bc5531deSDag-Erling Smørgrav 		{ "critical",		IPTOS_PREC_CRITIC_ECP },
1243bc5531deSDag-Erling Smørgrav 		{ "cs0",		IPTOS_DSCP_CS0 },
1244bc5531deSDag-Erling Smørgrav 		{ "cs1",		IPTOS_DSCP_CS1 },
1245bc5531deSDag-Erling Smørgrav 		{ "cs2",		IPTOS_DSCP_CS2 },
1246bc5531deSDag-Erling Smørgrav 		{ "cs3",		IPTOS_DSCP_CS3 },
1247bc5531deSDag-Erling Smørgrav 		{ "cs4",		IPTOS_DSCP_CS4 },
1248bc5531deSDag-Erling Smørgrav 		{ "cs5",		IPTOS_DSCP_CS5 },
1249bc5531deSDag-Erling Smørgrav 		{ "cs6",		IPTOS_DSCP_CS6 },
1250bc5531deSDag-Erling Smørgrav 		{ "cs7",		IPTOS_DSCP_CS7 },
1251bc5531deSDag-Erling Smørgrav 		{ "ef",			IPTOS_DSCP_EF },
1252bc5531deSDag-Erling Smørgrav 		{ "inetcontrol",	IPTOS_PREC_INTERNETCONTROL },
1253bc5531deSDag-Erling Smørgrav 		{ "lowdelay",		IPTOS_LOWDELAY },
1254bc5531deSDag-Erling Smørgrav 		{ "netcontrol",		IPTOS_PREC_NETCONTROL },
1255bc5531deSDag-Erling Smørgrav 		{ "reliability",	IPTOS_RELIABILITY },
1256bc5531deSDag-Erling Smørgrav 		{ "throughput",		IPTOS_THROUGHPUT },
1257bc5531deSDag-Erling Smørgrav 		{ NULL, 		-1 },
1258bc5531deSDag-Erling Smørgrav 	};
1259bc5531deSDag-Erling Smørgrav 
1260bc5531deSDag-Erling Smørgrav 	for (t = toskeywords; t->keyword != NULL; t++) {
1261bc5531deSDag-Erling Smørgrav 		if (strcmp(s, t->keyword) == 0) {
1262bc5531deSDag-Erling Smørgrav 			*val = t->val;
1263bc5531deSDag-Erling Smørgrav 			return (1);
1264bc5531deSDag-Erling Smørgrav 		}
1265bc5531deSDag-Erling Smørgrav 	}
1266*19261079SEd Maste #endif
1267bc5531deSDag-Erling Smørgrav 
1268bc5531deSDag-Erling Smørgrav 	return (0);
1269bc5531deSDag-Erling Smørgrav }
1270bc5531deSDag-Erling Smørgrav 
1271bc5531deSDag-Erling Smørgrav void
report_connect(const struct sockaddr * sa,socklen_t salen)1272bc5531deSDag-Erling Smørgrav report_connect(const struct sockaddr *sa, socklen_t salen)
1273bc5531deSDag-Erling Smørgrav {
1274bc5531deSDag-Erling Smørgrav 	char remote_host[NI_MAXHOST];
1275bc5531deSDag-Erling Smørgrav 	char remote_port[NI_MAXSERV];
1276bc5531deSDag-Erling Smørgrav 	int herr;
1277bc5531deSDag-Erling Smørgrav 	int flags = NI_NUMERICSERV;
1278bc5531deSDag-Erling Smørgrav 
1279bc5531deSDag-Erling Smørgrav 	if (nflag)
1280bc5531deSDag-Erling Smørgrav 		flags |= NI_NUMERICHOST;
1281bc5531deSDag-Erling Smørgrav 
1282bc5531deSDag-Erling Smørgrav 	if ((herr = getnameinfo(sa, salen,
1283bc5531deSDag-Erling Smørgrav 	    remote_host, sizeof(remote_host),
1284bc5531deSDag-Erling Smørgrav 	    remote_port, sizeof(remote_port),
1285bc5531deSDag-Erling Smørgrav 	    flags)) != 0) {
1286bc5531deSDag-Erling Smørgrav 		if (herr == EAI_SYSTEM)
1287bc5531deSDag-Erling Smørgrav 			err(1, "getnameinfo");
1288bc5531deSDag-Erling Smørgrav 		else
1289bc5531deSDag-Erling Smørgrav 			errx(1, "getnameinfo: %s", gai_strerror(herr));
1290bc5531deSDag-Erling Smørgrav 	}
1291bc5531deSDag-Erling Smørgrav 
1292bc5531deSDag-Erling Smørgrav 	fprintf(stderr,
1293bc5531deSDag-Erling Smørgrav 	    "Connection from %s %s "
1294bc5531deSDag-Erling Smørgrav 	    "received!\n", remote_host, remote_port);
1295bc5531deSDag-Erling Smørgrav }
1296bc5531deSDag-Erling Smørgrav 
1297bc5531deSDag-Erling Smørgrav void
help(void)1298bc5531deSDag-Erling Smørgrav help(void)
1299bc5531deSDag-Erling Smørgrav {
1300bc5531deSDag-Erling Smørgrav 	usage(0);
1301bc5531deSDag-Erling Smørgrav 	fprintf(stderr, "\tCommand Summary:\n\
1302bc5531deSDag-Erling Smørgrav 	\t-4		Use IPv4\n\
1303bc5531deSDag-Erling Smørgrav 	\t-6		Use IPv6\n\
1304bc5531deSDag-Erling Smørgrav 	\t-D		Enable the debug socket option\n\
1305bc5531deSDag-Erling Smørgrav 	\t-d		Detach from stdin\n\
1306bc5531deSDag-Erling Smørgrav 	\t-F		Pass socket fd\n\
1307bc5531deSDag-Erling Smørgrav 	\t-h		This help text\n\
1308bc5531deSDag-Erling Smørgrav 	\t-I length	TCP receive buffer length\n\
1309bc5531deSDag-Erling Smørgrav 	\t-i secs\t	Delay interval for lines sent, ports scanned\n\
1310bc5531deSDag-Erling Smørgrav 	\t-k		Keep inbound sockets open for multiple connects\n\
1311bc5531deSDag-Erling Smørgrav 	\t-l		Listen mode, for inbound connects\n\
1312bc5531deSDag-Erling Smørgrav 	\t-N		Shutdown the network socket after EOF on stdin\n\
1313bc5531deSDag-Erling Smørgrav 	\t-n		Suppress name/port resolutions\n\
1314bc5531deSDag-Erling Smørgrav 	\t-O length	TCP send buffer length\n\
1315bc5531deSDag-Erling Smørgrav 	\t-P proxyuser\tUsername for proxy authentication\n\
1316bc5531deSDag-Erling Smørgrav 	\t-p port\t	Specify local port for remote connects\n\
1317bc5531deSDag-Erling Smørgrav 	\t-r		Randomize remote ports\n\
1318bc5531deSDag-Erling Smørgrav 	\t-S		Enable the TCP MD5 signature option\n\
1319bc5531deSDag-Erling Smørgrav 	\t-s addr\t	Local source address\n\
1320bc5531deSDag-Erling Smørgrav 	\t-T toskeyword\tSet IP Type of Service\n\
1321bc5531deSDag-Erling Smørgrav 	\t-t		Answer TELNET negotiation\n\
1322bc5531deSDag-Erling Smørgrav 	\t-U		Use UNIX domain socket\n\
1323bc5531deSDag-Erling Smørgrav 	\t-u		UDP mode\n\
1324bc5531deSDag-Erling Smørgrav 	\t-V rtable	Specify alternate routing table\n\
1325bc5531deSDag-Erling Smørgrav 	\t-v		Verbose\n\
1326bc5531deSDag-Erling Smørgrav 	\t-w secs\t	Timeout for connects and final net reads\n\
1327bc5531deSDag-Erling Smørgrav 	\t-X proto	Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\
1328bc5531deSDag-Erling Smørgrav 	\t-x addr[:port]\tSpecify proxy address and port\n\
1329bc5531deSDag-Erling Smørgrav 	\t-z		Zero-I/O mode [used for scanning]\n\
1330bc5531deSDag-Erling Smørgrav 	Port numbers can be individual or ranges: lo-hi [inclusive]\n");
1331bc5531deSDag-Erling Smørgrav 	exit(1);
1332bc5531deSDag-Erling Smørgrav }
1333bc5531deSDag-Erling Smørgrav 
1334bc5531deSDag-Erling Smørgrav void
usage(int ret)1335bc5531deSDag-Erling Smørgrav usage(int ret)
1336bc5531deSDag-Erling Smørgrav {
1337bc5531deSDag-Erling Smørgrav 	fprintf(stderr,
1338bc5531deSDag-Erling Smørgrav 	    "usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n"
1339*19261079SEd Maste 	    "\t  [-P proxy_username] [-p source_port] [-s source] [-T toskeyword]\n"
1340bc5531deSDag-Erling Smørgrav 	    "\t  [-V rtable] [-w timeout] [-X proxy_protocol]\n"
1341bc5531deSDag-Erling Smørgrav 	    "\t  [-x proxy_address[:port]] [destination] [port]\n");
1342bc5531deSDag-Erling Smørgrav 	if (ret)
1343bc5531deSDag-Erling Smørgrav 		exit(1);
1344bc5531deSDag-Erling Smørgrav }
1345bc5531deSDag-Erling Smørgrav 
1346bc5531deSDag-Erling Smørgrav /* *** src/usr.bin/nc/socks.c *** */
1347bc5531deSDag-Erling Smørgrav 
1348bc5531deSDag-Erling Smørgrav 
1349bc5531deSDag-Erling Smørgrav /*	$OpenBSD: socks.c,v 1.20 2012/03/08 09:56:28 espie Exp $	*/
1350bc5531deSDag-Erling Smørgrav 
1351bc5531deSDag-Erling Smørgrav /*
1352bc5531deSDag-Erling Smørgrav  * Copyright (c) 1999 Niklas Hallqvist.  All rights reserved.
1353bc5531deSDag-Erling Smørgrav  * Copyright (c) 2004, 2005 Damien Miller.  All rights reserved.
1354bc5531deSDag-Erling Smørgrav  *
1355bc5531deSDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
1356bc5531deSDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
1357bc5531deSDag-Erling Smørgrav  * are met:
1358bc5531deSDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
1359bc5531deSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer.
1360bc5531deSDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
1361bc5531deSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
1362bc5531deSDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
1363bc5531deSDag-Erling Smørgrav  *
1364bc5531deSDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1365bc5531deSDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1366bc5531deSDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1367bc5531deSDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1368bc5531deSDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1369bc5531deSDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1370bc5531deSDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1371bc5531deSDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1372bc5531deSDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1373bc5531deSDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1374bc5531deSDag-Erling Smørgrav  */
1375bc5531deSDag-Erling Smørgrav 
1376bc5531deSDag-Erling Smørgrav #include <sys/types.h>
1377bc5531deSDag-Erling Smørgrav #include <sys/socket.h>
1378bc5531deSDag-Erling Smørgrav #include <netinet/in.h>
1379bc5531deSDag-Erling Smørgrav #include <arpa/inet.h>
1380bc5531deSDag-Erling Smørgrav 
1381bc5531deSDag-Erling Smørgrav #include <errno.h>
1382bc5531deSDag-Erling Smørgrav #include <netdb.h>
1383bc5531deSDag-Erling Smørgrav #include <stdio.h>
1384bc5531deSDag-Erling Smørgrav #include <stdlib.h>
1385bc5531deSDag-Erling Smørgrav #include <string.h>
1386bc5531deSDag-Erling Smørgrav #include <unistd.h>
1387bc5531deSDag-Erling Smørgrav #include <resolv.h>
1388bc5531deSDag-Erling Smørgrav 
1389bc5531deSDag-Erling Smørgrav #define SOCKS_PORT	"1080"
1390bc5531deSDag-Erling Smørgrav #define HTTP_PROXY_PORT	"3128"
1391bc5531deSDag-Erling Smørgrav #define HTTP_MAXHDRS	64
1392bc5531deSDag-Erling Smørgrav #define SOCKS_V5	5
1393bc5531deSDag-Erling Smørgrav #define SOCKS_V4	4
1394bc5531deSDag-Erling Smørgrav #define SOCKS_NOAUTH	0
1395bc5531deSDag-Erling Smørgrav #define SOCKS_NOMETHOD	0xff
1396bc5531deSDag-Erling Smørgrav #define SOCKS_CONNECT	1
1397bc5531deSDag-Erling Smørgrav #define SOCKS_IPV4	1
1398bc5531deSDag-Erling Smørgrav #define SOCKS_DOMAIN	3
1399bc5531deSDag-Erling Smørgrav #define SOCKS_IPV6	4
1400bc5531deSDag-Erling Smørgrav 
1401bc5531deSDag-Erling Smørgrav int	remote_connect(const char *, const char *, struct addrinfo);
1402bc5531deSDag-Erling Smørgrav int	socks_connect(const char *, const char *, struct addrinfo,
1403bc5531deSDag-Erling Smørgrav 	    const char *, const char *, struct addrinfo, int,
1404bc5531deSDag-Erling Smørgrav 	    const char *);
1405bc5531deSDag-Erling Smørgrav 
1406bc5531deSDag-Erling Smørgrav static int
decode_addrport(const char * h,const char * p,struct sockaddr * addr,socklen_t addrlen,int v4only,int numeric)1407bc5531deSDag-Erling Smørgrav decode_addrport(const char *h, const char *p, struct sockaddr *addr,
1408bc5531deSDag-Erling Smørgrav     socklen_t addrlen, int v4only, int numeric)
1409bc5531deSDag-Erling Smørgrav {
1410bc5531deSDag-Erling Smørgrav 	int r;
1411bc5531deSDag-Erling Smørgrav 	struct addrinfo hints, *res;
1412bc5531deSDag-Erling Smørgrav 
1413bc5531deSDag-Erling Smørgrav 	bzero(&hints, sizeof(hints));
1414bc5531deSDag-Erling Smørgrav 	hints.ai_family = v4only ? PF_INET : PF_UNSPEC;
1415bc5531deSDag-Erling Smørgrav 	hints.ai_flags = numeric ? AI_NUMERICHOST : 0;
1416bc5531deSDag-Erling Smørgrav 	hints.ai_socktype = SOCK_STREAM;
1417bc5531deSDag-Erling Smørgrav 	r = getaddrinfo(h, p, &hints, &res);
1418bc5531deSDag-Erling Smørgrav 	/* Don't fatal when attempting to convert a numeric address */
1419bc5531deSDag-Erling Smørgrav 	if (r != 0) {
1420bc5531deSDag-Erling Smørgrav 		if (!numeric) {
1421bc5531deSDag-Erling Smørgrav 			errx(1, "getaddrinfo(\"%.64s\", \"%.64s\"): %s", h, p,
1422bc5531deSDag-Erling Smørgrav 			    gai_strerror(r));
1423bc5531deSDag-Erling Smørgrav 		}
1424bc5531deSDag-Erling Smørgrav 		return (-1);
1425bc5531deSDag-Erling Smørgrav 	}
1426bc5531deSDag-Erling Smørgrav 	if (addrlen < res->ai_addrlen) {
1427bc5531deSDag-Erling Smørgrav 		freeaddrinfo(res);
1428bc5531deSDag-Erling Smørgrav 		errx(1, "internal error: addrlen < res->ai_addrlen");
1429bc5531deSDag-Erling Smørgrav 	}
1430bc5531deSDag-Erling Smørgrav 	memcpy(addr, res->ai_addr, res->ai_addrlen);
1431bc5531deSDag-Erling Smørgrav 	freeaddrinfo(res);
1432bc5531deSDag-Erling Smørgrav 	return (0);
1433bc5531deSDag-Erling Smørgrav }
1434bc5531deSDag-Erling Smørgrav 
1435bc5531deSDag-Erling Smørgrav static int
proxy_read_line(int fd,char * buf,size_t bufsz)1436bc5531deSDag-Erling Smørgrav proxy_read_line(int fd, char *buf, size_t bufsz)
1437bc5531deSDag-Erling Smørgrav {
1438bc5531deSDag-Erling Smørgrav 	size_t off;
1439bc5531deSDag-Erling Smørgrav 
1440bc5531deSDag-Erling Smørgrav 	for(off = 0;;) {
1441bc5531deSDag-Erling Smørgrav 		if (off >= bufsz)
1442bc5531deSDag-Erling Smørgrav 			errx(1, "proxy read too long");
1443bc5531deSDag-Erling Smørgrav 		if (atomicio(read, fd, buf + off, 1) != 1)
1444bc5531deSDag-Erling Smørgrav 			err(1, "proxy read");
1445bc5531deSDag-Erling Smørgrav 		/* Skip CR */
1446bc5531deSDag-Erling Smørgrav 		if (buf[off] == '\r')
1447bc5531deSDag-Erling Smørgrav 			continue;
1448bc5531deSDag-Erling Smørgrav 		if (buf[off] == '\n') {
1449bc5531deSDag-Erling Smørgrav 			buf[off] = '\0';
1450bc5531deSDag-Erling Smørgrav 			break;
1451bc5531deSDag-Erling Smørgrav 		}
1452bc5531deSDag-Erling Smørgrav 		off++;
1453bc5531deSDag-Erling Smørgrav 	}
1454bc5531deSDag-Erling Smørgrav 	return (off);
1455bc5531deSDag-Erling Smørgrav }
1456bc5531deSDag-Erling Smørgrav 
1457bc5531deSDag-Erling Smørgrav static const char *
getproxypass(const char * proxyuser,const char * proxyhost)1458bc5531deSDag-Erling Smørgrav getproxypass(const char *proxyuser, const char *proxyhost)
1459bc5531deSDag-Erling Smørgrav {
1460bc5531deSDag-Erling Smørgrav 	char prompt[512];
1461bc5531deSDag-Erling Smørgrav 	static char pw[256];
1462bc5531deSDag-Erling Smørgrav 
1463bc5531deSDag-Erling Smørgrav 	snprintf(prompt, sizeof(prompt), "Proxy password for %s@%s: ",
1464bc5531deSDag-Erling Smørgrav 	   proxyuser, proxyhost);
1465bc5531deSDag-Erling Smørgrav 	if (readpassphrase(prompt, pw, sizeof(pw), RPP_REQUIRE_TTY) == NULL)
1466bc5531deSDag-Erling Smørgrav 		errx(1, "Unable to read proxy passphrase");
1467bc5531deSDag-Erling Smørgrav 	return (pw);
1468bc5531deSDag-Erling Smørgrav }
1469bc5531deSDag-Erling Smørgrav 
1470bc5531deSDag-Erling Smørgrav int
socks_connect(const char * host,const char * port,struct addrinfo hints,const char * proxyhost,const char * proxyport,struct addrinfo proxyhints,int socksv,const char * proxyuser)1471bc5531deSDag-Erling Smørgrav socks_connect(const char *host, const char *port,
1472bc5531deSDag-Erling Smørgrav     struct addrinfo hints __attribute__ ((__unused__)),
1473bc5531deSDag-Erling Smørgrav     const char *proxyhost, const char *proxyport, struct addrinfo proxyhints,
1474bc5531deSDag-Erling Smørgrav     int socksv, const char *proxyuser)
1475bc5531deSDag-Erling Smørgrav {
1476bc5531deSDag-Erling Smørgrav 	int proxyfd, r, authretry = 0;
1477bc5531deSDag-Erling Smørgrav 	size_t hlen, wlen = 0;
1478bc5531deSDag-Erling Smørgrav 	unsigned char buf[1024];
1479bc5531deSDag-Erling Smørgrav 	size_t cnt;
1480bc5531deSDag-Erling Smørgrav 	struct sockaddr_storage addr;
1481bc5531deSDag-Erling Smørgrav 	struct sockaddr_in *in4 = (struct sockaddr_in *)&addr;
1482bc5531deSDag-Erling Smørgrav 	struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr;
1483bc5531deSDag-Erling Smørgrav 	in_port_t serverport;
1484bc5531deSDag-Erling Smørgrav 	const char *proxypass = NULL;
1485bc5531deSDag-Erling Smørgrav 
1486bc5531deSDag-Erling Smørgrav 	if (proxyport == NULL)
1487bc5531deSDag-Erling Smørgrav 		proxyport = (socksv == -1) ? HTTP_PROXY_PORT : SOCKS_PORT;
1488bc5531deSDag-Erling Smørgrav 
1489bc5531deSDag-Erling Smørgrav 	/* Abuse API to lookup port */
1490bc5531deSDag-Erling Smørgrav 	if (decode_addrport("0.0.0.0", port, (struct sockaddr *)&addr,
1491bc5531deSDag-Erling Smørgrav 	    sizeof(addr), 1, 1) == -1)
1492bc5531deSDag-Erling Smørgrav 		errx(1, "unknown port \"%.64s\"", port);
1493bc5531deSDag-Erling Smørgrav 	serverport = in4->sin_port;
1494bc5531deSDag-Erling Smørgrav 
1495bc5531deSDag-Erling Smørgrav  again:
1496bc5531deSDag-Erling Smørgrav 	if (authretry++ > 3)
1497bc5531deSDag-Erling Smørgrav 		errx(1, "Too many authentication failures");
1498bc5531deSDag-Erling Smørgrav 
1499bc5531deSDag-Erling Smørgrav 	proxyfd = remote_connect(proxyhost, proxyport, proxyhints);
1500bc5531deSDag-Erling Smørgrav 
1501bc5531deSDag-Erling Smørgrav 	if (proxyfd < 0)
1502bc5531deSDag-Erling Smørgrav 		return (-1);
1503bc5531deSDag-Erling Smørgrav 
1504bc5531deSDag-Erling Smørgrav 	if (socksv == 5) {
1505bc5531deSDag-Erling Smørgrav 		if (decode_addrport(host, port, (struct sockaddr *)&addr,
1506bc5531deSDag-Erling Smørgrav 		    sizeof(addr), 0, 1) == -1)
1507bc5531deSDag-Erling Smørgrav 			addr.ss_family = 0; /* used in switch below */
1508bc5531deSDag-Erling Smørgrav 
1509bc5531deSDag-Erling Smørgrav 		/* Version 5, one method: no authentication */
1510bc5531deSDag-Erling Smørgrav 		buf[0] = SOCKS_V5;
1511bc5531deSDag-Erling Smørgrav 		buf[1] = 1;
1512bc5531deSDag-Erling Smørgrav 		buf[2] = SOCKS_NOAUTH;
1513bc5531deSDag-Erling Smørgrav 		cnt = atomicio(vwrite, proxyfd, buf, 3);
1514bc5531deSDag-Erling Smørgrav 		if (cnt != 3)
1515bc5531deSDag-Erling Smørgrav 			err(1, "write failed (%zu/3)", cnt);
1516bc5531deSDag-Erling Smørgrav 
1517bc5531deSDag-Erling Smørgrav 		cnt = atomicio(read, proxyfd, buf, 2);
1518bc5531deSDag-Erling Smørgrav 		if (cnt != 2)
1519bc5531deSDag-Erling Smørgrav 			err(1, "read failed (%zu/3)", cnt);
1520bc5531deSDag-Erling Smørgrav 
1521bc5531deSDag-Erling Smørgrav 		if (buf[1] == SOCKS_NOMETHOD)
1522bc5531deSDag-Erling Smørgrav 			errx(1, "authentication method negotiation failed");
1523bc5531deSDag-Erling Smørgrav 
1524bc5531deSDag-Erling Smørgrav 		switch (addr.ss_family) {
1525bc5531deSDag-Erling Smørgrav 		case 0:
1526bc5531deSDag-Erling Smørgrav 			/* Version 5, connect: domain name */
1527bc5531deSDag-Erling Smørgrav 
1528bc5531deSDag-Erling Smørgrav 			/* Max domain name length is 255 bytes */
1529bc5531deSDag-Erling Smørgrav 			hlen = strlen(host);
1530bc5531deSDag-Erling Smørgrav 			if (hlen > 255)
1531bc5531deSDag-Erling Smørgrav 				errx(1, "host name too long for SOCKS5");
1532bc5531deSDag-Erling Smørgrav 			buf[0] = SOCKS_V5;
1533bc5531deSDag-Erling Smørgrav 			buf[1] = SOCKS_CONNECT;
1534bc5531deSDag-Erling Smørgrav 			buf[2] = 0;
1535bc5531deSDag-Erling Smørgrav 			buf[3] = SOCKS_DOMAIN;
1536bc5531deSDag-Erling Smørgrav 			buf[4] = hlen;
1537bc5531deSDag-Erling Smørgrav 			memcpy(buf + 5, host, hlen);
1538bc5531deSDag-Erling Smørgrav 			memcpy(buf + 5 + hlen, &serverport, sizeof serverport);
1539bc5531deSDag-Erling Smørgrav 			wlen = 7 + hlen;
1540bc5531deSDag-Erling Smørgrav 			break;
1541bc5531deSDag-Erling Smørgrav 		case AF_INET:
1542bc5531deSDag-Erling Smørgrav 			/* Version 5, connect: IPv4 address */
1543bc5531deSDag-Erling Smørgrav 			buf[0] = SOCKS_V5;
1544bc5531deSDag-Erling Smørgrav 			buf[1] = SOCKS_CONNECT;
1545bc5531deSDag-Erling Smørgrav 			buf[2] = 0;
1546bc5531deSDag-Erling Smørgrav 			buf[3] = SOCKS_IPV4;
1547bc5531deSDag-Erling Smørgrav 			memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr);
1548bc5531deSDag-Erling Smørgrav 			memcpy(buf + 8, &in4->sin_port, sizeof in4->sin_port);
1549bc5531deSDag-Erling Smørgrav 			wlen = 10;
1550bc5531deSDag-Erling Smørgrav 			break;
1551bc5531deSDag-Erling Smørgrav 		case AF_INET6:
1552bc5531deSDag-Erling Smørgrav 			/* Version 5, connect: IPv6 address */
1553bc5531deSDag-Erling Smørgrav 			buf[0] = SOCKS_V5;
1554bc5531deSDag-Erling Smørgrav 			buf[1] = SOCKS_CONNECT;
1555bc5531deSDag-Erling Smørgrav 			buf[2] = 0;
1556bc5531deSDag-Erling Smørgrav 			buf[3] = SOCKS_IPV6;
1557bc5531deSDag-Erling Smørgrav 			memcpy(buf + 4, &in6->sin6_addr, sizeof in6->sin6_addr);
1558bc5531deSDag-Erling Smørgrav 			memcpy(buf + 20, &in6->sin6_port,
1559bc5531deSDag-Erling Smørgrav 			    sizeof in6->sin6_port);
1560bc5531deSDag-Erling Smørgrav 			wlen = 22;
1561bc5531deSDag-Erling Smørgrav 			break;
1562bc5531deSDag-Erling Smørgrav 		default:
1563bc5531deSDag-Erling Smørgrav 			errx(1, "internal error: silly AF");
1564bc5531deSDag-Erling Smørgrav 		}
1565bc5531deSDag-Erling Smørgrav 
1566bc5531deSDag-Erling Smørgrav 		cnt = atomicio(vwrite, proxyfd, buf, wlen);
1567bc5531deSDag-Erling Smørgrav 		if (cnt != wlen)
1568bc5531deSDag-Erling Smørgrav 			err(1, "write failed (%zu/%zu)", cnt, wlen);
1569bc5531deSDag-Erling Smørgrav 
1570bc5531deSDag-Erling Smørgrav 		cnt = atomicio(read, proxyfd, buf, 4);
1571bc5531deSDag-Erling Smørgrav 		if (cnt != 4)
1572bc5531deSDag-Erling Smørgrav 			err(1, "read failed (%zu/4)", cnt);
1573bc5531deSDag-Erling Smørgrav 		if (buf[1] != 0)
1574bc5531deSDag-Erling Smørgrav 			errx(1, "connection failed, SOCKS error %d", buf[1]);
1575bc5531deSDag-Erling Smørgrav 		switch (buf[3]) {
1576bc5531deSDag-Erling Smørgrav 		case SOCKS_IPV4:
1577bc5531deSDag-Erling Smørgrav 			cnt = atomicio(read, proxyfd, buf + 4, 6);
1578bc5531deSDag-Erling Smørgrav 			if (cnt != 6)
1579bc5531deSDag-Erling Smørgrav 				err(1, "read failed (%zu/6)", cnt);
1580bc5531deSDag-Erling Smørgrav 			break;
1581bc5531deSDag-Erling Smørgrav 		case SOCKS_IPV6:
1582bc5531deSDag-Erling Smørgrav 			cnt = atomicio(read, proxyfd, buf + 4, 18);
1583bc5531deSDag-Erling Smørgrav 			if (cnt != 18)
1584bc5531deSDag-Erling Smørgrav 				err(1, "read failed (%zu/18)", cnt);
1585bc5531deSDag-Erling Smørgrav 			break;
1586bc5531deSDag-Erling Smørgrav 		default:
1587bc5531deSDag-Erling Smørgrav 			errx(1, "connection failed, unsupported address type");
1588bc5531deSDag-Erling Smørgrav 		}
1589bc5531deSDag-Erling Smørgrav 	} else if (socksv == 4) {
1590bc5531deSDag-Erling Smørgrav 		/* This will exit on lookup failure */
1591bc5531deSDag-Erling Smørgrav 		decode_addrport(host, port, (struct sockaddr *)&addr,
1592bc5531deSDag-Erling Smørgrav 		    sizeof(addr), 1, 0);
1593bc5531deSDag-Erling Smørgrav 
1594bc5531deSDag-Erling Smørgrav 		/* Version 4 */
1595bc5531deSDag-Erling Smørgrav 		buf[0] = SOCKS_V4;
1596bc5531deSDag-Erling Smørgrav 		buf[1] = SOCKS_CONNECT;	/* connect */
1597bc5531deSDag-Erling Smørgrav 		memcpy(buf + 2, &in4->sin_port, sizeof in4->sin_port);
1598bc5531deSDag-Erling Smørgrav 		memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr);
1599bc5531deSDag-Erling Smørgrav 		buf[8] = 0;	/* empty username */
1600bc5531deSDag-Erling Smørgrav 		wlen = 9;
1601bc5531deSDag-Erling Smørgrav 
1602bc5531deSDag-Erling Smørgrav 		cnt = atomicio(vwrite, proxyfd, buf, wlen);
1603bc5531deSDag-Erling Smørgrav 		if (cnt != wlen)
1604bc5531deSDag-Erling Smørgrav 			err(1, "write failed (%zu/%zu)", cnt, wlen);
1605bc5531deSDag-Erling Smørgrav 
1606bc5531deSDag-Erling Smørgrav 		cnt = atomicio(read, proxyfd, buf, 8);
1607bc5531deSDag-Erling Smørgrav 		if (cnt != 8)
1608bc5531deSDag-Erling Smørgrav 			err(1, "read failed (%zu/8)", cnt);
1609bc5531deSDag-Erling Smørgrav 		if (buf[1] != 90)
1610bc5531deSDag-Erling Smørgrav 			errx(1, "connection failed, SOCKS error %d", buf[1]);
1611bc5531deSDag-Erling Smørgrav 	} else if (socksv == -1) {
1612bc5531deSDag-Erling Smørgrav 		/* HTTP proxy CONNECT */
1613bc5531deSDag-Erling Smørgrav 
1614bc5531deSDag-Erling Smørgrav 		/* Disallow bad chars in hostname */
1615bc5531deSDag-Erling Smørgrav 		if (strcspn(host, "\r\n\t []:") != strlen(host))
1616bc5531deSDag-Erling Smørgrav 			errx(1, "Invalid hostname");
1617bc5531deSDag-Erling Smørgrav 
1618bc5531deSDag-Erling Smørgrav 		/* Try to be sane about numeric IPv6 addresses */
1619bc5531deSDag-Erling Smørgrav 		if (strchr(host, ':') != NULL) {
1620bc5531deSDag-Erling Smørgrav 			r = snprintf(buf, sizeof(buf),
1621bc5531deSDag-Erling Smørgrav 			    "CONNECT [%s]:%d HTTP/1.0\r\n",
1622bc5531deSDag-Erling Smørgrav 			    host, ntohs(serverport));
1623bc5531deSDag-Erling Smørgrav 		} else {
1624bc5531deSDag-Erling Smørgrav 			r = snprintf(buf, sizeof(buf),
1625bc5531deSDag-Erling Smørgrav 			    "CONNECT %s:%d HTTP/1.0\r\n",
1626bc5531deSDag-Erling Smørgrav 			    host, ntohs(serverport));
1627bc5531deSDag-Erling Smørgrav 		}
1628bc5531deSDag-Erling Smørgrav 		if (r == -1 || (size_t)r >= sizeof(buf))
1629bc5531deSDag-Erling Smørgrav 			errx(1, "hostname too long");
1630bc5531deSDag-Erling Smørgrav 		r = strlen(buf);
1631bc5531deSDag-Erling Smørgrav 
1632bc5531deSDag-Erling Smørgrav 		cnt = atomicio(vwrite, proxyfd, buf, r);
1633bc5531deSDag-Erling Smørgrav 		if (cnt != (size_t)r)
1634bc5531deSDag-Erling Smørgrav 			err(1, "write failed (%zu/%d)", cnt, r);
1635bc5531deSDag-Erling Smørgrav 
1636bc5531deSDag-Erling Smørgrav 		if (authretry > 1) {
1637bc5531deSDag-Erling Smørgrav 			char resp[1024];
1638bc5531deSDag-Erling Smørgrav 
1639bc5531deSDag-Erling Smørgrav 			proxypass = getproxypass(proxyuser, proxyhost);
1640bc5531deSDag-Erling Smørgrav 			r = snprintf(buf, sizeof(buf), "%s:%s",
1641bc5531deSDag-Erling Smørgrav 			    proxyuser, proxypass);
1642bc5531deSDag-Erling Smørgrav 			if (r == -1 || (size_t)r >= sizeof(buf) ||
1643bc5531deSDag-Erling Smørgrav 			    b64_ntop(buf, strlen(buf), resp,
1644bc5531deSDag-Erling Smørgrav 			    sizeof(resp)) == -1)
1645bc5531deSDag-Erling Smørgrav 				errx(1, "Proxy username/password too long");
1646bc5531deSDag-Erling Smørgrav 			r = snprintf(buf, sizeof(buf), "Proxy-Authorization: "
1647bc5531deSDag-Erling Smørgrav 			    "Basic %s\r\n", resp);
1648bc5531deSDag-Erling Smørgrav 			if (r == -1 || (size_t)r >= sizeof(buf))
1649bc5531deSDag-Erling Smørgrav 				errx(1, "Proxy auth response too long");
1650bc5531deSDag-Erling Smørgrav 			r = strlen(buf);
1651bc5531deSDag-Erling Smørgrav 			if ((cnt = atomicio(vwrite, proxyfd, buf, r)) != (size_t)r)
1652bc5531deSDag-Erling Smørgrav 				err(1, "write failed (%zu/%d)", cnt, r);
1653bc5531deSDag-Erling Smørgrav 		}
1654bc5531deSDag-Erling Smørgrav 
1655bc5531deSDag-Erling Smørgrav 		/* Terminate headers */
1656bc5531deSDag-Erling Smørgrav 		if ((r = atomicio(vwrite, proxyfd, "\r\n", 2)) != 2)
1657bc5531deSDag-Erling Smørgrav 			err(1, "write failed (2/%d)", r);
1658bc5531deSDag-Erling Smørgrav 
1659bc5531deSDag-Erling Smørgrav 		/* Read status reply */
1660bc5531deSDag-Erling Smørgrav 		proxy_read_line(proxyfd, buf, sizeof(buf));
1661bc5531deSDag-Erling Smørgrav 		if (proxyuser != NULL &&
1662bc5531deSDag-Erling Smørgrav 		    strncmp(buf, "HTTP/1.0 407 ", 12) == 0) {
1663bc5531deSDag-Erling Smørgrav 			if (authretry > 1) {
1664bc5531deSDag-Erling Smørgrav 				fprintf(stderr, "Proxy authentication "
1665bc5531deSDag-Erling Smørgrav 				    "failed\n");
1666bc5531deSDag-Erling Smørgrav 			}
1667bc5531deSDag-Erling Smørgrav 			close(proxyfd);
1668bc5531deSDag-Erling Smørgrav 			goto again;
1669bc5531deSDag-Erling Smørgrav 		} else if (strncmp(buf, "HTTP/1.0 200 ", 12) != 0 &&
1670bc5531deSDag-Erling Smørgrav 		    strncmp(buf, "HTTP/1.1 200 ", 12) != 0)
1671bc5531deSDag-Erling Smørgrav 			errx(1, "Proxy error: \"%s\"", buf);
1672bc5531deSDag-Erling Smørgrav 
1673bc5531deSDag-Erling Smørgrav 		/* Headers continue until we hit an empty line */
1674bc5531deSDag-Erling Smørgrav 		for (r = 0; r < HTTP_MAXHDRS; r++) {
1675bc5531deSDag-Erling Smørgrav 			proxy_read_line(proxyfd, buf, sizeof(buf));
1676bc5531deSDag-Erling Smørgrav 			if (*buf == '\0')
1677bc5531deSDag-Erling Smørgrav 				break;
1678bc5531deSDag-Erling Smørgrav 		}
1679bc5531deSDag-Erling Smørgrav 		if (*buf != '\0')
1680bc5531deSDag-Erling Smørgrav 			errx(1, "Too many proxy headers received");
1681bc5531deSDag-Erling Smørgrav 	} else
1682bc5531deSDag-Erling Smørgrav 		errx(1, "Unknown proxy protocol %d", socksv);
1683bc5531deSDag-Erling Smørgrav 
1684bc5531deSDag-Erling Smørgrav 	return (proxyfd);
1685bc5531deSDag-Erling Smørgrav }
1686bc5531deSDag-Erling Smørgrav 
1687