xref: /dflybsd-src/crypto/libressl/apps/nc/netcat.c (revision 961e30ea7dc61d1112b778ea4981eac68129fb86)
1*de0e0e4dSAntonio Huete Jimenez /* $OpenBSD: netcat.c,v 1.219 2022/06/08 20:07:31 tb Exp $ */
2f5b1c8a1SJohn Marino /*
3f5b1c8a1SJohn Marino  * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
4f5b1c8a1SJohn Marino  * Copyright (c) 2015 Bob Beck.  All rights reserved.
5f5b1c8a1SJohn Marino  *
6f5b1c8a1SJohn Marino  * Redistribution and use in source and binary forms, with or without
7f5b1c8a1SJohn Marino  * modification, are permitted provided that the following conditions
8f5b1c8a1SJohn Marino  * are met:
9f5b1c8a1SJohn Marino  *
10f5b1c8a1SJohn Marino  * 1. Redistributions of source code must retain the above copyright
11f5b1c8a1SJohn Marino  *   notice, this list of conditions and the following disclaimer.
12f5b1c8a1SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
13f5b1c8a1SJohn Marino  *   notice, this list of conditions and the following disclaimer in the
14f5b1c8a1SJohn Marino  *   documentation and/or other materials provided with the distribution.
15f5b1c8a1SJohn Marino  * 3. The name of the author may not be used to endorse or promote products
16f5b1c8a1SJohn Marino  *   derived from this software without specific prior written permission.
17f5b1c8a1SJohn Marino  *
18f5b1c8a1SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19f5b1c8a1SJohn Marino  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20f5b1c8a1SJohn Marino  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21f5b1c8a1SJohn Marino  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22f5b1c8a1SJohn Marino  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23f5b1c8a1SJohn Marino  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24f5b1c8a1SJohn Marino  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25f5b1c8a1SJohn Marino  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26f5b1c8a1SJohn Marino  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27f5b1c8a1SJohn Marino  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28f5b1c8a1SJohn Marino  */
29f5b1c8a1SJohn Marino 
30f5b1c8a1SJohn Marino /*
31f5b1c8a1SJohn Marino  * Re-written nc(1) for OpenBSD. Original implementation by
32f5b1c8a1SJohn Marino  * *Hobbit* <hobbit@avian.org>.
33f5b1c8a1SJohn Marino  */
34f5b1c8a1SJohn Marino 
35f5b1c8a1SJohn Marino #include <sys/types.h>
36f5b1c8a1SJohn Marino #include <sys/socket.h>
37f5b1c8a1SJohn Marino #include <sys/uio.h>
38f5b1c8a1SJohn Marino #include <sys/un.h>
39f5b1c8a1SJohn Marino 
40f5b1c8a1SJohn Marino #include <netinet/in.h>
41f5b1c8a1SJohn Marino #include <netinet/tcp.h>
42f5b1c8a1SJohn Marino #include <netinet/ip.h>
43f5b1c8a1SJohn Marino #include <arpa/telnet.h>
44f5b1c8a1SJohn Marino 
4572c33676SMaxim Ag #include <ctype.h>
46f5b1c8a1SJohn Marino #include <err.h>
47f5b1c8a1SJohn Marino #include <errno.h>
48f5b1c8a1SJohn Marino #include <limits.h>
49f5b1c8a1SJohn Marino #include <netdb.h>
50f5b1c8a1SJohn Marino #include <poll.h>
51f5b1c8a1SJohn Marino #include <signal.h>
52f5b1c8a1SJohn Marino #include <stdarg.h>
53f5b1c8a1SJohn Marino #include <stdio.h>
54f5b1c8a1SJohn Marino #include <stdlib.h>
55f5b1c8a1SJohn Marino #include <string.h>
56f5b1c8a1SJohn Marino #include <time.h>
57f5b1c8a1SJohn Marino #include <tls.h>
5872c33676SMaxim Ag #include <unistd.h>
5972c33676SMaxim Ag 
60f5b1c8a1SJohn Marino #include "atomicio.h"
61f5b1c8a1SJohn Marino 
6240945e55Szrj #if !defined(OpenBSD)
6340945e55Szrj #define pledge(request, paths) 0
6440945e55Szrj #define unveil(path, permissions) 0
6540945e55Szrj #endif
6640945e55Szrj 
67f5b1c8a1SJohn Marino #define PORT_MAX	65535
68f5b1c8a1SJohn Marino #define UNIX_DG_TMP_SOCKET_SIZE	19
69f5b1c8a1SJohn Marino 
70f5b1c8a1SJohn Marino #define POLL_STDIN	0
71f5b1c8a1SJohn Marino #define POLL_NETOUT	1
72f5b1c8a1SJohn Marino #define POLL_NETIN	2
73f5b1c8a1SJohn Marino #define POLL_STDOUT	3
74f5b1c8a1SJohn Marino #define BUFSIZE		16384
75f5b1c8a1SJohn Marino 
7672c33676SMaxim Ag #define TLS_NOVERIFY	(1 << 1)
7772c33676SMaxim Ag #define TLS_NONAME	(1 << 2)
7872c33676SMaxim Ag #define TLS_CCERT	(1 << 3)
7972c33676SMaxim Ag #define TLS_MUSTSTAPLE	(1 << 4)
80f5b1c8a1SJohn Marino 
81f5b1c8a1SJohn Marino /* Command Line Options */
82f5b1c8a1SJohn Marino int	dflag;					/* detached, no stdin */
83f5b1c8a1SJohn Marino int	Fflag;					/* fdpass sock to stdout */
84f5b1c8a1SJohn Marino unsigned int iflag;				/* Interval Flag */
85f5b1c8a1SJohn Marino int	kflag;					/* More than one connect */
86f5b1c8a1SJohn Marino int	lflag;					/* Bind to local port */
87f5b1c8a1SJohn Marino int	Nflag;					/* shutdown() network socket */
88f5b1c8a1SJohn Marino int	nflag;					/* Don't do name look up */
89f5b1c8a1SJohn Marino char   *Pflag;					/* Proxy username */
90f5b1c8a1SJohn Marino char   *pflag;					/* Localport flag */
91f5b1c8a1SJohn Marino int	rflag;					/* Random ports flag */
92f5b1c8a1SJohn Marino char   *sflag;					/* Source Address */
93f5b1c8a1SJohn Marino int	tflag;					/* Telnet Emulation */
94f5b1c8a1SJohn Marino int	uflag;					/* UDP - Default to TCP */
95f5b1c8a1SJohn Marino int	vflag;					/* Verbosity */
96f5b1c8a1SJohn Marino int	xflag;					/* Socks proxy */
97f5b1c8a1SJohn Marino int	zflag;					/* Port Scan Flag */
98f5b1c8a1SJohn Marino int	Dflag;					/* sodebug */
99f5b1c8a1SJohn Marino int	Iflag;					/* TCP receive buffer size */
100f5b1c8a1SJohn Marino int	Oflag;					/* TCP send buffer size */
101f5b1c8a1SJohn Marino #ifdef TCP_MD5SIG
102f5b1c8a1SJohn Marino int	Sflag;					/* TCP MD5 signature option */
103f5b1c8a1SJohn Marino #endif
104f5b1c8a1SJohn Marino int	Tflag = -1;				/* IP Type of Service */
105f5b1c8a1SJohn Marino #ifdef SO_RTABLE
106f5b1c8a1SJohn Marino int	rtableid = -1;
107f5b1c8a1SJohn Marino #endif
108f5b1c8a1SJohn Marino 
109f5b1c8a1SJohn Marino int	usetls;					/* use TLS */
11072c33676SMaxim Ag const char    *Cflag;				/* Public cert file */
11172c33676SMaxim Ag const char    *Kflag;				/* Private key file */
11272c33676SMaxim Ag const char    *oflag;				/* OCSP stapling file */
11372c33676SMaxim Ag const char    *Rflag;				/* Root CA file */
114f5b1c8a1SJohn Marino int	tls_cachanged;				/* Using non-default CA file */
115f5b1c8a1SJohn Marino int     TLSopt;					/* TLS options */
116f5b1c8a1SJohn Marino char	*tls_expectname;			/* required name in peer cert */
117f5b1c8a1SJohn Marino char	*tls_expecthash;			/* required hash of peer cert */
11872c33676SMaxim Ag char	*tls_ciphers;				/* TLS ciphers */
11972c33676SMaxim Ag char	*tls_protocols;				/* TLS protocols */
12072c33676SMaxim Ag FILE	*Zflag;					/* file to save peer cert */
121f5b1c8a1SJohn Marino 
12272c33676SMaxim Ag int recvcount, recvlimit;
123f5b1c8a1SJohn Marino int timeout = -1;
124f5b1c8a1SJohn Marino int family = AF_UNSPEC;
125f5b1c8a1SJohn Marino char *portlist[PORT_MAX+1];
126f5b1c8a1SJohn Marino char *unix_dg_tmp_socket;
127f5b1c8a1SJohn Marino int ttl = -1;
128f5b1c8a1SJohn Marino int minttl = -1;
129f5b1c8a1SJohn Marino 
130f5b1c8a1SJohn Marino void	atelnet(int, unsigned char *, unsigned int);
13172c33676SMaxim Ag int	strtoport(char *portstr, int udp);
132f5b1c8a1SJohn Marino void	build_ports(char *);
13372c33676SMaxim Ag void	help(void) __attribute__((noreturn));
13472c33676SMaxim Ag int	local_listen(const char *, const char *, struct addrinfo);
135f5b1c8a1SJohn Marino void	readwrite(int, struct tls *);
136f5b1c8a1SJohn Marino void	fdpass(int nfd) __attribute__((noreturn));
137cca6fc52SDaniel Fojt int	remote_connect(const char *, const char *, struct addrinfo, char *);
13872c33676SMaxim Ag int	timeout_tls(int, struct tls *, int (*)(struct tls *));
139f5b1c8a1SJohn Marino int	timeout_connect(int, const struct sockaddr *, socklen_t);
140f5b1c8a1SJohn Marino int	socks_connect(const char *, const char *, struct addrinfo,
141f5b1c8a1SJohn Marino 	    const char *, const char *, struct addrinfo, int, const char *);
142f5b1c8a1SJohn Marino int	udptest(int);
143f5b1c8a1SJohn Marino int	unix_bind(char *, int);
144f5b1c8a1SJohn Marino int	unix_connect(char *);
145f5b1c8a1SJohn Marino int	unix_listen(char *);
146f5b1c8a1SJohn Marino void	set_common_sockopts(int, int);
14772c33676SMaxim Ag int	process_tos_opt(char *, int *);
14872c33676SMaxim Ag int	process_tls_opt(char *, int *);
14972c33676SMaxim Ag void	save_peer_cert(struct tls *_tls_ctx, FILE *_fp);
15072c33676SMaxim Ag void	report_sock(const char *, const struct sockaddr *, socklen_t, char *);
15172c33676SMaxim Ag void	report_tls(struct tls *tls_ctx, char * host);
152f5b1c8a1SJohn Marino void	usage(int);
153f5b1c8a1SJohn Marino ssize_t drainbuf(int, unsigned char *, size_t *, struct tls *);
154f5b1c8a1SJohn Marino ssize_t fillbuf(int, unsigned char *, size_t *, struct tls *);
155f5b1c8a1SJohn Marino void	tls_setup_client(struct tls *, int, char *);
156f5b1c8a1SJohn Marino struct tls *tls_setup_server(struct tls *, int, char *);
157f5b1c8a1SJohn Marino 
158f5b1c8a1SJohn Marino int
main(int argc,char * argv[])159f5b1c8a1SJohn Marino main(int argc, char *argv[])
160f5b1c8a1SJohn Marino {
161f5b1c8a1SJohn Marino 	int ch, s = -1, ret, socksv;
162f5b1c8a1SJohn Marino 	char *host, *uport;
163cca6fc52SDaniel Fojt 	char ipaddr[NI_MAXHOST];
164f5b1c8a1SJohn Marino 	struct addrinfo hints;
165f5b1c8a1SJohn Marino 	struct servent *sv;
166f5b1c8a1SJohn Marino 	socklen_t len;
167f5b1c8a1SJohn Marino 	struct sockaddr_storage cliaddr;
16872c33676SMaxim Ag 	char *proxy = NULL, *proxyport = NULL;
16972c33676SMaxim Ag 	const char *errstr;
170f5b1c8a1SJohn Marino 	struct addrinfo proxyhints;
171f5b1c8a1SJohn Marino 	char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE];
172f5b1c8a1SJohn Marino 	struct tls_config *tls_cfg = NULL;
173f5b1c8a1SJohn Marino 	struct tls *tls_ctx = NULL;
17472c33676SMaxim Ag 	uint32_t protocols;
175f5b1c8a1SJohn Marino 
176f5b1c8a1SJohn Marino 	ret = 1;
177f5b1c8a1SJohn Marino 	socksv = 5;
178f5b1c8a1SJohn Marino 	host = NULL;
179f5b1c8a1SJohn Marino 	uport = NULL;
180f5b1c8a1SJohn Marino 	sv = NULL;
18172c33676SMaxim Ag 	Rflag = tls_default_ca_cert_file();
182f5b1c8a1SJohn Marino 
183f5b1c8a1SJohn Marino 	signal(SIGPIPE, SIG_IGN);
184f5b1c8a1SJohn Marino 
185f5b1c8a1SJohn Marino 	while ((ch = getopt(argc, argv,
18672c33676SMaxim Ag 	    "46C:cDde:FH:hI:i:K:klM:m:NnO:o:P:p:R:rSs:T:tUuV:vW:w:X:x:Z:z"))
18772c33676SMaxim Ag 	    != -1) {
188f5b1c8a1SJohn Marino 		switch (ch) {
189f5b1c8a1SJohn Marino 		case '4':
190f5b1c8a1SJohn Marino 			family = AF_INET;
191f5b1c8a1SJohn Marino 			break;
192f5b1c8a1SJohn Marino 		case '6':
193f5b1c8a1SJohn Marino 			family = AF_INET6;
194f5b1c8a1SJohn Marino 			break;
195f5b1c8a1SJohn Marino 		case 'U':
196f5b1c8a1SJohn Marino 			family = AF_UNIX;
197f5b1c8a1SJohn Marino 			break;
198f5b1c8a1SJohn Marino 		case 'X':
199f5b1c8a1SJohn Marino 			if (strcasecmp(optarg, "connect") == 0)
200f5b1c8a1SJohn Marino 				socksv = -1; /* HTTP proxy CONNECT */
201f5b1c8a1SJohn Marino 			else if (strcmp(optarg, "4") == 0)
202f5b1c8a1SJohn Marino 				socksv = 4; /* SOCKS v.4 */
203f5b1c8a1SJohn Marino 			else if (strcmp(optarg, "5") == 0)
204f5b1c8a1SJohn Marino 				socksv = 5; /* SOCKS v.5 */
205f5b1c8a1SJohn Marino 			else
206f5b1c8a1SJohn Marino 				errx(1, "unsupported proxy protocol");
207f5b1c8a1SJohn Marino 			break;
208f5b1c8a1SJohn Marino 		case 'C':
209f5b1c8a1SJohn Marino 			Cflag = optarg;
210f5b1c8a1SJohn Marino 			break;
211f5b1c8a1SJohn Marino 		case 'c':
212f5b1c8a1SJohn Marino 			usetls = 1;
213f5b1c8a1SJohn Marino 			break;
214f5b1c8a1SJohn Marino 		case 'd':
215f5b1c8a1SJohn Marino 			dflag = 1;
216f5b1c8a1SJohn Marino 			break;
217f5b1c8a1SJohn Marino 		case 'e':
218f5b1c8a1SJohn Marino 			tls_expectname = optarg;
219f5b1c8a1SJohn Marino 			break;
220f5b1c8a1SJohn Marino 		case 'F':
221f5b1c8a1SJohn Marino 			Fflag = 1;
222f5b1c8a1SJohn Marino 			break;
223f5b1c8a1SJohn Marino 		case 'H':
224f5b1c8a1SJohn Marino 			tls_expecthash = optarg;
225f5b1c8a1SJohn Marino 			break;
226f5b1c8a1SJohn Marino 		case 'h':
227f5b1c8a1SJohn Marino 			help();
228f5b1c8a1SJohn Marino 			break;
229f5b1c8a1SJohn Marino 		case 'i':
230f5b1c8a1SJohn Marino 			iflag = strtonum(optarg, 0, UINT_MAX, &errstr);
231f5b1c8a1SJohn Marino 			if (errstr)
232f5b1c8a1SJohn Marino 				errx(1, "interval %s: %s", errstr, optarg);
233f5b1c8a1SJohn Marino 			break;
234f5b1c8a1SJohn Marino 		case 'K':
235f5b1c8a1SJohn Marino 			Kflag = optarg;
236f5b1c8a1SJohn Marino 			break;
237f5b1c8a1SJohn Marino 		case 'k':
238f5b1c8a1SJohn Marino 			kflag = 1;
239f5b1c8a1SJohn Marino 			break;
240f5b1c8a1SJohn Marino 		case 'l':
241f5b1c8a1SJohn Marino 			lflag = 1;
242f5b1c8a1SJohn Marino 			break;
243f5b1c8a1SJohn Marino 		case 'M':
244f5b1c8a1SJohn Marino 			ttl = strtonum(optarg, 0, 255, &errstr);
245f5b1c8a1SJohn Marino 			if (errstr)
246f5b1c8a1SJohn Marino 				errx(1, "ttl is %s", errstr);
247f5b1c8a1SJohn Marino 			break;
248f5b1c8a1SJohn Marino 		case 'm':
249f5b1c8a1SJohn Marino 			minttl = strtonum(optarg, 0, 255, &errstr);
250f5b1c8a1SJohn Marino 			if (errstr)
251f5b1c8a1SJohn Marino 				errx(1, "minttl is %s", errstr);
252f5b1c8a1SJohn Marino 			break;
253f5b1c8a1SJohn Marino 		case 'N':
254f5b1c8a1SJohn Marino 			Nflag = 1;
255f5b1c8a1SJohn Marino 			break;
256f5b1c8a1SJohn Marino 		case 'n':
257f5b1c8a1SJohn Marino 			nflag = 1;
258f5b1c8a1SJohn Marino 			break;
259f5b1c8a1SJohn Marino 		case 'P':
260f5b1c8a1SJohn Marino 			Pflag = optarg;
261f5b1c8a1SJohn Marino 			break;
262f5b1c8a1SJohn Marino 		case 'p':
263f5b1c8a1SJohn Marino 			pflag = optarg;
264f5b1c8a1SJohn Marino 			break;
265f5b1c8a1SJohn Marino 		case 'R':
266f5b1c8a1SJohn Marino 			tls_cachanged = 1;
267f5b1c8a1SJohn Marino 			Rflag = optarg;
268f5b1c8a1SJohn Marino 			break;
269f5b1c8a1SJohn Marino 		case 'r':
270f5b1c8a1SJohn Marino 			rflag = 1;
271f5b1c8a1SJohn Marino 			break;
272f5b1c8a1SJohn Marino 		case 's':
273f5b1c8a1SJohn Marino 			sflag = optarg;
274f5b1c8a1SJohn Marino 			break;
275f5b1c8a1SJohn Marino 		case 't':
276f5b1c8a1SJohn Marino 			tflag = 1;
277f5b1c8a1SJohn Marino 			break;
278f5b1c8a1SJohn Marino 		case 'u':
279f5b1c8a1SJohn Marino 			uflag = 1;
280f5b1c8a1SJohn Marino 			break;
281f5b1c8a1SJohn Marino #ifdef SO_RTABLE
282f5b1c8a1SJohn Marino 		case 'V':
283f5b1c8a1SJohn Marino 			rtableid = (int)strtonum(optarg, 0,
284f5b1c8a1SJohn Marino 			    RT_TABLEID_MAX, &errstr);
285f5b1c8a1SJohn Marino 			if (errstr)
286f5b1c8a1SJohn Marino 				errx(1, "rtable %s: %s", errstr, optarg);
287f5b1c8a1SJohn Marino 			break;
288f5b1c8a1SJohn Marino #endif
289f5b1c8a1SJohn Marino 		case 'v':
290f5b1c8a1SJohn Marino 			vflag = 1;
291f5b1c8a1SJohn Marino 			break;
29272c33676SMaxim Ag 		case 'W':
29372c33676SMaxim Ag 			recvlimit = strtonum(optarg, 1, INT_MAX, &errstr);
29472c33676SMaxim Ag 			if (errstr)
29572c33676SMaxim Ag 				errx(1, "receive limit %s: %s", errstr, optarg);
29672c33676SMaxim Ag 			break;
297f5b1c8a1SJohn Marino 		case 'w':
298f5b1c8a1SJohn Marino 			timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr);
299f5b1c8a1SJohn Marino 			if (errstr)
300f5b1c8a1SJohn Marino 				errx(1, "timeout %s: %s", errstr, optarg);
301f5b1c8a1SJohn Marino 			timeout *= 1000;
302f5b1c8a1SJohn Marino 			break;
303f5b1c8a1SJohn Marino 		case 'x':
304f5b1c8a1SJohn Marino 			xflag = 1;
305f5b1c8a1SJohn Marino 			if ((proxy = strdup(optarg)) == NULL)
306f5b1c8a1SJohn Marino 				err(1, NULL);
307f5b1c8a1SJohn Marino 			break;
30872c33676SMaxim Ag 		case 'Z':
30972c33676SMaxim Ag 			if (strcmp(optarg, "-") == 0)
31072c33676SMaxim Ag 				Zflag = stderr;
31172c33676SMaxim Ag 			else if ((Zflag = fopen(optarg, "w")) == NULL)
31272c33676SMaxim Ag 				err(1, "can't open %s", optarg);
31372c33676SMaxim Ag 			break;
314f5b1c8a1SJohn Marino 		case 'z':
315f5b1c8a1SJohn Marino 			zflag = 1;
316f5b1c8a1SJohn Marino 			break;
317f5b1c8a1SJohn Marino 		case 'D':
318f5b1c8a1SJohn Marino 			Dflag = 1;
319f5b1c8a1SJohn Marino 			break;
320f5b1c8a1SJohn Marino 		case 'I':
321f5b1c8a1SJohn Marino 			Iflag = strtonum(optarg, 1, 65536 << 14, &errstr);
322f5b1c8a1SJohn Marino 			if (errstr != NULL)
323f5b1c8a1SJohn Marino 				errx(1, "TCP receive window %s: %s",
324f5b1c8a1SJohn Marino 				    errstr, optarg);
325f5b1c8a1SJohn Marino 			break;
326f5b1c8a1SJohn Marino 		case 'O':
327f5b1c8a1SJohn Marino 			Oflag = strtonum(optarg, 1, 65536 << 14, &errstr);
328f5b1c8a1SJohn Marino 			if (errstr != NULL)
329f5b1c8a1SJohn Marino 				errx(1, "TCP send window %s: %s",
330f5b1c8a1SJohn Marino 				    errstr, optarg);
331f5b1c8a1SJohn Marino 			break;
33272c33676SMaxim Ag 		case 'o':
33372c33676SMaxim Ag 			oflag = optarg;
33472c33676SMaxim Ag 			break;
335f5b1c8a1SJohn Marino #ifdef TCP_MD5SIG
336f5b1c8a1SJohn Marino 		case 'S':
337f5b1c8a1SJohn Marino 			Sflag = 1;
338f5b1c8a1SJohn Marino 			break;
339f5b1c8a1SJohn Marino #endif
340f5b1c8a1SJohn Marino 		case 'T':
341f5b1c8a1SJohn Marino 			errstr = NULL;
342f5b1c8a1SJohn Marino 			errno = 0;
34372c33676SMaxim Ag 			if (process_tls_opt(optarg, &TLSopt))
344f5b1c8a1SJohn Marino 				break;
34572c33676SMaxim Ag 			if (process_tos_opt(optarg, &Tflag))
346f5b1c8a1SJohn Marino 				break;
347f5b1c8a1SJohn Marino 			if (strlen(optarg) > 1 && optarg[0] == '0' &&
348f5b1c8a1SJohn Marino 			    optarg[1] == 'x')
349f5b1c8a1SJohn Marino 				Tflag = (int)strtol(optarg, NULL, 16);
350f5b1c8a1SJohn Marino 			else
351f5b1c8a1SJohn Marino 				Tflag = (int)strtonum(optarg, 0, 255,
352f5b1c8a1SJohn Marino 				    &errstr);
353f5b1c8a1SJohn Marino 			if (Tflag < 0 || Tflag > 255 || errstr || errno)
354f5b1c8a1SJohn Marino 				errx(1, "illegal tos/tls value %s", optarg);
355f5b1c8a1SJohn Marino 			break;
356f5b1c8a1SJohn Marino 		default:
357f5b1c8a1SJohn Marino 			usage(1);
358f5b1c8a1SJohn Marino 		}
359f5b1c8a1SJohn Marino 	}
360f5b1c8a1SJohn Marino 	argc -= optind;
361f5b1c8a1SJohn Marino 	argv += optind;
362f5b1c8a1SJohn Marino 
363f5b1c8a1SJohn Marino #ifdef SO_RTABLE
364f5b1c8a1SJohn Marino 	if (rtableid >= 0)
365f5b1c8a1SJohn Marino 		if (setrtable(rtableid) == -1)
366f5b1c8a1SJohn Marino 			err(1, "setrtable");
367f5b1c8a1SJohn Marino #endif
368f5b1c8a1SJohn Marino 
369f5b1c8a1SJohn Marino 	/* Cruft to make sure options are clean, and used properly. */
370cca6fc52SDaniel Fojt 	if (argc == 1 && family == AF_UNIX) {
371f5b1c8a1SJohn Marino 		host = argv[0];
372cca6fc52SDaniel Fojt 	} else if (argc == 1 && lflag) {
373f5b1c8a1SJohn Marino 		uport = argv[0];
374cca6fc52SDaniel Fojt 	} else if (argc == 2) {
375f5b1c8a1SJohn Marino 		host = argv[0];
376f5b1c8a1SJohn Marino 		uport = argv[1];
377f5b1c8a1SJohn Marino 	} else
378f5b1c8a1SJohn Marino 		usage(1);
379f5b1c8a1SJohn Marino 
38072c33676SMaxim Ag 	if (usetls) {
38172c33676SMaxim Ag 		if (Cflag && unveil(Cflag, "r") == -1)
382*de0e0e4dSAntonio Huete Jimenez 			err(1, "unveil %s", Cflag);
38372c33676SMaxim Ag 		if (unveil(Rflag, "r") == -1)
384*de0e0e4dSAntonio Huete Jimenez 			err(1, "unveil %s", Rflag);
38572c33676SMaxim Ag 		if (Kflag && unveil(Kflag, "r") == -1)
386*de0e0e4dSAntonio Huete Jimenez 			err(1, "unveil %s", Kflag);
38772c33676SMaxim Ag 		if (oflag && unveil(oflag, "r") == -1)
388*de0e0e4dSAntonio Huete Jimenez 			err(1, "unveil %s", oflag);
389cca6fc52SDaniel Fojt 	} else if (family == AF_UNIX && uflag && lflag && !kflag) {
390cca6fc52SDaniel Fojt 		/*
391cca6fc52SDaniel Fojt 		 * After recvfrom(2) from client, the server connects
392cca6fc52SDaniel Fojt 		 * to the client socket.  As the client path is determined
393cca6fc52SDaniel Fojt 		 * during runtime, we cannot unveil(2).
394cca6fc52SDaniel Fojt 		 */
39572c33676SMaxim Ag 	} else {
39672c33676SMaxim Ag 		if (family == AF_UNIX) {
39772c33676SMaxim Ag 			if (unveil(host, "rwc") == -1)
398*de0e0e4dSAntonio Huete Jimenez 				err(1, "unveil %s", host);
399cca6fc52SDaniel Fojt 			if (uflag && !kflag) {
400cca6fc52SDaniel Fojt 				if (sflag) {
401cca6fc52SDaniel Fojt 					if (unveil(sflag, "rwc") == -1)
402*de0e0e4dSAntonio Huete Jimenez 						err(1, "unveil %s", sflag);
403cca6fc52SDaniel Fojt 				} else {
404cca6fc52SDaniel Fojt 					if (unveil("/tmp", "rwc") == -1)
405*de0e0e4dSAntonio Huete Jimenez 						err(1, "unveil /tmp");
40672c33676SMaxim Ag 				}
407cca6fc52SDaniel Fojt 			}
40872c33676SMaxim Ag 		} else {
409cca6fc52SDaniel Fojt 			/* no filesystem visibility */
41072c33676SMaxim Ag 			if (unveil("/", "") == -1)
411*de0e0e4dSAntonio Huete Jimenez 				err(1, "unveil /");
41272c33676SMaxim Ag 		}
41372c33676SMaxim Ag 	}
41472c33676SMaxim Ag 
41572c33676SMaxim Ag 	if (family == AF_UNIX) {
41672c33676SMaxim Ag 		if (pledge("stdio rpath wpath cpath tmppath unix", NULL) == -1)
41772c33676SMaxim Ag 			err(1, "pledge");
41872c33676SMaxim Ag 	} else if (Fflag && Pflag) {
41972c33676SMaxim Ag 		if (pledge("stdio inet dns sendfd tty", NULL) == -1)
42072c33676SMaxim Ag 			err(1, "pledge");
42172c33676SMaxim Ag 	} else if (Fflag) {
42272c33676SMaxim Ag 		if (pledge("stdio inet dns sendfd", NULL) == -1)
42372c33676SMaxim Ag 			err(1, "pledge");
42472c33676SMaxim Ag 	} else if (Pflag && usetls) {
42572c33676SMaxim Ag 		if (pledge("stdio rpath inet dns tty", NULL) == -1)
42672c33676SMaxim Ag 			err(1, "pledge");
42772c33676SMaxim Ag 	} else if (Pflag) {
42872c33676SMaxim Ag 		if (pledge("stdio inet dns tty", NULL) == -1)
42972c33676SMaxim Ag 			err(1, "pledge");
43072c33676SMaxim Ag 	} else if (usetls) {
43172c33676SMaxim Ag 		if (pledge("stdio rpath inet dns", NULL) == -1)
43272c33676SMaxim Ag 			err(1, "pledge");
43372c33676SMaxim Ag 	} else if (pledge("stdio inet dns", NULL) == -1)
43472c33676SMaxim Ag 		err(1, "pledge");
43572c33676SMaxim Ag 
436f5b1c8a1SJohn Marino 	if (lflag && sflag)
437f5b1c8a1SJohn Marino 		errx(1, "cannot use -s and -l");
438f5b1c8a1SJohn Marino 	if (lflag && pflag)
439f5b1c8a1SJohn Marino 		errx(1, "cannot use -p and -l");
440f5b1c8a1SJohn Marino 	if (lflag && zflag)
441f5b1c8a1SJohn Marino 		errx(1, "cannot use -z and -l");
442f5b1c8a1SJohn Marino 	if (!lflag && kflag)
443f5b1c8a1SJohn Marino 		errx(1, "must use -l with -k");
444f5b1c8a1SJohn Marino 	if (uflag && usetls)
445f5b1c8a1SJohn Marino 		errx(1, "cannot use -c and -u");
446f5b1c8a1SJohn Marino 	if ((family == AF_UNIX) && usetls)
447f5b1c8a1SJohn Marino 		errx(1, "cannot use -c and -U");
448f5b1c8a1SJohn Marino 	if ((family == AF_UNIX) && Fflag)
449f5b1c8a1SJohn Marino 		errx(1, "cannot use -F and -U");
450f5b1c8a1SJohn Marino 	if (Fflag && usetls)
451f5b1c8a1SJohn Marino 		errx(1, "cannot use -c and -F");
452f5b1c8a1SJohn Marino 	if (TLSopt && !usetls)
453f5b1c8a1SJohn Marino 		errx(1, "you must specify -c to use TLS options");
454f5b1c8a1SJohn Marino 	if (Cflag && !usetls)
455f5b1c8a1SJohn Marino 		errx(1, "you must specify -c to use -C");
456f5b1c8a1SJohn Marino 	if (Kflag && !usetls)
457f5b1c8a1SJohn Marino 		errx(1, "you must specify -c to use -K");
45872c33676SMaxim Ag 	if (Zflag && !usetls)
45972c33676SMaxim Ag 		errx(1, "you must specify -c to use -Z");
46072c33676SMaxim Ag 	if (oflag && !Cflag)
46172c33676SMaxim Ag 		errx(1, "you must specify -C to use -o");
462f5b1c8a1SJohn Marino 	if (tls_cachanged && !usetls)
463f5b1c8a1SJohn Marino 		errx(1, "you must specify -c to use -R");
464f5b1c8a1SJohn Marino 	if (tls_expecthash && !usetls)
465f5b1c8a1SJohn Marino 		errx(1, "you must specify -c to use -H");
466f5b1c8a1SJohn Marino 	if (tls_expectname && !usetls)
467f5b1c8a1SJohn Marino 		errx(1, "you must specify -c to use -e");
468f5b1c8a1SJohn Marino 
469f5b1c8a1SJohn Marino 	/* Get name of temporary socket for unix datagram client */
470f5b1c8a1SJohn Marino 	if ((family == AF_UNIX) && uflag && !lflag) {
471f5b1c8a1SJohn Marino 		if (sflag) {
472f5b1c8a1SJohn Marino 			unix_dg_tmp_socket = sflag;
473f5b1c8a1SJohn Marino 		} else {
474f5b1c8a1SJohn Marino 			strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX",
475f5b1c8a1SJohn Marino 			    UNIX_DG_TMP_SOCKET_SIZE);
476f5b1c8a1SJohn Marino 			if (mktemp(unix_dg_tmp_socket_buf) == NULL)
477f5b1c8a1SJohn Marino 				err(1, "mktemp");
478f5b1c8a1SJohn Marino 			unix_dg_tmp_socket = unix_dg_tmp_socket_buf;
479f5b1c8a1SJohn Marino 		}
480f5b1c8a1SJohn Marino 	}
481f5b1c8a1SJohn Marino 
482f5b1c8a1SJohn Marino 	/* Initialize addrinfo structure. */
483f5b1c8a1SJohn Marino 	if (family != AF_UNIX) {
484f5b1c8a1SJohn Marino 		memset(&hints, 0, sizeof(struct addrinfo));
485f5b1c8a1SJohn Marino 		hints.ai_family = family;
486f5b1c8a1SJohn Marino 		hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
487f5b1c8a1SJohn Marino 		hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
488f5b1c8a1SJohn Marino 		if (nflag)
489f5b1c8a1SJohn Marino 			hints.ai_flags |= AI_NUMERICHOST;
490f5b1c8a1SJohn Marino 	}
491f5b1c8a1SJohn Marino 
492f5b1c8a1SJohn Marino 	if (xflag) {
493f5b1c8a1SJohn Marino 		if (uflag)
494f5b1c8a1SJohn Marino 			errx(1, "no proxy support for UDP mode");
495f5b1c8a1SJohn Marino 
496f5b1c8a1SJohn Marino 		if (lflag)
497f5b1c8a1SJohn Marino 			errx(1, "no proxy support for listen");
498f5b1c8a1SJohn Marino 
499f5b1c8a1SJohn Marino 		if (family == AF_UNIX)
500f5b1c8a1SJohn Marino 			errx(1, "no proxy support for unix sockets");
501f5b1c8a1SJohn Marino 
502f5b1c8a1SJohn Marino 		if (sflag)
503f5b1c8a1SJohn Marino 			errx(1, "no proxy support for local source address");
504f5b1c8a1SJohn Marino 
50572c33676SMaxim Ag 		if (*proxy == '[') {
50672c33676SMaxim Ag 			++proxy;
50772c33676SMaxim Ag 			proxyport = strchr(proxy, ']');
50872c33676SMaxim Ag 			if (proxyport == NULL)
50972c33676SMaxim Ag 				errx(1, "missing closing bracket in proxy");
51072c33676SMaxim Ag 			*proxyport++ = '\0';
51172c33676SMaxim Ag 			if (*proxyport == '\0')
51272c33676SMaxim Ag 				/* Use default proxy port. */
51372c33676SMaxim Ag 				proxyport = NULL;
51472c33676SMaxim Ag 			else {
51572c33676SMaxim Ag 				if (*proxyport == ':')
51672c33676SMaxim Ag 					++proxyport;
51772c33676SMaxim Ag 				else
51872c33676SMaxim Ag 					errx(1, "garbage proxy port delimiter");
51972c33676SMaxim Ag 			}
52072c33676SMaxim Ag 		} else {
52172c33676SMaxim Ag 			proxyport = strrchr(proxy, ':');
52272c33676SMaxim Ag 			if (proxyport != NULL)
52372c33676SMaxim Ag 				*proxyport++ = '\0';
52472c33676SMaxim Ag 		}
525f5b1c8a1SJohn Marino 
526f5b1c8a1SJohn Marino 		memset(&proxyhints, 0, sizeof(struct addrinfo));
527f5b1c8a1SJohn Marino 		proxyhints.ai_family = family;
528f5b1c8a1SJohn Marino 		proxyhints.ai_socktype = SOCK_STREAM;
529f5b1c8a1SJohn Marino 		proxyhints.ai_protocol = IPPROTO_TCP;
530f5b1c8a1SJohn Marino 		if (nflag)
531f5b1c8a1SJohn Marino 			proxyhints.ai_flags |= AI_NUMERICHOST;
532f5b1c8a1SJohn Marino 	}
533f5b1c8a1SJohn Marino 
534f5b1c8a1SJohn Marino 	if (usetls) {
535f5b1c8a1SJohn Marino 		if ((tls_cfg = tls_config_new()) == NULL)
536f5b1c8a1SJohn Marino 			errx(1, "unable to allocate TLS config");
53772c33676SMaxim Ag 		if (Rflag && tls_config_set_ca_file(tls_cfg, Rflag) == -1)
53872c33676SMaxim Ag 			errx(1, "%s", tls_config_error(tls_cfg));
53972c33676SMaxim Ag 		if (Cflag && tls_config_set_cert_file(tls_cfg, Cflag) == -1)
54072c33676SMaxim Ag 			errx(1, "%s", tls_config_error(tls_cfg));
54172c33676SMaxim Ag 		if (Kflag && tls_config_set_key_file(tls_cfg, Kflag) == -1)
54272c33676SMaxim Ag 			errx(1, "%s", tls_config_error(tls_cfg));
54372c33676SMaxim Ag 		if (oflag && tls_config_set_ocsp_staple_file(tls_cfg, oflag) == -1)
54472c33676SMaxim Ag 			errx(1, "%s", tls_config_error(tls_cfg));
54572c33676SMaxim Ag 		if (tls_config_parse_protocols(&protocols, tls_protocols) == -1)
54672c33676SMaxim Ag 			errx(1, "invalid TLS protocols `%s'", tls_protocols);
54772c33676SMaxim Ag 		if (tls_config_set_protocols(tls_cfg, protocols) == -1)
54872c33676SMaxim Ag 			errx(1, "%s", tls_config_error(tls_cfg));
54972c33676SMaxim Ag 		if (tls_config_set_ciphers(tls_cfg, tls_ciphers) == -1)
55072c33676SMaxim Ag 			errx(1, "%s", tls_config_error(tls_cfg));
551f5b1c8a1SJohn Marino 		if (!lflag && (TLSopt & TLS_CCERT))
552f5b1c8a1SJohn Marino 			errx(1, "clientcert is only valid with -l");
553f5b1c8a1SJohn Marino 		if (TLSopt & TLS_NONAME)
554f5b1c8a1SJohn Marino 			tls_config_insecure_noverifyname(tls_cfg);
555f5b1c8a1SJohn Marino 		if (TLSopt & TLS_NOVERIFY) {
556f5b1c8a1SJohn Marino 			if (tls_expecthash != NULL)
557f5b1c8a1SJohn Marino 				errx(1, "-H and -T noverify may not be used "
558f5b1c8a1SJohn Marino 				    "together");
559f5b1c8a1SJohn Marino 			tls_config_insecure_noverifycert(tls_cfg);
560f5b1c8a1SJohn Marino 		}
56172c33676SMaxim Ag 		if (TLSopt & TLS_MUSTSTAPLE)
56272c33676SMaxim Ag 			tls_config_ocsp_require_stapling(tls_cfg);
56372c33676SMaxim Ag 
56472c33676SMaxim Ag 		if (Pflag) {
56572c33676SMaxim Ag 			if (pledge("stdio inet dns tty", NULL) == -1)
56672c33676SMaxim Ag 				err(1, "pledge");
56772c33676SMaxim Ag 		} else if (pledge("stdio inet dns", NULL) == -1)
56872c33676SMaxim Ag 			err(1, "pledge");
569f5b1c8a1SJohn Marino 	}
570f5b1c8a1SJohn Marino 	if (lflag) {
571f5b1c8a1SJohn Marino 		ret = 0;
572f5b1c8a1SJohn Marino 
573f5b1c8a1SJohn Marino 		if (family == AF_UNIX) {
574f5b1c8a1SJohn Marino 			if (uflag)
575f5b1c8a1SJohn Marino 				s = unix_bind(host, 0);
576f5b1c8a1SJohn Marino 			else
577f5b1c8a1SJohn Marino 				s = unix_listen(host);
578f5b1c8a1SJohn Marino 		}
579f5b1c8a1SJohn Marino 
580f5b1c8a1SJohn Marino 		if (usetls) {
581f5b1c8a1SJohn Marino 			tls_config_verify_client_optional(tls_cfg);
582f5b1c8a1SJohn Marino 			if ((tls_ctx = tls_server()) == NULL)
583f5b1c8a1SJohn Marino 				errx(1, "tls server creation failed");
584f5b1c8a1SJohn Marino 			if (tls_configure(tls_ctx, tls_cfg) == -1)
585f5b1c8a1SJohn Marino 				errx(1, "tls configuration failed (%s)",
586f5b1c8a1SJohn Marino 				    tls_error(tls_ctx));
587f5b1c8a1SJohn Marino 		}
588f5b1c8a1SJohn Marino 		/* Allow only one connection at a time, but stay alive. */
589f5b1c8a1SJohn Marino 		for (;;) {
59072c33676SMaxim Ag 			if (family != AF_UNIX) {
59172c33676SMaxim Ag 				if (s != -1)
59272c33676SMaxim Ag 					close(s);
593f5b1c8a1SJohn Marino 				s = local_listen(host, uport, hints);
59472c33676SMaxim Ag 			}
595cca6fc52SDaniel Fojt 			if (s == -1)
596f5b1c8a1SJohn Marino 				err(1, NULL);
59772c33676SMaxim Ag 			if (uflag && kflag) {
598cca6fc52SDaniel Fojt 				if (family == AF_UNIX) {
599cca6fc52SDaniel Fojt 					if (pledge("stdio unix", NULL) == -1)
600cca6fc52SDaniel Fojt 						err(1, "pledge");
601cca6fc52SDaniel Fojt 				}
602f5b1c8a1SJohn Marino 				/*
60372c33676SMaxim Ag 				 * For UDP and -k, don't connect the socket,
60472c33676SMaxim Ag 				 * let it receive datagrams from multiple
60572c33676SMaxim Ag 				 * socket pairs.
606f5b1c8a1SJohn Marino 				 */
607f5b1c8a1SJohn Marino 				readwrite(s, NULL);
60872c33676SMaxim Ag 			} else if (uflag && !kflag) {
609f5b1c8a1SJohn Marino 				/*
61072c33676SMaxim Ag 				 * For UDP and not -k, we will use recvfrom()
61172c33676SMaxim Ag 				 * initially to wait for a caller, then use
61272c33676SMaxim Ag 				 * the regular functions to talk to the caller.
613f5b1c8a1SJohn Marino 				 */
61472c33676SMaxim Ag 				int rv;
61572c33676SMaxim Ag 				char buf[2048];
616f5b1c8a1SJohn Marino 				struct sockaddr_storage z;
617f5b1c8a1SJohn Marino 
618f5b1c8a1SJohn Marino 				len = sizeof(z);
61972c33676SMaxim Ag 				rv = recvfrom(s, buf, sizeof(buf), MSG_PEEK,
620f5b1c8a1SJohn Marino 				    (struct sockaddr *)&z, &len);
621cca6fc52SDaniel Fojt 				if (rv == -1)
622f5b1c8a1SJohn Marino 					err(1, "recvfrom");
623f5b1c8a1SJohn Marino 
624f5b1c8a1SJohn Marino 				rv = connect(s, (struct sockaddr *)&z, len);
625cca6fc52SDaniel Fojt 				if (rv == -1)
626f5b1c8a1SJohn Marino 					err(1, "connect");
627f5b1c8a1SJohn Marino 
628cca6fc52SDaniel Fojt 				if (family == AF_UNIX) {
629cca6fc52SDaniel Fojt 					if (pledge("stdio unix", NULL) == -1)
630cca6fc52SDaniel Fojt 						err(1, "pledge");
631cca6fc52SDaniel Fojt 				}
632f5b1c8a1SJohn Marino 				if (vflag)
63372c33676SMaxim Ag 					report_sock("Connection received",
634cca6fc52SDaniel Fojt 					    (struct sockaddr *)&z, len,
635cca6fc52SDaniel Fojt 					    family == AF_UNIX ? host : NULL);
636f5b1c8a1SJohn Marino 
637f5b1c8a1SJohn Marino 				readwrite(s, NULL);
638f5b1c8a1SJohn Marino 			} else {
63972c33676SMaxim Ag 				struct tls *tls_cctx = NULL;
64072c33676SMaxim Ag 				int connfd;
64172c33676SMaxim Ag 
642f5b1c8a1SJohn Marino 				len = sizeof(cliaddr);
643f5b1c8a1SJohn Marino 				connfd = accept4(s, (struct sockaddr *)&cliaddr,
644f5b1c8a1SJohn Marino 				    &len, SOCK_NONBLOCK);
645f5b1c8a1SJohn Marino 				if (connfd == -1) {
646f5b1c8a1SJohn Marino 					/* For now, all errnos are fatal */
647f5b1c8a1SJohn Marino 					err(1, "accept");
648f5b1c8a1SJohn Marino 				}
649f5b1c8a1SJohn Marino 				if (vflag)
65072c33676SMaxim Ag 					report_sock("Connection received",
65172c33676SMaxim Ag 					    (struct sockaddr *)&cliaddr, len,
652f5b1c8a1SJohn Marino 					    family == AF_UNIX ? host : NULL);
653f5b1c8a1SJohn Marino 				if ((usetls) &&
654f5b1c8a1SJohn Marino 				    (tls_cctx = tls_setup_server(tls_ctx, connfd, host)))
655f5b1c8a1SJohn Marino 					readwrite(connfd, tls_cctx);
656f5b1c8a1SJohn Marino 				if (!usetls)
657f5b1c8a1SJohn Marino 					readwrite(connfd, NULL);
65872c33676SMaxim Ag 				if (tls_cctx)
65972c33676SMaxim Ag 					timeout_tls(s, tls_cctx, tls_close);
660f5b1c8a1SJohn Marino 				close(connfd);
66172c33676SMaxim Ag 				tls_free(tls_cctx);
662f5b1c8a1SJohn Marino 			}
66372c33676SMaxim Ag 			if (family == AF_UNIX && uflag) {
664cca6fc52SDaniel Fojt 				if (connect(s, NULL, 0) == -1)
665f5b1c8a1SJohn Marino 					err(1, "connect");
666f5b1c8a1SJohn Marino 			}
667f5b1c8a1SJohn Marino 
668f5b1c8a1SJohn Marino 			if (!kflag)
669f5b1c8a1SJohn Marino 				break;
670f5b1c8a1SJohn Marino 		}
671f5b1c8a1SJohn Marino 	} else if (family == AF_UNIX) {
672f5b1c8a1SJohn Marino 		ret = 0;
673f5b1c8a1SJohn Marino 
67472c33676SMaxim Ag 		if ((s = unix_connect(host)) > 0) {
67572c33676SMaxim Ag 			if (!zflag)
676f5b1c8a1SJohn Marino 				readwrite(s, NULL);
677f5b1c8a1SJohn Marino 			close(s);
67872c33676SMaxim Ag 		} else {
67972c33676SMaxim Ag 			warn("%s", host);
680f5b1c8a1SJohn Marino 			ret = 1;
68172c33676SMaxim Ag 		}
682f5b1c8a1SJohn Marino 
683f5b1c8a1SJohn Marino 		if (uflag)
684f5b1c8a1SJohn Marino 			unlink(unix_dg_tmp_socket);
68572c33676SMaxim Ag 		return ret;
686f5b1c8a1SJohn Marino 	} else {
687f5b1c8a1SJohn Marino 		int i = 0;
688f5b1c8a1SJohn Marino 
689f5b1c8a1SJohn Marino 		/* Construct the portlist[] array. */
690f5b1c8a1SJohn Marino 		build_ports(uport);
691f5b1c8a1SJohn Marino 
692f5b1c8a1SJohn Marino 		/* Cycle through portlist, connecting to each port. */
693f5b1c8a1SJohn Marino 		for (s = -1, i = 0; portlist[i] != NULL; i++) {
694f5b1c8a1SJohn Marino 			if (s != -1)
695f5b1c8a1SJohn Marino 				close(s);
69672c33676SMaxim Ag 			tls_free(tls_ctx);
69772c33676SMaxim Ag 			tls_ctx = NULL;
698f5b1c8a1SJohn Marino 
699f5b1c8a1SJohn Marino 			if (usetls) {
700f5b1c8a1SJohn Marino 				if ((tls_ctx = tls_client()) == NULL)
701f5b1c8a1SJohn Marino 					errx(1, "tls client creation failed");
702f5b1c8a1SJohn Marino 				if (tls_configure(tls_ctx, tls_cfg) == -1)
703f5b1c8a1SJohn Marino 					errx(1, "tls configuration failed (%s)",
704f5b1c8a1SJohn Marino 					    tls_error(tls_ctx));
705f5b1c8a1SJohn Marino 			}
706f5b1c8a1SJohn Marino 			if (xflag)
707f5b1c8a1SJohn Marino 				s = socks_connect(host, portlist[i], hints,
70872c33676SMaxim Ag 				    proxy, proxyport, proxyhints, socksv,
709f5b1c8a1SJohn Marino 				    Pflag);
710f5b1c8a1SJohn Marino 			else
711cca6fc52SDaniel Fojt 				s = remote_connect(host, portlist[i], hints,
712cca6fc52SDaniel Fojt 				    ipaddr);
713f5b1c8a1SJohn Marino 
714f5b1c8a1SJohn Marino 			if (s == -1)
715f5b1c8a1SJohn Marino 				continue;
716f5b1c8a1SJohn Marino 
717f5b1c8a1SJohn Marino 			ret = 0;
718f5b1c8a1SJohn Marino 			if (vflag || zflag) {
719f5b1c8a1SJohn Marino 				/* For UDP, make sure we are connected. */
720f5b1c8a1SJohn Marino 				if (uflag) {
721f5b1c8a1SJohn Marino 					if (udptest(s) == -1) {
722f5b1c8a1SJohn Marino 						ret = 1;
723f5b1c8a1SJohn Marino 						continue;
724f5b1c8a1SJohn Marino 					}
725f5b1c8a1SJohn Marino 				}
726f5b1c8a1SJohn Marino 
727f5b1c8a1SJohn Marino 				/* Don't look up port if -n. */
728f5b1c8a1SJohn Marino 				if (nflag)
729f5b1c8a1SJohn Marino 					sv = NULL;
730f5b1c8a1SJohn Marino 				else {
731f5b1c8a1SJohn Marino 					sv = getservbyport(
732f5b1c8a1SJohn Marino 					    ntohs(atoi(portlist[i])),
733f5b1c8a1SJohn Marino 					    uflag ? "udp" : "tcp");
734f5b1c8a1SJohn Marino 				}
735f5b1c8a1SJohn Marino 
736cca6fc52SDaniel Fojt 				fprintf(stderr, "Connection to %s", host);
737cca6fc52SDaniel Fojt 
738cca6fc52SDaniel Fojt 				/*
739cca6fc52SDaniel Fojt 				 * if we aren't connecting thru a proxy and
740cca6fc52SDaniel Fojt 				 * there is something to report, print IP
741cca6fc52SDaniel Fojt 				 */
742*de0e0e4dSAntonio Huete Jimenez 				if (!nflag && !xflag &&
743*de0e0e4dSAntonio Huete Jimenez 				    strcmp(host, ipaddr) != 0)
744cca6fc52SDaniel Fojt 					fprintf(stderr, " (%s)", ipaddr);
745cca6fc52SDaniel Fojt 
746cca6fc52SDaniel Fojt 				fprintf(stderr, " %s port [%s/%s] succeeded!\n",
747cca6fc52SDaniel Fojt 				    portlist[i], uflag ? "udp" : "tcp",
748f5b1c8a1SJohn Marino 				    sv ? sv->s_name : "*");
749f5b1c8a1SJohn Marino 			}
750f5b1c8a1SJohn Marino 			if (Fflag)
751f5b1c8a1SJohn Marino 				fdpass(s);
752f5b1c8a1SJohn Marino 			else {
753f5b1c8a1SJohn Marino 				if (usetls)
754f5b1c8a1SJohn Marino 					tls_setup_client(tls_ctx, s, host);
755f5b1c8a1SJohn Marino 				if (!zflag)
756f5b1c8a1SJohn Marino 					readwrite(s, tls_ctx);
75772c33676SMaxim Ag 				if (tls_ctx)
75872c33676SMaxim Ag 					timeout_tls(s, tls_ctx, tls_close);
759f5b1c8a1SJohn Marino 			}
760f5b1c8a1SJohn Marino 		}
761f5b1c8a1SJohn Marino 	}
762f5b1c8a1SJohn Marino 
763f5b1c8a1SJohn Marino 	if (s != -1)
764f5b1c8a1SJohn Marino 		close(s);
76572c33676SMaxim Ag 	tls_free(tls_ctx);
766f5b1c8a1SJohn Marino 	tls_config_free(tls_cfg);
767f5b1c8a1SJohn Marino 
76872c33676SMaxim Ag 	return ret;
769f5b1c8a1SJohn Marino }
770f5b1c8a1SJohn Marino 
771f5b1c8a1SJohn Marino /*
772f5b1c8a1SJohn Marino  * unix_bind()
773f5b1c8a1SJohn Marino  * Returns a unix socket bound to the given path
774f5b1c8a1SJohn Marino  */
775f5b1c8a1SJohn Marino int
unix_bind(char * path,int flags)776f5b1c8a1SJohn Marino unix_bind(char *path, int flags)
777f5b1c8a1SJohn Marino {
778f5b1c8a1SJohn Marino 	struct sockaddr_un s_un;
779f5b1c8a1SJohn Marino 	int s, save_errno;
780f5b1c8a1SJohn Marino 
781f5b1c8a1SJohn Marino 	/* Create unix domain socket. */
782f5b1c8a1SJohn Marino 	if ((s = socket(AF_UNIX, flags | (uflag ? SOCK_DGRAM : SOCK_STREAM),
783cca6fc52SDaniel Fojt 	    0)) == -1)
78472c33676SMaxim Ag 		return -1;
785f5b1c8a1SJohn Marino 
786f5b1c8a1SJohn Marino 	memset(&s_un, 0, sizeof(struct sockaddr_un));
787f5b1c8a1SJohn Marino 	s_un.sun_family = AF_UNIX;
788f5b1c8a1SJohn Marino 
789f5b1c8a1SJohn Marino 	if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) >=
790f5b1c8a1SJohn Marino 	    sizeof(s_un.sun_path)) {
791f5b1c8a1SJohn Marino 		close(s);
792f5b1c8a1SJohn Marino 		errno = ENAMETOOLONG;
79372c33676SMaxim Ag 		return -1;
794f5b1c8a1SJohn Marino 	}
795f5b1c8a1SJohn Marino 
796cca6fc52SDaniel Fojt 	if (bind(s, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
797f5b1c8a1SJohn Marino 		save_errno = errno;
798f5b1c8a1SJohn Marino 		close(s);
799f5b1c8a1SJohn Marino 		errno = save_errno;
80072c33676SMaxim Ag 		return -1;
801f5b1c8a1SJohn Marino 	}
80272c33676SMaxim Ag 	if (vflag)
80372c33676SMaxim Ag 		report_sock("Bound", NULL, 0, path);
80472c33676SMaxim Ag 
80572c33676SMaxim Ag 	return s;
80672c33676SMaxim Ag }
80772c33676SMaxim Ag 
80872c33676SMaxim Ag int
timeout_tls(int s,struct tls * tls_ctx,int (* func)(struct tls *))80972c33676SMaxim Ag timeout_tls(int s, struct tls *tls_ctx, int (*func)(struct tls *))
81072c33676SMaxim Ag {
81172c33676SMaxim Ag 	struct pollfd pfd;
81272c33676SMaxim Ag 	int ret;
81372c33676SMaxim Ag 
81472c33676SMaxim Ag 	while ((ret = (*func)(tls_ctx)) != 0) {
81572c33676SMaxim Ag 		if (ret == TLS_WANT_POLLIN)
81672c33676SMaxim Ag 			pfd.events = POLLIN;
81772c33676SMaxim Ag 		else if (ret == TLS_WANT_POLLOUT)
81872c33676SMaxim Ag 			pfd.events = POLLOUT;
81972c33676SMaxim Ag 		else
82072c33676SMaxim Ag 			break;
82172c33676SMaxim Ag 		pfd.fd = s;
82272c33676SMaxim Ag 		if ((ret = poll(&pfd, 1, timeout)) == 1)
82372c33676SMaxim Ag 			continue;
82472c33676SMaxim Ag 		else if (ret == 0) {
82572c33676SMaxim Ag 			errno = ETIMEDOUT;
82672c33676SMaxim Ag 			ret = -1;
82772c33676SMaxim Ag 			break;
82872c33676SMaxim Ag 		} else
82972c33676SMaxim Ag 			err(1, "poll failed");
83072c33676SMaxim Ag 	}
83172c33676SMaxim Ag 
83272c33676SMaxim Ag 	return ret;
833f5b1c8a1SJohn Marino }
834f5b1c8a1SJohn Marino 
835f5b1c8a1SJohn Marino void
tls_setup_client(struct tls * tls_ctx,int s,char * host)836f5b1c8a1SJohn Marino tls_setup_client(struct tls *tls_ctx, int s, char *host)
837f5b1c8a1SJohn Marino {
83872c33676SMaxim Ag 	const char *errstr;
839f5b1c8a1SJohn Marino 
840f5b1c8a1SJohn Marino 	if (tls_connect_socket(tls_ctx, s,
841f5b1c8a1SJohn Marino 	    tls_expectname ? tls_expectname : host) == -1) {
842f5b1c8a1SJohn Marino 		errx(1, "tls connection failed (%s)",
843f5b1c8a1SJohn Marino 		    tls_error(tls_ctx));
844f5b1c8a1SJohn Marino 	}
84572c33676SMaxim Ag 	if (timeout_tls(s, tls_ctx, tls_handshake) == -1) {
84672c33676SMaxim Ag 		if ((errstr = tls_error(tls_ctx)) == NULL)
84772c33676SMaxim Ag 			errstr = strerror(errno);
84872c33676SMaxim Ag 		errx(1, "tls handshake failed (%s)", errstr);
84972c33676SMaxim Ag 	}
850f5b1c8a1SJohn Marino 	if (vflag)
85172c33676SMaxim Ag 		report_tls(tls_ctx, host);
852cca6fc52SDaniel Fojt 	if (tls_expecthash && (tls_peer_cert_hash(tls_ctx) == NULL ||
853cca6fc52SDaniel Fojt 	    strcmp(tls_expecthash, tls_peer_cert_hash(tls_ctx)) != 0))
854f5b1c8a1SJohn Marino 		errx(1, "peer certificate is not %s", tls_expecthash);
85572c33676SMaxim Ag 	if (Zflag) {
85672c33676SMaxim Ag 		save_peer_cert(tls_ctx, Zflag);
85772c33676SMaxim Ag 		if (Zflag != stderr && (fclose(Zflag) != 0))
85872c33676SMaxim Ag 			err(1, "fclose failed saving peer cert");
85972c33676SMaxim Ag 	}
860f5b1c8a1SJohn Marino }
861f5b1c8a1SJohn Marino 
862f5b1c8a1SJohn Marino struct tls *
tls_setup_server(struct tls * tls_ctx,int connfd,char * host)863f5b1c8a1SJohn Marino tls_setup_server(struct tls *tls_ctx, int connfd, char *host)
864f5b1c8a1SJohn Marino {
865f5b1c8a1SJohn Marino 	struct tls *tls_cctx;
86672c33676SMaxim Ag 	const char *errstr;
867f5b1c8a1SJohn Marino 
86872c33676SMaxim Ag 	if (tls_accept_socket(tls_ctx, &tls_cctx, connfd) == -1) {
86972c33676SMaxim Ag 		warnx("tls accept failed (%s)", tls_error(tls_ctx));
87072c33676SMaxim Ag 	} else if (timeout_tls(connfd, tls_cctx, tls_handshake) == -1) {
87172c33676SMaxim Ag 		if ((errstr = tls_error(tls_cctx)) == NULL)
87272c33676SMaxim Ag 			errstr = strerror(errno);
87372c33676SMaxim Ag 		warnx("tls handshake failed (%s)", errstr);
874f5b1c8a1SJohn Marino 	} else {
875f5b1c8a1SJohn Marino 		int gotcert = tls_peer_cert_provided(tls_cctx);
876f5b1c8a1SJohn Marino 
877f5b1c8a1SJohn Marino 		if (vflag && gotcert)
87872c33676SMaxim Ag 			report_tls(tls_cctx, host);
879f5b1c8a1SJohn Marino 		if ((TLSopt & TLS_CCERT) && !gotcert)
880f5b1c8a1SJohn Marino 			warnx("No client certificate provided");
881cca6fc52SDaniel Fojt 		else if (gotcert && tls_expecthash &&
882cca6fc52SDaniel Fojt 		    (tls_peer_cert_hash(tls_cctx) == NULL ||
883cca6fc52SDaniel Fojt 		    strcmp(tls_expecthash, tls_peer_cert_hash(tls_cctx)) != 0))
884f5b1c8a1SJohn Marino 			warnx("peer certificate is not %s", tls_expecthash);
885f5b1c8a1SJohn Marino 		else if (gotcert && tls_expectname &&
886f5b1c8a1SJohn Marino 		    (!tls_peer_cert_contains_name(tls_cctx, tls_expectname)))
887f5b1c8a1SJohn Marino 			warnx("name (%s) not found in client cert",
888f5b1c8a1SJohn Marino 			    tls_expectname);
889f5b1c8a1SJohn Marino 		else {
890f5b1c8a1SJohn Marino 			return tls_cctx;
891f5b1c8a1SJohn Marino 		}
892f5b1c8a1SJohn Marino 	}
893f5b1c8a1SJohn Marino 	return NULL;
894f5b1c8a1SJohn Marino }
895f5b1c8a1SJohn Marino 
896f5b1c8a1SJohn Marino /*
897f5b1c8a1SJohn Marino  * unix_connect()
898f5b1c8a1SJohn Marino  * Returns a socket connected to a local unix socket. Returns -1 on failure.
899f5b1c8a1SJohn Marino  */
900f5b1c8a1SJohn Marino int
unix_connect(char * path)901f5b1c8a1SJohn Marino unix_connect(char *path)
902f5b1c8a1SJohn Marino {
903f5b1c8a1SJohn Marino 	struct sockaddr_un s_un;
904f5b1c8a1SJohn Marino 	int s, save_errno;
905f5b1c8a1SJohn Marino 
906f5b1c8a1SJohn Marino 	if (uflag) {
907cca6fc52SDaniel Fojt 		if ((s = unix_bind(unix_dg_tmp_socket, SOCK_CLOEXEC)) == -1)
90872c33676SMaxim Ag 			return -1;
909f5b1c8a1SJohn Marino 	} else {
910cca6fc52SDaniel Fojt 		if ((s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1)
91172c33676SMaxim Ag 			return -1;
912f5b1c8a1SJohn Marino 	}
913f5b1c8a1SJohn Marino 
914f5b1c8a1SJohn Marino 	memset(&s_un, 0, sizeof(struct sockaddr_un));
915f5b1c8a1SJohn Marino 	s_un.sun_family = AF_UNIX;
916f5b1c8a1SJohn Marino 
917f5b1c8a1SJohn Marino 	if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) >=
918f5b1c8a1SJohn Marino 	    sizeof(s_un.sun_path)) {
919f5b1c8a1SJohn Marino 		close(s);
920f5b1c8a1SJohn Marino 		errno = ENAMETOOLONG;
92172c33676SMaxim Ag 		return -1;
922f5b1c8a1SJohn Marino 	}
923cca6fc52SDaniel Fojt 	if (connect(s, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
924f5b1c8a1SJohn Marino 		save_errno = errno;
925f5b1c8a1SJohn Marino 		close(s);
926f5b1c8a1SJohn Marino 		errno = save_errno;
92772c33676SMaxim Ag 		return -1;
928f5b1c8a1SJohn Marino 	}
92972c33676SMaxim Ag 	return s;
930f5b1c8a1SJohn Marino }
931f5b1c8a1SJohn Marino 
932f5b1c8a1SJohn Marino /*
933f5b1c8a1SJohn Marino  * unix_listen()
934f5b1c8a1SJohn Marino  * Create a unix domain socket, and listen on it.
935f5b1c8a1SJohn Marino  */
936f5b1c8a1SJohn Marino int
unix_listen(char * path)937f5b1c8a1SJohn Marino unix_listen(char *path)
938f5b1c8a1SJohn Marino {
939f5b1c8a1SJohn Marino 	int s;
940f5b1c8a1SJohn Marino 
941cca6fc52SDaniel Fojt 	if ((s = unix_bind(path, 0)) == -1)
94272c33676SMaxim Ag 		return -1;
943cca6fc52SDaniel Fojt 	if (listen(s, 5) == -1) {
944f5b1c8a1SJohn Marino 		close(s);
94572c33676SMaxim Ag 		return -1;
946f5b1c8a1SJohn Marino 	}
94772c33676SMaxim Ag 	if (vflag)
94872c33676SMaxim Ag 		report_sock("Listening", NULL, 0, path);
94972c33676SMaxim Ag 
95072c33676SMaxim Ag 	return s;
951f5b1c8a1SJohn Marino }
952f5b1c8a1SJohn Marino 
953f5b1c8a1SJohn Marino /*
954f5b1c8a1SJohn Marino  * remote_connect()
955f5b1c8a1SJohn Marino  * Returns a socket connected to a remote host. Properly binds to a local
956f5b1c8a1SJohn Marino  * port or source address if needed. Returns -1 on failure.
957f5b1c8a1SJohn Marino  */
958f5b1c8a1SJohn Marino int
remote_connect(const char * host,const char * port,struct addrinfo hints,char * ipaddr)959cca6fc52SDaniel Fojt remote_connect(const char *host, const char *port, struct addrinfo hints,
960cca6fc52SDaniel Fojt     char *ipaddr)
961f5b1c8a1SJohn Marino {
962f5b1c8a1SJohn Marino 	struct addrinfo *res, *res0;
963cca6fc52SDaniel Fojt 	int s = -1, error, herr, save_errno;
964f5b1c8a1SJohn Marino #ifdef SO_BINDANY
965f5b1c8a1SJohn Marino 	int on = 1;
966f5b1c8a1SJohn Marino #endif
967f5b1c8a1SJohn Marino 
96872c33676SMaxim Ag 	if ((error = getaddrinfo(host, port, &hints, &res0)))
96972c33676SMaxim Ag 		errx(1, "getaddrinfo for host \"%s\" port %s: %s", host,
97072c33676SMaxim Ag 		    port, gai_strerror(error));
971f5b1c8a1SJohn Marino 
97272c33676SMaxim Ag 	for (res = res0; res; res = res->ai_next) {
97372c33676SMaxim Ag 		if ((s = socket(res->ai_family, res->ai_socktype |
974cca6fc52SDaniel Fojt 		    SOCK_NONBLOCK, res->ai_protocol)) == -1)
975f5b1c8a1SJohn Marino 			continue;
976f5b1c8a1SJohn Marino 
977f5b1c8a1SJohn Marino 		/* Bind to a local port or source address if specified. */
978f5b1c8a1SJohn Marino 		if (sflag || pflag) {
979f5b1c8a1SJohn Marino 			struct addrinfo ahints, *ares;
980f5b1c8a1SJohn Marino 
981f5b1c8a1SJohn Marino #ifdef SO_BINDANY
982f5b1c8a1SJohn Marino 			/* try SO_BINDANY, but don't insist */
983f5b1c8a1SJohn Marino 			setsockopt(s, SOL_SOCKET, SO_BINDANY, &on, sizeof(on));
984f5b1c8a1SJohn Marino #endif
985f5b1c8a1SJohn Marino 			memset(&ahints, 0, sizeof(struct addrinfo));
98672c33676SMaxim Ag 			ahints.ai_family = res->ai_family;
987f5b1c8a1SJohn Marino 			ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
988f5b1c8a1SJohn Marino 			ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
989f5b1c8a1SJohn Marino 			ahints.ai_flags = AI_PASSIVE;
990f5b1c8a1SJohn Marino 			if ((error = getaddrinfo(sflag, pflag, &ahints, &ares)))
991f5b1c8a1SJohn Marino 				errx(1, "getaddrinfo: %s", gai_strerror(error));
992f5b1c8a1SJohn Marino 
993f5b1c8a1SJohn Marino 			if (bind(s, (struct sockaddr *)ares->ai_addr,
994cca6fc52SDaniel Fojt 			    ares->ai_addrlen) == -1)
995f5b1c8a1SJohn Marino 				err(1, "bind failed");
996f5b1c8a1SJohn Marino 			freeaddrinfo(ares);
997f5b1c8a1SJohn Marino 		}
998f5b1c8a1SJohn Marino 
99972c33676SMaxim Ag 		set_common_sockopts(s, res->ai_family);
1000f5b1c8a1SJohn Marino 
1001cca6fc52SDaniel Fojt 		if (ipaddr != NULL) {
1002cca6fc52SDaniel Fojt 			herr = getnameinfo(res->ai_addr, res->ai_addrlen,
1003cca6fc52SDaniel Fojt 			    ipaddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
1004cca6fc52SDaniel Fojt 			switch (herr) {
1005cca6fc52SDaniel Fojt 			case 0:
1006cca6fc52SDaniel Fojt 				break;
1007cca6fc52SDaniel Fojt 			case EAI_SYSTEM:
1008cca6fc52SDaniel Fojt 				err(1, "getnameinfo");
1009cca6fc52SDaniel Fojt 			default:
1010cca6fc52SDaniel Fojt 				errx(1, "getnameinfo: %s", gai_strerror(herr));
1011cca6fc52SDaniel Fojt 			}
1012cca6fc52SDaniel Fojt 		}
1013cca6fc52SDaniel Fojt 
101472c33676SMaxim Ag 		if (timeout_connect(s, res->ai_addr, res->ai_addrlen) == 0)
1015f5b1c8a1SJohn Marino 			break;
1016cca6fc52SDaniel Fojt 
1017cca6fc52SDaniel Fojt 		if (vflag) {
1018cca6fc52SDaniel Fojt 			/* only print IP if there is something to report */
1019cca6fc52SDaniel Fojt 			if (nflag || ipaddr == NULL ||
1020cca6fc52SDaniel Fojt 			    (strncmp(host, ipaddr, NI_MAXHOST) == 0))
1021cca6fc52SDaniel Fojt 				warn("connect to %s port %s (%s) failed", host,
1022cca6fc52SDaniel Fojt 				    port, uflag ? "udp" : "tcp");
1023cca6fc52SDaniel Fojt 			else
1024cca6fc52SDaniel Fojt 				warn("connect to %s (%s) port %s (%s) failed",
1025cca6fc52SDaniel Fojt 				    host, ipaddr, port, uflag ? "udp" : "tcp");
1026cca6fc52SDaniel Fojt 		}
1027f5b1c8a1SJohn Marino 
1028f5b1c8a1SJohn Marino 		save_errno = errno;
1029f5b1c8a1SJohn Marino 		close(s);
1030f5b1c8a1SJohn Marino 		errno = save_errno;
1031f5b1c8a1SJohn Marino 		s = -1;
103272c33676SMaxim Ag 	}
1033f5b1c8a1SJohn Marino 
103472c33676SMaxim Ag 	freeaddrinfo(res0);
1035f5b1c8a1SJohn Marino 
103672c33676SMaxim Ag 	return s;
1037f5b1c8a1SJohn Marino }
1038f5b1c8a1SJohn Marino 
1039f5b1c8a1SJohn Marino int
timeout_connect(int s,const struct sockaddr * name,socklen_t namelen)1040f5b1c8a1SJohn Marino timeout_connect(int s, const struct sockaddr *name, socklen_t namelen)
1041f5b1c8a1SJohn Marino {
1042f5b1c8a1SJohn Marino 	struct pollfd pfd;
1043f5b1c8a1SJohn Marino 	socklen_t optlen;
1044f5b1c8a1SJohn Marino 	int optval;
1045f5b1c8a1SJohn Marino 	int ret;
1046f5b1c8a1SJohn Marino 
1047f5b1c8a1SJohn Marino 	if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) {
1048f5b1c8a1SJohn Marino 		pfd.fd = s;
1049f5b1c8a1SJohn Marino 		pfd.events = POLLOUT;
1050f5b1c8a1SJohn Marino 		if ((ret = poll(&pfd, 1, timeout)) == 1) {
1051f5b1c8a1SJohn Marino 			optlen = sizeof(optval);
1052f5b1c8a1SJohn Marino 			if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR,
1053f5b1c8a1SJohn Marino 			    &optval, &optlen)) == 0) {
1054f5b1c8a1SJohn Marino 				errno = optval;
1055f5b1c8a1SJohn Marino 				ret = optval == 0 ? 0 : -1;
1056f5b1c8a1SJohn Marino 			}
1057f5b1c8a1SJohn Marino 		} else if (ret == 0) {
1058f5b1c8a1SJohn Marino 			errno = ETIMEDOUT;
1059f5b1c8a1SJohn Marino 			ret = -1;
1060f5b1c8a1SJohn Marino 		} else
1061f5b1c8a1SJohn Marino 			err(1, "poll failed");
1062f5b1c8a1SJohn Marino 	}
1063f5b1c8a1SJohn Marino 
106472c33676SMaxim Ag 	return ret;
1065f5b1c8a1SJohn Marino }
1066f5b1c8a1SJohn Marino 
1067f5b1c8a1SJohn Marino /*
1068f5b1c8a1SJohn Marino  * local_listen()
1069f5b1c8a1SJohn Marino  * Returns a socket listening on a local port, binds to specified source
1070f5b1c8a1SJohn Marino  * address. Returns -1 on failure.
1071f5b1c8a1SJohn Marino  */
1072f5b1c8a1SJohn Marino int
local_listen(const char * host,const char * port,struct addrinfo hints)107372c33676SMaxim Ag local_listen(const char *host, const char *port, struct addrinfo hints)
1074f5b1c8a1SJohn Marino {
1075f5b1c8a1SJohn Marino 	struct addrinfo *res, *res0;
107672c33676SMaxim Ag 	int s = -1, save_errno;
1077f5b1c8a1SJohn Marino #ifdef SO_REUSEPORT
1078f5b1c8a1SJohn Marino 	int ret, x = 1;
1079f5b1c8a1SJohn Marino #endif
1080f5b1c8a1SJohn Marino 	int error;
1081f5b1c8a1SJohn Marino 
1082f5b1c8a1SJohn Marino 	/* Allow nodename to be null. */
1083f5b1c8a1SJohn Marino 	hints.ai_flags |= AI_PASSIVE;
1084f5b1c8a1SJohn Marino 
1085f5b1c8a1SJohn Marino 	/*
1086f5b1c8a1SJohn Marino 	 * In the case of binding to a wildcard address
1087f5b1c8a1SJohn Marino 	 * default to binding to an ipv4 address.
1088f5b1c8a1SJohn Marino 	 */
1089f5b1c8a1SJohn Marino 	if (host == NULL && hints.ai_family == AF_UNSPEC)
1090f5b1c8a1SJohn Marino 		hints.ai_family = AF_INET;
1091f5b1c8a1SJohn Marino 
109272c33676SMaxim Ag 	if ((error = getaddrinfo(host, port, &hints, &res0)))
1093f5b1c8a1SJohn Marino 		errx(1, "getaddrinfo: %s", gai_strerror(error));
1094f5b1c8a1SJohn Marino 
109572c33676SMaxim Ag 	for (res = res0; res; res = res->ai_next) {
109672c33676SMaxim Ag 		if ((s = socket(res->ai_family, res->ai_socktype,
1097cca6fc52SDaniel Fojt 		    res->ai_protocol)) == -1)
1098f5b1c8a1SJohn Marino 			continue;
1099f5b1c8a1SJohn Marino 
1100f5b1c8a1SJohn Marino #ifdef SO_REUSEPORT
1101f5b1c8a1SJohn Marino 		ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));
1102f5b1c8a1SJohn Marino 		if (ret == -1)
1103f5b1c8a1SJohn Marino 			err(1, NULL);
1104f5b1c8a1SJohn Marino #endif
1105f5b1c8a1SJohn Marino 
110672c33676SMaxim Ag 		set_common_sockopts(s, res->ai_family);
1107f5b1c8a1SJohn Marino 
110872c33676SMaxim Ag 		if (bind(s, (struct sockaddr *)res->ai_addr,
110972c33676SMaxim Ag 		    res->ai_addrlen) == 0)
1110f5b1c8a1SJohn Marino 			break;
1111f5b1c8a1SJohn Marino 
1112f5b1c8a1SJohn Marino 		save_errno = errno;
1113f5b1c8a1SJohn Marino 		close(s);
1114f5b1c8a1SJohn Marino 		errno = save_errno;
1115f5b1c8a1SJohn Marino 		s = -1;
111672c33676SMaxim Ag 	}
1117f5b1c8a1SJohn Marino 
1118f5b1c8a1SJohn Marino 	if (!uflag && s != -1) {
1119cca6fc52SDaniel Fojt 		if (listen(s, 1) == -1)
1120f5b1c8a1SJohn Marino 			err(1, "listen");
1121f5b1c8a1SJohn Marino 	}
112272c33676SMaxim Ag 	if (vflag && s != -1) {
112372c33676SMaxim Ag 		struct sockaddr_storage ss;
112472c33676SMaxim Ag 		socklen_t len;
1125f5b1c8a1SJohn Marino 
112672c33676SMaxim Ag 		len = sizeof(ss);
112772c33676SMaxim Ag 		if (getsockname(s, (struct sockaddr *)&ss, &len) == -1)
112872c33676SMaxim Ag 			err(1, "getsockname");
112972c33676SMaxim Ag 		report_sock(uflag ? "Bound" : "Listening",
113072c33676SMaxim Ag 		    (struct sockaddr *)&ss, len, NULL);
113172c33676SMaxim Ag 	}
1132f5b1c8a1SJohn Marino 
113372c33676SMaxim Ag 	freeaddrinfo(res0);
113472c33676SMaxim Ag 
113572c33676SMaxim Ag 	return s;
1136f5b1c8a1SJohn Marino }
1137f5b1c8a1SJohn Marino 
1138f5b1c8a1SJohn Marino /*
1139f5b1c8a1SJohn Marino  * readwrite()
1140f5b1c8a1SJohn Marino  * Loop that polls on the network file descriptor and stdin.
1141f5b1c8a1SJohn Marino  */
1142f5b1c8a1SJohn Marino void
readwrite(int net_fd,struct tls * tls_ctx)1143f5b1c8a1SJohn Marino readwrite(int net_fd, struct tls *tls_ctx)
1144f5b1c8a1SJohn Marino {
1145f5b1c8a1SJohn Marino 	struct pollfd pfd[4];
1146f5b1c8a1SJohn Marino 	int stdin_fd = STDIN_FILENO;
1147f5b1c8a1SJohn Marino 	int stdout_fd = STDOUT_FILENO;
1148f5b1c8a1SJohn Marino 	unsigned char netinbuf[BUFSIZE];
1149f5b1c8a1SJohn Marino 	size_t netinbufpos = 0;
1150f5b1c8a1SJohn Marino 	unsigned char stdinbuf[BUFSIZE];
1151f5b1c8a1SJohn Marino 	size_t stdinbufpos = 0;
1152f5b1c8a1SJohn Marino 	int n, num_fds;
1153f5b1c8a1SJohn Marino 	ssize_t ret;
1154f5b1c8a1SJohn Marino 
1155f5b1c8a1SJohn Marino 	/* don't read from stdin if requested */
1156f5b1c8a1SJohn Marino 	if (dflag)
1157f5b1c8a1SJohn Marino 		stdin_fd = -1;
1158f5b1c8a1SJohn Marino 
1159f5b1c8a1SJohn Marino 	/* stdin */
1160f5b1c8a1SJohn Marino 	pfd[POLL_STDIN].fd = stdin_fd;
1161f5b1c8a1SJohn Marino 	pfd[POLL_STDIN].events = POLLIN;
1162f5b1c8a1SJohn Marino 
1163f5b1c8a1SJohn Marino 	/* network out */
1164f5b1c8a1SJohn Marino 	pfd[POLL_NETOUT].fd = net_fd;
1165f5b1c8a1SJohn Marino 	pfd[POLL_NETOUT].events = 0;
1166f5b1c8a1SJohn Marino 
1167f5b1c8a1SJohn Marino 	/* network in */
1168f5b1c8a1SJohn Marino 	pfd[POLL_NETIN].fd = net_fd;
1169f5b1c8a1SJohn Marino 	pfd[POLL_NETIN].events = POLLIN;
1170f5b1c8a1SJohn Marino 
1171f5b1c8a1SJohn Marino 	/* stdout */
1172f5b1c8a1SJohn Marino 	pfd[POLL_STDOUT].fd = stdout_fd;
1173f5b1c8a1SJohn Marino 	pfd[POLL_STDOUT].events = 0;
1174f5b1c8a1SJohn Marino 
1175f5b1c8a1SJohn Marino 	while (1) {
1176f5b1c8a1SJohn Marino 		/* both inputs are gone, buffers are empty, we are done */
1177f5b1c8a1SJohn Marino 		if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1 &&
117872c33676SMaxim Ag 		    stdinbufpos == 0 && netinbufpos == 0)
1179f5b1c8a1SJohn Marino 			return;
1180f5b1c8a1SJohn Marino 		/* both outputs are gone, we can't continue */
118172c33676SMaxim Ag 		if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1)
1182f5b1c8a1SJohn Marino 			return;
1183f5b1c8a1SJohn Marino 		/* listen and net in gone, queues empty, done */
1184f5b1c8a1SJohn Marino 		if (lflag && pfd[POLL_NETIN].fd == -1 &&
118572c33676SMaxim Ag 		    stdinbufpos == 0 && netinbufpos == 0)
1186f5b1c8a1SJohn Marino 			return;
1187f5b1c8a1SJohn Marino 
1188f5b1c8a1SJohn Marino 		/* help says -i is for "wait between lines sent". We read and
1189f5b1c8a1SJohn Marino 		 * write arbitrary amounts of data, and we don't want to start
1190f5b1c8a1SJohn Marino 		 * scanning for newlines, so this is as good as it gets */
1191f5b1c8a1SJohn Marino 		if (iflag)
1192f5b1c8a1SJohn Marino 			sleep(iflag);
1193f5b1c8a1SJohn Marino 
1194f5b1c8a1SJohn Marino 		/* poll */
1195f5b1c8a1SJohn Marino 		num_fds = poll(pfd, 4, timeout);
1196f5b1c8a1SJohn Marino 
1197f5b1c8a1SJohn Marino 		/* treat poll errors */
119872c33676SMaxim Ag 		if (num_fds == -1)
1199f5b1c8a1SJohn Marino 			err(1, "polling error");
1200f5b1c8a1SJohn Marino 
1201f5b1c8a1SJohn Marino 		/* timeout happened */
1202f5b1c8a1SJohn Marino 		if (num_fds == 0)
1203f5b1c8a1SJohn Marino 			return;
1204f5b1c8a1SJohn Marino 
1205f5b1c8a1SJohn Marino 		/* treat socket error conditions */
1206f5b1c8a1SJohn Marino 		for (n = 0; n < 4; n++) {
1207f5b1c8a1SJohn Marino 			if (pfd[n].revents & (POLLERR|POLLNVAL)) {
1208f5b1c8a1SJohn Marino 				pfd[n].fd = -1;
1209f5b1c8a1SJohn Marino 			}
1210f5b1c8a1SJohn Marino 		}
1211f5b1c8a1SJohn Marino 		/* reading is possible after HUP */
1212f5b1c8a1SJohn Marino 		if (pfd[POLL_STDIN].events & POLLIN &&
1213f5b1c8a1SJohn Marino 		    pfd[POLL_STDIN].revents & POLLHUP &&
1214f5b1c8a1SJohn Marino 		    !(pfd[POLL_STDIN].revents & POLLIN))
1215f5b1c8a1SJohn Marino 			pfd[POLL_STDIN].fd = -1;
1216f5b1c8a1SJohn Marino 
1217f5b1c8a1SJohn Marino 		if (pfd[POLL_NETIN].events & POLLIN &&
1218f5b1c8a1SJohn Marino 		    pfd[POLL_NETIN].revents & POLLHUP &&
1219f5b1c8a1SJohn Marino 		    !(pfd[POLL_NETIN].revents & POLLIN))
1220f5b1c8a1SJohn Marino 			pfd[POLL_NETIN].fd = -1;
1221f5b1c8a1SJohn Marino 
1222f5b1c8a1SJohn Marino 		if (pfd[POLL_NETOUT].revents & POLLHUP) {
1223f5b1c8a1SJohn Marino 			if (Nflag)
1224f5b1c8a1SJohn Marino 				shutdown(pfd[POLL_NETOUT].fd, SHUT_WR);
1225f5b1c8a1SJohn Marino 			pfd[POLL_NETOUT].fd = -1;
1226f5b1c8a1SJohn Marino 		}
1227f5b1c8a1SJohn Marino 		/* if HUP, stop watching stdout */
1228f5b1c8a1SJohn Marino 		if (pfd[POLL_STDOUT].revents & POLLHUP)
1229f5b1c8a1SJohn Marino 			pfd[POLL_STDOUT].fd = -1;
1230f5b1c8a1SJohn Marino 		/* if no net out, stop watching stdin */
1231f5b1c8a1SJohn Marino 		if (pfd[POLL_NETOUT].fd == -1)
1232f5b1c8a1SJohn Marino 			pfd[POLL_STDIN].fd = -1;
1233f5b1c8a1SJohn Marino 		/* if no stdout, stop watching net in */
1234f5b1c8a1SJohn Marino 		if (pfd[POLL_STDOUT].fd == -1) {
1235f5b1c8a1SJohn Marino 			if (pfd[POLL_NETIN].fd != -1)
1236f5b1c8a1SJohn Marino 				shutdown(pfd[POLL_NETIN].fd, SHUT_RD);
1237f5b1c8a1SJohn Marino 			pfd[POLL_NETIN].fd = -1;
1238f5b1c8a1SJohn Marino 		}
1239f5b1c8a1SJohn Marino 
1240f5b1c8a1SJohn Marino 		/* try to read from stdin */
1241f5b1c8a1SJohn Marino 		if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) {
1242f5b1c8a1SJohn Marino 			ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf,
1243f5b1c8a1SJohn Marino 			    &stdinbufpos, NULL);
1244f5b1c8a1SJohn Marino 			if (ret == TLS_WANT_POLLIN)
1245f5b1c8a1SJohn Marino 				pfd[POLL_STDIN].events = POLLIN;
1246f5b1c8a1SJohn Marino 			else if (ret == TLS_WANT_POLLOUT)
1247f5b1c8a1SJohn Marino 				pfd[POLL_STDIN].events = POLLOUT;
1248f5b1c8a1SJohn Marino 			else if (ret == 0 || ret == -1)
1249f5b1c8a1SJohn Marino 				pfd[POLL_STDIN].fd = -1;
1250f5b1c8a1SJohn Marino 			/* read something - poll net out */
1251f5b1c8a1SJohn Marino 			if (stdinbufpos > 0)
1252f5b1c8a1SJohn Marino 				pfd[POLL_NETOUT].events = POLLOUT;
1253f5b1c8a1SJohn Marino 			/* filled buffer - remove self from polling */
1254f5b1c8a1SJohn Marino 			if (stdinbufpos == BUFSIZE)
1255f5b1c8a1SJohn Marino 				pfd[POLL_STDIN].events = 0;
1256f5b1c8a1SJohn Marino 		}
1257f5b1c8a1SJohn Marino 		/* try to write to network */
1258f5b1c8a1SJohn Marino 		if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) {
1259f5b1c8a1SJohn Marino 			ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf,
1260f5b1c8a1SJohn Marino 			    &stdinbufpos, tls_ctx);
1261f5b1c8a1SJohn Marino 			if (ret == TLS_WANT_POLLIN)
1262f5b1c8a1SJohn Marino 				pfd[POLL_NETOUT].events = POLLIN;
1263f5b1c8a1SJohn Marino 			else if (ret == TLS_WANT_POLLOUT)
1264f5b1c8a1SJohn Marino 				pfd[POLL_NETOUT].events = POLLOUT;
1265f5b1c8a1SJohn Marino 			else if (ret == -1)
1266f5b1c8a1SJohn Marino 				pfd[POLL_NETOUT].fd = -1;
1267f5b1c8a1SJohn Marino 			/* buffer empty - remove self from polling */
1268f5b1c8a1SJohn Marino 			if (stdinbufpos == 0)
1269f5b1c8a1SJohn Marino 				pfd[POLL_NETOUT].events = 0;
1270f5b1c8a1SJohn Marino 			/* buffer no longer full - poll stdin again */
1271f5b1c8a1SJohn Marino 			if (stdinbufpos < BUFSIZE)
1272f5b1c8a1SJohn Marino 				pfd[POLL_STDIN].events = POLLIN;
1273f5b1c8a1SJohn Marino 		}
1274f5b1c8a1SJohn Marino 		/* try to read from network */
1275f5b1c8a1SJohn Marino 		if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) {
1276f5b1c8a1SJohn Marino 			ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf,
1277f5b1c8a1SJohn Marino 			    &netinbufpos, tls_ctx);
1278f5b1c8a1SJohn Marino 			if (ret == TLS_WANT_POLLIN)
1279f5b1c8a1SJohn Marino 				pfd[POLL_NETIN].events = POLLIN;
1280f5b1c8a1SJohn Marino 			else if (ret == TLS_WANT_POLLOUT)
1281f5b1c8a1SJohn Marino 				pfd[POLL_NETIN].events = POLLOUT;
1282f5b1c8a1SJohn Marino 			else if (ret == -1)
1283f5b1c8a1SJohn Marino 				pfd[POLL_NETIN].fd = -1;
1284f5b1c8a1SJohn Marino 			/* eof on net in - remove from pfd */
1285f5b1c8a1SJohn Marino 			if (ret == 0) {
1286f5b1c8a1SJohn Marino 				shutdown(pfd[POLL_NETIN].fd, SHUT_RD);
1287f5b1c8a1SJohn Marino 				pfd[POLL_NETIN].fd = -1;
1288f5b1c8a1SJohn Marino 			}
128972c33676SMaxim Ag 			if (recvlimit > 0 && ++recvcount >= recvlimit) {
129072c33676SMaxim Ag 				if (pfd[POLL_NETIN].fd != -1)
129172c33676SMaxim Ag 					shutdown(pfd[POLL_NETIN].fd, SHUT_RD);
129272c33676SMaxim Ag 				pfd[POLL_NETIN].fd = -1;
129372c33676SMaxim Ag 				pfd[POLL_STDIN].fd = -1;
129472c33676SMaxim Ag 			}
1295f5b1c8a1SJohn Marino 			/* read something - poll stdout */
1296f5b1c8a1SJohn Marino 			if (netinbufpos > 0)
1297f5b1c8a1SJohn Marino 				pfd[POLL_STDOUT].events = POLLOUT;
1298f5b1c8a1SJohn Marino 			/* filled buffer - remove self from polling */
1299f5b1c8a1SJohn Marino 			if (netinbufpos == BUFSIZE)
1300f5b1c8a1SJohn Marino 				pfd[POLL_NETIN].events = 0;
1301f5b1c8a1SJohn Marino 			/* handle telnet */
1302f5b1c8a1SJohn Marino 			if (tflag)
1303f5b1c8a1SJohn Marino 				atelnet(pfd[POLL_NETIN].fd, netinbuf,
1304f5b1c8a1SJohn Marino 				    netinbufpos);
1305f5b1c8a1SJohn Marino 		}
1306f5b1c8a1SJohn Marino 		/* try to write to stdout */
1307f5b1c8a1SJohn Marino 		if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) {
1308f5b1c8a1SJohn Marino 			ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf,
1309f5b1c8a1SJohn Marino 			    &netinbufpos, NULL);
1310f5b1c8a1SJohn Marino 			if (ret == TLS_WANT_POLLIN)
1311f5b1c8a1SJohn Marino 				pfd[POLL_STDOUT].events = POLLIN;
1312f5b1c8a1SJohn Marino 			else if (ret == TLS_WANT_POLLOUT)
1313f5b1c8a1SJohn Marino 				pfd[POLL_STDOUT].events = POLLOUT;
1314f5b1c8a1SJohn Marino 			else if (ret == -1)
1315f5b1c8a1SJohn Marino 				pfd[POLL_STDOUT].fd = -1;
1316f5b1c8a1SJohn Marino 			/* buffer empty - remove self from polling */
1317f5b1c8a1SJohn Marino 			if (netinbufpos == 0)
1318f5b1c8a1SJohn Marino 				pfd[POLL_STDOUT].events = 0;
1319f5b1c8a1SJohn Marino 			/* buffer no longer full - poll net in again */
1320f5b1c8a1SJohn Marino 			if (netinbufpos < BUFSIZE)
1321f5b1c8a1SJohn Marino 				pfd[POLL_NETIN].events = POLLIN;
1322f5b1c8a1SJohn Marino 		}
1323f5b1c8a1SJohn Marino 
1324f5b1c8a1SJohn Marino 		/* stdin gone and queue empty? */
1325f5b1c8a1SJohn Marino 		if (pfd[POLL_STDIN].fd == -1 && stdinbufpos == 0) {
1326f5b1c8a1SJohn Marino 			if (pfd[POLL_NETOUT].fd != -1 && Nflag)
1327f5b1c8a1SJohn Marino 				shutdown(pfd[POLL_NETOUT].fd, SHUT_WR);
1328f5b1c8a1SJohn Marino 			pfd[POLL_NETOUT].fd = -1;
1329f5b1c8a1SJohn Marino 		}
1330f5b1c8a1SJohn Marino 		/* net in gone and queue empty? */
1331f5b1c8a1SJohn Marino 		if (pfd[POLL_NETIN].fd == -1 && netinbufpos == 0) {
1332f5b1c8a1SJohn Marino 			pfd[POLL_STDOUT].fd = -1;
1333f5b1c8a1SJohn Marino 		}
1334f5b1c8a1SJohn Marino 	}
1335f5b1c8a1SJohn Marino }
1336f5b1c8a1SJohn Marino 
1337f5b1c8a1SJohn Marino ssize_t
drainbuf(int fd,unsigned char * buf,size_t * bufpos,struct tls * tls)1338f5b1c8a1SJohn Marino drainbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls)
1339f5b1c8a1SJohn Marino {
1340f5b1c8a1SJohn Marino 	ssize_t n;
1341f5b1c8a1SJohn Marino 	ssize_t adjust;
1342f5b1c8a1SJohn Marino 
134372c33676SMaxim Ag 	if (tls) {
1344f5b1c8a1SJohn Marino 		n = tls_write(tls, buf, *bufpos);
134572c33676SMaxim Ag 		if (n == -1)
134672c33676SMaxim Ag 			errx(1, "tls write failed (%s)", tls_error(tls));
134772c33676SMaxim Ag 	} else {
1348f5b1c8a1SJohn Marino 		n = write(fd, buf, *bufpos);
1349f5b1c8a1SJohn Marino 		/* don't treat EAGAIN, EINTR as error */
1350f5b1c8a1SJohn Marino 		if (n == -1 && (errno == EAGAIN || errno == EINTR))
1351f5b1c8a1SJohn Marino 			n = TLS_WANT_POLLOUT;
1352f5b1c8a1SJohn Marino 	}
1353f5b1c8a1SJohn Marino 	if (n <= 0)
1354f5b1c8a1SJohn Marino 		return n;
1355f5b1c8a1SJohn Marino 	/* adjust buffer */
1356f5b1c8a1SJohn Marino 	adjust = *bufpos - n;
1357f5b1c8a1SJohn Marino 	if (adjust > 0)
1358f5b1c8a1SJohn Marino 		memmove(buf, buf + n, adjust);
1359f5b1c8a1SJohn Marino 	*bufpos -= n;
1360f5b1c8a1SJohn Marino 	return n;
1361f5b1c8a1SJohn Marino }
1362f5b1c8a1SJohn Marino 
1363f5b1c8a1SJohn Marino ssize_t
fillbuf(int fd,unsigned char * buf,size_t * bufpos,struct tls * tls)1364f5b1c8a1SJohn Marino fillbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls)
1365f5b1c8a1SJohn Marino {
1366f5b1c8a1SJohn Marino 	size_t num = BUFSIZE - *bufpos;
1367f5b1c8a1SJohn Marino 	ssize_t n;
1368f5b1c8a1SJohn Marino 
136972c33676SMaxim Ag 	if (tls) {
1370f5b1c8a1SJohn Marino 		n = tls_read(tls, buf + *bufpos, num);
137172c33676SMaxim Ag 		if (n == -1)
137272c33676SMaxim Ag 			errx(1, "tls read failed (%s)", tls_error(tls));
137372c33676SMaxim Ag 	} else {
1374f5b1c8a1SJohn Marino 		n = read(fd, buf + *bufpos, num);
1375f5b1c8a1SJohn Marino 		/* don't treat EAGAIN, EINTR as error */
1376f5b1c8a1SJohn Marino 		if (n == -1 && (errno == EAGAIN || errno == EINTR))
1377f5b1c8a1SJohn Marino 			n = TLS_WANT_POLLIN;
1378f5b1c8a1SJohn Marino 	}
1379f5b1c8a1SJohn Marino 	if (n <= 0)
1380f5b1c8a1SJohn Marino 		return n;
1381f5b1c8a1SJohn Marino 	*bufpos += n;
1382f5b1c8a1SJohn Marino 	return n;
1383f5b1c8a1SJohn Marino }
1384f5b1c8a1SJohn Marino 
1385f5b1c8a1SJohn Marino /*
1386f5b1c8a1SJohn Marino  * fdpass()
1387f5b1c8a1SJohn Marino  * Pass the connected file descriptor to stdout and exit.
1388f5b1c8a1SJohn Marino  */
1389f5b1c8a1SJohn Marino void
fdpass(int nfd)1390f5b1c8a1SJohn Marino fdpass(int nfd)
1391f5b1c8a1SJohn Marino {
1392f5b1c8a1SJohn Marino 	struct msghdr mh;
1393f5b1c8a1SJohn Marino 	union {
1394f5b1c8a1SJohn Marino 		struct cmsghdr hdr;
1395f5b1c8a1SJohn Marino 		char buf[CMSG_SPACE(sizeof(int))];
1396f5b1c8a1SJohn Marino 	} cmsgbuf;
1397f5b1c8a1SJohn Marino 	struct cmsghdr *cmsg;
1398f5b1c8a1SJohn Marino 	struct iovec iov;
1399f5b1c8a1SJohn Marino 	char c = '\0';
1400f5b1c8a1SJohn Marino 	ssize_t r;
1401f5b1c8a1SJohn Marino 	struct pollfd pfd;
1402f5b1c8a1SJohn Marino 
1403f5b1c8a1SJohn Marino 	/* Avoid obvious stupidity */
1404f5b1c8a1SJohn Marino 	if (isatty(STDOUT_FILENO))
1405f5b1c8a1SJohn Marino 		errx(1, "Cannot pass file descriptor to tty");
1406f5b1c8a1SJohn Marino 
140772c33676SMaxim Ag 	memset(&mh, 0, sizeof(mh));
140872c33676SMaxim Ag 	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
140972c33676SMaxim Ag 	memset(&iov, 0, sizeof(iov));
1410f5b1c8a1SJohn Marino 
1411f5b1c8a1SJohn Marino 	mh.msg_control = (caddr_t)&cmsgbuf.buf;
1412f5b1c8a1SJohn Marino 	mh.msg_controllen = sizeof(cmsgbuf.buf);
1413f5b1c8a1SJohn Marino 	cmsg = CMSG_FIRSTHDR(&mh);
1414f5b1c8a1SJohn Marino 	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
1415f5b1c8a1SJohn Marino 	cmsg->cmsg_level = SOL_SOCKET;
1416f5b1c8a1SJohn Marino 	cmsg->cmsg_type = SCM_RIGHTS;
1417f5b1c8a1SJohn Marino 	*(int *)CMSG_DATA(cmsg) = nfd;
1418f5b1c8a1SJohn Marino 
1419f5b1c8a1SJohn Marino 	iov.iov_base = &c;
1420f5b1c8a1SJohn Marino 	iov.iov_len = 1;
1421f5b1c8a1SJohn Marino 	mh.msg_iov = &iov;
1422f5b1c8a1SJohn Marino 	mh.msg_iovlen = 1;
1423f5b1c8a1SJohn Marino 
142472c33676SMaxim Ag 	memset(&pfd, 0, sizeof(pfd));
1425f5b1c8a1SJohn Marino 	pfd.fd = STDOUT_FILENO;
1426f5b1c8a1SJohn Marino 	pfd.events = POLLOUT;
1427f5b1c8a1SJohn Marino 	for (;;) {
1428f5b1c8a1SJohn Marino 		r = sendmsg(STDOUT_FILENO, &mh, 0);
1429f5b1c8a1SJohn Marino 		if (r == -1) {
1430f5b1c8a1SJohn Marino 			if (errno == EAGAIN || errno == EINTR) {
1431f5b1c8a1SJohn Marino 				if (poll(&pfd, 1, -1) == -1)
1432f5b1c8a1SJohn Marino 					err(1, "poll");
1433f5b1c8a1SJohn Marino 				continue;
1434f5b1c8a1SJohn Marino 			}
1435f5b1c8a1SJohn Marino 			err(1, "sendmsg");
1436f5b1c8a1SJohn Marino 		} else if (r != 1)
1437f5b1c8a1SJohn Marino 			errx(1, "sendmsg: unexpected return value %zd", r);
1438f5b1c8a1SJohn Marino 		else
1439f5b1c8a1SJohn Marino 			break;
1440f5b1c8a1SJohn Marino 	}
1441f5b1c8a1SJohn Marino 	exit(0);
1442f5b1c8a1SJohn Marino }
1443f5b1c8a1SJohn Marino 
1444f5b1c8a1SJohn Marino /* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */
1445f5b1c8a1SJohn Marino void
atelnet(int nfd,unsigned char * buf,unsigned int size)1446f5b1c8a1SJohn Marino atelnet(int nfd, unsigned char *buf, unsigned int size)
1447f5b1c8a1SJohn Marino {
1448f5b1c8a1SJohn Marino 	unsigned char *p, *end;
1449f5b1c8a1SJohn Marino 	unsigned char obuf[4];
1450f5b1c8a1SJohn Marino 
1451f5b1c8a1SJohn Marino 	if (size < 3)
1452f5b1c8a1SJohn Marino 		return;
1453f5b1c8a1SJohn Marino 	end = buf + size - 2;
1454f5b1c8a1SJohn Marino 
1455f5b1c8a1SJohn Marino 	for (p = buf; p < end; p++) {
1456f5b1c8a1SJohn Marino 		if (*p != IAC)
1457f5b1c8a1SJohn Marino 			continue;
1458f5b1c8a1SJohn Marino 
1459f5b1c8a1SJohn Marino 		obuf[0] = IAC;
1460f5b1c8a1SJohn Marino 		p++;
1461f5b1c8a1SJohn Marino 		if ((*p == WILL) || (*p == WONT))
1462f5b1c8a1SJohn Marino 			obuf[1] = DONT;
1463f5b1c8a1SJohn Marino 		else if ((*p == DO) || (*p == DONT))
1464f5b1c8a1SJohn Marino 			obuf[1] = WONT;
1465f5b1c8a1SJohn Marino 		else
1466f5b1c8a1SJohn Marino 			continue;
1467f5b1c8a1SJohn Marino 
1468f5b1c8a1SJohn Marino 		p++;
1469f5b1c8a1SJohn Marino 		obuf[2] = *p;
1470f5b1c8a1SJohn Marino 		if (atomicio(vwrite, nfd, obuf, 3) != 3)
1471f5b1c8a1SJohn Marino 			warn("Write Error!");
1472f5b1c8a1SJohn Marino 	}
1473f5b1c8a1SJohn Marino }
1474f5b1c8a1SJohn Marino 
1475f5b1c8a1SJohn Marino int
strtoport(char * portstr,int udp)1476f5b1c8a1SJohn Marino strtoport(char *portstr, int udp)
1477f5b1c8a1SJohn Marino {
1478f5b1c8a1SJohn Marino 	struct servent *entry;
1479f5b1c8a1SJohn Marino 	const char *errstr;
1480f5b1c8a1SJohn Marino 	char *proto;
1481f5b1c8a1SJohn Marino 	int port = -1;
1482f5b1c8a1SJohn Marino 
1483f5b1c8a1SJohn Marino 	proto = udp ? "udp" : "tcp";
1484f5b1c8a1SJohn Marino 
1485f5b1c8a1SJohn Marino 	port = strtonum(portstr, 1, PORT_MAX, &errstr);
1486f5b1c8a1SJohn Marino 	if (errstr == NULL)
1487f5b1c8a1SJohn Marino 		return port;
1488f5b1c8a1SJohn Marino 	if (errno != EINVAL)
1489f5b1c8a1SJohn Marino 		errx(1, "port number %s: %s", errstr, portstr);
1490f5b1c8a1SJohn Marino 	if ((entry = getservbyname(portstr, proto)) == NULL)
1491f5b1c8a1SJohn Marino 		errx(1, "service \"%s\" unknown", portstr);
1492f5b1c8a1SJohn Marino 	return ntohs(entry->s_port);
1493f5b1c8a1SJohn Marino }
1494f5b1c8a1SJohn Marino 
1495f5b1c8a1SJohn Marino /*
1496f5b1c8a1SJohn Marino  * build_ports()
1497f5b1c8a1SJohn Marino  * Build an array of ports in portlist[], listing each port
1498f5b1c8a1SJohn Marino  * that we should try to connect to.
1499f5b1c8a1SJohn Marino  */
1500f5b1c8a1SJohn Marino void
build_ports(char * p)1501f5b1c8a1SJohn Marino build_ports(char *p)
1502f5b1c8a1SJohn Marino {
1503f5b1c8a1SJohn Marino 	char *n;
1504f5b1c8a1SJohn Marino 	int hi, lo, cp;
1505f5b1c8a1SJohn Marino 	int x = 0;
1506f5b1c8a1SJohn Marino 
150772c33676SMaxim Ag 	if (isdigit((unsigned char)*p) && (n = strchr(p, '-')) != NULL) {
1508f5b1c8a1SJohn Marino 		*n = '\0';
1509f5b1c8a1SJohn Marino 		n++;
1510f5b1c8a1SJohn Marino 
1511f5b1c8a1SJohn Marino 		/* Make sure the ports are in order: lowest->highest. */
1512f5b1c8a1SJohn Marino 		hi = strtoport(n, uflag);
1513f5b1c8a1SJohn Marino 		lo = strtoport(p, uflag);
1514f5b1c8a1SJohn Marino 		if (lo > hi) {
1515f5b1c8a1SJohn Marino 			cp = hi;
1516f5b1c8a1SJohn Marino 			hi = lo;
1517f5b1c8a1SJohn Marino 			lo = cp;
1518f5b1c8a1SJohn Marino 		}
1519f5b1c8a1SJohn Marino 
1520f5b1c8a1SJohn Marino 		/*
1521f5b1c8a1SJohn Marino 		 * Initialize portlist with a random permutation.  Based on
1522f5b1c8a1SJohn Marino 		 * Knuth, as in ip_randomid() in sys/netinet/ip_id.c.
1523f5b1c8a1SJohn Marino 		 */
1524f5b1c8a1SJohn Marino 		if (rflag) {
1525f5b1c8a1SJohn Marino 			for (x = 0; x <= hi - lo; x++) {
1526f5b1c8a1SJohn Marino 				cp = arc4random_uniform(x + 1);
1527f5b1c8a1SJohn Marino 				portlist[x] = portlist[cp];
1528cca6fc52SDaniel Fojt 				if (asprintf(&portlist[cp], "%d", x + lo) == -1)
1529f5b1c8a1SJohn Marino 					err(1, "asprintf");
1530f5b1c8a1SJohn Marino 			}
1531f5b1c8a1SJohn Marino 		} else { /* Load ports sequentially. */
1532f5b1c8a1SJohn Marino 			for (cp = lo; cp <= hi; cp++) {
1533cca6fc52SDaniel Fojt 				if (asprintf(&portlist[x], "%d", cp) == -1)
1534f5b1c8a1SJohn Marino 					err(1, "asprintf");
1535f5b1c8a1SJohn Marino 				x++;
1536f5b1c8a1SJohn Marino 			}
1537f5b1c8a1SJohn Marino 		}
1538f5b1c8a1SJohn Marino 	} else {
1539f5b1c8a1SJohn Marino 		char *tmp;
1540f5b1c8a1SJohn Marino 
1541f5b1c8a1SJohn Marino 		hi = strtoport(p, uflag);
1542f5b1c8a1SJohn Marino 		if (asprintf(&tmp, "%d", hi) != -1)
1543f5b1c8a1SJohn Marino 			portlist[0] = tmp;
1544f5b1c8a1SJohn Marino 		else
1545f5b1c8a1SJohn Marino 			err(1, NULL);
1546f5b1c8a1SJohn Marino 	}
1547f5b1c8a1SJohn Marino }
1548f5b1c8a1SJohn Marino 
1549f5b1c8a1SJohn Marino /*
1550f5b1c8a1SJohn Marino  * udptest()
1551f5b1c8a1SJohn Marino  * Do a few writes to see if the UDP port is there.
1552f5b1c8a1SJohn Marino  * Fails once PF state table is full.
1553f5b1c8a1SJohn Marino  */
1554f5b1c8a1SJohn Marino int
udptest(int s)1555f5b1c8a1SJohn Marino udptest(int s)
1556f5b1c8a1SJohn Marino {
1557f5b1c8a1SJohn Marino 	int i, ret;
1558f5b1c8a1SJohn Marino 
1559f5b1c8a1SJohn Marino 	for (i = 0; i <= 3; i++) {
1560f5b1c8a1SJohn Marino 		if (write(s, "X", 1) == 1)
1561f5b1c8a1SJohn Marino 			ret = 1;
1562f5b1c8a1SJohn Marino 		else
1563f5b1c8a1SJohn Marino 			ret = -1;
1564f5b1c8a1SJohn Marino 	}
156572c33676SMaxim Ag 	return ret;
1566f5b1c8a1SJohn Marino }
1567f5b1c8a1SJohn Marino 
1568f5b1c8a1SJohn Marino void
set_common_sockopts(int s,int af)1569f5b1c8a1SJohn Marino set_common_sockopts(int s, int af)
1570f5b1c8a1SJohn Marino {
1571f5b1c8a1SJohn Marino 	int x = 1;
1572f5b1c8a1SJohn Marino 
1573f5b1c8a1SJohn Marino #ifdef TCP_MD5SIG
1574f5b1c8a1SJohn Marino 	if (Sflag) {
1575f5b1c8a1SJohn Marino 		if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG,
1576f5b1c8a1SJohn Marino 		    &x, sizeof(x)) == -1)
1577f5b1c8a1SJohn Marino 			err(1, NULL);
1578f5b1c8a1SJohn Marino 	}
1579f5b1c8a1SJohn Marino #endif
1580f5b1c8a1SJohn Marino 	if (Dflag) {
1581f5b1c8a1SJohn Marino 		if (setsockopt(s, SOL_SOCKET, SO_DEBUG,
1582f5b1c8a1SJohn Marino 		    &x, sizeof(x)) == -1)
1583f5b1c8a1SJohn Marino 			err(1, NULL);
1584f5b1c8a1SJohn Marino 	}
1585f5b1c8a1SJohn Marino 	if (Tflag != -1) {
1586f5b1c8a1SJohn Marino 		if (af == AF_INET && setsockopt(s, IPPROTO_IP,
1587f5b1c8a1SJohn Marino 		    IP_TOS, &Tflag, sizeof(Tflag)) == -1)
1588f5b1c8a1SJohn Marino 			err(1, "set IP ToS");
1589f5b1c8a1SJohn Marino 
159072c33676SMaxim Ag #ifdef IPV6_TCLASS
1591f5b1c8a1SJohn Marino 		else if (af == AF_INET6 && setsockopt(s, IPPROTO_IPV6,
1592f5b1c8a1SJohn Marino 		    IPV6_TCLASS, &Tflag, sizeof(Tflag)) == -1)
1593f5b1c8a1SJohn Marino 			err(1, "set IPv6 traffic class");
159472c33676SMaxim Ag #else
159572c33676SMaxim Ag 		else if (af == AF_INET6) {
159672c33676SMaxim Ag 			errno = ENOPROTOOPT;
159772c33676SMaxim Ag 			err(1, "set IPv6 traffic class not supported");
159872c33676SMaxim Ag 		}
159972c33676SMaxim Ag #endif
1600f5b1c8a1SJohn Marino 	}
1601f5b1c8a1SJohn Marino 	if (Iflag) {
1602f5b1c8a1SJohn Marino 		if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
1603f5b1c8a1SJohn Marino 		    &Iflag, sizeof(Iflag)) == -1)
1604f5b1c8a1SJohn Marino 			err(1, "set TCP receive buffer size");
1605f5b1c8a1SJohn Marino 	}
1606f5b1c8a1SJohn Marino 	if (Oflag) {
1607f5b1c8a1SJohn Marino 		if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
1608f5b1c8a1SJohn Marino 		    &Oflag, sizeof(Oflag)) == -1)
1609f5b1c8a1SJohn Marino 			err(1, "set TCP send buffer size");
1610f5b1c8a1SJohn Marino 	}
1611f5b1c8a1SJohn Marino 
1612f5b1c8a1SJohn Marino 	if (ttl != -1) {
1613f5b1c8a1SJohn Marino 		if (af == AF_INET && setsockopt(s, IPPROTO_IP,
1614f5b1c8a1SJohn Marino 		    IP_TTL, &ttl, sizeof(ttl)))
1615f5b1c8a1SJohn Marino 			err(1, "set IP TTL");
1616f5b1c8a1SJohn Marino 
1617f5b1c8a1SJohn Marino 		else if (af == AF_INET6 && setsockopt(s, IPPROTO_IPV6,
1618f5b1c8a1SJohn Marino 		    IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)))
1619f5b1c8a1SJohn Marino 			err(1, "set IPv6 unicast hops");
1620f5b1c8a1SJohn Marino 	}
1621f5b1c8a1SJohn Marino 
1622f5b1c8a1SJohn Marino 	if (minttl != -1) {
1623f5b1c8a1SJohn Marino #ifdef IP_MINTTL
1624f5b1c8a1SJohn Marino 		if (af == AF_INET && setsockopt(s, IPPROTO_IP,
1625f5b1c8a1SJohn Marino 		    IP_MINTTL, &minttl, sizeof(minttl)))
1626f5b1c8a1SJohn Marino 			err(1, "set IP min TTL");
1627f5b1c8a1SJohn Marino #endif
1628f5b1c8a1SJohn Marino 
1629f5b1c8a1SJohn Marino #ifdef IPV6_MINHOPCOUNT
1630f5b1c8a1SJohn Marino 		if (af == AF_INET6 && setsockopt(s, IPPROTO_IPV6,
1631f5b1c8a1SJohn Marino 		    IPV6_MINHOPCOUNT, &minttl, sizeof(minttl)))
1632f5b1c8a1SJohn Marino 			err(1, "set IPv6 min hop count");
1633f5b1c8a1SJohn Marino #endif
1634f5b1c8a1SJohn Marino 	}
1635f5b1c8a1SJohn Marino }
1636f5b1c8a1SJohn Marino 
1637f5b1c8a1SJohn Marino int
process_tos_opt(char * s,int * val)163872c33676SMaxim Ag process_tos_opt(char *s, int *val)
1639f5b1c8a1SJohn Marino {
1640f5b1c8a1SJohn Marino 	/* DiffServ Codepoints and other TOS mappings */
1641f5b1c8a1SJohn Marino 	const struct toskeywords {
1642f5b1c8a1SJohn Marino 		const char	*keyword;
1643f5b1c8a1SJohn Marino 		int		 val;
1644f5b1c8a1SJohn Marino 	} *t, toskeywords[] = {
1645f5b1c8a1SJohn Marino 		{ "af11",		IPTOS_DSCP_AF11 },
1646f5b1c8a1SJohn Marino 		{ "af12",		IPTOS_DSCP_AF12 },
1647f5b1c8a1SJohn Marino 		{ "af13",		IPTOS_DSCP_AF13 },
1648f5b1c8a1SJohn Marino 		{ "af21",		IPTOS_DSCP_AF21 },
1649f5b1c8a1SJohn Marino 		{ "af22",		IPTOS_DSCP_AF22 },
1650f5b1c8a1SJohn Marino 		{ "af23",		IPTOS_DSCP_AF23 },
1651f5b1c8a1SJohn Marino 		{ "af31",		IPTOS_DSCP_AF31 },
1652f5b1c8a1SJohn Marino 		{ "af32",		IPTOS_DSCP_AF32 },
1653f5b1c8a1SJohn Marino 		{ "af33",		IPTOS_DSCP_AF33 },
1654f5b1c8a1SJohn Marino 		{ "af41",		IPTOS_DSCP_AF41 },
1655f5b1c8a1SJohn Marino 		{ "af42",		IPTOS_DSCP_AF42 },
1656f5b1c8a1SJohn Marino 		{ "af43",		IPTOS_DSCP_AF43 },
1657f5b1c8a1SJohn Marino 		{ "critical",		IPTOS_PREC_CRITIC_ECP },
1658f5b1c8a1SJohn Marino 		{ "cs0",		IPTOS_DSCP_CS0 },
1659f5b1c8a1SJohn Marino 		{ "cs1",		IPTOS_DSCP_CS1 },
1660f5b1c8a1SJohn Marino 		{ "cs2",		IPTOS_DSCP_CS2 },
1661f5b1c8a1SJohn Marino 		{ "cs3",		IPTOS_DSCP_CS3 },
1662f5b1c8a1SJohn Marino 		{ "cs4",		IPTOS_DSCP_CS4 },
1663f5b1c8a1SJohn Marino 		{ "cs5",		IPTOS_DSCP_CS5 },
1664f5b1c8a1SJohn Marino 		{ "cs6",		IPTOS_DSCP_CS6 },
1665f5b1c8a1SJohn Marino 		{ "cs7",		IPTOS_DSCP_CS7 },
1666f5b1c8a1SJohn Marino 		{ "ef",			IPTOS_DSCP_EF },
1667f5b1c8a1SJohn Marino 		{ "inetcontrol",	IPTOS_PREC_INTERNETCONTROL },
1668f5b1c8a1SJohn Marino 		{ "lowdelay",		IPTOS_LOWDELAY },
1669f5b1c8a1SJohn Marino 		{ "netcontrol",		IPTOS_PREC_NETCONTROL },
1670f5b1c8a1SJohn Marino 		{ "reliability",	IPTOS_RELIABILITY },
1671f5b1c8a1SJohn Marino 		{ "throughput",		IPTOS_THROUGHPUT },
1672f5b1c8a1SJohn Marino 		{ NULL,			-1 },
1673f5b1c8a1SJohn Marino 	};
1674f5b1c8a1SJohn Marino 
1675f5b1c8a1SJohn Marino 	for (t = toskeywords; t->keyword != NULL; t++) {
1676f5b1c8a1SJohn Marino 		if (strcmp(s, t->keyword) == 0) {
1677f5b1c8a1SJohn Marino 			*val = t->val;
167872c33676SMaxim Ag 			return 1;
1679f5b1c8a1SJohn Marino 		}
1680f5b1c8a1SJohn Marino 	}
1681f5b1c8a1SJohn Marino 
168272c33676SMaxim Ag 	return 0;
1683f5b1c8a1SJohn Marino }
1684f5b1c8a1SJohn Marino 
1685f5b1c8a1SJohn Marino int
process_tls_opt(char * s,int * flags)168672c33676SMaxim Ag process_tls_opt(char *s, int *flags)
1687f5b1c8a1SJohn Marino {
168872c33676SMaxim Ag 	size_t len;
168972c33676SMaxim Ag 	char *v;
169072c33676SMaxim Ag 
1691f5b1c8a1SJohn Marino 	const struct tlskeywords {
1692f5b1c8a1SJohn Marino 		const char	*keyword;
169372c33676SMaxim Ag 		int		 flag;
169472c33676SMaxim Ag 		char		**value;
1695f5b1c8a1SJohn Marino 	} *t, tlskeywords[] = {
169672c33676SMaxim Ag 		{ "ciphers",		-1,			&tls_ciphers },
169772c33676SMaxim Ag 		{ "clientcert",		TLS_CCERT,		NULL },
169872c33676SMaxim Ag 		{ "muststaple",		TLS_MUSTSTAPLE,		NULL },
169972c33676SMaxim Ag 		{ "noverify",		TLS_NOVERIFY,		NULL },
170072c33676SMaxim Ag 		{ "noname",		TLS_NONAME,		NULL },
170172c33676SMaxim Ag 		{ "protocols",		-1,			&tls_protocols },
170272c33676SMaxim Ag 		{ NULL,			-1,			NULL },
1703f5b1c8a1SJohn Marino 	};
1704f5b1c8a1SJohn Marino 
170572c33676SMaxim Ag 	len = strlen(s);
170672c33676SMaxim Ag 	if ((v = strchr(s, '=')) != NULL) {
170772c33676SMaxim Ag 		len = v - s;
170872c33676SMaxim Ag 		v++;
170972c33676SMaxim Ag 	}
171072c33676SMaxim Ag 
1711f5b1c8a1SJohn Marino 	for (t = tlskeywords; t->keyword != NULL; t++) {
171272c33676SMaxim Ag 		if (strlen(t->keyword) == len &&
171372c33676SMaxim Ag 		    strncmp(s, t->keyword, len) == 0) {
171472c33676SMaxim Ag 			if (t->value != NULL) {
171572c33676SMaxim Ag 				if (v == NULL)
171672c33676SMaxim Ag 					errx(1, "invalid tls value `%s'", s);
171772c33676SMaxim Ag 				*t->value = v;
171872c33676SMaxim Ag 			} else {
171972c33676SMaxim Ag 				*flags |= t->flag;
172072c33676SMaxim Ag 			}
172172c33676SMaxim Ag 			return 1;
1722f5b1c8a1SJohn Marino 		}
1723f5b1c8a1SJohn Marino 	}
172472c33676SMaxim Ag 	return 0;
1725f5b1c8a1SJohn Marino }
1726f5b1c8a1SJohn Marino 
1727f5b1c8a1SJohn Marino void
save_peer_cert(struct tls * tls_ctx,FILE * fp)172872c33676SMaxim Ag save_peer_cert(struct tls *tls_ctx, FILE *fp)
172972c33676SMaxim Ag {
173072c33676SMaxim Ag 	const char *pem;
173172c33676SMaxim Ag 	size_t plen;
173272c33676SMaxim Ag 
173372c33676SMaxim Ag 	if ((pem = tls_peer_cert_chain_pem(tls_ctx, &plen)) == NULL)
173472c33676SMaxim Ag 		errx(1, "Can't get peer certificate");
173572c33676SMaxim Ag 	if (fprintf(fp, "%.*s", (int)plen, pem) < 0)
173672c33676SMaxim Ag 		err(1, "unable to save peer cert");
173772c33676SMaxim Ag 	if (fflush(fp) != 0)
173872c33676SMaxim Ag 		err(1, "unable to flush peer cert");
173972c33676SMaxim Ag }
174072c33676SMaxim Ag 
174172c33676SMaxim Ag void
report_tls(struct tls * tls_ctx,char * host)174272c33676SMaxim Ag report_tls(struct tls *tls_ctx, char *host)
1743f5b1c8a1SJohn Marino {
1744f5b1c8a1SJohn Marino 	time_t t;
174572c33676SMaxim Ag 	const char *ocsp_url;
174672c33676SMaxim Ag 
1747f5b1c8a1SJohn Marino 	fprintf(stderr, "TLS handshake negotiated %s/%s with host %s\n",
1748f5b1c8a1SJohn Marino 	    tls_conn_version(tls_ctx), tls_conn_cipher(tls_ctx), host);
1749f5b1c8a1SJohn Marino 	fprintf(stderr, "Peer name: %s\n",
1750f5b1c8a1SJohn Marino 	    tls_expectname ? tls_expectname : host);
1751f5b1c8a1SJohn Marino 	if (tls_peer_cert_subject(tls_ctx))
1752f5b1c8a1SJohn Marino 		fprintf(stderr, "Subject: %s\n",
1753f5b1c8a1SJohn Marino 		    tls_peer_cert_subject(tls_ctx));
1754f5b1c8a1SJohn Marino 	if (tls_peer_cert_issuer(tls_ctx))
1755f5b1c8a1SJohn Marino 		fprintf(stderr, "Issuer: %s\n",
1756f5b1c8a1SJohn Marino 		    tls_peer_cert_issuer(tls_ctx));
1757f5b1c8a1SJohn Marino 	if ((t = tls_peer_cert_notbefore(tls_ctx)) != -1)
1758f5b1c8a1SJohn Marino 		fprintf(stderr, "Valid From: %s", ctime(&t));
1759f5b1c8a1SJohn Marino 	if ((t = tls_peer_cert_notafter(tls_ctx)) != -1)
1760f5b1c8a1SJohn Marino 		fprintf(stderr, "Valid Until: %s", ctime(&t));
1761f5b1c8a1SJohn Marino 	if (tls_peer_cert_hash(tls_ctx))
1762f5b1c8a1SJohn Marino 		fprintf(stderr, "Cert Hash: %s\n",
1763f5b1c8a1SJohn Marino 		    tls_peer_cert_hash(tls_ctx));
176472c33676SMaxim Ag 	ocsp_url = tls_peer_ocsp_url(tls_ctx);
176572c33676SMaxim Ag 	if (ocsp_url != NULL)
176672c33676SMaxim Ag 		fprintf(stderr, "OCSP URL: %s\n", ocsp_url);
176772c33676SMaxim Ag 	switch (tls_peer_ocsp_response_status(tls_ctx)) {
176872c33676SMaxim Ag 	case TLS_OCSP_RESPONSE_SUCCESSFUL:
176972c33676SMaxim Ag 		fprintf(stderr, "OCSP Stapling: %s\n",
177072c33676SMaxim Ag 		    tls_peer_ocsp_result(tls_ctx) == NULL ? "" :
177172c33676SMaxim Ag 		    tls_peer_ocsp_result(tls_ctx));
177272c33676SMaxim Ag 		fprintf(stderr,
177372c33676SMaxim Ag 		    "  response_status=%d cert_status=%d crl_reason=%d\n",
177472c33676SMaxim Ag 		    tls_peer_ocsp_response_status(tls_ctx),
177572c33676SMaxim Ag 		    tls_peer_ocsp_cert_status(tls_ctx),
177672c33676SMaxim Ag 		    tls_peer_ocsp_crl_reason(tls_ctx));
177772c33676SMaxim Ag 		t = tls_peer_ocsp_this_update(tls_ctx);
177872c33676SMaxim Ag 		fprintf(stderr, "  this update: %s",
177972c33676SMaxim Ag 		    t != -1 ? ctime(&t) : "\n");
178072c33676SMaxim Ag 		t = tls_peer_ocsp_next_update(tls_ctx);
178172c33676SMaxim Ag 		fprintf(stderr, "  next update: %s",
178272c33676SMaxim Ag 		    t != -1 ? ctime(&t) : "\n");
178372c33676SMaxim Ag 		t = tls_peer_ocsp_revocation_time(tls_ctx);
178472c33676SMaxim Ag 		fprintf(stderr, "  revocation: %s",
178572c33676SMaxim Ag 		    t != -1 ? ctime(&t) : "\n");
178672c33676SMaxim Ag 		break;
178772c33676SMaxim Ag 	case -1:
178872c33676SMaxim Ag 		break;
178972c33676SMaxim Ag 	default:
1790*de0e0e4dSAntonio Huete Jimenez 		fprintf(stderr,
1791*de0e0e4dSAntonio Huete Jimenez 		    "OCSP Stapling:  failure - response_status %d (%s)\n",
179272c33676SMaxim Ag 		    tls_peer_ocsp_response_status(tls_ctx),
179372c33676SMaxim Ag 		    tls_peer_ocsp_result(tls_ctx) == NULL ? "" :
179472c33676SMaxim Ag 		    tls_peer_ocsp_result(tls_ctx));
179572c33676SMaxim Ag 		break;
179672c33676SMaxim Ag 	}
1797f5b1c8a1SJohn Marino }
1798f5b1c8a1SJohn Marino 
1799f5b1c8a1SJohn Marino void
report_sock(const char * msg,const struct sockaddr * sa,socklen_t salen,char * path)180072c33676SMaxim Ag report_sock(const char *msg, const struct sockaddr *sa, socklen_t salen,
180172c33676SMaxim Ag     char *path)
1802f5b1c8a1SJohn Marino {
180372c33676SMaxim Ag 	char host[NI_MAXHOST], port[NI_MAXSERV];
1804f5b1c8a1SJohn Marino 	int herr;
1805f5b1c8a1SJohn Marino 	int flags = NI_NUMERICSERV;
1806f5b1c8a1SJohn Marino 
1807f5b1c8a1SJohn Marino 	if (path != NULL) {
180872c33676SMaxim Ag 		fprintf(stderr, "%s on %s\n", msg, path);
1809f5b1c8a1SJohn Marino 		return;
1810f5b1c8a1SJohn Marino 	}
1811f5b1c8a1SJohn Marino 
1812f5b1c8a1SJohn Marino 	if (nflag)
1813f5b1c8a1SJohn Marino 		flags |= NI_NUMERICHOST;
1814f5b1c8a1SJohn Marino 
1815cca6fc52SDaniel Fojt 	herr = getnameinfo(sa, salen, host, sizeof(host), port, sizeof(port),
1816cca6fc52SDaniel Fojt 	    flags);
1817cca6fc52SDaniel Fojt 	switch (herr) {
1818cca6fc52SDaniel Fojt 	case 0:
1819cca6fc52SDaniel Fojt 		break;
1820cca6fc52SDaniel Fojt 	case EAI_SYSTEM:
1821f5b1c8a1SJohn Marino 		err(1, "getnameinfo");
1822cca6fc52SDaniel Fojt 	default:
1823f5b1c8a1SJohn Marino 		errx(1, "getnameinfo: %s", gai_strerror(herr));
1824f5b1c8a1SJohn Marino 	}
1825f5b1c8a1SJohn Marino 
182672c33676SMaxim Ag 	fprintf(stderr, "%s on %s %s\n", msg, host, port);
1827f5b1c8a1SJohn Marino }
1828f5b1c8a1SJohn Marino 
1829f5b1c8a1SJohn Marino void
help(void)1830f5b1c8a1SJohn Marino help(void)
1831f5b1c8a1SJohn Marino {
1832f5b1c8a1SJohn Marino 	usage(0);
1833f5b1c8a1SJohn Marino 	fprintf(stderr, "\tCommand Summary:\n\
1834f5b1c8a1SJohn Marino 	\t-4		Use IPv4\n\
1835f5b1c8a1SJohn Marino 	\t-6		Use IPv6\n\
1836f5b1c8a1SJohn Marino 	\t-C certfile	Public key file\n\
1837f5b1c8a1SJohn Marino 	\t-c		Use TLS\n\
1838f5b1c8a1SJohn Marino 	\t-D		Enable the debug socket option\n\
1839f5b1c8a1SJohn Marino 	\t-d		Detach from stdin\n\
1840f5b1c8a1SJohn Marino 	\t-e name\t	Required name in peer certificate\n\
1841f5b1c8a1SJohn Marino 	\t-F		Pass socket fd\n\
1842f5b1c8a1SJohn Marino 	\t-H hash\t	Hash string of peer certificate\n\
1843f5b1c8a1SJohn Marino 	\t-h		This help text\n\
1844f5b1c8a1SJohn Marino 	\t-I length	TCP receive buffer length\n\
1845f5b1c8a1SJohn Marino 	\t-i interval	Delay interval for lines sent, ports scanned\n\
1846f5b1c8a1SJohn Marino 	\t-K keyfile	Private key file\n\
1847f5b1c8a1SJohn Marino 	\t-k		Keep inbound sockets open for multiple connects\n\
1848f5b1c8a1SJohn Marino 	\t-l		Listen mode, for inbound connects\n\
1849f5b1c8a1SJohn Marino 	\t-M ttl		Outgoing TTL / Hop Limit\n\
1850f5b1c8a1SJohn Marino 	\t-m minttl	Minimum incoming TTL / Hop Limit\n\
1851f5b1c8a1SJohn Marino 	\t-N		Shutdown the network socket after EOF on stdin\n\
1852f5b1c8a1SJohn Marino 	\t-n		Suppress name/port resolutions\n\
1853f5b1c8a1SJohn Marino 	\t-O length	TCP send buffer length\n\
185472c33676SMaxim Ag 	\t-o staplefile	Staple file\n\
1855f5b1c8a1SJohn Marino 	\t-P proxyuser\tUsername for proxy authentication\n\
1856f5b1c8a1SJohn Marino 	\t-p port\t	Specify local port for remote connects\n\
1857f5b1c8a1SJohn Marino 	\t-R CAfile	CA bundle\n\
1858f5b1c8a1SJohn Marino 	\t-r		Randomize remote ports\n"
1859f5b1c8a1SJohn Marino #ifdef TCP_MD5SIG
1860cca6fc52SDaniel Fojt 	"\t-S		Enable the TCP MD5 signature option\n"
1861f5b1c8a1SJohn Marino #endif
1862cca6fc52SDaniel Fojt 	"\t-s sourceaddr	Local source address\n\
1863f5b1c8a1SJohn Marino 	\t-T keyword	TOS value or TLS options\n\
1864f5b1c8a1SJohn Marino 	\t-t		Answer TELNET negotiation\n\
1865f5b1c8a1SJohn Marino 	\t-U		Use UNIX domain socket\n\
1866f5b1c8a1SJohn Marino 	\t-u		UDP mode\n"
1867f5b1c8a1SJohn Marino #ifdef SO_RTABLE
1868cca6fc52SDaniel Fojt 	"\t-V rtable	Specify alternate routing table\n"
1869f5b1c8a1SJohn Marino #endif
1870cca6fc52SDaniel Fojt 	"\t-v		Verbose\n\
187172c33676SMaxim Ag 	\t-W recvlimit	Terminate after receiving a number of packets\n\
1872f5b1c8a1SJohn Marino 	\t-w timeout	Timeout for connects and final net reads\n\
1873f5b1c8a1SJohn Marino 	\t-X proto	Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\
1874f5b1c8a1SJohn Marino 	\t-x addr[:port]\tSpecify proxy address and port\n\
187572c33676SMaxim Ag 	\t-Z		Peer certificate file\n\
1876f5b1c8a1SJohn Marino 	\t-z		Zero-I/O mode [used for scanning]\n\
1877f5b1c8a1SJohn Marino 	Port numbers can be individual or ranges: lo-hi [inclusive]\n");
1878f5b1c8a1SJohn Marino 	exit(1);
1879f5b1c8a1SJohn Marino }
1880f5b1c8a1SJohn Marino 
1881f5b1c8a1SJohn Marino void
usage(int ret)1882f5b1c8a1SJohn Marino usage(int ret)
1883f5b1c8a1SJohn Marino {
1884f5b1c8a1SJohn Marino 	fprintf(stderr,
1885f5b1c8a1SJohn Marino 	    "usage: nc [-46cDdFhklNnrStUuvz] [-C certfile] [-e name] "
1886f5b1c8a1SJohn Marino 	    "[-H hash] [-I length]\n"
1887f5b1c8a1SJohn Marino 	    "\t  [-i interval] [-K keyfile] [-M ttl] [-m minttl] [-O length]\n"
188872c33676SMaxim Ag 	    "\t  [-o staplefile] [-P proxy_username] [-p source_port] "
188972c33676SMaxim Ag 	    "[-R CAfile]\n"
1890cca6fc52SDaniel Fojt 	    "\t  [-s sourceaddr] [-T keyword] [-V rtable] [-W recvlimit] "
189172c33676SMaxim Ag 	    "[-w timeout]\n"
189272c33676SMaxim Ag 	    "\t  [-X proxy_protocol] [-x proxy_address[:port]] "
189372c33676SMaxim Ag 	    "[-Z peercertfile]\n"
189472c33676SMaxim Ag 	    "\t  [destination] [port]\n");
1895f5b1c8a1SJohn Marino 	if (ret)
1896f5b1c8a1SJohn Marino 		exit(1);
1897f5b1c8a1SJohn Marino }
1898