diff options
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/netcat/atomicio.c | 56 | ||||
-rw-r--r-- | contrib/netcat/nc.1 | 387 | ||||
-rw-r--r-- | contrib/netcat/netcat.c | 802 | ||||
-rw-r--r-- | contrib/netcat/socks.c | 235 |
4 files changed, 1480 insertions, 0 deletions
diff --git a/contrib/netcat/atomicio.c b/contrib/netcat/atomicio.c new file mode 100644 index 0000000..9e73290 --- /dev/null +++ b/contrib/netcat/atomicio.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/uio.h> + +#include <errno.h> +#include <unistd.h> + +ssize_t atomicio(ssize_t (*f)(int, void *, size_t), int fd, void *_s, size_t n); + +/* + * ensure all of data on socket comes through. f==read || f==write + */ +ssize_t +atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) +{ + char *s = _s; + ssize_t res, pos = 0; + + while (n > pos) { + res = (f) (fd, s + pos, n - pos); + switch (res) { + case -1: + if (errno == EINTR || errno == EAGAIN) + continue; + case 0: + return (res); + default: + pos += res; + } + } + return (pos); +} diff --git a/contrib/netcat/nc.1 b/contrib/netcat/nc.1 new file mode 100644 index 0000000..472fa76 --- /dev/null +++ b/contrib/netcat/nc.1 @@ -0,0 +1,387 @@ +.\" $OpenBSD: nc.1,v 1.36 2005/01/07 10:11:31 jmc Exp $ +.\" +.\" Copyright (c) 1996 David Sacerdote +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (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 June 25, 2001 +.Dt NC 1 +.Os +.Sh NAME +.Nm nc +.Nd arbitrary TCP and UDP connections and listens +.Sh SYNOPSIS +.Nm nc +.Bk -words +.Op Fl 46DdhklnrStUuvz +.Op Fl i Ar interval +.Op Fl p Ar source_port +.Op Fl s Ar source_ip_address +.Op Fl w Ar timeout +.Op Fl X Ar proxy_protocol +.Oo Xo +.Fl x Ar proxy_address Ns Oo : Ns +.Ar port Oc Oc +.Xc +.Op Ar hostname +.Op Ar port Ns Bq Ar s +.Ek +.Sh DESCRIPTION +The +.Nm +(or +.Nm netcat ) +utility is used for just about anything under the sun involving TCP +or UDP. +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. +Unlike +.Xr telnet 1 , +.Nm +scripts nicely, and separates error messages onto standard error instead +of sending them to standard output, as +.Xr telnet 1 +does with some. +.Pp +Common uses include: +.Pp +.Bl -bullet -offset indent -compact +.It +simple TCP proxies +.It +shell-script based HTTP clients and servers +.It +network daemon testing +.It +a SOCKS or HTTP ProxyCommand for +.Xr ssh 1 +.It +and much, much more +.El +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl 4 +Forces +.Nm +to use IPv4 addresses only. +.It Fl 6 +Forces +.Nm +to use IPv6 addresses only. +.It Fl D +Enable debugging on the socket. +.It Fl d +Do not attempt to read from stdin. +.It Fl h +Prints out +.Nm +help. +.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 +Forces +.Nm +to stay listening for another connection after its current connection +is completed. +It is an error to use this option without the +.Fl l +option. +.It Fl l +Used to specify that +.Nm +should listen for an incoming connection rather than initiate a +connection to a remote host. +It is an error to use this option in conjunction with the +.Fl p , +.Fl s , +or +.Fl z +options. +Additionally, any timeouts specified with the +.Fl w +option are ignored. +.It Fl n +Do not do any DNS or service lookups on any specified addresses, +hostnames or ports. +.It Fl p Ar source_port +Specifies the source port +.Nm +should use, subject to privilege restrictions and availability. +It is an error to use this option in conjunction with the +.Fl l +option. +.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 +assigns them. +.It Fl S +Enables the RFC 2385 TCP MD5 signature option. +.It Fl s Ar source_ip_address +Specifies the IP of the interface which is used to send the packets. +It is an error to use this option in conjunction with the +.Fl l +option. +.It Fl t +Causes +.Nm +to send RFC 854 DON'T and WON'T responses to RFC 854 DO and WILL requests. +This makes it possible to use +.Nm +to script telnet sessions. +.It Fl U +Specifies to use Unix Domain Sockets. +.It Fl u +Use UDP instead of the default option of TCP. +.It Fl v +Have +.Nm +give more verbose output. +.It Fl w Ar timeout +If a connection and stdin are idle for more than +.Ar timeout +seconds, then the connection is silently closed. +The +.Fl w +flag has no effect on the +.Fl l +option, i.e.\& +.Nm +will listen forever for a connection, with or without the +.Fl w +flag. +The default is no timeout. +.It Fl X Ar proxy_version +Requests that +.Nm +should use the specified protocol when talking to the proxy server. +Supported protocols are +.Dq 4 +(SOCKS v.4), +.Dq 5 +(SOCKS v.5) +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 +Requests that +.Nm +should connect to +.Ar hostname +using a proxy at +.Ar proxy_address +and +.Ar port . +If +.Ar port +is not specified, the well-known port for the proxy protocol is used (1080 +for SOCKS, 3128 for HTTPS). +.It Fl z +Specifies that +.Nm +should just scan for listening daemons, without sending any data to them. +It is an error to use this option in conjunction with the +.Fl l +option. +.El +.Pp +.Ar hostname +can be a numerical IP address or a symbolic hostname +(unless the +.Fl n +option is given). +In general, a hostname must be specified, +unless the +.Fl l +option is given +(in which case the local host is used). +.Pp +.Ar port Ns Op Ar s +can be single integers or ranges. +Ranges are in the form nn-mm. +In general, +a destination port must be specified, +unless the +.Fl U +option is given +(in which case a socket must be specified). +.Sh CLIENT/SERVER MODEL +It is quite simple to build a very basic client/server model using +.Nm . +On one console, start +.Nm +listening on a specific port for a connection. +For example: +.Pp +.Dl $ nc -l 1234 +.Pp +.Nm +is now listening on port 1234 for a connection. +On a second console +.Pq or a second machine , +connect to the machine and port being listened on: +.Pp +.Dl $ nc 127.0.0.1 1234 +.Pp +There should now be a connection between the ports. +Anything typed at the second console will be concatenated to the first, +and vice-versa. +After the connection has been set up, +.Nm +does not really care which side is being used as a +.Sq server +and which side is being used as a +.Sq client . +The connection may be terminated using an +.Dv EOF +.Pq Sq ^D . +.Sh DATA TRANSFER +The example in the previous section can be expanded to build a +basic data transfer model. +Any information input into one end of the connection will be output +to the other end, and input and output can be easily captured in order to +emulate file transfer. +.Pp +Start by using +.Nm +to listen on a specific port, with output captured into a file: +.Pp +.Dl $ nc -l 1234 \*(Gt filename.out +.Pp +Using a second machine, connect to the listening +.Nm +process, feeding it the file which is to be transferred: +.Pp +.Dl $ nc host.example.com 1234 \*(Lt filename.in +.Pp +After the file has been transferred, the connection will close automatically. +.Sh TALKING TO SERVERS +It is sometimes useful to talk to servers +.Dq by hand +rather than through a user interface. +It can aid in troubleshooting, +when it might be necessary to verify what data a server is sending +in response to commands issued by the client. +For example, to retrieve the home page of a web site: +.Pp +.Dl $ echo \&"GET\&" | nc host.example.com 80 +.Pp +Note that this also displays the headers sent by the web server. +They can be filtered, using a tool such as +.Xr sed 1 , +if necessary. +.Pp +More complicated examples can be built up when the user knows the format +of requests required by the server. +As another example, an email may be submitted to an SMTP server using: +.Bd -literal -offset indent +$ nc localhost 25 \*(Lt\*(Lt EOF +HELO host.example.com +MAIL FROM: \*(Ltuser@host.example.com\*(Gt +RCPT TO: \*(Ltuser2@host.example.com\*(Gt +DATA +Body of email. +\&. +QUIT +EOF +.Ed +.Sh PORT SCANNING +It may be useful to know which ports are open and running services on +a target machine. +The +.Fl z +flag can be used to tell +.Nm +not to initiate a connection, +together with the +.Fl v +.Pq verbose +flag, +to report open ports. +For example: +.Bd -literal -offset indent +$ nc -vz host.example.com 20-30 +Connection to host.example.com 22 port [tcp/ssh] succeeded! +Connection to host.example.com 25 port [tcp/smtp] succeeded! +.Ed +.Pp +The port range was specified to limit the search to ports 20 \- 30. +.Pp +Alternatively, it might be useful to know which server software +is running, and which versions. +This information is often contained within the greeting banners. +In order to retrieve these, it is necessary to first make a connection, +and then break the connection when the banner has been retrieved. +This can be accomplished by specifying a small timeout with the +.Fl w +flag, or perhaps by issuing a +.Qq Dv QUIT +command to the server: +.Bd -literal -offset indent +$ echo "QUIT" | nc host.example.com 20-30 +SSH-1.99-OpenSSH_3.6.1p2 +Protocol mismatch. +220 host.example.com IMS SMTP Receiver Version 0.84 Ready +.Ed +.Sh EXAMPLES +Open a TCP connection to port 42 of hostname, using port 31337 as +the source port, with a timeout of 5 seconds: +.Pp +.Dl $ nc -p 31337 -w 5 hostname 42 +.Pp +Open a UDP connection to port 53 of hostname: +.Pp +.Dl $ nc -u hostname 53 +.Pp +Open a TCP connection to port 42 of example.host using 10.1.2.3 as the +IP for the local end of the connection: +.Pp +.Dl $ nc -s 10.1.2.3 example.host 42 +.Pp +Send UDP packets to ports 20-30 of example.host, and report which ones +responded with an ICMP packet after three seconds: +.Pp +.Dl $ nc -uvz -w 3 hostname 20-30 +.Pp +Create and listen on a Unix Domain Socket: +.Pp +.Dl $ nc -lU /var/tmp/dsocket +.Pp +Connect to port 42 of hostname via an HTTP proxy at 10.2.3.4, port 8080: +.Pp +.Dl $ nc -x10.2.3.4:8080 -Xconnect hostname 42 +.Sh SEE ALSO +.Xr cat 1 +.Sh AUTHORS +Original implementation by *Hobbit* +.Aq hobbit@avian.org . +.br +Rewritten with IPv6 support by +.An Eric Jackson Aq ericj@monkey.org . diff --git a/contrib/netcat/netcat.c b/contrib/netcat/netcat.c new file mode 100644 index 0000000..3c610b9 --- /dev/null +++ b/contrib/netcat/netcat.c @@ -0,0 +1,802 @@ +/* $OpenBSD: netcat.c,v 1.76 2004/12/10 16:51:31 hshoexer Exp $ */ +/* + * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Re-written nc(1) for OpenBSD. Original implementation by + * *Hobbit* <hobbit@avian.org>. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/un.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/telnet.h> + +#include <err.h> +#include <errno.h> +#include <netdb.h> +#include <poll.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.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 + +/* Command Line Options */ +int dflag; /* detached, no stdin */ +int iflag; /* Interval Flag */ +int kflag; /* More than one connect */ +int lflag; /* Bind to local port */ +int nflag; /* Don't do name look up */ +char *pflag; /* Localport flag */ +int rflag; /* Random ports flag */ +char *sflag; /* Source Address */ +int tflag; /* Telnet Emulation */ +int uflag; /* UDP - Default to TCP */ +int vflag; /* Verbosity */ +int xflag; /* Socks proxy */ +int zflag; /* Port Scan Flag */ +int Dflag; /* sodebug */ +int Sflag; /* TCP MD5 signature option */ + +int timeout = -1; +int family = AF_UNSPEC; +char *portlist[PORT_MAX+1]; + +ssize_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t); +void atelnet(int, unsigned char *, unsigned int); +void build_ports(char *); +void help(void); +int local_listen(char *, char *, struct addrinfo); +void readwrite(int); +int remote_connect(char *, char *, struct addrinfo); +int socks_connect(char *, char *, struct addrinfo, char *, char *, + struct addrinfo, int); +int udptest(int); +int unix_connect(char *); +int unix_listen(char *); +void usage(int); + +int +main(int argc, char *argv[]) +{ + int ch, s, ret, socksv; + char *host, *uport, *endp; + struct addrinfo hints; + struct servent *sv; + socklen_t len; + struct sockaddr_storage cliaddr; + char *proxy; + char *proxyhost = "", *proxyport = NULL; + struct addrinfo proxyhints; + + ret = 1; + s = 0; + socksv = 5; + host = NULL; + uport = NULL; + endp = NULL; + sv = NULL; + + while ((ch = getopt(argc, argv, "46Ddhi:klnp:rSs:tUuvw:X:x:z")) != -1) { + switch (ch) { + case '4': + family = AF_INET; + break; + case '6': + family = AF_INET6; + break; + case 'U': + family = AF_UNIX; + break; + case 'X': + if (strcasecmp(optarg, "connect") == 0) + socksv = -1; /* HTTP proxy CONNECT */ + else if (strcmp(optarg, "4") == 0) + socksv = 4; /* SOCKS v.4 */ + else if (strcmp(optarg, "5") == 0) + socksv = 5; /* SOCKS v.5 */ + else + errx(1, "unsupported proxy protocol"); + break; + case 'd': + dflag = 1; + break; + case 'h': + help(); + break; + case 'i': + iflag = (int)strtoul(optarg, &endp, 10); + if (iflag < 0 || *endp != '\0') + errx(1, "interval cannot be negative"); + break; + case 'k': + kflag = 1; + break; + case 'l': + lflag = 1; + break; + case 'n': + nflag = 1; + break; + case 'p': + pflag = optarg; + break; + case 'r': + rflag = 1; + break; + case 's': + sflag = optarg; + break; + case 't': + tflag = 1; + break; + case 'u': + uflag = 1; + break; + case 'v': + vflag = 1; + break; + case 'w': + timeout = (int)strtoul(optarg, &endp, 10); + if (timeout < 0 || *endp != '\0') + errx(1, "timeout cannot be negative"); + if (timeout >= (INT_MAX / 1000)) + errx(1, "timeout too large"); + timeout *= 1000; + break; + case 'x': + xflag = 1; + if ((proxy = strdup(optarg)) == NULL) + err(1, NULL); + break; + case 'z': + zflag = 1; + break; + case 'D': + Dflag = 1; + break; + case 'S': + Sflag = 1; + break; + default: + usage(1); + } + } + argc -= optind; + argv += optind; + + /* 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]) { + if (!lflag) + usage(1); + uport = argv[0]; + host = NULL; + } else if (argv[0] && argv[1]) { + host = argv[0]; + uport = argv[1]; + } else + usage(1); + + if (lflag && sflag) + errx(1, "cannot use -s and -l"); + if (lflag && pflag) + errx(1, "cannot use -p and -l"); + if (lflag && zflag) + errx(1, "cannot use -z and -l"); + if (!lflag && kflag) + errx(1, "must use -l with -k"); + + /* Initialize addrinfo structure. */ + if (family != AF_UNIX) { + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = family; + hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; + hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; + if (nflag) + hints.ai_flags |= AI_NUMERICHOST; + } + + if (xflag) { + if (uflag) + errx(1, "no proxy support for UDP mode"); + + if (lflag) + errx(1, "no proxy support for listen"); + + 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; + + memset(&proxyhints, 0, sizeof(struct addrinfo)); + proxyhints.ai_family = family; + proxyhints.ai_socktype = SOCK_STREAM; + proxyhints.ai_protocol = IPPROTO_TCP; + if (nflag) + proxyhints.ai_flags |= AI_NUMERICHOST; + } + + if (lflag) { + int connfd; + ret = 0; + + if (family == AF_UNIX) + s = unix_listen(host); + + /* Allow only one connection at a time, but stay alive. */ + for (;;) { + if (family != AF_UNIX) + s = local_listen(host, uport, hints); + if (s < 0) + err(1, NULL); + /* + * For UDP, we will use recvfrom() initially + * to wait for a caller, then use the regular + * functions to talk to the caller. + */ + if (uflag) { + int rv; + char buf[1024]; + struct sockaddr_storage z; + + len = sizeof(z); + rv = recvfrom(s, buf, sizeof(buf), MSG_PEEK, + (struct sockaddr *)&z, &len); + if (rv < 0) + err(1, "recvfrom"); + + rv = connect(s, (struct sockaddr *)&z, len); + if (rv < 0) + err(1, "connect"); + + connfd = s; + } else { + connfd = accept(s, (struct sockaddr *)&cliaddr, + &len); + } + + readwrite(connfd); + close(connfd); + if (family != AF_UNIX) + close(s); + + if (!kflag) + break; + } + } else if (family == AF_UNIX) { + ret = 0; + + if ((s = unix_connect(host)) > 0 && !zflag) { + readwrite(s); + close(s); + } else + ret = 1; + + exit(ret); + + } else { + int i = 0; + + /* Construct the portlist[] array. */ + build_ports(uport); + + /* Cycle through portlist, connecting to each port. */ + for (i = 0; portlist[i] != NULL; i++) { + if (s) + close(s); + + if (xflag) + s = socks_connect(host, portlist[i], hints, + proxyhost, proxyport, proxyhints, socksv); + else + s = remote_connect(host, portlist[i], hints); + + if (s < 0) + continue; + + ret = 0; + if (vflag || zflag) { + /* For UDP, make sure we are connected. */ + if (uflag) { + if (udptest(s) == -1) { + ret = 1; + continue; + } + } + + /* Don't look up port if -n. */ + if (nflag) + sv = NULL; + else { + sv = getservbyport( + ntohs(atoi(portlist[i])), + uflag ? "udp" : "tcp"); + } + + printf("Connection to %s %s port [%s/%s] succeeded!\n", + host, portlist[i], uflag ? "udp" : "tcp", + sv ? sv->s_name : "*"); + } + if (!zflag) + readwrite(s); + } + } + + if (s) + close(s); + + exit(ret); +} + +/* + * unix_connect() + * Returns a socket connected to a local unix socket. Returns -1 on failure. + */ +int +unix_connect(char *path) +{ + struct sockaddr_un sun; + int s; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return (-1); + (void)fcntl(s, F_SETFD, 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 (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) { + close(s); + return (-1); + } + return (s); + +} + +/* + * unix_listen() + * Create a unix domain socket, and listen on it. + */ +int +unix_listen(char *path) +{ + struct sockaddr_un sun; + int s; + + /* Create unix domain socket. */ + if ((s = socket(AF_UNIX, 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); + } + + if (listen(s, 5) < 0) { + close(s); + return (-1); + } + return (s); +} + +/* + * remote_connect() + * Returns a socket connected to a remote host. Properly binds to a local + * port or source address if needed. Returns -1 on failure. + */ +int +remote_connect(char *host, char *port, struct addrinfo hints) +{ + struct addrinfo *res, *res0; + int s, error, x = 1; + + if ((error = getaddrinfo(host, port, &hints, &res))) + errx(1, "getaddrinfo: %s", gai_strerror(error)); + + res0 = res; + do { + if ((s = socket(res0->ai_family, res0->ai_socktype, + res0->ai_protocol)) < 0) + continue; + + /* Bind to a local port or source address if specified. */ + if (sflag || pflag) { + struct addrinfo ahints, *ares; + + if (!(sflag && pflag)) { + if (!sflag) + sflag = NULL; + else + pflag = NULL; + } + + memset(&ahints, 0, sizeof(struct addrinfo)); + ahints.ai_family = res0->ai_family; + ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; + ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; + ahints.ai_flags = AI_PASSIVE; + if ((error = getaddrinfo(sflag, pflag, &ahints, &ares))) + errx(1, "getaddrinfo: %s", gai_strerror(error)); + + if (bind(s, (struct sockaddr *)ares->ai_addr, + ares->ai_addrlen) < 0) + errx(1, "bind failed: %s", strerror(errno)); + freeaddrinfo(ares); + } + if (Sflag) { + if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG, + &x, sizeof(x)) == -1) + err(1, NULL); + } + if (Dflag) { + if (setsockopt(s, SOL_SOCKET, SO_DEBUG, + &x, sizeof(x)) == -1) + err(1, NULL); + } + + if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0) + break; + else if (vflag) + warn("connect to %s port %s (%s) failed", host, port, + uflag ? "udp" : "tcp"); + + close(s); + s = -1; + } while ((res0 = res0->ai_next) != NULL); + + freeaddrinfo(res); + + return (s); +} + +/* + * local_listen() + * Returns a socket listening on a local port, binds to specified source + * address. Returns -1 on failure. + */ +int +local_listen(char *host, char *port, struct addrinfo hints) +{ + struct addrinfo *res, *res0; + int s, ret, x = 1; + int error; + + /* Allow nodename to be null. */ + hints.ai_flags |= AI_PASSIVE; + + /* + * In the case of binding to a wildcard address + * default to binding to an ipv4 address. + */ + if (host == NULL && hints.ai_family == AF_UNSPEC) + hints.ai_family = AF_INET; + + if ((error = getaddrinfo(host, port, &hints, &res))) + errx(1, "getaddrinfo: %s", gai_strerror(error)); + + res0 = res; + do { + if ((s = socket(res0->ai_family, res0->ai_socktype, + res0->ai_protocol)) == 0) + continue; + + ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x)); + if (ret == -1) + err(1, NULL); + if (Sflag) { + ret = setsockopt(s, IPPROTO_TCP, TCP_MD5SIG, + &x, sizeof(x)); + if (ret == -1) + err(1, NULL); + } + if (Dflag) { + if (setsockopt(s, SOL_SOCKET, SO_DEBUG, + &x, sizeof(x)) == -1) + err(1, NULL); + } + + if (bind(s, (struct sockaddr *)res0->ai_addr, + res0->ai_addrlen) == 0) + break; + + close(s); + s = -1; + } while ((res0 = res0->ai_next) != NULL); + + if (!uflag && s != -1) { + if (listen(s, 1) < 0) + err(1, "listen"); + } + + freeaddrinfo(res); + + return (s); +} + +/* + * readwrite() + * Loop that polls on the network file descriptor and stdin. + */ +void +readwrite(int nfd) +{ + struct pollfd pfd[2]; + unsigned char buf[BUFSIZ]; + int wfd = fileno(stdin), n; + int lfd = fileno(stdout); + + /* Setup Network FD */ + pfd[0].fd = nfd; + pfd[0].events = POLLIN; + + /* Set up STDIN FD. */ + pfd[1].fd = wfd; + pfd[1].events = POLLIN; + + while (pfd[0].fd != -1) { + if (iflag) + sleep(iflag); + + if ((n = poll(pfd, 2 - dflag, timeout)) < 0) { + close(nfd); + err(1, "Polling Error"); + } + + if (n == 0) + return; + + if (pfd[0].revents & POLLIN) { + if ((n = read(nfd, buf, sizeof(buf))) < 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((ssize_t (*)(int, void *, size_t))write, + lfd, buf, n) != n) + return; + } + } + + if (!dflag && pfd[1].revents & POLLIN) { + if ((n = read(wfd, buf, sizeof(buf))) < 0) + return; + else if (n == 0) { + shutdown(nfd, SHUT_WR); + pfd[1].fd = -1; + pfd[1].events = 0; + } else { + if (atomicio((ssize_t (*)(int, void *, size_t))write, + nfd, buf, n) != n) + return; + } + } + } +} + +/* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */ +void +atelnet(int nfd, unsigned char *buf, unsigned int size) +{ + unsigned char *p, *end; + unsigned char obuf[4]; + + end = buf + size; + obuf[0] = '\0'; + + for (p = buf; p < end; p++) { + if (*p != IAC) + break; + + obuf[0] = IAC; + p++; + if ((*p == WILL) || (*p == WONT)) + obuf[1] = DONT; + if ((*p == DO) || (*p == DONT)) + obuf[1] = WONT; + if (obuf) { + p++; + obuf[2] = *p; + obuf[3] = '\0'; + if (atomicio((ssize_t (*)(int, void *, size_t))write, + nfd, obuf, 3) != 3) + warnx("Write Error!"); + obuf[0] = '\0'; + } + } +} + +/* + * build_ports() + * Build an array or ports in portlist[], listing each port + * that we should try to connect to. + */ +void +build_ports(char *p) +{ + char *n, *endp; + int hi, lo, cp; + int x = 0; + + if ((n = strchr(p, '-')) != NULL) { + if (lflag) + errx(1, "Cannot use -l with multiple ports!"); + + *n = '\0'; + n++; + + /* Make sure the ports are in order: lowest->highest. */ + hi = (int)strtoul(n, &endp, 10); + if (hi <= 0 || hi > PORT_MAX || *endp != '\0') + errx(1, "port range not valid"); + lo = (int)strtoul(p, &endp, 10); + if (lo <= 0 || lo > PORT_MAX || *endp != '\0') + errx(1, "port range not valid"); + + if (lo > hi) { + cp = hi; + hi = lo; + 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. */ + 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; + } + } + } else { + hi = (int)strtoul(p, &endp, 10); + if (hi <= 0 || hi > PORT_MAX || *endp != '\0') + errx(1, "port range not valid"); + portlist[0] = calloc(1, PORT_MAX_LEN); + if (portlist[0] == NULL) + err(1, NULL); + portlist[0] = p; + } +} + +/* + * udptest() + * Do a few writes to see if the UDP port is there. + * XXX - Better way of doing this? Doesn't work for IPv6. + * Also fails after around 100 ports checked. + */ +int +udptest(int s) +{ + int i, ret; + + for (i = 0; i <= 3; i++) { + if (write(s, "X", 1) == 1) + ret = 1; + else + ret = -1; + } + return (ret); +} + +void +help(void) +{ + usage(0); + fprintf(stderr, "\tCommand Summary:\n\ + \t-4 Use IPv4\n\ + \t-6 Use IPv6\n\ + \t-D Enable the debug socket option\n\ + \t-d Detach from stdin\n\ + \t-h This help text\n\ + \t-i secs\t Delay interval for lines sent, ports scanned\n\ + \t-k Keep inbound sockets open for multiple connects\n\ + \t-l Listen mode, for inbound connects\n\ + \t-n Suppress name/port resolutions\n\ + \t-p port\t Specify local port for remote connects\n\ + \t-r Randomize remote ports\n\ + \t-S Enable the TCP MD5 signature option\n\ + \t-s addr\t Local source address\n\ + \t-t Answer TELNET negotiation\n\ + \t-U Use UNIX domain socket\n\ + \t-u UDP mode\n\ + \t-v Verbose\n\ + \t-w secs\t 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 Zero-I/O mode [used for scanning]\n\ + Port numbers can be individual or ranges: lo-hi [inclusive]\n"); + exit(1); +} + +void +usage(int ret) +{ + fprintf(stderr, "usage: nc [-46DdhklnrStUuvz] [-i interval] [-p source_port]\n"); + fprintf(stderr, "\t [-s source_ip_address] [-w timeout] [-X proxy_version]\n"); + fprintf(stderr, "\t [-x proxy_address[:port]] [hostname] [port[s]]\n"); + if (ret) + exit(1); +} diff --git a/contrib/netcat/socks.c b/contrib/netcat/socks.c new file mode 100644 index 0000000..e7d35b6 --- /dev/null +++ b/contrib/netcat/socks.c @@ -0,0 +1,235 @@ +/* $OpenBSD: socks.c,v 1.9 2004/10/17 03:13:55 djm Exp $ */ + +/* + * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <err.h> +#include <errno.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define SOCKS_PORT "1080" +#define HTTP_PROXY_PORT "3128" +#define HTTP_MAXHDRS 64 +#define SOCKS_V5 5 +#define SOCKS_V4 4 +#define SOCKS_NOAUTH 0 +#define SOCKS_NOMETHOD 0xff +#define SOCKS_CONNECT 1 +#define SOCKS_IPV4 1 + + +int remote_connect(char *, char *, struct addrinfo); +int socks_connect(char *host, char *port, struct addrinfo hints, + char *proxyhost, char *proxyport, struct addrinfo proxyhints, + int socksv); + +static in_addr_t +decode_addr(const char *s) +{ + struct hostent *hp = gethostbyname (s); + struct in_addr retval; + + if (hp) + return *(in_addr_t *)hp->h_addr_list[0]; + if (inet_aton (s, &retval)) + return retval.s_addr; + errx (1, "cannot decode address \"%s\"", s); +} + +static in_port_t +decode_port(const char *s) +{ + struct servent *sp; + in_port_t port; + char *p; + + port = strtol (s, &p, 10); + if (s == p) { + sp = getservbyname (s, "tcp"); + if (sp) + return sp->s_port; + } + if (*s != '\0' && *p == '\0') + return htons (port); + errx (1, "cannot decode port \"%s\"", s); +} + +static int +proxy_read_line(int fd, char *buf, int bufsz) +{ + int r, off; + + for(off = 0;;) { + if (off >= bufsz) + errx(1, "proxy read too long"); + if ((r = read(fd, buf + off, 1)) <= 0) { + if (r == -1 && errno == EINTR) + continue; + err(1, "proxy read"); + } + /* Skip CR */ + if (buf[off] == '\r') + continue; + if (buf[off] == '\n') { + buf[off] = '\0'; + break; + } + off++; + } + return (off); +} + +int +socks_connect(char *host, char *port, struct addrinfo hints, + char *proxyhost, char *proxyport, struct addrinfo proxyhints, + int socksv) +{ + int proxyfd, r; + unsigned char buf[1024]; + ssize_t cnt; + in_addr_t serveraddr; + in_port_t serverport; + + if (proxyport == NULL) + proxyport = (socksv == -1) ? HTTP_PROXY_PORT : SOCKS_PORT; + + proxyfd = remote_connect(proxyhost, proxyport, proxyhints); + + if (proxyfd < 0) + return -1; + + serveraddr = decode_addr (host); + serverport = decode_port (port); + + if (socksv == 5) { + /* Version 5, one method: no authentication */ + buf[0] = SOCKS_V5; + buf[1] = 1; + buf[2] = SOCKS_NOAUTH; + cnt = write (proxyfd, buf, 3); + if (cnt == -1) + err (1, "write failed"); + if (cnt != 3) + errx (1, "short write, %d (expected 3)", cnt); + + read (proxyfd, buf, 2); + if (buf[1] == SOCKS_NOMETHOD) + errx (1, "authentication method negotiation failed"); + + /* Version 5, connect: IPv4 address */ + buf[0] = SOCKS_V5; + buf[1] = SOCKS_CONNECT; + buf[2] = 0; + buf[3] = SOCKS_IPV4; + memcpy (buf + 4, &serveraddr, sizeof serveraddr); + memcpy (buf + 8, &serverport, sizeof serverport); + + /* XXX Handle short writes better */ + cnt = write (proxyfd, buf, 10); + if (cnt == -1) + err (1, "write failed"); + if (cnt != 10) + errx (1, "short write, %d (expected 10)", cnt); + + /* XXX Handle short reads better */ + cnt = read (proxyfd, buf, sizeof buf); + if (cnt == -1) + err (1, "read failed"); + if (cnt != 10) + errx (1, "unexpected reply size %d (expected 10)", cnt); + if (buf[1] != 0) + errx (1, "connection failed, SOCKS error %d", buf[1]); + } else if (socksv == 4) { + /* Version 4 */ + buf[0] = SOCKS_V4; + buf[1] = SOCKS_CONNECT; /* connect */ + memcpy (buf + 2, &serverport, sizeof serverport); + memcpy (buf + 4, &serveraddr, sizeof serveraddr); + buf[8] = 0; /* empty username */ + + cnt = write (proxyfd, buf, 9); + if (cnt == -1) + err (1, "write failed"); + if (cnt != 9) + errx (1, "short write, %d (expected 9)", cnt); + + /* XXX Handle short reads better */ + cnt = read (proxyfd, buf, 8); + if (cnt == -1) + err (1, "read failed"); + if (cnt != 8) + errx (1, "unexpected reply size %d (expected 8)", cnt); + if (buf[1] != 90) + errx (1, "connection failed, SOCKS error %d", buf[1]); + } else if (socksv == -1) { + /* HTTP proxy CONNECT */ + + /* Disallow bad chars in hostname */ + if (strcspn(host, "\r\n\t []:") != strlen(host)) + errx (1, "Invalid hostname"); + + /* Try to be sane about numeric IPv6 addresses */ + if (strchr(host, ':') != NULL) { + r = snprintf(buf, sizeof(buf), + "CONNECT [%s]:%d HTTP/1.0\r\n\r\n", + host, ntohs(serverport)); + } else { + r = snprintf(buf, sizeof(buf), + "CONNECT %s:%d HTTP/1.0\r\n\r\n", + host, ntohs(serverport)); + } + if (r == -1 || r >= sizeof(buf)) + errx (1, "hostname too long"); + r = strlen(buf); + + /* XXX atomicio */ + cnt = write (proxyfd, buf, r); + if (cnt == -1) + err (1, "write failed"); + if (cnt != r) + errx (1, "short write, %d (expected %d)", cnt, r); + + /* Read reply */ + for (r = 0; r < HTTP_MAXHDRS; r++) { + proxy_read_line(proxyfd, buf, sizeof(buf)); + if (r == 0 && strncmp(buf, "HTTP/1.0 200 ", 12) != 0) + errx (1, "Proxy error: \"%s\"", buf); + /* Discard headers until we hit an empty line */ + if (*buf == '\0') + break; + } + } else + errx (1, "Unknown proxy protocol %d", socksv); + + return proxyfd; +} |