Annotation of src/usr.bin/nc/netcat.c, Revision 1.38
1.38 ! jakob 1: /* $OpenBSD: netcat.c,v 1.37 2001/09/02 19:11:46 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
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:
364: if (error == 0)
365: break;
1.21 ericj 366:
367: close(s);
368: s = -1;
369: } while ((res0 = res0->ai_next) != NULL);
370:
371: freeaddrinfo(res);
1.1 deraadt 372:
1.21 ericj 373: return (s);
1.7 deraadt 374: }
1.1 deraadt 375:
1.11 ericj 376: /*
1.21 ericj 377: * local_listen()
378: * Return's a socket listening on a local port, binds to specified source
379: * address. Return's -1 on failure.
1.11 ericj 380: */
1.21 ericj 381: int
1.37 jakob 382: local_listen(char *host, char *port, struct addrinfo hints)
1.21 ericj 383: {
384: struct addrinfo *res, *res0;
385: int s, ret, x = 1;
386: int error;
1.6 deraadt 387:
1.21 ericj 388: /* Allow nodename to be null */
389: hints.ai_flags |= AI_PASSIVE;
1.7 deraadt 390:
1.21 ericj 391: /*
392: * In the case of binding to a wildcard address
393: * default to binding to an ipv4 address.
394: */
395: if (host == NULL && hints.ai_family == AF_UNSPEC)
396: hints.ai_family = AF_INET;
1.1 deraadt 397:
1.21 ericj 398: if ((error = getaddrinfo(host, port, &hints, &res)))
399: errx(1, "%s", gai_strerror(error));
1.14 ericj 400:
1.21 ericj 401: res0 = res;
402: do {
403: if ((s = socket(res0->ai_family, res0->ai_socktype,
1.37 jakob 404: res0->ai_protocol)) == 0)
1.21 ericj 405: continue;
1.1 deraadt 406:
1.21 ericj 407: ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));
408: if (ret == -1)
1.30 smart 409: err(1, NULL);
1.1 deraadt 410:
1.21 ericj 411: if (bind(s, (struct sockaddr *)res0->ai_addr,
1.37 jakob 412: res0->ai_addrlen) == 0)
1.21 ericj 413: break;
1.1 deraadt 414:
1.21 ericj 415: close(s);
416: s = -1;
417: } while ((res0 = res0->ai_next) != NULL);
1.1 deraadt 418:
1.21 ericj 419: if (!uflag) {
420: if (listen(s, 1) < 0)
421: errx(1, "%s", strerror(errno));
1.12 ericj 422: }
1.1 deraadt 423:
1.21 ericj 424: freeaddrinfo(res);
1.1 deraadt 425:
1.21 ericj 426: return (s);
1.7 deraadt 427: }
428:
1.11 ericj 429: /*
1.21 ericj 430: * readwrite()
431: * Loop that polls on the network file descriptor and stdin.
1.11 ericj 432: */
1.21 ericj 433: void
1.37 jakob 434: readwrite(int nfd)
1.6 deraadt 435: {
1.21 ericj 436: struct pollfd *pfd;
437: char buf[BUFSIZ];
438: int wfd = fileno(stdin), n, ret;
439: int lfd = fileno(stdout);
440:
441: pfd = malloc(2 * sizeof(struct pollfd));
442:
443: /* Setup Network FD */
444: pfd[0].fd = nfd;
445: pfd[0].events = POLLIN;
446:
447: /* Setup STDIN FD */
448: pfd[1].fd = wfd;
449: pfd[1].events = POLLIN;
450:
451: for (;;) {
452: if (iflag)
453: sleep(iflag);
454:
455: if (poll(pfd, 2, timeout) < 0) {
456: close(nfd);
457: close(wfd);
458: free(pfd);
459: errx(1, "Polling Error");
460: }
461:
462: if (pfd[0].revents & POLLIN) {
463: if ((n = read(nfd, buf, sizeof(buf))) <= 0) {
464: return;
465: } else {
466: if (tflag)
467: atelnet(nfd, buf, n);
468: if ((ret = atomicio(write, lfd, buf, n)) != n)
469: return;
1.6 deraadt 470: }
1.21 ericj 471: }
472:
473: if (pfd[1].revents & POLLIN) {
474: if ((n = read(wfd, buf, sizeof(buf))) <= 0) {
475: return;
476: } else
477: if((ret = atomicio(write, nfd, buf, n)) != n)
478: return;
479: }
1.11 ericj 480: }
1.7 deraadt 481: }
1.24 ericj 482: /* Deal with RFC854 WILL/WONT DO/DONT negotiation */
1.21 ericj 483: void
1.37 jakob 484: atelnet(int nfd, unsigned char *buf, unsigned int size)
1.6 deraadt 485: {
1.28 ericj 486: int ret;
1.24 ericj 487: unsigned char *p, *end;
488: unsigned char obuf[4];
489:
490: end = buf + size;
491: obuf[0] = '\0';
492:
493: for (p = buf; p < end; p++) {
1.21 ericj 494: if (*p != IAC)
1.24 ericj 495: break;
496:
1.25 ericj 497: obuf[0] = IAC;
1.24 ericj 498: p++;
499: if ((*p == WILL) || (*p == WONT)) {
500: obuf[1] = DONT;
501: }
502: if ((*p == DO) || (*p == DONT)) {
503: obuf[1] = WONT;
504: }
505: if (obuf) {
506: p++;
1.11 ericj 507: obuf[2] = *p;
1.24 ericj 508: obuf[3] = '\0';
1.21 ericj 509: if ((ret = atomicio(write , nfd, obuf, 3)) != 3)
510: warnx("Write Error!");
1.24 ericj 511: obuf[0] = '\0';
1.11 ericj 512: }
513: }
1.7 deraadt 514: }
515:
1.11 ericj 516: /*
1.21 ericj 517: * build_ports()
518: * Build an array or ports in portlist[], listing each port
519: * that we should try to connect too.
1.11 ericj 520: */
1.21 ericj 521: void
1.37 jakob 522: build_ports(char *p)
1.6 deraadt 523: {
1.26 ericj 524: char *n, *endp;
1.21 ericj 525: int hi, lo, cp;
526: int x = 0;
527:
528: if ((n = strchr(p, '-')) != NULL) {
529: if (lflag)
530: errx(1, "Cannot use -l with multiple ports!");
531:
532: *n = '\0';
533: n++;
534:
535: /* Make sure the ports are in order: lowest->highest */
1.26 ericj 536: hi = (int)strtoul(n, &endp, 10);
1.31 ericj 537: if (hi <= 0 || hi > PORT_MAX || *endp != '\0')
1.26 ericj 538: errx(1, "port range not valid");
539: lo = (int)strtoul(p, &endp, 10);
1.31 ericj 540: if (lo <= 0 || lo > PORT_MAX || *endp != '\0')
1.26 ericj 541: errx(1, "port range not valid");
1.21 ericj 542:
543: if (lo > hi) {
544: cp = hi;
545: hi = lo;
546: lo = cp;
547: }
548:
549: /* Load ports sequentially */
550: for (cp = lo; cp <= hi; cp++) {
1.33 ericj 551: portlist[x] = calloc(1, PORT_MAX);
1.21 ericj 552: sprintf(portlist[x], "%d", cp);
553: x++;
554: }
555:
556: /* Randomly swap ports */
557: if (rflag) {
558: int y;
559: char *c;
560:
561: for (x = 0; x <= (hi - lo); x++) {
562: y = (arc4random() & 0xFFFF) % (hi - lo);
563: c = portlist[x];
564: portlist[x] = portlist[y];
565: portlist[y] = c;
1.6 deraadt 566: }
1.11 ericj 567: }
1.21 ericj 568: } else {
1.26 ericj 569: hi = (int)strtoul(p, &endp, 10);
1.31 ericj 570: if (hi <= 0 || hi > PORT_MAX || *endp != '\0')
1.26 ericj 571: errx(1, "port range not valid");
1.33 ericj 572: portlist[0] = calloc(1, PORT_MAX);
1.21 ericj 573: portlist[0] = p;
1.11 ericj 574: }
1.13 ericj 575: }
576:
577: /*
1.21 ericj 578: * udptest()
579: * Do a few writes to see if the UDP port is there.
580: * XXX - Better way of doing this? Doesn't work for IPv6
581: * Also fails after around 100 ports checked.
1.13 ericj 582: */
1.21 ericj 583: int
1.37 jakob 584: udptest(int s)
1.13 ericj 585: {
1.21 ericj 586: int i, rv, ret;
1.13 ericj 587:
1.21 ericj 588: for (i=0; i <= 3; i++) {
589: if ((rv = write(s, "X", 1)) == 1)
590: ret = 1;
1.14 ericj 591: else
1.21 ericj 592: ret = -1;
1.14 ericj 593: }
1.21 ericj 594: return (ret);
1.7 deraadt 595: }
1.1 deraadt 596:
1.11 ericj 597: void
1.21 ericj 598: help()
1.1 deraadt 599: {
1.21 ericj 600: usage(0);
601: fprintf(stderr, "\tCommand Summary:\n\
602: \t-4 Use IPv4\n\
603: \t-6 Use IPv6\n\
604: \t-h This help text\n\
605: \t-i secs\t Delay interval for lines sent, ports scanned\n\
606: \t-k Keep inbound sockets open for multiple connects\n\
607: \t-l Listen mode, for inbound connects\n\
1.22 jasoni 608: \t-n Suppress name/port resolutions\n\
1.36 jakob 609: \t-p port\t Specify local port for remote connects\n\
1.21 ericj 610: \t-r Randomize remote ports\n\
611: \t-s addr\t Local source address\n\
612: \t-t Answer TELNET negotiation\n\
613: \t-u UDP mode\n\
614: \t-v Verbose\n\
615: \t-w secs\t Timeout for connects and final net reads\n\
1.34 jakob 616: \t-x addr[:port]\tSpecify socks5 proxy address and port\n\
1.21 ericj 617: \t-z Zero-I/O mode [used for scanning]\n\
618: Port numbers can be individual or ranges: lo-hi [inclusive]\n");
619: exit(1);
1.11 ericj 620: }
621:
622: void
1.37 jakob 623: usage(int ret)
1.11 ericj 624: {
1.21 ericj 625: fprintf(stderr, "usage: nc [-46hklnrtuvz] [-i interval] [-p source port]\n");
1.36 jakob 626: fprintf(stderr, "\t [-s ip address] [-w timeout] [-x proxy address [:port]]\n");
627: fprintf(stderr, "\t [hostname] [port[s...]]\n");
1.21 ericj 628: if (ret)
629: exit(1);
1.7 deraadt 630: }