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