source: npl/overig/nc/netcat.c.orig @ 9befa48

Last change on this file since 9befa48 was c5c522c, checked in by Edwin Eefting <edwin@datux.nl>, 8 years ago

initial commit, transferred from cleaned syn3 svn tree

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