Annotation of src/usr.bin/nc/netcat.c, Revision 1.41
1.41 ! ericj 1: /* $OpenBSD: netcat.c,v 1.40 2002/02/16 21:27:50 millert Exp $ */
1.21 ericj 2: /*
3: * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
1.7 deraadt 4: *
1.21 ericj 5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
1.7 deraadt 8: *
1.21 ericj 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.
1.7 deraadt 16: *
1.21 ericj 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: */
1.1 deraadt 28:
1.24 ericj 29: /*
30: * Re-written nc(1) for OpenBSD. Original implementation by
1.21 ericj 31: * *Hobbit* <hobbit@avian.org>.
32: */
1.1 deraadt 33:
1.7 deraadt 34: #include <sys/types.h>
1.21 ericj 35: #include <sys/socket.h>
1.7 deraadt 36: #include <sys/time.h>
1.21 ericj 37:
1.7 deraadt 38: #include <netinet/in.h>
1.21 ericj 39: #include <arpa/telnet.h>
1.29 smart 40:
1.11 ericj 41: #include <err.h>
1.7 deraadt 42: #include <errno.h>
1.21 ericj 43: #include <netdb.h>
44: #include <poll.h>
1.13 ericj 45: #include <stdarg.h>
1.21 ericj 46: #include <stdio.h>
1.1 deraadt 47: #include <stdlib.h>
1.21 ericj 48: #include <string.h>
1.5 art 49: #include <unistd.h>
1.1 deraadt 50:
1.31 ericj 51: #define PORT_MAX 65535
52:
1.21 ericj 53: /* Command Line Options */
54: int iflag; /* Interval Flag */
55: int kflag; /* More than one connect */
56: int lflag; /* Bind to local port */
57: int nflag; /* Dont do name lookup */
58: char *pflag; /* Localport flag */
59: int rflag; /* Random ports flag */
60: char *sflag; /* Source Address */
61: int tflag; /* Telnet Emulation */
62: int uflag; /* UDP - Default to TCP */
63: int vflag; /* Verbosity */
1.34 jakob 64: int xflag; /* Socks proxy */
1.21 ericj 65: int zflag; /* Port Scan Flag */
66:
67: int timeout;
68: int family = AF_UNSPEC;
1.31 ericj 69: char *portlist[PORT_MAX];
1.21 ericj 70:
1.29 smart 71: ssize_t atomicio __P((ssize_t (*)(), int, void *, size_t));
1.40 millert 72: void atelnet(int, unsigned char *, unsigned int);
73: void build_ports(char *);
74: void help(void);
75: int local_listen(char *, char *, struct addrinfo);
76: void readwrite(int);
77: int remote_connect(char *, char *, struct addrinfo);
78: int udptest(int);
79: void usage(int);
1.1 deraadt 80:
1.21 ericj 81: int
1.37 jakob 82: main(int argc, char *argv[])
1.21 ericj 83: {
1.29 smart 84: int ch, s, ret;
1.26 ericj 85: char *host, *uport, *endp;
1.21 ericj 86: struct addrinfo hints;
1.29 smart 87: struct servent *sv;
1.21 ericj 88: socklen_t len;
89: struct sockaddr *cliaddr;
1.34 jakob 90: char *proxy;
91: char *proxyhost, *proxyport;
92: struct addrinfo proxyhints;
1.11 ericj 93:
1.29 smart 94: ret = 1;
95: s = 0;
96: host = NULL;
97: uport = NULL;
98: endp = NULL;
99: sv = NULL;
100:
1.34 jakob 101: while ((ch = getopt(argc, argv, "46hi:klnp:rs:tuvw:x:z")) != -1) {
1.21 ericj 102: switch (ch) {
103: case '4':
104: family = AF_INET;
105: break;
106: case '6':
107: family = AF_INET6;
108: break;
109: case 'h':
110: help();
111: break;
112: case 'i':
1.26 ericj 113: iflag = (int)strtoul(optarg, &endp, 10);
114: if (iflag < 0 || *endp != '\0')
115: errx(1, "interval cannot be negative");
1.21 ericj 116: break;
117: case 'k':
118: kflag = 1;
119: break;
120: case 'l':
121: lflag = 1;
122: break;
123: case 'n':
124: nflag = 1;
125: break;
126: case 'p':
127: pflag = optarg;
128: break;
129: case 'r':
130: rflag = 1;
131: break;
132: case 's':
133: sflag = optarg;
134: break;
135: case 't':
136: tflag = 1;
137: break;
138: case 'u':
139: uflag = 1;
140: break;
141: case 'v':
142: vflag = 1;
143: break;
1.26 ericj 144: case 'w':
145: timeout = (int)strtoul(optarg, &endp, 10);
146: if (timeout < 0 || *endp != '\0')
147: errx(1, "timeout cannot be negative");
1.21 ericj 148: break;
1.34 jakob 149: case 'x':
150: xflag = 1;
151: proxy = strdup(optarg);
152: break;
1.21 ericj 153: case 'z':
154: zflag = 1;
155: break;
156: default:
157: usage(1);
158: }
159: }
160: argc -= optind;
161: argv += optind;
1.11 ericj 162:
1.21 ericj 163: /* Cruft to make sure options are clean, and used properly. */
164: if (argv[0] && !argv[1]) {
165: if (!lflag)
166: usage(1);
167: uport = argv[0];
168: host = NULL;
169: } else if (argv[0] && argv[1]) {
170: host = argv[0];
171: uport = argv[1];
172: } else
173: usage(1);
1.1 deraadt 174:
1.21 ericj 175: if (lflag && sflag)
176: errx(1, "cannot use -s and -l");
177: if (lflag && pflag)
178: errx(1, "cannot use -p and -l");
179: if (lflag && zflag)
1.32 ericj 180: errx(1, "cannot use -z and -l");
1.21 ericj 181: if (!lflag && kflag)
1.32 ericj 182: errx(1, "must use -l with -k");
1.21 ericj 183:
184: /* Initialize addrinfo structure */
185: memset(&hints, 0, sizeof(struct addrinfo));
186: hints.ai_family = family;
187: hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
188: hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
189: if (nflag)
190: hints.ai_flags |= AI_NUMERICHOST;
1.1 deraadt 191:
1.34 jakob 192: if (xflag) {
193: if (uflag)
194: errx(1, "no proxy support for UDP mode");
195:
196: if (lflag)
197: errx(1, "no proxy support for listen");
198:
199: /* XXX IPv6 transport to proxy would probably work */
200: if (family == AF_INET6)
201: errx(1, "no proxy support for IPv6");
202:
203: if (sflag)
204: errx(1, "no proxy support for local source address");
205:
206: proxyhost = strsep(&proxy, ":");
207: proxyport = proxy;
208:
209: memset(&proxyhints, 0, sizeof(struct addrinfo));
210: proxyhints.ai_family = family;
211: proxyhints.ai_socktype = SOCK_STREAM;
212: proxyhints.ai_protocol = IPPROTO_TCP;
213: if (nflag)
214: proxyhints.ai_flags |= AI_NUMERICHOST;
215: }
216:
1.21 ericj 217: if (lflag) {
218: int connfd;
1.27 ericj 219: ret = 0;
1.1 deraadt 220:
1.21 ericj 221: /* Allow only one connection at a time, but stay alive */
222: for (;;) {
1.27 ericj 223: if ((s = local_listen(host, uport, hints)) < 0)
1.30 smart 224: err(1, NULL);
1.21 ericj 225: /*
226: * For UDP, we will use recvfrom() initially
227: * to wait for a caller, then use the regular
228: * functions to talk to the caller.
229: */
230: if (uflag) {
1.23 ericj 231: int rv;
1.21 ericj 232: char buf[1024];
233: struct sockaddr_storage z;
234:
235: len = sizeof(z);
1.23 ericj 236: rv = recvfrom(s, buf, sizeof(buf), MSG_PEEK,
1.37 jakob 237: (struct sockaddr *)&z, &len);
1.23 ericj 238: if (rv < 0)
1.21 ericj 239: errx(1, "%s", strerror(errno));
240:
1.37 jakob 241: rv = connect(s, (struct sockaddr *)&z, len);
1.23 ericj 242: if (rv < 0)
1.21 ericj 243: errx(1, "%s", strerror(errno));
1.1 deraadt 244:
1.21 ericj 245: connfd = s;
246: } else {
247: connfd = accept(s, (struct sockaddr *)&cliaddr,
1.37 jakob 248: &len);
1.21 ericj 249: }
1.1 deraadt 250:
1.21 ericj 251: readwrite(connfd);
252: close(connfd);
1.27 ericj 253: close(s);
254:
1.21 ericj 255: if (!kflag)
256: break;
1.11 ericj 257: }
1.21 ericj 258: } else {
259: int i = 0;
1.6 deraadt 260:
1.21 ericj 261: /* construct the portlist[] array */
262: build_ports(uport);
1.1 deraadt 263:
1.21 ericj 264: /* Cycle through portlist, connecting to each port */
265: for (i = 0; portlist[i] != NULL; i++) {
266:
267: if (s)
268: close(s);
1.34 jakob 269:
270: if (xflag)
271: s = socks_connect(host, portlist[i], hints,
272: proxyhost, proxyport, proxyhints);
273: else
274: s = remote_connect(host, portlist[i], hints);
275:
276: if (s < 0)
1.21 ericj 277: continue;
1.1 deraadt 278:
1.21 ericj 279: ret = 0;
280: if (vflag || zflag) {
281: /* For UDP, make sure we are connected */
282: if (uflag) {
283: if ((udptest(s)) == -1) {
284: ret = 1;
285: continue;
286: }
287: }
1.1 deraadt 288:
1.21 ericj 289: /* Don't lookup port if -n */
290: if (nflag)
291: sv = NULL;
292: else {
293: sv = getservbyport(
1.37 jakob 294: ntohs(atoi(portlist[i])),
295: uflag ? "udp" : "tcp");
1.21 ericj 296: }
297:
298: printf("Connection to %s %s port [%s/%s] succeeded!\n",
1.37 jakob 299: host, portlist[i], uflag ? "udp" : "tcp",
300: sv ? sv->s_name : "*");
1.21 ericj 301: }
302: if (!zflag)
303: readwrite(s);
1.7 deraadt 304: }
1.11 ericj 305: }
1.1 deraadt 306:
1.21 ericj 307: if (s)
308: close(s);
309:
310: exit(ret);
1.7 deraadt 311: }
1.1 deraadt 312:
1.11 ericj 313: /*
1.21 ericj 314: * remote_connect()
315: * Return's a socket connected to a remote host. Properly bind's to a local
316: * port or source address if needed. Return's -1 on failure.
1.11 ericj 317: */
1.21 ericj 318: int
1.37 jakob 319: remote_connect(char *host, char *port, struct addrinfo hints)
1.21 ericj 320: {
321: struct addrinfo *res, *res0;
322: int s, error;
323:
324: if ((error = getaddrinfo(host, port, &hints, &res)))
325: errx(1, "%s", gai_strerror(error));
326:
327: res0 = res;
328: do {
329: if ((s = socket(res0->ai_family, res0->ai_socktype,
1.37 jakob 330: res0->ai_protocol)) < 0)
1.21 ericj 331: continue;
332:
333: /* Bind to a local port or source address if specified */
334: if (sflag || pflag) {
335: struct addrinfo ahints, *ares;
336:
337: if (!(sflag && pflag)) {
338: if (!sflag)
339: sflag = NULL;
340: else
341: pflag = NULL;
342: }
1.6 deraadt 343:
1.21 ericj 344: memset(&ahints, 0, sizeof(struct addrinfo));
345: ahints.ai_family = res0->ai_family;
346: ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
347: ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
1.25 ericj 348: ahints.ai_flags = AI_PASSIVE;
1.38 jakob 349: if ((error = getaddrinfo(sflag, pflag, &ahints, &ares)))
1.21 ericj 350: errx(1, "%s", gai_strerror(error));
351:
352: if (bind(s, (struct sockaddr *)ares->ai_addr,
1.37 jakob 353: ares->ai_addrlen) < 0) {
1.21 ericj 354: errx(1, "bind failed: %s", strerror(errno));
355: freeaddrinfo(ares);
356: continue;
357: }
358: freeaddrinfo(ares);
1.6 deraadt 359: }
360:
1.21 ericj 361: if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
1.6 deraadt 362: break;
1.34 jakob 363:
1.21 ericj 364: close(s);
365: s = -1;
366: } while ((res0 = res0->ai_next) != NULL);
367:
368: freeaddrinfo(res);
1.1 deraadt 369:
1.21 ericj 370: return (s);
1.7 deraadt 371: }
1.1 deraadt 372:
1.11 ericj 373: /*
1.21 ericj 374: * local_listen()
375: * Return's a socket listening on a local port, binds to specified source
376: * address. Return's -1 on failure.
1.11 ericj 377: */
1.21 ericj 378: int
1.37 jakob 379: local_listen(char *host, char *port, struct addrinfo hints)
1.21 ericj 380: {
381: struct addrinfo *res, *res0;
382: int s, ret, x = 1;
383: int error;
1.6 deraadt 384:
1.21 ericj 385: /* Allow nodename to be null */
386: hints.ai_flags |= AI_PASSIVE;
1.7 deraadt 387:
1.21 ericj 388: /*
389: * In the case of binding to a wildcard address
390: * default to binding to an ipv4 address.
391: */
392: if (host == NULL && hints.ai_family == AF_UNSPEC)
393: hints.ai_family = AF_INET;
1.1 deraadt 394:
1.21 ericj 395: if ((error = getaddrinfo(host, port, &hints, &res)))
396: errx(1, "%s", gai_strerror(error));
1.14 ericj 397:
1.21 ericj 398: res0 = res;
399: do {
400: if ((s = socket(res0->ai_family, res0->ai_socktype,
1.37 jakob 401: res0->ai_protocol)) == 0)
1.21 ericj 402: continue;
1.1 deraadt 403:
1.21 ericj 404: ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));
405: if (ret == -1)
1.30 smart 406: err(1, NULL);
1.1 deraadt 407:
1.21 ericj 408: if (bind(s, (struct sockaddr *)res0->ai_addr,
1.37 jakob 409: res0->ai_addrlen) == 0)
1.21 ericj 410: break;
1.1 deraadt 411:
1.21 ericj 412: close(s);
413: s = -1;
414: } while ((res0 = res0->ai_next) != NULL);
1.1 deraadt 415:
1.21 ericj 416: if (!uflag) {
417: if (listen(s, 1) < 0)
418: errx(1, "%s", strerror(errno));
1.12 ericj 419: }
1.1 deraadt 420:
1.21 ericj 421: freeaddrinfo(res);
1.1 deraadt 422:
1.21 ericj 423: return (s);
1.7 deraadt 424: }
425:
1.11 ericj 426: /*
1.21 ericj 427: * readwrite()
428: * Loop that polls on the network file descriptor and stdin.
1.11 ericj 429: */
1.21 ericj 430: void
1.37 jakob 431: readwrite(int nfd)
1.6 deraadt 432: {
1.21 ericj 433: struct pollfd *pfd;
434: char buf[BUFSIZ];
435: int wfd = fileno(stdin), n, ret;
436: int lfd = fileno(stdout);
437:
438: pfd = malloc(2 * sizeof(struct pollfd));
439:
440: /* Setup Network FD */
441: pfd[0].fd = nfd;
442: pfd[0].events = POLLIN;
443:
444: /* Setup STDIN FD */
445: pfd[1].fd = wfd;
446: pfd[1].events = POLLIN;
447:
448: for (;;) {
449: if (iflag)
450: sleep(iflag);
451:
452: if (poll(pfd, 2, timeout) < 0) {
453: close(nfd);
454: close(wfd);
455: free(pfd);
456: errx(1, "Polling Error");
457: }
458:
459: if (pfd[0].revents & POLLIN) {
460: if ((n = read(nfd, buf, sizeof(buf))) <= 0) {
461: return;
462: } else {
463: if (tflag)
464: atelnet(nfd, buf, n);
465: if ((ret = atomicio(write, lfd, buf, n)) != n)
466: return;
1.6 deraadt 467: }
1.21 ericj 468: }
469:
470: if (pfd[1].revents & POLLIN) {
1.41 ! ericj 471: if ((n = read(wfd, buf, sizeof(buf))) < 0) {
1.21 ericj 472: return;
473: } else
474: if((ret = atomicio(write, nfd, buf, n)) != n)
475: return;
476: }
1.11 ericj 477: }
1.7 deraadt 478: }
1.24 ericj 479: /* Deal with RFC854 WILL/WONT DO/DONT negotiation */
1.21 ericj 480: void
1.37 jakob 481: atelnet(int nfd, unsigned char *buf, unsigned int size)
1.6 deraadt 482: {
1.28 ericj 483: int ret;
1.24 ericj 484: unsigned char *p, *end;
485: unsigned char obuf[4];
486:
487: end = buf + size;
488: obuf[0] = '\0';
489:
490: for (p = buf; p < end; p++) {
1.21 ericj 491: if (*p != IAC)
1.24 ericj 492: break;
493:
1.25 ericj 494: obuf[0] = IAC;
1.24 ericj 495: p++;
496: if ((*p == WILL) || (*p == WONT)) {
497: obuf[1] = DONT;
498: }
499: if ((*p == DO) || (*p == DONT)) {
500: obuf[1] = WONT;
501: }
502: if (obuf) {
503: p++;
1.11 ericj 504: obuf[2] = *p;
1.24 ericj 505: obuf[3] = '\0';
1.21 ericj 506: if ((ret = atomicio(write , nfd, obuf, 3)) != 3)
507: warnx("Write Error!");
1.24 ericj 508: obuf[0] = '\0';
1.11 ericj 509: }
510: }
1.7 deraadt 511: }
512:
1.11 ericj 513: /*
1.21 ericj 514: * build_ports()
515: * Build an array or ports in portlist[], listing each port
516: * that we should try to connect too.
1.11 ericj 517: */
1.21 ericj 518: void
1.37 jakob 519: build_ports(char *p)
1.6 deraadt 520: {
1.26 ericj 521: char *n, *endp;
1.21 ericj 522: int hi, lo, cp;
523: int x = 0;
524:
525: if ((n = strchr(p, '-')) != NULL) {
526: if (lflag)
527: errx(1, "Cannot use -l with multiple ports!");
528:
529: *n = '\0';
530: n++;
531:
532: /* Make sure the ports are in order: lowest->highest */
1.26 ericj 533: hi = (int)strtoul(n, &endp, 10);
1.31 ericj 534: if (hi <= 0 || hi > PORT_MAX || *endp != '\0')
1.26 ericj 535: errx(1, "port range not valid");
536: lo = (int)strtoul(p, &endp, 10);
1.31 ericj 537: if (lo <= 0 || lo > PORT_MAX || *endp != '\0')
1.26 ericj 538: errx(1, "port range not valid");
1.21 ericj 539:
540: if (lo > hi) {
541: cp = hi;
542: hi = lo;
543: lo = cp;
544: }
545:
546: /* Load ports sequentially */
547: for (cp = lo; cp <= hi; cp++) {
1.33 ericj 548: portlist[x] = calloc(1, PORT_MAX);
1.21 ericj 549: sprintf(portlist[x], "%d", cp);
550: x++;
551: }
552:
553: /* Randomly swap ports */
554: if (rflag) {
555: int y;
556: char *c;
557:
558: for (x = 0; x <= (hi - lo); x++) {
559: y = (arc4random() & 0xFFFF) % (hi - lo);
560: c = portlist[x];
561: portlist[x] = portlist[y];
562: portlist[y] = c;
1.6 deraadt 563: }
1.11 ericj 564: }
1.21 ericj 565: } else {
1.26 ericj 566: hi = (int)strtoul(p, &endp, 10);
1.31 ericj 567: if (hi <= 0 || hi > PORT_MAX || *endp != '\0')
1.26 ericj 568: errx(1, "port range not valid");
1.33 ericj 569: portlist[0] = calloc(1, PORT_MAX);
1.21 ericj 570: portlist[0] = p;
1.11 ericj 571: }
1.13 ericj 572: }
573:
574: /*
1.21 ericj 575: * udptest()
576: * Do a few writes to see if the UDP port is there.
577: * XXX - Better way of doing this? Doesn't work for IPv6
578: * Also fails after around 100 ports checked.
1.13 ericj 579: */
1.21 ericj 580: int
1.37 jakob 581: udptest(int s)
1.13 ericj 582: {
1.21 ericj 583: int i, rv, ret;
1.13 ericj 584:
1.21 ericj 585: for (i=0; i <= 3; i++) {
586: if ((rv = write(s, "X", 1)) == 1)
587: ret = 1;
1.14 ericj 588: else
1.21 ericj 589: ret = -1;
1.14 ericj 590: }
1.21 ericj 591: return (ret);
1.7 deraadt 592: }
1.1 deraadt 593:
1.11 ericj 594: void
1.21 ericj 595: help()
1.1 deraadt 596: {
1.21 ericj 597: usage(0);
598: fprintf(stderr, "\tCommand Summary:\n\
599: \t-4 Use IPv4\n\
600: \t-6 Use IPv6\n\
601: \t-h This help text\n\
602: \t-i secs\t Delay interval for lines sent, ports scanned\n\
603: \t-k Keep inbound sockets open for multiple connects\n\
604: \t-l Listen mode, for inbound connects\n\
1.22 jasoni 605: \t-n Suppress name/port resolutions\n\
1.36 jakob 606: \t-p port\t Specify local port for remote connects\n\
1.21 ericj 607: \t-r Randomize remote ports\n\
608: \t-s addr\t Local source address\n\
609: \t-t Answer TELNET negotiation\n\
610: \t-u UDP mode\n\
611: \t-v Verbose\n\
612: \t-w secs\t Timeout for connects and final net reads\n\
1.34 jakob 613: \t-x addr[:port]\tSpecify socks5 proxy address and port\n\
1.21 ericj 614: \t-z Zero-I/O mode [used for scanning]\n\
615: Port numbers can be individual or ranges: lo-hi [inclusive]\n");
616: exit(1);
1.11 ericj 617: }
618:
619: void
1.37 jakob 620: usage(int ret)
1.11 ericj 621: {
1.21 ericj 622: fprintf(stderr, "usage: nc [-46hklnrtuvz] [-i interval] [-p source port]\n");
1.36 jakob 623: fprintf(stderr, "\t [-s ip address] [-w timeout] [-x proxy address [:port]]\n");
624: fprintf(stderr, "\t [hostname] [port[s...]]\n");
1.21 ericj 625: if (ret)
626: exit(1);
1.7 deraadt 627: }