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