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