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