[BACK]Return to netcat.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / nc

Annotation of src/usr.bin/nc/netcat.c, Revision 1.11

1.11    ! ericj       1: /* $OpenBSD$ */
        !             2:
1.1       deraadt     3: /* Netcat 1.10 RELEASE 960320
1.7       deraadt     4:  *
                      5:  *   A damn useful little "backend" utility begun 950915 or thereabouts,
                      6:  *   as *Hobbit*'s first real stab at some sockets programming.  Something that
                      7:  *   should have and indeed may have existed ten years ago, but never became a
                      8:  *   standard Unix utility.  IMHO, "nc" could take its place right next to cat,
                      9:  *   cp, rm, mv, dd, ls, and all those other cryptic and Unix-like things.
                     10:  *
                     11:  *   Read the README for the whole story, doc, applications, etc.
                     12:  *
                     13:  *   Layout:
                     14:  *     conditional includes:
                     15:  *     includes:
                     16:  *     handy defines:
                     17:  *     globals:
                     18:  *     malloced globals:
                     19:  *     cmd-flag globals:
                     20:  *     support routines:
                     21:  *     readwrite select loop:
                     22:  *     main:
                     23:  *
                     24:  *  bluesky:
                     25:  *     parse ranges of IP address as well as ports, perhaps
                     26:  *     RAW mode!
                     27:  *     backend progs to grab a pty and look like a real telnetd?!
                     28:  *     backend progs to do various encryption modes??!?!
1.1       deraadt    29: */
                     30:
                     31:
                     32: #define HAVE_BIND              /* ASSUMPTION -- seems to work everywhere! */
                     33:
1.7       deraadt    34: #include <sys/types.h>
                     35: #include <sys/time.h>
                     36: #include <sys/select.h>
                     37: #include <sys/socket.h>
                     38: #include <netinet/in.h>
                     39: #include <netinet/in_systm.h>
                     40: #include <netinet/ip.h>
                     41: #include <arpa/inet.h>
                     42: #include <netdb.h>             /* hostent, gethostby*, getservby* */
                     43: #include <stdio.h>
                     44: #include <string.h>
1.11    ! ericj      45: #include <err.h>
1.7       deraadt    46: #include <errno.h>
                     47: #include <setjmp.h>
                     48: #include <signal.h>
                     49: #include <fcntl.h>
1.1       deraadt    50: #include <stdlib.h>
1.5       art        51: #include <unistd.h>
1.1       deraadt    52:
1.11    ! ericj      53: /* Random Numbers aren't too needed here */
        !            54: #define SRAND srandom
        !            55: #define RAND random
1.1       deraadt    56:
                     57: #define SLEAZE_PORT 31337      /* for UDP-scan RTT trick, change if ya want */
                     58: #define BIGSIZ 8192            /* big buffers */
                     59:
1.7       deraadt    60: struct host_info {
1.11    ! ericj      61:        char    name[MAXHOSTNAMELEN];   /* DNS name */
        !            62:        char    addrs[8][24];           /* ascii-format IP addresses */
        !            63:        struct  in_addr iaddrs[8];      /* in_addr.s_addr: ulong */
1.1       deraadt    64: };
                     65:
1.7       deraadt    66: struct port_info {
1.6       deraadt    67:        char    name[64];       /* name in /etc/services */
                     68:        char    anum[8];        /* ascii-format number */
1.7       deraadt    69:        u_short  num;           /* real host-order number */
1.1       deraadt    70: };
                     71:
                     72: /* globals: */
1.11    ! ericj      73: jmp_buf jbuf;                  /* timer jump buffer*/
1.6       deraadt    74: int     jval = 0;              /* timer crud */
                     75: int     netfd = -1;
                     76: int     ofd = 0;               /* hexdump output fd */
1.7       deraadt    77:
1.1       deraadt    78: extern int h_errno;
                     79: /* stolen almost wholesale from bsd herror.c */
1.6       deraadt    80: static char *h_errs[] = {
1.11    ! ericj      81:        "Error 0",                              /* but we *don't* use this */
        !            82:        "Unknown host",                         /* 1 HOST_NOT_FOUND */
        !            83:        "Host name lookup failure",             /* 2 TRY_AGAIN */
        !            84:        "Unknown server error",                 /* 3 NO_RECOVERY */
1.6       deraadt    85:        "No address associated with name",      /* 4 NO_ADDRESS */
1.1       deraadt    86: };
1.7       deraadt    87:
1.6       deraadt    88: int     gatesidx = 0;          /* LSRR hop count */
                     89: int     gatesptr = 4;          /* initial LSRR pointer, settable */
1.7       deraadt    90: u_short  Single = 1;           /* zero if scanning */
1.1       deraadt    91: unsigned int insaved = 0;      /* stdin-buffer size for multi-mode */
                     92: unsigned int wrote_out = 0;    /* total stdout bytes */
                     93: unsigned int wrote_net = 0;    /* total net bytes */
                     94: static char hexnibs[20] = "0123456789abcdef  ";
                     95:
                     96: /* will malloc up the following globals: */
1.7       deraadt    97: struct timeval timer1, timer2;
1.11    ! ericj      98: struct sockaddr_in    *lclend = NULL;  /* sockaddr_in structs */
1.7       deraadt    99: struct sockaddr_in    *remend = NULL;
1.11    ! ericj     100: struct host_info  **gates = NULL;      /* LSRR hop hinfo */
        !           101: char   *optbuf = NULL;                 /* LSRR or sockopts */
        !           102: char   *bigbuf_in;                     /* data buffers */
1.6       deraadt   103: char   *bigbuf_net;
1.7       deraadt   104: fd_set fds1, fds2;
1.11    ! ericj     105: struct port_info   *pinfo = NULL;      /* for getpinfo / getservby* */
        !           106: unsigned char *stage = NULL;           /* hexdump line buffer */
1.1       deraadt   107:
                    108: /* global cmd flags: */
1.7       deraadt   109: u_short  o_alla = 0;
1.1       deraadt   110: unsigned int o_interval = 0;
1.7       deraadt   111: u_short  o_listen = 0;
                    112: u_short  o_nflag = 0;
                    113: u_short  o_wfile = 0;
                    114: u_short  o_random = 0;
                    115: u_short  o_udpmode = 0;
                    116: u_short  o_verbose = 0;
1.1       deraadt   117: unsigned int o_wait = 0;
1.7       deraadt   118: u_short  o_zero = 0;
1.1       deraadt   119:
1.11    ! ericj     120: /* Function Prototype's */
        !           121: void   usage   __P((int));
        !           122: void   help    __P(());
        !           123:
        !           124: /*
        !           125:  * support routines -- the bulk of this thing.  Placed in such an order that
        !           126:  * we don't have to forward-declare anything:
        !           127:  */
        !           128:
        !           129: /*
        !           130:  * catch :
        !           131:  * no-brainer interrupt handler
        !           132:  */
1.6       deraadt   133: void
                    134: catch()
1.1       deraadt   135: {
1.6       deraadt   136:        errno = 0;
                    137:        if (o_verbose > 1)      /* normally we don't care */
1.11    ! ericj     138:                errx(1, "Sent %i Rcvd %i", wrote_net, wrote_out);
        !           139:        errx(1, " punt!");
1.1       deraadt   140: }
                    141:
                    142: /* timeout and other signal handling cruft */
1.6       deraadt   143: void
                    144: tmtravel()
1.1       deraadt   145: {
1.6       deraadt   146:        signal(SIGALRM, SIG_IGN);
                    147:        alarm(0);
                    148:        if (jval == 0)
1.11    ! ericj     149:                errx(1, "spurious timer interrupt!");
1.6       deraadt   150:        longjmp(jbuf, jval);
1.1       deraadt   151: }
                    152:
1.11    ! ericj     153: /*
        !           154:  * arm :
        !           155:  * set the timer.  Zero secs arg means unarm
        !           156:  */
1.6       deraadt   157: void
                    158: arm(num, secs)
                    159:        unsigned int num;
                    160:        unsigned int secs;
                    161: {
1.11    ! ericj     162:        if (secs == 0) {
1.6       deraadt   163:                signal(SIGALRM, SIG_IGN);
                    164:                alarm(0);
                    165:                jval = 0;
1.11    ! ericj     166:        } else {
1.6       deraadt   167:                signal(SIGALRM, tmtravel);
                    168:                alarm(secs);
                    169:                jval = num;
1.11    ! ericj     170:        }
1.7       deraadt   171: }
1.1       deraadt   172:
1.11    ! ericj     173: /*
        !           174:  * findline :
        !           175:  * find the next newline in a buffer; return inclusive size of that "line",
        !           176:  * or the entire buffer size, so the caller knows how much to then write().
        !           177:  * Not distinguishing \n vs \r\n for the nonce; it just works as is...
        !           178:  */
