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