svn commit: r298554 - vendor/netcat/dist

Xin LI delphij at FreeBSD.org
Sun Apr 24 22:12:48 UTC 2016


Author: delphij
Date: Sun Apr 24 22:12:47 2016
New Revision: 298554
URL: https://svnweb.freebsd.org/changeset/base/298554

Log:
  Vendor import nc(1) from OPENBSD_5_9.

Modified:
  vendor/netcat/dist/Makefile
  vendor/netcat/dist/nc.1
  vendor/netcat/dist/netcat.c
  vendor/netcat/dist/socks.c

Modified: vendor/netcat/dist/Makefile
==============================================================================
--- vendor/netcat/dist/Makefile	Sun Apr 24 21:35:01 2016	(r298553)
+++ vendor/netcat/dist/Makefile	Sun Apr 24 22:12:47 2016	(r298554)
@@ -1,6 +1,8 @@
-#	$OpenBSD: Makefile,v 1.6 2001/09/02 18:45:41 jakob Exp $
+#	$OpenBSD: Makefile,v 1.7 2015/09/11 21:07:01 beck Exp $
 
 PROG=	nc
 SRCS=	netcat.c atomicio.c socks.c
+LDADD+= -ltls -lssl -lcrypto
+DPADD+=  ${LIBTLS} ${LIBSSL} ${LIBCRYPTO}
 
 .include <bsd.prog.mk>

Modified: vendor/netcat/dist/nc.1
==============================================================================
--- vendor/netcat/dist/nc.1	Sun Apr 24 21:35:01 2016	(r298553)
+++ vendor/netcat/dist/nc.1	Sun Apr 24 22:12:47 2016	(r298554)
@@ -1,4 +1,4 @@
-.\"     $OpenBSD: nc.1,v 1.68 2015/03/26 10:35:04 tobias Exp $
+.\"     $OpenBSD: nc.1,v 1.71 2015/09/25 14:56:33 schwarze Exp $
 .\"
 .\" Copyright (c) 1996 David Sacerdote
 .\" All rights reserved.
@@ -25,7 +25,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: February 26 2014 $
+.Dd $Mdocdate: September 12 2015 $
 .Dt NC 1
 .Os
 .Sh NAME
@@ -33,25 +33,25 @@
 .Nd arbitrary TCP and UDP connections and listens
 .Sh SYNOPSIS
 .Nm nc
-.Bk -words
-.Op Fl 46DdFhklNnrStUuvz
+.Op Fl 46cDdFhklNnrStUuvz
+.Op Fl C Ar certfile
+.Op Fl e Ar name
+.Op Fl H Ar hash
 .Op Fl I Ar length
 .Op Fl i Ar interval
+.Op Fl K Ar keyfile
 .Op Fl O Ar length
 .Op Fl P Ar proxy_username
 .Op Fl p Ar source_port
+.Op Fl R Ar CAfile
 .Op Fl s Ar source
-.Op Fl T Ar toskeyword
+.Op Fl T Ar keyword
 .Op Fl V Ar rtable
 .Op Fl w Ar timeout
 .Op Fl X Ar proxy_protocol
-.Oo Xo
-.Fl x Ar proxy_address Ns Oo : Ns
-.Ar port Oc
-.Xc Oc
+.Op Fl x Ar proxy_address Ns Op : Ns Ar port
 .Op Ar destination
 .Op Ar port
-.Ek
 .Sh DESCRIPTION
 The
 .Nm
@@ -98,10 +98,20 @@ to use IPv4 addresses only.
 Forces
 .Nm
 to use IPv6 addresses only.
+.It Fl C Ar certfile
+Specifies the filename from which the public key part of the TLS
+certificate is loaded, in PEM format.
+May only be used with TLS.
+.It Fl c
+If using a TCP socket to connect or listen, use TLS.
+Illegal if not using TCP sockets.
 .It Fl D
 Enable debugging on the socket.
 .It Fl d
 Do not attempt to read from stdin.
+.It Fl e Ar name
+Specify the name that must be present in the peer certificate when using TLS.
+Illegal if not using TLS.
 .It Fl F
 Pass the first connected socket using
 .Xr sendmsg 2
@@ -117,6 +127,11 @@ using the
 .Xr ssh_config 5
 .Cm ProxyUseFdpass
 option).
+.It Fl H Ar hash
+Specifies the required hash string of the peer certificate when using TLS.
+The string format required is that used by
+.Xr tls_peer_cert_hash 3 .
+Illegal if not using TLS, and may not be used with -T noverify.
 .It Fl h
 Prints out
 .Nm
@@ -126,6 +141,10 @@ Specifies the size of the TCP receive bu
 .It Fl i Ar interval
 Specifies a delay time interval between lines of text sent and received.
 Also causes a delay time between connections to multiple ports.