1.6       deraadt   179: unsigned int
                    180: findline(buf, siz)
                    181:        char   *buf;
                    182:        unsigned int siz;
                    183: {
1.11    ! ericj     184:        char *p;
        !           185:        int x;
1.6       deraadt   186:        if (!buf)               /* various sanity checks... */
                    187:                return (0);
                    188:        if (siz > BIGSIZ)
                    189:                return (0);
                    190:        x = siz;
                    191:        for (p = buf; x > 0; x--) {
                    192:                if (*p == '\n') {
                    193:                        x = (int) (p - buf);
                    194:                        x++;    /* 'sokay if it points just past the end! */
                    195:                            return (x);
                    196:                }
                    197:                p++;
1.11    ! ericj     198:        }
1.6       deraadt   199:            return (siz);
1.7       deraadt   200: }
1.1       deraadt   201:
1.11    ! ericj     202: /*
        !           203:  * comparehosts :
        !           204:  * cross-check the host_info we have so far against new gethostby*() info,
        !           205:  * and holler about mismatches.  Perhaps gratuitous, but it can't hurt to
        !           206:  * point out when someone's DNS is fukt.  Returns 1 if mismatch, in case
        !           207:  * someone else wants to do something about it.
        !           208:  */
1.6       deraadt   209: int
1.11    ! ericj     210: comparehosts(hinfo, hp)
        !           211:        struct host_info   *hinfo;
1.6       deraadt   212:        struct hostent *hp;
                    213: {
                    214:        errno = 0;
                    215:        h_errno = 0;
1.11    ! ericj     216:        if (strcasecmp(hinfo->name, hp->h_name) != 0) {
        !           217:                warn("DNS fwd/rev mismatch: %s != %s", hinfo->name, hp->h_name);
1.6       deraadt   218:                return (1);
                    219:        }
                    220:        return (0);
1.7       deraadt   221: }
1.1       deraadt   222:
1.11    ! ericj     223: /*
        !           224:  * gethinfo:
        !           225:  * resolve a host 8 ways from sunday; return a new host_info struct with its
        !           226:  * info.  The argument can be a name or [ascii] IP address; it will try its
        !           227:  * damndest to deal with it.  "numeric" governs whether we do any DNS at all,
        !           228:  * and we also check o_verbose for what's appropriate work to do.
        !           229:  */
1.7       deraadt   230: struct host_info   *
1.11    ! ericj     231: gethinfo(name, numeric)
1.6       deraadt   232:        char   *name;
1.7       deraadt   233:        u_short  numeric;
1.6       deraadt   234: {
                    235:        struct hostent *hostent;
                    236:        struct in_addr iaddr;
1.11    ! ericj     237:        struct host_info *hinfo = NULL;
        !           238:        int x;
1.1       deraadt   239:
1.6       deraadt   240:        errno = 0;
                    241:        h_errno = 0;
                    242:        if (name)
1.11    ! ericj     243:                hinfo = (struct host_info *) calloc(1, sizeof(struct host_info));
        !           244:
        !           245:        if (!hinfo)
        !           246:                errx(1, "error obtaining host information");
        !           247:
        !           248:        strlcpy(hinfo->name, "(UNKNOWN)", sizeof(hinfo->name));
1.7       deraadt   249:        if (inet_aton(name, &iaddr) == 0) {
1.11    ! ericj     250:                if (numeric)
        !           251:                        errx(1, "Can't parse %s as an IP address", name);
1.6       deraadt   252:
1.11    ! ericj     253:                /*
        !           254:                 * failure to look up a name is fatal,
        !           255:                 * since we can't do anything with it.
        !           256:                 */
1.6       deraadt   257:                hostent = gethostbyname(name);
                    258:                if (!hostent)
1.11    ! ericj     259:                        errx(1, "%s: forward host lookup failed: ", name);
        !           260:
        !           261:                strlcpy(hinfo->name, hostent->h_name, MAXHOSTNAMELEN);
1.6       deraadt   262:                for (x = 0; hostent->h_addr_list[x] && (x < 8); x++) {
1.11    ! ericj     263:                        memcpy(&hinfo->iaddrs[x], hostent->h_addr_list[x],
1.7       deraadt   264:                            sizeof(struct in_addr));
1.11    ! ericj     265:                        strlcpy(hinfo->addrs[x], inet_ntoa(hinfo->iaddrs[x]),
        !           266:                            sizeof(hinfo->addrs[0]));
1.7       deraadt   267:                }
1.11    ! ericj     268:                /* Go ahead and return if we don't want to view more */
        !           269:                if (!o_verbose)
        !           270:                        return (hinfo);
        !           271:
        !           272:                /*
        !           273:                 * Do inverse lookups in separate loop based on our collected
        !           274:                 * forward addrs, since gethostby* tends to crap into the same
        !           275:                 * buffer over and over.
        !           276:                 */
        !           277:                for (x = 0; hinfo->iaddrs[x].s_addr && (x < 8); x++) {
        !           278:                        hostent = gethostbyaddr((char *) &hinfo->iaddrs[x],
1.7       deraadt   279:                            sizeof(struct in_addr), AF_INET);
1.6       deraadt   280:                        if ((!hostent) || (!hostent->h_name))
1.11    ! ericj     281:                                warn("Warning: inverse host lookup failed for %s: ",
        !           282:                                    hinfo->addrs[x]);
1.6       deraadt   283:                        else
1.11    ! ericj     284:                                (void) comparehosts(hinfo, hostent);
        !           285:                }
1.6       deraadt   286:
                    287:        } else {                /* not INADDR_NONE: numeric addresses... */
1.11    ! ericj     288:                memcpy(hinfo->iaddrs, &iaddr, sizeof(struct in_addr));
        !           289:                strlcpy(hinfo->addrs[0], inet_ntoa(iaddr), sizeof(hinfo->addrs));
        !           290:                /* If all that's wanted is numeric IP, go ahead and leave */
        !           291:                if (numeric)
        !           292:                        return (hinfo);
        !           293:
        !           294:                /* Go ahead and return if we don't want to view more */
        !           295:                if (!o_verbose)
        !           296:                        return (hinfo);
        !           297:
        !           298:                hostent = gethostbyaddr((char *) &iaddr,
        !           299:                                        sizeof(struct in_addr), AF_INET);
        !           300:
        !           301:                /*
        !           302:                 * numeric or not, failure to look up a PTR is
        !           303:                 * *not* considered fatal
        !           304:                 */
1.6       deraadt   305:                if (!hostent)
1.11    ! ericj     306:                        warn("%s: inverse host lookup failed: ", name);
1.6       deraadt   307:                else {
1.11    ! ericj     308:                        strlcpy(hinfo->name, hostent->h_name, MAXHOSTNAMELEN);
        !           309:                        hostent = gethostbyname(hinfo->name);
1.6       deraadt   310:                        if ((!hostent) || (!hostent->h_addr_list[0]))
1.11    ! ericj     311:                                warn("Warning: forward host lookup failed for %s: ",
        !           312:                                    hinfo->name);
1.6       deraadt   313:                        else
1.11    ! ericj     314:                                (void) comparehosts(hinfo, hostent);
        !           315:                }
        !           316:        }
1.1       deraadt   317:
1.11    ! ericj     318:        /*
        !           319:         * Whatever-all went down previously, we should now have a host_info
        !           320:         * struct with at least one IP address in it.
        !           321:         */
1.6       deraadt   322:        h_errno = 0;
1.11    ! ericj     323:        return (hinfo);
1.7       deraadt   324: }
1.1       deraadt   325:
1.11    ! ericj     326: /*
        !           327:  * getpinfo:
        !           328:  * Same general idea as gethinfo-- look up a port in /etc/services, fill
        !           329:  * in global port_info, but return the actual port *number*.  Pass ONE of:
        !           330:  *     pstring to resolve stuff like "23" or "exec";
        !           331:  *     pnum to reverse-resolve something that's already a number.
        !           332:  * If o_nflag is on, fill in what we can but skip the getservby??? stuff.
        !           333:  * Might as well have consistent behavior here, and it *is* faster.
        !           334:  */
