1 N              [0-9]
2 O              ({N}{1,3})
3 
4 C              [0-9A-Fa-f]
5 H              ({C}{1,4})
6 
7     #include <sys/types.h>
8     #include <sys/socket.h>
9     #include <sys/time.h>
10     #include <sys/stat.h>
11 
12     #include <netinet/in.h>
13 
14     #include <arpa/inet.h>
15     #include <arpa/nameser.h>
16 
17     #include <ctype.h>
18     #include <errno.h>
19     #ifdef HAVE_MEMORY_H
20     #include <memory.h>
21     #endif
22     #include <netdb.h>
23     #include <resolv.h>
24     #include <setjmp.h>
25     #include <signal.h>
26     #include <stdio.h>
27     #include <stdlib.h>
28     #include <string.h>
29     #include <unistd.h>
30 
31     #include "gnuc.h"
32     #ifdef HAVE_OS_PROTO_H
33     #include "os-proto.h"
34     #endif
35 
36     #include "nb_dns.h"
37     #include "setsignal.h"
38     #include "version.h"
39 
40     #undef yywrap
41     #ifdef FLEX_SCANNER
42     #define YY_NO_INPUT
43     #define YY_NO_UNPUT
44     #endif
45 
46     /* -x: Only print the ip addresses, one per line; -xx: include cidr width */
47     #define MATCH(isv6) if (xflag > 1) { \
48 	    echo(); \
49 	    BEGIN(WIDTH); \
50     } else if (xflag) { \
51 	    echo(); \
52 	    putchar('\n'); \
53     } else { \
54 	    convert(yytext, (isv6)); \
55     }
56     #define NOMATCH if (!xflag) { \
57 	    echo(); \
58     }
59 
60     int doinfo;
61     int linemode;		/* convert at most one entry per line */
62     #ifdef HAVE_ASYNC_DNS
63     int lookup_pass;		/* true if lookup only */
64     #endif
65     int triedone;
66     int xflag;			/* only print matches with no translation */
67 
68     void convert(const char *, int);
69     void reportinfo(void);
70     int yywrap(void);
71     int yylex(void);
72 
73     static inline void
echo()74     echo()
75     {
76     #ifdef HAVE_ASYNC_DNS
77 	    if (!lookup_pass)
78     #endif
79 		    (void)fwrite(yytext, yyleng, 1, yyout);
80     #ifdef SIGINFO
81 	    if (doinfo) {
82 		    reportinfo();
83 		    doinfo = 0;
84 	    }
85     #endif
86     }
87     #define ECHO echo()
88 
89 %x WIDTH
90 
91 %%
92 
93 ::{O}(\.{O}){3}		MATCH(1);
94 {O}(\.{O}){3}		MATCH(0);
95 
96 :(:{H}){1,7}		MATCH(1);
97 {H}(:{H}){7}		MATCH(1);
98 {H}:(:{H}){1,6}		MATCH(1);
99 ({H}:){2}(:{H}){1,5}	MATCH(1);
100 ({H}:){3}(:{H}){1,4}	MATCH(1);
101 ({H}:){4}(:{H}){1,3}	MATCH(1);
102 ({H}:){5}(:{H}){1,2}	MATCH(1);
103 ({H}:){6}:{H}		MATCH(1);
104 
105 <WIDTH>"/"{N}+		{
106 			/* Output width part of cidr and newline */
107 			echo();
108 			putchar('\n');
109 			BEGIN(0);
110 			}
111 
112 <WIDTH>.		{
113 			/* No cdir width; output newline */
114 			putchar('\n');
115 			BEGIN(0);
116 			}
117 
118 ({O}\.){1,3}		NOMATCH;	/* anti-backtrack */
119 {O}((\.{O}){1,2})	NOMATCH;	/* anti-backtrack */
120 
121     /*
122      * Speedups: Avoid handling unmatched characters one at a time
123      * via the default echo rule.
124      */
125 
126 {H}+			NOMATCH;
127 [^0-9A-Fa-f\n]+		NOMATCH;
128 
129 [^0-9A-Fa-f\n]+\n	{
130 			NOMATCH;
131 			triedone = 0;
132 			}
133 
134 <WIDTH>\n		{
135 			/* No cdir width; output newline */
136 			putchar('\n');
137 			triedone = 0;
138 			BEGIN(0);
139 			}
140 
141 \n			{
142 			NOMATCH;
143 			triedone = 0;
144 			}
145 
146 %%
147 
148 /*
149  * Copyright (c) 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2009, 2013, 2014, 2016, 2017, 2020
150  * The Regents of the University of California. All rights reserved.
151  *
152  * Redistribution and use in source and binary forms, with or without
153  * modification, are permitted provided that the following conditions are met:
154  *     * Redistributions of source code must retain the above copyright
155  *       notice, this list of conditions and the following disclaimer.
156  *     * Redistributions in binary form must reproduce the above copyright
157  *       notice, this list of conditions and the following disclaimer in the
158  *       documentation and/or other materials provided with the distribution.
159  *     * Neither the name of the University nor the names of its contributors
160  *       may be used to endorse or promote products derived from this software
161  *       without specific prior written permission.
162  *
163  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
164  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
165  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
166  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
167  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
168  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
169  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
170  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
171  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
172  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
173  * SUCH DAMAGE.
174  */
175 
176 #ifndef lint
177 static const char copyright[] __attribute__ ((unused)) =
178     "@(#) Copyright (c) 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2009, 2013, 2014, 2016, 2017, 2020\n\
179 The Regents of the University of California.  All rights reserved.\n";
180 static const char rcsid[] __attribute__ ((unused)) =
181     "@(#) $Id: hf.l 221 2020-09-15 23:17:21Z leres $ (LBL)";
182 #endif
183 
184 #define HSIZE 8192		/* must be a power of two */
185 
186 struct htable {
187 	char addr[NS_IN6ADDRSZ];
188 	int af;			/* address family */
189 	int alen;
190 	int state;
191 	char *name;		/* overloaded variable */
192 	struct htable *next;
193 } htable[HSIZE];
194 
195 #define STATE_FREE	0	/* not in use */
196 #define STATE_RAW	1	/* couldn't translate */
197 #define STATE_SENTPTR	2
198 #define STATE_HAVEPTR	3
199 #define STATE_SENTA	4
200 #define STATE_HAVEA	5
201 
202 #define PLURAL(n) ((n) == 1 ? "" : "s")
203 
204 int strip = 1;			/* strip local domain when possible */
205 int lcase = 1;			/* force lowercase */
206 int shortdomain;		/* strip entire domain */
207 const char defaultefmt[] = "%h";
208 const char *efmt = defaultefmt;	/* expansion format */
209 #ifdef HAVE_ASYNC_DNS
210 int asyncdns;			/* 2 pass async dns hack */
211 int numasync;			/* number of outstanding async requests */
212 int asyncfd;
213 #endif
214 int networknumber;		/* convert to network numbers */
215 int check;			/* check PTR's against A records */
216 int debug;
217 
218 int tmo;			/* seconds to wait for a answer from the dns */
219 int doingdns;			/* true if we're waiting for the nameserver */
220 sigjmp_buf alrmenv;		/* siglongjmp() buffer */
221 
222 /* Rate limit */
223 float queriespersec = 1000.0;	/* maximum queries per second with async */
224 struct timeval startts;		/* start time for rate limit calculation */
225 long querycount;		/* number of queries so far */
226 
227 long cachehits;			/* number of successful cache hits */
228 int filecount;			/* number of files so far */
229 char *prog;
230 
231 char domain[64];		/* current domain name (including '.') */
232 int domainlen;			/* length of domain name */
233 
234 char azero[NS_IN6ADDRSZ];
235 
236 #ifdef HAVE_ASYNC_DNS
237 struct nb_dns_info *nd;
238 #endif
239 
240 int targc;
241 char **targv;
242 
243 extern char *optarg;
244 extern int optind, opterr;
245 
246 /* ANSI C defines this */
247 #ifndef __STDC__
248 extern char *malloc();
249 #endif
250 
251 /* Forwards */
252 char *a2h(const char *, int, int);
253 char *addr2host(const char *, int, int);
254 #ifdef HAVE_ASYNC_DNS
255 void asyncreap(int);
256 #endif
257 float calculaterate(void);
258 struct htable *cacheaddr(const char *, int, int, int, const char *);
259 void dump(void);
260 const char *format(const char *, const char *, const char *);
261 int getdomain(void);
262 void gettime(struct timeval *);
263 struct htable *hash(const char *, int);
264 #ifdef SIGINFO
265 RETSIGTYPE info(int);
266 #endif
267 #ifdef HAVE_ASYNC_DNS
268 int ispipe(FILE *);
269 #endif
270 struct htable *lookupaddr(const char *, int, int);
271 int main(int, char **);
272 void massagename(char *);
273 void mysleep(int);
274 void ratelimit(void);
275 RETSIGTYPE timeout(int);
276 void usage(void) __attribute__((noreturn));
277 
278 int
main(argc,argv)279 main(argc, argv)
280 	int argc;
281 	char **argv;
282 {
283 	char *cp, *ep;
284 	int op, nflags;
285 	long v;
286 #ifdef HAVE_ASYNC_DNS
287 	char errstr[NB_DNS_ERRSIZE];
288 #endif
289 
290 	if (argv[0] == NULL)
291 		prog = "hf";
292 	else if ((cp = strrchr(argv[0], '/')) != NULL)
293 		prog = cp + 1;
294 	else
295 		prog = argv[0];
296 
297 	opterr = 0;
298 	nflags = 0;
299 	while ((op = getopt(argc, argv, "1abcdf:ilnNR:t:x")) != EOF)
300 		switch (op) {
301 
302 		case '1':
303 			++linemode;
304 			++nflags;
305 			break;
306 
307 		case 'a':
308 #ifdef HAVE_ASYNC_DNS
309 			++asyncdns;
310 #else
311 			fprintf(stderr,
312 			    "%s: warning: -a not supported; ignored\n", prog);
313 #endif
314 			++nflags;
315 			break;
316 
317 		case 'b':
318 			efmt = "%h(%i)";
319 			++nflags;
320 			break;
321 
322 		case 'c':
323 			++check;
324 			++nflags;
325 			break;
326 
327 		case 'd':
328 			++debug;
329 			++nflags;
330 			break;
331 
332 		case 'f':
333 			if (*optarg == '\0')
334 				efmt = defaultefmt;
335 			else
336 				efmt = optarg;
337 			++nflags;
338 			break;
339 
340 		case 'i':
341 			lcase = 0;
342 			++nflags;
343 			break;
344 
345 		case 'l':
346 			strip = 0;
347 			++nflags;
348 			break;
349 
350 		case 'n':
351 #ifdef notdef
352 			++networknumber;
353 #else
354 			fprintf(stderr, "%s: -n not currently impemented\n",
355 			    prog);
356 			exit(1);
357 #endif
358 			++nflags;
359 			break;
360 
361 		case 'N':
362 			++shortdomain;
363 			++nflags;
364 			break;
365 
366 		case 'R':
367 			v = strtol(optarg, &ep, 10);
368 			if (*ep != '\0' || v > 1000000)
369 				usage();
370 			queriespersec = (float)v;
371 			break;
372 
373 		case 't':
374 			tmo = atoi(optarg);
375 			if (tmo <= 0)
376 				usage();
377 			++nflags;
378 			break;
379 
380 		case 'x':
381 			++xflag;
382 			break;
383 
384 		default:
385 			usage();
386 		}
387 
388 	if (xflag && nflags)
389 		usage();
390 
391 #ifdef HAVE_ASYNC_DNS
392 	if (asyncdns) {
393 		nd = nb_dns_init(errstr);
394 		if (nd == NULL) {
395 			fprintf(stderr, "%s: nb_dns_init: %s\n", prog, errstr);
396 			exit(1);
397 		}
398 		asyncfd = nb_dns_fd(nd);
399 		/* If no explicit timeout, use resolver retransmit */
400 		if (tmo == 0)
401 			tmo = _res.retrans;
402 	}
403 #endif
404 
405 	/* Figure out our domain, if necessary */
406 	if (!strip || shortdomain || !getdomain())
407 		domain[0] = '\0';
408 
409 	/* Up number of retries, we really want answers */
410 	_res.retry = 20;
411 
412 	/* Don't search, we'll use only FQDNs */
413 	_res.options &= ~RES_DNSRCH;
414 
415 	/* Use a persistent TCP connection */
416 	_res.options |= (RES_USEVC | RES_STAYOPEN);
417 
418 	/* Start time for rate limit calculations */
419 	gettime(&startts);
420 
421 #ifdef SIGINFO
422 	(void)setsignal(SIGINFO, info);
423 #endif
424 
425 	/* Setup alarm catcher if -t */
426 #ifdef HAVE_ASYNC_DNS
427 	if (!asyncdns)
428 #endif
429 		if (tmo > 0)
430 			(void)setsignal(SIGALRM, timeout);
431 
432 	/* Let yywrap() figure out if there are any arguments to open */
433 	targc = argc - optind;
434 	targv = &argv[optind];
435 	yyin = NULL;
436 	(void)yywrap();
437 
438 	/* Process file opened by yywrap() or stdin if no arguments */
439 	if (yyin) {
440 #ifdef HAVE_ASYNC_DNS
441 		/* XXX depends on the type of stdin */
442 		/* XXX can we do a test rewind? */
443 #ifdef notdef
444 		if (asyncdns && yyin == stdin)
445 			fprintf(stderr,
446 			    "%s: warning: can't use -a on stdin\n", prog);
447 #endif
448 #endif
449 		yylex();
450 	}
451 
452 	if (debug) {
453 		fflush(stdout);
454 		reportinfo();
455 		if (debug > 1)
456 			dump();
457 	}
458 	exit(0);
459 }
460 
461 int
yywrap()462 yywrap()
463 {
464 	char *file;
465 	static int didany = 0;
466 
467 	/* Close file, if necessary */
468 	if (yyin) {
469 #ifdef HAVE_ASYNC_DNS
470 		if (asyncdns) {
471 			if (lookup_pass) {
472 				if (fseek(yyin, 0L, SEEK_SET) < 0) {
473 					fprintf(stderr,
474 					    "%s: fseek/rewind: %s\n",
475 					    prog, strerror(errno));
476 					exit(1);
477 				}
478 				yyrestart(yyin);
479 				lookup_pass = 0;
480 				asyncreap(1);
481 				return (0);
482 			}
483 			numasync = 0;
484 		}
485 #endif
486 		if (yyin != stdin)
487 			(void)fclose(yyin);
488 		yyin = NULL;
489 	}
490 
491 	/* Spin through arguments until we run out or successfully open one */
492 	while (targc > 0) {
493 		file = targv[0];
494 		--targc;
495 		++targv;
496 		++didany;
497 		if ((yyin = fopen(file, "r")) != NULL) {
498 #ifdef HAVE_ASYNC_DNS
499 			if (asyncdns)
500 				lookup_pass = 1;
501 #endif
502 			++filecount;
503 			return (0);
504 		}
505 		perror(file);
506 	}
507 	if (!didany) {
508 		++didany;
509 		++filecount;
510 		yyin = stdin;
511 #ifdef HAVE_ASYNC_DNS
512 		if (asyncdns) {
513 			if (ispipe(yyin)) {
514 				fprintf(stderr,
515 				    "%s: warning: can't use -a on a pipe\n",
516 				    prog);
517 				asyncdns = 0;
518 			} else
519 				lookup_pass = 1;
520 		}
521 #endif
522 		return (0);
523 	}
524 	return (1);
525 }
526 
527 const char *
format(const char * fmt,const char * hnstr,const char * ipstr)528 format(const char *fmt, const char *hnstr, const char *ipstr)
529 {
530 	char *cp;
531 	const char *cp2, *item;
532 	size_t len, ilen, llen, dlen, nlen, hlen, itemlen;
533 	static char buf[1024];
534 
535 	/* ip address length */
536 	ilen = strlen(ipstr);
537 
538 	/* Normally we are passed the long hostname */
539 	if (hnstr != NULL) {
540 		/* Long hostname length */
541 		llen = strlen(hnstr);
542 
543 		/* Local domain truncated hostname length */
544 		dlen = llen;
545 		if (*domain != '\0') {
546 			cp2 = hnstr + (llen - domainlen);
547 			if (cp2 > hnstr && strcasecmp(cp2, domain) == 0)
548 				dlen = cp2 - hnstr;
549 		}
550 
551 		/* Local domain truncated hostname length */
552 		cp = strchr(hnstr, '.');
553 		if (cp == NULL)
554 			nlen = llen;
555 		else
556 			nlen = cp - hnstr;
557 
558 		/* Default hostname length */
559 		if (shortdomain)
560 			hlen = nlen;
561 		else
562 			hlen = dlen;
563 	} else {
564 		/* We only have the ip address string */
565 		hnstr = ipstr;
566 		llen = strlen(hnstr);
567 		dlen = llen;
568 		nlen = llen;
569 		hlen = llen;
570 	}
571 
572 	cp = buf;
573 	/* Leave room for EOS */
574 	len = sizeof(buf) - 1;
575 	cp2 = fmt;
576 	while (*cp2 != '\0' && len > 0) {
577 		if (*cp2 != '%') {
578 			*cp++ = *cp2++;
579 			--len;
580 			continue;
581 		}
582 		++cp2;
583 		switch (*cp2) {
584 
585 		case 'h':
586 			/* Default hostname */
587 			item = hnstr;
588 			itemlen = hlen;
589 			break;
590 
591 		case 'D':
592 			/* Local domain truncated hostname */
593 			item = hnstr;
594 			itemlen = dlen;
595 			break;
596 
597 		case 'N':
598 			/* Domain truncated hostname */
599 			item = hnstr;
600 			itemlen = nlen;
601 			break;
602 
603 		case 'i':
604 			/* ip address */
605 			item = ipstr;
606 			itemlen = ilen;
607 			break;
608 
609 		case 'l':
610 			/* Long hostname */
611 			item = hnstr;
612 			itemlen = llen;
613 			break;
614 
615 		default:
616 			/* Random character */
617 			*cp++ = *cp2++;
618 			--len;
619 			continue;
620 		}
621 		if (itemlen > len)
622 			itemlen = len;
623 		strncpy(cp, item, itemlen);
624 		cp += itemlen;
625 		len -= itemlen;
626 		++cp2;
627 	}
628 	*cp = '\0';
629 
630 	return (buf);
631 }
632 
633 int
getdomain()634 getdomain()
635 {
636 	char *cp;
637 	struct hostent *hp;
638 	char host[128];
639 
640 	if (gethostname(host, sizeof(host) - 1) < 0)
641 		return (0);
642 	if ((cp = strchr(host, '.')) == NULL) {
643 		/* Not already canonical */
644 		if (tmo > 0)
645 			alarm(tmo);
646 		doingdns = 1;
647 		if (sigsetjmp(alrmenv, 1))
648 			return (0);
649 		hp = gethostbyname(host);
650 		doingdns = 0;
651 		if (hp == NULL)
652 			return (0);
653 		if ((cp = strchr(hp->h_name, '.')) == NULL)
654 			return (0);
655 	}
656 	(void)strncpy(domain, cp, sizeof(domain));
657 	domain[sizeof(domain) - 1] = '\0';
658 	if (lcase)
659 		for (cp = domain; *cp; ++cp)
660 			if (isupper((int)*cp))
661 				*cp = tolower(*cp);
662 	domainlen = strlen(domain);
663 	return (1);
664 }
665 
666 void
gettime(struct timeval * tvp)667 gettime(struct timeval *tvp)
668 {
669 	if (gettimeofday(tvp, NULL) < 0) {
670 		fprintf(stderr, "%s: gettimeofday: %s\n",
671 		    prog, strerror(errno));
672 		exit(1);
673 	}
674 }
675 
676 void
ratelimit()677 ratelimit()
678 {
679 	if (queriespersec > 0.0) {
680 		if (querycount > 0)
681 			while (calculaterate() > queriespersec)
682 				mysleep(10);
683 		++querycount;
684 	}
685 }
686 
687 RETSIGTYPE
timeout(int signo)688 timeout(int signo)
689 {
690 	if (doingdns) {
691 		doingdns = 0;
692 		siglongjmp(alrmenv, 1);
693 	}
694 	return RETSIGVAL;
695 }
696 
697 /* Convert address to hostname via the dns */
698 char *
a2h(const char * ap,int alen,int af)699 a2h(const char *ap, int alen, int af)
700 {
701 	char **pp, *host2;
702 	size_t len;
703 	static struct hostent *hp;
704 	static char *host = NULL;
705 	static size_t hostlen = 0;
706 
707 	/* Look up the PTR */
708 	if (tmo > 0)
709 		alarm(tmo);
710 	doingdns = 1;
711 	if (sigsetjmp(alrmenv, 1))
712 		return (NULL);
713 
714 	/* Handle rate limiting */
715 	ratelimit();
716 
717 	hp = gethostbyaddr(ap, alen, af);
718 	doingdns = 0;
719 	if (hp == NULL)
720 		return (NULL);
721 
722 	len = strlen(hp->h_name) + 1;
723 	if (hostlen < len) {
724 		if (len < 132)
725 			len = 132;
726 		if (host == NULL)
727 			host = malloc(len);
728 		else {
729 			host2 = realloc(host, len);
730 			if (host2 != NULL)
731 				host = host2;
732 			else {
733 				free(host);
734 				host = NULL;
735 			}
736 		}
737 		if (host == NULL) {
738 			hostlen = 0;
739 			return (NULL);
740 		}
741 		hostlen = len;
742 	}
743 	(void)strcpy(host, hp->h_name);
744 
745 	/* Done if we aren't checking */
746 	if (!check)
747 		return (host);
748 
749 #ifndef HAVE_GETHOSTBYNAME2
750 	if (af != AF_INET)
751 		return (NULL);
752 #endif
753 
754 	/* Check PTR against the A record */
755 	if (tmo > 0)
756 		alarm(tmo);
757 	doingdns = 1;
758 	if (sigsetjmp(alrmenv, 1))
759 		return (NULL);
760 
761 	/* Handle rate limiting */
762 	ratelimit();
763 
764 #ifdef HAVE_GETHOSTBYNAME2
765 	hp = gethostbyname2(host, af);
766 #else
767 	hp = gethostbyname(host);
768 #endif
769 	doingdns = 0;
770 	if (hp == NULL)
771 		return (NULL);
772 	if (af != hp->h_addrtype)
773 		return (NULL);
774 
775 	/* Spin through ip addresses looking for a match */
776 	for (pp = hp->h_addr_list; *pp != NULL; ++pp)
777 		if (memcmp(ap, *pp, alen) == 0)
778 			return (host);
779 
780 	return (NULL);
781 }
782 
783 /* Convert address to hostname via the cache and/or dns */
784 char *
addr2host(const char * ap,int alen,int af)785 addr2host(const char *ap, int alen, int af)
786 {
787 	int state;
788 	char *host;
789 	struct htable *p;
790 
791 	/* First look in hash table */
792 	p = lookupaddr(ap, alen, af);
793 	if (p != NULL)
794 		return (p->name);
795 
796 	/* Lookup this host */
797 	host = a2h(ap, alen, af);
798 	state = STATE_RAW;
799 	if (host != NULL) {
800 		if (check)
801 			state = STATE_HAVEA;
802 		else
803 			state = STATE_HAVEPTR;
804 		massagename(host);
805 	}
806 
807 	p = cacheaddr(ap, state, alen, af, host);
808 	if (p != NULL)
809 		return (p->name);
810 
811 	return (host);
812 }
813 
814 /* Look hash table entry for address */
815 struct htable *
lookupaddr(const char * ap,int alen,int af)816 lookupaddr(const char *ap, int alen, int af)
817 {
818 	struct htable *p;
819 
820 	for (p = hash(ap, af); p != NULL; p = p->next) {
821 		if (p->af == af && memcmp(p->addr, ap, alen) == 0) {
822 #ifdef HAVE_ASYNC_DNS
823 			if (!asyncdns || lookup_pass)
824 #endif
825 				++cachehits;
826 			return (p);
827 		}
828 	}
829 	return (NULL);
830 }
831 
832 void
massagename(char * name)833 massagename(char *name)
834 {
835 	char *cp;
836 
837 	if (lcase)
838 		for (cp = name; *cp; ++cp)
839 			if (isupper((int)*cp))
840 				*cp = tolower(*cp);
841 }
842 
843 void
mysleep(int ms)844 mysleep(int ms)
845 {
846 	struct timeval tv;
847 	div_t res;
848 
849 	res = div(ms, 1000);
850 	tv.tv_sec = res.quot;
851 	tv.tv_usec = res.rem * 1000;
852 	if (select(0, NULL, NULL, NULL, &tv) < 0 && errno != EINTR) {
853 		fprintf(stderr, "%s: mysleep: select: %s\n",
854 		    prog, strerror(errno));
855 		exit(1);
856 	}
857 }
858 
859 struct htable *
cacheaddr(const char * ap,int state,int alen,int af,const char * host)860 cacheaddr(const char *ap, int state, int alen, int af, const char *host)
861 {
862 	struct htable *p, *p2;
863 
864 	/* Don't cache zero */
865 	if (memcmp(ap, azero, alen) == 0)
866 		return (NULL);
867 
868 	/* Look for existing slot in hash table */
869 	for (p = hash(ap, af); p != NULL; p = p->next)
870 		if (p->state != STATE_FREE &&
871 		    p->af == af &&
872 		    memcmp(p->addr, ap, alen) == 0)
873 			break;
874 
875 	/* Allocate a new slot */
876 	if (p == NULL) {
877 		p = hash(ap, af);
878 		if (p->state != STATE_FREE) {
879 			/* Handle the collision */
880 			p2 = (struct htable *)malloc(sizeof(struct htable));
881 			/* Lose, lose */
882 			if (p2 == NULL)
883 				return (NULL);
884 			memset((char *)p2, 0, sizeof(struct htable));
885 			p2->next = p->next;
886 			p->next = p2;
887 			p = p2;
888 		}
889 	}
890 
891 	/* Install new host */
892 	memmove(p->addr, ap, alen);
893 	p->alen = alen;
894 	p->af = af;
895 	if (host != NULL)
896 		p->name = strdup(host);
897 	if (state != 0)
898 		p->state = state;
899 	if (p->state == STATE_FREE)
900 		abort();
901 
902 	/* Return answer entry */
903 	return (p);
904 }
905 
906 void
dump()907 dump()
908 {
909 	char *cp;
910 	int i, j, n, d;
911 	struct htable *p, *p2;
912 	char buf[132];
913 
914 	d = n = 0;
915 	for (p = htable, i = 0; i < HSIZE; ++p, ++i)
916 		if (p->name) {
917 			++n;
918 			j = 0;
919 			for (p2 = p; p2; p2 = p2->next) {
920 				if ((cp = p2->name) == NULL)
921 					cp = "<nil>";
922 				else if (cp == (char *)1)
923 					cp = "<raw>";
924 				(void)fprintf(stderr, "%4d:%d ", i, j);
925 				if (inet_ntop(p2->af, p2->addr,
926 				    buf, sizeof(buf)) == NULL)
927 					(void)fprintf(stderr, "?");
928 				else
929 					(void)fprintf(stderr, "%s", buf);
930 				switch (p2->state) {
931 
932 				case STATE_HAVEA:
933 					(void)fprintf(stderr, " HAVEA");
934 					break;
935 
936 				case STATE_HAVEPTR:
937 					(void)fprintf(stderr, " HAVEPTR");
938 					break;
939 
940 				case STATE_SENTPTR:
941 					(void)fprintf(stderr, " SENTPTR");
942 					break;
943 
944 				case STATE_RAW:
945 					(void)fprintf(stderr, " RAW");
946 					break;
947 
948 				default:
949 					(void)fprintf(stderr, " #%d",
950 					    p2->state);
951 					break;
952 				}
953 				(void)fprintf(stderr, " \"%s\"\n", cp);
954 				++d;
955 				++j;
956 			}
957 		}
958 	d -= n;
959 	(void)fprintf(stderr, "%d entries (%d dynamically linked)\n", n, d);
960 }
961 
962 #ifdef HAVE_ASYNC_DNS
963 void
asyncreap(int ateof)964 asyncreap(int ateof)
965 {
966 	char *host;
967 	int n;
968 	char **pp;
969 	struct htable *p;
970 	struct nb_dns_result *nr;
971 	struct hostent *hp;
972 	fd_set fds;
973 	struct timeval to;
974 	char errstr[NB_DNS_ERRSIZE];
975 	struct nb_dns_result xxxnr;
976 
977 	nr = &xxxnr;
978 	memset(nr, 0, sizeof(*nr));
979 	while (numasync > 0) {
980 		FD_ZERO(&fds);
981 		FD_SET(asyncfd, &fds);
982 		/* If we're not at EOF, just poll */
983 		if (!ateof) {
984 			to.tv_sec = 0;
985 			to.tv_usec = 0;
986 		} else {
987 			to.tv_sec = tmo;
988 			to.tv_usec = 0;
989 		}
990 		n = select(asyncfd + 1, &fds, NULL, NULL, &to);
991 		if (n < 0) {
992 			fprintf(stderr, "%s: select: %s\n",
993 			    prog, strerror(errno));
994 			exit(1);
995 		}
996 
997 		/* Done if timed out */
998 		if (n == 0)
999 			break;
1000 
1001 		n = nb_dns_activity(nd, nr, errstr);
1002 		if (n < 0) {
1003 			fprintf(stderr, "%s: nb_dns_activity: %s\n",
1004 			    prog, errstr);
1005 			exit(1);
1006 		}
1007 
1008 		/* Bail if reply doesn't match any current queries */
1009 		if (n == 0)
1010 			continue;
1011 
1012 		/* Decrement outstanding request counter */
1013 		--numasync;
1014 
1015 		/* Bail if not a good answer */
1016 		if (nr->host_errno != NETDB_SUCCESS)
1017 			continue;
1018 
1019 		/* Bail if no hostname (probably shouldn't happen) */
1020 		hp = nr->hostent;
1021 		host = hp->h_name;
1022 		if (host == NULL)
1023 			continue;
1024 
1025 		/* Recover hash table pointer */
1026 		p = (struct htable *)nr->cookie;
1027 
1028 		switch (p->state) {
1029 
1030 		case STATE_SENTPTR:
1031 			/* Are we done? */
1032 			if (!check) {
1033 				p->state = STATE_HAVEPTR;
1034 				break;
1035 			}
1036 
1037 			/* Now look up the A record */
1038 			if (nb_dns_host_request2(nd, host, p->af,
1039 			    (void *)p, errstr) < 0) {
1040 				fprintf(stderr, "%s: nb_dns_host_request: %s\n",
1041 				    prog, errstr);
1042 				p->state = STATE_RAW;
1043 				free(p->name);
1044 				p->name = NULL;
1045 				break;
1046 			}
1047 
1048 			/* Cache the fact that we're looking */
1049 			++numasync;
1050 			p->state = STATE_SENTA;
1051 			break;
1052 
1053 		case STATE_SENTA:
1054 			/* Check A against our address */
1055 			if (p->af != hp->h_addrtype) {
1056 				p->state = STATE_RAW;
1057 				free(p->name);
1058 				p->name = NULL;
1059 				break;
1060 			}
1061 
1062 			/* Spin through ip addresses looking for a match */
1063 			for (pp = hp->h_addr_list; *pp != NULL; ++pp)
1064 				if (memcmp(p->addr, *pp, p->alen) == 0)
1065 					break;
1066 
1067 			if (pp == NULL) {
1068 				p->state = STATE_RAW;
1069 				free(p->name);
1070 				p->name = NULL;
1071 				break;
1072 			}
1073 			p->state = STATE_HAVEA;
1074 			break;
1075 
1076 		default:
1077 			abort();
1078 		}
1079 		massagename(host);
1080 		if (p->name != NULL)
1081 			abort();
1082 		if (host != NULL)
1083 			p->name = strdup(host);
1084 	}
1085 }
1086 #endif
1087 
1088 float
calculaterate()1089 calculaterate()
1090 {
1091 	struct timeval now, delta;
1092 
1093 	gettime(&now);
1094 	timersub(&now, &startts, &delta);
1095 	return ((float)querycount) /
1096 	    (((float)delta.tv_sec) + (((float)delta.tv_usec) / 1000000.0));
1097 }
1098 
1099 void
convert(const char * ipstr,int isv6)1100 convert(const char *ipstr, int isv6)
1101 {
1102 	const char *hnstr;
1103 	int alen;
1104 	int af;
1105 #ifdef HAVE_ASYNC_DNS
1106 	struct htable *p;
1107 	char errstr[NB_DNS_ERRSIZE];
1108 	static int num = 0;
1109 #endif
1110 	char addr[NS_IN6ADDRSZ];
1111 
1112 	if (isv6) {
1113 #ifdef AF_INET6
1114 		af = AF_INET6;
1115 		alen = NS_IN6ADDRSZ;
1116 #else
1117 #ifdef HAVE_ASYNC_DNS
1118 		if (!asyncdns || !lookup_pass)
1119 #endif
1120 			fputs(ipstr, stdout);
1121 		return;
1122 #endif
1123 	} else {
1124 		af = AF_INET;
1125 		alen = NS_INADDRSZ;
1126 	}
1127 
1128 #ifdef HAVE_ASYNC_DNS
1129 	if (asyncdns && lookup_pass) {
1130 		if (inet_pton(af, ipstr, addr) != 1)
1131 			return;
1132 
1133 		/* Done if already in hash table */
1134 		if (lookupaddr(addr, alen, af) != NULL)
1135 			return;
1136 
1137 		p = cacheaddr(addr, STATE_SENTPTR, alen, af, NULL);
1138 		if (p == NULL)
1139 			return;
1140 
1141 		/* Handle rate limiting */
1142 		ratelimit();
1143 
1144 		if (nb_dns_addr_request2(nd, addr, af,
1145 		    (void *)p, errstr) >= 0) {
1146 			/* Cache the fact that we're looking */
1147 			++numasync;
1148 			++num;
1149 		} else
1150 			fprintf(stderr, "%s: nb_dns_host_request: %s\n",
1151 			    prog, errstr);
1152 		/* reap replies after we send a number of queries */
1153 		if (num > 10) {
1154 			asyncreap(0);
1155 			num = 0;
1156 		}
1157 		return;
1158 	}
1159 #endif
1160 
1161 	/* Only attempt to translate one address per line */
1162 	if (linemode && triedone) {
1163 		fputs(ipstr, stdout);
1164 		return;
1165 	}
1166 	++triedone;
1167 
1168 	if (inet_pton(af, ipstr, addr) == 1)
1169 		hnstr = addr2host(addr, alen, af);
1170 	else
1171 		hnstr = NULL;
1172 	fputs(format(efmt, hnstr, ipstr), stdout);
1173 }
1174 
1175 struct htable *
hash(const char * ap,int af)1176 hash(const char *ap, int af)
1177 {
1178 	u_int32_t h;
1179 
1180 	switch (af) {
1181 
1182 	case AF_INET:
1183 		memmove(&h, ap, sizeof(h));
1184 		break;
1185 
1186 	case AF_INET6:
1187 		memmove(&h, ap + NS_IN6ADDRSZ - sizeof(h), sizeof(h));
1188 		break;
1189 
1190 	default:
1191 		abort();
1192 	}
1193 	return (&htable[h & (HSIZE - 1)]);
1194 }
1195 
1196 #ifdef SIGINFO
1197 RETSIGTYPE
info(int signo)1198 info(int signo)
1199 {
1200 	doinfo = 1;
1201 	return RETSIGVAL;
1202 }
1203 #endif
1204 
1205 #ifdef HAVE_ASYNC_DNS
1206 int
ispipe(FILE * f)1207 ispipe(FILE *f)
1208 {
1209 	struct stat sbuf;
1210 
1211 	if (fstat(fileno(f), &sbuf) < 0) {
1212 		fprintf(stderr, "%s: fstat: %s\n", prog, strerror(errno));
1213 		exit(1);
1214 	}
1215 	if ((sbuf.st_mode & S_IFMT) != S_IFREG)
1216 		return (1);
1217 	return (0);
1218 }
1219 #endif
1220 
1221 void
reportinfo(void)1222 reportinfo(void)
1223 {
1224 	struct timeval now, delta;
1225 
1226 	gettime(&now);
1227 	timersub(&now, &startts, &delta);
1228 	(void)fprintf(stderr, "[%d file%s, %ld querie%s,"
1229 	    " %ld.%03ld seconds, %ld cache hit%s, %.1f queries/sec]\n",
1230 	    filecount, PLURAL(filecount),
1231 	    querycount, PLURAL(querycount),
1232 	    delta.tv_sec, delta.tv_usec / 100,
1233 	    cachehits, PLURAL(cachehits),
1234 	    calculaterate());
1235 }
1236 
1237 void
usage()1238 usage()
1239 {
1240 
1241 	(void)fprintf(stderr, "Version %s\n", version);
1242 	(void)fprintf(stderr, "usage: %s [-1abcdilN] [-f format] [-R qps]"
1243 	    " [-t secs] [file ...]\n", prog);
1244 	(void)fprintf(stderr, "       %s -x [file ...]\n", prog);
1245 	exit(1);
1246 }
1247