+.It Fl K Ar keyfile
+Specifies the filename from which the private key
+is loaded in PEM format.
+May only be used with TLS.
 .It Fl k
 Forces
 .Nm
@@ -172,6 +191,12 @@ should use, subject to privilege restric
 It is an error to use this option in conjunction with the
 .Fl l
 option.
+.It Fl R Ar CAfile
+Specifies the filename from which the root CA bundle for certificate
+verification is loaded, in PEM format.
+Illegal if not using TLS.
+The default is
+.Pa /etc/ssl/cert.pem .
 .It Fl r
 Specifies that source and/or destination ports should be chosen randomly
 instead of sequentially within a range or in the order that the system
@@ -187,9 +212,23 @@ to create and use so that datagrams can 
 It is an error to use this option in conjunction with the
 .Fl l
 option.
-.It Fl T Ar toskeyword
-Change IPv4 TOS value.
-.Ar toskeyword
+.It Fl T Ar keyword
+Change IPv4 TOS value or TLS options.
+For TLS options
+.Ar keyword
+may be one of
+.Ar tlslegacy ,
+which allows legacy TLS protocols;
+.Ar noverify ,
+which disables certificate verification;
+.Ar noname ,
+which disables certificate name checking; or
+.Ar clientcert ,
+which requires a client certificate on incoming connections.
+It is illegal to specify TLS options if not using TLS.
+.Pp
+For IPv4 TOS value
+.Ar keyword
 may be one of
 .Ar critical ,
 .Ar inetcontrol ,
@@ -258,10 +297,7 @@ and
 .Dq connect
 (HTTPS proxy).
 If the protocol is not specified, SOCKS version 5 is used.
-.It Xo
-.Fl x Ar proxy_address Ns Oo : Ns
-.Ar port Oc
-.Xc
+.It Fl x Ar proxy_address Ns Op : Ns Ar port
 Requests that
 .Nm
 should connect to
@@ -429,6 +465,11 @@ the source port, with a timeout of 5 sec
 .Pp
 .Dl $ nc -p 31337 -w 5 host.example.com 42
 .Pp
+Open a TCP connection to port 443 of www.google.ca, and negotiate TLS.
+Check for a different name in the certificate for validation.
+.Pp
+.Dl $  nc -v -c -e adsf.au.doubleclick.net www.google.ca 443
+.Pp
 Open a UDP connection to port 53 of host.example.com:
 .Pp
 .Dl $ nc -u host.example.com 53

Modified: vendor/netcat/dist/netcat.c
==============================================================================
--- vendor/netcat/dist/netcat.c	Sun Apr 24 21:35:01 2016	(r298553)
+++ vendor/netcat/dist/netcat.c	Sun Apr 24 22:12:47 2016	(r298554)
@@ -1,6 +1,7 @@
-/* $OpenBSD: netcat.c,v 1.130 2015/07/26 19:12:28 chl Exp $ */
+/* $OpenBSD: netcat.c,v 1.150 2016/01/04 02:18:31 bcook Exp $ */
 /*
  * Copyright (c) 2001 Eric Jackson <ericj at monkey.org>
+ * Copyright (c) 2015 Bob Beck.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,7 +34,6 @@
 
 #include <sys/types.h>
 #include <sys/socket.h>
-#include <sys/time.h>
 #include <sys/uio.h>
 #include <sys/un.h>
 
@@ -44,7 +44,6 @@
 
 #include <err.h>
 #include <errno.h>
-#include <fcntl.h>
 #include <limits.h>
 #include <netdb.h>
 #include <poll.h>
@@ -53,16 +52,12 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 #include <unistd.h>
+#include <tls.h>
 #include "atomicio.h"
 
-#ifndef SUN_LEN
-#define SUN_LEN(su) \
-	(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
-#endif
-
 #define PORT_MAX	65535
-#define PORT_MAX_LEN	6
 #define UNIX_DG_TMP_SOCKET_SIZE	19
 
 #define POLL_STDIN 0
@@ -70,6 +65,12 @@
 #define POLL_NETIN 2
 #define POLL_STDOUT 3
 #define BUFSIZE 16384
+#define DEFAULT_CA_FILE "/etc/ssl/cert.pem"
+
+#define TLS_LEGACY	(1 << 1)
+#define TLS_NOVERIFY	(1 << 2)
+#define TLS_NONAME	(1 << 3)
+#define TLS_CCERT	(1 << 4)
 
 /* Command Line Options */
 int	dflag;					/* detached, no stdin */
@@ -95,6 +96,21 @@ int	Sflag;					/* TCP MD5 signature opti
 int	Tflag = -1;				/* IP Type of Service */
 int	rtableid = -1;
 
