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