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