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