diff options
Diffstat (limited to 'src/usr.bin/nc')
| -rw-r--r-- | src/usr.bin/nc/Makefile | 6 | ||||
| -rw-r--r-- | src/usr.bin/nc/atomicio.c | 58 | ||||
| -rw-r--r-- | src/usr.bin/nc/nc.1 | 198 | ||||
| -rw-r--r-- | src/usr.bin/nc/netcat.c | 738 | ||||
| -rw-r--r-- | src/usr.bin/nc/socks.c | 171 |
5 files changed, 1171 insertions, 0 deletions
diff --git a/src/usr.bin/nc/Makefile b/src/usr.bin/nc/Makefile new file mode 100644 index 0000000000..150f8295bd --- /dev/null +++ b/src/usr.bin/nc/Makefile | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | # $OpenBSD: Makefile,v 1.6 2001/09/02 18:45:41 jakob Exp $ | ||
| 2 | |||
| 3 | PROG= nc | ||
| 4 | SRCS= netcat.c atomicio.c socks.c | ||
| 5 | |||
| 6 | .include <bsd.prog.mk> | ||
diff --git a/src/usr.bin/nc/atomicio.c b/src/usr.bin/nc/atomicio.c new file mode 100644 index 0000000000..f404eeedd8 --- /dev/null +++ b/src/usr.bin/nc/atomicio.c | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. | ||
| 3 | * All rights reserved. | ||
| 4 | * | ||
| 5 | * Redistribution and use in source and binary forms, with or without | ||
| 6 | * modification, are permitted provided that the following conditions | ||
| 7 | * are met: | ||
| 8 | * 1. Redistributions of source code must retain the above copyright | ||
| 9 | * notice, this list of conditions and the following disclaimer. | ||
| 10 | * 2. Redistributions in binary form must reproduce the above copyright | ||
| 11 | * notice, this list of conditions and the following disclaimer in the | ||
| 12 | * documentation and/or other materials provided with the distribution. | ||
| 13 | * | ||
| 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
| 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
| 16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
| 17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| 18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
| 19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| 20 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| 21 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
| 23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 24 | */ | ||
| 25 | |||
| 26 | #include <sys/types.h> | ||
| 27 | #include <sys/uio.h> | ||
| 28 | |||
| 29 | #include <errno.h> | ||
| 30 | #include <unistd.h> | ||
| 31 | |||
| 32 | /* | ||
| 33 | * ensure all of data on socket comes through. f==read || f==write | ||
| 34 | */ | ||
| 35 | ssize_t | ||
| 36 | atomicio(f, fd, _s, n) | ||
| 37 | ssize_t (*f) (); | ||
| 38 | int fd; | ||
| 39 | void *_s; | ||
| 40 | size_t n; | ||
| 41 | { | ||
| 42 | char *s = _s; | ||
| 43 | ssize_t res, pos = 0; | ||
| 44 | |||
| 45 | while (n > pos) { | ||
| 46 | res = (f) (fd, s + pos, n - pos); | ||
| 47 | switch (res) { | ||
| 48 | case -1: | ||
| 49 | if (errno == EINTR || errno == EAGAIN) | ||
| 50 | continue; | ||
| 51 | case 0: | ||
| 52 | return (res); | ||
| 53 | default: | ||
| 54 | pos += res; | ||
| 55 | } | ||
| 56 | } | ||
| 57 | return (pos); | ||
| 58 | } | ||
diff --git a/src/usr.bin/nc/nc.1 b/src/usr.bin/nc/nc.1 new file mode 100644 index 0000000000..759be26a31 --- /dev/null +++ b/src/usr.bin/nc/nc.1 | |||
| @@ -0,0 +1,198 @@ | |||
| 1 | .\" $OpenBSD: nc.1,v 1.22 2002/02/28 18:05:36 markus Exp $ | ||
| 2 | .\" | ||
| 3 | .\" Copyright (c) 1996 David Sacerdote | ||
| 4 | .\" All rights reserved. | ||
| 5 | .\" | ||
| 6 | .\" Redistribution and use in source and binary forms, with or without | ||
| 7 | .\" modification, are permitted provided that the following conditions | ||
| 8 | .\" are met: | ||
| 9 | .\" 1. Redistributions of source code must retain the above copyright | ||
| 10 | .\" notice, this list of conditions and the following disclaimer. | ||
| 11 | .\" 2. Redistributions in binary form must reproduce the above copyright | ||
| 12 | .\" notice, this list of conditions and the following disclaimer in the | ||
| 13 | .\" documentation and/or other materials provided with the distribution. | ||
| 14 | .\" 3. The name of the author may not be used to endorse or promote products | ||
| 15 | .\" derived from this software without specific prior written permission | ||
| 16 | .\" | ||
| 17 | .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
| 18 | .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
| 19 | .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
| 20 | .\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| 21 | .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
| 22 | .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| 23 | .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| 24 | .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 25 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
| 26 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 27 | .\" | ||
| 28 | .Dd June 25, 2001 | ||
| 29 | .Dt NC 1 | ||
| 30 | .Os | ||
| 31 | .Sh NAME | ||
| 32 | .Nm nc | ||
| 33 | .Nd "arbitrary TCP and UDP connections and listens" | ||
| 34 | .Sh SYNOPSIS | ||
| 35 | .Nm nc | ||
| 36 | .Op Fl 46hklnrtuvzU | ||
| 37 | .Op Fl i Ar interval | ||
| 38 | .Op Fl p Ar source port | ||
| 39 | .Op Fl s Ar source ip address | ||
| 40 | .Op Fl x Ar proxy address Op :port | ||
| 41 | .Op Fl w Ar timeout | ||
| 42 | .Op Fl X Ar socks version | ||
| 43 | .Op Ar hostname | ||
| 44 | .Op Ar port[s] | ||
| 45 | .Sh DESCRIPTION | ||
| 46 | The | ||
| 47 | .Nm | ||
| 48 | (or | ||
| 49 | .Nm netcat ) | ||
| 50 | utility is used for just about anything under the sun involving TCP | ||
| 51 | or UDP. | ||
| 52 | It can open TCP connections, send UDP packets, listen on arbitrary | ||
| 53 | TCP and UDP ports, do port scanning, and deal with both IPv4 and | ||
| 54 | IPv6. | ||
| 55 | Unlike | ||
| 56 | .Xr telnet 1 , | ||
| 57 | .Nm | ||
| 58 | scripts nicely, and separates error messages onto standard error instead | ||
| 59 | of sending them to standard output, as | ||
| 60 | .Xr telnet 1 , | ||
| 61 | does with some. | ||
| 62 | .Pp | ||
| 63 | Destination ports can be single integers or ranges. | ||
| 64 | Ranges are in the form nn-mm. | ||
| 65 | .Pp | ||
| 66 | Common uses include: | ||
| 67 | .Pp | ||
| 68 | .Bl -bullet -offset indent -compact | ||
| 69 | .It | ||
| 70 | simple TCP proxies | ||
| 71 | .It | ||
| 72 | shell\-script based HTTP clients and servers | ||
| 73 | .It | ||
| 74 | network daemon testing | ||
| 75 | .It | ||
| 76 | and much, much more | ||
| 77 | .El | ||
| 78 | .Pp | ||
| 79 | The options are as follows: | ||
| 80 | .Bl -tag -width Ds | ||
| 81 | .It Fl 4 | ||
| 82 | Forces | ||
| 83 | .Nm | ||
| 84 | to use IPv4 addresses only. | ||
| 85 | .It Fl 6 | ||
| 86 | Forces | ||
| 87 | .Nm | ||
| 88 | to use IPv6 addresses only. | ||
| 89 | .It Fl h | ||
| 90 | Prints out | ||
| 91 | .Nm | ||
| 92 | help. | ||
| 93 | .It Fl i Ar interval | ||
| 94 | Specifies a delay time interval between lines of text sent and received. | ||
| 95 | Also causes a delay time between connections to multiple ports. | ||
| 96 | .It Fl k | ||
| 97 | Forces | ||
| 98 | .Nm | ||
| 99 | to stay listening for another connection after its current connection | ||
| 100 | is completed. | ||
| 101 | .It Fl l | ||
| 102 | Used to specify that | ||
| 103 | .Nm | ||
| 104 | should listen for an incoming connection rather than initiate a | ||
| 105 | connection to a remote host. | ||
| 106 | .It Fl n | ||
| 107 | Do not do any DNS or service lookups on any specified addresses, | ||
| 108 | hostnames or ports. | ||
| 109 | .It Fl p Ar port | ||
| 110 | Specifies the source port | ||
| 111 | .Nm | ||
| 112 | should use, subject to privilege restrictions and availability. | ||
| 113 | .It Fl r | ||
| 114 | Specifies that source and/or destination ports should be chosen randomly | ||
| 115 | instead of sequentially within a range or in the order that the system | ||
| 116 | assigns them. | ||
| 117 | .It Fl s Ar hostname/ip address | ||
| 118 | Specifies the IP of the interface which is used to send the packets. | ||
| 119 | .It Fl t | ||
| 120 | Causes | ||
| 121 | .Nm | ||
| 122 | to send RFC854 DON'T and WON'T responses to RFC854 DO and WILL requests. | ||
| 123 | This makes it possible to use | ||
| 124 | .Nm | ||
| 125 | to script telnet sessions. | ||
| 126 | .It Fl u | ||
| 127 | Use UDP instead of the default option of TCP. | ||
| 128 | .It Fl v | ||
| 129 | Have | ||
| 130 | .Nm | ||
| 131 | give more verbose output. | ||
| 132 | .It Fl x Ar proxy address Op :port | ||
| 133 | Requests that | ||
| 134 | .Nm | ||
| 135 | should connect to | ||
| 136 | .Ar hostname | ||
| 137 | using a SOCKS proxy at address and port. | ||
| 138 | If port is not specified, port 1080 is used. | ||
| 139 | .It Fl z | ||
| 140 | Specifies that | ||
| 141 | .Nm | ||
| 142 | should just scan for listening daemons, without sending any data to them. | ||
| 143 | .It Fl U | ||
| 144 | Specifies to use Unix Domain Sockets. | ||
| 145 | .It Fl X Ar version | ||
| 146 | Requests that | ||
| 147 | .Nm | ||
| 148 | should use the specified version of the SOCKS protocol when talking to | ||
| 149 | a SOCKS proxy. | ||
| 150 | If version is not specified, SOCKS version 5 is used. | ||
| 151 | .El | ||
| 152 | .Sh EXAMPLES | ||
| 153 | .Bl -tag -width x | ||
| 154 | .It Li "nc hostname 42" | ||
| 155 | Open a TCP connection to port 42 of hostname. | ||
| 156 | .It Li "nc -p 31337 hostname 42" | ||
| 157 | Open a TCP connection to port 42 of hostname, and use port 31337 as | ||
| 158 | the source port. | ||
| 159 | .It Li "nc -w 5 hostname 42" | ||
| 160 | Open a TCP connection to port 42 of hostname, and timeout after | ||
| 161 | five seconds while attempting to connect. | ||
| 162 | .It Li "nc -u hostname 53" | ||
| 163 | Open a UDP connection to port 53 of hostname. | ||
| 164 | .It Li "nc -s 10.1.2.3 example.host 42" | ||
| 165 | Open a TCP connection to port 42 of example.host using 10.1.2.3 as the | ||
| 166 | IP for the local end of the connection. | ||
| 167 | .It Li "nc -v hostname 42" | ||
| 168 | Open a TCP connection to port 42 of hostname, displaying some | ||
| 169 | diagnostic messages on stderr. | ||
| 170 | .It Li "nc -v -z hostname 20-30" | ||
| 171 | Attempt to open TCP connections to ports 20 through 30 of | ||
| 172 | hostname, and report which ones | ||
| 173 | .Nm | ||
| 174 | was able to connect to. | ||
| 175 | .It Li "nc -v -u -z -w 3 hostname 20-30" | ||
| 176 | Send UDP packets to ports 20-30 of example.host, and report which ones | ||
| 177 | did not respond with an ICMP packet after three seconds. | ||
| 178 | .It Li "nc -l 3000" | ||
| 179 | Listen on TCP port 3000, and once there is a connection, send stdin to | ||
| 180 | the remote host, and send data from the remote host to stdout. | ||
| 181 | .It Li "echo foobar | nc hostname 1000" | ||
| 182 | Connect to port 1000 of hostname, send the string "foobar" | ||
| 183 | followed by a newline, and move data from port 1000 of hostname to | ||
| 184 | stdout until hostname closes the connection. | ||
| 185 | .It Li "nc -U /var/tmp/dsocket" | ||
| 186 | Connect to a Unix Domain Socket. | ||
| 187 | .It Li "nc -lU /var/tmp/dsocket" | ||
| 188 | Create and listen on a Unix Domain Socket. | ||
| 189 | .El | ||
| 190 | .Sh SEE ALSO | ||
| 191 | .Xr cat 1 , | ||
| 192 | .Xr telnet 1 | ||
| 193 | .Sh AUTHORS | ||
| 194 | Original implementation by *Hobbit* | ||
| 195 | .Aq hobbit@avian.org . | ||
| 196 | .Pp | ||
| 197 | Rewritten with IPv6 support by Eric Jackson | ||
| 198 | .Aq ericj@monkey.org . | ||
diff --git a/src/usr.bin/nc/netcat.c b/src/usr.bin/nc/netcat.c new file mode 100644 index 0000000000..9e6acc9f6d --- /dev/null +++ b/src/usr.bin/nc/netcat.c | |||
| @@ -0,0 +1,738 @@ | |||
| 1 | /* $OpenBSD: netcat.c,v 1.52 2002/07/04 04:42:25 vincent Exp $ */ | ||
| 2 | /* | ||
| 3 | * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> | ||
| 4 | * | ||
| 5 | * Redistribution and use in source and binary forms, with or without | ||
| 6 | * modification, are permitted provided that the following conditions | ||
| 7 | * are met: | ||
| 8 | * | ||
| 9 | * 1. Redistributions of source code must retain the above copyright | ||
| 10 | * notice, this list of conditions and the following disclaimer. | ||
| 11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
| 12 | * notice, this list of conditions and the following disclaimer in the | ||
| 13 | * documentation and/or other materials provided with the distribution. | ||
| 14 | * 3. The name of the author may not be used to endorse or promote products | ||
| 15 | * derived from this software without specific prior written permission. | ||
| 16 | * | ||
| 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
| 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
| 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
| 20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
| 22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| 24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
| 26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 27 | */ | ||
| 28 | |||
| 29 | /* | ||
| 30 | * Re-written nc(1) for OpenBSD. Original implementation by | ||
| 31 | * *Hobbit* <hobbit@avian.org>. | ||
| 32 | */ | ||
| 33 | |||
| 34 | #include <sys/types.h> | ||
| 35 | #include <sys/socket.h> | ||
| 36 | #include <sys/time.h> | ||
| 37 | #include <sys/un.h> | ||
| 38 | |||
| 39 | #include <netinet/in.h> | ||
| 40 | #include <arpa/telnet.h> | ||
| 41 | |||
| 42 | #include <err.h> | ||
| 43 | #include <errno.h> | ||
| 44 | #include <netdb.h> | ||
| 45 | #include <poll.h> | ||
| 46 | #include <stdarg.h> | ||
| 47 | #include <stdio.h> | ||
| 48 | #include <stdlib.h> | ||
| 49 | #include <string.h> | ||
| 50 | #include <unistd.h> | ||
| 51 | #include <fcntl.h> | ||
| 52 | |||
| 53 | #ifndef SUN_LEN | ||
| 54 | #define SUN_LEN(su) \ | ||
| 55 | (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) | ||
| 56 | #endif | ||
| 57 | |||
| 58 | #define PORT_MAX 65535 | ||
| 59 | |||
| 60 | /* Command Line Options */ | ||
| 61 | int iflag; /* Interval Flag */ | ||
| 62 | int kflag; /* More than one connect */ | ||
| 63 | int lflag; /* Bind to local port */ | ||
| 64 | int nflag; /* Dont do name lookup */ | ||
| 65 | char *pflag; /* Localport flag */ | ||
| 66 | int rflag; /* Random ports flag */ | ||
| 67 | char *sflag; /* Source Address */ | ||
| 68 | int tflag; /* Telnet Emulation */ | ||
| 69 | int uflag; /* UDP - Default to TCP */ | ||
| 70 | int vflag; /* Verbosity */ | ||
| 71 | int xflag; /* Socks proxy */ | ||
| 72 | int zflag; /* Port Scan Flag */ | ||
| 73 | |||
| 74 | int timeout = -1; | ||
| 75 | int family = AF_UNSPEC; | ||
| 76 | char *portlist[PORT_MAX]; | ||
| 77 | |||
| 78 | ssize_t atomicio(ssize_t (*)(), int, void *, size_t); | ||
| 79 | void atelnet(int, unsigned char *, unsigned int); | ||
| 80 | void build_ports(char *); | ||
| 81 | void help(void); | ||
| 82 | int local_listen(char *, char *, struct addrinfo); | ||
| 83 | void readwrite(int); | ||
| 84 | int remote_connect(char *, char *, struct addrinfo); | ||
| 85 | int socks_connect(char *, char *, struct addrinfo, char *, char *, | ||
| 86 | struct addrinfo, int); | ||
| 87 | int udptest(int); | ||
| 88 | int unix_connect(char *); | ||
| 89 | int unix_listen(char *); | ||
| 90 | void usage(int); | ||
| 91 | |||
| 92 | int | ||
| 93 | main(int argc, char *argv[]) | ||
| 94 | { | ||
| 95 | int ch, s, ret, socksv; | ||
| 96 | char *host, *uport, *endp; | ||
| 97 | struct addrinfo hints; | ||
| 98 | struct servent *sv; | ||
| 99 | socklen_t len; | ||
| 100 | struct sockaddr *cliaddr; | ||
| 101 | char *proxy; | ||
| 102 | char *proxyhost = "", *proxyport = NULL; | ||
| 103 | struct addrinfo proxyhints; | ||
| 104 | |||
| 105 | ret = 1; | ||
| 106 | s = 0; | ||
| 107 | socksv = 5; | ||
| 108 | host = NULL; | ||
| 109 | uport = NULL; | ||
| 110 | endp = NULL; | ||
| 111 | sv = NULL; | ||
| 112 | |||
| 113 | while ((ch = getopt(argc, argv, "46UX:hi:klnp:rs:tuvw:x:z")) != -1) { | ||
| 114 | switch (ch) { | ||
| 115 | case '4': | ||
| 116 | family = AF_INET; | ||
| 117 | break; | ||
| 118 | case '6': | ||
| 119 | family = AF_INET6; | ||
| 120 | break; | ||
| 121 | case 'U': | ||
| 122 | family = AF_UNIX; | ||
| 123 | break; | ||
| 124 | case 'X': | ||
| 125 | socksv = (int)strtoul(optarg, &endp, 10); | ||
| 126 | if ((socksv != 4 && socksv != 5) || *endp != '\0') | ||
| 127 | errx(1, "only SOCKS version 4 and 5 supported"); | ||
| 128 | break; | ||
| 129 | case 'h': | ||
| 130 | help(); | ||
| 131 | break; | ||
| 132 | case 'i': | ||
| 133 | iflag = (int)strtoul(optarg, &endp, 10); | ||
| 134 | if (iflag < 0 || *endp != '\0') | ||
| 135 | errx(1, "interval cannot be negative"); | ||
| 136 | break; | ||
| 137 | case 'k': | ||
| 138 | kflag = 1; | ||
| 139 | break; | ||
| 140 | case 'l': | ||
| 141 | lflag = 1; | ||
| 142 | break; | ||
| 143 | case 'n': | ||
| 144 | nflag = 1; | ||
| 145 | break; | ||
| 146 | case 'p': | ||
| 147 | pflag = optarg; | ||
| 148 | break; | ||
| 149 | case 'r': | ||
| 150 | rflag = 1; | ||
| 151 | break; | ||
| 152 | case 's': | ||
| 153 | sflag = optarg; | ||
| 154 | break; | ||
| 155 | case 't': | ||
| 156 | tflag = 1; | ||
| 157 | break; | ||
| 158 | case 'u': | ||
| 159 | uflag = 1; | ||
| 160 | break; | ||
| 161 | case 'v': | ||
| 162 | vflag = 1; | ||
| 163 | break; | ||
| 164 | case 'w': | ||
| 165 | timeout = (int)strtoul(optarg, &endp, 10); | ||
| 166 | if (timeout < 0 || *endp != '\0') | ||
| 167 | errx(1, "timeout cannot be negative"); | ||
| 168 | if (timeout >= (INT_MAX / 1000)) | ||
| 169 | errx(1, "timeout too large"); | ||
| 170 | timeout *= 1000; | ||
| 171 | break; | ||
| 172 | case 'x': | ||
| 173 | xflag = 1; | ||
| 174 | proxy = strdup(optarg); | ||
| 175 | break; | ||
| 176 | case 'z': | ||
| 177 | zflag = 1; | ||
| 178 | break; | ||
| 179 | default: | ||
| 180 | usage(1); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | argc -= optind; | ||
| 184 | argv += optind; | ||
| 185 | |||
| 186 | /* Cruft to make sure options are clean, and used properly. */ | ||
| 187 | if (argv[0] && !argv[1] && family == AF_UNIX) { | ||
| 188 | if (uflag) | ||
| 189 | errx(1, "cannot use -u and -U"); | ||
| 190 | host = argv[0]; | ||
| 191 | uport = NULL; | ||
| 192 | } else if (argv[0] && !argv[1]) { | ||
| 193 | if (!lflag) | ||
| 194 | usage(1); | ||
| 195 | uport = argv[0]; | ||
| 196 | host = NULL; | ||
| 197 | } else if (argv[0] && argv[1]) { | ||
| 198 | host = argv[0]; | ||
| 199 | uport = argv[1]; | ||
| 200 | } else | ||
| 201 | usage(1); | ||
| 202 | |||
| 203 | if (lflag && sflag) | ||
| 204 | errx(1, "cannot use -s and -l"); | ||
| 205 | if (lflag && pflag) | ||
| 206 | errx(1, "cannot use -p and -l"); | ||
| 207 | if (lflag && zflag) | ||
| 208 | errx(1, "cannot use -z and -l"); | ||
| 209 | if (!lflag && kflag) | ||
| 210 | errx(1, "must use -l with -k"); | ||
| 211 | |||
| 212 | /* Initialize addrinfo structure */ | ||
| 213 | if (family != AF_UNIX) { | ||
| 214 | memset(&hints, 0, sizeof(struct addrinfo)); | ||
| 215 | hints.ai_family = family; | ||
| 216 | hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; | ||
| 217 | hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; | ||
| 218 | if (nflag) | ||
| 219 | hints.ai_flags |= AI_NUMERICHOST; | ||
| 220 | } | ||
| 221 | |||
| 222 | |||
| 223 | if (xflag) { | ||
| 224 | if (uflag) | ||
| 225 | errx(1, "no proxy support for UDP mode"); | ||
| 226 | |||
| 227 | if (lflag) | ||
| 228 | errx(1, "no proxy support for listen"); | ||
| 229 | |||
| 230 | if (family == AF_UNIX) | ||
| 231 | errx(1, "no proxy support for unix sockets"); | ||
| 232 | |||
| 233 | /* XXX IPv6 transport to proxy would probably work */ | ||
| 234 | if (family == AF_INET6) | ||
| 235 | errx(1, "no proxy support for IPv6"); | ||
| 236 | |||
| 237 | if (sflag) | ||
| 238 | errx(1, "no proxy support for local source address"); | ||
| 239 | |||
| 240 | proxyhost = strsep(&proxy, ":"); | ||
| 241 | proxyport = proxy; | ||
| 242 | |||
| 243 | memset(&proxyhints, 0, sizeof(struct addrinfo)); | ||
| 244 | proxyhints.ai_family = family; | ||
| 245 | proxyhints.ai_socktype = SOCK_STREAM; | ||
| 246 | proxyhints.ai_protocol = IPPROTO_TCP; | ||
| 247 | if (nflag) | ||
| 248 | proxyhints.ai_flags |= AI_NUMERICHOST; | ||
| 249 | } | ||
| 250 | |||
| 251 | if (lflag) { | ||
| 252 | int connfd; | ||
| 253 | ret = 0; | ||
| 254 | |||
| 255 | if (family == AF_UNIX) | ||
| 256 | s = unix_listen(host); | ||
| 257 | |||
| 258 | /* Allow only one connection at a time, but stay alive */ | ||
| 259 | for (;;) { | ||
| 260 | if (family != AF_UNIX) | ||
| 261 | s = local_listen(host, uport, hints); | ||
| 262 | if (s < 0) | ||
| 263 | err(1, NULL); | ||
| 264 | /* | ||
| 265 | * For UDP, we will use recvfrom() initially | ||
| 266 | * to wait for a caller, then use the regular | ||
| 267 | * functions to talk to the caller. | ||
| 268 | */ | ||
| 269 | if (uflag) { | ||
| 270 | int rv; | ||
| 271 | char buf[1024]; | ||
| 272 | struct sockaddr_storage z; | ||
| 273 | |||
| 274 | len = sizeof(z); | ||
| 275 | rv = recvfrom(s, buf, sizeof(buf), MSG_PEEK, | ||
| 276 | (struct sockaddr *)&z, &len); | ||
| 277 | if (rv < 0) | ||
| 278 | errx(1, "%s", strerror(errno)); | ||
| 279 | |||
| 280 | rv = connect(s, (struct sockaddr *)&z, len); | ||
| 281 | if (rv < 0) | ||
| 282 | errx(1, "%s", strerror(errno)); | ||
| 283 | |||
| 284 | connfd = s; | ||
| 285 | } else { | ||
| 286 | connfd = accept(s, (struct sockaddr *)&cliaddr, | ||
| 287 | &len); | ||
| 288 | } | ||
| 289 | |||
| 290 | readwrite(connfd); | ||
| 291 | close(connfd); | ||
| 292 | if (family != AF_UNIX) | ||
| 293 | close(s); | ||
| 294 | |||
| 295 | if (!kflag) | ||
| 296 | break; | ||
| 297 | } | ||
| 298 | } else if (family == AF_UNIX) { | ||
| 299 | ret = 0; | ||
| 300 | |||
| 301 | if ((s = unix_connect(host)) > 0 && !zflag) { | ||
| 302 | readwrite(s); | ||
| 303 | close(s); | ||
| 304 | } else | ||
| 305 | ret = 1; | ||
| 306 | |||
| 307 | exit(ret); | ||
| 308 | |||
| 309 | } else { | ||
| 310 | int i = 0; | ||
| 311 | |||
| 312 | /* construct the portlist[] array */ | ||
| 313 | build_ports(uport); | ||
| 314 | |||
| 315 | /* Cycle through portlist, connecting to each port */ | ||
| 316 | for (i = 0; portlist[i] != NULL; i++) { | ||
| 317 | if (s) | ||
| 318 | close(s); | ||
| 319 | |||
| 320 | if (xflag) | ||
| 321 | s = socks_connect(host, portlist[i], hints, | ||
| 322 | proxyhost, proxyport, proxyhints, socksv); | ||
| 323 | else | ||
| 324 | s = remote_connect(host, portlist[i], hints); | ||
| 325 | |||
| 326 | if (s < 0) | ||
| 327 | continue; | ||
| 328 | |||
| 329 | ret = 0; | ||
| 330 | if (vflag || zflag) { | ||
| 331 | /* For UDP, make sure we are connected */ | ||
| 332 | if (uflag) { | ||
| 333 | if (udptest(s) == -1) { | ||
| 334 | ret = 1; | ||
| 335 | continue; | ||
| 336 | } | ||
| 337 | } | ||
| 338 | |||
| 339 | /* Don't lookup port if -n */ | ||
| 340 | if (nflag) | ||
| 341 | sv = NULL; | ||
| 342 | else { | ||
| 343 | sv = getservbyport( | ||
| 344 | ntohs(atoi(portlist[i])), | ||
| 345 | uflag ? "udp" : "tcp"); | ||
| 346 | } | ||
| 347 | |||
| 348 | printf("Connection to %s %s port [%s/%s] succeeded!\n", | ||
| 349 | host, portlist[i], uflag ? "udp" : "tcp", | ||
| 350 | sv ? sv->s_name : "*"); | ||
| 351 | } | ||
| 352 | if (!zflag) | ||
| 353 | readwrite(s); | ||
| 354 | } | ||
| 355 | } | ||
| 356 | |||
| 357 | if (s) | ||
| 358 | close(s); | ||
| 359 | |||
| 360 | exit(ret); | ||
| 361 | } | ||
| 362 | |||
| 363 | /* | ||
| 364 | * unix_connect() | ||
| 365 | * Return's a socket connected to a local unix socket. Return's -1 on failure. | ||
| 366 | */ | ||
| 367 | int | ||
| 368 | unix_connect(char *path) | ||
| 369 | { | ||
| 370 | struct sockaddr_un sun; | ||
| 371 | int s; | ||
| 372 | |||
| 373 | if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) | ||
| 374 | return (-1); | ||
| 375 | (void)fcntl(s, F_SETFD, 1); | ||
| 376 | |||
| 377 | memset(&sun, 0, sizeof(struct sockaddr_un)); | ||
| 378 | sun.sun_family = AF_UNIX; | ||
| 379 | strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); | ||
| 380 | if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) { | ||
| 381 | close(s); | ||
| 382 | return (-1); | ||
| 383 | } | ||
| 384 | return (s); | ||
| 385 | |||
| 386 | } | ||
| 387 | |||
| 388 | /* | ||
| 389 | * unix_listen() | ||
| 390 | * create a unix domain socket, and listen on it. | ||
| 391 | */ | ||
| 392 | int | ||
| 393 | unix_listen(char *path) | ||
| 394 | { | ||
| 395 | struct sockaddr_un sun; | ||
| 396 | int s; | ||
| 397 | |||
| 398 | /* create unix domain socket */ | ||
| 399 | if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) | ||
| 400 | return (-1); | ||
| 401 | |||
| 402 | strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); | ||
| 403 | sun.sun_family = AF_UNIX; | ||
| 404 | if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) { | ||
| 405 | close(s); | ||
| 406 | return (-1); | ||
| 407 | } | ||
| 408 | |||
| 409 | if (listen(s, 5) < 0) { | ||
| 410 | close(s); | ||
| 411 | return (-1); | ||
| 412 | } | ||
| 413 | return (s); | ||
| 414 | } | ||
| 415 | |||
| 416 | /* | ||
| 417 | * remote_connect() | ||
| 418 | * Return's a socket connected to a remote host. Properly bind's to a local | ||
| 419 | * port or source address if needed. Return's -1 on failure. | ||
| 420 | */ | ||
| 421 | int | ||
| 422 | remote_connect(char *host, char *port, struct addrinfo hints) | ||
| 423 | { | ||
| 424 | struct addrinfo *res, *res0; | ||
| 425 | int s, error; | ||
| 426 | |||
| 427 | if ((error = getaddrinfo(host, port, &hints, &res))) | ||
| 428 | errx(1, "%s", gai_strerror(error)); | ||
| 429 | |||
| 430 | res0 = res; | ||
| 431 | do { | ||
| 432 | if ((s = socket(res0->ai_family, res0->ai_socktype, | ||
| 433 | res0->ai_protocol)) < 0) | ||
| 434 | continue; | ||
| 435 | |||
| 436 | /* Bind to a local port or source address if specified */ | ||
| 437 | if (sflag || pflag) { | ||
| 438 | struct addrinfo ahints, *ares; | ||
| 439 | |||
| 440 | if (!(sflag && pflag)) { | ||
| 441 | if (!sflag) | ||
| 442 | sflag = NULL; | ||
| 443 | else | ||
| 444 | pflag = NULL; | ||
| 445 | } | ||
| 446 | |||
| 447 | memset(&ahints, 0, sizeof(struct addrinfo)); | ||
| 448 | ahints.ai_family = res0->ai_family; | ||
| 449 | ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; | ||
| 450 | ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; | ||
| 451 | ahints.ai_flags = AI_PASSIVE; | ||
| 452 | if ((error = getaddrinfo(sflag, pflag, &ahints, &ares))) | ||
| 453 | errx(1, "%s", gai_strerror(error)); | ||
| 454 | |||
| 455 | if (bind(s, (struct sockaddr *)ares->ai_addr, | ||
| 456 | ares->ai_addrlen) < 0) { | ||
| 457 | errx(1, "bind failed: %s", strerror(errno)); | ||
| 458 | freeaddrinfo(ares); | ||
| 459 | continue; | ||
| 460 | } | ||
| 461 | freeaddrinfo(ares); | ||
| 462 | } | ||
| 463 | |||
| 464 | if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0) | ||
| 465 | break; | ||
| 466 | |||
| 467 | close(s); | ||
| 468 | s = -1; | ||
| 469 | } while ((res0 = res0->ai_next) != NULL); | ||
| 470 | |||
| 471 | freeaddrinfo(res); | ||
| 472 | |||
| 473 | return (s); | ||
| 474 | } | ||
| 475 | |||
| 476 | /* | ||
| 477 | * local_listen() | ||
| 478 | * Return's a socket listening on a local port, binds to specified source | ||
| 479 | * address. Return's -1 on failure. | ||
| 480 | */ | ||
| 481 | int | ||
| 482 | local_listen(char *host, char *port, struct addrinfo hints) | ||
| 483 | { | ||
| 484 | struct addrinfo *res, *res0; | ||
| 485 | int s, ret, x = 1; | ||
| 486 | int error; | ||
| 487 | |||
| 488 | /* Allow nodename to be null */ | ||
| 489 | hints.ai_flags |= AI_PASSIVE; | ||
| 490 | |||
| 491 | /* | ||
| 492 | * In the case of binding to a wildcard address | ||
| 493 | * default to binding to an ipv4 address. | ||
| 494 | */ | ||
| 495 | if (host == NULL && hints.ai_family == AF_UNSPEC) | ||
| 496 | hints.ai_family = AF_INET; | ||
| 497 | |||
| 498 | if ((error = getaddrinfo(host, port, &hints, &res))) | ||
| 499 | errx(1, "%s", gai_strerror(error)); | ||
| 500 | |||
| 501 | res0 = res; | ||
| 502 | do { | ||
| 503 | if ((s = socket(res0->ai_family, res0->ai_socktype, | ||
| 504 | res0->ai_protocol)) == 0) | ||
| 505 | continue; | ||
| 506 | |||
| 507 | ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x)); | ||
| 508 | if (ret == -1) | ||
| 509 | err(1, NULL); | ||
| 510 | |||
| 511 | if (bind(s, (struct sockaddr *)res0->ai_addr, | ||
| 512 | res0->ai_addrlen) == 0) | ||
| 513 | break; | ||
| 514 | |||
| 515 | close(s); | ||
| 516 | s = -1; | ||
| 517 | } while ((res0 = res0->ai_next) != NULL); | ||
| 518 | |||
| 519 | if (!uflag && s != -1) { | ||
| 520 | if (listen(s, 1) < 0) | ||
| 521 | errx(1, "%s", strerror(errno)); | ||
| 522 | } | ||
| 523 | |||
| 524 | freeaddrinfo(res); | ||
| 525 | |||
| 526 | return (s); | ||
| 527 | } | ||
| 528 | |||
| 529 | /* | ||
| 530 | * readwrite() | ||
| 531 | * Loop that polls on the network file descriptor and stdin. | ||
| 532 | */ | ||
| 533 | void | ||
| 534 | readwrite(int nfd) | ||
| 535 | { | ||
| 536 | struct pollfd pfd[2]; | ||
| 537 | char buf[BUFSIZ]; | ||
| 538 | int wfd = fileno(stdin), n, ret; | ||
| 539 | int lfd = fileno(stdout); | ||
| 540 | |||
| 541 | /* Setup Network FD */ | ||
| 542 | pfd[0].fd = nfd; | ||
| 543 | pfd[0].events = POLLIN; | ||
| 544 | |||
| 545 | /* Setup STDIN FD */ | ||
| 546 | pfd[1].fd = wfd; | ||
| 547 | pfd[1].events = POLLIN; | ||
| 548 | |||
| 549 | while (pfd[0].fd != -1 || pfd[1].fd != -1) { | ||
| 550 | if (iflag) | ||
| 551 | sleep(iflag); | ||
| 552 | |||
| 553 | if ((n = poll(pfd, 2, timeout)) < 0) { | ||
| 554 | close(nfd); | ||
| 555 | err(1, "Polling Error"); | ||
| 556 | } | ||
| 557 | |||
| 558 | if (n == 0) | ||
| 559 | return; | ||
| 560 | |||
| 561 | if (pfd[0].revents & POLLIN) { | ||
| 562 | if ((n = read(nfd, buf, sizeof(buf))) < 0) | ||
| 563 | return; | ||
| 564 | else if (n == 0) { | ||
| 565 | shutdown(nfd, SHUT_RD); | ||
| 566 | pfd[0].fd = -1; | ||
| 567 | pfd[0].events = 0; | ||
| 568 | } else { | ||
| 569 | if (tflag) | ||
| 570 | atelnet(nfd, buf, n); | ||
| 571 | if ((ret = atomicio(write, lfd, buf, n)) != n) | ||
| 572 | return; | ||
| 573 | } | ||
| 574 | } | ||
| 575 | |||
| 576 | if (pfd[1].revents & POLLIN) { | ||
| 577 | if ((n = read(wfd, buf, sizeof(buf))) < 0) | ||
| 578 | return; | ||
| 579 | else if (n == 0) { | ||
| 580 | shutdown(nfd, SHUT_WR); | ||
| 581 | pfd[1].fd = -1; | ||
| 582 | pfd[1].events = 0; | ||
| 583 | } else { | ||
| 584 | if((ret = atomicio(write, nfd, buf, n)) != n) | ||
| 585 | return; | ||
| 586 | } | ||
| 587 | } | ||
| 588 | } | ||
| 589 | } | ||
| 590 | |||
| 591 | /* Deal with RFC854 WILL/WONT DO/DONT negotiation */ | ||
| 592 | void | ||
| 593 | atelnet(int nfd, unsigned char *buf, unsigned int size) | ||
| 594 | { | ||
| 595 | int ret; | ||
| 596 | unsigned char *p, *end; | ||
| 597 | unsigned char obuf[4]; | ||
| 598 | |||
| 599 | end = buf + size; | ||
| 600 | obuf[0] = '\0'; | ||
| 601 | |||
| 602 | for (p = buf; p < end; p++) { | ||
| 603 | if (*p != IAC) | ||
| 604 | break; | ||
| 605 | |||
| 606 | obuf[0] = IAC; | ||
| 607 | p++; | ||
| 608 | if ((*p == WILL) || (*p == WONT)) | ||
| 609 | obuf[1] = DONT; | ||
| 610 | if ((*p == DO) || (*p == DONT)) | ||
| 611 | obuf[1] = WONT; | ||
| 612 | if (obuf) { | ||
| 613 | p++; | ||
| 614 | obuf[2] = *p; | ||
| 615 | obuf[3] = '\0'; | ||
| 616 | if ((ret = atomicio(write , nfd, obuf, 3)) != 3) | ||
| 617 | warnx("Write Error!"); | ||
| 618 | obuf[0] = '\0'; | ||
| 619 | } | ||
| 620 | } | ||
| 621 | } | ||
| 622 | |||
| 623 | /* | ||
| 624 | * build_ports() | ||
| 625 | * Build an array or ports in portlist[], listing each port | ||
| 626 | * that we should try to connect too. | ||
| 627 | */ | ||
| 628 | void | ||
| 629 | build_ports(char *p) | ||
| 630 | { | ||
| 631 | char *n, *endp; | ||
| 632 | int hi, lo, cp; | ||
| 633 | int x = 0; | ||
| 634 | |||
| 635 | if ((n = strchr(p, '-')) != NULL) { | ||
| 636 | if (lflag) | ||
| 637 | errx(1, "Cannot use -l with multiple ports!"); | ||
| 638 | |||
| 639 | *n = '\0'; | ||
| 640 | n++; | ||
| 641 | |||
| 642 | /* Make sure the ports are in order: lowest->highest */ | ||
| 643 | hi = (int)strtoul(n, &endp, 10); | ||
| 644 | if (hi <= 0 || hi > PORT_MAX || *endp != '\0') | ||
| 645 | errx(1, "port range not valid"); | ||
| 646 | lo = (int)strtoul(p, &endp, 10); | ||
| 647 | if (lo <= 0 || lo > PORT_MAX || *endp != '\0') | ||
| 648 | errx(1, "port range not valid"); | ||
| 649 | |||
| 650 | if (lo > hi) { | ||
| 651 | cp = hi; | ||
| 652 | hi = lo; | ||
| 653 | lo = cp; | ||
| 654 | } | ||
| 655 | |||
| 656 | /* Load ports sequentially */ | ||
| 657 | for (cp = lo; cp <= hi; cp++) { | ||
| 658 | portlist[x] = calloc(1, PORT_MAX); | ||
| 659 | snprintf(portlist[x], PORT_MAX, "%d", cp); | ||
| 660 | x++; | ||
| 661 | } | ||
| 662 | |||
| 663 | /* Randomly swap ports */ | ||
| 664 | if (rflag) { | ||
| 665 | int y; | ||
| 666 | char *c; | ||
| 667 | |||
| 668 | for (x = 0; x <= (hi - lo); x++) { | ||
| 669 | y = (arc4random() & 0xFFFF) % (hi - lo); | ||
| 670 | c = portlist[x]; | ||
| 671 | portlist[x] = portlist[y]; | ||
| 672 | portlist[y] = c; | ||
| 673 | } | ||
| 674 | } | ||
| 675 | } else { | ||
| 676 | hi = (int)strtoul(p, &endp, 10); | ||
| 677 | if (hi <= 0 || hi > PORT_MAX || *endp != '\0') | ||
| 678 | errx(1, "port range not valid"); | ||
| 679 | portlist[0] = calloc(1, PORT_MAX); | ||
| 680 | portlist[0] = p; | ||
| 681 | } | ||
| 682 | } | ||
| 683 | |||
| 684 | /* | ||
| 685 | * udptest() | ||
| 686 | * Do a few writes to see if the UDP port is there. | ||
| 687 | * XXX - Better way of doing this? Doesn't work for IPv6 | ||
| 688 | * Also fails after around 100 ports checked. | ||
| 689 | */ | ||
| 690 | int | ||
| 691 | udptest(int s) | ||
| 692 | { | ||
| 693 | int i, rv, ret; | ||
| 694 | |||
| 695 | for (i = 0; i <= 3; i++) { | ||
| 696 | if ((rv = write(s, "X", 1)) == 1) | ||
| 697 | ret = 1; | ||
| 698 | else | ||
| 699 | ret = -1; | ||
| 700 | } | ||
| 701 | return (ret); | ||
| 702 | } | ||
| 703 | |||
| 704 | void | ||
| 705 | help() | ||
| 706 | { | ||
| 707 | usage(0); | ||
| 708 | fprintf(stderr, "\tCommand Summary:\n\ | ||
| 709 | \t-4 Use IPv4\n\ | ||
| 710 | \t-6 Use IPv6\n\ | ||
| 711 | \t-U Use UNIX domain socket\n\ | ||
| 712 | \t-h This help text\n\ | ||
| 713 | \t-i secs\t Delay interval for lines sent, ports scanned\n\ | ||
| 714 | \t-k Keep inbound sockets open for multiple connects\n\ | ||
| 715 | \t-l Listen mode, for inbound connects\n\ | ||
| 716 | \t-n Suppress name/port resolutions\n\ | ||
| 717 | \t-p port\t Specify local port for remote connects\n\ | ||
| 718 | \t-r Randomize remote ports\n\ | ||
| 719 | \t-s addr\t Local source address\n\ | ||
| 720 | \t-t Answer TELNET negotiation\n\ | ||
| 721 | \t-u UDP mode\n\ | ||
| 722 | \t-v Verbose\n\ | ||
| 723 | \t-w secs\t Timeout for connects and final net reads\n\ | ||
| 724 | \t-x addr[:port]\tSpecify socks5 proxy address and port\n\ | ||
| 725 | \t-z Zero-I/O mode [used for scanning]\n\ | ||
| 726 | Port numbers can be individual or ranges: lo-hi [inclusive]\n"); | ||
| 727 | exit(1); | ||
| 728 | } | ||
| 729 | |||
| 730 | void | ||
| 731 | usage(int ret) | ||
| 732 | { | ||
| 733 | fprintf(stderr, "usage: nc [-46Uhklnrtuvz] [-i interval] [-p source port]\n"); | ||
| 734 | fprintf(stderr, "\t [-s ip address] [-w timeout] [-x proxy address [:port]]\n"); | ||
| 735 | fprintf(stderr, "\t [hostname] [port[s...]]\n"); | ||
| 736 | if (ret) | ||
| 737 | exit(1); | ||
| 738 | } | ||
diff --git a/src/usr.bin/nc/socks.c b/src/usr.bin/nc/socks.c new file mode 100644 index 0000000000..af0fe29cff --- /dev/null +++ b/src/usr.bin/nc/socks.c | |||
| @@ -0,0 +1,171 @@ | |||
| 1 | /* $OpenBSD: socks.c,v 1.5 2002/02/28 18:05:36 markus Exp $ */ | ||
| 2 | |||
| 3 | /* | ||
| 4 | * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. | ||
| 5 | * | ||
| 6 | * Redistribution and use in source and binary forms, with or without | ||
| 7 | * modification, are permitted provided that the following conditions | ||
| 8 | * are met: | ||
| 9 | * 1. Redistributions of source code must retain the above copyright | ||
| 10 | * notice, this list of conditions and the following disclaimer. | ||
| 11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
| 12 | * notice, this list of conditions and the following disclaimer in the | ||
| 13 | * documentation and/or other materials provided with the distribution. | ||
| 14 | * 3. All advertising materials mentioning features or use of this software | ||
| 15 | * must display the following acknowledgement: | ||
| 16 | * This product includes software developed by Niklas Hallqvist. | ||
| 17 | * 4. The name of the author may not be used to endorse or promote products | ||
| 18 | * derived from this software without specific prior written permission. | ||
| 19 | * | ||
| 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
| 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
| 22 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
| 23 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| 24 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
| 25 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
| 29 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 30 | */ | ||
| 31 | |||
| 32 | #include <sys/types.h> | ||
| 33 | #include <sys/socket.h> | ||
| 34 | #include <netinet/in.h> | ||
| 35 | #include <arpa/inet.h> | ||
| 36 | |||
| 37 | #include <err.h> | ||
| 38 | #include <netdb.h> | ||
| 39 | #include <stdio.h> | ||
| 40 | #include <stdlib.h> | ||
| 41 | #include <string.h> | ||
| 42 | #include <unistd.h> | ||
| 43 | |||
| 44 | #define SOCKS_PORT "1080" | ||
| 45 | #define SOCKS_V5 5 | ||
| 46 | #define SOCKS_V4 4 | ||
| 47 | #define SOCKS_NOAUTH 0 | ||
| 48 | #define SOCKS_NOMETHOD 0xff | ||
| 49 | #define SOCKS_CONNECT 1 | ||
| 50 | #define SOCKS_IPV4 1 | ||
| 51 | #define SOCKS_MAXCMDSZ 10 | ||
| 52 | |||
| 53 | int remote_connect(char *, char *, struct addrinfo); | ||
| 54 | |||
| 55 | static in_addr_t | ||
| 56 | decode_addr (const char *s) | ||
| 57 | { | ||
| 58 | struct hostent *hp = gethostbyname (s); | ||
| 59 | struct in_addr retval; | ||
| 60 | |||
| 61 | if (hp) | ||
| 62 | return *(in_addr_t *)hp->h_addr_list[0]; | ||
| 63 | if (inet_aton (s, &retval)) | ||
| 64 | return retval.s_addr; | ||
| 65 | errx (1, "cannot decode address \"%s\"", s); | ||
| 66 | } | ||
| 67 | |||
| 68 | static in_port_t | ||
| 69 | decode_port (const char *s) | ||
| 70 | { | ||
| 71 | struct servent *sp; | ||
| 72 | in_port_t port; | ||
| 73 | char *p; | ||
| 74 | |||
| 75 | port = strtol (s, &p, 10); | ||
| 76 | if (s == p) { | ||
| 77 | sp = getservbyname (s, "tcp"); | ||
| 78 | if (sp) | ||
| 79 | return sp->s_port; | ||
| 80 | } | ||
| 81 | if (*s != '\0' && *p == '\0') | ||
| 82 | return htons (port); | ||
| 83 | errx (1, "cannot decode port \"%s\"", s); | ||
| 84 | } | ||
| 85 | |||
| 86 | int | ||
| 87 | socks_connect (char *host, char *port, struct addrinfo hints, | ||
| 88 | char *proxyhost, char *proxyport, struct addrinfo proxyhints, | ||
| 89 | int socksv) | ||
| 90 | { | ||
| 91 | int proxyfd; | ||
| 92 | unsigned char buf[SOCKS_MAXCMDSZ]; | ||
| 93 | ssize_t cnt; | ||
| 94 | in_addr_t serveraddr; | ||
| 95 | in_port_t serverport; | ||
| 96 | |||
| 97 | if (proxyport) | ||
| 98 | proxyfd = remote_connect(proxyhost, proxyport, proxyhints); | ||
| 99 | else | ||
| 100 | proxyfd = remote_connect(proxyhost, SOCKS_PORT, proxyhints); | ||
| 101 | |||
| 102 | if (!proxyfd) | ||
| 103 | return -1; | ||
| 104 | |||
| 105 | serveraddr = decode_addr (host); | ||
| 106 | serverport = decode_port (port); | ||
| 107 | |||
| 108 | if (socksv == 5) { | ||
| 109 | /* Version 5, one method: no authentication */ | ||
| 110 | buf[0] = SOCKS_V5; | ||
| 111 | buf[1] = 1; | ||
| 112 | buf[2] = SOCKS_NOAUTH; | ||
| 113 | cnt = write (proxyfd, buf, 3); | ||
| 114 | if (cnt == -1) | ||
| 115 | err (1, "write failed"); | ||
| 116 | if (cnt != 3) | ||
| 117 | errx (1, "short write, %d (expected 3)", cnt); | ||
| 118 | |||
| 119 | read (proxyfd, buf, 2); | ||
| 120 | if (buf[1] == SOCKS_NOMETHOD) | ||
| 121 | errx (1, "authentication method negotiation failed"); | ||
| 122 | |||
| 123 | /* Version 5, connect: IPv4 address */ | ||
| 124 | buf[0] = SOCKS_V5; | ||
| 125 | buf[1] = SOCKS_CONNECT; | ||
| 126 | buf[2] = 0; | ||
| 127 | buf[3] = SOCKS_IPV4; | ||
| 128 | memcpy (buf + 4, &serveraddr, sizeof serveraddr); | ||
| 129 | memcpy (buf + 8, &serverport, sizeof serverport); | ||
| 130 | |||
| 131 | /* XXX Handle short writes better */ | ||
| 132 | cnt = write (proxyfd, buf, 10); | ||
| 133 | if (cnt == -1) | ||
| 134 | err (1, "write failed"); | ||
| 135 | if (cnt != 10) | ||
| 136 | errx (1, "short write, %d (expected 10)", cnt); | ||
| 137 | |||
| 138 | /* XXX Handle short reads better */ | ||
| 139 | cnt = read (proxyfd, buf, sizeof buf); | ||
| 140 | if (cnt == -1) | ||
| 141 | err (1, "read failed"); | ||
| 142 | if (cnt != 10) | ||
| 143 | errx (1, "unexpected reply size %d (expected 10)", cnt); | ||
| 144 | if (buf[1] != 0) | ||
| 145 | errx (1, "connection failed, SOCKS error %d", buf[1]); | ||
| 146 | } else { | ||
| 147 | /* Version 4 */ | ||
| 148 | buf[0] = SOCKS_V4; | ||
| 149 | buf[1] = SOCKS_CONNECT; /* connect */ | ||
| 150 | memcpy (buf + 2, &serverport, sizeof serverport); | ||
| 151 | memcpy (buf + 4, &serveraddr, sizeof serveraddr); | ||
| 152 | buf[8] = 0; /* empty username */ | ||
| 153 | |||
| 154 | cnt = write (proxyfd, buf, 9); | ||
| 155 | if (cnt == -1) | ||
| 156 | err (1, "write failed"); | ||
| 157 | if (cnt != 9) | ||
| 158 | errx (1, "short write, %d (expected 9)", cnt); | ||
| 159 | |||
| 160 | /* XXX Handle short reads better */ | ||
| 161 | cnt = read (proxyfd, buf, 8); | ||
| 162 | if (cnt == -1) | ||
| 163 | err (1, "read failed"); | ||
| 164 | if (cnt != 8) | ||
| 165 | errx (1, "unexpected reply size %d (expected 8)", cnt); | ||
| 166 | if (buf[1] != 90) | ||
| 167 | errx (1, "connection failed, SOCKS error %d", buf[1]); | ||
| 168 | } | ||
| 169 | |||
| 170 | return proxyfd; | ||
| 171 | } | ||
