Annotation of src/usr.bin/nc/netcat.c, Revision 1.27
1.27 ! ericj 1: /* $OpenBSD: netcat.c,v 1.26 2001/06/26 21:57:35 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: char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
192: struct sockaddr_storage z;
193:
194: len = sizeof(z);
1.23 ericj 195: rv = recvfrom(s, buf, sizeof(buf), MSG_PEEK,
1.21 ericj 196: (struct sockaddr *)&z, &len);
1.23 ericj 197: if (rv < 0)
1.21 ericj 198: errx(1, "%s", strerror(errno));
199:
1.23 ericj 200: rv = connect(s, (struct sockaddr *)&z,
1.21 ericj 201: len);
1.23 ericj 202: if (rv < 0)
1.21 ericj 203: errx(1, "%s", strerror(errno));
1.1 deraadt 204:
1.21 ericj 205: connfd = s;
206: } else {
207: connfd = accept(s, (struct sockaddr *)&cliaddr,
208: &len);
209: }
1.1 deraadt 210:
1.21 ericj 211: readwrite(connfd);
212: close(connfd);
1.27 ! ericj 213: close(s);
! 214:
1.21 ericj 215: if (!kflag)
216: break;
1.11 ericj 217: }
1.21 ericj 218: } else {
219: int i = 0;
1.6 deraadt 220:
1.21 ericj 221: /* construct the portlist[] array */
222: build_ports(uport);
1.1 deraadt 223:
1.21 ericj 224: /* Cycle through portlist, connecting to each port */
225: for (i = 0; portlist[i] != NULL; i++) {
226:
227: if (s)
228: close(s);
229:
230: if ((s = remote_connect(host, portlist[i], hints)) < 0)
231: continue;
1.1 deraadt 232:
1.21 ericj 233: ret = 0;
234: if (vflag || zflag) {
235: /* For UDP, make sure we are connected */
236: if (uflag) {
237: if ((udptest(s)) == -1) {
238: ret = 1;
239: continue;
240: }
241: }
1.1 deraadt 242:
1.21 ericj 243: /* Don't lookup port if -n */
244: if (nflag)
245: sv = NULL;
246: else {
247: sv = getservbyport(
248: ntohs(atoi(portlist[i])),
249: uflag ? "udp" : "tcp");
250: }
251:
252: printf("Connection to %s %s port [%s/%s] succeeded!\n",
253: host, portlist[i], uflag ? "udp" : "tcp",
254: sv ? sv->s_name : "*");
255: }
256: if (!zflag)
257: readwrite(s);
1.7 deraadt 258: }
1.11 ericj 259: }
1.1 deraadt 260:
1.21 ericj 261: if (s)
262: close(s);
263:
264: exit(ret);
1.7 deraadt 265: }
1.1 deraadt 266:
1.11 ericj 267: /*
1.21 ericj 268: * remote_connect()
269: * Return's a socket connected to a remote host. Properly bind's to a local
270: * port or source address if needed. Return's -1 on failure.
1.11 ericj 271: */
1.21 ericj 272: int
273: remote_connect(host, port, hints)
274: char *host, *port;
275: struct addrinfo hints;
276: {
277: struct addrinfo *res, *res0;
278: int s, error;
279:
280: if ((error = getaddrinfo(host, port, &hints, &res)))
281: errx(1, "%s", gai_strerror(error));
282:
283: res0 = res;
284: do {
285: if ((s = socket(res0->ai_family, res0->ai_socktype,
286: res0->ai_protocol)) < 0)
287: continue;
288:
289: /* Bind to a local port or source address if specified */
290: if (sflag || pflag) {
291: struct addrinfo ahints, *ares;
292:
293: if (!(sflag && pflag)) {
294: if (!sflag)
295: sflag = NULL;
296: else
297: pflag = NULL;
298: }
1.6 deraadt 299:
1.21 ericj 300: memset(&ahints, 0, sizeof(struct addrinfo));
301: ahints.ai_family = res0->ai_family;
302: ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
303: ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
1.25 ericj 304: ahints.ai_flags = AI_PASSIVE;
1.21 ericj 305: if (getaddrinfo(sflag, pflag, &ahints, &ares))
306: errx(1, "%s", gai_strerror(error));
307:
308: if (bind(s, (struct sockaddr *)ares->ai_addr,
309: ares->ai_addrlen) < 0) {
310: errx(1, "bind failed: %s", strerror(errno));
311: freeaddrinfo(ares);
312: continue;
313: }
314: freeaddrinfo(ares);
1.6 deraadt 315: }
316:
1.21 ericj 317: if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
1.6 deraadt 318: break;
1.21 ericj 319:
320: close(s);
321: s = -1;
322: } while ((res0 = res0->ai_next) != NULL);
323:
324: freeaddrinfo(res);
1.1 deraadt 325:
1.21 ericj 326: return (s);
1.7 deraadt 327: }
1.1 deraadt 328:
1.11 ericj 329: /*
1.21 ericj 330: * local_listen()
331: * Return's a socket listening on a local port, binds to specified source
332: * address. Return's -1 on failure.
1.11 ericj 333: */
1.21 ericj 334: int
335: local_listen(host, port, hints)
336: char *host, *port;
337: struct addrinfo hints;
338: {
339: struct addrinfo *res, *res0;
340: int s, ret, x = 1;
341: int error;
1.6 deraadt 342:
1.21 ericj 343: /* Allow nodename to be null */
344: hints.ai_flags |= AI_PASSIVE;
1.7 deraadt 345:
1.21 ericj 346: /*
347: * In the case of binding to a wildcard address
348: * default to binding to an ipv4 address.
349: */
350: if (host == NULL && hints.ai_family == AF_UNSPEC)
351: hints.ai_family = AF_INET;
1.1 deraadt 352:
1.21 ericj 353: if ((error = getaddrinfo(host, port, &hints, &res)))
354: errx(1, "%s", gai_strerror(error));
1.14 ericj 355:
1.21 ericj 356: res0 = res;
357: do {
358: if ((s = socket(res0->ai_family, res0->ai_socktype,
359: res0->ai_protocol)) == 0)
360: continue;
1.1 deraadt 361:
1.21 ericj 362: ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));
363: if (ret == -1)
364: errx(1, NULL);
1.1 deraadt 365:
1.21 ericj 366: if (bind(s, (struct sockaddr *)res0->ai_addr,
367: res0->ai_addrlen) == 0)
368: break;
1.1 deraadt 369:
1.21 ericj 370: close(s);
371: s = -1;
372: } while ((res0 = res0->ai_next) != NULL);
1.1 deraadt 373:
1.21 ericj 374: if (!uflag) {
375: if (listen(s, 1) < 0)
376: errx(1, "%s", strerror(errno));
1.12 ericj 377: }
1.1 deraadt 378:
1.21 ericj 379: freeaddrinfo(res);
1.1 deraadt 380:
1.21 ericj 381: return (s);
1.7 deraadt 382: }
383:
1.11 ericj 384: /*
1.21 ericj 385: * readwrite()
386: * Loop that polls on the network file descriptor and stdin.
1.11 ericj 387: */
1.21 ericj 388: void
389: readwrite(nfd)
390: int nfd;
1.6 deraadt 391: {
1.21 ericj 392: struct pollfd *pfd;
393: char buf[BUFSIZ];
394: int wfd = fileno(stdin), n, ret;
395: int lfd = fileno(stdout);
396:
397: pfd = malloc(2 * sizeof(struct pollfd));
398:
399: /* Setup Network FD */
400: pfd[0].fd = nfd;
401: pfd[0].events = POLLIN;
402:
403: /* Setup STDIN FD */
404: pfd[1].fd = wfd;
405: pfd[1].events = POLLIN;
406:
407: for (;;) {
408: if (iflag)
409: sleep(iflag);
410:
411: if (poll(pfd, 2, timeout) < 0) {
412: close(nfd);
413: close(wfd);
414: free(pfd);
415: errx(1, "Polling Error");
416: }
417:
418: if (pfd[0].revents & POLLIN) {
419: if ((n = read(nfd, buf, sizeof(buf))) <= 0) {
420: return;
421: } else {
422: if (tflag)
423: atelnet(nfd, buf, n);
424: if ((ret = atomicio(write, lfd, buf, n)) != n)
425: return;
1.6 deraadt 426: }
1.21 ericj 427: }
428:
429: if (pfd[1].revents & POLLIN) {
430: if ((n = read(wfd, buf, sizeof(buf))) <= 0) {
431: return;
432: } else
433: if((ret = atomicio(write, nfd, buf, n)) != n)
434: return;
435: }
1.11 ericj 436: }
1.7 deraadt 437: }
1.24 ericj 438: /* Deal with RFC854 WILL/WONT DO/DONT negotiation */
1.21 ericj 439: void
440: atelnet(nfd, buf, size)
441: int nfd;
442: unsigned char *buf;
1.6 deraadt 443: unsigned int size;
444: {
1.24 ericj 445: int ret, pos = 0;
446: unsigned char *p, *end;
447: unsigned char obuf[4];
448:
449: end = buf + size;
450: obuf[0] = '\0';
451:
452: for (p = buf; p < end; p++) {
1.21 ericj 453: if (*p != IAC)
1.24 ericj 454: break;
455:
1.25 ericj 456: obuf[0] = IAC;
1.24 ericj 457: p++;
458: if ((*p == WILL) || (*p == WONT)) {
459: obuf[1] = DONT;
460: }
461: if ((*p == DO) || (*p == DONT)) {
462: obuf[1] = WONT;
463: }
464: if (obuf) {
465: p++;
1.11 ericj 466: obuf[2] = *p;
1.24 ericj 467: obuf[3] = '\0';
1.21 ericj 468: if ((ret = atomicio(write , nfd, obuf, 3)) != 3)
469: warnx("Write Error!");
1.24 ericj 470: obuf[0] = '\0';
1.11 ericj 471: }
472: }
1.7 deraadt 473: }
474:
1.11 ericj 475: /*
1.21 ericj 476: * build_ports()
477: * Build an array or ports in portlist[], listing each port
478: * that we should try to connect too.
1.11 ericj 479: */
1.21 ericj 480: void
481: build_ports(p)
482: char *p;
1.6 deraadt 483: {
1.26 ericj 484: char *n, *endp;
1.21 ericj 485: int hi, lo, cp;
486: int x = 0;
487:
488: if ((n = strchr(p, '-')) != NULL) {
489: if (lflag)
490: errx(1, "Cannot use -l with multiple ports!");
491:
492: *n = '\0';
493: n++;
494:
495: /* Make sure the ports are in order: lowest->highest */
1.26 ericj 496: hi = (int)strtoul(n, &endp, 10);
497: if (hi <= 0 || hi > 65535 || *endp != '\0')
498: errx(1, "port range not valid");
499: lo = (int)strtoul(p, &endp, 10);
500: if (lo <= 0 || lo > 65535 || *endp != '\0')
501: errx(1, "port range not valid");
1.21 ericj 502:
503: if (lo > hi) {
504: cp = hi;
505: hi = lo;
506: lo = cp;
507: }
508:
509: /* Load ports sequentially */
510: for (cp = lo; cp <= hi; cp++) {
511: portlist[x] = malloc(sizeof(65535));
512: sprintf(portlist[x], "%d", cp);
513: x++;
514: }
515:
516: /* Randomly swap ports */
517: if (rflag) {
518: int y;
519: char *c;
520:
521: for (x = 0; x <= (hi - lo); x++) {
522: y = (arc4random() & 0xFFFF) % (hi - lo);
523: c = portlist[x];
524: portlist[x] = portlist[y];
525: portlist[y] = c;
1.6 deraadt 526: }
1.11 ericj 527: }
1.21 ericj 528: } else {
1.26 ericj 529: hi = (int)strtoul(p, &endp, 10);
530: if (hi <= 0 || hi > 65535 || *endp != '\0')
531: errx(1, "port range not valid");
1.21 ericj 532: portlist[0] = malloc(sizeof(65535));
533: portlist[0] = p;
1.11 ericj 534: }
1.13 ericj 535: }
536:
537: /*
1.21 ericj 538: * udptest()
539: * Do a few writes to see if the UDP port is there.
540: * XXX - Better way of doing this? Doesn't work for IPv6
541: * Also fails after around 100 ports checked.
1.13 ericj 542: */
1.21 ericj 543: int
544: udptest(s)
545: int s;
1.13 ericj 546: {
1.21 ericj 547: int i, rv, ret;
1.13 ericj 548:
1.21 ericj 549: for (i=0; i <= 3; i++) {
550: if ((rv = write(s, "X", 1)) == 1)
551: ret = 1;
1.14 ericj 552: else
1.21 ericj 553: ret = -1;
1.14 ericj 554: }
1.21 ericj 555: return (ret);
1.7 deraadt 556: }
1.1 deraadt 557:
1.11 ericj 558: void
1.21 ericj 559: help()
1.1 deraadt 560: {
1.21 ericj 561: usage(0);
562: fprintf(stderr, "\tCommand Summary:\n\
563: \t-4 Use IPv4\n\
564: \t-6 Use IPv6\n\
565: \t-h This help text\n\
566: \t-i secs\t Delay interval for lines sent, ports scanned\n\
567: \t-k Keep inbound sockets open for multiple connects\n\
568: \t-l Listen mode, for inbound connects\n\
1.22 jasoni 569: \t-n Suppress name/port resolutions\n\
1.21 ericj 570: \t-p Specify local port for remote connects\n\
571: \t-r Randomize remote ports\n\
572: \t-s addr\t Local source address\n\
573: \t-t Answer TELNET negotiation\n\
574: \t-u UDP mode\n\
575: \t-v Verbose\n\
576: \t-w secs\t Timeout for connects and final net reads\n\
577: \t-z Zero-I/O mode [used for scanning]\n\
578: Port numbers can be individual or ranges: lo-hi [inclusive]\n");
579: exit(1);
1.11 ericj 580: }
581:
582: void
1.21 ericj 583: usage(ret)
584: int ret;
1.11 ericj 585: {
1.21 ericj 586: fprintf(stderr, "usage: nc [-46hklnrtuvz] [-i interval] [-p source port]\n");
587: fprintf(stderr, "\t [-s ip address] [-w timeout] [hostname] [port[s...]]\n");
588: if (ret)
589: exit(1);
1.7 deraadt 590: }