+int	usetls;					/* use TLS */
+char    *Cflag;					/* Public cert file */
+char    *Kflag;					/* Private key file */
+char    *Rflag = DEFAULT_CA_FILE;		/* Root CA file */
+int	tls_cachanged;				/* Using non-default CA file */
+int     TLSopt;					/* TLS options */
+char	*tls_expectname;			/* required name in peer cert */
+char	*tls_expecthash;			/* required hash of peer cert */
+uint8_t *cacert;
+size_t  cacertlen;
+uint8_t *privkey;
+size_t  privkeylen;
+uint8_t *pubcert;
+size_t  pubcertlen;
+
 int timeout = -1;
 int family = AF_UNSPEC;
 char *portlist[PORT_MAX+1];
@@ -104,22 +120,26 @@ void	atelnet(int, unsigned char *, unsig
 void	build_ports(char *);
 void	help(void);
 int	local_listen(char *, char *, struct addrinfo);
-void	readwrite(int);
+void	readwrite(int, struct tls *);
 void	fdpass(int nfd) __attribute__((noreturn));
 int	remote_connect(const char *, const char *, struct addrinfo);
 int	timeout_connect(int, const struct sockaddr *, socklen_t);
 int	socks_connect(const char *, const char *, struct addrinfo,
 	    const char *, const char *, struct addrinfo, int, const char *);
 int	udptest(int);
-int	unix_bind(char *);
+int	unix_bind(char *, int);
 int	unix_connect(char *);
 int	unix_listen(char *);
 void	set_common_sockopts(int, int);
 int	map_tos(char *, int *);
+int	map_tls(char *, int *);
 void	report_connect(const struct sockaddr *, socklen_t);
+void	report_tls(struct tls *tls_ctx, char * host, char *tls_expectname);
 void	usage(int);
-ssize_t drainbuf(int, unsigned char *, size_t *);
-ssize_t fillbuf(int, unsigned char *, size_t *);
+ssize_t drainbuf(int, unsigned char *, size_t *, struct tls *);
+ssize_t fillbuf(int, unsigned char *, size_t *, struct tls *);
+void	tls_setup_client(struct tls *, int, char *);
+struct tls *tls_setup_server(struct tls *, int, char *);
 
 int
 main(int argc, char *argv[])
@@ -134,6 +154,8 @@ main(int argc, char *argv[])
 	const char *errstr, *proxyhost = "", *proxyport = NULL;
 	struct addrinfo proxyhints;
 	char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE];
+	struct tls_config *tls_cfg = NULL;
+	struct tls *tls_ctx = NULL;
 
 	ret = 1;
 	s = 0;