1.7       deraadt   335: u_short
1.11    ! ericj     336: getpinfo(pstring, pnum)
1.6       deraadt   337:        char   *pstring;
                    338:        unsigned int pnum;
                    339: {
                    340:        struct servent *servent;
1.11    ! ericj     341:        int x;
        !           342:        int y;
1.7       deraadt   343:        char   *whichp = "tcp";
1.6       deraadt   344:        if (o_udpmode)
1.7       deraadt   345:                whichp = "udp";
1.1       deraadt   346:
1.11    ! ericj     347:        pinfo->name[0] = '?';/* fast preload */
        !           348:        pinfo->name[1] = '\0';
        !           349:
        !           350:        /*
        !           351:         * case 1: reverse-lookup of a number; placed first since this case
        !           352:         * is much more frequent if we're scanning.
        !           353:         */
1.6       deraadt   354:        if (pnum) {
1.11    ! ericj     355:                /* Can't be both */
        !           356:                if (pstring)
1.6       deraadt   357:                        return (0);
1.11    ! ericj     358:
1.6       deraadt   359:                x = pnum;
                    360:                if (o_nflag)    /* go faster, skip getservbyblah */
                    361:                        goto gp_finish;
                    362:                y = htons(x);   /* gotta do this -- see Fig.1 below */
                    363:                servent = getservbyport(y, whichp);
                    364:                if (servent) {
                    365:                        y = ntohs(servent->s_port);
                    366:                        if (x != y)     /* "never happen" */
1.11    ! ericj     367:                                warn("Warning: port-bynum mismatch, %d != %d", x, y);
        !           368:                        strlcpy(pinfo->name, servent->s_name,
        !           369:                            sizeof(pinfo->name));
1.7       deraadt   370:                }
1.6       deraadt   371:                goto gp_finish;
1.11    ! ericj     372:        }
        !           373:        /*
        !           374:         * case 2: resolve a string, but we still give preference to numbers
1.6       deraadt   375:         * instead of trying to resolve conflicts.  None of the entries in *my*
                    376:         * extensive /etc/services begins with a digit, so this should "always
                    377:         * work" unless you're at 3com and have some company-internal services
1.11    ! ericj     378:         * defined.
        !           379:         */
1.6       deraadt   380:        if (pstring) {
1.11    ! ericj     381:                /* Can't be both */
        !           382:                if (pnum)
1.6       deraadt   383:                        return (0);
1.11    ! ericj     384:
1.6       deraadt   385:                x = atoi(pstring);
                    386:                if (x)
1.11    ! ericj     387:                        return (getpinfo(NULL, x));     /* recurse for
1.6       deraadt   388:                                                         * numeric-string-arg */
                    389:                if (o_nflag)    /* can't use names! */
                    390:                        return (0);
                    391:                servent = getservbyname(pstring, whichp);
                    392:                if (servent) {
1.11    ! ericj     393:                        strlcpy(pinfo->name, servent->s_name,
        !           394:                            sizeof(pinfo->name));
1.6       deraadt   395:                        x = ntohs(servent->s_port);
                    396:                        goto gp_finish;
                    397:                }               /* if servent */
                    398:        }                       /* if pstring */
                    399:        return (0);             /* catches any problems so far */
1.1       deraadt   400:
                    401: gp_finish:
1.11    ! ericj     402:        /*
        !           403:         * Fall here whether or not we have a valid servent at this point, with
        !           404:         * x containing our [host-order and therefore useful, dammit] port number.
        !           405:         */
        !           406:        sprintf(pinfo->anum, "%d", x);  /* always load any numeric
1.6       deraadt   407:                                                 * specs! */
1.11    ! ericj     408:        pinfo->num = (x & 0xffff);      /* u_short, remember... */
        !           409:        return (pinfo->num);
1.7       deraadt   410: }
1.1       deraadt   411:
1.11    ! ericj     412: /*
        !           413:  * nextport :
        !           414:  * Come up with the next port to try, be it random or whatever.  "block" is
        !           415:  * a ptr to randports array, whose bytes [so far] carry these meanings:
        !           416:  *     0       ignore
        !           417:  *     1       to be tested
        !           418:  *     2       tested [which is set as we find them here]
        !           419:  * returns a u_short random port, or 0 if all the t-b-t ones are used up.
        !           420:  */
1.7       deraadt   421: u_short
1.6       deraadt   422: nextport(block)
                    423:        char   *block;
                    424: {
1.11    ! ericj     425:        unsigned int x;
        !           426:        unsigned int y;
1.6       deraadt   427:
1.11    ! ericj     428:        y = 70000;                      /* high safety count for rnd-tries */
1.6       deraadt   429:        while (y > 0) {
                    430:                x = (RAND() & 0xffff);
                    431:                if (block[x] == 1) {    /* try to find a not-done one... */
                    432:                        block[x] = 2;
                    433:                        break;
                    434:                }
1.11    ! ericj     435:                x = 0;
1.6       deraadt   436:                y--;
1.11    ! ericj     437:        }
1.6       deraadt   438:        if (x)
                    439:                return (x);
                    440:
                    441:        y = 65535;              /* no random one, try linear downsearch */
                    442:        while (y > 0) {         /* if they're all used, we *must* be sure! */
                    443:                if (block[y] == 1) {
                    444:                        block[y] = 2;
                    445:                        break;
                    446:                }
                    447:                y--;
1.11    ! ericj     448:        }
1.6       deraadt   449:        if (y)
                    450:                return (y);     /* at least one left */
1.1       deraadt   451:
1.11    ! ericj     452:        return (0);
1.7       deraadt   453: }
1.1       deraadt   454:
1.11    ! ericj     455: /*
        !           456:  * loadports :
        !           457:  * set "to be tested" indications in BLOCK, from LO to HI.  Almost too small
        !           458:  * to be a separate routine, but makes main() a little cleaner.
        !           459:  */
1.6       deraadt   460: void
                    461: loadports(block, lo, hi)
                    462:        char   *block;
1.7       deraadt   463:        u_short  lo;
                    464:        u_short  hi;
1.6       deraadt   465: {
1.7       deraadt   466:        u_short  x;
1.6       deraadt   467:
                    468:        if (!block)
1.11    ! ericj     469:                errx(1, "loadports: no block?!");
1.6       deraadt   470:        if ((!lo) || (!hi))
1.11    ! ericj     471:                errx(1, "loadports: bogus values %d, %d", lo, hi);
1.6       deraadt   472:        x = hi;
                    473:        while (lo <= x) {
                    474:                block[x] = 1;
                    475:                x--;
                    476:        }
1.7       deraadt   477: }
                    478:
1.1       deraadt   479:
1.11    ! ericj     480: /*
        !           481:  * doconnect :
        !           482:  * do all the socket stuff, and return an fd for one of
        !           483:  *     an open outbound TCP connection
        !           484:  *     a UDP stub-socket thingie
        !           485:  * with appropriate socket options set up if we wanted source-routing, or
        !           486:  *     an unconnected TCP or UDP socket to listen on.
        !           487:  * Examines various global o_blah flags to figure out what-all to do.
        !           488:  */
1.6       deraadt   489: int
                    490: doconnect(rad, rp, lad, lp)
1.7       deraadt   491:        struct in_addr     *rad;
                    492:        u_short  rp;
                    493:        struct in_addr     *lad;
                    494:        u_short  lp;
