diff options
Diffstat (limited to 'regress')
-rw-r--r-- | regress/Makefile | 2 | ||||
-rw-r--r-- | regress/multiplex.sh | 23 | ||||
-rw-r--r-- | regress/netcat.c | 1638 |
3 files changed, 1644 insertions, 19 deletions
diff --git a/regress/Makefile b/regress/Makefile index 27c4e79e1..ac1ee2d5f 100644 --- a/regress/Makefile +++ b/regress/Makefile | |||
@@ -92,7 +92,7 @@ CLEANFILES= t2.out t3.out t6.out1 t6.out2 t7.out t7.out.pub copy.1 copy.2 \ | |||
92 | regress.log failed-regress.log ssh-log-wrapper.sh \ | 92 | regress.log failed-regress.log ssh-log-wrapper.sh \ |
93 | sftp-server.sh sftp-server.log sftp.log setuid-allowed \ | 93 | sftp-server.sh sftp-server.log sftp.log setuid-allowed \ |
94 | data ed25519-agent ed25519-agent.pub key.ed25519-512 \ | 94 | data ed25519-agent ed25519-agent.pub key.ed25519-512 \ |
95 | key.ed25519-512.pub | 95 | key.ed25519-512.pub netcat |
96 | 96 | ||
97 | SUDO_CLEAN+= /var/run/testdata_${USER} /var/run/keycommand_${USER} | 97 | SUDO_CLEAN+= /var/run/testdata_${USER} /var/run/keycommand_${USER} |
98 | 98 | ||
diff --git a/regress/multiplex.sh b/regress/multiplex.sh index c75dee900..617615355 100644 --- a/regress/multiplex.sh +++ b/regress/multiplex.sh | |||
@@ -5,20 +5,7 @@ CTL=/tmp/openssh.regress.ctl-sock.$$ | |||
5 | 5 | ||
6 | tid="connection multiplexing" | 6 | tid="connection multiplexing" |
7 | 7 | ||
8 | if have_prog nc ; then | 8 | NC=$OBJ/netcat |
9 | if nc -h 2>&1 | grep -- -N >/dev/null; then | ||
10 | NC="nc -N"; | ||
11 | elif nc -h 2>&1 | grep -- "-U.*Use UNIX" >/dev/null ; then | ||
12 | NC="nc" | ||
13 | else | ||
14 | echo "nc is incompatible" | ||
15 | fi | ||
16 | fi | ||
17 | |||
18 | if test -z "$NC" ; then | ||
19 | echo "skipped (no compatible nc found)" | ||
20 | exit 0 | ||
21 | fi | ||
22 | 9 | ||
23 | trace "will use ProxyCommand $proxycmd" | 10 | trace "will use ProxyCommand $proxycmd" |
24 | if config_defined DISABLE_FD_PASSING ; then | 11 | if config_defined DISABLE_FD_PASSING ; then |
@@ -90,20 +77,20 @@ cmp ${DATA} ${COPY} || fail "scp: corrupted copy of ${DATA}" | |||
90 | rm -f ${COPY} | 77 | rm -f ${COPY} |
91 | verbose "test $tid: forward" | 78 | verbose "test $tid: forward" |
92 | trace "forward over TCP/IP and check result" | 79 | trace "forward over TCP/IP and check result" |
93 | $NC -l 127.0.0.1 $((${PORT} + 1)) < ${DATA} > /dev/null & | 80 | $NC -N -l 127.0.0.1 $((${PORT} + 1)) < ${DATA} > /dev/null & |
94 | netcat_pid=$! | 81 | netcat_pid=$! |
95 | ${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L127.0.0.1:$((${PORT} + 2)):127.0.0.1:$((${PORT} + 1)) otherhost >>$TEST_SSH_LOGFILE 2>&1 | 82 | ${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L127.0.0.1:$((${PORT} + 2)):127.0.0.1:$((${PORT} + 1)) otherhost >>$TEST_SSH_LOGFILE 2>&1 |
96 | $NC -d 127.0.0.1 $((${PORT} + 2)) > ${COPY} < /dev/null | 83 | $NC 127.0.0.1 $((${PORT} + 2)) < /dev/null > ${COPY} |
97 | cmp ${DATA} ${COPY} || fail "ssh: corrupted copy of ${DATA}" | 84 | cmp ${DATA} ${COPY} || fail "ssh: corrupted copy of ${DATA}" |
98 | kill $netcat_pid 2>/dev/null | 85 | kill $netcat_pid 2>/dev/null |
99 | rm -f ${COPY} $OBJ/unix-[123].fwd | 86 | rm -f ${COPY} $OBJ/unix-[123].fwd |
100 | 87 | ||
101 | trace "forward over UNIX and check result" | 88 | trace "forward over UNIX and check result" |
102 | $NC -Ul $OBJ/unix-1.fwd < ${DATA} > /dev/null & | 89 | $NC -N -Ul $OBJ/unix-1.fwd < ${DATA} > /dev/null & |
103 | netcat_pid=$! | 90 | netcat_pid=$! |
104 | ${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L$OBJ/unix-2.fwd:$OBJ/unix-1.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1 | 91 | ${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L$OBJ/unix-2.fwd:$OBJ/unix-1.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1 |
105 | ${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R$OBJ/unix-3.fwd:$OBJ/unix-2.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1 | 92 | ${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R$OBJ/unix-3.fwd:$OBJ/unix-2.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1 |
106 | $NC -d -U $OBJ/unix-3.fwd > ${COPY} < /dev/null | 93 | $NC -U $OBJ/unix-3.fwd < /dev/null > ${COPY} |
107 | cmp ${DATA} ${COPY} || fail "ssh: corrupted copy of ${DATA}" | 94 | cmp ${DATA} ${COPY} || fail "ssh: corrupted copy of ${DATA}" |
108 | kill $netcat_pid 2>/dev/null | 95 | kill $netcat_pid 2>/dev/null |
109 | rm -f ${COPY} $OBJ/unix-[123].fwd | 96 | rm -f ${COPY} $OBJ/unix-[123].fwd |
diff --git a/regress/netcat.c b/regress/netcat.c new file mode 100644 index 000000000..c14d8164c --- /dev/null +++ b/regress/netcat.c | |||
@@ -0,0 +1,1638 @@ | |||
1 | /* $OpenBSD: netcat.c,v 1.126 2014/10/30 16:08:31 tedu 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 "includes.h" | ||
35 | |||
36 | #include <sys/types.h> | ||
37 | #include <sys/socket.h> | ||
38 | #include <sys/time.h> | ||
39 | #include <sys/uio.h> | ||
40 | #include <sys/un.h> | ||
41 | |||
42 | #include <netinet/in.h> | ||
43 | #include <netinet/tcp.h> | ||
44 | #include <netinet/ip.h> | ||
45 | #include <arpa/telnet.h> | ||
46 | |||
47 | #include <err.h> | ||
48 | #include <errno.h> | ||
49 | #include <netdb.h> | ||
50 | #include <poll.h> | ||
51 | #include <stdarg.h> | ||
52 | #include <stdio.h> | ||
53 | #include <stdlib.h> | ||
54 | #include <string.h> | ||
55 | #include <unistd.h> | ||
56 | #include <fcntl.h> | ||
57 | #include <limits.h> | ||
58 | #include "atomicio.h" | ||
59 | |||
60 | #ifndef SUN_LEN | ||
61 | #define SUN_LEN(su) \ | ||
62 | (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) | ||
63 | #endif | ||
64 | |||
65 | #define PORT_MAX 65535 | ||
66 | #define PORT_MAX_LEN 6 | ||
67 | #define UNIX_DG_TMP_SOCKET_SIZE 19 | ||
68 | |||
69 | #define POLL_STDIN 0 | ||
70 | #define POLL_NETOUT 1 | ||
71 | #define POLL_NETIN 2 | ||
72 | #define POLL_STDOUT 3 | ||
73 | #define BUFSIZE 16384 | ||
74 | |||
75 | /* Command Line Options */ | ||
76 | int dflag; /* detached, no stdin */ | ||
77 | int Fflag; /* fdpass sock to stdout */ | ||
78 | unsigned int iflag; /* Interval Flag */ | ||
79 | int kflag; /* More than one connect */ | ||
80 | int lflag; /* Bind to local port */ | ||
81 | int Nflag; /* shutdown() network socket */ | ||
82 | int nflag; /* Don't do name look up */ | ||
83 | char *Pflag; /* Proxy username */ | ||
84 | char *pflag; /* Localport flag */ | ||
85 | int rflag; /* Random ports flag */ | ||
86 | char *sflag; /* Source Address */ | ||
87 | int tflag; /* Telnet Emulation */ | ||
88 | int uflag; /* UDP - Default to TCP */ | ||
89 | int vflag; /* Verbosity */ | ||
90 | int xflag; /* Socks proxy */ | ||
91 | int zflag; /* Port Scan Flag */ | ||
92 | int Dflag; /* sodebug */ | ||
93 | int Iflag; /* TCP receive buffer size */ | ||
94 | int Oflag; /* TCP send buffer size */ | ||
95 | int Sflag; /* TCP MD5 signature option */ | ||
96 | int Tflag = -1; /* IP Type of Service */ | ||
97 | int rtableid = -1; | ||
98 | |||
99 | int timeout = -1; | ||
100 | int family = AF_UNSPEC; | ||
101 | char *portlist[PORT_MAX+1]; | ||
102 | char *unix_dg_tmp_socket; | ||
103 | |||
104 | void atelnet(int, unsigned char *, unsigned int); | ||
105 | void build_ports(char *); | ||
106 | void help(void); | ||
107 | int local_listen(char *, char *, struct addrinfo); | ||
108 | void readwrite(int); | ||
109 | void fdpass(int nfd) __attribute__((noreturn)); | ||
110 | int remote_connect(const char *, const char *, struct addrinfo); | ||
111 | int timeout_connect(int, const struct sockaddr *, socklen_t); | ||
112 | int socks_connect(const char *, const char *, struct addrinfo, | ||
113 | const char *, const char *, struct addrinfo, int, const char *); | ||
114 | int udptest(int); | ||
115 | int unix_bind(char *); | ||
116 | int unix_connect(char *); | ||
117 | int unix_listen(char *); | ||
118 | void set_common_sockopts(int); | ||
119 | int map_tos(char *, int *); | ||
120 | void report_connect(const struct sockaddr *, socklen_t); | ||
121 | void usage(int); | ||
122 | ssize_t drainbuf(int, unsigned char *, size_t *); | ||
123 | ssize_t fillbuf(int, unsigned char *, size_t *); | ||
124 | |||
125 | int | ||
126 | main(int argc, char *argv[]) | ||
127 | { | ||
128 | int ch, s, ret, socksv; | ||
129 | char *host, *uport; | ||
130 | struct addrinfo hints; | ||
131 | struct servent *sv; | ||
132 | socklen_t len; | ||
133 | struct sockaddr_storage cliaddr; | ||
134 | char *proxy = NULL; | ||
135 | const char *errstr, *proxyhost = "", *proxyport = NULL; | ||
136 | struct addrinfo proxyhints; | ||
137 | char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE]; | ||
138 | |||
139 | ret = 1; | ||
140 | s = 0; | ||
141 | socksv = 5; | ||
142 | host = NULL; | ||
143 | uport = NULL; | ||
144 | sv = NULL; | ||
145 | |||
146 | while ((ch = getopt(argc, argv, | ||
147 | "46DdFhI:i:klNnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) { | ||
148 | switch (ch) { | ||
149 | case '4': | ||
150 | family = AF_INET; | ||
151 | break; | ||
152 | case '6': | ||
153 | family = AF_INET6; | ||
154 | break; | ||
155 | case 'U': | ||
156 | family = AF_UNIX; | ||
157 | break; | ||
158 | case 'X': | ||
159 | if (strcasecmp(optarg, "connect") == 0) | ||
160 | socksv = -1; /* HTTP proxy CONNECT */ | ||
161 | else if (strcmp(optarg, "4") == 0) | ||
162 | socksv = 4; /* SOCKS v.4 */ | ||
163 | else if (strcmp(optarg, "5") == 0) | ||
164 | socksv = 5; /* SOCKS v.5 */ | ||
165 | else | ||
166 | errx(1, "unsupported proxy protocol"); | ||
167 | break; | ||
168 | case 'd': | ||
169 | dflag = 1; | ||
170 | break; | ||
171 | case 'F': | ||
172 | Fflag = 1; | ||
173 | break; | ||
174 | case 'h': | ||
175 | help(); | ||
176 | break; | ||
177 | case 'i': | ||
178 | iflag = strtonum(optarg, 0, UINT_MAX, &errstr); | ||
179 | if (errstr) | ||
180 | errx(1, "interval %s: %s", errstr, optarg); | ||
181 | break; | ||
182 | case 'k': | ||
183 | kflag = 1; | ||
184 | break; | ||
185 | case 'l': | ||
186 | lflag = 1; | ||
187 | break; | ||
188 | case 'N': | ||
189 | Nflag = 1; | ||
190 | break; | ||
191 | case 'n': | ||
192 | nflag = 1; | ||
193 | break; | ||
194 | case 'P': | ||
195 | Pflag = optarg; | ||
196 | break; | ||
197 | case 'p': | ||
198 | pflag = optarg; | ||
199 | break; | ||
200 | case 'r': | ||
201 | rflag = 1; | ||
202 | break; | ||
203 | case 's': | ||
204 | sflag = optarg; | ||
205 | break; | ||
206 | case 't': | ||
207 | tflag = 1; | ||
208 | break; | ||
209 | case 'u': | ||
210 | uflag = 1; | ||
211 | break; | ||
212 | #ifdef SO_RTABLE | ||
213 | case 'V': | ||
214 | rtableid = (int)strtonum(optarg, 0, | ||
215 | RT_TABLEID_MAX, &errstr); | ||
216 | if (errstr) | ||
217 | errx(1, "rtable %s: %s", errstr, optarg); | ||
218 | break; | ||
219 | #endif | ||
220 | case 'v': | ||
221 | vflag = 1; | ||
222 | break; | ||
223 | case 'w': | ||
224 | timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr); | ||
225 | if (errstr) | ||
226 | errx(1, "timeout %s: %s", errstr, optarg); | ||
227 | timeout *= 1000; | ||
228 | break; | ||
229 | case 'x': | ||
230 | xflag = 1; | ||
231 | if ((proxy = strdup(optarg)) == NULL) | ||
232 | err(1, NULL); | ||
233 | break; | ||
234 | case 'z': | ||
235 | zflag = 1; | ||
236 | break; | ||
237 | case 'D': | ||
238 | Dflag = 1; | ||
239 | break; | ||
240 | case 'I': | ||
241 | Iflag = strtonum(optarg, 1, 65536 << 14, &errstr); | ||
242 | if (errstr != NULL) | ||
243 | errx(1, "TCP receive window %s: %s", | ||
244 | errstr, optarg); | ||
245 | break; | ||
246 | case 'O': | ||
247 | Oflag = strtonum(optarg, 1, 65536 << 14, &errstr); | ||
248 | if (errstr != NULL) | ||
249 | errx(1, "TCP send window %s: %s", | ||
250 | errstr, optarg); | ||
251 | break; | ||
252 | case 'S': | ||
253 | Sflag = 1; | ||
254 | break; | ||
255 | case 'T': | ||
256 | errstr = NULL; | ||
257 | errno = 0; | ||
258 | if (map_tos(optarg, &Tflag)) | ||
259 | break; | ||
260 | if (strlen(optarg) > 1 && optarg[0] == '0' && | ||
261 | optarg[1] == 'x') | ||
262 | Tflag = (int)strtol(optarg, NULL, 16); | ||
263 | else | ||
264 | Tflag = (int)strtonum(optarg, 0, 255, | ||
265 | &errstr); | ||
266 | if (Tflag < 0 || Tflag > 255 || errstr || errno) | ||
267 | errx(1, "illegal tos value %s", optarg); | ||
268 | break; | ||
269 | default: | ||
270 | usage(1); | ||
271 | } | ||
272 | } | ||
273 | argc -= optind; | ||
274 | argv += optind; | ||
275 | |||
276 | /* Cruft to make sure options are clean, and used properly. */ | ||
277 | if (argv[0] && !argv[1] && family == AF_UNIX) { | ||
278 | host = argv[0]; | ||
279 | uport = NULL; | ||
280 | } else if (argv[0] && !argv[1]) { | ||
281 | if (!lflag) | ||
282 | usage(1); | ||
283 | uport = argv[0]; | ||
284 | host = NULL; | ||
285 | } else if (argv[0] && argv[1]) { | ||
286 | host = argv[0]; | ||
287 | uport = argv[1]; | ||
288 | } else | ||
289 | usage(1); | ||
290 | |||
291 | if (lflag && sflag) | ||
292 | errx(1, "cannot use -s and -l"); | ||
293 | if (lflag && pflag) | ||
294 | errx(1, "cannot use -p and -l"); | ||
295 | if (lflag && zflag) | ||
296 | errx(1, "cannot use -z and -l"); | ||
297 | if (!lflag && kflag) | ||
298 | errx(1, "must use -l with -k"); | ||
299 | |||
300 | /* Get name of temporary socket for unix datagram client */ | ||
301 | if ((family == AF_UNIX) && uflag && !lflag) { | ||
302 | if (sflag) { | ||
303 | unix_dg_tmp_socket = sflag; | ||
304 | } else { | ||
305 | strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX", | ||
306 | UNIX_DG_TMP_SOCKET_SIZE); | ||
307 | if (mktemp(unix_dg_tmp_socket_buf) == NULL) | ||
308 | err(1, "mktemp"); | ||
309 | unix_dg_tmp_socket = unix_dg_tmp_socket_buf; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | /* Initialize addrinfo structure. */ | ||
314 | if (family != AF_UNIX) { | ||
315 | memset(&hints, 0, sizeof(struct addrinfo)); | ||
316 | hints.ai_family = family; | ||
317 | hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; | ||
318 | hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; | ||
319 | if (nflag) | ||
320 | hints.ai_flags |= AI_NUMERICHOST; | ||
321 | } | ||
322 | |||
323 | if (xflag) { | ||
324 | if (uflag) | ||
325 | errx(1, "no proxy support for UDP mode"); | ||
326 | |||
327 | if (lflag) | ||
328 | errx(1, "no proxy support for listen"); | ||
329 | |||
330 | if (family == AF_UNIX) | ||
331 | errx(1, "no proxy support for unix sockets"); | ||
332 | |||
333 | /* XXX IPv6 transport to proxy would probably work */ | ||
334 | if (family == AF_INET6) | ||
335 | errx(1, "no proxy support for IPv6"); | ||
336 | |||
337 | if (sflag) | ||
338 | errx(1, "no proxy support for local source address"); | ||
339 | |||
340 | proxyhost = strsep(&proxy, ":"); | ||
341 | proxyport = proxy; | ||
342 | |||
343 | memset(&proxyhints, 0, sizeof(struct addrinfo)); | ||
344 | proxyhints.ai_family = family; | ||
345 | proxyhints.ai_socktype = SOCK_STREAM; | ||
346 | proxyhints.ai_protocol = IPPROTO_TCP; | ||
347 | if (nflag) | ||
348 | proxyhints.ai_flags |= AI_NUMERICHOST; | ||
349 | } | ||
350 | |||
351 | if (lflag) { | ||
352 | int connfd; | ||
353 | ret = 0; | ||
354 | |||
355 | if (family == AF_UNIX) { | ||
356 | if (uflag) | ||
357 | s = unix_bind(host); | ||
358 | else | ||
359 | s = unix_listen(host); | ||
360 | } | ||
361 | |||
362 | /* Allow only one connection at a time, but stay alive. */ | ||
363 | for (;;) { | ||
364 | if (family != AF_UNIX) | ||
365 | s = local_listen(host, uport, hints); | ||
366 | if (s < 0) | ||
367 | err(1, NULL); | ||
368 | /* | ||
369 | * For UDP and -k, don't connect the socket, let it | ||
370 | * receive datagrams from multiple socket pairs. | ||
371 | */ | ||
372 | if (uflag && kflag) | ||
373 | readwrite(s); | ||
374 | /* | ||
375 | * For UDP and not -k, we will use recvfrom() initially | ||
376 | * to wait for a caller, then use the regular functions | ||
377 | * to talk to the caller. | ||
378 | */ | ||
379 | else if (uflag && !kflag) { | ||
380 | int rv, plen; | ||
381 | char buf[16384]; | ||
382 | struct sockaddr_storage z; | ||
383 | |||
384 | len = sizeof(z); | ||
385 | plen = 2048; | ||
386 | rv = recvfrom(s, buf, plen, MSG_PEEK, | ||
387 | (struct sockaddr *)&z, &len); | ||
388 | if (rv < 0) | ||
389 | err(1, "recvfrom"); | ||
390 | |||
391 | rv = connect(s, (struct sockaddr *)&z, len); | ||
392 | if (rv < 0) | ||
393 | err(1, "connect"); | ||
394 | |||
395 | if (vflag) | ||
396 | report_connect((struct sockaddr *)&z, len); | ||
397 | |||
398 | readwrite(s); | ||
399 | } else { | ||
400 | len = sizeof(cliaddr); | ||
401 | connfd = accept(s, (struct sockaddr *)&cliaddr, | ||
402 | &len); | ||
403 | if (connfd == -1) { | ||
404 | /* For now, all errnos are fatal */ | ||
405 | err(1, "accept"); | ||
406 | } | ||
407 | if (vflag) | ||
408 | report_connect((struct sockaddr *)&cliaddr, len); | ||
409 | |||
410 | readwrite(connfd); | ||
411 | close(connfd); | ||
412 | } | ||
413 | |||
414 | if (family != AF_UNIX) | ||
415 | close(s); | ||
416 | else if (uflag) { | ||
417 | if (connect(s, NULL, 0) < 0) | ||
418 | err(1, "connect"); | ||
419 | } | ||
420 | |||
421 | if (!kflag) | ||
422 | break; | ||
423 | } | ||
424 | } else if (family == AF_UNIX) { | ||
425 | ret = 0; | ||
426 | |||
427 | if ((s = unix_connect(host)) > 0 && !zflag) { | ||
428 | readwrite(s); | ||
429 | close(s); | ||
430 | } else | ||
431 | ret = 1; | ||
432 | |||
433 | if (uflag) | ||
434 | unlink(unix_dg_tmp_socket); | ||
435 | exit(ret); | ||
436 | |||
437 | } else { | ||
438 | int i = 0; | ||
439 | |||
440 | /* Construct the portlist[] array. */ | ||
441 | build_ports(uport); | ||
442 | |||
443 | /* Cycle through portlist, connecting to each port. */ | ||
444 | for (i = 0; portlist[i] != NULL; i++) { | ||
445 | if (s) | ||
446 | close(s); | ||
447 | |||
448 | if (xflag) | ||
449 | s = socks_connect(host, portlist[i], hints, | ||
450 | proxyhost, proxyport, proxyhints, socksv, | ||
451 | Pflag); | ||
452 | else | ||
453 | s = remote_connect(host, portlist[i], hints); | ||
454 | |||
455 | if (s < 0) | ||
456 | continue; | ||
457 | |||
458 | ret = 0; | ||
459 | if (vflag || zflag) { | ||
460 | /* For UDP, make sure we are connected. */ | ||
461 | if (uflag) { | ||
462 | if (udptest(s) == -1) { | ||
463 | ret = 1; | ||
464 | continue; | ||
465 | } | ||
466 | } | ||
467 | |||
468 | /* Don't look up port if -n. */ | ||
469 | if (nflag) | ||
470 | sv = NULL; | ||
471 | else { | ||
472 | sv = getservbyport( | ||
473 | ntohs(atoi(portlist[i])), | ||
474 | uflag ? "udp" : "tcp"); | ||
475 | } | ||
476 | |||
477 | fprintf(stderr, | ||
478 | "Connection to %s %s port [%s/%s] " | ||
479 | "succeeded!\n", host, portlist[i], | ||
480 | uflag ? "udp" : "tcp", | ||
481 | sv ? sv->s_name : "*"); | ||
482 | } | ||
483 | if (Fflag) | ||
484 | fdpass(s); | ||
485 | else if (!zflag) | ||
486 | readwrite(s); | ||
487 | } | ||
488 | } | ||
489 | |||
490 | if (s) | ||
491 | close(s); | ||
492 | |||
493 | exit(ret); | ||
494 | } | ||
495 | |||
496 | /* | ||
497 | * unix_bind() | ||
498 | * Returns a unix socket bound to the given path | ||
499 | */ | ||
500 | int | ||
501 | unix_bind(char *path) | ||
502 | { | ||
503 | struct sockaddr_un sun; | ||
504 | int s; | ||
505 | |||
506 | /* Create unix domain socket. */ | ||
507 | if ((s = socket(AF_UNIX, uflag ? SOCK_DGRAM : SOCK_STREAM, | ||
508 | 0)) < 0) | ||
509 | return (-1); | ||
510 | |||
511 | memset(&sun, 0, sizeof(struct sockaddr_un)); | ||
512 | sun.sun_family = AF_UNIX; | ||
513 | |||
514 | if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= | ||
515 | sizeof(sun.sun_path)) { | ||
516 | close(s); | ||
517 | errno = ENAMETOOLONG; | ||
518 | return (-1); | ||
519 | } | ||
520 | |||
521 | if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) { | ||
522 | close(s); | ||
523 | return (-1); | ||
524 | } | ||
525 | return (s); | ||
526 | } | ||
527 | |||
528 | /* | ||
529 | * unix_connect() | ||
530 | * Returns a socket connected to a local unix socket. Returns -1 on failure. | ||
531 | */ | ||
532 | int | ||
533 | unix_connect(char *path) | ||
534 | { | ||
535 | struct sockaddr_un sun; | ||
536 | int s; | ||
537 | |||
538 | if (uflag) { | ||
539 | if ((s = unix_bind(unix_dg_tmp_socket)) < 0) | ||
540 | return (-1); | ||
541 | } else { | ||
542 | if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) | ||
543 | return (-1); | ||
544 | } | ||
545 | (void)fcntl(s, F_SETFD, FD_CLOEXEC); | ||
546 | |||
547 | memset(&sun, 0, sizeof(struct sockaddr_un)); | ||
548 | sun.sun_family = AF_UNIX; | ||
549 | |||
550 | if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= | ||
551 | sizeof(sun.sun_path)) { | ||
552 | close(s); | ||
553 | errno = ENAMETOOLONG; | ||
554 | return (-1); | ||
555 | } | ||
556 | if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) { | ||
557 | close(s); | ||
558 | return (-1); | ||
559 | } | ||
560 | return (s); | ||
561 | |||
562 | } | ||
563 | |||
564 | /* | ||
565 | * unix_listen() | ||
566 | * Create a unix domain socket, and listen on it. | ||
567 | */ | ||
568 | int | ||
569 | unix_listen(char *path) | ||
570 | { | ||
571 | int s; | ||
572 | if ((s = unix_bind(path)) < 0) | ||
573 | return (-1); | ||
574 | |||
575 | if (listen(s, 5) < 0) { | ||
576 | close(s); | ||
577 | return (-1); | ||
578 | } | ||
579 | return (s); | ||
580 | } | ||
581 | |||
582 | /* | ||
583 | * remote_connect() | ||
584 | * Returns a socket connected to a remote host. Properly binds to a local | ||
585 | * port or source address if needed. Returns -1 on failure. | ||
586 | */ | ||
587 | int | ||
588 | remote_connect(const char *host, const char *port, struct addrinfo hints) | ||
589 | { | ||
590 | struct addrinfo *res, *res0; | ||
591 | int s, error; | ||
592 | #ifdef SO_RTABLE | ||
593 | int on = 1; | ||
594 | #endif | ||
595 | |||
596 | if ((error = getaddrinfo(host, port, &hints, &res))) | ||
597 | errx(1, "getaddrinfo: %s", gai_strerror(error)); | ||
598 | |||
599 | res0 = res; | ||
600 | do { | ||
601 | if ((s = socket(res0->ai_family, res0->ai_socktype, | ||
602 | res0->ai_protocol)) < 0) | ||
603 | continue; | ||
604 | |||
605 | #ifdef SO_RTABLE | ||
606 | if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_RTABLE, | ||
607 | &rtableid, sizeof(rtableid)) == -1)) | ||
608 | err(1, "setsockopt SO_RTABLE"); | ||
609 | #endif | ||
610 | /* Bind to a local port or source address if specified. */ | ||
611 | if (sflag || pflag) { | ||
612 | struct addrinfo ahints, *ares; | ||
613 | |||
614 | #ifdef SO_BINDANY | ||
615 | /* try SO_BINDANY, but don't insist */ | ||
616 | setsockopt(s, SOL_SOCKET, SO_BINDANY, &on, sizeof(on)); | ||
617 | #endif | ||
618 | memset(&ahints, 0, sizeof(struct addrinfo)); | ||
619 | ahints.ai_family = res0->ai_family; | ||
620 | ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; | ||
621 | ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; | ||
622 | ahints.ai_flags = AI_PASSIVE; | ||
623 | if ((error = getaddrinfo(sflag, pflag, &ahints, &ares))) | ||
624 | errx(1, "getaddrinfo: %s", gai_strerror(error)); | ||
625 | |||
626 | if (bind(s, (struct sockaddr *)ares->ai_addr, | ||
627 | ares->ai_addrlen) < 0) | ||
628 | err(1, "bind failed"); | ||
629 | freeaddrinfo(ares); | ||
630 | } | ||
631 | |||
632 | set_common_sockopts(s); | ||
633 | |||
634 | if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0) | ||
635 | break; | ||
636 | else if (vflag) | ||
637 | warn("connect to %s port %s (%s) failed", host, port, | ||
638 | uflag ? "udp" : "tcp"); | ||
639 | |||
640 | close(s); | ||
641 | s = -1; | ||
642 | } while ((res0 = res0->ai_next) != NULL); | ||
643 | |||
644 | freeaddrinfo(res); | ||
645 | |||
646 | return (s); | ||
647 | } | ||
648 | |||
649 | int | ||
650 | timeout_connect(int s, const struct sockaddr *name, socklen_t namelen) | ||
651 | { | ||
652 | struct pollfd pfd; | ||
653 | socklen_t optlen; | ||
654 | int flags = 0, optval; | ||
655 | int ret; | ||
656 | |||
657 | if (timeout != -1) { | ||
658 | flags = fcntl(s, F_GETFL, 0); | ||
659 | if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) | ||
660 | err(1, "set non-blocking mode"); | ||
661 | } | ||
662 | |||
663 | if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) { | ||
664 | pfd.fd = s; | ||
665 | pfd.events = POLLOUT; | ||
666 | if ((ret = poll(&pfd, 1, timeout)) == 1) { | ||
667 | optlen = sizeof(optval); | ||
668 | if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR, | ||
669 | &optval, &optlen)) == 0) { | ||
670 | errno = optval; | ||
671 | ret = optval == 0 ? 0 : -1; | ||
672 | } | ||
673 | } else if (ret == 0) { | ||
674 | errno = ETIMEDOUT; | ||
675 | ret = -1; | ||
676 | } else | ||
677 | err(1, "poll failed"); | ||
678 | } | ||
679 | |||
680 | if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1) | ||
681 | err(1, "restoring flags"); | ||
682 | |||
683 | return (ret); | ||
684 | } | ||
685 | |||
686 | /* | ||
687 | * local_listen() | ||
688 | * Returns a socket listening on a local port, binds to specified source | ||
689 | * address. Returns -1 on failure. | ||
690 | */ | ||
691 | int | ||
692 | local_listen(char *host, char *port, struct addrinfo hints) | ||
693 | { | ||
694 | struct addrinfo *res, *res0; | ||
695 | int s, ret, x = 1; | ||
696 | int error; | ||
697 | |||
698 | /* Allow nodename to be null. */ | ||
699 | hints.ai_flags |= AI_PASSIVE; | ||
700 | |||
701 | /* | ||
702 | * In the case of binding to a wildcard address | ||
703 | * default to binding to an ipv4 address. | ||
704 | */ | ||
705 | if (host == NULL && hints.ai_family == AF_UNSPEC) | ||
706 | hints.ai_family = AF_INET; | ||
707 | |||
708 | if ((error = getaddrinfo(host, port, &hints, &res))) | ||
709 | errx(1, "getaddrinfo: %s", gai_strerror(error)); | ||
710 | |||
711 | res0 = res; | ||
712 | do { | ||
713 | if ((s = socket(res0->ai_family, res0->ai_socktype, | ||
714 | res0->ai_protocol)) < 0) | ||
715 | continue; | ||
716 | |||
717 | #ifdef SO_RTABLE | ||
718 | if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_RTABLE, | ||
719 | &rtableid, sizeof(rtableid)) == -1)) | ||
720 | err(1, "setsockopt SO_RTABLE"); | ||
721 | #endif | ||
722 | |||
723 | ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x)); | ||
724 | if (ret == -1) | ||
725 | err(1, NULL); | ||
726 | |||
727 | set_common_sockopts(s); | ||
728 | |||
729 | if (bind(s, (struct sockaddr *)res0->ai_addr, | ||
730 | res0->ai_addrlen) == 0) | ||
731 | break; | ||
732 | |||
733 | close(s); | ||
734 | s = -1; | ||
735 | } while ((res0 = res0->ai_next) != NULL); | ||
736 | |||
737 | if (!uflag && s != -1) { | ||
738 | if (listen(s, 1) < 0) | ||
739 | err(1, "listen"); | ||
740 | } | ||
741 | |||
742 | freeaddrinfo(res); | ||
743 | |||
744 | return (s); | ||
745 | } | ||
746 | |||
747 | /* | ||
748 | * readwrite() | ||
749 | * Loop that polls on the network file descriptor and stdin. | ||
750 | */ | ||
751 | void | ||
752 | readwrite(int net_fd) | ||
753 | { | ||
754 | struct pollfd pfd[4]; | ||
755 | int stdin_fd = STDIN_FILENO; | ||
756 | int stdout_fd = STDOUT_FILENO; | ||
757 | unsigned char netinbuf[BUFSIZE]; | ||
758 | size_t netinbufpos = 0; | ||
759 | unsigned char stdinbuf[BUFSIZE]; | ||
760 | size_t stdinbufpos = 0; | ||
761 | int n, num_fds; | ||
762 | ssize_t ret; | ||
763 | |||
764 | /* don't read from stdin if requested */ | ||
765 | if (dflag) | ||
766 | stdin_fd = -1; | ||
767 | |||
768 | /* stdin */ | ||
769 | pfd[POLL_STDIN].fd = stdin_fd; | ||
770 | pfd[POLL_STDIN].events = POLLIN; | ||
771 | |||
772 | /* network out */ | ||
773 | pfd[POLL_NETOUT].fd = net_fd; | ||
774 | pfd[POLL_NETOUT].events = 0; | ||
775 | |||
776 | /* network in */ | ||
777 | pfd[POLL_NETIN].fd = net_fd; | ||
778 | pfd[POLL_NETIN].events = POLLIN; | ||
779 | |||
780 | /* stdout */ | ||
781 | pfd[POLL_STDOUT].fd = stdout_fd; | ||
782 | pfd[POLL_STDOUT].events = 0; | ||
783 | |||
784 | while (1) { | ||
785 | /* both inputs are gone, buffers are empty, we are done */ | ||
786 | if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1 | ||
787 | && stdinbufpos == 0 && netinbufpos == 0) { | ||
788 | close(net_fd); | ||
789 | return; | ||
790 | } | ||
791 | /* both outputs are gone, we can't continue */ | ||
792 | if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) { | ||
793 | close(net_fd); | ||
794 | return; | ||
795 | } | ||
796 | /* listen and net in gone, queues empty, done */ | ||
797 | if (lflag && pfd[POLL_NETIN].fd == -1 | ||
798 | && stdinbufpos == 0 && netinbufpos == 0) { | ||
799 | close(net_fd); | ||
800 | return; | ||
801 | } | ||
802 | |||
803 | /* help says -i is for "wait between lines sent". We read and | ||
804 | * write arbitrary amounts of data, and we don't want to start | ||
805 | * scanning for newlines, so this is as good as it gets */ | ||
806 | if (iflag) | ||
807 | sleep(iflag); | ||
808 | |||
809 | /* poll */ | ||
810 | num_fds = poll(pfd, 4, timeout); | ||
811 | |||
812 | /* treat poll errors */ | ||
813 | if (num_fds == -1) { | ||
814 | close(net_fd); | ||
815 | err(1, "polling error"); | ||
816 | } | ||
817 | |||
818 | /* timeout happened */ | ||
819 | if (num_fds == 0) | ||
820 | return; | ||
821 | |||
822 | /* treat socket error conditions */ | ||
823 | for (n = 0; n < 4; n++) { | ||
824 | if (pfd[n].revents & (POLLERR|POLLNVAL)) { | ||
825 | pfd[n].fd = -1; | ||
826 | } | ||
827 | } | ||
828 | /* reading is possible after HUP */ | ||
829 | if (pfd[POLL_STDIN].events & POLLIN && | ||
830 | pfd[POLL_STDIN].revents & POLLHUP && | ||
831 | ! (pfd[POLL_STDIN].revents & POLLIN)) | ||
832 | pfd[POLL_STDIN].fd = -1; | ||
833 | |||
834 | if (pfd[POLL_NETIN].events & POLLIN && | ||
835 | pfd[POLL_NETIN].revents & POLLHUP && | ||
836 | ! (pfd[POLL_NETIN].revents & POLLIN)) | ||
837 | pfd[POLL_NETIN].fd = -1; | ||
838 | |||
839 | if (pfd[POLL_NETOUT].revents & POLLHUP) { | ||
840 | if (Nflag) | ||
841 | shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); | ||
842 | pfd[POLL_NETOUT].fd = -1; | ||
843 | } | ||
844 | /* if HUP, stop watching stdout */ | ||
845 | if (pfd[POLL_STDOUT].revents & POLLHUP) | ||
846 | pfd[POLL_STDOUT].fd = -1; | ||
847 | /* if no net out, stop watching stdin */ | ||
848 | if (pfd[POLL_NETOUT].fd == -1) | ||
849 | pfd[POLL_STDIN].fd = -1; | ||
850 | /* if no stdout, stop watching net in */ | ||
851 | if (pfd[POLL_STDOUT].fd == -1) { | ||
852 | if (pfd[POLL_NETIN].fd != -1) | ||
853 | shutdown(pfd[POLL_NETIN].fd, SHUT_RD); | ||
854 | pfd[POLL_NETIN].fd = -1; | ||
855 | } | ||
856 | |||
857 | /* try to read from stdin */ | ||
858 | if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) { | ||
859 | ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf, | ||
860 | &stdinbufpos); | ||
861 | /* error or eof on stdin - remove from pfd */ | ||
862 | if (ret == 0 || ret == -1) | ||
863 | pfd[POLL_STDIN].fd = -1; | ||
864 | /* read something - poll net out */ | ||
865 | if (stdinbufpos > 0) | ||
866 | pfd[POLL_NETOUT].events = POLLOUT; | ||
867 | /* filled buffer - remove self from polling */ | ||
868 | if (stdinbufpos == BUFSIZE) | ||
869 | pfd[POLL_STDIN].events = 0; | ||
870 | } | ||
871 | /* try to write to network */ | ||
872 | if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) { | ||
873 | ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf, | ||
874 | &stdinbufpos); | ||
875 | if (ret == -1) | ||
876 | pfd[POLL_NETOUT].fd = -1; | ||
877 | /* buffer empty - remove self from polling */ | ||
878 | if (stdinbufpos == 0) | ||
879 | pfd[POLL_NETOUT].events = 0; | ||
880 | /* buffer no longer full - poll stdin again */ | ||
881 | if (stdinbufpos < BUFSIZE) | ||
882 | pfd[POLL_STDIN].events = POLLIN; | ||
883 | } | ||
884 | /* try to read from network */ | ||
885 | if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) { | ||
886 | ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf, | ||
887 | &netinbufpos); | ||
888 | if (ret == -1) | ||
889 | pfd[POLL_NETIN].fd = -1; | ||
890 | /* eof on net in - remove from pfd */ | ||
891 | if (ret == 0) { | ||
892 | shutdown(pfd[POLL_NETIN].fd, SHUT_RD); | ||
893 | pfd[POLL_NETIN].fd = -1; | ||
894 | } | ||
895 | /* read something - poll stdout */ | ||
896 | if (netinbufpos > 0) | ||
897 | pfd[POLL_STDOUT].events = POLLOUT; | ||
898 | /* filled buffer - remove self from polling */ | ||
899 | if (netinbufpos == BUFSIZE) | ||
900 | pfd[POLL_NETIN].events = 0; | ||
901 | /* handle telnet */ | ||
902 | if (tflag) | ||
903 | atelnet(pfd[POLL_NETIN].fd, netinbuf, | ||
904 | netinbufpos); | ||
905 | } | ||
906 | /* try to write to stdout */ | ||
907 | if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) { | ||
908 | ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf, | ||
909 | &netinbufpos); | ||
910 | if (ret == -1) | ||
911 | pfd[POLL_STDOUT].fd = -1; | ||
912 | /* buffer empty - remove self from polling */ | ||
913 | if (netinbufpos == 0) | ||
914 | pfd[POLL_STDOUT].events = 0; | ||
915 | /* buffer no longer full - poll net in again */ | ||
916 | if (netinbufpos < BUFSIZE) | ||
917 | pfd[POLL_NETIN].events = POLLIN; | ||
918 | } | ||
919 | |||
920 | /* stdin gone and queue empty? */ | ||
921 | if (pfd[POLL_STDIN].fd == -1 && stdinbufpos == 0) { | ||
922 | if (pfd[POLL_NETOUT].fd != -1 && Nflag) | ||
923 | shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); | ||
924 | pfd[POLL_NETOUT].fd = -1; | ||
925 | } | ||
926 | /* net in gone and queue empty? */ | ||
927 | if (pfd[POLL_NETIN].fd == -1 && netinbufpos == 0) { | ||
928 | pfd[POLL_STDOUT].fd = -1; | ||
929 | } | ||
930 | } | ||
931 | } | ||
932 | |||
933 | ssize_t | ||
934 | drainbuf(int fd, unsigned char *buf, size_t *bufpos) | ||
935 | { | ||
936 | ssize_t n; | ||
937 | ssize_t adjust; | ||
938 | |||
939 | n = write(fd, buf, *bufpos); | ||
940 | /* don't treat EAGAIN, EINTR as error */ | ||
941 | if (n == -1 && (errno == EAGAIN || errno == EINTR)) | ||
942 | n = -2; | ||
943 | if (n <= 0) | ||
944 | return n; | ||
945 | /* adjust buffer */ | ||
946 | adjust = *bufpos - n; | ||
947 | if (adjust > 0) | ||
948 | memmove(buf, buf + n, adjust); | ||
949 | *bufpos -= n; | ||
950 | return n; | ||
951 | } | ||
952 | |||
953 | |||
954 | ssize_t | ||
955 | fillbuf(int fd, unsigned char *buf, size_t *bufpos) | ||
956 | { | ||
957 | size_t num = BUFSIZE - *bufpos; | ||
958 | ssize_t n; | ||
959 | |||
960 | n = read(fd, buf + *bufpos, num); | ||
961 | /* don't treat EAGAIN, EINTR as error */ | ||
962 | if (n == -1 && (errno == EAGAIN || errno == EINTR)) | ||
963 | n = -2; | ||
964 | if (n <= 0) | ||
965 | return n; | ||
966 | *bufpos += n; | ||
967 | return n; | ||
968 | } | ||
969 | |||
970 | /* | ||
971 | * fdpass() | ||
972 | * Pass the connected file descriptor to stdout and exit. | ||
973 | */ | ||
974 | void | ||
975 | fdpass(int nfd) | ||
976 | { | ||
977 | struct msghdr mh; | ||
978 | union { | ||
979 | struct cmsghdr hdr; | ||
980 | char buf[CMSG_SPACE(sizeof(int))]; | ||
981 | } cmsgbuf; | ||
982 | struct cmsghdr *cmsg; | ||
983 | struct iovec iov; | ||
984 | char c = '\0'; | ||
985 | ssize_t r; | ||
986 | struct pollfd pfd; | ||
987 | |||
988 | /* Avoid obvious stupidity */ | ||
989 | if (isatty(STDOUT_FILENO)) | ||
990 | errx(1, "Cannot pass file descriptor to tty"); | ||
991 | |||
992 | bzero(&mh, sizeof(mh)); | ||
993 | bzero(&cmsgbuf, sizeof(cmsgbuf)); | ||
994 | bzero(&iov, sizeof(iov)); | ||
995 | bzero(&pfd, sizeof(pfd)); | ||
996 | |||
997 | mh.msg_control = (caddr_t)&cmsgbuf.buf; | ||
998 | mh.msg_controllen = sizeof(cmsgbuf.buf); | ||
999 | cmsg = CMSG_FIRSTHDR(&mh); | ||
1000 | cmsg->cmsg_len = CMSG_LEN(sizeof(int)); | ||
1001 | cmsg->cmsg_level = SOL_SOCKET; | ||
1002 | cmsg->cmsg_type = SCM_RIGHTS; | ||
1003 | *(int *)CMSG_DATA(cmsg) = nfd; | ||
1004 | |||
1005 | iov.iov_base = &c; | ||
1006 | iov.iov_len = 1; | ||
1007 | mh.msg_iov = &iov; | ||
1008 | mh.msg_iovlen = 1; | ||
1009 | |||
1010 | bzero(&pfd, sizeof(pfd)); | ||
1011 | pfd.fd = STDOUT_FILENO; | ||
1012 | for (;;) { | ||
1013 | r = sendmsg(STDOUT_FILENO, &mh, 0); | ||
1014 | if (r == -1) { | ||
1015 | if (errno == EAGAIN || errno == EINTR) { | ||
1016 | pfd.events = POLLOUT; | ||
1017 | if (poll(&pfd, 1, -1) == -1) | ||
1018 | err(1, "poll"); | ||
1019 | continue; | ||
1020 | } | ||
1021 | err(1, "sendmsg"); | ||
1022 | } else if (r == -1) | ||
1023 | errx(1, "sendmsg: unexpected return value %zd", r); | ||
1024 | else | ||
1025 | break; | ||
1026 | } | ||
1027 | exit(0); | ||
1028 | } | ||
1029 | |||
1030 | /* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */ | ||
1031 | void | ||
1032 | atelnet(int nfd, unsigned char *buf, unsigned int size) | ||
1033 | { | ||
1034 | unsigned char *p, *end; | ||
1035 | unsigned char obuf[4]; | ||
1036 | |||
1037 | if (size < 3) | ||
1038 | return; | ||
1039 | end = buf + size - 2; | ||
1040 | |||
1041 | for (p = buf; p < end; p++) { | ||
1042 | if (*p != IAC) | ||
1043 | continue; | ||
1044 | |||
1045 | obuf[0] = IAC; | ||
1046 | p++; | ||
1047 | if ((*p == WILL) || (*p == WONT)) | ||
1048 | obuf[1] = DONT; | ||
1049 | else if ((*p == DO) || (*p == DONT)) | ||
1050 | obuf[1] = WONT; | ||
1051 | else | ||
1052 | continue; | ||
1053 | |||
1054 | p++; | ||
1055 | obuf[2] = *p; | ||
1056 | if (atomicio(vwrite, nfd, obuf, 3) != 3) | ||
1057 | warn("Write Error!"); | ||
1058 | } | ||
1059 | } | ||
1060 | |||
1061 | /* | ||
1062 | * build_ports() | ||
1063 | * Build an array of ports in portlist[], listing each port | ||
1064 | * that we should try to connect to. | ||
1065 | */ | ||
1066 | void | ||
1067 | build_ports(char *p) | ||
1068 | { | ||
1069 | const char *errstr; | ||
1070 | char *n; | ||
1071 | int hi, lo, cp; | ||
1072 | int x = 0; | ||
1073 | |||
1074 | if ((n = strchr(p, '-')) != NULL) { | ||
1075 | *n = '\0'; | ||
1076 | n++; | ||
1077 | |||
1078 | /* Make sure the ports are in order: lowest->highest. */ | ||
1079 | hi = strtonum(n, 1, PORT_MAX, &errstr); | ||
1080 | if (errstr) | ||
1081 | errx(1, "port number %s: %s", errstr, n); | ||
1082 | lo = strtonum(p, 1, PORT_MAX, &errstr); | ||
1083 | if (errstr) | ||
1084 | errx(1, "port number %s: %s", errstr, p); | ||
1085 | |||
1086 | if (lo > hi) { | ||
1087 | cp = hi; | ||
1088 | hi = lo; | ||
1089 | lo = cp; | ||
1090 | } | ||
1091 | |||
1092 | /* Load ports sequentially. */ | ||
1093 | for (cp = lo; cp <= hi; cp++) { | ||
1094 | portlist[x] = calloc(1, PORT_MAX_LEN); | ||
1095 | if (portlist[x] == NULL) | ||
1096 | err(1, NULL); | ||
1097 | snprintf(portlist[x], PORT_MAX_LEN, "%d", cp); | ||
1098 | x++; | ||
1099 | } | ||
1100 | |||
1101 | /* Randomly swap ports. */ | ||
1102 | if (rflag) { | ||
1103 | int y; | ||
1104 | char *c; | ||
1105 | |||
1106 | for (x = 0; x <= (hi - lo); x++) { | ||
1107 | y = (arc4random() & 0xFFFF) % (hi - lo); | ||
1108 | c = portlist[x]; | ||
1109 | portlist[x] = portlist[y]; | ||
1110 | portlist[y] = c; | ||
1111 | } | ||
1112 | } | ||
1113 | } else { | ||
1114 | hi = strtonum(p, 1, PORT_MAX, &errstr); | ||
1115 | if (errstr) | ||
1116 | errx(1, "port number %s: %s", errstr, p); | ||
1117 | portlist[0] = strdup(p); | ||
1118 | if (portlist[0] == NULL) | ||
1119 | err(1, NULL); | ||
1120 | } | ||
1121 | } | ||
1122 | |||
1123 | /* | ||
1124 | * udptest() | ||
1125 | * Do a few writes to see if the UDP port is there. | ||
1126 | * Fails once PF state table is full. | ||
1127 | */ | ||
1128 | int | ||
1129 | udptest(int s) | ||
1130 | { | ||
1131 | int i, ret; | ||
1132 | |||
1133 | for (i = 0; i <= 3; i++) { | ||
1134 | if (write(s, "X", 1) == 1) | ||
1135 | ret = 1; | ||
1136 | else | ||
1137 | ret = -1; | ||
1138 | } | ||
1139 | return (ret); | ||
1140 | } | ||
1141 | |||
1142 | void | ||
1143 | set_common_sockopts(int s) | ||
1144 | { | ||
1145 | int x = 1; | ||
1146 | |||
1147 | if (Sflag) { | ||
1148 | if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG, | ||
1149 | &x, sizeof(x)) == -1) | ||
1150 | err(1, NULL); | ||
1151 | } | ||
1152 | if (Dflag) { | ||
1153 | if (setsockopt(s, SOL_SOCKET, SO_DEBUG, | ||
1154 | &x, sizeof(x)) == -1) | ||
1155 | err(1, NULL); | ||
1156 | } | ||
1157 | if (Tflag != -1) { | ||
1158 | if (setsockopt(s, IPPROTO_IP, IP_TOS, | ||
1159 | &Tflag, sizeof(Tflag)) == -1) | ||
1160 | err(1, "set IP ToS"); | ||
1161 | } | ||
1162 | if (Iflag) { | ||
1163 | if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, | ||
1164 | &Iflag, sizeof(Iflag)) == -1) | ||
1165 | err(1, "set TCP receive buffer size"); | ||
1166 | } | ||
1167 | if (Oflag) { | ||
1168 | if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, | ||
1169 | &Oflag, sizeof(Oflag)) == -1) | ||
1170 | err(1, "set TCP send buffer size"); | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | int | ||
1175 | map_tos(char *s, int *val) | ||
1176 | { | ||
1177 | /* DiffServ Codepoints and other TOS mappings */ | ||
1178 | const struct toskeywords { | ||
1179 | const char *keyword; | ||
1180 | int val; | ||
1181 | } *t, toskeywords[] = { | ||
1182 | { "af11", IPTOS_DSCP_AF11 }, | ||
1183 | { "af12", IPTOS_DSCP_AF12 }, | ||
1184 | { "af13", IPTOS_DSCP_AF13 }, | ||
1185 | { "af21", IPTOS_DSCP_AF21 }, | ||
1186 | { "af22", IPTOS_DSCP_AF22 }, | ||
1187 | { "af23", IPTOS_DSCP_AF23 }, | ||
1188 | { "af31", IPTOS_DSCP_AF31 }, | ||
1189 | { "af32", IPTOS_DSCP_AF32 }, | ||
1190 | { "af33", IPTOS_DSCP_AF33 }, | ||
1191 | { "af41", IPTOS_DSCP_AF41 }, | ||
1192 | { "af42", IPTOS_DSCP_AF42 }, | ||
1193 | { "af43", IPTOS_DSCP_AF43 }, | ||
1194 | { "critical", IPTOS_PREC_CRITIC_ECP }, | ||
1195 | { "cs0", IPTOS_DSCP_CS0 }, | ||
1196 | { "cs1", IPTOS_DSCP_CS1 }, | ||
1197 | { "cs2", IPTOS_DSCP_CS2 }, | ||
1198 | { "cs3", IPTOS_DSCP_CS3 }, | ||
1199 | { "cs4", IPTOS_DSCP_CS4 }, | ||
1200 | { "cs5", IPTOS_DSCP_CS5 }, | ||
1201 | { "cs6", IPTOS_DSCP_CS6 }, | ||
1202 | { "cs7", IPTOS_DSCP_CS7 }, | ||
1203 | { "ef", IPTOS_DSCP_EF }, | ||
1204 | { "inetcontrol", IPTOS_PREC_INTERNETCONTROL }, | ||
1205 | { "lowdelay", IPTOS_LOWDELAY }, | ||
1206 | { "netcontrol", IPTOS_PREC_NETCONTROL }, | ||
1207 | { "reliability", IPTOS_RELIABILITY }, | ||
1208 | { "throughput", IPTOS_THROUGHPUT }, | ||
1209 | { NULL, -1 }, | ||
1210 | }; | ||
1211 | |||
1212 | for (t = toskeywords; t->keyword != NULL; t++) { | ||
1213 | if (strcmp(s, t->keyword) == 0) { | ||
1214 | *val = t->val; | ||
1215 | return (1); | ||
1216 | } | ||
1217 | } | ||
1218 | |||
1219 | return (0); | ||
1220 | } | ||
1221 | |||
1222 | void | ||
1223 | report_connect(const struct sockaddr *sa, socklen_t salen) | ||
1224 | { | ||
1225 | char remote_host[NI_MAXHOST]; | ||
1226 | char remote_port[NI_MAXSERV]; | ||
1227 | int herr; | ||
1228 | int flags = NI_NUMERICSERV; | ||
1229 | |||
1230 | if (nflag) | ||
1231 | flags |= NI_NUMERICHOST; | ||
1232 | |||
1233 | if ((herr = getnameinfo(sa, salen, | ||
1234 | remote_host, sizeof(remote_host), | ||
1235 | remote_port, sizeof(remote_port), | ||
1236 | flags)) != 0) { | ||
1237 | if (herr == EAI_SYSTEM) | ||
1238 | err(1, "getnameinfo"); | ||
1239 | else | ||
1240 | errx(1, "getnameinfo: %s", gai_strerror(herr)); | ||
1241 | } | ||
1242 | |||
1243 | fprintf(stderr, | ||
1244 | "Connection from %s %s " | ||
1245 | "received!\n", remote_host, remote_port); | ||
1246 | } | ||
1247 | |||
1248 | void | ||
1249 | help(void) | ||
1250 | { | ||
1251 | usage(0); | ||
1252 | fprintf(stderr, "\tCommand Summary:\n\ | ||
1253 | \t-4 Use IPv4\n\ | ||
1254 | \t-6 Use IPv6\n\ | ||
1255 | \t-D Enable the debug socket option\n\ | ||
1256 | \t-d Detach from stdin\n\ | ||
1257 | \t-F Pass socket fd\n\ | ||
1258 | \t-h This help text\n\ | ||
1259 | \t-I length TCP receive buffer length\n\ | ||
1260 | \t-i secs\t Delay interval for lines sent, ports scanned\n\ | ||
1261 | \t-k Keep inbound sockets open for multiple connects\n\ | ||
1262 | \t-l Listen mode, for inbound connects\n\ | ||
1263 | \t-N Shutdown the network socket after EOF on stdin\n\ | ||
1264 | \t-n Suppress name/port resolutions\n\ | ||
1265 | \t-O length TCP send buffer length\n\ | ||
1266 | \t-P proxyuser\tUsername for proxy authentication\n\ | ||
1267 | \t-p port\t Specify local port for remote connects\n\ | ||
1268 | \t-r Randomize remote ports\n\ | ||
1269 | \t-S Enable the TCP MD5 signature option\n\ | ||
1270 | \t-s addr\t Local source address\n\ | ||
1271 | \t-T toskeyword\tSet IP Type of Service\n\ | ||
1272 | \t-t Answer TELNET negotiation\n\ | ||
1273 | \t-U Use UNIX domain socket\n\ | ||
1274 | \t-u UDP mode\n\ | ||
1275 | \t-V rtable Specify alternate routing table\n\ | ||
1276 | \t-v Verbose\n\ | ||
1277 | \t-w secs\t Timeout for connects and final net reads\n\ | ||
1278 | \t-X proto Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\ | ||
1279 | \t-x addr[:port]\tSpecify proxy address and port\n\ | ||
1280 | \t-z Zero-I/O mode [used for scanning]\n\ | ||
1281 | Port numbers can be individual or ranges: lo-hi [inclusive]\n"); | ||
1282 | exit(1); | ||
1283 | } | ||
1284 | |||
1285 | void | ||
1286 | usage(int ret) | ||
1287 | { | ||
1288 | fprintf(stderr, | ||
1289 | "usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n" | ||
1290 | "\t [-P proxy_username] [-p source_port] [-s source] [-T ToS]\n" | ||
1291 | "\t [-V rtable] [-w timeout] [-X proxy_protocol]\n" | ||
1292 | "\t [-x proxy_address[:port]] [destination] [port]\n"); | ||
1293 | if (ret) | ||
1294 | exit(1); | ||
1295 | } | ||
1296 | |||
1297 | /* *** src/usr.bin/nc/socks.c *** */ | ||
1298 | |||
1299 | |||
1300 | /* $OpenBSD: socks.c,v 1.20 2012/03/08 09:56:28 espie Exp $ */ | ||
1301 | |||
1302 | /* | ||
1303 | * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. | ||
1304 | * Copyright (c) 2004, 2005 Damien Miller. All rights reserved. | ||
1305 | * | ||
1306 | * Redistribution and use in source and binary forms, with or without | ||
1307 | * modification, are permitted provided that the following conditions | ||
1308 | * are met: | ||
1309 | * 1. Redistributions of source code must retain the above copyright | ||
1310 | * notice, this list of conditions and the following disclaimer. | ||
1311 | * 2. Redistributions in binary form must reproduce the above copyright | ||
1312 | * notice, this list of conditions and the following disclaimer in the | ||
1313 | * documentation and/or other materials provided with the distribution. | ||
1314 | * | ||
1315 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
1316 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
1317 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
1318 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
1319 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
1320 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
1321 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
1322 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
1323 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
1324 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
1325 | */ | ||
1326 | |||
1327 | #include <sys/types.h> | ||
1328 | #include <sys/socket.h> | ||
1329 | #include <netinet/in.h> | ||
1330 | #include <arpa/inet.h> | ||
1331 | |||
1332 | #include <err.h> | ||
1333 | #include <errno.h> | ||
1334 | #include <netdb.h> | ||
1335 | #include <stdio.h> | ||
1336 | #include <stdlib.h> | ||
1337 | #include <string.h> | ||
1338 | #include <unistd.h> | ||
1339 | #include <resolv.h> | ||
1340 | |||
1341 | #define SOCKS_PORT "1080" | ||
1342 | #define HTTP_PROXY_PORT "3128" | ||
1343 | #define HTTP_MAXHDRS 64 | ||
1344 | #define SOCKS_V5 5 | ||
1345 | #define SOCKS_V4 4 | ||
1346 | #define SOCKS_NOAUTH 0 | ||
1347 | #define SOCKS_NOMETHOD 0xff | ||
1348 | #define SOCKS_CONNECT 1 | ||
1349 | #define SOCKS_IPV4 1 | ||
1350 | #define SOCKS_DOMAIN 3 | ||
1351 | #define SOCKS_IPV6 4 | ||
1352 | |||
1353 | int remote_connect(const char *, const char *, struct addrinfo); | ||
1354 | int socks_connect(const char *, const char *, struct addrinfo, | ||
1355 | const char *, const char *, struct addrinfo, int, | ||
1356 | const char *); | ||
1357 | |||
1358 | static int | ||
1359 | decode_addrport(const char *h, const char *p, struct sockaddr *addr, | ||
1360 | socklen_t addrlen, int v4only, int numeric) | ||
1361 | { | ||
1362 | int r; | ||
1363 | struct addrinfo hints, *res; | ||
1364 | |||
1365 | bzero(&hints, sizeof(hints)); | ||
1366 | hints.ai_family = v4only ? PF_INET : PF_UNSPEC; | ||
1367 | hints.ai_flags = numeric ? AI_NUMERICHOST : 0; | ||
1368 | hints.ai_socktype = SOCK_STREAM; | ||
1369 | r = getaddrinfo(h, p, &hints, &res); | ||
1370 | /* Don't fatal when attempting to convert a numeric address */ | ||
1371 | if (r != 0) { | ||
1372 | if (!numeric) { | ||
1373 | errx(1, "getaddrinfo(\"%.64s\", \"%.64s\"): %s", h, p, | ||
1374 | gai_strerror(r)); | ||
1375 | } | ||
1376 | return (-1); | ||
1377 | } | ||
1378 | if (addrlen < res->ai_addrlen) { | ||
1379 | freeaddrinfo(res); | ||
1380 | errx(1, "internal error: addrlen < res->ai_addrlen"); | ||
1381 | } | ||
1382 | memcpy(addr, res->ai_addr, res->ai_addrlen); | ||
1383 | freeaddrinfo(res); | ||
1384 | return (0); | ||
1385 | } | ||
1386 | |||
1387 | static int | ||
1388 | proxy_read_line(int fd, char *buf, size_t bufsz) | ||
1389 | { | ||
1390 | size_t off; | ||
1391 | |||
1392 | for(off = 0;;) { | ||
1393 | if (off >= bufsz) | ||
1394 | errx(1, "proxy read too long"); | ||
1395 | if (atomicio(read, fd, buf + off, 1) != 1) | ||
1396 | err(1, "proxy read"); | ||
1397 | /* Skip CR */ | ||
1398 | if (buf[off] == '\r') | ||
1399 | continue; | ||
1400 | if (buf[off] == '\n') { | ||
1401 | buf[off] = '\0'; | ||
1402 | break; | ||
1403 | } | ||
1404 | off++; | ||
1405 | } | ||
1406 | return (off); | ||
1407 | } | ||
1408 | |||
1409 | static const char * | ||
1410 | getproxypass(const char *proxyuser, const char *proxyhost) | ||
1411 | { | ||
1412 | char prompt[512]; | ||
1413 | static char pw[256]; | ||
1414 | |||
1415 | snprintf(prompt, sizeof(prompt), "Proxy password for %s@%s: ", | ||
1416 | proxyuser, proxyhost); | ||
1417 | if (readpassphrase(prompt, pw, sizeof(pw), RPP_REQUIRE_TTY) == NULL) | ||
1418 | errx(1, "Unable to read proxy passphrase"); | ||
1419 | return (pw); | ||
1420 | } | ||
1421 | |||
1422 | int | ||
1423 | socks_connect(const char *host, const char *port, | ||
1424 | struct addrinfo hints __attribute__ ((__unused__)), | ||
1425 | const char *proxyhost, const char *proxyport, struct addrinfo proxyhints, | ||
1426 | int socksv, const char *proxyuser) | ||
1427 | { | ||
1428 | int proxyfd, r, authretry = 0; | ||
1429 | size_t hlen, wlen; | ||
1430 | unsigned char buf[1024]; | ||
1431 | size_t cnt; | ||
1432 | struct sockaddr_storage addr; | ||
1433 | struct sockaddr_in *in4 = (struct sockaddr_in *)&addr; | ||
1434 | struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr; | ||
1435 | in_port_t serverport; | ||
1436 | const char *proxypass = NULL; | ||
1437 | |||
1438 | if (proxyport == NULL) | ||
1439 | proxyport = (socksv == -1) ? HTTP_PROXY_PORT : SOCKS_PORT; | ||
1440 | |||
1441 | /* Abuse API to lookup port */ | ||
1442 | if (decode_addrport("0.0.0.0", port, (struct sockaddr *)&addr, | ||
1443 | sizeof(addr), 1, 1) == -1) | ||
1444 | errx(1, "unknown port \"%.64s\"", port); | ||
1445 | serverport = in4->sin_port; | ||
1446 | |||
1447 | again: | ||
1448 | if (authretry++ > 3) | ||
1449 | errx(1, "Too many authentication failures"); | ||
1450 | |||
1451 | proxyfd = remote_connect(proxyhost, proxyport, proxyhints); | ||
1452 | |||
1453 | if (proxyfd < 0) | ||
1454 | return (-1); | ||
1455 | |||
1456 | if (socksv == 5) { | ||
1457 | if (decode_addrport(host, port, (struct sockaddr *)&addr, | ||
1458 | sizeof(addr), 0, 1) == -1) | ||
1459 | addr.ss_family = 0; /* used in switch below */ | ||
1460 | |||
1461 | /* Version 5, one method: no authentication */ | ||
1462 | buf[0] = SOCKS_V5; | ||
1463 | buf[1] = 1; | ||
1464 | buf[2] = SOCKS_NOAUTH; | ||
1465 | cnt = atomicio(vwrite, proxyfd, buf, 3); | ||
1466 | if (cnt != 3) | ||
1467 | err(1, "write failed (%zu/3)", cnt); | ||
1468 | |||
1469 | cnt = atomicio(read, proxyfd, buf, 2); | ||
1470 | if (cnt != 2) | ||
1471 | err(1, "read failed (%zu/3)", cnt); | ||
1472 | |||
1473 | if (buf[1] == SOCKS_NOMETHOD) | ||
1474 | errx(1, "authentication method negotiation failed"); | ||
1475 | |||
1476 | switch (addr.ss_family) { | ||
1477 | case 0: | ||
1478 | /* Version 5, connect: domain name */ | ||
1479 | |||
1480 | /* Max domain name length is 255 bytes */ | ||
1481 | hlen = strlen(host); | ||
1482 | if (hlen > 255) | ||
1483 | errx(1, "host name too long for SOCKS5"); | ||
1484 | buf[0] = SOCKS_V5; | ||
1485 | buf[1] = SOCKS_CONNECT; | ||
1486 | buf[2] = 0; | ||
1487 | buf[3] = SOCKS_DOMAIN; | ||
1488 | buf[4] = hlen; | ||
1489 | memcpy(buf + 5, host, hlen); | ||
1490 | memcpy(buf + 5 + hlen, &serverport, sizeof serverport); | ||
1491 | wlen = 7 + hlen; | ||
1492 | break; | ||
1493 | case AF_INET: | ||
1494 | /* Version 5, connect: IPv4 address */ | ||
1495 | buf[0] = SOCKS_V5; | ||
1496 | buf[1] = SOCKS_CONNECT; | ||
1497 | buf[2] = 0; | ||
1498 | buf[3] = SOCKS_IPV4; | ||
1499 | memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr); | ||
1500 | memcpy(buf + 8, &in4->sin_port, sizeof in4->sin_port); | ||
1501 | wlen = 10; | ||
1502 | break; | ||
1503 | case AF_INET6: | ||
1504 | /* Version 5, connect: IPv6 address */ | ||
1505 | buf[0] = SOCKS_V5; | ||
1506 | buf[1] = SOCKS_CONNECT; | ||
1507 | buf[2] = 0; | ||
1508 | buf[3] = SOCKS_IPV6; | ||
1509 | memcpy(buf + 4, &in6->sin6_addr, sizeof in6->sin6_addr); | ||
1510 | memcpy(buf + 20, &in6->sin6_port, | ||
1511 | sizeof in6->sin6_port); | ||
1512 | wlen = 22; | ||
1513 | break; | ||
1514 | default: | ||
1515 | errx(1, "internal error: silly AF"); | ||
1516 | } | ||
1517 | |||
1518 | cnt = atomicio(vwrite, proxyfd, buf, wlen); | ||
1519 | if (cnt != wlen) | ||
1520 | err(1, "write failed (%zu/%zu)", cnt, wlen); | ||
1521 | |||
1522 | cnt = atomicio(read, proxyfd, buf, 4); | ||
1523 | if (cnt != 4) | ||
1524 | err(1, "read failed (%zu/4)", cnt); | ||
1525 | if (buf[1] != 0) | ||
1526 | errx(1, "connection failed, SOCKS error %d", buf[1]); | ||
1527 | switch (buf[3]) { | ||
1528 | case SOCKS_IPV4: | ||
1529 | cnt = atomicio(read, proxyfd, buf + 4, 6); | ||
1530 | if (cnt != 6) | ||
1531 | err(1, "read failed (%zu/6)", cnt); | ||
1532 | break; | ||
1533 | case SOCKS_IPV6: | ||
1534 | cnt = atomicio(read, proxyfd, buf + 4, 18); | ||
1535 | if (cnt != 18) | ||
1536 | err(1, "read failed (%zu/18)", cnt); | ||
1537 | break; | ||
1538 | default: | ||
1539 | errx(1, "connection failed, unsupported address type"); | ||
1540 | } | ||
1541 | } else if (socksv == 4) { | ||
1542 | /* This will exit on lookup failure */ | ||
1543 | decode_addrport(host, port, (struct sockaddr *)&addr, | ||
1544 | sizeof(addr), 1, 0); | ||
1545 | |||
1546 | /* Version 4 */ | ||
1547 | buf[0] = SOCKS_V4; | ||
1548 | buf[1] = SOCKS_CONNECT; /* connect */ | ||
1549 | memcpy(buf + 2, &in4->sin_port, sizeof in4->sin_port); | ||
1550 | memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr); | ||
1551 | buf[8] = 0; /* empty username */ | ||
1552 | wlen = 9; | ||
1553 | |||
1554 | cnt = atomicio(vwrite, proxyfd, buf, wlen); | ||
1555 | if (cnt != wlen) | ||
1556 | err(1, "write failed (%zu/%zu)", cnt, wlen); | ||
1557 | |||
1558 | cnt = atomicio(read, proxyfd, buf, 8); | ||
1559 | if (cnt != 8) | ||
1560 | err(1, "read failed (%zu/8)", cnt); | ||
1561 | if (buf[1] != 90) | ||
1562 | errx(1, "connection failed, SOCKS error %d", buf[1]); | ||
1563 | } else if (socksv == -1) { | ||
1564 | /* HTTP proxy CONNECT */ | ||
1565 | |||
1566 | /* Disallow bad chars in hostname */ | ||
1567 | if (strcspn(host, "\r\n\t []:") != strlen(host)) | ||
1568 | errx(1, "Invalid hostname"); | ||
1569 | |||
1570 | /* Try to be sane about numeric IPv6 addresses */ | ||
1571 | if (strchr(host, ':') != NULL) { | ||
1572 | r = snprintf(buf, sizeof(buf), | ||
1573 | "CONNECT [%s]:%d HTTP/1.0\r\n", | ||
1574 | host, ntohs(serverport)); | ||
1575 | } else { | ||
1576 | r = snprintf(buf, sizeof(buf), | ||
1577 | "CONNECT %s:%d HTTP/1.0\r\n", | ||
1578 | host, ntohs(serverport)); | ||
1579 | } | ||
1580 | if (r == -1 || (size_t)r >= sizeof(buf)) | ||
1581 | errx(1, "hostname too long"); | ||
1582 | r = strlen(buf); | ||
1583 | |||
1584 | cnt = atomicio(vwrite, proxyfd, buf, r); | ||
1585 | if (cnt != (size_t)r) | ||
1586 | err(1, "write failed (%zu/%d)", cnt, r); | ||
1587 | |||
1588 | if (authretry > 1) { | ||
1589 | char resp[1024]; | ||
1590 | |||
1591 | proxypass = getproxypass(proxyuser, proxyhost); | ||
1592 | r = snprintf(buf, sizeof(buf), "%s:%s", | ||
1593 | proxyuser, proxypass); | ||
1594 | if (r == -1 || (size_t)r >= sizeof(buf) || | ||
1595 | b64_ntop(buf, strlen(buf), resp, | ||
1596 | sizeof(resp)) == -1) | ||
1597 | errx(1, "Proxy username/password too long"); | ||
1598 | r = snprintf(buf, sizeof(buf), "Proxy-Authorization: " | ||
1599 | "Basic %s\r\n", resp); | ||
1600 | if (r == -1 || (size_t)r >= sizeof(buf)) | ||
1601 | errx(1, "Proxy auth response too long"); | ||
1602 | r = strlen(buf); | ||
1603 | if ((cnt = atomicio(vwrite, proxyfd, buf, r)) != (size_t)r) | ||
1604 | err(1, "write failed (%zu/%d)", cnt, r); | ||
1605 | } | ||
1606 | |||
1607 | /* Terminate headers */ | ||
1608 | if ((r = atomicio(vwrite, proxyfd, "\r\n", 2)) != 2) | ||
1609 | err(1, "write failed (2/%d)", r); | ||
1610 | |||
1611 | /* Read status reply */ | ||
1612 | proxy_read_line(proxyfd, buf, sizeof(buf)); | ||
1613 | if (proxyuser != NULL && | ||
1614 | strncmp(buf, "HTTP/1.0 407 ", 12) == 0) { | ||
1615 | if (authretry > 1) { | ||
1616 | fprintf(stderr, "Proxy authentication " | ||
1617 | "failed\n"); | ||
1618 | } | ||
1619 | close(proxyfd); | ||
1620 | goto again; | ||
1621 | } else if (strncmp(buf, "HTTP/1.0 200 ", 12) != 0 && | ||
1622 | strncmp(buf, "HTTP/1.1 200 ", 12) != 0) | ||
1623 | errx(1, "Proxy error: \"%s\"", buf); | ||
1624 | |||
1625 | /* Headers continue until we hit an empty line */ | ||
1626 | for (r = 0; r < HTTP_MAXHDRS; r++) { | ||
1627 | proxy_read_line(proxyfd, buf, sizeof(buf)); | ||
1628 | if (*buf == '\0') | ||
1629 | break; | ||
1630 | } | ||
1631 | if (*buf != '\0') | ||
1632 | errx(1, "Too many proxy headers received"); | ||
1633 | } else | ||
1634 | errx(1, "Unknown proxy protocol %d", socksv); | ||
1635 | |||
1636 | return (proxyfd); | ||
1637 | } | ||
1638 | |||