@@ -145,7 +167,7 @@ main(int argc, char *argv[])
 	signal(SIGPIPE, SIG_IGN);
 
 	while ((ch = getopt(argc, argv,
-	    "46DdFhI:i:klNnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) {
+	    "46C:cDde:FH:hI:i:K:klNnO:P:p:R:rSs:T:tUuV:vw:X:x:z")) != -1) {
 		switch (ch) {
 		case '4':
 			family = AF_INET;
@@ -166,12 +188,24 @@ main(int argc, char *argv[])
 			else
 				errx(1, "unsupported proxy protocol");
 			break;
+		case 'C':
+			Cflag = optarg;
+			break;
+		case 'c':
+			usetls = 1;
+			break;
 		case 'd':
 			dflag = 1;
 			break;
+		case 'e':
+			tls_expectname = optarg;
+			break;
 		case 'F':
 			Fflag = 1;
 			break;
+		case 'H':
+			tls_expecthash = optarg;
+			break;
 		case 'h':
 			help();
 			break;
@@ -180,6 +214,9 @@ main(int argc, char *argv[])
 			if (errstr)
 				errx(1, "interval %s: %s", errstr, optarg);
 			break;
+		case 'K':
+			Kflag = optarg;
+			break;
 		case 'k':
 			kflag = 1;
 			break;
@@ -198,6 +235,10 @@ main(int argc, char *argv[])
 		case 'p':
 			pflag = optarg;
 			break;
+		case 'R':
+			tls_cachanged = 1;
+			Rflag = optarg;
+			break;
 		case 'r':
 			rflag = 1;
 			break;
@@ -256,6 +297,8 @@ main(int argc, char *argv[])
 			errno = 0;
 			if (map_tos(optarg, &Tflag))
 				break;
+			if (map_tls(optarg, &TLSopt))
+				break;
 			if (strlen(optarg) > 1 && optarg[0] == '0' &&
 			    optarg[1] == 'x')
 				Tflag = (int)strtol(optarg, NULL, 16);
@@ -263,7 +306,7 @@ main(int argc, char *argv[])
 				Tflag = (int)strtonum(optarg, 0, 255,
 				    &errstr);
 			if (Tflag < 0 || Tflag > 255 || errstr || errno)
-				errx(1, "illegal tos value %s", optarg);
+				errx(1, "illegal tos/tls value %s", optarg);
 			break;
 		default:
 			usage(1);
@@ -272,6 +315,22 @@ main(int argc, char *argv[])
 	argc -= optind;
 	argv += optind;
 
+	if (rtableid >= 0)
+		if (setrtable(rtableid) == -1)
+			err(1, "setrtable");
+
+	if (family == AF_UNIX) {
+		if (pledge("stdio rpath wpath cpath tmppath unix", NULL) == -1)
+			err(1, "pledge");
+	} else if (Fflag) {
+		if (pledge("stdio inet dns sendfd", NULL) == -1)
+			err(1, "pledge");
+	} else if (usetls) {
+		if (pledge("stdio rpath inet dns", NULL) == -1)
+			err(1, "pledge");
+	} else if (pledge("stdio inet dns", NULL) == -1)
+		err(1, "pledge");
+
 	/* Cruft to make sure options are clean, and used properly. */
 	if (argv[0] && !argv[1] && family == AF_UNIX) {
 		host = argv[0];
@@ -295,6 +354,26 @@ main(int argc, char *argv[])
 		errx(1, "cannot use -z and -l");
 	if (!lflag && kflag)
 		errx(1, "must use -l with -k");
+	if (uflag && usetls)
+		errx(1, "cannot use -c and -u");
+	if ((family == AF_UNIX) && usetls)
+		errx(1, "cannot use -c and -U");
+	if ((family == AF_UNIX) && Fflag)
+		errx(1, "cannot use -F and -U");
+	if (Fflag && usetls)
+		errx(1, "cannot use -c and -F");
+	if (TLSopt && !usetls)
+		errx(1, "you must specify -c to use TLS options");
+	if (Cflag && !usetls)
+		errx(1, "you must specify -c to use -C");
+	if (Kflag && !usetls)
+		errx(1, "you must specify -c to use -K");
+	if (tls_cachanged && !usetls)
+		errx(1, "you must specify -c to use -R");
+	if (tls_expecthash && !usetls)
+		errx(1, "you must specify -c to use -H");
+	if (tls_expectname && !usetls)
+		errx(1, "you must specify -c to use -e");
 
 	/* Get name of temporary socket for unix datagram client */
 	if ((family == AF_UNIX) && uflag && !lflag) {
@@ -302,7 +381,7 @@ main(int argc, char *argv[])
 			unix_dg_tmp_socket = sflag;
 		} else {
 			strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX",
-				UNIX_DG_TMP_SOCKET_SIZE);
+			    UNIX_DG_TMP_SOCKET_SIZE);
 			if (mktemp(unix_dg_tmp_socket_buf) == NULL)
 				err(1, "mktemp");
 			unix_dg_tmp_socket = unix_dg_tmp_socket_buf;
@@ -347,17 +426,62 @@ main(int argc, char *argv[])
 			proxyhints.ai_flags |= AI_NUMERICHOST;
 	}
 
+	if (usetls) {
+		if (Rflag && (cacert = tls_load_file(Rflag, &cacertlen, NULL)) == NULL)
+			errx(1, "unable to load root CA file %s", Rflag);
+		if (Cflag && (pubcert = tls_load_file(Cflag, &pubcertlen, NULL)) == NULL)
+			errx(1, "unable to load TLS certificate file %s", Cflag);
+		if (Kflag && (privkey = tls_load_file(Kflag, &privkeylen, NULL)) == NULL)
+			errx(1, "unable to load TLS key file %s", Kflag);
+
+		if (pledge("stdio inet dns", NULL) == -1)
+			err(1, "pledge");
+
+		if (tls_init() == -1)
+			errx(1, "unable to initialize TLS");
+		if ((tls_cfg = tls_config_new()) == NULL)
+			errx(1, "unable to allocate TLS config");
+		if (Rflag && tls_config_set_ca_mem(tls_cfg, cacert, cacertlen) == -1)
+			errx(1, "unable to set root CA file %s", Rflag);
+		if (Cflag && tls_config_set_cert_mem(tls_cfg, pubcert, pubcertlen) == -1)
+			errx(1, "unable to set TLS certificate file %s", Cflag);
+		if (Kflag && tls_config_set_key_mem(tls_cfg, privkey, privkeylen) == -1)
+			errx(1, "unable to set TLS key file %s", Kflag);
+		if (TLSopt & TLS_LEGACY) {
+			tls_config_set_protocols(tls_cfg, TLS_PROTOCOLS_ALL);
+			tls_config_set_ciphers(tls_cfg, "legacy");
+		}
+		if (!lflag && (TLSopt & TLS_CCERT))
+			errx(1, "clientcert is only valid with -l");
+		if (TLSopt & TLS_NONAME)
+			tls_config_insecure_noverifyname(tls_cfg);
+		if (TLSopt & TLS_NOVERIFY) {
+			if (tls_expecthash != NULL)
+				errx(1, "-H and -T noverify may not be used"
+				    "together");
+			tls_config_insecure_noverifycert(tls_cfg);
+		}
+	}
 	if (lflag) {
+		struct tls *tls_cctx = NULL;
 		int connfd;
 		ret = 0;
 
 		if (family == AF_UNIX) {
 			if (uflag)
-				s = unix_bind(host);
+				s = unix_bind(host, 0);
 			else
 				s = unix_listen(host);
 		}
 
+		if (usetls) {
+			tls_config_verify_client_optional(tls_cfg);
+			if ((tls_ctx = tls_server()) == NULL)
+				errx(1, "tls server creation failed");
+			if (tls_configure(tls_ctx, tls_cfg) == -1)
+				errx(1, "tls configuration failed (%s)",
+				    tls_error(tls_ctx));
+		}
 		/* Allow only one connection at a time, but stay alive. */
 		for (;;) {
 			if (family != AF_UNIX)
@@ -369,7 +493,7 @@ main(int argc, char *argv[])
 			 * receive datagrams from multiple socket pairs.
 			 */
 			if (uflag && kflag)
-				readwrite(s);
+				readwrite(s, NULL);
 			/*
 			 * For UDP and not -k, we will use recvfrom() initially
 			 * to wait for a caller, then use the regular functions
@@ -394,22 +518,34 @@ main(int argc, char *argv[])
 				if (vflag)
 					report_connect((struct sockaddr *)&z, len);
 
-				readwrite(s);
+				readwrite(s, NULL);
 			} else {
 				len = sizeof(cliaddr);
-				connfd = accept(s, (struct sockaddr *)&cliaddr,
-				    &len);
+				connfd = accept4(s, (struct sockaddr *)&cliaddr,
+				    &len, SOCK_NONBLOCK);
 				if (connfd == -1) {
 					/* For now, all errnos are fatal */
 					err(1, "accept");
 				}
 				if (vflag)
 					report_connect((struct sockaddr *)&cliaddr, len);
-
-				readwrite(connfd);
+				if ((usetls) &&
+				    (tls_cctx = tls_setup_server(tls_ctx, connfd, host)))
+					readwrite(connfd, tls_cctx);
+				if (!usetls)
+					readwrite(connfd, NULL);
+				if (tls_cctx) {
+					int i;
+
+					do {
+						i = tls_close(tls_cctx);
+					} while (i == TLS_WANT_POLLIN ||
+					    i == TLS_WANT_POLLOUT);
+					tls_free(tls_cctx);
+					tls_cctx = NULL;
+				}
 				close(connfd);
 			}
-
 			if (family != AF_UNIX)
 				close(s);
 			else if (uflag) {
@@ -424,7 +560,7 @@ main(int argc, char *argv[])
 		ret = 0;
 
 		if ((s = unix_connect(host)) > 0 && !zflag) {
-			readwrite(s);
+			readwrite(s, NULL);
 			close(s);
 		} else
 			ret = 1;
@@ -444,6 +580,13 @@ main(int argc, char *argv[])
 			if (s)
 				close(s);
 
+			if (usetls) {
+				if ((tls_ctx = tls_client()) == NULL)
+					errx(1, "tls client creation failed");
+				if (tls_configure(tls_ctx, tls_cfg) == -1)
+					errx(1, "tls configuration failed (%s)",
+					    tls_error(tls_ctx));
+			}
 			if (xflag)
 				s = socks_connect(host, portlist[i], hints,
 				    proxyhost, proxyport, proxyhints, socksv,
@@ -481,14 +624,30 @@ main(int argc, char *argv[])
 			}
 			if (Fflag)
 				fdpass(s);
-			else if (!zflag)
-				readwrite(s);
+			else {
+				if (usetls)
+					tls_setup_client(tls_ctx, s, host);
+				if (!zflag)
+					readwrite(s, tls_ctx);
+				if (tls_ctx) {
+					int j;
+
+					do {
+						j = tls_close(tls_ctx);
+					} while (j == TLS_WANT_POLLIN ||
+					    j == TLS_WANT_POLLOUT);
+					tls_free(tls_ctx);
+					tls_ctx = NULL;
+				}
+			}
 		}
 	}
 
 	if (s)
 		close(s);
 