1.6       deraadt   495: {
1.11    ! ericj     496:        int nnetfd;
        !           497:        int rr;
1.6       deraadt   498:        int     x, y;
                    499:        errno = 0;
1.1       deraadt   500:
1.11    ! ericj     501:        /* grab a socket; set opts */
1.1       deraadt   502: newskt:
1.6       deraadt   503:        if (o_udpmode)
                    504:                nnetfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
                    505:        else
                    506:                nnetfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
                    507:        if (nnetfd < 0)
1.11    ! ericj     508:                errx(1, "Can't get socket");
1.6       deraadt   509:        if (nnetfd == 0)        /* if stdin was closed this might *be* 0, */
                    510:                goto newskt;    /* so grab another.  See text for why... */
                    511:        x = 1;
                    512:        rr = setsockopt(nnetfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
                    513:        if (rr == -1)
1.11    ! ericj     514:                warn("nnetfd reuseaddr failed");        /* ??? */
1.6       deraadt   515:
                    516:        /* fill in all the right sockaddr crud */
                    517:        lclend->sin_family = AF_INET;
1.1       deraadt   518:
1.11    ! ericj     519:        /* fill in all the right sockaddr crud */
1.6       deraadt   520:        lclend->sin_family = AF_INET;
                    521:        remend->sin_family = AF_INET;
1.1       deraadt   522:
1.11    ! ericj     523:        /* if lad/lp, do appropriate binding */
1.6       deraadt   524:        if (lad)
1.7       deraadt   525:                memcpy(&lclend->sin_addr.s_addr, lad, sizeof(struct in_addr));
1.6       deraadt   526:        if (lp)
                    527:                lclend->sin_port = htons(lp);
1.11    ! ericj     528:
1.6       deraadt   529:        rr = 0;
                    530:        if (lad || lp) {
                    531:                x = (int) lp;
1.11    ! ericj     532:                /* try a few times for the local bind, a la ftp-data-port... */
1.6       deraadt   533:                for (y = 4; y > 0; y--) {
1.7       deraadt   534:                        rr = bind(nnetfd, (struct sockaddr *) lclend,
                    535:                            sizeof(struct sockaddr_in));
1.6       deraadt   536:                        if (rr == 0)
                    537:                                break;
                    538:                        if (errno != EADDRINUSE)
                    539:                                break;
                    540:                        else {
1.11    ! ericj     541:                                warn("retrying local %s:%d", inet_ntoa(lclend->sin_addr), lp);
1.6       deraadt   542:                                sleep(2);
                    543:                                errno = 0;      /* clear from sleep */
1.11    ! ericj     544:                        }
        !           545:                }
        !           546:        }
1.6       deraadt   547:        if (rr)
1.11    ! ericj     548:                errx(1, "Can't grab %s:%d with bind",
1.6       deraadt   549:                    inet_ntoa(lclend->sin_addr), lp);
1.1       deraadt   550:
1.6       deraadt   551:        if (o_listen)
                    552:                return (nnetfd);/* thanks, that's all for today */
1.1       deraadt   553:
1.7       deraadt   554:        memcpy(&remend->sin_addr.s_addr, rad, sizeof(struct in_addr));
1.6       deraadt   555:        remend->sin_port = htons(rp);
1.1       deraadt   556:
1.6       deraadt   557:        /* wrap connect inside a timer, and hit it */
                    558:        arm(1, o_wait);
                    559:        if (setjmp(jbuf) == 0) {
1.11    ! ericj     560:                rr = connect(nnetfd, (struct sockaddr *) remend,
        !           561:                                                sizeof(struct sockaddr));
        !           562:        } else {
1.6       deraadt   563:                rr = -1;
1.11    ! ericj     564:                errno = ETIMEDOUT;
1.6       deraadt   565:        }
                    566:        arm(0, 0);
                    567:        if (rr == 0)
                    568:                return (nnetfd);
1.11    ! ericj     569:        close(nnetfd);
1.6       deraadt   570:        return (-1);
1.7       deraadt   571: }
1.1       deraadt   572:
1.11    ! ericj     573: /*
        !           574:  * dolisten :
        !           575:  * just like doconnect, and in fact calls a hunk of doconnect, but listens for
        !           576:  * incoming and returns an open connection *from* someplace.  If we were
        !           577:  * given host/port args, any connections from elsewhere are rejected.  This
        !           578:  * in conjunction with local-address binding should limit things nicely.
        !           579:  */
1.6       deraadt   580: int
                    581: dolisten(rad, rp, lad, lp)
1.7       deraadt   582:        struct in_addr     *rad;
                    583:        u_short  rp;
                    584:        struct in_addr     *lad;
                    585:        u_short  lp;
1.6       deraadt   586: {
1.11    ! ericj     587:        int nnetfd;
        !           588:        int rr;
1.7       deraadt   589:        struct host_info   *whozis = NULL;
1.6       deraadt   590:        int     x;
                    591:        char   *cp;
1.7       deraadt   592:        u_short  z;
1.6       deraadt   593:        errno = 0;
1.1       deraadt   594:
1.11    ! ericj     595:        /*
        !           596:         * Pass everything off to doconnect,
        !           597:         * who in o_listen mode just gets a socket
        !           598:         */
1.6       deraadt   599:        nnetfd = doconnect(rad, rp, lad, lp);
                    600:        if (nnetfd <= 0)
                    601:                return (-1);
1.11    ! ericj     602:        if (o_udpmode) {
        !           603:                if (!lp)
        !           604:                        errx(1, "UDP listen needs -p arg");
1.6       deraadt   605:        } else {
1.11    ! ericj     606:                rr = listen(nnetfd, 1);
        !           607:                if (rr < 0)
        !           608:                        errx(1, "error listening");
1.6       deraadt   609:        }
1.1       deraadt   610:
1.6       deraadt   611:        if (o_verbose) {
1.11    ! ericj     612:                x = sizeof(struct sockaddr);
1.7       deraadt   613:                rr = getsockname(nnetfd, (struct sockaddr *) lclend, &x);
1.6       deraadt   614:                if (rr < 0)
1.11    ! ericj     615:                        warn("local getsockname failed");
1.6       deraadt   616:                strcpy(bigbuf_net, "listening on [");   /* buffer reuse... */
                    617:                if (lclend->sin_addr.s_addr)
                    618:                        strcat(bigbuf_net, inet_ntoa(lclend->sin_addr));
                    619:                else
                    620:                        strcat(bigbuf_net, "any");
                    621:                strcat(bigbuf_net, "] %d ...");
                    622:                z = ntohs(lclend->sin_port);
1.11    ! ericj     623:                warn(bigbuf_net, z);
1.6       deraadt   624:        }                       /* verbose -- whew!! */
1.11    ! ericj     625:        /*
        !           626:         * UDP is a speeeeecial case -- we have to do I/O *and* get the
1.6       deraadt   627:         * calling party's particulars all at once, listen() and accept()
                    628:         * don't apply. At least in the BSD universe, however, recvfrom/PEEK
                    629:         * is enough to tell us something came in, and we can set things up so
                    630:         * straight read/write actually does work after all.  Yow.  YMMV on
1.11    ! ericj     631:         * strange platforms!
        !           632:         */
1.6       deraadt   633:        if (o_udpmode) {
1.7       deraadt   634:                x = sizeof(struct sockaddr);    /* retval for recvfrom */
1.6       deraadt   635:                arm(2, o_wait); /* might as well timeout this, too */
                    636:                if (setjmp(jbuf) == 0) {        /* do timeout for initial
                    637:                                                 * connect */
1.11    ! ericj     638:                        rr = recvfrom(nnetfd, bigbuf_net, BIGSIZ, MSG_PEEK,
        !           639:                                        (struct sockaddr *)remend, &x);
1.6       deraadt   640:                } else
1.11    ! ericj     641:                        goto dol_tmo;
1.6       deraadt   642:                arm(0, 0);
1.11    ! ericj     643:                rr = connect(nnetfd, (struct sockaddr *)remend,
        !           644:                                                sizeof(struct sockaddr));
1.6       deraadt   645:                goto whoisit;
1.11    ! ericj     646:        }
1.6       deraadt   647:        /* fall here for TCP */
1.11    ! ericj     648:        x = sizeof(struct sockaddr);
        !           649:        arm(2, o_wait);
1.6       deraadt   650:        if (setjmp(jbuf) == 0) {
1.7       deraadt   651:                rr = accept(nnetfd, (struct sockaddr *) remend, &x);
1.6       deraadt   652:        } else
1.11    ! ericj     653:                goto dol_tmo;
1.6       deraadt   654:        arm(0, 0);
                    655:        close(nnetfd);          /* dump the old socket */
                    656:        nnetfd = rr;            /* here's our new one */
1.1       deraadt   657:
                    658: whoisit:
1.6       deraadt   659:        if (rr < 0)
                    660:                goto dol_err;   /* bail out if any errors so far */
1.1       deraadt   661:
1.11    ! ericj     662:        /*
        !           663:         * Find out what address the connection was *to* on
        !           664:         * our end, in case we're doing a listen-on-any on
        !           665:         * a multihomed machine. This allows one to offer
        !           666:         * different services via different alias addresses,
        !           667:         * such as the "virtual web site" hack.
        !           668:         */
1.6       deraadt   669:        memset(bigbuf_net, 0, 64);
                    670:        cp = &bigbuf_net[32];
1.7       deraadt   671:        x = sizeof(struct sockaddr);
                    672:        rr = getsockname(nnetfd, (struct sockaddr *) lclend, &x);
1.6       deraadt   673:        if (rr < 0)
1.11    ! ericj     674:                warn("post-rcv getsockname failed");
1.6       deraadt   675:        strcpy(cp, inet_ntoa(lclend->sin_addr));
1.1       deraadt   676:
1.6       deraadt   677:        z = ntohs(remend->sin_port);
                    678:        strcpy(bigbuf_net, inet_ntoa(remend->sin_addr));
1.11    ! ericj     679:        whozis = gethinfo(bigbuf_net, o_nflag);
1.6       deraadt   680:        errno = 0;
1.11    ! ericj     681:        x = 0;
1.6       deraadt   682:        if (rad)                /* xxx: fix to go down the *list* if we have
                    683:                                 * one? */
1.7       deraadt   684:                if (memcmp(rad, whozis->iaddrs, sizeof(struct sockaddr)))
1.6       deraadt   685:                        x = 1;
1.11    ! ericj     686:        if (rp) {
1.6       deraadt   687:                if (z != rp)
                    688:                        x = 1;
1.11    ! ericj     689:        }
        !           690:        if (x) {
        !           691:                errx(1, "invalid connection to [%s] from %s [%s] %d",
1.6       deraadt   692:                    cp, whozis->name, whozis->addrs[0], z);
1.11    ! ericj     693:        }
        !           694:        warn("connect to [%s] from %s [%s] %d",
1.6       deraadt   695:            cp, whozis->name, whozis->addrs[0], z);
1.11    ! ericj     696:        return (nnetfd);
1.1       deraadt   697:
                    698: dol_tmo:
1.11    ! ericj     699:        errno = ETIMEDOUT;
1.1       deraadt   700: dol_err:
1.6       deraadt   701:        close(nnetfd);
                    702:        return (-1);
1.7       deraadt   703: }
1.1       deraadt   704:
1.11    ! ericj     705: /*
        !           706:  * udptest :
        !           707:  * fire a couple of packets at a UDP target port, just to see if it's really
        !           708:  * there.  On BSD kernels, ICMP host/port-unreachable errors get delivered to
        !           709:  * our socket as ECONNREFUSED write errors.  On SV kernels, we lose; we'll have
        !           710:  * to collect and analyze raw ICMP ourselves a la satan's probe_udp_ports
        !           711:  * backend.  Guess where one could swipe the appropriate code from...
        !           712:  *
        !           713:  * Use the time delay between writes if given, otherwise use the "tcp ping"
        !           714:  * trick for getting the RTT.  [I got that idea from pluvius, and warped it.]
        !           715:  * Return either the original fd, or clean up and return -1.
        !           716:  */
1.6       deraadt   717: udptest(fd, where)
                    718:        int     fd;
1.7       deraadt   719:        struct in_addr     *where;
1.6       deraadt   720: {
1.11    ! ericj     721:        int rr;
1.6       deraadt   722:
                    723:        rr = write(fd, bigbuf_in, 1);
                    724:        if (rr != 1)
1.11    ! ericj     725:                warn("udptest first write failed?! errno %d", errno);
1.6       deraadt   726:        if (o_wait)
                    727:                sleep(o_wait);
                    728:        else {
1.11    ! ericj     729:                o_udpmode = 0;
        !           730:                o_wait = 5;
1.6       deraadt   731:                rr = doconnect(where, SLEAZE_PORT, 0, 0);
                    732:                if (rr > 0)
1.11    ! ericj     733:                        close(rr);
        !           734:                o_wait = 0;
        !           735:                o_udpmode++;
        !           736:        }
        !           737:        errno = 0;
1.6       deraadt   738:        rr = write(fd, bigbuf_in, 1);
1.11    ! ericj     739:        if (rr == 1)
1.6       deraadt   740:                return (fd);
1.11    ! ericj     741:        close(fd);
1.6       deraadt   742:        return (-1);
1.7       deraadt   743: }
                    744:
1.11    ! ericj     745: /*
        !           746:  *  oprint :
        !           747:  * Hexdump bytes shoveled either way to a running logfile, in the format:
        !           748:  * D offset       -  - - - --- 16 bytes --- - - -  -     # .... ascii .....
        !           749:  * where "which" sets the direction indicator, D:
        !           750:  * 0 -- sent to network, or ">"
        !           751:  * 1 -- rcvd and printed to stdout, or "<"
        !           752:  * and "buf" and "n" are data-block and length.  If the current block generates
        !           753:  * a partial line, so be it; we *want* that lockstep indication of who sent
        !           754:  * what when.  Adapted from dgaudet's original example -- but must be ripping
        !           755:  * *fast*, since we don't want to be too disk-bound.
        !           756:  */
1.6       deraadt   757: void
                    758: oprint(which, buf, n)
                    759:        int     which;
                    760:        char   *buf;
                    761:        int     n;
                    762: {
                    763:        int     bc;             /* in buffer count */
                    764:        int     obc;            /* current "global" offset */
                    765:        int     soc;            /* stage write count */
1.11    ! ericj     766:        unsigned char *p;       /* main buf ptr; m.b. unsigned here */
        !           767:        unsigned char *op;      /* out hexdump ptr */
        !           768:        unsigned char *a;       /* out asc-dump ptr */
        !           769:        int x;
        !           770:        unsigned int y;
1.6       deraadt   771:
                    772:        if (!ofd)
1.11    ! ericj     773:                errx(1, "oprint called with no open fd?!");
1.6       deraadt   774:        if (n == 0)
                    775:                return;
                    776:
                    777:        op = stage;
                    778:        if (which) {
                    779:                *op = '<';
                    780:                obc = wrote_out;/* use the globals! */
                    781:        } else {
                    782:                *op = '>';
                    783:                obc = wrote_net;
                    784:        }
                    785:        op++;                   /* preload "direction" */
                    786:        *op = ' ';
                    787:        p = (unsigned char *) buf;
                    788:        bc = n;
                    789:        stage[59] = '#';        /* preload separator */
                    790:        stage[60] = ' ';
                    791:
                    792:        while (bc) {            /* for chunk-o-data ... */
                    793:                x = 16;
                    794:                soc = 78;       /* len of whole formatted line */
                    795:                if (bc < x) {
                    796:                        soc = soc - 16 + bc;    /* fiddle for however much is
                    797:                                                 * left */
                    798:                        x = (bc * 3) + 11;      /* 2 digits + space per, after
                    799:                                                 * D & offset */
                    800:                        op = &stage[x];
                    801:                        x = 16 - bc;
                    802:                        while (x) {
                    803:                                *op++ = ' ';    /* preload filler spaces */
                    804:                                *op++ = ' ';
                    805:                                *op++ = ' ';
                    806:                                x--;
                    807:                        }
                    808:                        x = bc; /* re-fix current linecount */
                    809:                }               /* if bc < x */
                    810:                bc -= x;        /* fix wrt current line size */
                    811:                sprintf(&stage[2], "%8.8x ", obc);      /* xxx: still slow? */
                    812:                obc += x;       /* fix current offset */
                    813:                op = &stage[11];/* where hex starts */
                    814:                a = &stage[61]; /* where ascii starts */
                    815:
                    816:                while (x) {     /* for line of dump, however long ... */
                    817:                        y = (int) (*p >> 4);    /* hi half */
                    818:                        *op = hexnibs[y];
                    819:                        op++;
                    820:                        y = (int) (*p & 0x0f);  /* lo half */
                    821:                        *op = hexnibs[y];
                    822:                        op++;
                    823:                        *op = ' ';
                    824:                        op++;
                    825:                        if ((*p > 31) && (*p < 127))
                    826:                                *a = *p;        /* printing */
                    827:                        else
                    828:                                *a = '.';       /* nonprinting, loose def */
                    829:                        a++;
                    830:                        p++;
                    831:                        x--;
                    832:                }               /* while x */
                    833:                *a = '\n';      /* finish the line */
                    834:                x = write(ofd, stage, soc);
                    835:                if (x < 0)
1.11    ! ericj     836:                        errx(1, "ofd write err");
        !           837:        }
1.7       deraadt   838: }
                    839:
1.1       deraadt   840: #ifdef TELNET
1.7       deraadt   841: u_short  o_tn = 0;             /* global -t option */
1.1       deraadt   842:
1.11    ! ericj     843: /*
        !           844:  *  atelnet :
        !           845:  * Answer anything that looks like telnet negotiation with don't/won't.
        !           846:  * This doesn't modify any data buffers, update the global output count,
        !           847:  * or show up in a hexdump -- it just shits into the outgoing stream.
        !           848:  * Idea and codebase from Mudge@l0pht.com.
        !           849:  */
1.6       deraadt   850: void
                    851: atelnet(buf, size)
                    852:        unsigned char *buf;     /* has to be unsigned here! */
                    853:        unsigned int size;
                    854: {
                    855:        static unsigned char obuf[4];   /* tiny thing to build responses into */
1.11    ! ericj     856:        int x;
        !           857:        unsigned char y;
        !           858:        unsigned char *p;
1.6       deraadt   859:
                    860:        y = 0;
                    861:        p = buf;
                    862:        x = size;
                    863:        while (x > 0) {
                    864:                if (*p != 255)  /* IAC? */
                    865:                        goto notiac;
                    866:                obuf[0] = 255;
                    867:                p++;
                    868:                x--;
                    869:                if ((*p == 251) || (*p == 252)) /* WILL or WONT */
                    870:                        y = 254;/* -> DONT */
                    871:                if ((*p == 253) || (*p == 254)) /* DO or DONT */
                    872:                        y = 252;/* -> WONT */
                    873:                if (y) {
                    874:                        obuf[1] = y;
                    875:                        p++;
                    876:                        x--;
1.11    ! ericj     877:                        obuf[2] = *p;
1.6       deraadt   878:                        (void) write(netfd, obuf, 3);
1.11    ! ericj     879:                        /*
        !           880:                         * if one wanted to bump wrote_net or do
        !           881:                         * a hexdump line, here's the place.
        !           882:                         */
1.6       deraadt   883:                        y = 0;
1.11    ! ericj     884:                }
1.1       deraadt   885: notiac:
1.6       deraadt   886:                p++;
                    887:                x--;
1.11    ! ericj     888:        }
1.7       deraadt   889: }
1.11    ! ericj     890: #endif /* TELNET */
1.7       deraadt   891:
1.11    ! ericj     892: /*
        !           893:  *  readwrite :
        !           894:  * handle stdin/stdout/network I/O.  Bwahaha!! -- the select loop from hell.
        !           895:  * In this instance, return what might become our exit status.
        !           896:  */
1.6       deraadt   897: int
                    898: readwrite(fd)
                    899:        int     fd;
                    900: {
1.11    ! ericj     901:        int rr;
        !           902:        char *zp;       /* stdin buf ptr */
        !           903:        char *np;       /* net-in buf ptr */
1.6       deraadt   904:        unsigned int rzleft;
                    905:        unsigned int rnleft;
1.7       deraadt   906:        u_short  netretry;      /* net-read retry counter */
1.11    ! ericj     907:        u_short  wretry;        /* net-write sanity counter */
        !           908:        u_short  wfirst;        /* one-shot flag to skip first net read */
1.1       deraadt   909:
1.11    ! ericj     910:        /*
        !           911:         * if you don't have all this FD_* macro hair in sys/types.h,
        !           912:         * you'll have to either find it or do your own bit-bashing:
        !           913:         * *ds1 |= (1 << fd), etc.
        !           914:         */
1.6       deraadt   915:        if (fd > FD_SETSIZE) {
1.11    ! ericj     916:                warn("Preposterous fd value %d", fd);
1.6       deraadt   917:                return (1);
                    918:        }
1.11    ! ericj     919:        FD_SET(fd, &fds1);
1.6       deraadt   920:        netretry = 2;
                    921:        wfirst = 0;
                    922:        rzleft = rnleft = 0;
                    923:        if (insaved) {
                    924:                rzleft = insaved;       /* preload multi-mode fakeouts */
                    925:                zp = bigbuf_in;
                    926:                wfirst = 1;
1.11    ! ericj     927:                /* If not scanning, this is a one-off first */
        !           928:                if (Single)
        !           929:                        insaved = 0;
1.6       deraadt   930:                else {
1.11    ! ericj     931:                        FD_CLR(0, &fds1);
        !           932:                        close(0);
        !           933:                }
        !           934:        }
1.6       deraadt   935:        if (o_interval)
1.11    ! ericj     936:                sleep(o_interval);
        !           937:        errno = 0;
1.1       deraadt   938:
1.7       deraadt   939:        while (FD_ISSET(fd, &fds1)) {   /* i.e. till the *net* closes! */
1.9       art       940:                struct timeval *tv;
                    941:
1.11    ! ericj     942:                wretry = 8200;          /* more than we'll ever hafta write */
        !           943:                if (wfirst) {           /* any saved stdin buffer? */
1.6       deraadt   944:                        wfirst = 0;     /* clear flag for the duration */
                    945:                        goto shovel;    /* and go handle it first */
                    946:                }
1.7       deraadt   947:                fds2 = fds1;
1.9       art       948:                if (timer1.tv_sec > 0 || timer1.tv_usec > 0) {
                    949:                        memcpy(&timer2, &timer1, sizeof(struct timeval));
                    950:                        tv = &timer2;
                    951:                } else
                    952:                        tv = NULL;
                    953:                rr = select(getdtablesize(), &fds2, 0, 0, tv);
1.6       deraadt   954:                if (rr < 0) {
1.11    ! ericj     955:                        if (errno != EINTR) {
        !           956:                                warn("Select Failure");
1.6       deraadt   957:                                close(fd);
                    958:                                return (1);
                    959:                        }
1.11    ! ericj     960:                }
1.6       deraadt   961:                /* if we have a timeout AND stdin is closed AND we haven't
                    962:                 * heard anything from the net during that time, assume it's
                    963:                 * dead and close it too. */
                    964:                if (rr == 0) {
1.7       deraadt   965:                        if (!FD_ISSET(0, &fds1))
1.6       deraadt   966:                                netretry--;     /* we actually try a coupla
                    967:                                                 * times. */
                    968:                        if (!netretry) {
                    969:                                if (o_verbose > 1)      /* normally we don't
                    970:                                                         * care */
1.11    ! ericj     971:                                        warn("net timeout");
1.6       deraadt   972:                                close(fd);
                    973:                                return (0);     /* not an error! */
                    974:                        }
                    975:                }               /* select timeout */
1.11    ! ericj     976:                /* XXX: should we check the exception fds too?  The read fds
1.6       deraadt   977:                 * seem to give us the right info, and none of the examples I
                    978:                 * found bothered. */
                    979:                /* Ding!!  Something arrived, go check all the incoming
                    980:                 * hoppers, net first */
1.7       deraadt   981:                if (FD_ISSET(fd, &fds2)) {      /* net: ding! */
1.6       deraadt   982:                        rr = read(fd, bigbuf_net, BIGSIZ);
                    983:                        if (rr <= 0) {
1.7       deraadt   984:                                FD_CLR(fd, &fds1);      /* net closed, we'll
1.6       deraadt   985:                                                         * finish up... */
                    986:                                rzleft = 0;     /* can't write anymore: broken
                    987:                                                 * pipe */
                    988:                        } else {
                    989:                                rnleft = rr;
                    990:                                np = bigbuf_net;
1.1       deraadt   991: #ifdef TELNET
1.6       deraadt   992:                                if (o_tn)
                    993:                                        atelnet(np, rr);        /* fake out telnet stuff */
1.11    ! ericj     994: #endif /* TELNET */
        !           995:                        }
        !           996:                }
1.6       deraadt   997:                /* if we're in "slowly" mode there's probably still stuff in
                    998:                 * the stdin buffer, so don't read unless we really need MORE
                    999:                 * INPUT!  MORE INPUT! */
                   1000:                if (rzleft)
                   1001:                        goto shovel;
1.1       deraadt  1002:
1.11    ! ericj    1003:                if (FD_ISSET(0, &fds2)) {
1.6       deraadt  1004:                        rr = read(0, bigbuf_in, BIGSIZ);
1.11    ! ericj    1005:                        if (rr <= 0) {
        !          1006:                                FD_CLR(0, &fds1);       /* disable and close */
1.6       deraadt  1007:                                close(0);
                   1008:                        } else {
                   1009:                                rzleft = rr;
                   1010:                                zp = bigbuf_in;
1.11    ! ericj    1011:                                if (!Single) {
        !          1012:                                        insaved = rr;
        !          1013:                                        FD_CLR(0, &fds1);
        !          1014:                                        close(0);
        !          1015:                                }
        !          1016:                        }
        !          1017:                }
1.1       deraadt  1018: shovel:
1.11    ! ericj    1019:                /* sanity check.  Works because they're both unsigned... */
1.6       deraadt  1020:                if ((rzleft > 8200) || (rnleft > 8200)) {
1.11    ! ericj    1021:                        warn("Bogus buffers: %d, %d", rzleft, rnleft);
1.6       deraadt  1022:                        rzleft = rnleft = 0;
                   1023:                }
1.11    ! ericj    1024:                /* net write retries sometimes happen on UDP connections */
1.6       deraadt  1025:                if (!wretry) {  /* is something hung? */
1.11    ! ericj    1026:                        warn("too many output retries");
1.6       deraadt  1027:                        return (1);
                   1028:                }
                   1029:                if (rnleft) {
                   1030:                        rr = write(1, np, rnleft);
                   1031:                        if (rr > 0) {
                   1032:                                if (o_wfile)
1.11    ! ericj    1033:                                        oprint(1, np, rr);
        !          1034:                                np += rr;
        !          1035:                                rnleft -= rr;
1.6       deraadt  1036:                                wrote_out += rr;        /* global count */
                   1037:                        }
1.11    ! ericj    1038:                }
1.6       deraadt  1039:                if (rzleft) {
1.11    ! ericj    1040:                        if (o_interval)
1.6       deraadt  1041:                                rr = findline(zp, rzleft);
                   1042:                        else
                   1043:                                rr = rzleft;
1.11    ! ericj    1044:                        rr = write(fd, zp, rr);
1.6       deraadt  1045:                        if (rr > 0) {
                   1046:                                if (o_wfile)
1.11    ! ericj    1047:                                        oprint(0, zp, rr);
1.6       deraadt  1048:                                zp += rr;
                   1049:                                rzleft -= rr;
1.11    ! ericj    1050:                                wrote_net += rr;
1.6       deraadt  1051:                        }
1.11    ! ericj    1052:                }
        !          1053:                if (o_interval) {
1.6       deraadt  1054:                        sleep(o_interval);
1.11    ! ericj    1055:                        errno = 0;
        !          1056:                        continue;
1.6       deraadt  1057:                }
1.11    ! ericj    1058:                if ((rzleft) || (rnleft)) {
        !          1059:                        wretry--;
1.6       deraadt  1060:                        goto shovel;
                   1061:                }
1.11    ! ericj    1062:        }
1.1       deraadt  1063:
1.6       deraadt  1064:        close(fd);
                   1065:        return (0);
1.7       deraadt  1066: }
1.1       deraadt  1067:
                   1068: /* main :
                   1069:    now we pull it all together... */
1.6       deraadt  1070: main(argc, argv)
                   1071:        int     argc;
                   1072:        char  **argv;
1.1       deraadt  1073: {
1.11    ! ericj    1074:        int x, ch;
        !          1075:        char *cp;
1.7       deraadt  1076:        struct host_info   *gp;
                   1077:        struct host_info   *whereto = NULL;
                   1078:        struct host_info   *wherefrom = NULL;
                   1079:        struct in_addr     *ouraddr = NULL;
                   1080:        struct in_addr     *themaddr = NULL;
                   1081:        u_short  o_lport = 0;
                   1082:        u_short  ourport = 0;
                   1083:        u_short  loport = 0;    /* for scanning stuff */
                   1084:        u_short  hiport = 0;
                   1085:        u_short  curport = 0;
1.6       deraadt  1086:        char   *randports = NULL;
1.1       deraadt  1087:
                   1088: #ifdef HAVE_BIND
1.6       deraadt  1089:        res_init();
1.1       deraadt  1090: #endif
1.7       deraadt  1091:        lclend = (struct sockaddr_in *) calloc(1, sizeof(struct sockaddr));
                   1092:        remend = (struct sockaddr_in *) calloc(1, sizeof(struct sockaddr));
                   1093:        bigbuf_in = calloc(1, BIGSIZ);
                   1094:        bigbuf_net = calloc(1, BIGSIZ);
1.11    ! ericj    1095:        pinfo= (struct port_info *) calloc(1, sizeof(struct port_info));
1.6       deraadt  1096:
                   1097:        errno = 0;
                   1098:        gatesptr = 4;
                   1099:        h_errno = 0;
1.1       deraadt  1100:
1.11    ! ericj    1101:        /*
        !          1102:         * We want to catch a few of these signals.
        !          1103:         * Others we disgard.
        !          1104:         */
1.6       deraadt  1105:        signal(SIGINT, catch);
                   1106:        signal(SIGQUIT, catch);
                   1107:        signal(SIGTERM, catch);
                   1108:        signal(SIGURG, SIG_IGN);
                   1109:        signal(SIGPIPE, SIG_IGN);       /* important! */
1.1       deraadt  1110:
1.11    ! ericj    1111:        /*
        !          1112:         * If no args given at all, get 'em from stdin, construct an argv,
        !          1113:         * and hand anything left over to readwrite().
        !          1114:         */
1.6       deraadt  1115:        if (argc == 1) {
                   1116:                cp = argv[0];
1.11    ! ericj    1117:                /* XXX - 128 ? */
        !          1118:                argv = (char **) calloc(1, 128 * sizeof(char *));
1.6       deraadt  1119:                argv[0] = cp;   /* leave old prog name intact */
1.7       deraadt  1120:                cp = calloc(1, BIGSIZ);
1.6       deraadt  1121:                argv[1] = cp;   /* head of new arg block */
                   1122:                fprintf(stderr, "Cmd line: ");
                   1123:                fflush(stderr); /* I dont care if it's unbuffered or not! */
1.10      deraadt  1124:                insaved = read(0, cp, BIGSIZ-1); /* we're gonna fake fgets()
1.6       deraadt  1125:                                                 * here */
1.10      deraadt  1126:                cp[BIGSIZ-1] = '\0';
1.6       deraadt  1127:                if (insaved <= 0)
1.11    ! ericj    1128:                        errx(1, "wrong");
1.6       deraadt  1129:                x = findline(cp, insaved);
                   1130:                if (x)
                   1131:                        insaved -= x;   /* remaining chunk size to be sent */
                   1132:                if (insaved)    /* which might be zero... */
                   1133:                        memcpy(bigbuf_in, &cp[x], insaved);
                   1134:                cp = strchr(argv[1], '\n');
                   1135:                if (cp)
                   1136:                        *cp = '\0';
                   1137:                cp = strchr(argv[1], '\r');     /* look for ^M too */
                   1138:                if (cp)
                   1139:                        *cp = '\0';
1.1       deraadt  1140:
1.11    ! ericj    1141:                /*
        !          1142:                 * Find and stash pointers to remaining new "args"
        !          1143:                 */
1.6       deraadt  1144:                cp = argv[1];
                   1145:                cp++;           /* skip past first char */
                   1146:                x = 2;          /* we know argv 0 and 1 already */
                   1147:                for (; *cp != '\0'; cp++) {
                   1148:                        if (*cp == ' ') {
                   1149:                                *cp = '\0';     /* smash all spaces */
                   1150:                                continue;
                   1151:                        } else {
                   1152:                                if (*(cp - 1) == '\0') {
                   1153:                                        argv[x] = cp;
                   1154:                                        x++;
                   1155:                                }
                   1156:                        }       /* if space */
                   1157:                }               /* for cp */
                   1158:                argc = x;
1.11    ! ericj    1159:        }
        !          1160:
        !          1161:        while ((ch = getopt(argc, argv, "g:G:hi:lno:p:rs:tuvw:z")) != -1) {
        !          1162:                switch (ch) {
        !          1163:                case 'G':                       /* srcrt gateways pointer val */
1.6       deraadt  1164:                        x = atoi(optarg);
1.11    ! ericj    1165:                        /* Mask of bits */
        !          1166:                        if ((x) && (x == (x & 0x1c)))
1.6       deraadt  1167:                                gatesptr = x;
                   1168:                        else
1.11    ! ericj    1169:                                errx(1, "invalid hop pointer %d, must be multiple of 4 <= 28", x);
1.6       deraadt  1170:                        break;
1.11    ! ericj    1171:                case 'g':                       /* srcroute hop[s] */
1.6       deraadt  1172:                        if (gatesidx > 8)
1.11    ! ericj    1173:                                errx(1, "Too many -g hops!");
        !          1174:                        if (gates == NULL)
        !          1175:                                gates = (struct host_info **) calloc(1,
        !          1176:                                                sizeof(struct host_info *) * 10);
        !          1177:                        gp = gethinfo(optarg, o_nflag);
1.6       deraadt  1178:                        if (gp)
                   1179:                                gates[gatesidx] = gp;
                   1180:                        gatesidx++;
                   1181:                        break;
                   1182:                case 'h':
1.11    ! ericj    1183:                        help();
        !          1184:                        break;
        !          1185:                case 'i':                       /* line-interval time */
1.6       deraadt  1186:                        o_interval = atoi(optarg) & 0xffff;
                   1187:                        if (!o_interval)
1.11    ! ericj    1188:                                errx(1, "invalid interval time %s", optarg);
1.6       deraadt  1189:                        break;
1.11    ! ericj    1190:                case 'l':                       /* listen mode */
1.6       deraadt  1191:                        o_listen++;
                   1192:                        break;
1.11    ! ericj    1193:                case 'n':                       /* numeric-only, no DNS lookups */
1.6       deraadt  1194:                        o_nflag++;
                   1195:                        break;
1.11    ! ericj    1196:                case 'o':                       /* hexdump log */
1.6       deraadt  1197:                        stage = (unsigned char *) optarg;
                   1198:                        o_wfile++;
                   1199:                        break;
1.11    ! ericj    1200:                case 'p':                       /* local source port */
        !          1201:                        o_lport = getpinfo(optarg, 0);
1.6       deraadt  1202:                        if (o_lport == 0)
1.11    ! ericj    1203:                                errx(1, "invalid local port %s", optarg);
1.6       deraadt  1204:                        break;
1.11    ! ericj    1205:                case 'r':                       /* randomize various things */
1.6       deraadt  1206:                        o_random++;
                   1207:                        break;
1.11    ! ericj    1208:                /*
        !          1209:                 * Do a full lookup [since everything else goes through the same
        !          1210:                 * mill], unless -n was previously specified. In fact, careful
        !          1211:                 * placement of -n can be useful, so we'll still pass o_nflag
        !          1212:                 * here instead of forcing numeric.
        !          1213:                 */
        !          1214:                case 's':                       /* local source address */
        !          1215:                        wherefrom = gethinfo(optarg, o_nflag);
1.6       deraadt  1216:                        ouraddr = &wherefrom->iaddrs[0];
                   1217:                        break;
1.1       deraadt  1218: #ifdef TELNET
1.11    ! ericj    1219:                case 't':                       /* do telnet fakeout */
1.6       deraadt  1220:                        o_tn++;
                   1221:                        break;
1.11    ! ericj    1222: #endif
        !          1223:                case 'u':                       /* use UDP */
1.6       deraadt  1224:                        o_udpmode++;
                   1225:                        break;
1.11    ! ericj    1226:                case 'v':                       /* verbose */
1.6       deraadt  1227:                        o_verbose++;
                   1228:                        break;
1.11    ! ericj    1229:                case 'w':                       /* wait time */
1.6       deraadt  1230:                        o_wait = atoi(optarg);
                   1231:                        if (o_wait <= 0)
1.11    ! ericj    1232:                                errx(1, "invalid wait-time %s", optarg);
1.7       deraadt  1233:                        timer1.tv_sec = o_wait;
                   1234:                        timer1.tv_usec = 0;
1.6       deraadt  1235:                        break;
1.11    ! ericj    1236:                case 'z':                       /* little or no data xfer */
1.6       deraadt  1237:                        o_zero++;
                   1238:                        break;
                   1239:                default:
1.11    ! ericj    1240:                        usage(1);
        !          1241:                }
        !          1242:        }
1.1       deraadt  1243:
1.11    ! ericj    1244:        /* other misc initialization */
1.7       deraadt  1245:            FD_SET(0, &fds1);   /* stdin *is* initially open */
1.6       deraadt  1246:        if (o_random) {
                   1247:                SRAND(time(0));
1.11    ! ericj    1248:                randports = calloc(1, 65536);   /* big flag array for ports */
1.6       deraadt  1249:        }
                   1250:        if (o_wfile) {
                   1251:                ofd = open(stage, O_WRONLY | O_CREAT | O_TRUNC, 0664);
                   1252:                if (ofd <= 0)   /* must be > extant 0/1/2 */
1.11    ! ericj    1253:                        errx(1, "Can't open %s", stage);
1.7       deraadt  1254:                stage = (unsigned char *) calloc(1, 100);
1.6       deraadt  1255:        }
1.11    ! ericj    1256:        /* optind is now index of first non -x arg */
        !          1257:        if (argv[optind])
        !          1258:                whereto = gethinfo(argv[optind], o_nflag);
1.6       deraadt  1259:        if (whereto && whereto->iaddrs)
                   1260:                themaddr = &whereto->iaddrs[0];
                   1261:        if (themaddr)
                   1262:                optind++;       /* skip past valid host lookup */
                   1263:        errno = 0;
                   1264:        h_errno = 0;
1.1       deraadt  1265:
1.11    ! ericj    1266:        /*
        !          1267:         * Handle listen mode here, and exit afterward.  Only does one connect;
        !          1268:         * this is arguably the right thing to do.  A "persistent listen-and-fork"
        !          1269:         * mode a la inetd has been thought about, but not implemented.  A tiny
        !          1270:         * wrapper script can handle such things.
        !          1271:         */
1.6       deraadt  1272:        if (o_listen) {
1.11    ! ericj    1273:                curport = 0;
        !          1274:                if (argv[optind]) {
        !          1275:                        curport = getpinfo(argv[optind], 0);
        !          1276:                        if (curport == 0)
        !          1277:                                errx(1, "invalid port %s", argv[optind]);
        !          1278:                }
1.6       deraadt  1279:                netfd = dolisten(themaddr, curport, ouraddr, o_lport);
                   1280:                if (netfd > 0) {
1.11    ! ericj    1281:                        x = readwrite(netfd);
        !          1282:                        if (o_verbose > 1)
        !          1283:                                warn("Sent %i Rcvd %i", wrote_net, wrote_out);
        !          1284:                        exit(x);
        !          1285:                } else
        !          1286:                        errx(1, "no connection");
        !          1287:        }
1.6       deraadt  1288:        /* fall thru to outbound connects.  Now we're more picky about args... */
                   1289:        if (!themaddr)
1.11    ! ericj    1290:                errx(1, "no destination");
1.6       deraadt  1291:        if (argv[optind] == NULL)
1.11    ! ericj    1292:                errx(1, "no port[s] to connect to");
        !          1293:        if (argv[optind + 1])
        !          1294:                Single = 0;
        !          1295:        ourport = o_lport;
        !          1296:
1.6       deraadt  1297:        while (argv[optind]) {
                   1298:                hiport = loport = 0;
1.11    ! ericj    1299:                cp = strchr(argv[optind], '-');
1.6       deraadt  1300:                if (cp) {
                   1301:                        *cp = '\0';
                   1302:                        cp++;
1.11    ! ericj    1303:                        hiport = getpinfo(cp, 0);
1.6       deraadt  1304:                        if (hiport == 0)
1.11    ! ericj    1305:                                errx(1, "invalid port %s", cp);
1.6       deraadt  1306:                }               /* if found a dash */
1.11    ! ericj    1307:                loport = getpinfo(argv[optind], 0);
1.6       deraadt  1308:                if (loport == 0)
1.11    ! ericj    1309:                        errx(1, "invalid port %s", argv[optind]);
1.6       deraadt  1310:                if (hiport > loport) {  /* was it genuinely a range? */
                   1311:                        Single = 0;     /* multi-mode, case B */
                   1312:                        if (o_random) { /* maybe populate the random array */
                   1313:                                loadports(randports, loport, hiport);
                   1314:                                curport = nextport(randports);
1.11    ! ericj    1315:                        } else
        !          1316:                                curport = hiport;
1.6       deraadt  1317:                } else          /* not a range, including args like "25-25" */
                   1318:                        curport = loport;
1.11    ! ericj    1319:                    /*
        !          1320:                     * Now start connecting to these things.
        !          1321:                     * curport is already preloaded.
        !          1322:                     */
1.6       deraadt  1323:                    while (loport <= curport) {
1.11    ! ericj    1324:                        curport = getpinfo(NULL, curport);
1.6       deraadt  1325:                        netfd = doconnect(themaddr, curport, ouraddr, ourport);
1.11    ! ericj    1326:                        if (netfd > 0)
        !          1327:                                if (o_zero && o_udpmode)
1.6       deraadt  1328:                                        netfd = udptest(netfd, themaddr);
1.11    ! ericj    1329:                        if (netfd > 0) {
        !          1330:                                x = 0;
        !          1331:                                if (o_verbose) {
        !          1332:                                        warn("%s [%s] %d (%s) open",
        !          1333:                                                whereto->name,
        !          1334:                                                whereto->addrs[0], curport,
        !          1335:                                                pinfo->name);
        !          1336:                                }
1.6       deraadt  1337:                                if (!o_zero)
1.11    ! ericj    1338:                                        x = readwrite(netfd);
        !          1339:                        } else {
        !          1340:                                x = 1;
        !          1341:                                if ((Single || (o_verbose > 1))
        !          1342:                                   || (errno != ECONNREFUSED)) {
        !          1343:                                        warn("%s [%s] %d (%s)",
        !          1344:                                            whereto->name, whereto->addrs[0],
        !          1345:                                                        curport, pinfo->name);
        !          1346:                                }
        !          1347:                        }
        !          1348:                        close(netfd);
1.6       deraadt  1349:                        if (o_interval)
1.11    ! ericj    1350:                                sleep(o_interval);
1.6       deraadt  1351:                        if (o_random)
                   1352:                                curport = nextport(randports);
                   1353:                        else
1.11    ! ericj    1354:                                curport--;
        !          1355:                }
1.6       deraadt  1356:                optind++;
1.11    ! ericj    1357:        }
1.6       deraadt  1358:
                   1359:        errno = 0;
1.11    ! ericj    1360:        if (o_verbose > 1)
        !          1361:                warn("Sent %i Rcvd %i", wrote_net, wrote_out);
1.6       deraadt  1362:        if (Single)
1.11    ! ericj    1363:                exit(x);
        !          1364:        exit(0);
1.7       deraadt  1365: }
1.1       deraadt  1366:
1.11    ! ericj    1367: void
        !          1368: usage(doexit)
1.1       deraadt  1369: {
1.11    ! ericj    1370:        fprintf(stderr, "netcat - [v1.10]\n");
        !          1371:        fprintf(stderr, "nc [-lnrtuvz] [-e command] [-g intermediates]\n");
        !          1372:        fprintf(stderr, "   [-G hopcount] [-i interval] [-o filename] [-p source port]\n");
        !          1373:        fprintf(stderr, "   [-s ip address] [-w timeout] [hostname] [port[s...]]\n");
        !          1374:        if (doexit)
        !          1375:                exit(1);
        !          1376: }
        !          1377:
        !          1378: void
        !          1379: help()
        !          1380: {
        !          1381:        usage(0);
        !          1382:        fprintf(stderr, "\tCommand Summary:\n\
        !          1383:         \t-g gateway   source-routing hop point[s], up to 8\n\
        !          1384:         \t-G num\t     source-routing pointer: 4, 8, 12, ...\n\
        !          1385:         \t-h           this help text\n\
        !          1386:         \t-i secs\t    delay interval for lines sent, ports scanned\n\
        !          1387:         \t-l           listen mode, for inbound connects\n\
        !          1388:         \t-n           numeric-only IP addresses, no DNS\n\
        !          1389:         \t-o file\t    hex dump of traffic\n\
        !          1390:         \t-r           randomize local and remote ports\n\
        !          1391:         \t-s addr\t    local source address\n");
1.1       deraadt  1392: #ifdef TELNET
1.11    ! ericj    1393:         fprintf(stderr, "\t\t-t                answer TELNET negotiation\n");
1.1       deraadt  1394: #endif
1.11    ! ericj    1395:         fprintf(stderr, "\t\t-u                UDP mode\n\
        !          1396:         \t-v           verbose [use twice to be more verbose]\n\
        !          1397:         \t-w secs\t    timeout for connects and final net reads\n\
        !          1398:         \t-z           zero-I/O mode [used for scanning]\n\
        !          1399:         Port numbers can be individual or ranges: lo-hi [inclusive]\n");
        !          1400:        exit(1);
1.7       deraadt  1401: }