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