netcat.c revision 3b923003c7c5a13b4ff2e2091acd307e9d1304b2
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
104struct 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
111struct 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: */
119jmp_buf jbuf;			/* timer crud */
120int jval = 0;			/* timer crud */
121int netfd = -1;
122int ofd = 0;			/* hexdump output fd */
123static char unknown[] = "(UNKNOWN)";
124static char p_tcp[] = "tcp";	/* for getservby* */
125static char p_udp[] = "udp";
126#ifdef HAVE_BIND
127extern int h_errno;
128/* stolen almost wholesale from bsd herror.c */
129static 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
137int h_errno;			/* just so we *do* have it available */
138#endif /* HAVE_BIND */
139int gatesidx = 0;		/* LSRR hop count */
140int gatesptr = 4;		/* initial LSRR pointer, settable */
141USHORT Single = 1;		/* zero if scanning */
142unsigned int insaved = 0;	/* stdin-buffer size for multi-mode */
143unsigned int wrote_out = 0;	/* total stdout bytes */
144unsigned int wrote_net = 0;	/* total net bytes */
145static char wrote_txt[] = " sent %d, rcvd %d";
146static char hexnibs[20] = "0123456789abcdef  ";
147
148/* will malloc up the following globals: */
149struct timeval * timer1 = NULL;
150struct timeval * timer2 = NULL;
151SAI * lclend = NULL;		/* sockaddr_in structs */
152SAI * remend = NULL;
153HINF ** gates = NULL;		/* LSRR hop hostpoop */
154char * optbuf = NULL;		/* LSRR or sockopts */
155char * bigbuf_in;		/* data buffers */
156char * bigbuf_net;
157fd_set * ding1;			/* for select loop */
158fd_set * ding2;
159PINF * portpoop = NULL;		/* for getportpoop / getservby* */
160unsigned char * stage = NULL;	/* hexdump line buffer */
161
162/* global cmd flags: */
163USHORT o_alla = 0;
164unsigned int o_interval = 0;
165USHORT o_listen = 0;
166USHORT o_nflag = 0;
167USHORT o_wfile = 0;
168USHORT o_random = 0;
169USHORT o_udpmode = 0;
170USHORT o_verbose = 0;
171unsigned int o_wait = 0;
172USHORT 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. */
192void 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, 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 */
217void 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 */
230void 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 */
239void 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 */
250void 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. */
268char * 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... */
284unsigned 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! */
299Debug (("findline returning %d", x))
300      return (x);
301    }
302    p++;
303  } /* for */
304Debug (("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. */
313int 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. */
338HINF * 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. */
438USHORT 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
503gp_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. */
518USHORT 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... */
554void 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
573char * 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!! */
581doexec (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;
595Debug (("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. */
608int 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 */
620newskt:
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.
687Option comes after IP-hdr dest addr in packet, padded to *4, and ihl > 5.
688IHL 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
695If we want to route A -> B via hops C and D, we must add C, D, *and* B to the
696options list.  Why?  Because when we hand the kernel A -> B with list C, D, B
697the "send shuffle" inside the kernel changes it into A -> C with list D, B and
698the outbound packet gets sent to C.  If B wasn't also in the hops list, the
699final destination would have been lost at this point.
700
701When C gets the packet, it changes it to A -> D with list C', B where C' is
702the interface address that C used to forward the packet.  This "records" the
703route hop from B's point of view, i.e. which address points "toward" B.  This
704is to make B better able to return the packets.  The pointer gets bumped by 4,
705so that D does the right thing instead of trying to forward back to C.
706
707When B finally gets the packet, it sees that the pointer is at the end of the
708LSRR list and is thus "completed".  B will then try to use the packet instead
709of forwarding it, i.e. deliver it up to some application.
710
711Note that by moving the pointer yourself, you could send the traffic directly
712to B but have it return via your preconstructed source-route.  Playing with
713this and watching "tcpdump -v" is the best way to understand what's going on.
714
715Only works for TCP in BSD-flavor kernels.  UDP is a loss; udp_input calls
716stripoptions() early on, and the code to save the srcrt is notdef'ed.
717Linux 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... */
775int 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);
837Debug (("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
867whoisit:
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");
884Debug (("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 */
898dol_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
940dol_tmo:
941  errno = ETIMEDOUT;			/* fake it */
942dol_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. */
957int 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:
992D 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... */
1000void 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
1082USHORT 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@l0pht.com. */
1089void 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 */
1118notiac:
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. */
1127int 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 */
1213Debug (("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
1242shovel:
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	}
1266Debug (("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	}
1281Debug (("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... */
1305int 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 */
1489Debug (("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 */
1510Debug (("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;
1585Debug (("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);
1596Debug (("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 */
1640void
1641helpme()
1642{
1643  o_verbose = 1;
1644  holler ("[v1.10]\n\
1645connect to somewhere:	nc [-options] hostname port[s] [ports] ... \n\
1646listen for inbound:	nc -l -p port [-options] [hostname] [port]\n\
1647options:");
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