From owner-svn-src-all@FreeBSD.ORG Thu May 21 21:45:38 2015 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id C4650D48; Thu, 21 May 2015 21:45:38 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id A4A101C58; Thu, 21 May 2015 21:45:38 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t4LLjcte058423; Thu, 21 May 2015 21:45:38 GMT (envelope-from delphij@FreeBSD.org) Received: (from delphij@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t4LLjcvn058422; Thu, 21 May 2015 21:45:38 GMT (envelope-from delphij@FreeBSD.org) Message-Id: <201505212145.t4LLjcvn058422@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: delphij set sender to delphij@FreeBSD.org using -f From: Xin LI Date: Thu, 21 May 2015 21:45:38 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r283270 - stable/10/contrib/netcat X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 21 May 2015 21:45:38 -0000 Author: delphij Date: Thu May 21 21:45:37 2015 New Revision: 283270 URL: https://svnweb.freebsd.org/changeset/base/283270 Log: MFC r282613: MFV r282611: netcat from OpenBSD 5.7. Modified: stable/10/contrib/netcat/netcat.c Directory Properties: stable/10/ (props changed) Modified: stable/10/contrib/netcat/netcat.c ============================================================================== --- stable/10/contrib/netcat/netcat.c Thu May 21 20:47:19 2015 (r283269) +++ stable/10/contrib/netcat/netcat.c Thu May 21 21:45:37 2015 (r283270) @@ -1,4 +1,4 @@ -/* $OpenBSD: netcat.c,v 1.122 2014/07/20 01:38:40 guenther Exp $ */ +/* $OpenBSD: netcat.c,v 1.127 2015/02/14 22:40:22 jca Exp $ */ /* * Copyright (c) 2001 Eric Jackson * @@ -42,7 +42,6 @@ #include #include -#include #ifdef IPSEC #include #endif @@ -73,6 +72,12 @@ #define PORT_MAX_LEN 6 #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 + /* Command Line Options */ int dflag; /* detached, no stdin */ int Fflag; /* fdpass sock to stdout */ @@ -117,10 +122,12 @@ int udptest(int); int unix_bind(char *); int unix_connect(char *); int unix_listen(char *); -void set_common_sockopts(int); +void set_common_sockopts(int, int); int map_tos(char *, int *); void report_connect(const struct sockaddr *, socklen_t); void usage(int); +ssize_t drainbuf(int, unsigned char *, size_t *); +ssize_t fillbuf(int, unsigned char *, size_t *); #ifdef IPSEC void add_ipsec_policy(int, char *); @@ -436,7 +443,7 @@ main(int argc, char *argv[]) &len); if (connfd == -1) { /* For now, all errnos are fatal */ - err(1, "accept"); + err(1, "accept"); } if (vflag) report_connect((struct sockaddr *)&cliaddr, len); @@ -663,7 +670,7 @@ remote_connect(const char *host, const c freeaddrinfo(ares); } - set_common_sockopts(s); + set_common_sockopts(s, res0->ai_family); if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0) break; @@ -767,6 +774,8 @@ local_listen(char *host, char *port, str err(1, "disable TCP options"); } + set_common_sockopts(s, res0->ai_family); + if (bind(s, (struct sockaddr *)res0->ai_addr, res0->ai_addrlen) == 0) break; @@ -790,68 +799,224 @@ local_listen(char *host, char *port, str * Loop that polls on the network file descriptor and stdin. */ void -readwrite(int nfd) +readwrite(int net_fd) { - struct pollfd pfd[2]; - unsigned char buf[16 * 1024]; - int n, wfd = fileno(stdin); - int lfd = fileno(stdout); - int plen; - - plen = sizeof(buf); - - /* Setup Network FD */ - pfd[0].fd = nfd; - pfd[0].events = POLLIN; - - /* Set up STDIN FD. */ - pfd[1].fd = wfd; - pfd[1].events = POLLIN; + struct pollfd pfd[4]; + int stdin_fd = STDIN_FILENO; + int stdout_fd = STDOUT_FILENO; + unsigned char netinbuf[BUFSIZE]; + size_t netinbufpos = 0; + unsigned char stdinbuf[BUFSIZE]; + size_t stdinbufpos = 0; + int n, num_fds; + ssize_t ret; + + /* don't read from stdin if requested */ + if (dflag) + stdin_fd = -1; + + /* stdin */ + pfd[POLL_STDIN].fd = stdin_fd; + pfd[POLL_STDIN].events = POLLIN; + + /* network out */ + pfd[POLL_NETOUT].fd = net_fd; + pfd[POLL_NETOUT].events = 0; + + /* network in */ + pfd[POLL_NETIN].fd = net_fd; + pfd[POLL_NETIN].events = POLLIN; + + /* stdout */ + pfd[POLL_STDOUT].fd = stdout_fd; + pfd[POLL_STDOUT].events = 0; + + 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); + return; + } + /* both outputs are gone, we can't continue */ + if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) { + close(net_fd); + return; + } + /* listen and net in gone, queues empty, done */ + if (lflag && pfd[POLL_NETIN].fd == -1 + && stdinbufpos == 0 && netinbufpos == 0) { + close(net_fd); + return; + } - while (pfd[0].fd != -1) { + /* help says -i is for "wait between lines sent". We read and + * write arbitrary amounts of data, and we don't want to start + * scanning for newlines, so this is as good as it gets */ if (iflag) sleep(iflag); - if ((n = poll(pfd, 2 - dflag, timeout)) < 0) { - int saved_errno = errno; - close(nfd); - errc(1, saved_errno, "Polling Error"); + /* poll */ + num_fds = poll(pfd, 4, timeout); + + /* treat poll errors */ + if (num_fds == -1) { + close(net_fd); + err(1, "polling error"); } - if (n == 0) + /* timeout happened */ + if (num_fds == 0) return; - if (pfd[0].revents & POLLIN) { - if ((n = read(nfd, buf, plen)) < 0) - return; - else if (n == 0) { - shutdown(nfd, SHUT_RD); - pfd[0].fd = -1; - pfd[0].events = 0; - } else { - if (tflag) - atelnet(nfd, buf, n); - if (atomicio(vwrite, lfd, buf, n) != n) - return; + /* treat socket error conditions */ + for (n = 0; n < 4; n++) { + if (pfd[n].revents & (POLLERR|POLLNVAL)) { + pfd[n].fd = -1; } } + /* 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; + + if (pfd[POLL_NETIN].events & POLLIN && + pfd[POLL_NETIN].revents & POLLHUP && + ! (pfd[POLL_NETIN].revents & POLLIN)) + pfd[POLL_NETIN].fd = -1; + + if (pfd[POLL_NETOUT].revents & POLLHUP) { + if (Nflag) + shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); + pfd[POLL_NETOUT].fd = -1; + } + /* if HUP, stop watching stdout */ + if (pfd[POLL_STDOUT].revents & POLLHUP) + pfd[POLL_STDOUT].fd = -1; + /* if no net out, stop watching stdin */ + if (pfd[POLL_NETOUT].fd == -1) + pfd[POLL_STDIN].fd = -1; + /* if no stdout, stop watching net in */ + if (pfd[POLL_STDOUT].fd == -1) { + if (pfd[POLL_NETIN].fd != -1) + shutdown(pfd[POLL_NETIN].fd, SHUT_RD); + pfd[POLL_NETIN].fd = -1; + } - if (!dflag && pfd[1].revents & POLLIN) { - if ((n = read(wfd, buf, plen)) < 0) - return; - else if (n == 0) { - if (Nflag) - shutdown(nfd, SHUT_WR); - pfd[1].fd = -1; - pfd[1].events = 0; - } else { - if (atomicio(vwrite, nfd, buf, n) != n) - return; + /* 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) + pfd[POLL_STDIN].fd = -1; + /* read something - poll net out */ + if (stdinbufpos > 0) + pfd[POLL_NETOUT].events = POLLOUT; + /* filled buffer - remove self from polling */ + if (stdinbufpos == BUFSIZE) + pfd[POLL_STDIN].events = 0; + } + /* try to write to network */ + if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) { + ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf, + &stdinbufpos); + if (ret == -1) + pfd[POLL_NETOUT].fd = -1; + /* buffer empty - remove self from polling */ + if (stdinbufpos == 0) + pfd[POLL_NETOUT].events = 0; + /* buffer no longer full - poll stdin again */ + if (stdinbufpos < BUFSIZE) + pfd[POLL_STDIN].events = POLLIN; + } + /* try to read from network */ + if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) { + ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf, + &netinbufpos); + if (ret == -1) + pfd[POLL_NETIN].fd = -1; + /* eof on net in - remove from pfd */ + if (ret == 0) { + shutdown(pfd[POLL_NETIN].fd, SHUT_RD); + pfd[POLL_NETIN].fd = -1; } + /* read something - poll stdout */ + if (netinbufpos > 0) + pfd[POLL_STDOUT].events = POLLOUT; + /* filled buffer - remove self from polling */ + if (netinbufpos == BUFSIZE) + pfd[POLL_NETIN].events = 0; + /* handle telnet */ + if (tflag) + atelnet(pfd[POLL_NETIN].fd, netinbuf, + netinbufpos); + } + /* try to write to stdout */ + if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) { + ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf, + &netinbufpos); + if (ret == -1) + pfd[POLL_STDOUT].fd = -1; + /* buffer empty - remove self from polling */ + if (netinbufpos == 0) + pfd[POLL_STDOUT].events = 0; + /* buffer no longer full - poll net in again */ + if (netinbufpos < BUFSIZE) + pfd[POLL_NETIN].events = POLLIN; + } + + /* stdin gone and queue empty? */ + if (pfd[POLL_STDIN].fd == -1 && stdinbufpos == 0) { + if (pfd[POLL_NETOUT].fd != -1 && Nflag) + shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); + pfd[POLL_NETOUT].fd = -1; + } + /* net in gone and queue empty? */ + if (pfd[POLL_NETIN].fd == -1 && netinbufpos == 0) { + pfd[POLL_STDOUT].fd = -1; } } } +ssize_t +drainbuf(int fd, unsigned char *buf, size_t *bufpos) +{ + 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 (n <= 0) + return n; + /* adjust buffer */ + adjust = *bufpos - n; + if (adjust > 0) + memmove(buf, buf + n, adjust); + *bufpos -= n; + return n; +} + + +ssize_t +fillbuf(int fd, unsigned char *buf, size_t *bufpos) +{ + 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 (n <= 0) + return n; + *bufpos += n; + return n; +} + /* * fdpass() * Pass the connected file descriptor to stdout and exit. @@ -1025,7 +1190,7 @@ udptest(int s) } void -set_common_sockopts(int s) +set_common_sockopts(int s, int af) { int x = 1; @@ -1040,8 +1205,17 @@ set_common_sockopts(int s) err(1, NULL); } if (Tflag != -1) { - if (setsockopt(s, IPPROTO_IP, IP_TOS, - &Tflag, sizeof(Tflag)) == -1) + int proto, option; + + if (af == AF_INET6) { + proto = IPPROTO_IPV6; + option = IPV6_TCLASS; + } else { + proto = IPPROTO_IP; + option = IP_TOS; + } + + if (setsockopt(s, proto, option, &Tflag, sizeof(Tflag)) == -1) err(1, "set IP ToS"); } if (Iflag) {