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