From c98f06c929bb8c8a81b4254bebab2fb08a98b6ce Mon Sep 17 00:00:00 2001 From: Xin LI Date: Wed, 11 May 2011 18:57:17 +0000 Subject: [PATCH] Import nc from OpenBSD 4.9. --- atomicio.c | 4 +- nc.1 | 47 +++++++++++++++++------- netcat.c | 106 +++++++++++++++++++++++++++++++++++++---------------- socks.c | 22 +++++++++-- 4 files changed, 129 insertions(+), 50 deletions(-) diff --git a/atomicio.c b/atomicio.c index e9d98b3561e8..feb6f194409e 100644 --- a/atomicio.c +++ b/atomicio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: atomicio.c,v 1.9 2007/09/07 14:50:44 tobias Exp $ */ +/* $OpenBSD: atomicio.c,v 1.10 2011/01/08 00:47:19 jeremy Exp $ */ /* * Copyright (c) 2006 Damien Miller. All rights reserved. * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. @@ -53,7 +53,7 @@ atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) case -1: if (errno == EINTR) continue; - if (errno == EAGAIN) { + if ((errno == EAGAIN) || (errno == ENOBUFS)) { (void)poll(&pfd, 1, -1); continue; } diff --git a/nc.1 b/nc.1 index 05b46f8f74df..27040065dc23 100644 --- a/nc.1 +++ b/nc.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: nc.1,v 1.55 2010/07/25 07:51:39 guenther Exp $ +.\" $OpenBSD: nc.1,v 1.57 2011/01/09 22:16:46 jeremy 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 3 2010 $ +.Dd $Mdocdate: January 8 2011 $ .Dt NC 1 .Os .Sh NAME @@ -40,7 +40,7 @@ .Op Fl O Ar length .Op Fl P Ar proxy_username .Op Fl p Ar source_port -.Op Fl s Ar source_ip_address +.Op Fl s Ar source .Op Fl T Ar ToS .Op Fl V Ar rtable .Op Fl w Ar timeout @@ -49,7 +49,7 @@ .Fl x Ar proxy_address Ns Oo : Ns .Ar port Oc .Xc Oc -.Op Ar hostname +.Op Ar destination .Op Ar port .Ek .Sh DESCRIPTION @@ -57,8 +57,10 @@ The .Nm (or .Nm netcat ) -utility is used for just about anything under the sun involving TCP -or UDP. +utility is used for just about anything under the sun involving TCP, +UDP, or +.Ux Ns -domain +sockets. It can open TCP connections, send UDP packets, listen on arbitrary TCP and UDP ports, do port scanning, and deal with both IPv4 and IPv6. @@ -153,8 +155,12 @@ instead of sequentially within a range or in the order that the system assigns them. .It Fl S Enables the RFC 2385 TCP MD5 signature option. -.It Fl s Ar source_ip_address +.It Fl s Ar source Specifies the IP of the interface which is used to send the packets. +For +.Ux Ns -domain +datagram sockets, specifies the local temporary socket file +to create and use so that datagrams can be received. It is an error to use this option in conjunction with the .Fl l option. @@ -179,6 +185,16 @@ Specifies to use sockets. .It Fl u Use UDP instead of the default option of TCP. +For +.Ux Ns -domain +sockets, use a datagram socket instead of a stream socket. +If a +.Ux Ns -domain +socket is used, a temporary receiving socket is created in +.Pa /tmp +unless the +.Fl s +flag is given. .It Fl V Ar rtable Set the routing table to be used. The default is 0. @@ -220,7 +236,7 @@ If the protocol is not specified, SOCKS version 5 is used. Requests that .Nm should connect to -.Ar hostname +.Ar destination using a proxy at .Ar proxy_address and @@ -238,16 +254,22 @@ It is an error to use this option in conjunction with the option. .El .Pp -.Ar hostname +.Ar destination can be a numerical IP address or a symbolic hostname (unless the .Fl n option is given). -In general, a hostname must be specified, +In general, a destination must be specified, unless the .Fl l option is given (in which case the local host is used). +For +.Ux Ns -domain +sockets, a destination is required and is the socket path to connect to +(or listen on if the +.Fl l +option is given). .Pp .Ar port can be a single integer or a range of ports. @@ -256,8 +278,7 @@ In general, a destination port must be specified, unless the .Fl U -option is given -(in which case a socket must be specified). +option is given. .Sh CLIENT/SERVER MODEL It is quite simple to build a very basic client/server model using .Nm . @@ -390,7 +411,7 @@ IP for the local end of the connection: .Pp Create and listen on a .Ux Ns -domain -socket: +stream socket: .Pp .Dl $ nc -lU /var/tmp/dsocket .Pp diff --git a/netcat.c b/netcat.c index e471182b2ad8..5c81e43e859d 100644 --- a/netcat.c +++ b/netcat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: netcat.c,v 1.98 2010/07/03 04:44:51 guenther Exp $ */ +/* $OpenBSD: netcat.c,v 1.100 2011/01/09 22:16:46 jeremy Exp $ */ /* * Copyright (c) 2001 Eric Jackson * @@ -62,6 +62,7 @@ #define PORT_MAX 65535 #define PORT_MAX_LEN 6 +#define UNIX_DG_TMP_SOCKET_SIZE 19 /* Command Line Options */ int dflag; /* detached, no stdin */ @@ -89,6 +90,7 @@ u_int rtableid; int timeout = -1; int family = AF_UNSPEC; char *portlist[PORT_MAX+1]; +char *unix_dg_tmp_socket; void atelnet(int, unsigned char *, unsigned int); void build_ports(char *); @@ -99,6 +101,7 @@ int remote_connect(const char *, const char *, struct addrinfo); 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_connect(char *); int unix_listen(char *); void set_common_sockopts(int); @@ -117,6 +120,7 @@ main(int argc, char *argv[]) char *proxy; const char *errstr, *proxyhost = "", *proxyport = NULL; struct addrinfo proxyhints; + char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE]; ret = 1; s = 0; @@ -241,8 +245,6 @@ main(int argc, char *argv[]) /* Cruft to make sure options are clean, and used properly. */ if (argv[0] && !argv[1] && family == AF_UNIX) { - if (uflag) - errx(1, "cannot use -u and -U"); host = argv[0]; uport = NULL; } else if (argv[0] && !argv[1]) { @@ -265,6 +267,19 @@ main(int argc, char *argv[]) if (!lflag && kflag) errx(1, "must use -l with -k"); + /* Get name of temporary socket for unix datagram client */ + if ((family == AF_UNIX) && uflag && !lflag) { + if (sflag) { + unix_dg_tmp_socket = sflag; + } else { + strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX", + 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; + } + } + /* Initialize addrinfo structure. */ if (family != AF_UNIX) { memset(&hints, 0, sizeof(struct addrinfo)); @@ -307,8 +322,12 @@ main(int argc, char *argv[]) int connfd; ret = 0; - if (family == AF_UNIX) - s = unix_listen(host); + if (family == AF_UNIX) { + if (uflag) + s = unix_bind(host); + else + s = unix_listen(host); + } /* Allow only one connection at a time, but stay alive. */ for (;;) { @@ -337,17 +356,21 @@ main(int argc, char *argv[]) if (rv < 0) err(1, "connect"); - connfd = s; + readwrite(s); } else { len = sizeof(cliaddr); connfd = accept(s, (struct sockaddr *)&cliaddr, &len); + readwrite(connfd); + close(connfd); } - readwrite(connfd); - close(connfd); if (family != AF_UNIX) close(s); + else if (uflag) { + if (connect(s, NULL, 0) < 0) + err(1, "connect"); + } if (!kflag) break; @@ -361,6 +384,8 @@ main(int argc, char *argv[]) } else ret = 1; + if (uflag) + unlink(unix_dg_tmp_socket); exit(ret); } else { @@ -420,6 +445,38 @@ main(int argc, char *argv[]) exit(ret); } +/* + * unix_bind() + * Returns a unix socket bound to the given path + */ +int +unix_bind(char *path) +{ + struct sockaddr_un sun; + int s; + + /* Create unix domain socket. */ + if ((s = socket(AF_UNIX, uflag ? SOCK_DGRAM : SOCK_STREAM, + 0)) < 0) + return (-1); + + memset(&sun, 0, sizeof(struct sockaddr_un)); + sun.sun_family = AF_UNIX; + + if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= + sizeof(sun.sun_path)) { + close(s); + errno = ENAMETOOLONG; + return (-1); + } + + if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) { + close(s); + return (-1); + } + return (s); +} + /* * unix_connect() * Returns a socket connected to a local unix socket. Returns -1 on failure. @@ -430,8 +487,13 @@ unix_connect(char *path) struct sockaddr_un sun; int s; - if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - return (-1); + if (uflag) { + if ((s = unix_bind(unix_dg_tmp_socket)) < 0) + return (-1); + } else { + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return (-1); + } (void)fcntl(s, F_SETFD, 1); memset(&sun, 0, sizeof(struct sockaddr_un)); @@ -458,28 +520,10 @@ unix_connect(char *path) int unix_listen(char *path) { - struct sockaddr_un sun; int s; - - /* Create unix domain socket. */ - if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + if ((s = unix_bind(path)) < 0) return (-1); - memset(&sun, 0, sizeof(struct sockaddr_un)); - sun.sun_family = AF_UNIX; - - if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= - sizeof(sun.sun_path)) { - close(s); - errno = ENAMETOOLONG; - return (-1); - } - - if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) { - close(s); - return (-1); - } - if (listen(s, 5) < 0) { close(s); return (-1); @@ -886,9 +930,9 @@ usage(int ret) { fprintf(stderr, "usage: nc [-46DdhklnrStUuvz] [-I length] [-i interval] [-O length]\n" - "\t [-P proxy_username] [-p source_port] [-s source_ip_address] [-T ToS]\n" + "\t [-P proxy_username] [-p source_port] [-s source] [-T ToS]\n" "\t [-V rtable] [-w timeout] [-X proxy_protocol]\n" - "\t [-x proxy_address[:port]] [hostname] [port]\n"); + "\t [-x proxy_address[:port]] [destination] [port]\n"); if (ret) exit(1); } diff --git a/socks.c b/socks.c index b38dff741e19..71108d543b38 100644 --- a/socks.c +++ b/socks.c @@ -1,4 +1,4 @@ -/* $OpenBSD: socks.c,v 1.18 2010/04/20 07:26:35 nicm Exp $ */ +/* $OpenBSD: socks.c,v 1.19 2011/02/12 15:54:18 okan Exp $ */ /* * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. @@ -222,11 +222,25 @@ socks_connect(const char *host, const char *port, if (cnt != wlen) err(1, "write failed (%zu/%zu)", cnt, wlen); - cnt = atomicio(read, proxyfd, buf, 10); - if (cnt != 10) - err(1, "read failed (%zu/10)", cnt); + cnt = atomicio(read, proxyfd, buf, 4); + if (cnt != 4) + err(1, "read failed (%zu/4)", cnt); if (buf[1] != 0) errx(1, "connection failed, SOCKS error %d", buf[1]); + switch (buf[3]) { + case SOCKS_IPV4: + cnt = atomicio(read, proxyfd, buf + 4, 6); + if (cnt != 6) + err(1, "read failed (%d/6)", cnt); + break; + case SOCKS_IPV6: + cnt = atomicio(read, proxyfd, buf + 4, 18); + if (cnt != 18) + err(1, "read failed (%d/18)", cnt); + break; + default: + errx(1, "connection failed, unsupported address type"); + } } else if (socksv == 4) { /* This will exit on lookup failure */ decode_addrport(host, port, (struct sockaddr *)&addr,