Date: Fri, 10 May 2019 17:29:17 +0000 (UTC) From: =?UTF-8?Q?Dag-Erling_Sm=c3=b8rgrav?= <des@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org Subject: svn commit: r347448 - vendor/netcat/dist Message-ID: <201905101729.x4AHTH2s009370@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: des Date: Fri May 10 17:29:17 2019 New Revision: 347448 URL: https://svnweb.freebsd.org/changeset/base/347448 Log: Import netcat from OpenBSD 6.1. Modified: vendor/netcat/dist/nc.1 vendor/netcat/dist/netcat.c Modified: vendor/netcat/dist/nc.1 ============================================================================== --- vendor/netcat/dist/nc.1 Fri May 10 17:29:00 2019 (r347447) +++ vendor/netcat/dist/nc.1 Fri May 10 17:29:17 2019 (r347448) @@ -1,4 +1,4 @@ -.\" $OpenBSD: nc.1,v 1.74 2016/07/02 05:58:00 jmc Exp $ +.\" $OpenBSD: nc.1,v 1.82 2017/02/09 20:15:59 jca 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: July 2 2016 $ +.Dd $Mdocdate: February 9 2017 $ .Dt NC 1 .Os .Sh NAME @@ -43,6 +43,7 @@ .Op Fl M Ar ttl .Op Fl m Ar minttl .Op Fl O Ar length +.Op Fl o Ar staplefile .Op Fl P Ar proxy_username .Op Fl p Ar source_port .Op Fl R Ar CAfile @@ -187,6 +188,12 @@ Do not do any DNS or service lookups on any specified hostnames or ports. .It Fl O Ar length Specifies the size of the TCP send buffer. +.It Fl o Ar staplefile +Specifies the filename from which to load data to be stapled +during the TLS handshake. +The file is expected to contain an OCSP response from an OCSP server in +DER format. +May only be used with TLS and when a certificate is being used. .It Fl P Ar proxy_username Specifies a username to present to a proxy server that requires authentication. If no username is specified then authentication will not be attempted. @@ -224,14 +231,17 @@ 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 , +.Ar tlsall ; +which allows the use of all supported TLS protocols and ciphers, +.Ar noverify ; which disables certificate verification; .Ar noname , -which disables certificate name checking; or +which disables certificate name checking; .Ar clientcert , -which requires a client certificate on incoming connections. +which requires a client certificate on incoming connections; or +.Ar muststaple , +which requires the peer to provide a valid stapled OCSP response +with the handshake. It is illegal to specify TLS options if not using TLS. .Pp For IPv4 TOS value @@ -317,6 +327,9 @@ If .Ar port is not specified, the well-known port for the proxy protocol is used (1080 for SOCKS, 3128 for HTTPS). +An IPv6 address can be specified unambiguously by enclosing +.Ar proxy_address +in square brackets. .It Fl z Specifies that .Nm Modified: vendor/netcat/dist/netcat.c ============================================================================== --- vendor/netcat/dist/netcat.c Fri May 10 17:29:00 2019 (r347447) +++ vendor/netcat/dist/netcat.c Fri May 10 17:29:17 2019 (r347448) @@ -1,4 +1,4 @@ -/* $OpenBSD: netcat.c,v 1.160 2016/07/13 16:35:47 jsing Exp $ */ +/* $OpenBSD: netcat.c,v 1.178 2017/03/09 13:58:00 bluhm Exp $ */ /* * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> * Copyright (c) 2015 Bob Beck. All rights reserved. @@ -67,10 +67,11 @@ #define BUFSIZE 16384 #define DEFAULT_CA_FILE "/etc/ssl/cert.pem" -#define TLS_LEGACY (1 << 1) +#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) /* Command Line Options */ int dflag; /* detached, no stdin */ @@ -99,17 +100,12 @@ int rtableid = -1; int usetls; /* use TLS */ char *Cflag; /* Public cert file */ char *Kflag; /* Private key file */ +char *oflag; /* OCSP stapling 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; @@ -125,6 +121,7 @@ int local_listen(char *, char *, struct addrinfo); void readwrite(int, struct tls *); void fdpass(int nfd) __attribute__((noreturn)); int remote_connect(const char *, const char *, struct addrinfo); +int timeout_tls(int, struct tls *, int (*)(struct tls *)); 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 *); @@ -152,8 +149,8 @@ main(int argc, char *argv[]) struct servent *sv; socklen_t len; struct sockaddr_storage cliaddr; - char *proxy; - const char *errstr, *proxyhost = "", *proxyport = NULL; + char *proxy, *proxyport = NULL; + const char *errstr; struct addrinfo proxyhints; char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE]; struct tls_config *tls_cfg = NULL; @@ -168,7 +165,7 @@ main(int argc, char *argv[]) signal(SIGPIPE, SIG_IGN); while ((ch = getopt(argc, argv, - "46C:cDde:FH:hI:i:K:klM:m:NnO: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:X:x:z")) != -1) { switch (ch) { case '4': family = AF_INET; @@ -300,6 +297,9 @@ main(int argc, char *argv[]) errx(1, "TCP send window %s: %s", errstr, optarg); break; + case 'o': + oflag = optarg; + break; case 'S': Sflag = 1; break; @@ -385,6 +385,8 @@ main(int argc, char *argv[]) errx(1, "you must specify -c to use -C"); if (Kflag && !usetls) errx(1, "you must specify -c to use -K"); + if (oflag && !Cflag) + errx(1, "you must specify -C to use -o"); if (tls_cachanged && !usetls) errx(1, "you must specify -c to use -R"); if (tls_expecthash && !usetls) @@ -425,15 +427,29 @@ main(int argc, char *argv[]) if (family == AF_UNIX) errx(1, "no proxy support for unix sockets"); - /* XXX IPv6 transport to proxy would probably work */ - if (family == AF_INET6) - errx(1, "no proxy support for IPv6"); - if (sflag) errx(1, "no proxy support for local source address"); - proxyhost = strsep(&proxy, ":"); - proxyport = proxy; + if (*proxy == '[') { + ++proxy; + proxyport = strchr(proxy, ']'); + if (proxyport == NULL) + errx(1, "missing closing bracket in proxy"); + *proxyport++ = '\0'; + if (*proxyport == '\0') + /* Use default proxy port. */ + proxyport = NULL; + else { + if (*proxyport == ':') + ++proxyport; + else + errx(1, "garbage proxy port delimiter"); + } + } else { + proxyport = strrchr(proxy, ':'); + if (proxyport != NULL) + *proxyport++ = '\0'; + } memset(&proxyhints, 0, sizeof(struct addrinfo)); proxyhints.ai_family = family; @@ -444,32 +460,30 @@ main(int argc, char *argv[]) } 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 (Pflag) { - if (pledge("stdio inet dns tty", NULL) == -1) + if (pledge("stdio inet dns tty rpath", NULL) == -1) err(1, "pledge"); - } else if (pledge("stdio inet dns", NULL) == -1) + } 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) 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, "all"); + if (Rflag && tls_config_set_ca_file(tls_cfg, Rflag) == -1) + errx(1, "%s", tls_config_error(tls_cfg)); + if (Cflag && tls_config_set_cert_file(tls_cfg, Cflag) == -1) + errx(1, "%s", tls_config_error(tls_cfg)); + if (Kflag && tls_config_set_key_file(tls_cfg, Kflag) == -1) + 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 (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) + errx(1, "%s", tls_config_error(tls_cfg)); } if (!lflag && (TLSopt & TLS_CCERT)) errx(1, "clientcert is only valid with -l"); @@ -481,6 +495,14 @@ main(int argc, char *argv[]) "together"); tls_config_insecure_noverifycert(tls_cfg); } + if (TLSopt & TLS_MUSTSTAPLE) + tls_config_ocsp_require_stapling(tls_cfg); + + if (Pflag) { + if (pledge("stdio inet dns tty", NULL) == -1) + err(1, "pledge"); + } else if (pledge("stdio inet dns", NULL) == -1) + err(1, "pledge"); } if (lflag) { struct tls *tls_cctx = NULL; @@ -556,12 +578,7 @@ main(int argc, char *argv[]) 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); + timeout_tls(s, tls_cctx, tls_close); tls_free(tls_cctx); tls_cctx = NULL; } @@ -580,8 +597,9 @@ main(int argc, char *argv[]) } else if (family == AF_UNIX) { ret = 0; - if ((s = unix_connect(host)) > 0 && !zflag) { - readwrite(s, NULL); + if ((s = unix_connect(host)) > 0) { + if (!zflag) + readwrite(s, NULL); close(s); } else ret = 1; @@ -610,7 +628,7 @@ main(int argc, char *argv[]) } if (xflag) s = socks_connect(host, portlist[i], hints, - proxyhost, proxyport, proxyhints, socksv, + proxy, proxyport, proxyhints, socksv, Pflag); else s = remote_connect(host, portlist[i], hints); @@ -651,12 +669,7 @@ main(int argc, char *argv[]) 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); + timeout_tls(s, tls_ctx, tls_close); tls_free(tls_ctx); tls_ctx = NULL; } @@ -706,21 +719,48 @@ unix_bind(char *path, int flags) return (s); } +int +timeout_tls(int s, struct tls *tls_ctx, int (*func)(struct tls *)) +{ + struct pollfd pfd; + int ret; + + while ((ret = (*func)(tls_ctx)) != 0) { + if (ret == TLS_WANT_POLLIN) + pfd.events = POLLIN; + else if (ret == TLS_WANT_POLLOUT) + pfd.events = POLLOUT; + else + break; + pfd.fd = s; + if ((ret = poll(&pfd, 1, timeout)) == 1) + continue; + else if (ret == 0) { + errno = ETIMEDOUT; + ret = -1; + break; + } else + err(1, "poll failed"); + } + + return (ret); +} + void tls_setup_client(struct tls *tls_ctx, int s, char *host) { - int i; + const char *errstr; 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 (timeout_tls(s, tls_ctx, tls_handshake) == -1) { + if ((errstr = tls_error(tls_ctx)) == NULL) + errstr = strerror(errno); + errx(1, "tls handshake failed (%s)", errstr); + } if (vflag) report_tls(tls_ctx, host, tls_expectname); if (tls_expecthash && tls_peer_cert_hash(tls_ctx) && @@ -732,22 +772,15 @@ struct tls * tls_setup_server(struct tls *tls_ctx, int connfd, char *host) { struct tls *tls_cctx; + const char *errstr; - if (tls_accept_socket(tls_ctx, &tls_cctx, - connfd) == -1) { - warnx("tls accept failed (%s)", - tls_error(tls_ctx)); - tls_cctx = NULL; + if (tls_accept_socket(tls_ctx, &tls_cctx, connfd) == -1) { + warnx("tls accept failed (%s)", tls_error(tls_ctx)); + } else if (timeout_tls(connfd, tls_cctx, tls_handshake) == -1) { + if ((errstr = tls_error(tls_cctx)) == NULL) + errstr = strerror(errno); + warnx("tls handshake failed (%s)", errstr); } 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) @@ -832,15 +865,15 @@ int remote_connect(const char *host, const char *port, struct addrinfo hints) { struct addrinfo *res, *res0; - int s, error, on = 1, save_errno; + int s = -1, error, on = 1, save_errno; - if ((error = getaddrinfo(host, port, &hints, &res))) - errx(1, "getaddrinfo: %s", gai_strerror(error)); + if ((error = getaddrinfo(host, port, &hints, &res0))) + errx(1, "getaddrinfo for host \"%s\" port %s: %s", host, + port, gai_strerror(error)); - res0 = res; - do { - if ((s = socket(res0->ai_family, res0->ai_socktype | - SOCK_NONBLOCK, res0->ai_protocol)) < 0) + for (res = res0; res; res = res->ai_next) { + if ((s = socket(res->ai_family, res->ai_socktype | + SOCK_NONBLOCK, res->ai_protocol)) < 0) continue; /* Bind to a local port or source address if specified. */ @@ -850,7 +883,7 @@ remote_connect(const char *host, const char *port, str /* try SO_BINDANY, but don't insist */ setsockopt(s, SOL_SOCKET, SO_BINDANY, &on, sizeof(on)); memset(&ahints, 0, sizeof(struct addrinfo)); - ahints.ai_family = res0->ai_family; + ahints.ai_family = res->ai_family; ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; ahints.ai_flags = AI_PASSIVE; @@ -863,9 +896,9 @@ remote_connect(const char *host, const char *port, str freeaddrinfo(ares); } - set_common_sockopts(s, res0->ai_family); + set_common_sockopts(s, res->ai_family); - if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0) + if (timeout_connect(s, res->ai_addr, res->ai_addrlen) == 0) break; if (vflag) warn("connect to %s port %s (%s) failed", host, port, @@ -875,9 +908,9 @@ remote_connect(const char *host, const char *port, str close(s); errno = save_errno; s = -1; - } while ((res0 = res0->ai_next) != NULL); + } - freeaddrinfo(res); + freeaddrinfo(res0); return (s); } @@ -919,7 +952,7 @@ int local_listen(char *host, char *port, struct addrinfo hints) { struct addrinfo *res, *res0; - int s, ret, x = 1, save_errno; + int s = -1, ret, x = 1, save_errno; int error; /* Allow nodename to be null. */ @@ -932,37 +965,36 @@ local_listen(char *host, char *port, struct addrinfo h if (host == NULL && hints.ai_family == AF_UNSPEC) hints.ai_family = AF_INET; - if ((error = getaddrinfo(host, port, &hints, &res))) + if ((error = getaddrinfo(host, port, &hints, &res0))) errx(1, "getaddrinfo: %s", gai_strerror(error)); - res0 = res; - do { - if ((s = socket(res0->ai_family, res0->ai_socktype, - res0->ai_protocol)) < 0) + for (res = res0; res; res = res->ai_next) { + if ((s = socket(res->ai_family, res->ai_socktype, + res->ai_protocol)) < 0) continue; ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x)); if (ret == -1) err(1, NULL); - set_common_sockopts(s, res0->ai_family); + set_common_sockopts(s, res->ai_family); - if (bind(s, (struct sockaddr *)res0->ai_addr, - res0->ai_addrlen) == 0) + if (bind(s, (struct sockaddr *)res->ai_addr, + res->ai_addrlen) == 0) break; save_errno = errno; close(s); errno = save_errno; s = -1; - } while ((res0 = res0->ai_next) != NULL); + } if (!uflag && s != -1) { if (listen(s, 1) < 0) err(1, "listen"); } - freeaddrinfo(res); + freeaddrinfo(res0); return (s); } @@ -1007,21 +1039,15 @@ readwrite(int net_fd, struct tls *tls_ctx) 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) { - close(net_fd); + stdinbufpos == 0 && netinbufpos == 0) return; - } /* both outputs are gone, we can't continue */ - if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) { - close(net_fd); + if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) return; - } /* listen and net in gone, queues empty, done */ if (lflag && pfd[POLL_NETIN].fd == -1 && - stdinbufpos == 0 && netinbufpos == 0) { - close(net_fd); + stdinbufpos == 0 && netinbufpos == 0) return; - } /* help says -i is for "wait between lines sent". We read and * write arbitrary amounts of data, and we don't want to start @@ -1033,10 +1059,8 @@ readwrite(int net_fd, struct tls *tls_ctx) num_fds = poll(pfd, 4, timeout); /* treat poll errors */ - if (num_fds == -1) { - close(net_fd); + if (num_fds == -1) err(1, "polling error"); - } /* timeout happened */ if (num_fds == 0) @@ -1507,10 +1531,11 @@ map_tls(char *s, int *val) const char *keyword; int val; } *t, tlskeywords[] = { - { "tlslegacy", TLS_LEGACY }, + { "tlsall", TLS_ALL }, { "noverify", TLS_NOVERIFY }, { "noname", TLS_NONAME }, { "clientcert", TLS_CCERT}, + { "muststaple", TLS_MUSTSTAPLE}, { NULL, -1 }, }; @@ -1527,6 +1552,8 @@ void report_tls(struct tls * tls_ctx, char * host, char *tls_expectname) { time_t t; + const char *ocsp_url; + fprintf(stderr, "TLS handshake negotiated %s/%s with host %s\n", tls_conn_version(tls_ctx), tls_conn_cipher(tls_ctx), host); fprintf(stderr, "Peer name: %s\n", @@ -1544,6 +1571,39 @@ report_tls(struct tls * tls_ctx, char * host, char *tl if (tls_peer_cert_hash(tls_ctx)) fprintf(stderr, "Cert Hash: %s\n", tls_peer_cert_hash(tls_ctx)); + ocsp_url = tls_peer_ocsp_url(tls_ctx); + if (ocsp_url != NULL) + fprintf(stderr, "OCSP URL: %s\n", ocsp_url); + switch (tls_peer_ocsp_response_status(tls_ctx)) { + case TLS_OCSP_RESPONSE_SUCCESSFUL: + fprintf(stderr, "OCSP Stapling: %s\n", + tls_peer_ocsp_result(tls_ctx) == NULL ? "" : + tls_peer_ocsp_result(tls_ctx)); + fprintf(stderr, + " response_status=%d cert_status=%d crl_reason=%d\n", + tls_peer_ocsp_response_status(tls_ctx), + tls_peer_ocsp_cert_status(tls_ctx), + tls_peer_ocsp_crl_reason(tls_ctx)); + t = tls_peer_ocsp_this_update(tls_ctx); + fprintf(stderr, " this update: %s", + t != -1 ? ctime(&t) : "\n"); + t = tls_peer_ocsp_next_update(tls_ctx); + fprintf(stderr, " next update: %s", + t != -1 ? ctime(&t) : "\n"); + t = tls_peer_ocsp_revocation_time(tls_ctx); + fprintf(stderr, " revocation: %s", + t != -1 ? ctime(&t) : "\n"); + break; + case -1: + break; + default: + fprintf(stderr, "OCSP Stapling: failure - response_status %d (%s)\n", + tls_peer_ocsp_response_status(tls_ctx), + tls_peer_ocsp_result(tls_ctx) == NULL ? "" : + tls_peer_ocsp_result(tls_ctx)); + break; + + } } void @@ -1602,6 +1662,7 @@ help(void) \t-N Shutdown the network socket after EOF on stdin\n\ \t-n Suppress name/port resolutions\n\ \t-O length TCP send buffer length\n\ + \t-o staplefile Staple file\n\ \t-P proxyuser\tUsername for proxy authentication\n\ \t-p port\t Specify local port for remote connects\n\ \t-R CAfile CA bundle\n\ @@ -1629,8 +1690,10 @@ usage(int ret) "usage: nc [-46cDdFhklNnrStUuvz] [-C certfile] [-e name] " "[-H hash] [-I length]\n" "\t [-i interval] [-K keyfile] [-M ttl] [-m minttl] [-O length]\n" - "\t [-P proxy_username] [-p source_port] [-R CAfile] [-s source]\n" - "\t [-T keyword] [-V rtable] [-w timeout] [-X proxy_protocol]\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"); if (ret) exit(1);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201905101729.x4AHTH2s009370>