Home | History | Annotate | Download | only in netcat
      1 /* Netcat 1.10 RELEASE 960320
      2 
      3    A damn useful little "backend" utility begun 950915 or thereabouts,
      4    as *Hobbit*'s first real stab at some sockets programming.  Something that
      5    should have and indeed may have existed ten years ago, but never became a
      6    standard Unix utility.  IMHO, "nc" could take its place right next to cat,
      7    cp, rm, mv, dd, ls, and all those other cryptic and Unix-like things.
      8 
      9    Read the README for the whole story, doc, applications, etc.
     10 
     11    Layout:
     12 	conditional includes:
     13 	includes:
     14 	handy defines:
     15 	globals:
     16 	malloced globals:
     17 	cmd-flag globals:
     18 	support routines:
     19 	readwrite select loop:
     20 	main:
     21 
     22   bluesky:
     23 	parse ranges of IP address as well as ports, perhaps
     24 	RAW mode!
     25 	backend progs to grab a pty and look like a real telnetd?!
     26 	backend progs to do various encryption modes??!?!
     27 */
     28 
     29 #include "generic.h"		/* same as with L5, skey, etc */
     30 
     31 /* conditional includes -- a very messy section which you may have to dink
     32    for your own architecture [and please send diffs...]: */
     33 #if 0
     34 #undef _POSIX_SOURCE		/* might need this for something? */
     35 #endif
     36 #define HAVE_BIND		/* ASSUMPTION -- seems to work everywhere! */
     37 #define HAVE_HELP		/* undefine if you dont want the help text */
     38 #if 0
     39 #define ANAL			/* if you want case-sensitive DNS matching */
     40 #endif
     41 
     42 #ifdef HAVE_STDLIB_H
     43 #include <stdlib.h>
     44 #else
     45 #include <malloc.h>
     46 #endif
     47 #ifdef HAVE_SELECT_H		/* random SV variants need this */
     48 #include <sys/select.h>
     49 #endif
     50 
     51 /* have to do this *before* including types.h. xxx: Linux still has it wrong */
     52 #ifdef FD_SETSIZE		/* should be in types.h, butcha never know. */
     53 #undef FD_SETSIZE		/* if we ever need more than 16 active */
     54 #endif				/* fd's, something is horribly wrong! */
     55 #define FD_SETSIZE 16		/* <-- this'll give us a long anyways, wtf */
     56 #include <sys/types.h>		/* *now* do it.  Sigh, this is broken */
     57 
     58 #ifdef HAVE_RANDOM		/* aficionados of ?rand48() should realize */
     59 #define SRAND srandom		/* that this doesn't need *strong* random */
     60 #define RAND random		/* numbers just to mix up port numbers!! */
     61 #else
     62 #define SRAND srand
     63 #define RAND rand
     64 #endif /* HAVE_RANDOM */
     65 
     66 /* includes: */
     67 #include <sys/time.h>		/* timeval, time_t */
     68 #include <setjmp.h>		/* jmp_buf et al */
     69 #include <sys/socket.h>		/* basics, SO_ and AF_ defs, sockaddr, ... */
     70 
     71 #include <netinet/in.h>		/* sockaddr_in, htons, in_addr */
     72 
     73 #if 0
     74 #include <netinet/in_systm.h>	/* misc crud that netinet/ip.h references */
     75 #endif
     76 #include <netinet/ip.h>		/* IPOPT_LSRR, header stuff */
     77 #include <netdb.h>		/* hostent, gethostby*, getservby* */
     78 #include <arpa/inet.h>		/* inet_ntoa */
     79 #include <stdio.h>
     80 #include <string.h>		/* strcpy, strchr, yadda yadda */
     81 #include <errno.h>
     82 #include <signal.h>
     83 #include <fcntl.h>		/* O_WRONLY et al */
     84 
     85 /* handy stuff: */
     86 #define SA struct sockaddr	/* socket overgeneralization braindeath */
     87 #define SAI struct sockaddr_in	/* ... whoever came up with this model */
     88 #define IA struct in_addr	/* ... should be taken out and shot, */
     89 				/* ... not that TLI is any better.  sigh.. */
     90 #define SLEAZE_PORT 31337	/* for UDP-scan RTT trick, change if ya want */
     91 #define USHORT unsigned short	/* use these for options an' stuff */
     92 #define BIGSIZ 8192		/* big buffers */
     93 
     94 #ifndef INADDR_NONE
     95 #define INADDR_NONE 0xffffffff
     96 #endif
     97 #ifdef MAXHOSTNAMELEN
     98 #undef MAXHOSTNAMELEN		/* might be too small on aix, so fix it */
     99 #endif
    100 #define MAXHOSTNAMELEN 256
    101 
    102 struct host_poop {
    103   char name[MAXHOSTNAMELEN];	/* dns name */
    104   char addrs[8][24];		/* ascii-format IP addresses */
    105   struct in_addr iaddrs[8];	/* real addresses: in_addr.s_addr: ulong */
    106 };
    107 #define HINF struct host_poop
    108 
    109 struct port_poop {
    110   char name [64];		/* name in /etc/services */
    111   char anum [8];		/* ascii-format number */
    112   USHORT num;			/* real host-order number */
    113 };
    114 #define PINF struct port_poop
    115 
    116 /* globals: */
    117 jmp_buf jbuf;			/* timer crud */
    118 int jval = 0;			/* timer crud */
    119 int netfd = -1;
    120 int ofd = 0;			/* hexdump output fd */
    121 static char unknown[] = "(UNKNOWN)";
    122 static char p_tcp[] = "tcp";	/* for getservby* */
    123 static char p_udp[] = "udp";
    124 #ifdef HAVE_BIND
    125 extern int h_errno;
    126 /* stolen almost wholesale from bsd herror.c */
    127 static char * h_errs[] = {
    128   "Error 0",				/* but we *don't* use this */
    129   "Unknown host",			/* 1 HOST_NOT_FOUND */
    130   "Host name lookup failure",		/* 2 TRY_AGAIN */
    131   "Unknown server error",		/* 3 NO_RECOVERY */
    132   "No address associated with name",	/* 4 NO_ADDRESS */
    133 };
    134 #else
    135 int h_errno;			/* just so we *do* have it available */
    136 #endif /* HAVE_BIND */
    137 int gatesidx = 0;		/* LSRR hop count */
    138 int gatesptr = 4;		/* initial LSRR pointer, settable */
    139 USHORT Single = 1;		/* zero if scanning */
    140 unsigned int insaved = 0;	/* stdin-buffer size for multi-mode */
    141 unsigned int wrote_out = 0;	/* total stdout bytes */
    142 unsigned int wrote_net = 0;	/* total net bytes */
    143 static char wrote_txt[] = " sent %d, rcvd %d";
    144 static char hexnibs[20] = "0123456789abcdef  ";
    145 
    146 /* will malloc up the following globals: */
    147 struct timeval * timer1 = NULL;
    148 struct timeval * timer2 = NULL;
    149 SAI * lclend = NULL;		/* sockaddr_in structs */
    150 SAI * remend = NULL;
    151 HINF ** gates = NULL;		/* LSRR hop hostpoop */
    152 char * optbuf = NULL;		/* LSRR or sockopts */
    153 char * bigbuf_in;		/* data buffers */
    154 char * bigbuf_net;
    155 fd_set * ding1;			/* for select loop */
    156 fd_set * ding2;
    157 PINF * portpoop = NULL;		/* for getportpoop / getservby* */
    158 unsigned char * stage = NULL;	/* hexdump line buffer */
    159 
    160 /* global cmd flags: */
    161 USHORT o_alla = 0;
    162 unsigned int o_interval = 0;
    163 USHORT o_listen = 0;
    164 USHORT o_nflag = 0;
    165 USHORT o_wfile = 0;
    166 USHORT o_random = 0;
    167 USHORT o_udpmode = 0;
    168 USHORT o_verbose = 0;
    169 unsigned int o_wait = 0;
    170 USHORT o_zero = 0;
    171 /* o_tn in optional section */
    172 
    173 /* Debug macro: squirt whatever message and sleep a bit so we can see it go
    174    by.  need to call like Debug ((stuff)) [with no ; ] so macro args match!
    175    Beware: writes to stdOUT... */
    176 #ifdef DEBUG
    177 #define Debug(x) printf x; printf ("\n"); fflush (stdout); sleep (1);
    178 #else
    179 #define Debug(x)	/* nil... */
    180 #endif
    181 
    182 
    183 /* support routines -- the bulk of this thing.  Placed in such an order that
    184    we don't have to forward-declare anything: */
    185 
    186 /* holler :
    187    fake varargs -- need to do this way because we wind up calling through
    188    more levels of indirection than vanilla varargs can handle, and not all
    189    machines have vfprintf/vsyslog/whatever!  6 params oughta be enough. */
    190 void holler (str, p1, p2, p3, p4, p5, p6)
    191   char * str;
    192   char * p1, * p2, * p3, * p4, * p5, * p6;
    193 {
    194   if (o_verbose) {
    195     fprintf (stderr, str, p1, p2, p3, p4, p5, p6);
    196 #ifdef HAVE_BIND
    197     if (h_errno) {		/* if host-lookup variety of error ... */
    198       if (h_errno > 4)		/* oh no you don't, either */
    199 	fprintf (stderr, "preposterous h_errno: %d", h_errno);
    200       else
    201 	fprintf (stderr, "%s", h_errs[h_errno]);	/* handle it here */
    202       h_errno = 0;				/* and reset for next call */
    203     }
    204 #endif
    205     if (errno) {		/* this gives funny-looking messages, but */
    206       perror (" ");		/* it's more portable than sys_errlist[]... */
    207     } else			/* xxx: do something better?  */
    208       fprintf (stderr, "\n");
    209     fflush (stderr);
    210   }
    211 } /* holler */
    212 
    213 /* bail :
    214    error-exit handler, callable from anywhere */
    215 void bail (str, p1, p2, p3, p4, p5, p6)
    216   char * str;
    217   char * p1, * p2, * p3, * p4, * p5, * p6;
    218 {
    219   o_verbose = 1;
    220   holler (str, p1, p2, p3, p4, p5, p6);
    221   close (netfd);
    222   sleep (1);
    223   exit (1);
    224 } /* bail */
    225 
    226 /* catch :
    227    no-brainer interrupt handler */
    228 void catch ()
    229 {
    230   errno = 0;
    231   if (o_verbose > 1)		/* normally we don't care */
    232     bail (wrote_txt, wrote_net, wrote_out);
    233   bail (" punt!");
    234 }
    235 
    236 /* timeout and other signal handling cruft */
    237 void tmtravel ()
    238 {
    239   signal (SIGALRM, SIG_IGN);
    240   alarm (0);
    241   if (jval == 0)
    242     bail ("spurious timer interrupt!");
    243   longjmp (jbuf, jval);
    244 }
    245 
    246 /* arm :
    247    set the timer.  Zero secs arg means unarm */
    248 void arm (num, secs)
    249   unsigned int num;
    250   unsigned int secs;
    251 {
    252   if (secs == 0) {			/* reset */
    253     signal (SIGALRM, SIG_IGN);
    254     alarm (0);
    255     jval = 0;
    256   } else {				/* set */
    257     signal (SIGALRM, tmtravel);
    258     alarm (secs);
    259     jval = num;
    260   } /* if secs */
    261 } /* arm */
    262 
    263 /* Hmalloc :
    264    malloc up what I want, rounded up to *4, and pre-zeroed.  Either succeeds
    265    or bails out on its own, so that callers don't have to worry about it. */
    266 char * Hmalloc (size)
    267   unsigned int size;
    268 {
    269   unsigned int s = (size + 4) & 0xfffffffc;	/* 4GB?! */
    270   char * p = malloc (s);
    271   if (p != NULL)
    272     memset (p, 0, s);
    273   else
    274     bail ("Hmalloc %d failed", s);
    275   return (p);
    276 } /* Hmalloc */
    277 
    278 /* findline :
    279    find the next newline in a buffer; return inclusive size of that "line",
    280    or the entire buffer size, so the caller knows how much to then write().
    281    Not distinguishing \n vs \r\n for the nonce; it just works as is... */
    282 unsigned int findline (buf, siz)
    283   char * buf;
    284   unsigned int siz;
    285 {
    286   register char * p;
    287   register int x;
    288   if (! buf)			/* various sanity checks... */
    289     return (0);
    290   if (siz > BIGSIZ)
    291     return (0);
    292   x = siz;
    293   for (p = buf; x > 0; x--) {
    294     if (*p == '\n') {
    295       x = (int) (p - buf);
    296       x++;			/* 'sokay if it points just past the end! */
    297 Debug (("findline returning %d", x))
    298       return (x);
    299     }
    300     p++;
    301   } /* for */
    302 Debug (("findline returning whole thing: %d", siz))
    303   return (siz);
    304 } /* findline */
    305 
    306 /* comparehosts :
    307    cross-check the host_poop we have so far against new gethostby*() info,
    308    and holler about mismatches.  Perhaps gratuitous, but it can't hurt to
    309    point out when someone's DNS is fukt.  Returns 1 if mismatch, in case
    310    someone else wants to do something about it. */
    311 int comparehosts (poop, hp)
    312   HINF * poop;
    313   struct hostent * hp;
    314 {
    315   errno = 0;
    316   h_errno = 0;
    317 /* The DNS spec is officially case-insensitive, but for those times when you
    318    *really* wanna see any and all discrepancies, by all means define this. */
    319 #ifdef ANAL
    320   if (strcmp (poop->name, hp->h_name) != 0) {		/* case-sensitive */
    321 #else
    322   if (strcasecmp (poop->name, hp->h_name) != 0) {	/* normal */
    323 #endif
    324     holler ("DNS fwd/rev mismatch: %s != %s", poop->name, hp->h_name);
    325     return (1);
    326   }
    327   return (0);
    328 /* ... do we need to do anything over and above that?? */
    329 } /* comparehosts */
    330 
    331 /* gethostpoop :
    332    resolve a host 8 ways from sunday; return a new host_poop struct with its
    333    info.  The argument can be a name or [ascii] IP address; it will try its
    334    damndest to deal with it.  "numeric" governs whether we do any DNS at all,
    335    and we also check o_verbose for what's appropriate work to do. */
    336 HINF * gethostpoop (name, numeric)
    337   char * name;
    338   USHORT numeric;
    339 {
    340   struct hostent * hostent;
    341   struct in_addr iaddr;
    342   register HINF * poop = NULL;
    343   register int x;
    344 
    345 /* I really want to strangle the twit who dreamed up all these sockaddr and
    346    hostent abstractions, and then forced them all to be incompatible with
    347    each other so you *HAVE* to do all this ridiculous casting back and forth.
    348    If that wasn't bad enough, all the doc insists on referring to local ports
    349    and addresses as "names", which makes NO sense down at the bare metal.
    350 
    351    What an absolutely horrid paradigm, and to think of all the people who
    352    have been wasting significant amounts of time fighting with this stupid
    353    deliberate obfuscation over the last 10 years... then again, I like
    354    languages wherein a pointer is a pointer, what you put there is your own
    355    business, the compiler stays out of your face, and sheep are nervous.
    356    Maybe that's why my C code reads like assembler half the time... */
    357 
    358 /* If we want to see all the DNS stuff, do the following hair --
    359    if inet_addr, do reverse and forward with any warnings; otherwise try
    360    to do forward and reverse with any warnings.  In other words, as long
    361    as we're here, do a complete DNS check on these clowns.  Yes, it slows
    362    things down a bit for a first run, but once it's cached, who cares? */
    363 
    364   errno = 0;
    365   h_errno = 0;
    366   if (name)
    367     poop = (HINF *) Hmalloc (sizeof (HINF));
    368   if (! poop)
    369     bail ("gethostpoop fuxored");
    370   strcpy (poop->name, unknown);		/* preload it */
    371 /* see wzv:workarounds.c for dg/ux return-a-struct inet_addr lossage */
    372   iaddr.s_addr = inet_addr (name);
    373 
    374   if (iaddr.s_addr == INADDR_NONE) {	/* here's the great split: names... */
    375     if (numeric)
    376       bail ("Can't parse %s as an IP address", name);
    377     hostent = gethostbyname (name);
    378     if (! hostent)
    379 /* failure to look up a name is fatal, since we can't do anything with it */
    380       bail ("%s: forward host lookup failed: ", name);
    381     strncpy (poop->name, hostent->h_name, MAXHOSTNAMELEN - 2);
    382     for (x = 0; hostent->h_addr_list[x] && (x < 8); x++) {
    383       memcpy (&poop->iaddrs[x], hostent->h_addr_list[x], sizeof (IA));
    384       strncpy (poop->addrs[x], inet_ntoa (poop->iaddrs[x]),
    385 	sizeof (poop->addrs[0]));
    386     } /* for x -> addrs, part A */
    387     if (! o_verbose)			/* if we didn't want to see the */
    388       return (poop);			/* inverse stuff, we're done. */
    389 /* do inverse lookups in separate loop based on our collected forward addrs,
    390    since gethostby* tends to crap into the same buffer over and over */
    391     for (x = 0; poop->iaddrs[x].s_addr && (x < 8); x++) {
    392       hostent = gethostbyaddr ((char *)&poop->iaddrs[x],
    393 				sizeof (IA), AF_INET);
    394       if ((! hostent) || (! hostent-> h_name))
    395 	holler ("Warning: inverse host lookup failed for %s: ",
    396 	  poop->addrs[x]);
    397       else
    398 	(void) comparehosts (poop, hostent);
    399     } /* for x -> addrs, part B */
    400 
    401   } else {  /* not INADDR_NONE: numeric addresses... */
    402     memcpy (poop->iaddrs, &iaddr, sizeof (IA));
    403     strncpy (poop->addrs[0], inet_ntoa (iaddr), sizeof (poop->addrs));
    404     if (numeric)			/* if numeric-only, we're done */
    405       return (poop);
    406     if (! o_verbose)			/* likewise if we don't want */
    407       return (poop);			/* the full DNS hair */
    408     hostent = gethostbyaddr ((char *) &iaddr, sizeof (IA), AF_INET);
    409 /* numeric or not, failure to look up a PTR is *not* considered fatal */
    410     if (! hostent)
    411 	holler ("%s: inverse host lookup failed: ", name);
    412     else {
    413 	strncpy (poop->name, hostent->h_name, MAXHOSTNAMELEN - 2);
    414 	hostent = gethostbyname (poop->name);
    415 	if ((! hostent) || (! hostent->h_addr_list[0]))
    416 	  holler ("Warning: forward host lookup failed for %s: ",
    417 		poop->name);
    418 	else
    419 	  (void) comparehosts (poop, hostent);
    420     } /* if hostent */
    421   } /* INADDR_NONE Great Split */
    422 
    423 /* whatever-all went down previously, we should now have a host_poop struct
    424    with at least one IP address in it. */
    425   h_errno = 0;
    426   return (poop);
    427 } /* gethostpoop */
    428 
    429 /* getportpoop :
    430    Same general idea as gethostpoop -- look up a port in /etc/services, fill
    431    in global port_poop, but return the actual port *number*.  Pass ONE of:
    432 	pstring to resolve stuff like "23" or "exec";
    433 	pnum to reverse-resolve something that's already a number.
    434    If o_nflag is on, fill in what we can but skip the getservby??? stuff.
    435    Might as well have consistent behavior here, and it *is* faster. */
    436 USHORT getportpoop (pstring, pnum)
    437   char * pstring;
    438   unsigned int pnum;
    439 {
    440   struct servent * servent;
    441   register int x;
    442   register int y;
    443   char * whichp = p_tcp;
    444   if (o_udpmode)
    445     whichp = p_udp;
    446   portpoop->name[0] = '?';		/* fast preload */
    447   portpoop->name[1] = '\0';
    448 
    449 /* case 1: reverse-lookup of a number; placed first since this case is much
    450    more frequent if we're scanning */
    451   if (pnum) {
    452     if (pstring)			/* one or the other, pleeze */
    453       return (0);
    454     x = pnum;
    455     if (o_nflag)			/* go faster, skip getservbyblah */
    456       goto gp_finish;
    457     y = htons (x);			/* gotta do this -- see Fig.1 below */
    458     servent = getservbyport (y, whichp);
    459     if (servent) {
    460       y = ntohs (servent->s_port);
    461       if (x != y)			/* "never happen" */
    462 	holler ("Warning: port-bynum mismatch, %d != %d", x, y);
    463       strncpy (portpoop->name, servent->s_name, sizeof (portpoop->name));
    464     } /* if servent */
    465     goto gp_finish;
    466   } /* if pnum */
    467 
    468 /* case 2: resolve a string, but we still give preference to numbers instead
    469    of trying to resolve conflicts.  None of the entries in *my* extensive
    470    /etc/services begins with a digit, so this should "always work" unless
    471    you're at 3com and have some company-internal services defined... */
    472   if (pstring) {
    473     if (pnum)				/* one or the other, pleeze */
    474       return (0);
    475     x = atoi (pstring);
    476     if (x)
    477       return (getportpoop (NULL, x));	/* recurse for numeric-string-arg */
    478     if (o_nflag)			/* can't use names! */
    479       return (0);
    480     servent = getservbyname (pstring, whichp);
    481     if (servent) {
    482       strncpy (portpoop->name, servent->s_name, sizeof (portpoop->name));
    483       x = ntohs (servent->s_port);
    484       goto gp_finish;
    485     } /* if servent */
    486   } /* if pstring */
    487 
    488   return (0);				/* catches any problems so far */
    489 
    490 /* Obligatory netdb.h-inspired rant: servent.s_port is supposed to be an int.
    491    Despite this, we still have to treat it as a short when copying it around.
    492    Not only that, but we have to convert it *back* into net order for
    493    getservbyport to work.  Manpages generally aren't clear on all this, but
    494    there are plenty of examples in which it is just quietly done.  More BSD
    495    lossage... since everything getserv* ever deals with is local to our own
    496    host, why bother with all this network-order/host-order crap at all?!
    497    That should be saved for when we want to actually plug the port[s] into
    498    some real network calls -- and guess what, we have to *re*-convert at that
    499    point as well.  Fuckheads. */
    500 
    501 gp_finish:
    502 /* Fall here whether or not we have a valid servent at this point, with
    503    x containing our [host-order and therefore useful, dammit] port number */
    504   sprintf (portpoop->anum, "%d", x);	/* always load any numeric specs! */
    505   portpoop->num = (x & 0xffff);		/* ushort, remember... */
    506   return (portpoop->num);
    507 } /* getportpoop */
    508 
    509 /* nextport :
    510    Come up with the next port to try, be it random or whatever.  "block" is
    511    a ptr to randports array, whose bytes [so far] carry these meanings:
    512 	0	ignore
    513 	1	to be tested
    514 	2	tested [which is set as we find them here]
    515    returns a USHORT random port, or 0 if all the t-b-t ones are used up. */
    516 USHORT nextport (block)
    517   char * block;
    518 {
    519   register unsigned int x;
    520   register unsigned int y;
    521 
    522   y = 70000;			/* high safety count for rnd-tries */
    523   while (y > 0) {
    524     x = (RAND() & 0xffff);
    525     if (block[x] == 1) {	/* try to find a not-done one... */
    526       block[x] = 2;
    527       break;
    528     }
    529     x = 0;			/* bummer. */
    530     y--;
    531   } /* while y */
    532   if (x)
    533     return (x);
    534 
    535   y = 65535;			/* no random one, try linear downsearch */
    536   while (y > 0) {		/* if they're all used, we *must* be sure! */
    537     if (block[y] == 1) {
    538       block[y] = 2;
    539       break;
    540     }
    541     y--;
    542   } /* while y */
    543   if (y)
    544     return (y);			/* at least one left */
    545 
    546   return (0);			/* no more left! */
    547 } /* nextport */
    548 
    549 /* loadports :
    550    set "to be tested" indications in BLOCK, from LO to HI.  Almost too small
    551    to be a separate routine, but makes main() a little cleaner... */
    552 void loadports (block, lo, hi)
    553   char * block;
    554   USHORT lo;
    555   USHORT hi;
    556 {
    557   USHORT x;
    558 
    559   if (! block)
    560     bail ("loadports: no block?!");
    561   if ((! lo) || (! hi))
    562     bail ("loadports: bogus values %d, %d", lo, hi);
    563   x = hi;
    564   while (lo <= x) {
    565     block[x] = 1;
    566     x--;
    567   }
    568 } /* loadports */
    569 
    570 #ifdef GAPING_SECURITY_HOLE
    571 char * pr00gie = NULL;			/* global ptr to -e arg */
    572 
    573 /* doexec :
    574    fiddle all the file descriptors around, and hand off to another prog.  Sort
    575    of like a one-off "poor man's inetd".  This is the only section of code
    576    that would be security-critical, which is why it's ifdefed out by default.
    577    Use at your own hairy risk; if you leave shells lying around behind open
    578    listening ports you deserve to lose!! */
    579 doexec (fd)
    580   int fd;
    581 {
    582   register char * p;
    583 
    584   dup2 (fd, 0);				/* the precise order of fiddlage */
    585   close (fd);				/* is apparently crucial; this is */
    586   dup2 (0, 1);				/* swiped directly out of "inetd". */
    587   dup2 (0, 2);
    588   p = strrchr (pr00gie, '/');		/* shorter argv[0] */
    589   if (p)
    590     p++;
    591   else
    592     p = pr00gie;
    593 Debug (("gonna exec %s as %s...", pr00gie, p))
    594   execl (pr00gie, p, NULL);
    595   bail ("exec %s failed", pr00gie);	/* this gets sent out.  Hmm... */
    596 } /* doexec */
    597 #endif /* GAPING_SECURITY_HOLE */
    598 
    599 /* doconnect :
    600    do all the socket stuff, and return an fd for one of
    601 	an open outbound TCP connection
    602 	a UDP stub-socket thingie
    603    with appropriate socket options set up if we wanted source-routing, or
    604 	an unconnected TCP or UDP socket to listen on.
    605    Examines various global o_blah flags to figure out what-all to do. */
    606 int doconnect (rad, rp, lad, lp)
    607   IA * rad;
    608   USHORT rp;
    609   IA * lad;
    610   USHORT lp;
    611 {
    612   register int nnetfd;
    613   register int rr;
    614   int x, y;
    615   errno = 0;
    616 
    617 /* grab a socket; set opts */
    618 newskt:
    619   if (o_udpmode)
    620     nnetfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    621   else
    622     nnetfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
    623   if (nnetfd < 0)
    624     bail ("Can't get socket");
    625   if (nnetfd == 0)		/* if stdin was closed this might *be* 0, */
    626     goto newskt;		/* so grab another.  See text for why... */
    627   x = 1;
    628   rr = setsockopt (nnetfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x));
    629   if (rr == -1)
    630     holler ("nnetfd reuseaddr failed");		/* ??? */
    631 #ifdef SO_REUSEPORT	/* doesnt exist everywhere... */
    632   rr = setsockopt (nnetfd, SOL_SOCKET, SO_REUSEPORT, &x, sizeof (x));
    633   if (rr == -1)
    634     holler ("nnetfd reuseport failed");		/* ??? */
    635 #endif
    636 #if 0
    637 /* If you want to screw with RCVBUF/SNDBUF, do it here.  Liudvikas Bukys at
    638    Rochester sent this example, which would involve YET MORE options and is
    639    just archived here in case you want to mess with it.  o_xxxbuf are global
    640    integers set in main() getopt loop, and check for rr == 0 afterward. */
    641   rr = setsockopt(nnetfd, SOL_SOCKET, SO_RCVBUF, &o_rcvbuf, sizeof o_rcvbuf);
    642   rr = setsockopt(nnetfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf);
    643 #endif
    644 
    645   /* fill in all the right sockaddr crud */
    646     lclend->sin_family = AF_INET;
    647 
    648 /* fill in all the right sockaddr crud */
    649   lclend->sin_family = AF_INET;
    650   remend->sin_family = AF_INET;
    651 
    652 /* if lad/lp, do appropriate binding */
    653   if (lad)
    654     memcpy (&lclend->sin_addr.s_addr, lad, sizeof (IA));
    655   if (lp)
    656     lclend->sin_port = htons (lp);
    657   rr = 0;
    658   if (lad || lp) {
    659     x = (int) lp;
    660 /* try a few times for the local bind, a la ftp-data-port... */
    661     for (y = 4; y > 0; y--) {
    662       rr = bind (nnetfd, (SA *)lclend, sizeof (SA));
    663       if (rr == 0)
    664 	break;
    665       if (errno != EADDRINUSE)
    666 	break;
    667       else {
    668 	holler ("retrying local %s:%d", inet_ntoa (lclend->sin_addr), lp);
    669 	sleep (2);
    670 	errno = 0;			/* clear from sleep */
    671       } /* if EADDRINUSE */
    672     } /* for y counter */
    673   } /* if lad or lp */
    674   if (rr)
    675     bail ("Can't grab %s:%d with bind",
    676 	inet_ntoa(lclend->sin_addr), lp);
    677 
    678   if (o_listen)
    679     return (nnetfd);			/* thanks, that's all for today */
    680 
    681   memcpy (&remend->sin_addr.s_addr, rad, sizeof (IA));
    682   remend->sin_port = htons (rp);
    683 
    684 /* rough format of LSRR option and explanation of weirdness.
    685 Option comes after IP-hdr dest addr in packet, padded to *4, and ihl > 5.
    686 IHL is multiples of 4, i.e. real len = ip_hl << 2.
    687 	type 131	1	; 0x83: copied, option class 0, number 3
    688 	len		1	; of *whole* option!
    689 	pointer		1	; nxt-hop-addr; 1-relative, not 0-relative
    690 	addrlist...	var	; 4 bytes per hop-addr
    691 	pad-to-32	var	; ones, i.e. "NOP"
    692 
    693 If we want to route A -> B via hops C and D, we must add C, D, *and* B to the
    694 options list.  Why?  Because when we hand the kernel A -> B with list C, D, B
    695 the "send shuffle" inside the kernel changes it into A -> C with list D, B and
    696 the outbound packet gets sent to C.  If B wasn't also in the hops list, the
    697 final destination would have been lost at this point.
    698 
    699 When C gets the packet, it changes it to A -> D with list C', B where C' is
    700 the interface address that C used to forward the packet.  This "records" the
    701 route hop from B's point of view, i.e. which address points "toward" B.  This
    702 is to make B better able to return the packets.  The pointer gets bumped by 4,
    703 so that D does the right thing instead of trying to forward back to C.
    704 
    705 When B finally gets the packet, it sees that the pointer is at the end of the
    706 LSRR list and is thus "completed".  B will then try to use the packet instead
    707 of forwarding it, i.e. deliver it up to some application.
    708 
    709 Note that by moving the pointer yourself, you could send the traffic directly
    710 to B but have it return via your preconstructed source-route.  Playing with
    711 this and watching "tcpdump -v" is the best way to understand what's going on.
    712 
    713 Only works for TCP in BSD-flavor kernels.  UDP is a loss; udp_input calls
    714 stripoptions() early on, and the code to save the srcrt is notdef'ed.
    715 Linux is also still a loss at 1.3.x it looks like; the lsrr code is { }...
    716 */
    717 
    718 /* if any -g arguments were given, set up source-routing.  We hit this after
    719    the gates are all looked up and ready to rock, any -G pointer is set,
    720    and gatesidx is now the *number* of hops */
    721   if (gatesidx) {		/* if we wanted any srcrt hops ... */
    722 /* don't even bother compiling if we can't do IP options here! */
    723 #ifdef IP_OPTIONS
    724     if (! optbuf) {		/* and don't already *have* a srcrt set */
    725       char * opp;		/* then do all this setup hair */
    726       optbuf = Hmalloc (48);
    727       opp = optbuf;
    728       *opp++ = IPOPT_LSRR;					/* option */
    729       *opp++ = (char)
    730 	(((gatesidx + 1) * sizeof (IA)) + 3) & 0xff;		/* length */
    731       *opp++ = gatesptr;					/* pointer */
    732 /* opp now points at first hop addr -- insert the intermediate gateways */
    733       for ( x = 0; x < gatesidx; x++) {
    734 	memcpy (opp, gates[x]->iaddrs, sizeof (IA));
    735 	opp += sizeof (IA);
    736       }
    737 /* and tack the final destination on the end [needed!] */
    738       memcpy (opp, rad, sizeof (IA));
    739       opp += sizeof (IA);
    740       *opp = IPOPT_NOP;			/* alignment filler */
    741     } /* if empty optbuf */
    742 /* calculate length of whole option mess, which is (3 + [hops] + [final] + 1),
    743    and apply it [have to do this every time through, of course] */
    744     x = ((gatesidx + 1) * sizeof (IA)) + 4;
    745     rr = setsockopt (nnetfd, IPPROTO_IP, IP_OPTIONS, optbuf, x);
    746     if (rr == -1)
    747       bail ("srcrt setsockopt fuxored");
    748 #else /* IP_OPTIONS */
    749     holler ("Warning: source routing unavailable on this machine, ignoring");
    750 #endif /* IP_OPTIONS*/
    751   } /* if gatesidx */
    752 
    753 /* wrap connect inside a timer, and hit it */
    754   arm (1, o_wait);
    755   if (setjmp (jbuf) == 0) {
    756     rr = connect (nnetfd, (SA *)remend, sizeof (SA));
    757   } else {				/* setjmp: connect failed... */
    758     rr = -1;
    759     errno = ETIMEDOUT;			/* fake it */
    760   }
    761   arm (0, 0);
    762   if (rr == 0)
    763     return (nnetfd);
    764   close (nnetfd);			/* clean up junked socket FD!! */
    765   return (-1);
    766 } /* doconnect */
    767 
    768 /* dolisten :
    769    just like doconnect, and in fact calls a hunk of doconnect, but listens for
    770    incoming and returns an open connection *from* someplace.  If we were
    771    given host/port args, any connections from elsewhere are rejected.  This
    772    in conjunction with local-address binding should limit things nicely... */
    773 int dolisten (rad, rp, lad, lp)
    774   IA * rad;
    775   USHORT rp;
    776   IA * lad;
    777   USHORT lp;
    778 {
    779   register int nnetfd;
    780   register int rr;
    781   HINF * whozis = NULL;
    782   int x;
    783   char * cp;
    784   USHORT z;
    785   errno = 0;
    786 
    787 /* Pass everything off to doconnect, who in o_listen mode just gets a socket */
    788   nnetfd = doconnect (rad, rp, lad, lp);
    789   if (nnetfd <= 0)
    790     return (-1);
    791   if (o_udpmode) {			/* apparently UDP can listen ON */
    792     if (! lp)				/* "port 0",  but that's not useful */
    793       bail ("UDP listen needs -p arg");
    794   } else {
    795     rr = listen (nnetfd, 1);		/* gotta listen() before we can get */
    796     if (rr < 0)				/* our local random port.  sheesh. */
    797       bail ("local listen fuxored");
    798   }
    799 
    800 /* Various things that follow temporarily trash bigbuf_net, which might contain
    801    a copy of any recvfrom()ed packet, but we'll read() another copy later. */
    802 
    803 /* I can't believe I have to do all this to get my own goddamn bound address
    804    and port number.  It should just get filled in during bind() or something.
    805    All this is only useful if we didn't say -p for listening, since if we
    806    said -p we *know* what port we're listening on.  At any rate we won't bother
    807    with it all unless we wanted to see it, although listening quietly on a
    808    random unknown port is probably not very useful without "netstat". */
    809   if (o_verbose) {
    810     x = sizeof (SA);		/* how 'bout getsockNUM instead, pinheads?! */
    811     rr = getsockname (nnetfd, (SA *) lclend, &x);
    812     if (rr < 0)
    813       holler ("local getsockname failed");
    814     strcpy (bigbuf_net, "listening on [");	/* buffer reuse... */
    815     if (lclend->sin_addr.s_addr)
    816       strcat (bigbuf_net, inet_ntoa (lclend->sin_addr));
    817     else
    818       strcat (bigbuf_net, "any");
    819     strcat (bigbuf_net, "] %d ...");
    820     z = ntohs (lclend->sin_port);
    821     holler (bigbuf_net, z);
    822   } /* verbose -- whew!! */
    823 
    824 /* UDP is a speeeeecial case -- we have to do I/O *and* get the calling
    825    party's particulars all at once, listen() and accept() don't apply.
    826    At least in the BSD universe, however, recvfrom/PEEK is enough to tell
    827    us something came in, and we can set things up so straight read/write
    828    actually does work after all.  Yow.  YMMV on strange platforms!  */
    829   if (o_udpmode) {
    830     x = sizeof (SA);		/* retval for recvfrom */
    831     arm (2, o_wait);		/* might as well timeout this, too */
    832     if (setjmp (jbuf) == 0) {	/* do timeout for initial connect */
    833       rr = recvfrom		/* and here we block... */
    834 	(nnetfd, bigbuf_net, BIGSIZ, MSG_PEEK, (SA *) remend, &x);
    835 Debug (("dolisten/recvfrom ding, rr = %d, netbuf %s ", rr, bigbuf_net))
    836     } else
    837       goto dol_tmo;		/* timeout */
    838     arm (0, 0);
    839 /* I'm not completely clear on how this works -- BSD seems to make UDP
    840    just magically work in a connect()ed context, but we'll undoubtedly run
    841    into systems this deal doesn't work on.  For now, we apparently have to
    842    issue a connect() on our just-tickled socket so we can write() back.
    843    Again, why the fuck doesn't it just get filled in and taken care of?!
    844    This hack is anything but optimal.  Basically, if you want your listener
    845    to also be able to send data back, you need this connect() line, which
    846    also has the side effect that now anything from a different source or even a
    847    different port on the other end won't show up and will cause ICMP errors.
    848    I guess that's what they meant by "connect".
    849    Let's try to remember what the "U" is *really* for, eh? */
    850     rr = connect (nnetfd, (SA *)remend, sizeof (SA));
    851     goto whoisit;
    852   } /* o_udpmode */
    853 
    854 /* fall here for TCP */
    855   x = sizeof (SA);		/* retval for accept */
    856   arm (2, o_wait);		/* wrap this in a timer, too; 0 = forever */
    857   if (setjmp (jbuf) == 0) {
    858     rr = accept (nnetfd, (SA *)remend, &x);
    859   } else
    860     goto dol_tmo;		/* timeout */
    861   arm (0, 0);
    862   close (nnetfd);		/* dump the old socket */
    863   nnetfd = rr;			/* here's our new one */
    864 
    865 whoisit:
    866   if (rr < 0)
    867     goto dol_err;		/* bail out if any errors so far */
    868 
    869 /* If we can, look for any IP options.  Useful for testing the receiving end of
    870    such things, and is a good exercise in dealing with it.  We do this before
    871    the connect message, to ensure that the connect msg is uniformly the LAST
    872    thing to emerge after all the intervening crud.  Doesn't work for UDP on
    873    any machines I've tested, but feel free to surprise me. */
    874 #ifdef IP_OPTIONS
    875   if (! o_verbose)			/* if we wont see it, we dont care */
    876     goto dol_noop;
    877   optbuf = Hmalloc (40);
    878   x = 40;
    879   rr = getsockopt (nnetfd, IPPROTO_IP, IP_OPTIONS, optbuf, &x);
    880   if (rr < 0)
    881     holler ("getsockopt failed");
    882 Debug (("ipoptions ret len %d", x))
    883   if (x) {				/* we've got options, lessee em... */
    884     unsigned char * q = (unsigned char *) optbuf;
    885     char * p = bigbuf_net;		/* local variables, yuk! */
    886     char * pp = &bigbuf_net[128];	/* get random space farther out... */
    887     memset (bigbuf_net, 0, 256);	/* clear it all first */
    888     while (x > 0) {
    889 	sprintf (pp, "%2.2x ", *q);	/* clumsy, but works: turn into hex */
    890 	strcat (p, pp);			/* and build the final string */
    891 	q++; p++;
    892 	x--;
    893     }
    894     holler ("IP options: %s", bigbuf_net);
    895   } /* if x, i.e. any options */
    896 dol_noop:
    897 #endif /* IP_OPTIONS */
    898 
    899 /* find out what address the connection was *to* on our end, in case we're
    900    doing a listen-on-any on a multihomed machine.  This allows one to
    901    offer different services via different alias addresses, such as the
    902    "virtual web site" hack. */
    903   memset (bigbuf_net, 0, 64);
    904   cp = &bigbuf_net[32];
    905   x = sizeof (SA);
    906   rr = getsockname (nnetfd, (SA *) lclend, &x);
    907   if (rr < 0)
    908     holler ("post-rcv getsockname failed");
    909   strcpy (cp, inet_ntoa (lclend->sin_addr));
    910 
    911 /* now check out who it is.  We don't care about mismatched DNS names here,
    912    but any ADDR and PORT we specified had better fucking well match the caller.
    913    Converting from addr to inet_ntoa and back again is a bit of a kludge, but
    914    gethostpoop wants a string and there's much gnarlier code out there already,
    915    so I don't feel bad.
    916    The *real* question is why BFD sockets wasn't designed to allow listens for
    917    connections *from* specific hosts/ports, instead of requiring the caller to
    918    accept the connection and then reject undesireable ones by closing.  In
    919    other words, we need a TCP MSG_PEEK. */
    920   z = ntohs (remend->sin_port);
    921   strcpy (bigbuf_net, inet_ntoa (remend->sin_addr));
    922   whozis = gethostpoop (bigbuf_net, o_nflag);
    923   errno = 0;
    924   x = 0;				/* use as a flag... */
    925   if (rad)	/* xxx: fix to go down the *list* if we have one? */
    926     if (memcmp (rad, whozis->iaddrs, sizeof (SA)))
    927       x = 1;
    928   if (rp)
    929     if (z != rp)
    930       x = 1;
    931   if (x)					/* guilty! */
    932     bail ("invalid connection to [%s] from %s [%s] %d",
    933 	cp, whozis->name, whozis->addrs[0], z);
    934   holler ("connect to [%s] from %s [%s] %d",		/* oh, you're okay.. */
    935 	cp, whozis->name, whozis->addrs[0], z);
    936   return (nnetfd);				/* open! */
    937 
    938 dol_tmo:
    939   errno = ETIMEDOUT;			/* fake it */
    940 dol_err:
    941   close (nnetfd);
    942   return (-1);
    943 } /* dolisten */
    944 
    945 /* udptest :
    946    fire a couple of packets at a UDP target port, just to see if it's really
    947    there.  On BSD kernels, ICMP host/port-unreachable errors get delivered to
    948    our socket as ECONNREFUSED write errors.  On SV kernels, we lose; we'll have
    949    to collect and analyze raw ICMP ourselves a la satan's probe_udp_ports
    950    backend.  Guess where one could swipe the appropriate code from...
    951 
    952    Use the time delay between writes if given, otherwise use the "tcp ping"
    953    trick for getting the RTT.  [I got that idea from pluvius, and warped it.]
    954    Return either the original fd, or clean up and return -1. */
    955 int udptest (fd, where)
    956   int fd;
    957   IA * where;
    958 {
    959   register int rr;
    960 
    961   rr = write (fd, bigbuf_in, 1);
    962   if (rr != 1)
    963     holler ("udptest first write failed?! errno %d", errno);
    964   if (o_wait)
    965     sleep (o_wait);
    966   else {
    967 /* use the tcp-ping trick: try connecting to a normally refused port, which
    968    causes us to block for the time that SYN gets there and RST gets back.
    969    Not completely reliable, but it *does* mostly work. */
    970     o_udpmode = 0;			/* so doconnect does TCP this time */
    971 /* Set a temporary connect timeout, so packet filtration doesnt cause
    972    us to hang forever, and hit it */
    973     o_wait = 5;				/* enough that we'll notice?? */
    974     rr = doconnect (where, SLEAZE_PORT, 0, 0);
    975     if (rr > 0)
    976       close (rr);			/* in case it *did* open */
    977     o_wait = 0;				/* reset it */
    978     o_udpmode++;			/* we *are* still doing UDP, right? */
    979   } /* if o_wait */
    980   errno = 0;				/* clear from sleep */
    981   rr = write (fd, bigbuf_in, 1);
    982   if (rr == 1)				/* if write error, no UDP listener */
    983     return (fd);
    984   close (fd);				/* use it or lose it! */
    985   return (-1);
    986 } /* udptest */
    987 
    988 /* oprint :
    989    Hexdump bytes shoveled either way to a running logfile, in the format:
    990 D offset       -  - - - --- 16 bytes --- - - -  -     # .... ascii .....
    991    where "which" sets the direction indicator, D:
    992 	0 -- sent to network, or ">"
    993 	1 -- rcvd and printed to stdout, or "<"
    994    and "buf" and "n" are data-block and length.  If the current block generates
    995    a partial line, so be it; we *want* that lockstep indication of who sent
    996    what when.  Adapted from dgaudet's original example -- but must be ripping
    997    *fast*, since we don't want to be too disk-bound... */
    998 void oprint (which, buf, n)
    999   int which;
   1000   char * buf;
   1001   int n;
   1002 {
   1003   int bc;			/* in buffer count */
   1004   int obc;			/* current "global" offset */
   1005   int soc;			/* stage write count */
   1006   register unsigned char * p;	/* main buf ptr; m.b. unsigned here */
   1007   register unsigned char * op;	/* out hexdump ptr */
   1008   register unsigned char * a;	/* out asc-dump ptr */
   1009   register int x;
   1010   register unsigned int y;
   1011 
   1012   if (! ofd)
   1013     bail ("oprint called with no open fd?!");
   1014   if (n == 0)
   1015     return;
   1016 
   1017   op = stage;
   1018   if (which) {
   1019     *op = '<';
   1020     obc = wrote_out;		/* use the globals! */
   1021   } else {
   1022     *op = '>';
   1023     obc = wrote_net;
   1024   }
   1025   op++;				/* preload "direction" */
   1026   *op = ' ';
   1027   p = (unsigned char *) buf;
   1028   bc = n;
   1029   stage[59] = '#';		/* preload separator */
   1030   stage[60] = ' ';
   1031 
   1032   while (bc) {			/* for chunk-o-data ... */
   1033     x = 16;
   1034     soc = 78;			/* len of whole formatted line */
   1035     if (bc < x) {
   1036       soc = soc - 16 + bc;	/* fiddle for however much is left */
   1037       x = (bc * 3) + 11;	/* 2 digits + space per, after D & offset */
   1038       op = &stage[x];
   1039       x = 16 - bc;
   1040       while (x) {
   1041 	*op++ = ' ';		/* preload filler spaces */
   1042 	*op++ = ' ';
   1043 	*op++ = ' ';
   1044 	x--;
   1045       }
   1046       x = bc;			/* re-fix current linecount */
   1047     } /* if bc < x */
   1048 
   1049     bc -= x;			/* fix wrt current line size */
   1050     sprintf (&stage[2], "%8.8x ", obc);		/* xxx: still slow? */
   1051     obc += x;			/* fix current offset */
   1052     op = &stage[11];		/* where hex starts */
   1053     a = &stage[61];		/* where ascii starts */
   1054 
   1055     while (x) {			/* for line of dump, however long ... */
   1056       y = (int)(*p >> 4);	/* hi half */
   1057       *op = hexnibs[y];
   1058       op++;
   1059       y = (int)(*p & 0x0f);	/* lo half */
   1060       *op = hexnibs[y];
   1061       op++;
   1062       *op = ' ';
   1063       op++;
   1064       if ((*p > 31) && (*p < 127))
   1065 	*a = *p;		/* printing */
   1066       else
   1067 	*a = '.';		/* nonprinting, loose def */
   1068       a++;
   1069       p++;
   1070       x--;
   1071     } /* while x */
   1072     *a = '\n';			/* finish the line */
   1073     x = write (ofd, stage, soc);
   1074     if (x < 0)
   1075       bail ("ofd write err");
   1076   } /* while bc */
   1077 } /* oprint */
   1078 
   1079 #ifdef TELNET
   1080 USHORT o_tn = 0;		/* global -t option */
   1081 
   1082 /* atelnet :
   1083    Answer anything that looks like telnet negotiation with don't/won't.
   1084    This doesn't modify any data buffers, update the global output count,
   1085    or show up in a hexdump -- it just shits into the outgoing stream.
   1086    Idea and codebase from Mudge (at) l0pht.com. */
   1087 void atelnet (buf, size)
   1088   unsigned char * buf;		/* has to be unsigned here! */
   1089   unsigned int size;
   1090 {
   1091   static unsigned char obuf [4];  /* tiny thing to build responses into */
   1092   register int x;
   1093   register unsigned char y;
   1094   register unsigned char * p;
   1095 
   1096   y = 0;
   1097   p = buf;
   1098   x = size;
   1099   while (x > 0) {
   1100     if (*p != 255)			/* IAC? */
   1101       goto notiac;
   1102     obuf[0] = 255;
   1103     p++; x--;
   1104     if ((*p == 251) || (*p == 252))	/* WILL or WONT */
   1105       y = 254;				/* -> DONT */
   1106     if ((*p == 253) || (*p == 254))	/* DO or DONT */
   1107       y = 252;				/* -> WONT */
   1108     if (y) {
   1109       obuf[1] = y;
   1110       p++; x--;
   1111       obuf[2] = *p;			/* copy actual option byte */
   1112       (void) write (netfd, obuf, 3);
   1113 /* if one wanted to bump wrote_net or do a hexdump line, here's the place */
   1114       y = 0;
   1115     } /* if y */
   1116 notiac:
   1117     p++; x--;
   1118   } /* while x */
   1119 } /* atelnet */
   1120 #endif /* TELNET */
   1121 
   1122 /* readwrite :
   1123    handle stdin/stdout/network I/O.  Bwahaha!! -- the select loop from hell.
   1124    In this instance, return what might become our exit status. */
   1125 int readwrite (fd)
   1126   int fd;
   1127 {
   1128   register int rr;
   1129   register char * zp;		/* stdin buf ptr */
   1130   register char * np;		/* net-in buf ptr */
   1131   unsigned int rzleft;
   1132   unsigned int rnleft;
   1133   USHORT netretry;		/* net-read retry counter */
   1134   USHORT wretry;		/* net-write sanity counter */
   1135   USHORT wfirst;		/* one-shot flag to skip first net read */
   1136 
   1137 /* if you don't have all this FD_* macro hair in sys/types.h, you'll have to
   1138    either find it or do your own bit-bashing: *ding1 |= (1 << fd), etc... */
   1139   if (fd > FD_SETSIZE) {
   1140     holler ("Preposterous fd value %d", fd);
   1141     return (1);
   1142   }
   1143   FD_SET (fd, ding1);		/* global: the net is open */
   1144   netretry = 2;
   1145   wfirst = 0;
   1146   rzleft = rnleft = 0;
   1147   if (insaved) {
   1148     rzleft = insaved;		/* preload multi-mode fakeouts */
   1149     zp = bigbuf_in;
   1150     wfirst = 1;
   1151     if (Single)			/* if not scanning, this is a one-off first */
   1152       insaved = 0;		/* buffer left over from argv construction, */
   1153     else {
   1154       FD_CLR (0, ding1);	/* OR we've already got our repeat chunk, */
   1155       close (0);		/* so we won't need any more stdin */
   1156     } /* Single */
   1157   } /* insaved */
   1158   if (o_interval)
   1159     sleep (o_interval);		/* pause *before* sending stuff, too */
   1160   errno = 0;			/* clear from sleep, close, whatever */
   1161 
   1162 /* and now the big ol' select shoveling loop ... */
   1163   while (FD_ISSET (fd, ding1)) {	/* i.e. till the *net* closes! */
   1164     wretry = 8200;			/* more than we'll ever hafta write */
   1165     if (wfirst) {			/* any saved stdin buffer? */
   1166       wfirst = 0;			/* clear flag for the duration */
   1167       goto shovel;			/* and go handle it first */
   1168     }
   1169     *ding2 = *ding1;			/* FD_COPY ain't portable... */
   1170 /* some systems, notably linux, crap into their select timers on return, so
   1171    we create a expendable copy and give *that* to select.  *Fuck* me ... */
   1172     if (timer1)
   1173       memcpy (timer2, timer1, sizeof (struct timeval));
   1174     rr = select (16, ding2, 0, 0, timer2);	/* here it is, kiddies */
   1175     if (rr < 0) {
   1176 	if (errno != EINTR) {		/* might have gotten ^Zed, etc ?*/
   1177 	  holler ("select fuxored");
   1178 	  close (fd);
   1179 	  return (1);
   1180 	}
   1181     } /* select fuckup */
   1182 /* if we have a timeout AND stdin is closed AND we haven't heard anything
   1183    from the net during that time, assume it's dead and close it too. */
   1184     if (rr == 0) {
   1185 	if (! FD_ISSET (0, ding1))
   1186 	  netretry--;			/* we actually try a coupla times. */
   1187 	if (! netretry) {
   1188 	  if (o_verbose > 1)		/* normally we don't care */
   1189 	    holler ("net timeout");
   1190 	  close (fd);
   1191 	  return (0);			/* not an error! */
   1192 	}
   1193     } /* select timeout */
   1194 /* xxx: should we check the exception fds too?  The read fds seem to give
   1195    us the right info, and none of the examples I found bothered. */
   1196 
   1197 /* Ding!!  Something arrived, go check all the incoming hoppers, net first */
   1198     if (FD_ISSET (fd, ding2)) {		/* net: ding! */
   1199 	rr = read (fd, bigbuf_net, BIGSIZ);
   1200 	if (rr <= 0) {
   1201 	  FD_CLR (fd, ding1);		/* net closed, we'll finish up... */
   1202 	  rzleft = 0;			/* can't write anymore: broken pipe */
   1203 	} else {
   1204 	  rnleft = rr;
   1205 	  np = bigbuf_net;
   1206 #ifdef TELNET
   1207 	  if (o_tn)
   1208 	    atelnet (np, rr);		/* fake out telnet stuff */
   1209 #endif /* TELNET */
   1210 	} /* if rr */
   1211 Debug (("got %d from the net, errno %d", rr, errno))
   1212     } /* net:ding */
   1213 
   1214 /* if we're in "slowly" mode there's probably still stuff in the stdin
   1215    buffer, so don't read unless we really need MORE INPUT!  MORE INPUT! */
   1216     if (rzleft)
   1217 	goto shovel;
   1218 
   1219 /* okay, suck more stdin */
   1220     if (FD_ISSET (0, ding2)) {		/* stdin: ding! */
   1221 	rr = read (0, bigbuf_in, BIGSIZ);
   1222 /* Considered making reads here smaller for UDP mode, but 8192-byte
   1223    mobygrams are kinda fun and exercise the reassembler. */
   1224 	if (rr <= 0) {			/* at end, or fukt, or ... */
   1225 	  FD_CLR (0, ding1);		/* disable and close stdin */
   1226 	  close (0);
   1227 	} else {
   1228 	  rzleft = rr;
   1229 	  zp = bigbuf_in;
   1230 /* special case for multi-mode -- we'll want to send this one buffer to every
   1231    open TCP port or every UDP attempt, so save its size and clean up stdin */
   1232 	  if (! Single) {		/* we might be scanning... */
   1233 	    insaved = rr;		/* save len */
   1234 	    FD_CLR (0, ding1);		/* disable further junk from stdin */
   1235 	    close (0);			/* really, I mean it */
   1236 	  } /* Single */
   1237 	} /* if rr/read */
   1238     } /* stdin:ding */
   1239 
   1240 shovel:
   1241 /* now that we've dingdonged all our thingdings, send off the results.
   1242    Geez, why does this look an awful lot like the big loop in "rsh"? ...
   1243    not sure if the order of this matters, but write net -> stdout first. */
   1244 
   1245 /* sanity check.  Works because they're both unsigned... */
   1246     if ((rzleft > 8200) || (rnleft > 8200)) {
   1247 	holler ("Bogus buffers: %d, %d", rzleft, rnleft);
   1248 	rzleft = rnleft = 0;
   1249     }
   1250 /* net write retries sometimes happen on UDP connections */
   1251     if (! wretry) {			/* is something hung? */
   1252 	holler ("too many output retries");
   1253 	return (1);
   1254     }
   1255     if (rnleft) {
   1256 	rr = write (1, np, rnleft);
   1257 	if (rr > 0) {
   1258 	  if (o_wfile)
   1259 	    oprint (1, np, rr);		/* log the stdout */
   1260 	  np += rr;			/* fix up ptrs and whatnot */
   1261 	  rnleft -= rr;			/* will get sanity-checked above */
   1262 	  wrote_out += rr;		/* global count */
   1263 	}
   1264 Debug (("wrote %d to stdout, errno %d", rr, errno))
   1265     } /* rnleft */
   1266     if (rzleft) {
   1267 	if (o_interval)			/* in "slowly" mode ?? */
   1268 	  rr = findline (zp, rzleft);
   1269 	else
   1270 	  rr = rzleft;
   1271 	rr = write (fd, zp, rr);	/* one line, or the whole buffer */
   1272 	if (rr > 0) {
   1273 	  if (o_wfile)
   1274 	    oprint (0, zp, rr);		/* log what got sent */
   1275 	  zp += rr;
   1276 	  rzleft -= rr;
   1277 	  wrote_net += rr;		/* global count */
   1278 	}
   1279 Debug (("wrote %d to net, errno %d", rr, errno))
   1280     } /* rzleft */
   1281     if (o_interval) {			/* cycle between slow lines, or ... */
   1282 	sleep (o_interval);
   1283 	errno = 0;			/* clear from sleep */
   1284 	continue;			/* ...with hairy select loop... */
   1285     }
   1286     if ((rzleft) || (rnleft)) {		/* shovel that shit till they ain't */
   1287 	wretry--;			/* none left, and get another load */
   1288 	goto shovel;
   1289     }
   1290   } /* while ding1:netfd is open */
   1291 
   1292 /* XXX: maybe want a more graceful shutdown() here, or screw around with
   1293    linger times??  I suspect that I don't need to since I'm always doing
   1294    blocking reads and writes and my own manual "last ditch" efforts to read
   1295    the net again after a timeout.  I haven't seen any screwups yet, but it's
   1296    not like my test network is particularly busy... */
   1297   close (fd);
   1298   return (0);
   1299 } /* readwrite */
   1300 
   1301 /* main :
   1302    now we pull it all together... */
   1303 int main (argc, argv)
   1304   int argc;
   1305   char ** argv;
   1306 {
   1307 #ifndef HAVE_GETOPT
   1308   extern char * optarg;
   1309   extern int optind, optopt;
   1310 #endif
   1311   register int x;
   1312   register char *cp;
   1313   HINF * gp;
   1314   HINF * whereto = NULL;
   1315   HINF * wherefrom = NULL;
   1316   IA * ouraddr = NULL;
   1317   IA * themaddr = NULL;
   1318   USHORT o_lport = 0;
   1319   USHORT ourport = 0;
   1320   USHORT loport = 0;		/* for scanning stuff */
   1321   USHORT hiport = 0;
   1322   USHORT curport = 0;
   1323   char * randports = NULL;
   1324 
   1325 #ifdef HAVE_BIND
   1326 /* can *you* say "cc -yaddayadda netcat.c -lresolv -l44bsd" on SunLOSs? */
   1327   res_init();
   1328 #endif
   1329 /* I was in this barbershop quartet in Skokie IL ... */
   1330 /* round up the usual suspects, i.e. malloc up all the stuff we need */
   1331   lclend = (SAI *) Hmalloc (sizeof (SA));
   1332   remend = (SAI *) Hmalloc (sizeof (SA));
   1333   bigbuf_in = Hmalloc (BIGSIZ);
   1334   bigbuf_net = Hmalloc (BIGSIZ);
   1335   ding1 = (fd_set *) Hmalloc (sizeof (fd_set));
   1336   ding2 = (fd_set *) Hmalloc (sizeof (fd_set));
   1337   portpoop = (PINF *) Hmalloc (sizeof (PINF));
   1338 
   1339   errno = 0;
   1340   gatesptr = 4;
   1341   h_errno = 0;
   1342 
   1343 /* catch a signal or two for cleanup */
   1344   signal (SIGINT, catch);
   1345   signal (SIGQUIT, catch);
   1346   signal (SIGTERM, catch);
   1347 /* and suppress others... */
   1348 #ifdef SIGURG
   1349   signal (SIGURG, SIG_IGN);
   1350 #endif
   1351 #ifdef SIGPIPE
   1352   signal (SIGPIPE, SIG_IGN);		/* important! */
   1353 #endif
   1354 
   1355 /* if no args given at all, get 'em from stdin, construct an argv, and hand
   1356    anything left over to readwrite(). */
   1357   if (argc == 1) {
   1358     cp = argv[0];
   1359     argv = (char **) Hmalloc (128 * sizeof (char *));	/* XXX: 128? */
   1360     argv[0] = cp;			/* leave old prog name intact */
   1361     cp = Hmalloc (BIGSIZ);
   1362     argv[1] = cp;			/* head of new arg block */
   1363     fprintf (stderr, "Cmd line: ");
   1364     fflush (stderr);		/* I dont care if it's unbuffered or not! */
   1365     insaved = read (0, cp, BIGSIZ);	/* we're gonna fake fgets() here */
   1366     if (insaved <= 0)
   1367       bail ("wrong");
   1368     x = findline (cp, insaved);
   1369     if (x)
   1370       insaved -= x;		/* remaining chunk size to be sent */
   1371     if (insaved)		/* which might be zero... */
   1372       memcpy (bigbuf_in, &cp[x], insaved);
   1373     cp = strchr (argv[1], '\n');
   1374     if (cp)
   1375       *cp = '\0';
   1376     cp = strchr (argv[1], '\r');	/* look for ^M too */
   1377     if (cp)
   1378       *cp = '\0';
   1379 
   1380 /* find and stash pointers to remaining new "args" */
   1381     cp = argv[1];
   1382     cp++;				/* skip past first char */
   1383     x = 2;				/* we know argv 0 and 1 already */
   1384     for (; *cp != '\0'; cp++) {
   1385       if (*cp == ' ') {
   1386 	*cp = '\0';			/* smash all spaces */
   1387 	continue;
   1388       } else {
   1389 	if (*(cp-1) == '\0') {
   1390 	  argv[x] = cp;
   1391 	  x++;
   1392 	}
   1393       } /* if space */
   1394     } /* for cp */
   1395     argc = x;
   1396   } /* if no args given */
   1397 
   1398 /* If your shitbox doesn't have getopt, step into the nineties already. */
   1399 /* optarg, optind = next-argv-component [i.e. flag arg]; optopt = last-char */
   1400   while ((x = getopt (argc, argv, "ae:g:G:hi:lno:p:rs:tuvw:z")) != EOF) {
   1401 /* Debug (("in go: x now %c, optarg %x optind %d", x, optarg, optind)) */
   1402     switch (x) {
   1403       case 'a':
   1404 	bail ("all-A-records NIY");
   1405 	o_alla++; break;
   1406 #ifdef GAPING_SECURITY_HOLE
   1407       case 'e':				/* prog to exec */
   1408 	pr00gie = optarg;
   1409 	break;
   1410 #endif
   1411       case 'G':				/* srcrt gateways pointer val */
   1412 	x = atoi (optarg);
   1413 	if ((x) && (x == (x & 0x1c)))	/* mask off bits of fukt values */
   1414 	  gatesptr = x;
   1415 	else
   1416 	  bail ("invalid hop pointer %d, must be multiple of 4 <= 28", x);
   1417 	break;
   1418       case 'g':				/* srcroute hop[s] */
   1419 	if (gatesidx > 8)
   1420 	  bail ("too many -g hops");
   1421 	if (gates == NULL)		/* eat this, Billy-boy */
   1422 	  gates = (HINF **) Hmalloc (sizeof (HINF *) * 10);
   1423 	gp = gethostpoop (optarg, o_nflag);
   1424 	if (gp)
   1425 	  gates[gatesidx] = gp;
   1426 	gatesidx++;
   1427 	break;
   1428       case 'h':
   1429 	errno = 0;
   1430 #ifdef HAVE_HELP
   1431 	helpme();			/* exits by itself */
   1432 #else
   1433 	bail ("no help available, dork -- RTFS");
   1434 #endif
   1435       case 'i':				/* line-interval time */
   1436 	o_interval = atoi (optarg) & 0xffff;
   1437 	if (! o_interval)
   1438 	  bail ("invalid interval time %s", optarg);
   1439 	break;
   1440       case 'l':				/* listen mode */
   1441 	o_listen++; break;
   1442       case 'n':				/* numeric-only, no DNS lookups */
   1443 	o_nflag++; break;
   1444       case 'o':				/* hexdump log */
   1445 	stage = (unsigned char *) optarg;
   1446 	o_wfile++; break;
   1447       case 'p':				/* local source port */
   1448 	o_lport = getportpoop (optarg, 0);
   1449 	if (o_lport == 0)
   1450 	  bail ("invalid local port %s", optarg);
   1451 	break;
   1452       case 'r':				/* randomize various things */
   1453 	o_random++; break;
   1454       case 's':				/* local source address */
   1455 /* do a full lookup [since everything else goes through the same mill],
   1456    unless -n was previously specified.  In fact, careful placement of -n can
   1457    be useful, so we'll still pass o_nflag here instead of forcing numeric.  */
   1458 	wherefrom = gethostpoop (optarg, o_nflag);
   1459 	ouraddr = &wherefrom->iaddrs[0];
   1460 	break;
   1461 #ifdef TELNET
   1462       case 't':				/* do telnet fakeout */
   1463 	o_tn++; break;
   1464 #endif /* TELNET */
   1465       case 'u':				/* use UDP */
   1466 	o_udpmode++; break;
   1467       case 'v':				/* verbose */
   1468 	o_verbose++; break;
   1469       case 'w':				/* wait time */
   1470 	o_wait = atoi (optarg);
   1471 	if (o_wait <= 0)
   1472 	  bail ("invalid wait-time %s", optarg);
   1473 	timer1 = (struct timeval *) Hmalloc (sizeof (struct timeval));
   1474 	timer2 = (struct timeval *) Hmalloc (sizeof (struct timeval));
   1475 	timer1->tv_sec = o_wait;	/* we need two.  see readwrite()... */
   1476 	break;
   1477       case 'z':				/* little or no data xfer */
   1478 	o_zero++;
   1479 	break;
   1480       default:
   1481 	errno = 0;
   1482 	bail ("nc -h for help");
   1483     } /* switch x */
   1484   } /* while getopt */
   1485 
   1486 /* other misc initialization */
   1487 Debug (("fd_set size %d", sizeof (*ding1)))	/* how big *is* it? */
   1488   FD_SET (0, ding1);			/* stdin *is* initially open */
   1489   if (o_random) {
   1490     SRAND (time (0));
   1491     randports = Hmalloc (65536);	/* big flag array for ports */
   1492   }
   1493 #ifdef GAPING_SECURITY_HOLE
   1494   if (pr00gie) {
   1495     close (0);				/* won't need stdin */
   1496     o_wfile = 0;			/* -o with -e is meaningless! */
   1497     ofd = 0;
   1498   }
   1499 #endif /* G_S_H */
   1500   if (o_wfile) {
   1501     ofd = open (stage, O_WRONLY | O_CREAT | O_TRUNC, 0664);
   1502     if (ofd <= 0)			/* must be > extant 0/1/2 */
   1503       bail ("can't open %s", stage);
   1504     stage = (unsigned char *) Hmalloc (100);
   1505   }
   1506 
   1507 /* optind is now index of first non -x arg */
   1508 Debug (("after go: x now %c, optarg %x optind %d", x, optarg, optind))
   1509 /* Debug (("optind up to %d at host-arg %s", optind, argv[optind])) */
   1510 /* gonna only use first addr of host-list, like our IQ was normal; if you wanna
   1511    get fancy with addresses, look up the list yourself and plug 'em in for now.
   1512    unless we finally implement -a, that is. */
   1513   if (argv[optind])
   1514     whereto = gethostpoop (argv[optind], o_nflag);
   1515   if (whereto && whereto->iaddrs)
   1516     themaddr = &whereto->iaddrs[0];
   1517   if (themaddr)
   1518     optind++;				/* skip past valid host lookup */
   1519   errno = 0;
   1520   h_errno = 0;
   1521 
   1522 /* Handle listen mode here, and exit afterward.  Only does one connect;
   1523    this is arguably the right thing to do.  A "persistent listen-and-fork"
   1524    mode a la inetd has been thought about, but not implemented.  A tiny
   1525    wrapper script can handle such things... */
   1526   if (o_listen) {
   1527     curport = 0;			/* rem port *can* be zero here... */
   1528     if (argv[optind]) {			/* any rem-port-arg? */
   1529       curport = getportpoop (argv[optind], 0);
   1530       if (curport == 0)			/* if given, demand correctness */
   1531 	bail ("invalid port %s", argv[optind]);
   1532     } /* if port-arg */
   1533     netfd = dolisten (themaddr, curport, ouraddr, o_lport);
   1534 /* dolisten does its own connect reporting, so we don't holler anything here */
   1535     if (netfd > 0) {
   1536 #ifdef GAPING_SECURITY_HOLE
   1537       if (pr00gie)			/* -e given? */
   1538 	doexec (netfd);
   1539 #endif /* GAPING_SECURITY_HOLE */
   1540       x = readwrite (netfd);		/* it even works with UDP! */
   1541       if (o_verbose > 1)		/* normally we don't care */
   1542 	holler (wrote_txt, wrote_net, wrote_out);
   1543       exit (x);				/* "pack out yer trash" */
   1544     } else /* if no netfd */
   1545       bail ("no connection");
   1546   } /* o_listen */
   1547 
   1548 /* fall thru to outbound connects.  Now we're more picky about args... */
   1549   if (! themaddr)
   1550     bail ("no destination");
   1551   if (argv[optind] == NULL)
   1552     bail ("no port[s] to connect to");
   1553   if (argv[optind + 1])		/* look ahead: any more port args given? */
   1554     Single = 0;				/* multi-mode, case A */
   1555   ourport = o_lport;			/* which can be 0 */
   1556 
   1557 /* everything from here down is treated as as ports and/or ranges thereof, so
   1558    it's all enclosed in this big ol' argv-parsin' loop.  Any randomization is
   1559    done within each given *range*, but in separate chunks per each succeeding
   1560    argument, so we can control the pattern somewhat. */
   1561   while (argv[optind]) {
   1562     hiport = loport = 0;
   1563     cp = strchr (argv[optind], '-');	/* nn-mm range? */
   1564     if (cp) {
   1565       *cp = '\0';
   1566       cp++;
   1567       hiport = getportpoop (cp, 0);
   1568       if (hiport == 0)
   1569 	bail ("invalid port %s", cp);
   1570     } /* if found a dash */
   1571     loport = getportpoop (argv[optind], 0);
   1572     if (loport == 0)
   1573       bail ("invalid port %s", argv[optind]);
   1574     if (hiport > loport) {		/* was it genuinely a range? */
   1575       Single = 0;			/* multi-mode, case B */
   1576       curport = hiport;			/* start high by default */
   1577       if (o_random) {			/* maybe populate the random array */
   1578 	loadports (randports, loport, hiport);
   1579 	curport = nextport (randports);
   1580       }
   1581     } else			/* not a range, including args like "25-25" */
   1582       curport = loport;
   1583 Debug (("Single %d, curport %d", Single, curport))
   1584 
   1585 /* Now start connecting to these things.  curport is already preloaded. */
   1586     while (loport <= curport) {
   1587       if ((! o_lport) && (o_random)) {	/* -p overrides random local-port */
   1588 	ourport = (RAND() & 0xffff);	/* random local-bind -- well above */
   1589 	if (ourport < 8192)		/* resv and any likely listeners??? */
   1590 	  ourport += 8192;		/* if it *still* conflicts, use -s. */
   1591       }
   1592       curport = getportpoop (NULL, curport);
   1593       netfd = doconnect (themaddr, curport, ouraddr, ourport);
   1594 Debug (("netfd %d from port %d to port %d", netfd, ourport, curport))
   1595       if (netfd > 0)
   1596 	if (o_zero && o_udpmode)	/* if UDP scanning... */
   1597 	  netfd = udptest (netfd, themaddr);
   1598       if (netfd > 0) {			/* Yow, are we OPEN YET?! */
   1599 	x = 0;				/* pre-exit status */
   1600 	holler ("%s [%s] %d (%s) open",
   1601 	  whereto->name, whereto->addrs[0], curport, portpoop->name);
   1602 #ifdef GAPING_SECURITY_HOLE
   1603 	if (pr00gie)			/* exec is valid for outbound, too */
   1604 	  doexec (netfd);
   1605 #endif /* GAPING_SECURITY_HOLE */
   1606 	if (! o_zero)
   1607 	  x = readwrite (netfd);	/* go shovel shit */
   1608       } else { /* no netfd... */
   1609 	x = 1;				/* preload exit status for later */
   1610 /* if we're scanning at a "one -v" verbosity level, don't print refusals.
   1611    Give it another -v if you want to see everything. */
   1612 	if ((Single || (o_verbose > 1)) || (errno != ECONNREFUSED))
   1613 	  holler ("%s [%s] %d (%s)",
   1614 	    whereto->name, whereto->addrs[0], curport, portpoop->name);
   1615       } /* if netfd */
   1616       close (netfd);			/* just in case we didn't already */
   1617       if (o_interval)
   1618 	sleep (o_interval);		/* if -i, delay between ports too */
   1619       if (o_random)
   1620 	curport = nextport (randports);
   1621       else
   1622 	curport--;			/* just decrement... */
   1623     } /* while curport within current range */
   1624     optind++;
   1625   } /* while remaining port-args -- end of big argv-ports loop*/
   1626 
   1627   errno = 0;
   1628   if (o_verbose > 1)		/* normally we don't care */
   1629     holler (wrote_txt, wrote_net, wrote_out);
   1630   if (Single)
   1631     exit (x);			/* give us status on one connection */
   1632   exit (0);			/* otherwise, we're just done */
   1633 } /* main */
   1634 
   1635 #ifdef HAVE_HELP		/* unless we wanna be *really* cryptic */
   1636 /* helpme :
   1637    the obvious */
   1638 void
   1639 helpme()
   1640 {
   1641   o_verbose = 1;
   1642   holler ("[v1.10]\n\
   1643 connect to somewhere:	nc [-options] hostname port[s] [ports] ... \n\
   1644 listen for inbound:	nc -l -p port [-options] [hostname] [port]\n\
   1645 options:");
   1646 /* sigh, this necessarily gets messy.  And the trailing \ characters may be
   1647    interpreted oddly by some compilers, generating or not generating extra
   1648    newlines as they bloody please.  u-fix... */
   1649 #ifdef GAPING_SECURITY_HOLE	/* needs to be separate holler() */
   1650   holler ("\
   1651 	-e prog			program to exec after connect [dangerous!!]");
   1652 #endif
   1653   holler ("\
   1654 	-g gateway		source-routing hop point[s], up to 8\n\
   1655 	-G num			source-routing pointer: 4, 8, 12, ...\n\
   1656 	-h			this cruft\n\
   1657 	-i secs			delay interval for lines sent, ports scanned\n\
   1658 	-l			listen mode, for inbound connects\n\
   1659 	-n			numeric-only IP addresses, no DNS\n\
   1660 	-o file			hex dump of traffic\n\
   1661 	-p port			local port number\n\
   1662 	-r			randomize local and remote ports\n\
   1663 	-s addr			local source address");
   1664 #ifdef TELNET
   1665   holler ("\
   1666 	-t			answer TELNET negotiation");
   1667 #endif
   1668   holler ("\
   1669 	-u			UDP mode\n\
   1670 	-v			verbose [use twice to be more verbose]\n\
   1671 	-w secs			timeout for connects and final net reads\n\
   1672 	-z			zero-I/O mode [used for scanning]");
   1673   bail ("port numbers can be individual or ranges: lo-hi [inclusive]");
   1674 } /* helpme */
   1675 #endif /* HAVE_HELP */
   1676 
   1677 /* None genuine without this seal!  _H*/
   1678