aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2019-05-10 17:29:30 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2019-05-10 17:29:30 +0000
commit61d7c99ff1528b8d57f9cd5f5dea2015b9e6b654 (patch)
tree6eae4c6e40f18b48c00722b9d51343380d0cff8b
parentd13462bc7b61d19a999b7860b1927996bd06baf3 (diff)
downloadsrc-vendor/netcat/6.2.tar.gz
src-vendor/netcat/6.2.zip
Import netcat from OpenBSD 6.2.vendor/netcat/6.2
-rw-r--r--nc.124
-rw-r--r--netcat.c186
2 files changed, 137 insertions, 73 deletions
diff --git a/nc.1 b/nc.1
index b1f96488ab0c..bb3a8f7cf537 100644
--- a/nc.1
+++ b/nc.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: nc.1,v 1.82 2017/02/09 20:15:59 jca Exp $
+.\" $OpenBSD: nc.1,v 1.87 2017/07/15 18:11:47 jmc 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 9 2017 $
+.Dd $Mdocdate: July 15 2017 $
.Dt NC 1
.Os
.Sh NAME
@@ -50,9 +50,11 @@
.Op Fl s Ar source
.Op Fl T Ar keyword
.Op Fl V Ar rtable
+.Op Fl W Ar recvlimit
.Op Fl w Ar timeout
.Op Fl X Ar proxy_protocol
.Op Fl x Ar proxy_address Ns Op : Ns Ar port
+.Op Fl Z Ar peercertfile
.Op Ar destination
.Op Ar port
.Sh DESCRIPTION
@@ -230,10 +232,12 @@ option.
Change IPv4 TOS value or TLS options.
For TLS options
.Ar keyword
-may be one of
-.Ar tlsall ;
-which allows the use of all supported TLS protocols and ciphers,
-.Ar noverify ;
+may be one of:
+.Ar tlsall ,
+which allows the use of all supported TLS protocols and ciphers;
+.Ar tlscompat ,
+which allows the use of all supported TLS protocols and "compat" ciphers;
+.Ar noverify ,
which disables certificate verification;
.Ar noname ,
which disables certificate name checking;
@@ -287,6 +291,10 @@ Set the routing table to be used.
Have
.Nm
give more verbose output.
+.It Fl W Ar recvlimit
+Terminate after receiving
+.Ar recvlimit
+packets from the network.
.It Fl w Ar timeout
Connections which cannot be established or are idle timeout after
.Ar timeout
@@ -330,6 +338,10 @@ for SOCKS, 3128 for HTTPS).
An IPv6 address can be specified unambiguously by enclosing
.Ar proxy_address
in square brackets.
+.It Fl Z Ar peercertfile
+Specifies the filename in which the peer supplied certificates will be saved
+in PEM format.
+May only be used with TLS.
.It Fl z
Specifies that
.Nm
diff --git a/netcat.c b/netcat.c
index e222e1e73115..ce55972a7c2f 100644
--- a/netcat.c
+++ b/netcat.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: netcat.c,v 1.178 2017/03/09 13:58:00 bluhm Exp $ */
+/* $OpenBSD: netcat.c,v 1.187 2017/07/15 17:27:39 jsing Exp $ */
/*
* Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
* Copyright (c) 2015 Bob Beck. All rights reserved.
@@ -53,25 +53,27 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include <unistd.h>
#include <tls.h>
+#include <unistd.h>
+
#include "atomicio.h"
#define PORT_MAX 65535
#define UNIX_DG_TMP_SOCKET_SIZE 19
-#define POLL_STDIN 0
-#define POLL_NETOUT 1
-#define POLL_NETIN 2
-#define POLL_STDOUT 3
-#define BUFSIZE 16384
-#define DEFAULT_CA_FILE "/etc/ssl/cert.pem"
+#define POLL_STDIN 0
+#define POLL_NETOUT 1
+#define POLL_NETIN 2
+#define POLL_STDOUT 3
+#define BUFSIZE 16384
+#define DEFAULT_CA_FILE "/etc/ssl/cert.pem"
#define TLS_ALL (1 << 1)
#define TLS_NOVERIFY (1 << 2)
#define TLS_NONAME (1 << 3)
#define TLS_CCERT (1 << 4)
#define TLS_MUSTSTAPLE (1 << 5)
+#define TLS_COMPAT (1 << 6)
/* Command Line Options */
int dflag; /* detached, no stdin */
@@ -106,7 +108,9 @@ 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 */
+FILE *Zflag; /* file to save peer cert */
+int recvcount, recvlimit;
int timeout = -1;
int family = AF_UNSPEC;
char *portlist[PORT_MAX+1];
@@ -115,8 +119,9 @@ int ttl = -1;
int minttl = -1;
void atelnet(int, unsigned char *, unsigned int);
+int strtoport(char *portstr, int udp);
void build_ports(char *);
-void help(void);
+void help(void) __attribute__((noreturn));
int local_listen(char *, char *, struct addrinfo);
void readwrite(int, struct tls *);
void fdpass(int nfd) __attribute__((noreturn));
@@ -132,8 +137,9 @@ int unix_listen(char *);
void set_common_sockopts(int, int);
int map_tos(char *, int *);
int map_tls(char *, int *);
+void save_peer_cert(struct tls *_tls_ctx, FILE *_fp);
void report_connect(const struct sockaddr *, socklen_t, char *);
-void report_tls(struct tls *tls_ctx, char * host, char *tls_expectname);
+void report_tls(struct tls *tls_ctx, char * host);
void usage(int);
ssize_t drainbuf(int, unsigned char *, size_t *, struct tls *);
ssize_t fillbuf(int, unsigned char *, size_t *, struct tls *);
@@ -149,7 +155,7 @@ main(int argc, char *argv[])
struct servent *sv;
socklen_t len;
struct sockaddr_storage cliaddr;
- char *proxy, *proxyport = NULL;
+ char *proxy = NULL, *proxyport = NULL;
const char *errstr;
struct addrinfo proxyhints;
char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE];
@@ -165,7 +171,8 @@ main(int argc, char *argv[])
signal(SIGPIPE, SIG_IGN);
while ((ch = getopt(argc, argv,
- "46C:cDde:FH:hI:i:K:klM:m:NnO:o:P:p:R:rSs:T:tUuV:vw:X:x:z")) != -1) {
+ "46C:cDde:FH:hI:i:K:klM:m:NnO:o:P:p:R:rSs:T:tUuV:vW:w:X:x:Z:z"))
+ != -1) {
switch (ch) {
case '4':
family = AF_INET;
@@ -268,6 +275,11 @@ main(int argc, char *argv[])
case 'v':
vflag = 1;
break;
+ case 'W':
+ recvlimit = strtonum(optarg, 1, INT_MAX, &errstr);
+ if (errstr)
+ errx(1, "receive limit %s: %s", errstr, optarg);
+ break;
case 'w':
timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr);
if (errstr)
@@ -279,6 +291,12 @@ main(int argc, char *argv[])
if ((proxy = strdup(optarg)) == NULL)
err(1, NULL);
break;
+ case 'Z':
+ if (strcmp(optarg, "-") == 0)
+ Zflag = stderr;
+ else if ((Zflag = fopen(optarg, "w")) == NULL)
+ err(1, "can't open %s", optarg);
+ break;
case 'z':
zflag = 1;
break;
@@ -333,11 +351,14 @@ main(int argc, char *argv[])
if (family == AF_UNIX) {
if (pledge("stdio rpath wpath cpath tmppath unix", NULL) == -1)
err(1, "pledge");
- } else if (Fflag) {
- if (Pflag) {
- if (pledge("stdio inet dns sendfd tty", NULL) == -1)
- err(1, "pledge");
- } else if (pledge("stdio inet dns sendfd", NULL) == -1)
+ } else if (Fflag && Pflag) {
+ if (pledge("stdio inet dns sendfd tty", NULL) == -1)
+ err(1, "pledge");
+ } else if (Fflag) {
+ if (pledge("stdio inet dns sendfd", NULL) == -1)
+ err(1, "pledge");
+ } else if (Pflag && usetls) {
+ if (pledge("stdio rpath inet dns tty", NULL) == -1)
err(1, "pledge");
} else if (Pflag) {
if (pledge("stdio inet dns tty", NULL) == -1)
@@ -353,7 +374,7 @@ main(int argc, char *argv[])
host = argv[0];
uport = NULL;
} else if (argv[0] && !argv[1]) {
- if (!lflag)
+ if (!lflag)
usage(1);
uport = argv[0];
host = NULL;
@@ -381,10 +402,14 @@ main(int argc, char *argv[])
errx(1, "cannot use -c and -F");
if (TLSopt && !usetls)
errx(1, "you must specify -c to use TLS options");
+ if ((TLSopt & (TLS_ALL|TLS_COMPAT)) == (TLS_ALL|TLS_COMPAT))
+ errx(1, "cannot use -T tlsall and -T tlscompat");
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 (Zflag && !usetls)
+ errx(1, "you must specify -c to use -Z");
if (oflag && !Cflag)
errx(1, "you must specify -C to use -o");
if (tls_cachanged && !usetls)
@@ -460,12 +485,6 @@ main(int argc, char *argv[])
}
if (usetls) {
- if (Pflag) {
- if (pledge("stdio inet dns tty rpath", NULL) == -1)
- err(1, "pledge");
- } else if (pledge("stdio inet dns rpath", NULL) == -1)
- err(1, "pledge");
-
if (tls_init() == -1)
errx(1, "unable to initialize TLS");
if ((tls_cfg = tls_config_new()) == NULL)
@@ -478,11 +497,12 @@ main(int argc, char *argv[])
errx(1, "%s", tls_config_error(tls_cfg));
if (oflag && tls_config_set_ocsp_staple_file(tls_cfg, oflag) == -1)
errx(1, "%s", tls_config_error(tls_cfg));
- if (TLSopt & TLS_ALL) {
+ if (TLSopt & (TLS_ALL|TLS_COMPAT)) {
if (tls_config_set_protocols(tls_cfg,
TLS_PROTOCOLS_ALL) != 0)
errx(1, "%s", tls_config_error(tls_cfg));
- if (tls_config_set_ciphers(tls_cfg, "all") != 0)
+ if (tls_config_set_ciphers(tls_cfg,
+ (TLSopt & TLS_ALL) ? "all" : "compat") != 0)
errx(1, "%s", tls_config_error(tls_cfg));
}
if (!lflag && (TLSopt & TLS_CCERT))
@@ -491,7 +511,7 @@ main(int argc, char *argv[])
tls_config_insecure_noverifyname(tls_cfg);
if (TLSopt & TLS_NOVERIFY) {
if (tls_expecthash != NULL)
- errx(1, "-H and -T noverify may not be used"
+ errx(1, "-H and -T noverify may not be used "
"together");
tls_config_insecure_noverifycert(tls_cfg);
}
@@ -530,18 +550,19 @@ main(int argc, char *argv[])
s = local_listen(host, uport, hints);
if (s < 0)
err(1, NULL);
- /*
- * For UDP and -k, don't connect the socket, let it
- * receive datagrams from multiple socket pairs.
- */
- if (uflag && kflag)
+ if (uflag && kflag) {
+ /*
+ * For UDP and -k, don't connect the socket,
+ * let it receive datagrams from multiple
+ * socket pairs.
+ */
readwrite(s, NULL);
- /*
- * For UDP and not -k, we will use recvfrom() initially
- * to wait for a caller, then use the regular functions
- * to talk to the caller.
- */
- else if (uflag && !kflag) {
+ } else if (uflag && !kflag) {
+ /*
+ * For UDP and not -k, we will use recvfrom()
+ * initially to wait for a caller, then use
+ * the regular functions to talk to the caller.
+ */
int rv, plen;
char buf[16384];
struct sockaddr_storage z;
@@ -606,7 +627,7 @@ main(int argc, char *argv[])
if (uflag)
unlink(unix_dg_tmp_socket);
- exit(ret);
+ return ret;
} else {
int i = 0;
@@ -682,7 +703,7 @@ main(int argc, char *argv[])
tls_config_free(tls_cfg);
- exit(ret);
+ return ret;
}
/*
@@ -698,7 +719,7 @@ unix_bind(char *path, int flags)
/* Create unix domain socket. */
if ((s = socket(AF_UNIX, flags | (uflag ? SOCK_DGRAM : SOCK_STREAM),
0)) < 0)
- return (-1);
+ return -1;
memset(&s_un, 0, sizeof(struct sockaddr_un));
s_un.sun_family = AF_UNIX;
@@ -707,16 +728,17 @@ unix_bind(char *path, int flags)
sizeof(s_un.sun_path)) {
close(s);
errno = ENAMETOOLONG;
- return (-1);
+ return -1;
}
if (bind(s, (struct sockaddr *)&s_un, sizeof(s_un)) < 0) {
save_errno = errno;
close(s);
errno = save_errno;
- return (-1);
+ return -1;
}
- return (s);
+
+ return s;
}
int
@@ -743,7 +765,7 @@ timeout_tls(int s, struct tls *tls_ctx, int (*func)(struct tls *))
err(1, "poll failed");
}
- return (ret);
+ return ret;
}
void
@@ -762,10 +784,15 @@ tls_setup_client(struct tls *tls_ctx, int s, char *host)
errx(1, "tls handshake failed (%s)", errstr);
}
if (vflag)
- report_tls(tls_ctx, host, tls_expectname);
+ report_tls(tls_ctx, host);
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);
+ if (Zflag) {
+ save_peer_cert(tls_ctx, Zflag);
+ if (Zflag != stderr && (fclose(Zflag) != 0))
+ err(1, "fclose failed saving peer cert");
+ }
}
struct tls *
@@ -784,7 +811,7 @@ tls_setup_server(struct tls *tls_ctx, int connfd, char *host)
int gotcert = tls_peer_cert_provided(tls_cctx);
if (vflag && gotcert)
- report_tls(tls_cctx, host, tls_expectname);
+ report_tls(tls_cctx, host);
if ((TLSopt & TLS_CCERT) && !gotcert)
warnx("No client certificate provided");
else if (gotcert && tls_peer_cert_hash(tls_ctx) && tls_expecthash &&
@@ -813,10 +840,10 @@ unix_connect(char *path)
if (uflag) {
if ((s = unix_bind(unix_dg_tmp_socket, SOCK_CLOEXEC)) < 0)
- return (-1);
+ return -1;
} else {
if ((s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) < 0)
- return (-1);
+ return -1;
}
memset(&s_un, 0, sizeof(struct sockaddr_un));
@@ -826,15 +853,15 @@ unix_connect(char *path)
sizeof(s_un.sun_path)) {
close(s);
errno = ENAMETOOLONG;
- return (-1);
+ return -1;
}
if (connect(s, (struct sockaddr *)&s_un, sizeof(s_un)) < 0) {
save_errno = errno;
close(s);
errno = save_errno;
- return (-1);
+ return -1;
}
- return (s);
+ return s;
}
@@ -847,13 +874,13 @@ unix_listen(char *path)
{
int s;
if ((s = unix_bind(path, 0)) < 0)
- return (-1);
+ return -1;
if (listen(s, 5) < 0) {
close(s);
- return (-1);
+ return -1;
}
- return (s);
+ return s;
}
/*
@@ -912,7 +939,7 @@ remote_connect(const char *host, const char *port, struct addrinfo hints)
freeaddrinfo(res0);
- return (s);
+ return s;
}
int
@@ -940,7 +967,7 @@ timeout_connect(int s, const struct sockaddr *name, socklen_t namelen)
err(1, "poll failed");
}
- return (ret);
+ return ret;
}
/*
@@ -996,7 +1023,7 @@ local_listen(char *host, char *port, struct addrinfo hints)
freeaddrinfo(res0);
- return (s);
+ return s;
}
/*
@@ -1150,6 +1177,12 @@ readwrite(int net_fd, struct tls *tls_ctx)
shutdown(pfd[POLL_NETIN].fd, SHUT_RD);
pfd[POLL_NETIN].fd = -1;
}
+ if (recvlimit > 0 && ++recvcount >= recvlimit) {
+ if (pfd[POLL_NETIN].fd != -1)
+ shutdown(pfd[POLL_NETIN].fd, SHUT_RD);
+ pfd[POLL_NETIN].fd = -1;
+ pfd[POLL_STDIN].fd = -1;
+ }
/* read something - poll stdout */
if (netinbufpos > 0)
pfd[POLL_STDOUT].events = POLLOUT;
@@ -1417,7 +1450,7 @@ udptest(int s)
else
ret = -1;
}
- return (ret);
+ return ret;
}
void
@@ -1517,11 +1550,11 @@ map_tos(char *s, int *val)
for (t = toskeywords; t->keyword != NULL; t++) {
if (strcmp(s, t->keyword) == 0) {
*val = t->val;
- return (1);
+ return 1;
}
}
- return (0);
+ return 0;
}
int
@@ -1536,20 +1569,35 @@ map_tls(char *s, int *val)
{ "noname", TLS_NONAME },
{ "clientcert", TLS_CCERT},
{ "muststaple", TLS_MUSTSTAPLE},
+ { "tlscompat", TLS_COMPAT },
{ NULL, -1 },
};
for (t = tlskeywords; t->keyword != NULL; t++) {
if (strcmp(s, t->keyword) == 0) {
*val |= t->val;
- return (1);
+ return 1;
}
}
- return (0);
+ return 0;
+}
+
+void
+save_peer_cert(struct tls *tls_ctx, FILE *fp)
+{
+ const char *pem;
+ size_t plen;
+
+ if ((pem = tls_peer_cert_chain_pem(tls_ctx, &plen)) == NULL)
+ errx(1, "Can't get peer certificate");
+ if (fprintf(fp, "%.*s", (int)plen, pem) < 0)
+ err(1, "unable to save peer cert");
+ if (fflush(fp) != 0)
+ err(1, "unable to flush peer cert");
}
void
-report_tls(struct tls * tls_ctx, char * host, char *tls_expectname)
+report_tls(struct tls * tls_ctx, char * host)
{
time_t t;
const char *ocsp_url;
@@ -1675,9 +1723,11 @@ help(void)
\t-u UDP mode\n\
\t-V rtable Specify alternate routing table\n\
\t-v Verbose\n\
+ \t-W recvlimit Terminate after receiving a number of packets\n\
\t-w timeout Timeout for connects and final net reads\n\
\t-X proto Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\
\t-x addr[:port]\tSpecify proxy address and port\n\
+ \t-Z Peer certificate file\n\
\t-z Zero-I/O mode [used for scanning]\n\
Port numbers can be individual or ranges: lo-hi [inclusive]\n");
exit(1);
@@ -1692,9 +1742,11 @@ usage(int ret)
"\t [-i interval] [-K keyfile] [-M ttl] [-m minttl] [-O length]\n"
"\t [-o staplefile] [-P proxy_username] [-p source_port] "
"[-R CAfile]\n"
- "\t [-s source] [-T keyword] [-V rtable] [-w timeout] "
- "[-X proxy_protocol]\n"
- "\t [-x proxy_address[:port]] [destination] [port]\n");
+ "\t [-s source] [-T keyword] [-V rtable] [-W recvlimit] "
+ "[-w timeout]\n"
+ "\t [-X proxy_protocol] [-x proxy_address[:port]] "
+ "[-Z peercertfile]\n"
+ "\t [destination] [port]\n");
if (ret)
exit(1);
}