+	tls_config_free(tls_cfg);
+
 	exit(ret);
 }
 
@@ -497,33 +656,95 @@ main(int argc, char *argv[])
  * Returns a unix socket bound to the given path
  */
 int
-unix_bind(char *path)
+unix_bind(char *path, int flags)
 {
-	struct sockaddr_un sun;
+	struct sockaddr_un s_un;
 	int s;
 
 	/* Create unix domain socket. */
-	if ((s = socket(AF_UNIX, uflag ? SOCK_DGRAM : SOCK_STREAM,
-	     0)) < 0)
+	if ((s = socket(AF_UNIX, flags | (uflag ? SOCK_DGRAM : SOCK_STREAM),
+	    0)) < 0)
 		return (-1);
 
-	memset(&sun, 0, sizeof(struct sockaddr_un));
-	sun.sun_family = AF_UNIX;
+	memset(&s_un, 0, sizeof(struct sockaddr_un));
+	s_un.sun_family = AF_UNIX;
 
-	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
-	    sizeof(sun.sun_path)) {
+	if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) >=
+	    sizeof(s_un.sun_path)) {
 		close(s);
 		errno = ENAMETOOLONG;
 		return (-1);
 	}
 
-	if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
+	if (bind(s, (struct sockaddr *)&s_un, sizeof(s_un)) < 0) {
 		close(s);
 		return (-1);
 	}
 	return (s);
 }
 
