summaryrefslogtreecommitdiff
path: root/src/usr.bin
diff options
context:
space:
mode:
authorcvs2svn <admin@example.com>2008-07-28 23:44:12 +0000
committercvs2svn <admin@example.com>2008-07-28 23:44:12 +0000
commitdaac2f633f49a45baa8412c5e4e71e594236e7b8 (patch)
treec2b7593b6807015d5bd1bbe95841e718a3b3df42 /src/usr.bin
parent10837c3c47f1b9d7d1a061fff2327a4e280ba338 (diff)
downloadopenbsd-pre_openssl_0_9_8h.tar.gz
openbsd-pre_openssl_0_9_8h.tar.bz2
openbsd-pre_openssl_0_9_8h.zip
This commit was manufactured by cvs2git to create tag 'pre_openssl_0_9_8h'.pre_openssl_0_9_8h
Diffstat (limited to 'src/usr.bin')
-rw-r--r--src/usr.bin/nc/Makefile6
-rw-r--r--src/usr.bin/nc/atomicio.c69
-rw-r--r--src/usr.bin/nc/atomicio.h39
-rw-r--r--src/usr.bin/nc/nc.1420
-rw-r--r--src/usr.bin/nc/netcat.c872
-rw-r--r--src/usr.bin/nc/socks.c326
6 files changed, 0 insertions, 1732 deletions
diff --git a/src/usr.bin/nc/Makefile b/src/usr.bin/nc/Makefile
deleted file mode 100644
index 150f8295bd..0000000000
--- a/src/usr.bin/nc/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
1# $OpenBSD: Makefile,v 1.6 2001/09/02 18:45:41 jakob Exp $
2
3PROG= nc
4SRCS= 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
deleted file mode 100644
index e9d98b3561..0000000000
--- a/src/usr.bin/nc/atomicio.c
+++ /dev/null
@@ -1,69 +0,0 @@
1/* $OpenBSD: atomicio.c,v 1.9 2007/09/07 14:50:44 tobias Exp $ */
2/*
3 * Copyright (c) 2006 Damien Miller. All rights reserved.
4 * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
5 * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
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#include <sys/param.h>
30
31#include <errno.h>
32#include <poll.h>
33#include <unistd.h>
34
35#include "atomicio.h"
36
37/*
38 * ensure all of data on socket comes through. f==read || f==vwrite
39 */
40size_t
41atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
42{
43 char *s = _s;
44 size_t pos = 0;
45 ssize_t res;
46 struct pollfd pfd;
47
48 pfd.fd = fd;
49 pfd.events = f == read ? POLLIN : POLLOUT;
50 while (n > pos) {
51 res = (f) (fd, s + pos, n - pos);
52 switch (res) {
53 case -1:
54 if (errno == EINTR)
55 continue;
56 if (errno == EAGAIN) {
57 (void)poll(&pfd, 1, -1);
58 continue;
59 }
60 return 0;
61 case 0:
62 errno = EPIPE;
63 return pos;
64 default:
65 pos += (size_t)res;
66 }
67 }
68 return (pos);
69}
diff --git a/src/usr.bin/nc/atomicio.h b/src/usr.bin/nc/atomicio.h
deleted file mode 100644
index 7bf5b25418..0000000000
--- a/src/usr.bin/nc/atomicio.h
+++ /dev/null
@@ -1,39 +0,0 @@
1/* $OpenBSD: atomicio.h,v 1.2 2007/09/07 14:50:44 tobias Exp $ */
2
3/*
4 * Copyright (c) 2006 Damien Miller. All rights reserved.
5 * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
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#ifndef _ATOMICIO_H
30#define _ATOMICIO_H
31
32/*
33 * Ensure all of data on socket comes through. f==read || f==vwrite
34 */
35size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t);
36
37#define vwrite (ssize_t (*)(int, void *, size_t))write
38
39#endif /* _ATOMICIO_H */
diff --git a/src/usr.bin/nc/nc.1 b/src/usr.bin/nc/nc.1
deleted file mode 100644
index 75410e298d..0000000000
--- a/src/usr.bin/nc/nc.1
+++ /dev/null
@@ -1,420 +0,0 @@
1.\" $OpenBSD: nc.1,v 1.47 2008/05/06 16:21:03 jmc 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 $Mdocdate: May 6 2008 $
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.Bk -words
37.Op Fl 46DdhklnrStUuvz
38.Op Fl I Ar length
39.Op Fl i Ar interval
40.Op Fl O Ar length
41.Op Fl P Ar proxy_username
42.Op Fl p Ar source_port
43.Op Fl s Ar source_ip_address
44.Op Fl T Ar ToS
45.Op Fl w Ar timeout
46.Op Fl X Ar proxy_protocol
47.Oo Xo
48.Fl x Ar proxy_address Ns Oo : Ns
49.Ar port Oc Oc
50.Xc
51.Op Ar hostname
52.Op Ar port Ns Bq Ar s
53.Ek
54.Sh DESCRIPTION
55The
56.Nm
57(or
58.Nm netcat )
59utility is used for just about anything under the sun involving TCP
60or UDP.
61It can open TCP connections, send UDP packets, listen on arbitrary
62TCP and UDP ports, do port scanning, and deal with both IPv4 and
63IPv6.
64Unlike
65.Xr telnet 1 ,
66.Nm
67scripts nicely, and separates error messages onto standard error instead
68of sending them to standard output, as
69.Xr telnet 1
70does with some.
71.Pp
72Common uses include:
73.Pp
74.Bl -bullet -offset indent -compact
75.It
76simple TCP proxies
77.It
78shell-script based HTTP clients and servers
79.It
80network daemon testing
81.It
82a SOCKS or HTTP ProxyCommand for
83.Xr ssh 1
84.It
85and much, much more
86.El
87.Pp
88The options are as follows:
89.Bl -tag -width Ds
90.It Fl 4
91Forces
92.Nm
93to use IPv4 addresses only.
94.It Fl 6
95Forces
96.Nm
97to use IPv6 addresses only.
98.It Fl D
99Enable debugging on the socket.
100.It Fl d
101Do not attempt to read from stdin.
102.It Fl h
103Prints out
104.Nm
105help.
106.It Fl I Ar length
107Specifies the size of the TCP receive buffer.
108.It Fl i Ar interval
109Specifies a delay time interval between lines of text sent and received.
110Also causes a delay time between connections to multiple ports.
111.It Fl k
112Forces
113.Nm
114to stay listening for another connection after its current connection
115is completed.
116It is an error to use this option without the
117.Fl l
118option.
119.It Fl l
120Used to specify that
121.Nm
122should listen for an incoming connection rather than initiate a
123connection to a remote host.
124It is an error to use this option in conjunction with the
125.Fl p ,
126.Fl s ,
127or
128.Fl z
129options.
130Additionally, any timeouts specified with the
131.Fl w
132option are ignored.
133.It Fl n
134Do not do any DNS or service lookups on any specified addresses,
135hostnames or ports.
136.It Fl O Ar length
137Specifies the size of the TCP send buffer.
138.It Fl P Ar proxy_username
139Specifies a username to present to a proxy server that requires authentication.
140If no username is specified then authentication will not be attempted.
141Proxy authentication is only supported for HTTP CONNECT proxies at present.
142.It Fl p Ar source_port
143Specifies the source port
144.Nm
145should use, subject to privilege restrictions and availability.
146It is an error to use this option in conjunction with the
147.Fl l
148option.
149.It Fl r
150Specifies that source and/or destination ports should be chosen randomly
151instead of sequentially within a range or in the order that the system
152assigns them.
153.It Fl S
154Enables the RFC 2385 TCP MD5 signature option.
155.It Fl s Ar source_ip_address
156Specifies the IP of the interface which is used to send the packets.
157It is an error to use this option in conjunction with the
158.Fl l
159option.
160.It Fl T Ar ToS
161Specifies IP Type of Service (ToS) for the connection.
162Valid values are the tokens
163.Dq lowdelay ,
164.Dq throughput ,
165.Dq reliability ,
166or an 8-bit hexadecimal value preceded by
167.Dq 0x .
168.It Fl t
169Causes
170.Nm
171to send RFC 854 DON'T and WON'T responses to RFC 854 DO and WILL requests.
172This makes it possible to use
173.Nm
174to script telnet sessions.
175.It Fl U
176Specifies to use Unix Domain Sockets.
177.It Fl u
178Use UDP instead of the default option of TCP.
179.It Fl v
180Have
181.Nm
182give more verbose output.
183.It Fl w Ar timeout
184If a connection and stdin are idle for more than
185.Ar timeout
186seconds, then the connection is silently closed.
187The
188.Fl w
189flag has no effect on the
190.Fl l
191option, i.e.\&
192.Nm
193will listen forever for a connection, with or without the
194.Fl w
195flag.
196The default is no timeout.
197.It Fl X Ar proxy_protocol
198Requests that
199.Nm
200should use the specified protocol when talking to the proxy server.
201Supported protocols are
202.Dq 4
203(SOCKS v.4),
204.Dq 5
205(SOCKS v.5)
206and
207.Dq connect
208(HTTPS proxy).
209If the protocol is not specified, SOCKS version 5 is used.
210.It Xo
211.Fl x Ar proxy_address Ns Oo : Ns
212.Ar port Oc
213.Xc
214Requests that
215.Nm
216should connect to
217.Ar hostname
218using a proxy at
219.Ar proxy_address
220and
221.Ar port .
222If
223.Ar port
224is not specified, the well-known port for the proxy protocol is used (1080
225for SOCKS, 3128 for HTTPS).
226.It Fl z
227Specifies that
228.Nm
229should just scan for listening daemons, without sending any data to them.
230It is an error to use this option in conjunction with the
231.Fl l
232option.
233.El
234.Pp
235.Ar hostname
236can be a numerical IP address or a symbolic hostname
237(unless the
238.Fl n
239option is given).
240In general, a hostname must be specified,
241unless the
242.Fl l
243option is given
244(in which case the local host is used).
245.Pp
246.Ar port Ns Op Ar s
247can be single integers or ranges.
248Ranges are in the form nn-mm.
249In general,
250a destination port must be specified,
251unless the
252.Fl U
253option is given
254(in which case a socket must be specified).
255.Sh CLIENT/SERVER MODEL
256It is quite simple to build a very basic client/server model using
257.Nm .
258On one console, start
259.Nm
260listening on a specific port for a connection.
261For example:
262.Pp
263.Dl $ nc -l 1234
264.Pp
265.Nm
266is now listening on port 1234 for a connection.
267On a second console
268.Pq or a second machine ,
269connect to the machine and port being listened on:
270.Pp
271.Dl $ nc 127.0.0.1 1234
272.Pp
273There should now be a connection between the ports.
274Anything typed at the second console will be concatenated to the first,
275and vice-versa.
276After the connection has been set up,
277.Nm
278does not really care which side is being used as a
279.Sq server
280and which side is being used as a
281.Sq client .
282The connection may be terminated using an
283.Dv EOF
284.Pq Sq ^D .
285.Sh DATA TRANSFER
286The example in the previous section can be expanded to build a
287basic data transfer model.
288Any information input into one end of the connection will be output
289to the other end, and input and output can be easily captured in order to
290emulate file transfer.
291.Pp
292Start by using
293.Nm
294to listen on a specific port, with output captured into a file:
295.Pp
296.Dl $ nc -l 1234 \*(Gt filename.out
297.Pp
298Using a second machine, connect to the listening
299.Nm
300process, feeding it the file which is to be transferred:
301.Pp
302.Dl $ nc host.example.com 1234 \*(Lt filename.in
303.Pp
304After the file has been transferred, the connection will close automatically.
305.Sh TALKING TO SERVERS
306It is sometimes useful to talk to servers
307.Dq by hand
308rather than through a user interface.
309It can aid in troubleshooting,
310when it might be necessary to verify what data a server is sending
311in response to commands issued by the client.
312For example, to retrieve the home page of a web site:
313.Bd -literal -offset indent
314$ echo -n "GET / HTTP/1.0\er\en\er\en" | nc host.example.com 80
315.Ed
316.Pp
317Note that this also displays the headers sent by the web server.
318They can be filtered, using a tool such as
319.Xr sed 1 ,
320if necessary.
321.Pp
322More complicated examples can be built up when the user knows the format
323of requests required by the server.
324As another example, an email may be submitted to an SMTP server using:
325.Bd -literal -offset indent
326$ nc localhost 25 \*(Lt\*(Lt EOF
327HELO host.example.com
328MAIL FROM:\*(Ltuser@host.example.com\*(Gt
329RCPT TO:\*(Ltuser2@host.example.com\*(Gt
330DATA
331Body of email.
332\&.
333QUIT
334EOF
335.Ed
336.Sh PORT SCANNING
337It may be useful to know which ports are open and running services on
338a target machine.
339The
340.Fl z
341flag can be used to tell
342.Nm
343to report open ports,
344rather than initiate a connection.
345For example:
346.Bd -literal -offset indent
347$ nc -z host.example.com 20-30
348Connection to host.example.com 22 port [tcp/ssh] succeeded!
349Connection to host.example.com 25 port [tcp/smtp] succeeded!
350.Ed
351.Pp
352The port range was specified to limit the search to ports 20 \- 30.
353.Pp
354Alternatively, it might be useful to know which server software
355is running, and which versions.
356This information is often contained within the greeting banners.
357In order to retrieve these, it is necessary to first make a connection,
358and then break the connection when the banner has been retrieved.
359This can be accomplished by specifying a small timeout with the
360.Fl w
361flag, or perhaps by issuing a
362.Qq Dv QUIT
363command to the server:
364.Bd -literal -offset indent
365$ echo "QUIT" | nc host.example.com 20-30
366SSH-1.99-OpenSSH_3.6.1p2
367Protocol mismatch.
368220 host.example.com IMS SMTP Receiver Version 0.84 Ready
369.Ed
370.Sh EXAMPLES
371Open a TCP connection to port 42 of host.example.com, using port 31337 as
372the source port, with a timeout of 5 seconds:
373.Pp
374.Dl $ nc -p 31337 -w 5 host.example.com 42
375.Pp
376Open a UDP connection to port 53 of host.example.com:
377.Pp
378.Dl $ nc -u host.example.com 53
379.Pp
380Open a TCP connection to port 42 of host.example.com using 10.1.2.3 as the
381IP for the local end of the connection:
382.Pp
383.Dl $ nc -s 10.1.2.3 host.example.com 42
384.Pp
385Create and listen on a Unix Domain Socket:
386.Pp
387.Dl $ nc -lU /var/tmp/dsocket
388.Pp
389Connect to port 42 of host.example.com via an HTTP proxy at 10.2.3.4,
390port 8080.
391This example could also be used by
392.Xr ssh 1 ;
393see the
394.Cm ProxyCommand
395directive in
396.Xr ssh_config 5
397for more information.
398.Pp
399.Dl $ nc -x10.2.3.4:8080 -Xconnect host.example.com 42
400.Pp
401The same example again, this time enabling proxy authentication with username
402.Dq ruser
403if the proxy requires it:
404.Pp
405.Dl $ nc -x10.2.3.4:8080 -Xconnect -Pruser host.example.com 42
406.Sh SEE ALSO
407.Xr cat 1 ,
408.Xr ssh 1
409.Sh AUTHORS
410Original implementation by *Hobbit*
411.Aq hobbit@avian.org .
412.br
413Rewritten with IPv6 support by
414.An Eric Jackson Aq ericj@monkey.org .
415.Sh CAVEATS
416UDP port scans will always succeed
417(i.e. report the port as open),
418rendering the
419.Fl uz
420combination of flags relatively useless.
diff --git a/src/usr.bin/nc/netcat.c b/src/usr.bin/nc/netcat.c
deleted file mode 100644
index 48b2b673ba..0000000000
--- a/src/usr.bin/nc/netcat.c
+++ /dev/null
@@ -1,872 +0,0 @@
1/* $OpenBSD: netcat.c,v 1.91 2008/05/09 09:00:11 markus 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 <netinet/in_systm.h>
41#include <netinet/tcp.h>
42#include <netinet/ip.h>
43#include <arpa/telnet.h>
44
45#include <err.h>
46#include <errno.h>
47#include <netdb.h>
48#include <poll.h>
49#include <stdarg.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <unistd.h>
54#include <fcntl.h>
55#include <limits.h>
56#include "atomicio.h"
57
58#ifndef SUN_LEN
59#define SUN_LEN(su) \
60 (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
61#endif
62
63#define PORT_MAX 65535
64#define PORT_MAX_LEN 6
65
66/* Command Line Options */
67int dflag; /* detached, no stdin */
68unsigned int iflag; /* Interval Flag */
69int jflag; /* use jumbo frames if we can */
70int kflag; /* More than one connect */
71int lflag; /* Bind to local port */
72int nflag; /* Don't do name look up */
73char *Pflag; /* Proxy username */
74char *pflag; /* Localport flag */
75int rflag; /* Random ports flag */
76char *sflag; /* Source Address */
77int tflag; /* Telnet Emulation */
78int uflag; /* UDP - Default to TCP */
79int vflag; /* Verbosity */
80int xflag; /* Socks proxy */
81int zflag; /* Port Scan Flag */
82int Dflag; /* sodebug */
83int Iflag; /* TCP receive buffer size */
84int Oflag; /* TCP send buffer size */
85int Sflag; /* TCP MD5 signature option */
86int Tflag = -1; /* IP Type of Service */
87
88int timeout = -1;
89int family = AF_UNSPEC;
90char *portlist[PORT_MAX+1];
91
92void atelnet(int, unsigned char *, unsigned int);
93void build_ports(char *);
94void help(void);
95int local_listen(char *, char *, struct addrinfo);
96void readwrite(int);
97int remote_connect(const char *, const char *, struct addrinfo);
98int socks_connect(const char *, const char *, struct addrinfo,
99 const char *, const char *, struct addrinfo, int, const char *);
100int udptest(int);
101int unix_connect(char *);
102int unix_listen(char *);
103void set_common_sockopts(int);
104int parse_iptos(char *);
105void usage(int);
106
107int
108main(int argc, char *argv[])
109{
110 int ch, s, ret, socksv;
111 char *host, *uport;
112 struct addrinfo hints;
113 struct servent *sv;
114 socklen_t len;
115 struct sockaddr_storage cliaddr;
116 char *proxy;
117 const char *errstr, *proxyhost = "", *proxyport = NULL;
118 struct addrinfo proxyhints;
119
120 ret = 1;
121 s = 0;
122 socksv = 5;
123 host = NULL;
124 uport = NULL;
125 sv = NULL;
126
127 while ((ch = getopt(argc, argv,
128 "46DdhI:i:jklnO:P:p:rSs:tT:Uuvw:X:x:z")) != -1) {
129 switch (ch) {
130 case '4':
131 family = AF_INET;
132 break;
133 case '6':
134 family = AF_INET6;
135 break;
136 case 'U':
137 family = AF_UNIX;
138 break;
139 case 'X':
140 if (strcasecmp(optarg, "connect") == 0)
141 socksv = -1; /* HTTP proxy CONNECT */
142 else if (strcmp(optarg, "4") == 0)
143 socksv = 4; /* SOCKS v.4 */
144 else if (strcmp(optarg, "5") == 0)
145 socksv = 5; /* SOCKS v.5 */
146 else
147 errx(1, "unsupported proxy protocol");
148 break;
149 case 'd':
150 dflag = 1;
151 break;
152 case 'h':
153 help();
154 break;
155 case 'i':
156 iflag = strtonum(optarg, 0, UINT_MAX, &errstr);
157 if (errstr)
158 errx(1, "interval %s: %s", errstr, optarg);
159 break;
160 case 'j':
161 jflag = 1;
162 break;
163 case 'k':
164 kflag = 1;
165 break;
166 case 'l':
167 lflag = 1;
168 break;
169 case 'n':
170 nflag = 1;
171 break;
172 case 'P':
173 Pflag = optarg;
174 break;
175 case 'p':
176 pflag = optarg;
177 break;
178 case 'r':
179 rflag = 1;
180 break;
181 case 's':
182 sflag = optarg;
183 break;
184 case 't':
185 tflag = 1;
186 break;
187 case 'u':
188 uflag = 1;
189 break;
190 case 'v':
191 vflag = 1;
192 break;
193 case 'w':
194 timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr);
195 if (errstr)
196 errx(1, "timeout %s: %s", errstr, optarg);
197 timeout *= 1000;
198 break;
199 case 'x':
200 xflag = 1;
201 if ((proxy = strdup(optarg)) == NULL)
202 err(1, NULL);
203 break;
204 case 'z':
205 zflag = 1;
206 break;
207 case 'D':
208 Dflag = 1;
209 break;
210 case 'I':
211 Iflag = strtonum(optarg, 1, 65536 << 14, &errstr);
212 if (errstr != NULL)
213 errx(1, "TCP receive window %s: %s",
214 errstr, optarg);
215 break;
216 case 'O':
217 Oflag = strtonum(optarg, 1, 65536 << 14, &errstr);
218 if (errstr != NULL)
219 errx(1, "TCP send window %s: %s",
220 errstr, optarg);
221 break;
222 case 'S':
223 Sflag = 1;
224 break;
225 case 'T':
226 Tflag = parse_iptos(optarg);
227 break;
228 default:
229 usage(1);
230 }
231 }
232 argc -= optind;
233 argv += optind;
234
235 /* Cruft to make sure options are clean, and used properly. */
236 if (argv[0] && !argv[1] && family == AF_UNIX) {
237 if (uflag)
238 errx(1, "cannot use -u and -U");
239 host = argv[0];
240 uport = NULL;
241 } else if (argv[0] && !argv[1]) {
242 if (!lflag)
243 usage(1);
244 uport = argv[0];
245 host = NULL;
246 } else if (argv[0] && argv[1]) {
247 host = argv[0];
248 uport = argv[1];
249 } else
250 usage(1);
251
252 if (lflag && sflag)
253 errx(1, "cannot use -s and -l");
254 if (lflag && pflag)
255 errx(1, "cannot use -p and -l");
256 if (lflag && zflag)
257 errx(1, "cannot use -z and -l");
258 if (!lflag && kflag)
259 errx(1, "must use -l with -k");
260
261 /* Initialize addrinfo structure. */
262 if (family != AF_UNIX) {
263 memset(&hints, 0, sizeof(struct addrinfo));
264 hints.ai_family = family;
265 hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
266 hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
267 if (nflag)
268 hints.ai_flags |= AI_NUMERICHOST;
269 }
270
271 if (xflag) {
272 if (uflag)
273 errx(1, "no proxy support for UDP mode");
274
275 if (lflag)
276 errx(1, "no proxy support for listen");
277
278 if (family == AF_UNIX)
279 errx(1, "no proxy support for unix sockets");
280
281 /* XXX IPv6 transport to proxy would probably work */
282 if (family == AF_INET6)
283 errx(1, "no proxy support for IPv6");
284
285 if (sflag)
286 errx(1, "no proxy support for local source address");
287
288 proxyhost = strsep(&proxy, ":");
289 proxyport = proxy;
290
291 memset(&proxyhints, 0, sizeof(struct addrinfo));
292 proxyhints.ai_family = family;
293 proxyhints.ai_socktype = SOCK_STREAM;
294 proxyhints.ai_protocol = IPPROTO_TCP;
295 if (nflag)
296 proxyhints.ai_flags |= AI_NUMERICHOST;
297 }
298
299 if (lflag) {
300 int connfd;
301 ret = 0;
302
303 if (family == AF_UNIX)
304 s = unix_listen(host);
305
306 /* Allow only one connection at a time, but stay alive. */
307 for (;;) {
308 if (family != AF_UNIX)
309 s = local_listen(host, uport, hints);
310 if (s < 0)
311 err(1, NULL);
312 /*
313 * For UDP, we will use recvfrom() initially
314 * to wait for a caller, then use the regular
315 * functions to talk to the caller.
316 */
317 if (uflag) {
318 int rv, plen;
319 char buf[8192];
320 struct sockaddr_storage z;
321
322 len = sizeof(z);
323 plen = jflag ? 8192 : 1024;
324 rv = recvfrom(s, buf, plen, MSG_PEEK,
325 (struct sockaddr *)&z, &len);
326 if (rv < 0)
327 err(1, "recvfrom");
328
329 rv = connect(s, (struct sockaddr *)&z, len);
330 if (rv < 0)
331 err(1, "connect");
332
333 connfd = s;
334 } else {
335 len = sizeof(cliaddr);
336 connfd = accept(s, (struct sockaddr *)&cliaddr,
337 &len);
338 }
339
340 readwrite(connfd);
341 close(connfd);
342 if (family != AF_UNIX)
343 close(s);
344
345 if (!kflag)
346 break;
347 }
348 } else if (family == AF_UNIX) {
349 ret = 0;
350
351 if ((s = unix_connect(host)) > 0 && !zflag) {
352 readwrite(s);
353 close(s);
354 } else
355 ret = 1;
356
357 exit(ret);
358
359 } else {
360 int i = 0;
361
362 /* Construct the portlist[] array. */
363 build_ports(uport);
364
365 /* Cycle through portlist, connecting to each port. */
366 for (i = 0; portlist[i] != NULL; i++) {
367 if (s)
368 close(s);
369
370 if (xflag)
371 s = socks_connect(host, portlist[i], hints,
372 proxyhost, proxyport, proxyhints, socksv,
373 Pflag);
374 else
375 s = remote_connect(host, portlist[i], hints);
376
377 if (s < 0)
378 continue;
379
380 ret = 0;
381 if (vflag || zflag) {
382 /* For UDP, make sure we are connected. */
383 if (uflag) {
384 if (udptest(s) == -1) {
385 ret = 1;
386 continue;
387 }
388 }
389
390 /* Don't look up port if -n. */
391 if (nflag)
392 sv = NULL;
393 else {
394 sv = getservbyport(
395 ntohs(atoi(portlist[i])),
396 uflag ? "udp" : "tcp");
397 }
398
399 printf("Connection to %s %s port [%s/%s] succeeded!\n",
400 host, portlist[i], uflag ? "udp" : "tcp",
401 sv ? sv->s_name : "*");
402 }
403 if (!zflag)
404 readwrite(s);
405 }
406 }
407
408 if (s)
409 close(s);
410
411 exit(ret);
412}
413
414/*
415 * unix_connect()
416 * Returns a socket connected to a local unix socket. Returns -1 on failure.
417 */
418int
419unix_connect(char *path)
420{
421 struct sockaddr_un sun;
422 int s;
423
424 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
425 return (-1);
426 (void)fcntl(s, F_SETFD, 1);
427
428 memset(&sun, 0, sizeof(struct sockaddr_un));
429 sun.sun_family = AF_UNIX;
430
431 if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
432 sizeof(sun.sun_path)) {
433 close(s);
434 errno = ENAMETOOLONG;
435 return (-1);
436 }
437 if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
438 close(s);
439 return (-1);
440 }
441 return (s);
442
443}
444
445/*
446 * unix_listen()
447 * Create a unix domain socket, and listen on it.
448 */
449int
450unix_listen(char *path)
451{
452 struct sockaddr_un sun;
453 int s;
454
455 /* Create unix domain socket. */
456 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
457 return (-1);
458
459 memset(&sun, 0, sizeof(struct sockaddr_un));
460 sun.sun_family = AF_UNIX;
461
462 if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
463 sizeof(sun.sun_path)) {
464 close(s);
465 errno = ENAMETOOLONG;
466 return (-1);
467 }
468
469 if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
470 close(s);
471 return (-1);
472 }
473
474 if (listen(s, 5) < 0) {
475 close(s);
476 return (-1);
477 }
478 return (s);
479}
480
481/*
482 * remote_connect()
483 * Returns a socket connected to a remote host. Properly binds to a local
484 * port or source address if needed. Returns -1 on failure.
485 */
486int
487remote_connect(const char *host, const char *port, struct addrinfo hints)
488{
489 struct addrinfo *res, *res0;
490 int s, error, on = 1;
491
492 if ((error = getaddrinfo(host, port, &hints, &res)))
493 errx(1, "getaddrinfo: %s", gai_strerror(error));
494
495 res0 = res;
496 do {
497 if ((s = socket(res0->ai_family, res0->ai_socktype,
498 res0->ai_protocol)) < 0)
499 continue;
500
501 /* Bind to a local port or source address if specified. */
502 if (sflag || pflag) {
503 struct addrinfo ahints, *ares;
504
505 /* try SO_BINDANY, but don't insist */
506 setsockopt(s, SOL_SOCKET, SO_BINDANY, &on, sizeof(on));
507 memset(&ahints, 0, sizeof(struct addrinfo));
508 ahints.ai_family = res0->ai_family;
509 ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
510 ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
511 ahints.ai_flags = AI_PASSIVE;
512 if ((error = getaddrinfo(sflag, pflag, &ahints, &ares)))
513 errx(1, "getaddrinfo: %s", gai_strerror(error));
514
515 if (bind(s, (struct sockaddr *)ares->ai_addr,
516 ares->ai_addrlen) < 0)
517 errx(1, "bind failed: %s", strerror(errno));
518 freeaddrinfo(ares);
519 }
520
521 set_common_sockopts(s);
522
523 if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
524 break;
525 else if (vflag)
526 warn("connect to %s port %s (%s) failed", host, port,
527 uflag ? "udp" : "tcp");
528
529 close(s);
530 s = -1;
531 } while ((res0 = res0->ai_next) != NULL);
532
533 freeaddrinfo(res);
534
535 return (s);
536}
537
538/*
539 * local_listen()
540 * Returns a socket listening on a local port, binds to specified source
541 * address. Returns -1 on failure.
542 */
543int
544local_listen(char *host, char *port, struct addrinfo hints)
545{
546 struct addrinfo *res, *res0;
547 int s, ret, x = 1;
548 int error;
549
550 /* Allow nodename to be null. */
551 hints.ai_flags |= AI_PASSIVE;
552
553 /*
554 * In the case of binding to a wildcard address
555 * default to binding to an ipv4 address.
556 */
557 if (host == NULL && hints.ai_family == AF_UNSPEC)
558 hints.ai_family = AF_INET;
559
560 if ((error = getaddrinfo(host, port, &hints, &res)))
561 errx(1, "getaddrinfo: %s", gai_strerror(error));
562
563 res0 = res;
564 do {
565 if ((s = socket(res0->ai_family, res0->ai_socktype,
566 res0->ai_protocol)) < 0)
567 continue;
568
569 ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));
570 if (ret == -1)
571 err(1, NULL);
572
573 set_common_sockopts(s);
574
575 if (bind(s, (struct sockaddr *)res0->ai_addr,
576 res0->ai_addrlen) == 0)
577 break;
578
579 close(s);
580 s = -1;
581 } while ((res0 = res0->ai_next) != NULL);
582
583 if (!uflag && s != -1) {
584 if (listen(s, 1) < 0)
585 err(1, "listen");
586 }
587
588 freeaddrinfo(res);
589
590 return (s);
591}
592
593/*
594 * readwrite()
595 * Loop that polls on the network file descriptor and stdin.
596 */
597void
598readwrite(int nfd)
599{
600 struct pollfd pfd[2];
601 unsigned char buf[8192];
602 int n, wfd = fileno(stdin);
603 int lfd = fileno(stdout);
604 int plen;
605
606 plen = jflag ? 8192 : 1024;
607
608 /* Setup Network FD */
609 pfd[0].fd = nfd;
610 pfd[0].events = POLLIN;
611
612 /* Set up STDIN FD. */
613 pfd[1].fd = wfd;
614 pfd[1].events = POLLIN;
615
616 while (pfd[0].fd != -1) {
617 if (iflag)
618 sleep(iflag);
619
620 if ((n = poll(pfd, 2 - dflag, timeout)) < 0) {
621 close(nfd);
622 err(1, "Polling Error");
623 }
624
625 if (n == 0)
626 return;
627
628 if (pfd[0].revents & POLLIN) {
629 if ((n = read(nfd, buf, plen)) < 0)
630 return;
631 else if (n == 0) {
632 shutdown(nfd, SHUT_RD);
633 pfd[0].fd = -1;
634 pfd[0].events = 0;
635 } else {
636 if (tflag)
637 atelnet(nfd, buf, n);
638 if (atomicio(vwrite, lfd, buf, n) != n)
639 return;
640 }
641 }
642
643 if (!dflag && pfd[1].revents & POLLIN) {
644 if ((n = read(wfd, buf, plen)) < 0)
645 return;
646 else if (n == 0) {
647 shutdown(nfd, SHUT_WR);
648 pfd[1].fd = -1;
649 pfd[1].events = 0;
650 } else {
651 if (atomicio(vwrite, nfd, buf, n) != n)
652 return;
653 }
654 }
655 }
656}
657
658/* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */
659void
660atelnet(int nfd, unsigned char *buf, unsigned int size)
661{
662 unsigned char *p, *end;
663 unsigned char obuf[4];
664
665 end = buf + size;
666 obuf[0] = '\0';
667
668 for (p = buf; p < end; p++) {
669 if (*p != IAC)
670 break;
671
672 obuf[0] = IAC;
673 p++;
674 if ((*p == WILL) || (*p == WONT))
675 obuf[1] = DONT;
676 if ((*p == DO) || (*p == DONT))
677 obuf[1] = WONT;
678 if (obuf) {
679 p++;
680 obuf[2] = *p;
681 obuf[3] = '\0';
682 if (atomicio(vwrite, nfd, obuf, 3) != 3)
683 warn("Write Error!");
684 obuf[0] = '\0';
685 }
686 }
687}
688
689/*
690 * build_ports()
691 * Build an array or ports in portlist[], listing each port
692 * that we should try to connect to.
693 */
694void
695build_ports(char *p)
696{
697 const char *errstr;
698 char *n;
699 int hi, lo, cp;
700 int x = 0;
701
702 if ((n = strchr(p, '-')) != NULL) {
703 if (lflag)
704 errx(1, "Cannot use -l with multiple ports!");
705
706 *n = '\0';
707 n++;
708
709 /* Make sure the ports are in order: lowest->highest. */
710 hi = strtonum(n, 1, PORT_MAX, &errstr);
711 if (errstr)
712 errx(1, "port number %s: %s", errstr, n);
713 lo = strtonum(p, 1, PORT_MAX, &errstr);
714 if (errstr)
715 errx(1, "port number %s: %s", errstr, p);
716
717 if (lo > hi) {
718 cp = hi;
719 hi = lo;
720 lo = cp;
721 }
722
723 /* Load ports sequentially. */
724 for (cp = lo; cp <= hi; cp++) {
725 portlist[x] = calloc(1, PORT_MAX_LEN);
726 if (portlist[x] == NULL)
727 err(1, NULL);
728 snprintf(portlist[x], PORT_MAX_LEN, "%d", cp);
729 x++;
730 }
731
732 /* Randomly swap ports. */
733 if (rflag) {
734 int y;
735 char *c;
736
737 for (x = 0; x <= (hi - lo); x++) {
738 y = (arc4random() & 0xFFFF) % (hi - lo);
739 c = portlist[x];
740 portlist[x] = portlist[y];
741 portlist[y] = c;
742 }
743 }
744 } else {
745 hi = strtonum(p, 1, PORT_MAX, &errstr);
746 if (errstr)
747 errx(1, "port number %s: %s", errstr, p);
748 portlist[0] = calloc(1, PORT_MAX_LEN);
749 if (portlist[0] == NULL)
750 err(1, NULL);
751 portlist[0] = p;
752 }
753}
754
755/*
756 * udptest()
757 * Do a few writes to see if the UDP port is there.
758 * XXX - Better way of doing this? Doesn't work for IPv6.
759 * Also fails after around 100 ports checked.
760 */
761int
762udptest(int s)
763{
764 int i, ret;
765
766 for (i = 0; i <= 3; i++) {
767 if (write(s, "X", 1) == 1)
768 ret = 1;
769 else
770 ret = -1;
771 }
772 return (ret);
773}
774
775void
776set_common_sockopts(int s)
777{
778 int x = 1;
779
780 if (Sflag) {
781 if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG,
782 &x, sizeof(x)) == -1)
783 err(1, NULL);
784 }
785 if (Dflag) {
786 if (setsockopt(s, SOL_SOCKET, SO_DEBUG,
787 &x, sizeof(x)) == -1)
788 err(1, NULL);
789 }
790 if (jflag) {
791 if (setsockopt(s, SOL_SOCKET, SO_JUMBO,
792 &x, sizeof(x)) == -1)
793 err(1, NULL);
794 }
795 if (Tflag != -1) {
796 if (setsockopt(s, IPPROTO_IP, IP_TOS,
797 &Tflag, sizeof(Tflag)) == -1)
798 err(1, "set IP ToS");
799 }
800 if (Iflag) {
801 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
802 &Iflag, sizeof(Iflag)) == -1)
803 err(1, "set TCP receive buffer size");
804 }
805 if (Oflag) {
806 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
807 &Oflag, sizeof(Oflag)) == -1)
808 err(1, "set TCP send buffer size");
809 }
810}
811
812int
813parse_iptos(char *s)
814{
815 int tos = -1;
816
817 if (strcmp(s, "lowdelay") == 0)
818 return (IPTOS_LOWDELAY);
819 if (strcmp(s, "throughput") == 0)
820 return (IPTOS_THROUGHPUT);
821 if (strcmp(s, "reliability") == 0)
822 return (IPTOS_RELIABILITY);
823
824 if (sscanf(s, "0x%x", &tos) != 1 || tos < 0 || tos > 0xff)
825 errx(1, "invalid IP Type of Service");
826 return (tos);
827}
828
829void
830help(void)
831{
832 usage(0);
833 fprintf(stderr, "\tCommand Summary:\n\
834 \t-4 Use IPv4\n\
835 \t-6 Use IPv6\n\
836 \t-D Enable the debug socket option\n\
837 \t-d Detach from stdin\n\
838 \t-h This help text\n\
839 \t-I length TCP receive buffer length\n\
840 \t-i secs\t Delay interval for lines sent, ports scanned\n\
841 \t-k Keep inbound sockets open for multiple connects\n\
842 \t-l Listen mode, for inbound connects\n\
843 \t-n Suppress name/port resolutions\n\
844 \t-O length TCP send buffer length\n\
845 \t-P proxyuser\tUsername for proxy authentication\n\
846 \t-p port\t Specify local port for remote connects\n\
847 \t-r Randomize remote ports\n\
848 \t-S Enable the TCP MD5 signature option\n\
849 \t-s addr\t Local source address\n\
850 \t-T ToS\t Set IP Type of Service\n\
851 \t-t Answer TELNET negotiation\n\
852 \t-U Use UNIX domain socket\n\
853 \t-u UDP mode\n\
854 \t-v Verbose\n\
855 \t-w secs\t Timeout for connects and final net reads\n\
856 \t-X proto Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\
857 \t-x addr[:port]\tSpecify proxy address and port\n\
858 \t-z Zero-I/O mode [used for scanning]\n\
859 Port numbers can be individual or ranges: lo-hi [inclusive]\n");
860 exit(1);
861}
862
863void
864usage(int ret)
865{
866 fprintf(stderr, "usage: nc [-46DdhklnrStUuvz] [-I receive_buffer_len] [-i interval]\n");
867 fprintf(stderr, "\t [-O send_buffer_len] [-P proxy_username] [-p source_port]\n");
868 fprintf(stderr, "\t [-s source_ip_address] [-T ToS] [-w timeout] [-X proxy_protocol]\n");
869 fprintf(stderr, "\t [-x proxy_address[:port]] [hostname] [port[s]]\n");
870 if (ret)
871 exit(1);
872}
diff --git a/src/usr.bin/nc/socks.c b/src/usr.bin/nc/socks.c
deleted file mode 100644
index da7bd0c60e..0000000000
--- a/src/usr.bin/nc/socks.c
+++ /dev/null
@@ -1,326 +0,0 @@
1/* $OpenBSD: socks.c,v 1.17 2006/09/25 04:51:20 ray Exp $ */
2
3/*
4 * Copyright (c) 1999 Niklas Hallqvist. All rights reserved.
5 * Copyright (c) 2004, 2005 Damien Miller. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <netinet/in.h>
31#include <arpa/inet.h>
32
33#include <err.h>
34#include <errno.h>
35#include <netdb.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40#include <resolv.h>
41#include <readpassphrase.h>
42#include "atomicio.h"
43
44#define SOCKS_PORT "1080"
45#define HTTP_PROXY_PORT "3128"
46#define HTTP_MAXHDRS 64
47#define SOCKS_V5 5
48#define SOCKS_V4 4
49#define SOCKS_NOAUTH 0
50#define SOCKS_NOMETHOD 0xff
51#define SOCKS_CONNECT 1
52#define SOCKS_IPV4 1
53#define SOCKS_DOMAIN 3
54#define SOCKS_IPV6 4
55
56int remote_connect(const char *, const char *, struct addrinfo);
57int socks_connect(const char *, const char *, struct addrinfo,
58 const char *, const char *, struct addrinfo, int,
59 const char *);
60
61static int
62decode_addrport(const char *h, const char *p, struct sockaddr *addr,
63 socklen_t addrlen, int v4only, int numeric)
64{
65 int r;
66 struct addrinfo hints, *res;
67
68 bzero(&hints, sizeof(hints));
69 hints.ai_family = v4only ? PF_INET : PF_UNSPEC;
70 hints.ai_flags = numeric ? AI_NUMERICHOST : 0;
71 hints.ai_socktype = SOCK_STREAM;
72 r = getaddrinfo(h, p, &hints, &res);
73 /* Don't fatal when attempting to convert a numeric address */
74 if (r != 0) {
75 if (!numeric) {
76 errx(1, "getaddrinfo(\"%.64s\", \"%.64s\"): %s", h, p,
77 gai_strerror(r));
78 }
79 return (-1);
80 }
81 if (addrlen < res->ai_addrlen) {
82 freeaddrinfo(res);
83 errx(1, "internal error: addrlen < res->ai_addrlen");
84 }
85 memcpy(addr, res->ai_addr, res->ai_addrlen);
86 freeaddrinfo(res);
87 return (0);
88}
89
90static int
91proxy_read_line(int fd, char *buf, size_t bufsz)
92{
93 size_t off;
94
95 for(off = 0;;) {
96 if (off >= bufsz)
97 errx(1, "proxy read too long");
98 if (atomicio(read, fd, buf + off, 1) != 1)
99 err(1, "proxy read");
100 /* Skip CR */
101 if (buf[off] == '\r')
102 continue;
103 if (buf[off] == '\n') {
104 buf[off] = '\0';
105 break;
106 }
107 off++;
108 }
109 return (off);
110}
111
112static const char *
113getproxypass(const char *proxyuser, const char *proxyhost)
114{
115 char prompt[512];
116 static char pw[256];
117
118 snprintf(prompt, sizeof(prompt), "Proxy password for %s@%s: ",
119 proxyuser, proxyhost);
120 if (readpassphrase(prompt, pw, sizeof(pw), RPP_REQUIRE_TTY) == NULL)
121 errx(1, "Unable to read proxy passphrase");
122 return (pw);
123}
124
125int
126socks_connect(const char *host, const char *port,
127 struct addrinfo hints __attribute__ ((__unused__)),
128 const char *proxyhost, const char *proxyport, struct addrinfo proxyhints,
129 int socksv, const char *proxyuser)
130{
131 int proxyfd, r, authretry = 0;
132 size_t hlen, wlen;
133 unsigned char buf[1024];
134 size_t cnt;
135 struct sockaddr_storage addr;
136 struct sockaddr_in *in4 = (struct sockaddr_in *)&addr;
137 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr;
138 in_port_t serverport;
139 const char *proxypass = NULL;
140
141 if (proxyport == NULL)
142 proxyport = (socksv == -1) ? HTTP_PROXY_PORT : SOCKS_PORT;
143
144 /* Abuse API to lookup port */
145 if (decode_addrport("0.0.0.0", port, (struct sockaddr *)&addr,
146 sizeof(addr), 1, 1) == -1)
147 errx(1, "unknown port \"%.64s\"", port);
148 serverport = in4->sin_port;
149
150 again:
151 if (authretry++ > 3)
152 errx(1, "Too many authentication failures");
153
154 proxyfd = remote_connect(proxyhost, proxyport, proxyhints);
155
156 if (proxyfd < 0)
157 return (-1);
158
159 if (socksv == 5) {
160 if (decode_addrport(host, port, (struct sockaddr *)&addr,
161 sizeof(addr), 0, 1) == -1)
162 addr.ss_family = 0; /* used in switch below */
163
164 /* Version 5, one method: no authentication */
165 buf[0] = SOCKS_V5;
166 buf[1] = 1;
167 buf[2] = SOCKS_NOAUTH;
168 cnt = atomicio(vwrite, proxyfd, buf, 3);
169 if (cnt != 3)
170 err(1, "write failed (%d/3)", cnt);
171
172 cnt = atomicio(read, proxyfd, buf, 2);
173 if (cnt != 2)
174 err(1, "read failed (%d/3)", cnt);
175
176 if (buf[1] == SOCKS_NOMETHOD)
177 errx(1, "authentication method negotiation failed");
178
179 switch (addr.ss_family) {
180 case 0:
181 /* Version 5, connect: domain name */
182
183 /* Max domain name length is 255 bytes */
184 hlen = strlen(host);
185 if (hlen > 255)
186 errx(1, "host name too long for SOCKS5");
187 buf[0] = SOCKS_V5;
188 buf[1] = SOCKS_CONNECT;
189 buf[2] = 0;
190 buf[3] = SOCKS_DOMAIN;
191 buf[4] = hlen;
192 memcpy(buf + 5, host, hlen);
193 memcpy(buf + 5 + hlen, &serverport, sizeof serverport);
194 wlen = 7 + hlen;
195 break;
196 case AF_INET:
197 /* Version 5, connect: IPv4 address */
198 buf[0] = SOCKS_V5;
199 buf[1] = SOCKS_CONNECT;
200 buf[2] = 0;
201 buf[3] = SOCKS_IPV4;
202 memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr);
203 memcpy(buf + 8, &in4->sin_port, sizeof in4->sin_port);
204 wlen = 10;
205 break;
206 case AF_INET6:
207 /* Version 5, connect: IPv6 address */
208 buf[0] = SOCKS_V5;
209 buf[1] = SOCKS_CONNECT;
210 buf[2] = 0;
211 buf[3] = SOCKS_IPV6;
212 memcpy(buf + 4, &in6->sin6_addr, sizeof in6->sin6_addr);
213 memcpy(buf + 20, &in6->sin6_port,
214 sizeof in6->sin6_port);
215 wlen = 22;
216 break;
217 default:
218 errx(1, "internal error: silly AF");
219 }
220
221 cnt = atomicio(vwrite, proxyfd, buf, wlen);
222 if (cnt != wlen)
223 err(1, "write failed (%d/%d)", cnt, wlen);
224
225 cnt = atomicio(read, proxyfd, buf, 10);
226 if (cnt != 10)
227 err(1, "read failed (%d/10)", cnt);
228 if (buf[1] != 0)
229 errx(1, "connection failed, SOCKS error %d", buf[1]);
230 } else if (socksv == 4) {
231 /* This will exit on lookup failure */
232 decode_addrport(host, port, (struct sockaddr *)&addr,
233 sizeof(addr), 1, 0);
234
235 /* Version 4 */
236 buf[0] = SOCKS_V4;
237 buf[1] = SOCKS_CONNECT; /* connect */
238 memcpy(buf + 2, &in4->sin_port, sizeof in4->sin_port);
239 memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr);
240 buf[8] = 0; /* empty username */
241 wlen = 9;
242
243 cnt = atomicio(vwrite, proxyfd, buf, wlen);
244 if (cnt != wlen)
245 err(1, "write failed (%d/%d)", cnt, wlen);
246
247 cnt = atomicio(read, proxyfd, buf, 8);
248 if (cnt != 8)
249 err(1, "read failed (%d/8)", cnt);
250 if (buf[1] != 90)
251 errx(1, "connection failed, SOCKS error %d", buf[1]);
252 } else if (socksv == -1) {
253 /* HTTP proxy CONNECT */
254
255 /* Disallow bad chars in hostname */
256 if (strcspn(host, "\r\n\t []:") != strlen(host))
257 errx(1, "Invalid hostname");
258
259 /* Try to be sane about numeric IPv6 addresses */
260 if (strchr(host, ':') != NULL) {
261 r = snprintf(buf, sizeof(buf),
262 "CONNECT [%s]:%d HTTP/1.0\r\n",
263 host, ntohs(serverport));
264 } else {
265 r = snprintf(buf, sizeof(buf),
266 "CONNECT %s:%d HTTP/1.0\r\n",
267 host, ntohs(serverport));
268 }
269 if (r == -1 || (size_t)r >= sizeof(buf))
270 errx(1, "hostname too long");
271 r = strlen(buf);
272
273 cnt = atomicio(vwrite, proxyfd, buf, r);
274 if (cnt != r)
275 err(1, "write failed (%d/%d)", cnt, r);
276
277 if (authretry > 1) {
278 char resp[1024];
279
280 proxypass = getproxypass(proxyuser, proxyhost);
281 r = snprintf(buf, sizeof(buf), "%s:%s",
282 proxyuser, proxypass);
283 if (r == -1 || (size_t)r >= sizeof(buf) ||
284 b64_ntop(buf, strlen(buf), resp,
285 sizeof(resp)) == -1)
286 errx(1, "Proxy username/password too long");
287 r = snprintf(buf, sizeof(buf), "Proxy-Authorization: "
288 "Basic %s\r\n", resp);
289 if (r == -1 || (size_t)r >= sizeof(buf))
290 errx(1, "Proxy auth response too long");
291 r = strlen(buf);
292 if ((cnt = atomicio(vwrite, proxyfd, buf, r)) != r)
293 err(1, "write failed (%d/%d)", cnt, r);
294 }
295
296 /* Terminate headers */
297 if ((r = atomicio(vwrite, proxyfd, "\r\n", 2)) != 2)
298 err(1, "write failed (2/%d)", r);
299
300 /* Read status reply */
301 proxy_read_line(proxyfd, buf, sizeof(buf));
302 if (proxyuser != NULL &&
303 strncmp(buf, "HTTP/1.0 407 ", 12) == 0) {
304 if (authretry > 1) {
305 fprintf(stderr, "Proxy authentication "
306 "failed\n");
307 }
308 close(proxyfd);
309 goto again;
310 } else if (strncmp(buf, "HTTP/1.0 200 ", 12) != 0 &&
311 strncmp(buf, "HTTP/1.1 200 ", 12) != 0)
312 errx(1, "Proxy error: \"%s\"", buf);
313
314 /* Headers continue until we hit an empty line */
315 for (r = 0; r < HTTP_MAXHDRS; r++) {
316 proxy_read_line(proxyfd, buf, sizeof(buf));
317 if (*buf == '\0')
318 break;
319 }
320 if (*buf != '\0')
321 errx(1, "Too many proxy headers received");
322 } else
323 errx(1, "Unknown proxy protocol %d", socksv);
324
325 return (proxyfd);
326}