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