+void
+tls_setup_client(struct tls *tls_ctx, int s, char *host)
+{
+	int i;
+
+	if (tls_connect_socket(tls_ctx, s,
+		tls_expectname ? tls_expectname : host) == -1) {
+		errx(1, "tls connection failed (%s)",
+		    tls_error(tls_ctx));
+	}
+	do {
+		if ((i = tls_handshake(tls_ctx)) == -1)
+			errx(1, "tls handshake failed (%s)",
+			    tls_error(tls_ctx));
+	} while (i == TLS_WANT_POLLIN || i == TLS_WANT_POLLOUT);
+	if (vflag)
+		report_tls(tls_ctx, host, tls_expectname);
+	if (tls_expecthash && tls_peer_cert_hash(tls_ctx) &&
+	    strcmp(tls_expecthash, tls_peer_cert_hash(tls_ctx)) != 0)
+		errx(1, "peer certificate is not %s", tls_expecthash);
+}
+
+struct tls *
+tls_setup_server(struct tls *tls_ctx, int connfd, char *host)
+{
+	struct tls *tls_cctx;
+
+	if (tls_accept_socket(tls_ctx, &tls_cctx,
+		connfd) == -1) {
+		warnx("tls accept failed (%s)",
+		    tls_error(tls_ctx));
+		tls_cctx = NULL;
+	} else {
+		int i;
+
+		do {
+			if ((i = tls_handshake(tls_cctx)) == -1)
+				warnx("tls handshake failed (%s)",
+				    tls_error(tls_cctx));
+		} while(i == TLS_WANT_POLLIN || i == TLS_WANT_POLLOUT);
+	}
+	if (tls_cctx) {
+		int gotcert = tls_peer_cert_provided(tls_cctx);
+
+		if (vflag && gotcert)
+			report_tls(tls_cctx, host, tls_expectname);
+		if ((TLSopt & TLS_CCERT) && !gotcert)
+			warnx("No client certificate provided");
+		else if (gotcert && tls_peer_cert_hash(tls_ctx) && tls_expecthash &&
+		    strcmp(tls_expecthash, tls_peer_cert_hash(tls_ctx)) != 0)
+			warnx("peer certificate is not %s", tls_expecthash);
+		else if (gotcert && tls_expectname &&
+		    (!tls_peer_cert_contains_name(tls_cctx, tls_expectname)))
+			warnx("name (%s) not found in client cert",
+			    tls_expectname);
+		else {
+			return tls_cctx;
+		}
+	}
+	return NULL;
+}
+
 /*
  * unix_connect()
  * Returns a socket connected to a local unix socket. Returns -1 on failure.
@@ -531,28 +752,27 @@ unix_bind(char *path)
 int
 unix_connect(char *path)
 {
-	struct sockaddr_un sun;
+	struct sockaddr_un s_un;
 	int s;
 
 	if (uflag) {
-		if ((s = unix_bind(unix_dg_tmp_socket)) < 0)
+		if ((s = unix_bind(unix_dg_tmp_socket, SOCK_CLOEXEC)) < 0)
 			return (-1);
 	} else {
-		if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+		if ((s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) < 0)
 			return (-1);
 	}
-	(void)fcntl(s, F_SETFD, FD_CLOEXEC);
 
-	memset(&sun, 0, sizeof(struct sockaddr_un));
-	sun.sun_family = AF_UNIX;
+	memset(&s_un, 0, sizeof(struct sockaddr_un));
+	s_un.sun_family = AF_UNIX;
 
-	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
-	    sizeof(sun.sun_path)) {
+	if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) >=
+	    sizeof(s_un.sun_path)) {
 		close(s);
 		errno = ENAMETOOLONG;
 		return (-1);
 	}
-	if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
+	if (connect(s, (struct sockaddr *)&s_un, sizeof(s_un)) < 0) {
 		close(s);
 		return (-1);
 	}
@@ -568,7 +788,7 @@ int
 unix_listen(char *path)
 {
 	int s;
-	if ((s = unix_bind(path)) < 0)
+	if ((s = unix_bind(path, 0)) < 0)
 		return (-1);
 
 	if (listen(s, 5) < 0) {
@@ -594,14 +814,10 @@ remote_connect(const char *host, const c
 
 	res0 = res;
 	do {
-		if ((s = socket(res0->ai_family, res0->ai_socktype,
-		    res0->ai_protocol)) < 0)
+		if ((s = socket(res0->ai_family, res0->ai_socktype |
+		    SOCK_NONBLOCK, res0->ai_protocol)) < 0)
 			continue;
 
-		if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_RTABLE,
-		    &rtableid, sizeof(rtableid)) == -1))
-			err(1, "setsockopt SO_RTABLE");
-
 		/* Bind to a local port or source address if specified. */
 		if (sflag || pflag) {
 			struct addrinfo ahints, *ares;
@@ -626,7 +842,7 @@ remote_connect(const char *host, const c
 
 		if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
 			break;
-		else if (vflag)
+		if (vflag)
 			warn("connect to %s port %s (%s) failed", host, port,
 			    uflag ? "udp" : "tcp");
 
@@ -644,15 +860,9 @@ timeout_connect(int s, const struct sock
 {
 	struct pollfd pfd;
 	socklen_t optlen;
-	int flags, optval;
+	int optval;
 	int ret;
 
-	if (timeout != -1) {
-		flags = fcntl(s, F_GETFL, 0);
-		if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
-			err(1, "set non-blocking mode");
-	}
-
 	if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) {
 		pfd.fd = s;
 		pfd.events = POLLOUT;
@@ -670,9 +880,6 @@ timeout_connect(int s, const struct sock
 			err(1, "poll failed");
 	}
 
-	if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1)
-		err(1, "restoring flags");
-
 	return (ret);
 }
 
@@ -707,10 +914,6 @@ local_listen(char *host, char *port, str
 		    res0->ai_protocol)) < 0)
 			continue;
 
-		if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_RTABLE,
-		    &rtableid, sizeof(rtableid)) == -1))
-			err(1, "setsockopt SO_RTABLE");
-
 		ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));
 		if (ret == -1)
 			err(1, NULL);
@@ -740,7 +943,7 @@ local_listen(char *host, char *port, str
  * Loop that polls on the network file descriptor and stdin.
  */
 void
-readwrite(int net_fd)
+readwrite(int net_fd, struct tls *tls_ctx)
 {
 	struct pollfd pfd[4];
 	int stdin_fd = STDIN_FILENO;
@@ -774,8 +977,8 @@ readwrite(int net_fd)
 
 	while (1) {
 		/* both inputs are gone, buffers are empty, we are done */
-		if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1
-		    && stdinbufpos == 0 && netinbufpos == 0) {
+		if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1 &&
+		    stdinbufpos == 0 && netinbufpos == 0) {
 			close(net_fd);
 			return;
 		}
@@ -785,8 +988,8 @@ readwrite(int net_fd)
 			return;
 		}
 		/* listen and net in gone, queues empty, done */
-		if (lflag && pfd[POLL_NETIN].fd == -1
-		    && stdinbufpos == 0 && netinbufpos == 0) {
+		if (lflag && pfd[POLL_NETIN].fd == -1 &&
+		    stdinbufpos == 0 && netinbufpos == 0) {
 			close(net_fd);
 			return;
 		}
@@ -819,13 +1022,13 @@ readwrite(int net_fd)
 		/* reading is possible after HUP */
 		if (pfd[POLL_STDIN].events & POLLIN &&
 		    pfd[POLL_STDIN].revents & POLLHUP &&
-		    ! (pfd[POLL_STDIN].revents & POLLIN))
-				pfd[POLL_STDIN].fd = -1;
+		    !(pfd[POLL_STDIN].revents & POLLIN))
+			pfd[POLL_STDIN].fd = -1;
 
 		if (pfd[POLL_NETIN].events & POLLIN &&
 		    pfd[POLL_NETIN].revents & POLLHUP &&
-		    ! (pfd[POLL_NETIN].revents & POLLIN))
-				pfd[POLL_NETIN].fd = -1;
+		    !(pfd[POLL_NETIN].revents & POLLIN))
+			pfd[POLL_NETIN].fd = -1;
 
 		if (pfd[POLL_NETOUT].revents & POLLHUP) {
 			if (Nflag)
@@ -848,9 +1051,12 @@ readwrite(int net_fd)
 		/* try to read from stdin */
 		if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) {
 			ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf,
-			    &stdinbufpos);
-			/* error or eof on stdin - remove from pfd */
-			if (ret == 0 || ret == -1)
+			    &stdinbufpos, NULL);
+			if (ret == TLS_WANT_POLLIN)
+				pfd[POLL_STDIN].events = POLLIN;
+			else if (ret == TLS_WANT_POLLOUT)
+				pfd[POLL_STDIN].events = POLLOUT;
+			else if (ret == 0 || ret == -1)
 				pfd[POLL_STDIN].fd = -1;
 			/* read something - poll net out */
 			if (stdinbufpos > 0)
@@ -862,8 +1068,12 @@ readwrite(int net_fd)
 		/* try to write to network */
 		if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) {
 			ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf,
-			    &stdinbufpos);
-			if (ret == -1)
+			    &stdinbufpos, tls_ctx);
+			if (ret == TLS_WANT_POLLIN)
+				pfd[POLL_NETOUT].events = POLLIN;
+			else if (ret == TLS_WANT_POLLOUT)
+				pfd[POLL_NETOUT].events = POLLOUT;
+			else if (ret == -1)
 				pfd[POLL_NETOUT].fd = -1;
 			/* buffer empty - remove self from polling */
 			if (stdinbufpos == 0)
@@ -875,8 +1085,12 @@ readwrite(int net_fd)
 		/* try to read from network */
 		if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) {
 			ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf,
-			    &netinbufpos);
-			if (ret == -1)
+			    &netinbufpos, tls_ctx);
+			if (ret == TLS_WANT_POLLIN)
+				pfd[POLL_NETIN].events = POLLIN;
+			else if (ret == TLS_WANT_POLLOUT)
+				pfd[POLL_NETIN].events = POLLOUT;
+			else if (ret == -1)
 				pfd[POLL_NETIN].fd = -1;
 			/* eof on net in - remove from pfd */
 			if (ret == 0) {
@@ -897,8 +1111,12 @@ readwrite(int net_fd)
 		/* try to write to stdout */
 		if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) {
 			ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf,
-			    &netinbufpos);
-			if (ret == -1)
+			    &netinbufpos, NULL);
+			if (ret == TLS_WANT_POLLIN)
+				pfd[POLL_STDOUT].events = POLLIN;
+			else if (ret == TLS_WANT_POLLOUT)
+				pfd[POLL_STDOUT].events = POLLOUT;
+			else if (ret == -1)
 				pfd[POLL_STDOUT].fd = -1;
 			/* buffer empty - remove self from polling */
 			if (netinbufpos == 0)
@@ -922,15 +1140,19 @@ readwrite(int net_fd)
 }
 
 ssize_t
-drainbuf(int fd, unsigned char *buf, size_t *bufpos)
+drainbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls)
 {
 	ssize_t n;
 	ssize_t adjust;
 
-	n = write(fd, buf, *bufpos);
-	/* don't treat EAGAIN, EINTR as error */
-	if (n == -1 && (errno == EAGAIN || errno == EINTR))
-		n = -2;
+	if (tls)
+		n = tls_write(tls, buf, *bufpos);
+	else {
+		n = write(fd, buf, *bufpos);
+		/* don't treat EAGAIN, EINTR as error */
+		if (n == -1 && (errno == EAGAIN || errno == EINTR))
+			n = TLS_WANT_POLLOUT;
+	}
 	if (n <= 0)
 		return n;
 	/* adjust buffer */
@@ -941,17 +1163,20 @@ drainbuf(int fd, unsigned char *buf, siz
 	return n;
 }
 
-
 ssize_t
-fillbuf(int fd, unsigned char *buf, size_t *bufpos)
+fillbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls)
 {
 	size_t num = BUFSIZE - *bufpos;
 	ssize_t n;
 
-	n = read(fd, buf + *bufpos, num);
-	/* don't treat EAGAIN, EINTR as error */
-	if (n == -1 && (errno == EAGAIN || errno == EINTR))
-		n = -2;
+	if (tls)
+		n = tls_read(tls, buf + *bufpos, num);
+	else {
+		n = read(fd, buf + *bufpos, num);
+		/* don't treat EAGAIN, EINTR as error */
+		if (n == -1 && (errno == EAGAIN || errno == EINTR))
+			n = TLS_WANT_POLLIN;
+	}
 	if (n <= 0)
 		return n;
 	*bufpos += n;
@@ -1079,25 +1304,22 @@ build_ports(char *p)
 			lo = cp;
 		}
 
-		/* Load ports sequentially. */
-		for (cp = lo; cp <= hi; cp++) {
-			portlist[x] = calloc(1, PORT_MAX_LEN);
-			if (portlist[x] == NULL)
-				err(1, NULL);
-			snprintf(portlist[x], PORT_MAX_LEN, "%d", cp);
-			x++;
-		}
-
-		/* Randomly swap ports. */
+		/*
+		 * Initialize portlist with a random permutation.  Based on
+		 * Knuth, as in ip_randomid() in sys/netinet/ip_id.c.
+		 */
 		if (rflag) {
-			int y;
-			char *c;
-
-			for (x = 0; x <= (hi - lo); x++) {
-				y = (arc4random() & 0xFFFF) % (hi - lo);
-				c = portlist[x];
-				portlist[x] = portlist[y];
-				portlist[y] = c;
+			for (x = 0; x <= hi - lo; x++) {
+				cp = arc4random_uniform(x + 1);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list