1 /*-
2  * Copyright (c) 2001, 2002, 2003, 2004, 2006, 2010, 2011, 2013
3  *	Thorsten Glaser <tg@mirbsd.org>
4  *
5  * Provided that these terms and disclaimer and all copyright notices
6  * are retained or reproduced in an accompanying document, permission
7  * is granted to deal in this work without restriction, including un-
8  * limited rights to use, publicly perform, distribute, sell, modify,
9  * merge, give away, or sublicence.
10  *
11  * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
12  * the utmost extent permitted by applicable law, neither express nor
13  * implied; without malicious intent or gross negligence. In no event
14  * may a licensor, author or contributor be held liable for indirect,
15  * direct, other damage, loss, or other issues arising in any way out
16  * of dealing in the work, even if advised of the possibility of such
17  * damage or existence of a defect, except proven that it results out
18  * of said person's immediate fault when using the work as intended.
19  *-
20  * Based upon code by:
21  * Copyright (c) 1985, 1989 Regents of the University of California.
22  * Copyright (c) by Eric Wassenaar, Nikhef-H, <e07@nikhef.nl>
23  */
24 
25 /*
26  *		Usage: host [options] name [server]
27  *		Usage: host [options] -x [name ...]
28  *		Usage: host [options] -X server [name ...]
29  *
30  * Regular command line options:
31  * ----------------------------
32  *
33  * -t type	specify query type; default is T_A for normal mode
34  * -a		specify query type T_ANY
35  * -v		print verbose messages (-vv is very verbose)
36  * -d		print debugging output (-dd prints even more)
37  *
38  * Special mode options.
39  * --------------------
40  *
41  * -l		special mode to generate zone listing for a zone
42  * -L level	do recursive zone listing/checking this level deep
43  * -p		use primary nameserver of zone for zone transfers
44  * -P server	give priority to preferred servers for zone transfers
45  * -N zone	do not perform zone transfer for these explicit zones
46  * -S		print zone resource record statistics
47  * -H		special mode to count hosts residing in a zone
48  * -G		same as -H but lists gateway hosts in addition
49  * -E		same as -H but lists extrazone hosts in addition
50  * -D		same as -H but lists duplicate hosts in addition
51  * -C		special mode to check SOA records for a zone
52  * -A		special mode to check reverse mappings of host addresses
53  *
54  * Miscellaneous options.
55  * ---------------------
56  *
57  * -f filename	log resource record output also in given file
58  * -F filename	same as -f, but exchange role of stdout and log file
59  * -I chars	chars are not considered illegal in domain names
60  * -i		generate reverse in-addr.arpa query for dotted quad
61  * -n		generate reverse nsap.int query for dotted nsap address
62  * -q		be quiet about some non-fatal errors
63  * -T		print ttl value during non-verbose output
64  * -Z		print selected RR output in full zone file format
65  *
66  * Seldom used options.
67  * -------------------
68  *
69  * -c class	specify query class; default is C_IN
70  * -e		exclude info from names that do not reside in the zone
71  * -m		specify query type T_MAILB and trace MB records
72  * -o		suppress resource record output to stdout
73  * -r		do not use recursion when querying nameserver
74  * -R		repeatedly add search domains to qualify queryname
75  * -s secs	specify timeout value in seconds; default is 2 * 5
76  * -u		use virtual circuit instead of datagram for queries
77  * -w		wait until nameserver becomes available
78  *
79  * Undocumented options. (Experimental, subject to change)
80  * --------------------
81  *
82  * -g length	only select names that are at least this long
83  * -B		enforce full BIND behavior during DNSRCH
84  * -M		special mode to list mailable delegated zones of zone
85  * -W		special mode to list wildcard records in a zone
86  * -z		special mode to list delegated zones in a zone
87  */
88 
89 static const char Usage[] =
90 "\
91 Usage:	 host [-v] [-a] [-t querytype] [options] name [server]\n\
92 Listing: host [-v] [-a] [-t querytype] [options] -l zone [server]\n\
93 Hostcnt: host [-v] [opts] -H [-D] [-E] [-G] zone\n\
94 Chk soa: host [-v] [opts] -C zone\n\
95 Addrchk: host [-v] [opts] -A host\n\
96 Listing opts: [-L level] [-S] [-A] [-p] [-P prefserver] [-N skipzone]\n\
97 Common opts:  [-d] [-f|-F filename] [-I chars] [-i|-n] [-q] [-T] [-Z]\n\
98 Other opts:   [-c class] [-e] [-m] [-o] [-r] [-R] [-s secs] [-u] [-w]\n\
99 Ext. usage:   [-x [name ...]] [-X server [name ...]]\n\
100 ";
101 static const char version[] = "961113-MirOS-20110418";
102 
103 #include <sys/param.h>
104 #include <sys/socket.h>
105 #include <sys/time.h>
106 
107 #include <netinet/in.h>
108 #include <arpa/inet.h>
109 #include <arpa/nameser.h>
110 #include <netdb.h>
111 #include <ctype.h>
112 #include <errno.h>
113 #include <resolv.h>
114 #include <setjmp.h>
115 #include <signal.h>
116 #include <stdbool.h>
117 #include <stdio.h>
118 #include <stdlib.h>
119 #include <string.h>
120 #include <time.h>
121 #include <unistd.h>
122 
123 #ifndef __MirBSD__
124 #ifdef USE_LIBBSD
125 #include <bsd/string.h>
126 #endif
127 
128 #undef __IDSTRING
129 #undef __IDSTRING_CONCAT
130 #undef __IDSTRING_EXPAND
131 #undef __COPYRIGHT
132 #undef __RCSID
133 #undef __SCCSID
134 #define __IDSTRING_CONCAT(l,p)		__LINTED__ ## l ## _ ## p
135 #define __IDSTRING_EXPAND(l,p)		__IDSTRING_CONCAT(l,p)
136 #define __IDSTRING(prefix, string)				\
137 	static const char __IDSTRING_EXPAND(__LINE__,prefix) []	\
138 	    __attribute__((__used__)) = "@(""#)" #prefix ": " string
139 #define __COPYRIGHT(x)		__IDSTRING(copyright,x)
140 #define __RCSID(x)		__IDSTRING(rcsid,x)
141 #define __SCCSID(x)		__IDSTRING(sccsid,x)
142 
143 extern  u_int16_t       _getshort(const unsigned char *);
144 extern  u_int32_t       _getlong(const unsigned char *);
145 #endif
146 
147 __SCCSID("@(#)host.c	e07@nikhef.nl (Eric Wassenaar) 961013");
148 __RCSID("$MirOS: src/usr.bin/host/host.c,v 1.8 2013/10/31 20:07:04 tg Exp $");
149 
150 #ifndef NO_DATA
151 #define NO_DATA	NO_ADDRESS	/* used here only in case authoritative */
152 #endif
153 #define NO_RREC	(NO_DATA + 1)	/* used for non-authoritative NO_DATA */
154 #define NO_HOST	(NO_DATA + 2)	/* used for non-authoritative HOST_NOT_FOUND */
155 #define QUERY_REFUSED  (NO_DATA + 3)	/* query was refused by server */
156 #define SERVER_FAILURE (NO_DATA + 4)	/* instead of TRY_AGAIN upon SERVFAIL */
157 #define HOST_NOT_CANON (NO_DATA + 5)	/* host name is not canonical */
158 #define T_NONE	0		/* yet unspecified resource record type */
159 #define T_FIRST	T_A		/* first possible type in resource record */
160 #define T_LAST	(T_IXFR - 1)	/* last  possible type in resource record */
161 #ifndef NOCHANGE
162 #define NOCHANGE 0xf		/* compatibility with older BIND versions */
163 #endif
164 #define NOT_DOTTED_QUAD	((ipaddr_t)-1)
165 #define BROADCAST_ADDR	((ipaddr_t)0xffffffff)
166 #define LOCALHOST_ADDR	((ipaddr_t)0x7f000001)
167 #if 0
168 #if PACKETSZ > 8192
169 #define MAXPACKET PACKETSZ	/* PACKETSZ should be the max udp size (512) */
170 #else
171 #define MAXPACKET 8192		/* but tcp packets can be considerably larger */
172 #endif
173 #else /* !0 */
174 #define MAXPACKET 262144	/* accommodate large AXFR */
175 #endif
176 #ifndef HFIXEDSZ
177 #define HFIXEDSZ 12		/* actually sizeof(HEADER) */
178 #endif
179 #define MAXDLEN (MAXPACKET - HFIXEDSZ)	/* upper bound for dlen */
180 #define STDERR	2
181 #define STDIN	0
182 #define STDOUT	1
183 #define assert(condition)
184 #define bitset(a,b)	(((a) & (b)) != 0)
185 #define fakeaddr(a)	(nulladdr(a) || ((a) == htonl(LOCALHOST_ADDR)))
186 #define fakename(a)	(samehead(a,"localhost.") || samehead(a,"loopback."))
187 #define hexdigit(n)	(((n) < 10) ? '0' + (n) : 'A' + (n) - 10);
188 #define in_string(s,c)	(index(s,c) != NULL)
189 #define incopy(a)	*((struct in_addr *)(a))
190 #define input			/* read-only input parameter */
191 #define is_alnum(c)	(isascii(c) && isalnum(c))
192 #define is_quoted(a,b)	(((a) > (b)) && ((a)[-1] == '\\'))
193 #define is_space(c)	(isascii(c) && isspace(c))
194 #define is_upper(c)	(isascii(c) && isupper(c))
195 #define is_xdigit(c)	(isascii(c) && isxdigit(c))
196 #define lower(c)	(((c) >= 'A' && (c) <= 'Z') ? (c) + 'a' - 'A' : (c))
197 #define lowercase(c)	(is_upper(c) ? tolower(c) : (c))
198 #define newlist(a,n,t)	(t *)xalloc((ptr_t *)(a), (siz_t)((n)*sizeof(t)))
199 #define newstr(s)	strncpy(newstring(s), s, (size_t)(strlen(s)+1))
200 #define newstring(s)	(char *)xalloc((ptr_t *)NULL, (siz_t)(strlen(s)+1))
201 #define newstruct(t)	(t *)xalloc((ptr_t *)NULL, (siz_t)(sizeof(t)))
202 #define nulladdr(a)	(((a) == 0) || ((a) == BROADCAST_ADDR))
203 #define output			/* modified output parameter */
204 #define plural(n)	(((n) == 1) ? "" : "s")
205 #define plurale(n)	(((n) == 1) ? "" : "es")
206 #define querysize(n)	(((n) > sizeof(querybuf)) ? sizeof(querybuf) : (n))
207 #define samehead(a,b)	(strncasecmp(a,b,sizeof(b)-1) == 0)
208 #define samepart(a,b)	(strncasecmp(a,b,strlen(b)) == 0)
209 #define sameword(a,b)	(strcasecmp(a,b) == 0)
210 #define setalarm(n)	(void) alarm((unsigned int)(n))
211 #define strlength(s)	(int)strlen(s)
212 #define xfree(a)	(void) free((ptr_t *)(a))
213 #define ARPA_ROOT	"in-addr.arpa"
214 #ifndef IPNG_ROOT
215 #define IPNG_ROOT	"ip6.int"
216 #endif
217 #ifndef NSAP_ROOT
218 #define NSAP_ROOT	"nsap.int"
219 #endif
220 #define MAXNSAP		20	/* maximum size of encoded NSAP address */
221 #define T_LOC_VERSION	0	/* must be zero */
222 #define	MAXMD5BITS	2552
223 #define	MAXMD5SIZE	(2*((MAXMD5BITS+7)/8)+3)
224 #define	MAXB64SIZE	(4*((MAXMD5SIZE+2)/3))
225 #ifndef NAMESERVER_PORT
226 #define NAMESERVER_PORT	53
227 #endif
228 #define MAXCHAIN	10	/* maximum count of recursive chain lookups */
229 #define MAXALIAS	35	/* maximum aliases count from gethnamaddr.c */
230 #define MAXADDRS	35	/* maximum address count from gethnamaddr.c */
231 #define MAXNSNAME	16	/* maximum count of nameservers per zone */
232 #define MAXIPADDR	10	/* maximum count of addresses per nameserver */
233 #define DEF_RETRIES	2	/* number of datagram retries per nameserver */
234 #define DEF_RETRANS	5	/* timeout (seconds) between datagram retries */
235 #define CONNTIMEOUT	5	/* connect timeout (value _res.retrans used) */
236 #define READTIMEOUT	60	/* read timeout (seconds) during stream I/O */
237 #define DBPREFIX	";; "
238 #undef  EX_OK			/* defined in <unistd.h> on SVR4 */
239 #define EX_SUCCESS	0	/* successful termination */
240 #define EX_USAGE	64	/* command line usage error */
241 #define EX_DATAERR	65	/* data format error */
242 #define EX_NOINPUT	66	/* cannot open input */
243 #define EX_NOUSER	67	/* addressee unknown */
244 #define EX_NOHOST	68	/* host name unknown */
245 #define EX_UNAVAILABLE	69	/* service unavailable */
246 #define EX_SOFTWARE	70	/* internal software error */
247 #define EX_OSERR	71	/* system error (e.g., can't fork) */
248 #define EX_OSFILE	72	/* critical OS file missing */
249 #define EX_CANTCREAT	73	/* can't create (user) output file */
250 #define EX_IOERR	74	/* input/output error */
251 #define EX_TEMPFAIL	75	/* temp failure; user is invited to retry */
252 #define EX_PROTOCOL	76	/* remote error in protocol */
253 #define EX_NOPERM	77	/* permission denied */
254 #define EX_CONFIG	78	/* local configuration error */
255 #if defined(SYSV) || defined(SVR4)
256 #define SYSV_MALLOC
257 #define SYSV_MEMSET
258 #define SYSV_STRCHR
259 #define SYSV_SETVBUF
260 #endif
261 #define BIND_49
262 #define BIND_493
263 #ifndef INT16SZ
264 #define	INT16SZ		2	/* for systems without 16-bit ints */
265 #endif
266 #ifndef INT32SZ
267 #define	INT32SZ		4	/* for systems without 32-bit ints */
268 #endif
269 #ifndef INADDRSZ
270 #define	INADDRSZ	4	/* for sizeof(struct inaddr) != 4 */
271 #endif
272 #define	IPNGSIZE	16	/* 128 bit ip v6 address size */
273 #define linebufmode(a)	(void) setlinebuf(a);
274 #define nslist(i)	_res.nsaddr_list[i]
275 #ifdef fp_nquery
276 #define pr_query(a,n,f)	fp_nquery(a,n,f)
277 #else
278 #define pr_query(a,n,f)	fp_query(a,f)
279 #endif
280 #define PROTO(TYPES)	()
281 #define MAXSTRING 255		/* maximum size of single encoded string */
282 #define MAXSTRLEN MAXDLEN	/* maximum size of multiple substrings */
283 #define t_rr		data.data_rr
284 #define t_a		data.data_a
285 #define t_ns		data.data_ns
286 #define t_md		data.data_md
287 #define t_mf		data.data_mf
288 #define t_cname		data.data_cname
289 #define t_soa		data.data_soa
290 #define t_mb		data.data_mb
291 #define t_mg		data.data_mg
292 #define t_mr		data.data_mr
293 #define t_null		data.data_null
294 #define t_wks		data.data_wks
295 #define t_ptr		data.data_ptr
296 #define t_hinfo		data.data_hinfo
297 #define t_minfo		data.data_minfo
298 #define t_mx		data.data_mx
299 #define t_txt		data.data_txt
300 #define t_rp		data.data_rp
301 #define t_afsdb		data.data_afsdb
302 #define t_x25		data.data_x25
303 #define t_isdn		data.data_isdn
304 #define t_rt		data.data_rt
305 #define t_nsap		data.data_nsap
306 #define t_nsapptr	data.data_nsapptr
307 #define t_sig		data.data_sig
308 #define t_key		data.data_key
309 #define t_px		data.data_px
310 #define t_gpos		data.data_gpos
311 #define t_aaaa		data.data_aaaa
312 #define t_loc		data.data_loc
313 #define t_nxt		data.data_nxt
314 #define t_srv		data.data_srv
315 #define t_naptr		data.data_naptr
316 #define t_uinfo		data.data_uinfo
317 #define t_uid		data.data_uid
318 #define t_gid		data.data_gid
319 #define t_unspec	data.data_unspec
320 #ifndef C_CSNET
321 #define C_CSNET		2
322 #endif
323 #ifndef C_CHAOS
324 #define C_CHAOS		3
325 #endif
326 #ifndef C_HS
327 #define C_HS		4
328 #endif
329 #ifndef T_MD
330 #define T_MD		3
331 #endif
332 #ifndef T_MF
333 #define T_MF		4
334 #endif
335 #ifndef T_MB
336 #define T_MB		7
337 #endif
338 #ifndef T_MG
339 #define T_MG		8
340 #endif
341 #ifndef T_MR
342 #define T_MR		9
343 #endif
344 #ifndef T_NULL
345 #define T_NULL		10
346 #endif
347 #ifndef T_MINFO
348 #define T_MINFO		14
349 #endif
350 #ifndef T_TXT
351 #define T_TXT		16
352 #endif
353 #ifndef T_RP
354 #define T_RP		17
355 #endif
356 #ifndef T_AFSDB
357 #define T_AFSDB		18
358 #endif
359 #ifndef T_X25
360 #define T_X25		19
361 #endif
362 #ifndef T_ISDN
363 #define T_ISDN		20
364 #endif
365 #ifndef T_RT
366 #define T_RT		21
367 #endif
368 #ifndef T_NSAP
369 #define T_NSAP		22
370 #endif
371 #ifndef T_NSAPPTR
372 #define T_NSAPPTR	23
373 #endif
374 #ifndef T_SIG
375 #define T_SIG		24
376 #endif
377 #ifndef T_KEY
378 #define T_KEY		25
379 #endif
380 #ifndef T_PX
381 #define T_PX		26
382 #endif
383 #ifndef T_GPOS
384 #define T_GPOS		27
385 #endif
386 #ifndef T_AAAA
387 #define T_AAAA		28
388 #endif
389 #ifndef T_LOC
390 #define T_LOC		29
391 #endif
392 #ifndef T_NXT
393 #define T_NXT		30
394 #endif
395 #ifndef T_EID
396 #define T_EID		31
397 #endif
398 #ifndef T_NIMLOC
399 #define T_NIMLOC	32
400 #endif
401 #ifndef T_SRV
402 #define T_SRV		33
403 #endif
404 #ifndef T_ATMA
405 #define T_ATMA		34
406 #endif
407 #ifndef T_NAPTR
408 #define T_NAPTR		35
409 #endif
410 #ifndef T_UINFO
411 #define T_UINFO		100
412 #endif
413 #ifndef T_UID
414 #define T_UID		101
415 #endif
416 #ifndef T_GID
417 #define T_GID		102
418 #endif
419 #ifndef T_UNSPEC
420 #define T_UNSPEC	103
421 #endif
422 #ifndef T_IXFR
423 #define T_IXFR		251
424 #endif
425 #ifndef T_AXFR
426 #define T_AXFR		252
427 #endif
428 #ifndef T_MAILB
429 #define T_MAILB		253
430 #endif
431 #ifndef T_MAILA
432 #define T_MAILA		254
433 #endif
434 #define dbprefix ""
435 
436 typedef struct __res_state	res_state_t;
437 
438 typedef u_char		rrec_t;
439 
440 typedef u_char	qbuf_t;
441 
442 typedef char	nbuf_t;
443 
444 typedef u_int	ipaddr_t;
445 
446 typedef struct rr_data {
447 	u_char databuf[MAXDLEN];	/* generic data buffer */
448 } rr_data_t;
449 
450 typedef struct a_data {
451 	ipaddr_t address;		/* internet address of host */
452 } a_data_t;
453 
454 typedef struct ns_data {
455 	char nameserver[MAXDNAME+1];	/* name of domain nameserver */
456 } ns_data_t;
457 
458 typedef struct md_data {
459 	char destination[MAXDNAME+1];	/* name of mail destination */
460 } md_data_t;
461 
462 typedef struct mf_data {
463 	char forwarder[MAXDNAME+1];	/* name of mail forwarder */
464 } mf_data_t;
465 
466 typedef struct cname_data {
467 	char canonical[MAXDNAME+1];	/* canonical domain name */
468 } cname_data_t;
469 
470 typedef struct soa_data {
471 	char primary[MAXDNAME+1];	/* name of primary nameserver */
472 	char hostmaster[MAXDNAME+1];	/* name of hostmaster mailbox */
473 	int serial;			/* serial (version) number */
474 	int refresh;			/* refresh time in seconds */
475 	int retry;			/* refresh retry time in seconds */
476 	int expire;			/* expiration time in seconds */
477 	int defttl;			/* default time_to_live */
478 } soa_data_t;
479 
480 typedef struct mb_data {
481 	char mailhost[MAXDNAME+1];	/* name of mailbox host */
482 } mb_data_t;
483 
484 typedef struct mg_data {
485 	char memberbox[MAXDNAME+1];	/* mailbox of mail group member */
486 } mg_data_t;
487 
488 typedef struct mr_data {
489 	char aliasbox[MAXDNAME+1];	/* mailbox of mail alias */
490 } mr_data_t;
491 
492 typedef struct null_data {
493 	u_char nullbuf[MAXDLEN];	/* generic data buffer */
494 } null_data_t;
495 
496 typedef struct wks_data {
497 	ipaddr_t servaddress;		/* internet address of host */
498 	int protocol;			/* protocol number */
499 	u_char services[32];		/* ports 0-255 */
500 } wks_data_t;
501 
502 typedef struct ptr_data {
503 	char domain[MAXDNAME+1];	/* domain name of pointer */
504 } ptr_data_t;
505 
506 typedef struct hinfo_data {
507 	char cputype[MAXSTRING+1];	/* machine description */
508 	char ostype[MAXSTRING+1];	/* operating system type */
509 } hinfo_data_t;
510 
511 typedef struct minfo_data {
512 	char ownerbox[MAXDNAME+1];	/* name of owner mailbox */
513 	char errorbox[MAXDNAME+1];	/* name of error mailbox */
514 } minfo_data_t;
515 
516 typedef struct mx_data {
517 	int preference;			/* preference value */
518 	char mxhost[MAXDNAME+1];	/* name of mx host */
519 } mx_data_t;
520 
521 typedef struct txt_data {
522 	char text[MAXSTRLEN+1];		/* multiple substrings */
523 } txt_data_t;
524 
525 typedef struct rp_data {
526 	char mailbox[MAXDNAME+1];	/* name of person mailbox */
527 	char txtinfo[MAXDNAME+1];	/* name of description txt record */
528 } rp_data_t;
529 
530 typedef struct afsdb_data {
531 	int afstype;			/* type of afs server */
532 	char afshost[MAXDNAME+1];	/* name of afs server */
533 } afsdb_data_t;
534 
535 typedef struct x25_data {
536 	char psdnaddress[MAXSTRING+1];	/* x25 psdn address */
537 } x25_data_t;
538 
539 typedef struct isdn_data {
540 	char isdnaddress[MAXSTRING+1];	/* isdn address */
541 	char isdnsubaddr[MAXSTRING+1];	/* isdn subaddress */
542 } isdn_data_t;
543 
544 typedef struct rt_data {
545 	int routepref;			/* preference value */
546 	char routehost[MAXDNAME+1];	/* name of route-through host */
547 } rt_data_t;
548 
549 typedef struct nsap_data {
550 	u_char nsapaddr[MAXNSAP];	/* binary nsap address */
551 } nsap_data_t;
552 
553 typedef struct nsapptr_data {
554 	char nsapdomain[MAXDNAME+1];	/* domain name of nsap pointer */
555 } nsapptr_data_t;
556 
557 typedef struct sig_data {
558 	int sigtype;			/* resource record type covered */
559 	int algorithm;			/* signature encoding algorithm */
560 	int nlabels;			/* number of labels in SIG name */
561 	int sigttl;			/* original ttl of SIG record */
562 	time_t expiretime;		/* signature expiration time */
563 	time_t sigtime;			/* time signature was signed */
564 	int footprint;			/* key identification */
565 	char signer[MAXDNAME+1];	/* signer's domain name */
566 	u_char sig[MAXMD5SIZE];		/* encoded signature */
567 } sig_data_t;
568 
569 typedef struct key_data {
570 	int keyflags;			/* key description flags */
571 	int protocol;			/* protocol suite */
572 	int algorithm;			/* key encoding algorithm */
573 	u_char key[MAXMD5SIZE];		/* encoded key */
574 } key_data_t;
575 
576 typedef struct px_data {
577 	int mappref;			/* preference value */
578 	char map822[MAXDNAME+1];	/* rfc822 domain name */
579 	char mapx400[MAXDNAME+1];	/* x400 domain name */
580 } px_data_t;
581 
582 typedef struct gpos_data {
583 	char longpos[MAXSTRING+1];	/* geographical longitude */
584 	char latpos[MAXSTRING+1];	/* geographical latitude */
585 	char altpos[MAXSTRING+1];	/* geographical altitude */
586 } gpos_data_t;
587 
588 typedef struct aaaa_data {
589 	u_char ipngaddr[IPNGSIZE];	/* binary ip v6 address */
590 } aaaa_data_t;
591 
592 typedef struct loc_data {
593 	int locversion;			/* version number */
594 	int objectsize;			/* size of object */
595 	int hprecision;			/* horizontal precision */
596 	int vprecision;			/* vertical precision */
597 	int longitude;			/* geographical longitude */
598 	int latitude;			/* geographical latitude */
599 	int altitude;			/* geographical altitude */
600 } loc_data_t;
601 
602 typedef struct nxt_data {
603 	char nxtdomain[MAXDNAME+1];	/* name of next domain in order */
604 	u_char typemap[32];		/* types 0-255 */
605 } nxt_data_t;
606 
607 typedef struct srv_data {
608 	int srvpref;			/* preference value */
609 	int srvweight;			/* load balancing weight */
610 	int srvport;			/* port of service */
611 	char srvhost[MAXDNAME+1];	/* name of service host */
612 } srv_data_t;
613 
614 typedef struct naptr_data {
615 	int naorder;
616 	int napref;			/* preference value */
617 	char naflags[MAXSTRING+1];	/* flags */
618 	char naservice[MAXSTRING+1];
619 	char naregexp[MAXSTRING+1];
620 	char nahost[MAXDNAME+1];	/* name of naming authority host */
621 } naptr_data_t;
622 
623 typedef struct uinfo_data {
624 	char userinfo[MAXSTRLEN+1];	/* user description */
625 } uinfo_data_t;
626 
627 typedef struct uid_data {
628 	int userid;			/* user uid */
629 } uid_data_t;
630 
631 typedef struct gid_data {
632 	int groupid;			/* user gid */
633 } gid_data_t;
634 
635 typedef struct unspec_data {
636 	u_char unspecbuf[MAXDLEN];	/* generic data buffer */
637 } unspec_data_t;
638 
639 typedef struct rrecord {
640 	char	name[MAXDNAME+1];	/* resource record name */
641 	int	type;			/* resource record type */
642 	int	class;			/* resource record class */
643 	int	ttl;			/* time_to_live value */
644 	union {
645 		rr_data_t	data_rr;
646 		a_data_t	data_a;
647 		ns_data_t	data_ns;
648 		md_data_t	data_md;
649 		mf_data_t	data_mf;
650 		cname_data_t	data_cname;
651 		soa_data_t	data_soa;
652 		mb_data_t	data_mb;
653 		mg_data_t	data_mg;
654 		mr_data_t	data_mr;
655 		null_data_t	data_null;
656 		wks_data_t	data_wks;
657 		ptr_data_t	data_ptr;
658 		hinfo_data_t	data_hinfo;
659 		minfo_data_t	data_minfo;
660 		mx_data_t	data_mx;
661 		txt_data_t	data_txt;
662 		rp_data_t	data_rp;
663 		afsdb_data_t	data_afsdb;
664 		x25_data_t	data_x25;
665 		isdn_data_t	data_isdn;
666 		rt_data_t	data_rt;
667 		nsap_data_t	data_nsap;
668 		nsapptr_data_t	data_nsapptr;
669 		sig_data_t	data_sig;
670 		key_data_t	data_key;
671 		px_data_t	data_px;
672 		gpos_data_t	data_gpos;
673 		aaaa_data_t	data_aaaa;
674 		loc_data_t	data_loc;
675 		nxt_data_t	data_nxt;
676 		srv_data_t	data_srv;
677 		naptr_data_t	data_naptr;
678 		uinfo_data_t	data_uinfo;
679 		uid_data_t	data_uid;
680 		gid_data_t	data_gid;
681 		unspec_data_t	data_unspec;
682 	} data;
683 } rrecord_t;
684 
685 typedef union {
686         HEADER header;
687         u_char packet[MAXPACKET];
688 } querybuf;
689 
690 #if defined(_BSD_SIGNALS)
691 typedef int	sigtype_t;
692 #else
693 typedef void	sigtype_t;
694 #endif
695 
696 #if defined(SYSV_MALLOC)
697 typedef void	ptr_t;		/* generic pointer type */
698 typedef u_int	siz_t;		/* general size type */
699 typedef void	free_t;
700 #else
701 typedef char	ptr_t;		/* generic pointer type */
702 typedef u_int	siz_t;		/* general size type */
703 typedef int	free_t;
704 #endif
705 
706 FILE *logfile = NULL;		/* default is stdout only */
707 bool addrmode = false;		/* check reverse mappings of addresses */
708 bool bindcompat = false;	/* enforce full BIND DNSRCH compatibility */
709 bool checkmode = false;		/* check SOA records at each nameserver */
710 bool classprint = false;	/* print class value in non-verbose mode */
711 bool dotprint = false;		/* print trailing dot in non-listing mode */
712 bool duplmode = false;		/* list duplicate hosts within zone */
713 bool exclusive = false;		/* exclude records that are not in zone */
714 bool extrmode = false;		/* list extrazone hosts within zone */
715 bool gatemode = false;		/* list gateway hosts within zone */
716 bool hostmode = false;		/* count real hosts residing within zone */
717 bool listmode = false;		/* generate zone listing of a zone */
718 bool listzones = false;		/* list only delegated zones in a zone */
719 bool logexchange = false;	/* exchange role of log file and stdout */
720 bool mailmode = false;		/* trace MG and MR into MB records */
721 bool mxdomains = false;		/* list MX records for each delegated zone */
722 bool primary = false;		/* use primary server for zone transfers */
723 bool quiet = false;		/* suppress non-fatal warning messages */
724 bool recurskip = false;		/* skip certain checks during recursion */
725 bool reverse = false;		/* generate reverse in-addr.arpa queries */
726 bool revnsap = false;		/* generate reverse nsap.int queries */
727 bool statistics = false;	/* print resource record statistics */
728 bool suppress = false;		/* suppress resource record output */
729 bool ttlprint = false;		/* print ttl value in non-verbose mode */
730 bool waitmode = false;		/* wait until server becomes available */
731 bool wildcards = false;		/* list only wildcard records in a zone */
732 char **optargv = NULL;		/* argument list including default options */
733 char *adrname = NULL;		/* LHS domain name of A record */
734 char *cname = NULL;		/* RHS name to which CNAME is aliased */
735 char *illegal = NULL;		/* give warning about illegal domain names */
736 char *listhost = NULL;		/* actual host queried during zone listing */
737 char *mname = NULL;		/* RHS name to which MR or MG is aliased */
738 char *prefserver = NULL;	/* preferred server(s) for zone listing */
739 char *queryname = NULL;		/* the name about which to query */
740 char *realname = NULL;		/* the actual name that was queried */
741 char *server = NULL;		/* name of explicit server to query */
742 char *skipzone = NULL;		/* zone(s) for which to skip zone transfer */
743 char *soaname = NULL;		/* LHS domain name of SOA record */
744 char *subname = NULL;		/* LHS domain name of NS record */
745 char adrnamebuf[MAXDNAME+1];
746 char cnamebuf[MAXDNAME+1];
747 char mnamebuf[MAXDNAME+1];
748 char realnamebuf[2*MAXDNAME+2];
749 char serverbuf[MAXDNAME+1];
750 char soanamebuf[MAXDNAME+1];
751 char subnamebuf[MAXDNAME+1];
752 extern int errno;
753 extern int h_errno;		/* defined in the resolver library */
754 extern res_state_t _res;	/* defined in res_init.c */
755 int debug = 0;			/* print resolver debugging output */
756 int errorcount = 0;		/* global error count */
757 int namelen = 0;		/* select records exceeding this length */
758 int optargc = 0;		/* number of arguments in new argument list */
759 int print_level = 0;		/* level below which to skip verbose output */
760 int queryclass = C_IN;		/* the class of the query */
761 int querytype = T_NONE;		/* the type of the query */
762 int record_stats[T_ANY+1];	/* count of resource records per type */
763 int recursion_level = 0;	/* current recursion level */
764 int recursive = 0;		/* recursive listmode maximum level */
765 int skip_level = 0;		/* level beyond which to skip checks */
766 int verbose = 0;		/* verbose mode for extra output */
767 ipaddr_t address;		/* internet address of A record */
768 ipaddr_t queryaddr;		/* set if name to query is dotted quad */
769 static int timeout;		/* connection read timeout */
770 static struct sockaddr_in from;	/* address of inbound packet */
771 static struct sockaddr *from_sa = (struct sockaddr *)&from;
772 
773 bool check_addr		PROTO((char *));
774 bool check_dupl		PROTO((ipaddr_t));
775 bool check_name		PROTO((ipaddr_t));
776 bool check_ttl		PROTO((char *, int, int, int));
777 bool check_zone		PROTO((char *));
778 bool do_transfer	PROTO((char *));
779 bool execute		PROTO((char *, ipaddr_t));
780 bool find_servers	PROTO((char *));
781 bool get_domaininfo	PROTO((char *, char *));
782 bool get_hostinfo	PROTO((char *, bool));
783 bool get_mxrec		PROTO((char *));
784 bool get_nsinfo		PROTO((querybuf *, int, char *));
785 bool get_recursive	PROTO((char **));
786 bool get_servers	PROTO((char *));
787 bool get_soainfo	PROTO((querybuf *, int, char *));
788 bool get_zone		PROTO((char *, struct in_addr, char *));
789 bool gluerecord		PROTO((char *, char *, char **, int));
790 bool host_query		PROTO((char *, ipaddr_t));
791 bool indomain		PROTO((char *, char *, bool));
792 bool list_zone		PROTO((char *));
793 bool print_info		PROTO((querybuf *, int, char *, int, int, bool));
794 bool samedomain		PROTO((char *, char *, bool));
795 bool skip_transfer	PROTO((char *));
796 bool transfer_zone	PROTO((char *, struct in_addr, char *));
797 bool valid_name		PROTO((char *, bool, bool, bool));
798 bool want_class		PROTO((int, int));
799 bool want_type		PROTO((int, int));
800 char *base_ntoa		PROTO((u_char *, int));
801 char *decode_error	PROTO((int));
802 char *get_primary	PROTO((char *));
803 char *in_addr_arpa	PROTO((char *));
804 char *inet_ntoa		PROTO((struct in_addr));
805 char *ipng_ntoa		PROTO((u_char *));
806 char *itoa		PROTO((int));
807 char *mapreverse	PROTO((char *, struct in_addr));
808 char *myhostname	PROTO((void));
809 char *nsap_int		PROTO((char *));
810 char *nsap_ntoa		PROTO((u_char *, int));
811 char *pr_class		PROTO((int));
812 char *pr_date		PROTO((int));
813 char *pr_domain		PROTO((char *, bool));
814 char *pr_dotname	PROTO((char *));
815 char *pr_nsap		PROTO((char *));
816 char *pr_precision	PROTO((int));
817 char *pr_spherical	PROTO((int, char *, char *));
818 char *pr_time		PROTO((int, bool));
819 char *pr_type		PROTO((int));
820 char *pr_vertical	PROTO((int, char *, char *));
821 char *stoa		PROTO((u_char *, int, bool));
822 char *utoa		PROTO((int));
823 char *xtoa		PROTO((int));
824 int _res_connect	PROTO((int, struct sockaddr_in *, int));
825 int _res_read		PROTO((int, struct sockaddr_in *, char *, char *, int));
826 int _res_write		PROTO((int, struct sockaddr_in *, char *, char *, int));
827 int canonical		PROTO((char *));
828 int check_canon		PROTO((char *));
829 int check_size		PROTO((char *, int, u_char *, u_char *, u_char *, int));
830 int compare_name	PROTO((const ptr_t *, const ptr_t *));
831 int execute_name	PROTO((char *));
832 int expand_name		PROTO((char *, int, u_char *, u_char *, u_char *, char *));
833 int get_info		PROTO((querybuf *, char *, int, int));
834 int host_index		PROTO((char *, bool));
835 int main		PROTO((int, char **));
836 int matchlabels		PROTO((char *, char *));
837 int parse_class		PROTO((char *));
838 int parse_type		PROTO((char *));
839 int process_argv	PROTO((int, char **));
840 int process_file	PROTO((FILE *));
841 int process_name	PROTO((char *));
842 int zone_index		PROTO((char *, bool));
843 ptr_t *xalloc		PROTO((ptr_t *, siz_t));
844 static int recv_sock	PROTO((int, char *, int));
845 static sigtype_t timer	PROTO((int));
846 struct hostent *geth_byaddr	PROTO((const char *, int, int));
847 struct hostent *geth_byname	PROTO((const char *));
848 u_char *print_rrec	PROTO((char *, int, int, u_char *, u_char *, u_char *, bool));
849 u_char *skip_qrec	PROTO((char *, int, int, u_char *, u_char *, u_char *));
850 unsigned int alarm	PROTO((unsigned int));
851 void _res_perror	PROTO((struct sockaddr_in *, char *, char *));
852 void check_soa		PROTO((querybuf *, char *));
853 void clear_hosttab	PROTO((void));
854 void clear_statistics	PROTO((void));
855 void clear_ttltab	PROTO((void));
856 void clear_zonetab	PROTO((void));
857 void do_check		PROTO((char *));
858 void errmsg		PROTO((char *, ...));
859 void fatal		PROTO((char *, ...));
860 void ns_error		PROTO((char *, int, int, char *));
861 void pr_error		PROTO((char *, ...));
862 void pr_warning		PROTO((char *, ...));
863 void print_data		PROTO((char *, ...));
864 void print_host		PROTO((char *, struct hostent *));
865 void print_statistics	PROTO((char *, int, int));
866 void print_status	PROTO((querybuf *, int));
867 void set_defaults	PROTO((char *, int, char **));
868 void set_logfile	PROTO((char *));
869 void set_server		PROTO((char *));
870 void show_res		PROTO((void));
871 void show_types		PROTO((char *, int, int));
872 void sort_servers	PROTO((void));
873 void update_zone	PROTO((char *));
874 
875 char *
strxcpy(char * dst,char * src,size_t howmany)876 strxcpy(char *dst, char *src, size_t howmany)
877 {
878 	strlcpy(dst, src, howmany);
879 	return dst;
880 }
881 
882 /*
883  * Copyright (c) 1985, 1989 Regents of the University of California.
884  * All rights reserved.
885  *
886  * Redistribution and use in source and binary forms are permitted
887  * provided that source distributions retain this entire copyright
888  * notice and comment. Neither the name of the University nor the
889  * names of its contributors may be used to endorse or promote
890  * products derived from this software without specific prior
891  * written permission.
892  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
893  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
894  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
895  */
896 
897 /*
898  * Originally, this program came from Rutgers University, however it
899  * is based on nslookup and other pieces of named tools, so it needs
900  * that copyright notice.
901  */
902 
903 /*
904  * Rewritten by Eric Wassenaar, Nikhef-H, <e07@nikhef.nl>
905  *
906  * The officially maintained source of this program is available
907  * via anonymous ftp from machine 'ftp.nikhef.nl' [192.16.199.1]
908  * in the directory '/pub/network' as 'host.tar.Z'
909  *
910  * You are kindly requested to report bugs and make suggestions
911  * for improvements to the author at the given email address,
912  * and to not re-distribute your own modifications to others.
913  */
914 
915 /*
916 ** MAIN -- Start of program host
917 ** -----------------------------
918 **
919 **	Exits:
920 **		EX_SUCCESS	Operation successfully completed
921 **		EX_UNAVAILABLE	Could not obtain requested information
922 **		EX_CANTCREAT	Could not create specified log file
923 **		EX_NOINPUT	No input arguments were found
924 **		EX_NOHOST	Could not lookup explicit server
925 **		EX_OSERR	Could not obtain resources
926 **		EX_USAGE	Improper parameter/option specified
927 **		EX_SOFTWARE	Assertion botch in DEBUG mode
928 */
929 
930 int
main(argc,argv)931 main(argc, argv)
932 input int argc;
933 input char *argv[];
934 {
935 	register char *option;
936 	res_state_t new_res;		/* new resolver database */
937 	int result;			/* result status of action taken */
938 	char *program;			/* name that host was called with */
939 	char *servername = NULL;	/* name of explicit server */
940 	char *logfilename = NULL;	/* name of log file */
941 	bool extended = false;		/* accept extended argument syntax */
942 
943 	assert(sizeof(int) >= 4);	/* probably paranoid */
944 
945 /*
946  * Synchronize stdout and stderr in case output is redirected.
947  */
948 	linebufmode(stdout);
949 
950 /*
951  * Initialize resolver, set new defaults. See show_res() for details.
952  * The old defaults are (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
953  */
954 	(void) res_init();
955 
956 	_res.options |=  RES_DEFNAMES;	/* qualify single names */
957 	_res.options &= ~RES_DNSRCH;	/* dotted names are qualified */
958 
959 	_res.options |=  RES_RECURSE;	/* request nameserver recursion */
960 	_res.options &= ~RES_DEBUG;	/* turn off debug printout */
961 	_res.options &= ~RES_USEVC;	/* do not use virtual circuit */
962 
963 	_res.retry = DEF_RETRIES;	/* number of datagram retries */
964 	_res.retrans = DEF_RETRANS;	/* timeout in secs between retries */
965 
966 	/* initialize packet id */
967 	_res.id = res_randomid();
968 
969 	/* save new defaults */
970 	new_res = _res;
971 
972 /*
973  * Check whether host was called with a different name.
974  * Interpolate default options and parameters.
975  */
976 	if (argc < 1 || argv[0] == NULL)
977 		fatal(Usage);
978 
979 	option = getenv("HOST_DEFAULTS");
980 	if (option != NULL)
981 	{
982 		set_defaults(option, argc, argv);
983 		argc = optargc; argv = optargv;
984 	}
985 
986 	program = rindex(argv[0], '/');
987 	if (program++ == NULL)
988 		program = argv[0];
989 
990 	/* check for resource record names */
991 	querytype = parse_type(program);
992 	if (querytype < 0)
993 		querytype = T_NONE;
994 
995 	/* check for zone listing abbreviation */
996 	if (sameword(program, "zone"))
997 		listmode = true;
998 
999 /*
1000  * Scan command line options and flags.
1001  */
1002 	while (argc > 1 && argv[1] != NULL && argv[1][0] == '-')
1003 	{
1004 	    for (option = &argv[1][1]; *option != '\0'; option++)
1005 	    {
1006 		switch (*option)
1007 		{
1008 		    case 'w' :
1009 			waitmode = true;
1010 			new_res.retry = DEF_RETRIES;
1011 			new_res.retrans = DEF_RETRANS;
1012 			break;
1013 
1014 		    case 's' :
1015 			if (argv[2] == NULL || argv[2][0] == '-')
1016 				fatal("Missing timeout value");
1017 			new_res.retry = DEF_RETRIES;
1018 			new_res.retrans = atoi(argv[2]);
1019 			if (new_res.retrans <= 0)
1020 				fatal("Invalid timeout value %s", argv[2]);
1021 			argv++; argc--;
1022 			break;
1023 
1024 		    case 'r' :
1025 			new_res.options &= ~RES_RECURSE;
1026 			break;
1027 
1028 		    case 'B' :
1029 			bindcompat = true;
1030 			/*FALLTHROUGH*/
1031 
1032 		    case 'R' :
1033 			new_res.options |= RES_DNSRCH;
1034 			break;
1035 
1036 		    case 'u' :
1037 			new_res.options |= RES_USEVC;
1038 			break;
1039 
1040 		    case 'd' :
1041 			new_res.options |= RES_DEBUG;
1042 			debug++;		/* increment debugging level */
1043 			break;
1044 
1045 		    case 'v' :
1046 			verbose++;		/* increment verbosity level */
1047 			break;
1048 
1049 		    case 'q' :
1050 			quiet = true;
1051 			break;
1052 
1053 		    case 'i' :
1054 			reverse = true;
1055 			break;
1056 
1057 		    case 'n' :
1058 			revnsap = true;
1059 			break;
1060 
1061 		    case 'p' :
1062 			primary = true;
1063 			break;
1064 
1065 		    case 'o' :
1066 			suppress = true;
1067 			break;
1068 
1069 		    case 'e' :
1070 			exclusive = true;
1071 			break;
1072 
1073 		    case 'S' :
1074 			statistics = true;
1075 			break;
1076 
1077 		    case 'T' :
1078 			ttlprint = true;
1079 			break;
1080 
1081 		    case 'Z' :
1082 			dotprint = true;
1083 			ttlprint = true;
1084 			classprint = true;
1085 			break;
1086 
1087 		    case 'A' :
1088 			addrmode = true;
1089 			break;
1090 
1091 		    case 'D' :
1092 		    case 'E' :
1093 		    case 'G' :
1094 		    case 'H' :
1095 			if (*option == 'D')
1096 				duplmode = true;
1097 			if (*option == 'E')
1098 				extrmode = true;
1099 			if (*option == 'G')
1100 				gatemode = true;
1101 			hostmode = true;
1102 			listmode = true;
1103 			if (querytype == T_NONE)
1104 				querytype = -1;	/* suppress zone data output */
1105 			break;
1106 
1107 		    case 'C' :
1108 			checkmode = true;
1109 			listmode = true;
1110 			if (querytype == T_NONE)
1111 				querytype = -1;	/* suppress zone data output */
1112 			break;
1113 
1114 		    case 'z' :
1115 			listzones = true;
1116 			listmode = true;
1117 			if (querytype == T_NONE)
1118 				querytype = -1;	/* suppress zone data output */
1119 			break;
1120 
1121 		    case 'M' :
1122 			mxdomains = true;
1123 			listmode = true;
1124 			if (querytype == T_NONE)
1125 				querytype = -1;	/* suppress zone data output */
1126 			break;
1127 
1128 		    case 'W' :
1129 			wildcards = true;
1130 			listmode = true;
1131 			if (querytype == T_NONE)
1132 				querytype = T_MX;
1133 			break;
1134 
1135 		    case 'L' :
1136 			if (argv[2] == NULL || argv[2][0] == '-')
1137 				fatal("Missing recursion level");
1138 			recursive = atoi(argv[2]);
1139 			if (recursive <= 0)
1140 				fatal("Invalid recursion level %s", argv[2]);
1141 			argv++; argc--;
1142 			/*FALLTHROUGH*/
1143 
1144 		    case 'l' :
1145 			listmode = true;
1146 			break;
1147 
1148 		    case 'c' :
1149 			if (argv[2] == NULL || argv[2][0] == '-')
1150 				fatal("Missing query class");
1151 			queryclass = parse_class(argv[2]);
1152 			if (queryclass < 0)
1153 				fatal("Invalid query class %s", argv[2]);
1154 			argv++; argc--;
1155 			break;
1156 
1157 		    case 't' :
1158 			if (argv[2] == NULL || argv[2][0] == '-')
1159 				fatal("Missing query type");
1160 			querytype = parse_type(argv[2]);
1161 			if (querytype < 0)
1162 				fatal("Invalid query type %s", argv[2]);
1163 			argv++; argc--;
1164 			break;
1165 
1166 		    case 'a' :
1167 			querytype = T_ANY;	/* filter anything available */
1168 			break;
1169 
1170 		    case 'm' :
1171 			mailmode = true;
1172 			querytype = T_MAILB;	/* filter MINFO/MG/MR/MB data */
1173 			break;
1174 
1175 		    case 'I' :
1176 			if (argv[2] == NULL || argv[2][0] == '-')
1177 				fatal("Missing allowed chars");
1178 			illegal = argv[2];
1179 			argv++; argc--;
1180 			break;
1181 
1182 		    case 'P' :
1183 			if (argv[2] == NULL || argv[2][0] == '-')
1184 				fatal("Missing preferred server");
1185 			prefserver = argv[2];
1186 			argv++; argc--;
1187 			break;
1188 
1189 		    case 'N' :
1190 			if (argv[2] == NULL || argv[2][0] == '-')
1191 				fatal("Missing zone to be skipped");
1192 			skipzone = argv[2];
1193 			argv++; argc--;
1194 			break;
1195 
1196 		    case 'F' :
1197 			logexchange = true;
1198 			/*FALLTHROUGH*/
1199 
1200 		    case 'f' :
1201 			if (argv[2] == NULL || argv[2][0] == '-')
1202 				fatal("Missing log file name");
1203 			logfilename = argv[2];
1204 			argv++; argc--;
1205 			break;
1206 
1207 		    case 'X' :
1208 			if (argv[2] == NULL || argv[2][0] == '-')
1209 				fatal("Missing server name");
1210 			servername = argv[2];
1211 			argv++; argc--;
1212 			/*FALLTHROUGH*/
1213 
1214 		    case 'x' :
1215 			extended = true;
1216 			break;
1217 		    case 'g' :
1218 			if (argv[2] == NULL || argv[2][0] == '-')
1219 				fatal("Missing minimum length");
1220 			namelen = atoi(argv[2]);
1221 			if (namelen <= 0)
1222 				fatal("Invalid minimum length %s", argv[2]);
1223 			argv++; argc--;
1224 			break;
1225 		    case 'V' :
1226 			printf("Version %s\n", version);
1227 			exit(EX_SUCCESS);
1228 
1229 		    default:
1230 			fatal(Usage);
1231 		}
1232 	    }
1233 
1234 	    argv++; argc--;
1235 	}
1236 
1237 /*
1238  * Check the remaining arguments.
1239  */
1240 	/* old syntax must have at least one argument */
1241 	if (!extended && (argc < 2 || argv[1] == NULL || argc > 3))
1242 		fatal(Usage);
1243 
1244 	/* old syntax has explicit server as second argument */
1245 	if (!extended && (argc > 2 && argv[2] != NULL))
1246 		servername = argv[2];
1247 
1248 /*
1249  * Open log file if requested.
1250  */
1251 	if (logfilename != NULL)
1252 		set_logfile(logfilename);
1253 
1254 /*
1255  * Set default preferred server for zone listings, if not specified.
1256  */
1257 	if (listmode && (prefserver == NULL))
1258 		prefserver = myhostname();
1259 
1260 /*
1261  * Check for possible alternative server. Use new resolver defaults.
1262  */
1263 	if (servername != NULL)
1264 		set_server(servername);
1265 
1266 /*
1267  * Do final resolver initialization.
1268  * Show resolver parameters and special environment options.
1269  */
1270 	/* set new resolver values changed by command options */
1271 	_res.retry = new_res.retry;
1272 	_res.retrans = new_res.retrans;
1273 	_res.options = new_res.options;
1274 
1275 	/* show the new resolver database */
1276 	if (verbose > 1 || debug > 1)
1277 		show_res();
1278 
1279 	/* show customized default domain */
1280 	option = getenv("LOCALDOMAIN");
1281 	if (option != NULL && verbose > 1)
1282 		printf("Explicit local domain %s\n\n", option);
1283 
1284 /*
1285  * Process command line argument(s) depending on syntax.
1286  */
1287 	if (!extended) /* only one argument */
1288 		result = process_name(argv[1]);
1289 
1290 	else if (argc < 2) /* no arguments */
1291 		result = process_file(stdin);
1292 
1293 	else /* multiple command line arguments */
1294 		result = process_argv(argc, argv);
1295 
1296 /*
1297  * Report result status of action taken.
1298  */
1299 	exit(result);
1300 	/*NOTREACHED*/
1301 }
1302 
1303 /*
1304 ** SET_DEFAULTS -- Interpolate default options and parameters in argv
1305 ** ------------------------------------------------------------------
1306 **
1307 **	The HOST_DEFAULTS environment variable gives customized options.
1308 **
1309 **	Returns:
1310 **		None.
1311 **
1312 **	Outputs:
1313 **		Creates ``optargv'' vector with ``optargc'' arguments.
1314 */
1315 
1316 void
set_defaults(option,argc,argv)1317 set_defaults(option, argc, argv)
1318 input char *option;			/* option string */
1319 input int argc;				/* original command line arg count */
1320 input char *argv[];			/* original command line arguments */
1321 {
1322 	register char *p, *q;
1323 	register int i;
1324 
1325 /*
1326  * Allocate new argument vector.
1327  */
1328 	optargv = newlist(NULL, 2, char *);
1329 	optargv[0] = argv[0];
1330 	optargc = 1;
1331 
1332 /*
1333  * Construct argument list from option string.
1334  */
1335 	for (q = "", p = newstr(option); *p != '\0'; p = q)
1336 	{
1337 		while (is_space(*p))
1338 			p++;
1339 
1340 		if (*p == '\0')
1341 			break;
1342 
1343 		for (q = p; *q != '\0' && !is_space(*q); q++)
1344 			continue;
1345 
1346 		if (*q != '\0')
1347 			*q++ = '\0';
1348 
1349 		optargv = newlist(optargv, optargc+2, char *);
1350 		optargv[optargc] = p;
1351 		optargc++;
1352 	}
1353 
1354 /*
1355  * Append command line arguments.
1356  */
1357 	for (i = 1; i < argc && argv[i] != NULL; i++)
1358 	{
1359 		optargv = newlist(optargv, optargc+2, char *);
1360 		optargv[optargc] = argv[i];
1361 		optargc++;
1362 	}
1363 
1364 	/* and terminate */
1365 	optargv[optargc] = NULL;
1366 }
1367 
1368 /*
1369 ** PROCESS_ARGV -- Process command line arguments
1370 ** ----------------------------------------------
1371 **
1372 **	Returns:
1373 **		EX_SUCCESS if information was obtained successfully.
1374 **		Appropriate exit code otherwise.
1375 */
1376 
1377 int
process_argv(argc,argv)1378 process_argv(argc, argv)
1379 input int argc;
1380 input char *argv[];
1381 {
1382 	register int i;
1383 	int result;			/* result status of action taken */
1384 	int excode = EX_NOINPUT;	/* overall result status */
1385 
1386 	for (i = 1; i < argc && argv[i] != NULL; i++)
1387 	{
1388 		/* process a single argument */
1389 		result = process_name(argv[i]);
1390 
1391 		/* maintain overall result */
1392 		if (result != EX_SUCCESS || excode == EX_NOINPUT)
1393 			excode = result;
1394 	}
1395 
1396 	/* return overall result */
1397 	return(excode);
1398 }
1399 
1400 /*
1401 ** PROCESS_FILE -- Process arguments from input file
1402 ** -------------------------------------------------
1403 **
1404 **	Returns:
1405 **		EX_SUCCESS if information was obtained successfully.
1406 **		Appropriate exit code otherwise.
1407 */
1408 
1409 int
process_file(fp)1410 process_file(fp)
1411 input FILE *fp;				/* input file with query names */
1412 {
1413 	register char *p, *q;
1414 	char buf[BUFSIZ];
1415 	int result;			/* result status of action taken */
1416 	int excode = EX_NOINPUT;	/* overall result status */
1417 
1418 	while (fgets(buf, sizeof(buf), fp) != NULL)
1419 	{
1420 		p = index(buf, '\n');
1421 		if (p != NULL)
1422 			*p = '\0';
1423 
1424 		/* extract names separated by whitespace */
1425 		for (q = "", p = buf; *p != '\0'; p = q)
1426 		{
1427 			while (is_space(*p))
1428 				p++;
1429 
1430 			/* ignore comment lines */
1431 			if (*p == '\0' || *p == '#' || *p == ';')
1432 				break;
1433 
1434 			for (q = p; *q != '\0' && !is_space(*q); q++)
1435 				continue;
1436 
1437 			if (*q != '\0')
1438 				*q++ = '\0';
1439 
1440 			/* process a single argument */
1441 			result = process_name(p);
1442 
1443 			/* maintain overall result */
1444 			if (result != EX_SUCCESS || excode == EX_NOINPUT)
1445 				excode = result;
1446 		}
1447 	}
1448 
1449 	/* return overall result */
1450 	return(excode);
1451 }
1452 
1453 /*
1454 ** PROCESS_NAME -- Process a single command line argument
1455 ** ------------------------------------------------------
1456 **
1457 **	Returns:
1458 **		EX_SUCCESS if information was obtained successfully.
1459 **		Appropriate exit code otherwise.
1460 **
1461 **	Wrapper for execute_name() to hide administrative tasks.
1462 */
1463 
1464 int
process_name(name)1465 process_name(name)
1466 input char *name;			/* command line argument */
1467 {
1468 	int result;			/* result status of action taken */
1469 	static int save_querytype;
1470 	static bool save_reverse;
1471 	static bool firstname = true;
1472 
1473 	/* separate subsequent pieces of output */
1474 	if (!firstname && (verbose || debug || checkmode))
1475 		printf("\n");
1476 
1477 /*
1478  * Some global variables are redefined further on. Save their initial
1479  * values in the first pass, and restore them during subsequent passes.
1480  */
1481 	if (firstname)
1482 	{
1483 		save_querytype = querytype;
1484 		save_reverse = reverse;
1485 		firstname = false;
1486 	}
1487 	else
1488 	{
1489 		querytype = save_querytype;
1490 		reverse = save_reverse;
1491 	}
1492 
1493 /*
1494  * Do the real work.
1495  */
1496 	result = execute_name(name);
1497 	return(result);
1498 }
1499 
1500 /*
1501 ** EXECUTE_NAME -- Process a single command line argument
1502 ** ------------------------------------------------------
1503 **
1504 **	Returns:
1505 **		EX_SUCCESS if information was obtained successfully.
1506 **		Appropriate exit code otherwise.
1507 **
1508 **	Outputs:
1509 **		Defines ``queryname'' and ``queryaddr'' appropriately.
1510 **
1511 **	Side effects:
1512 **		May redefine ``querytype'' and ``reverse'' if necessary.
1513 */
1514 
1515 int
execute_name(name)1516 execute_name(name)
1517 input char *name;			/* command line argument */
1518 {
1519 	bool result;			/* result status of action taken */
1520 
1521 	/* check for nonsense input name */
1522 	if (strlength(name) > MAXDNAME)
1523 	{
1524 		errmsg("Query name %s too long", name);
1525 		return(EX_USAGE);
1526 	}
1527 
1528 /*
1529  * Analyze the name and type to be queried about.
1530  * The name can be an ordinary domain name, or an internet address
1531  * in dotted quad notation. If the -n option is given, the name is
1532  * supposed to be a dotted nsap address.
1533  * Furthermore, an empty input name is treated as the root domain.
1534  */
1535 	queryname = name;
1536 	if (queryname[0] == '\0')
1537 		queryname = ".";
1538 
1539 	if (sameword(queryname, "."))
1540 		queryaddr = NOT_DOTTED_QUAD;
1541 	else
1542 		queryaddr = inet_addr(queryname);
1543 
1544 /*
1545  * Generate reverse in-addr.arpa query if so requested.
1546  * The input name must be a dotted quad, and be convertible.
1547  */
1548 	if (reverse)
1549 	{
1550 		if (queryaddr == NOT_DOTTED_QUAD)
1551 			name = NULL;
1552 		else
1553 			name = in_addr_arpa(queryname);
1554 
1555 		if (name == NULL)
1556 		{
1557 			errmsg("Invalid dotted quad %s", queryname);
1558 			return(EX_USAGE);
1559 		}
1560 
1561 		/* redefine appropriately */
1562 		queryname = name;
1563 		queryaddr = NOT_DOTTED_QUAD;
1564 	}
1565 
1566 /*
1567  * Generate reverse nsap.int query if so requested.
1568  * The input name must be a dotted nsap, and be convertible.
1569  */
1570 	if (revnsap)
1571 	{
1572 		if (reverse)
1573 			name = NULL;
1574 		else
1575 			name = nsap_int(queryname);
1576 
1577 		if (name == NULL)
1578 		{
1579 			errmsg("Invalid nsap address %s", queryname);
1580 			return(EX_USAGE);
1581 		}
1582 
1583 		/* redefine appropriately */
1584 		queryname = name;
1585 		queryaddr = NOT_DOTTED_QUAD;
1586 
1587 		/* this is also a reversed mapping domain */
1588 		reverse = true;
1589 	}
1590 
1591 /*
1592  * In regular mode, the querytype is used to formulate the nameserver
1593  * query, and any response is filtered out when processing the answer.
1594  * In listmode, the querytype is used to filter out the proper records.
1595  */
1596 	/* set querytype for regular mode if unspecified */
1597 	if ((querytype == T_NONE) && !listmode)
1598 	{
1599 		if ((queryaddr != NOT_DOTTED_QUAD) || reverse)
1600 			querytype = T_PTR;
1601 		else
1602 			querytype = T_A;
1603 	}
1604 
1605 /*
1606  * Check for incompatible options.
1607  */
1608 	/* cannot have dotted quad in listmode */
1609 	if (listmode && (queryaddr != NOT_DOTTED_QUAD))
1610 	{
1611 		errmsg("Invalid query name %s", queryname);
1612 		return(EX_USAGE);
1613 	}
1614 
1615 	/* must have regular name or dotted quad in addrmode */
1616 	if (!listmode && addrmode && reverse)
1617 	{
1618 		errmsg("Invalid query name %s", queryname);
1619 		return(EX_USAGE);
1620 	}
1621 
1622 	/* show what we are going to query about */
1623 	if (verbose)
1624 		show_types(queryname, querytype, queryclass);
1625 
1626 /*
1627  * All set. Perform requested function.
1628  */
1629 	result = execute(queryname, queryaddr);
1630 	return(result ? EX_SUCCESS : EX_UNAVAILABLE);
1631 }
1632 
1633 /*
1634 ** EXECUTE -- Perform the requested function
1635 ** -----------------------------------------
1636 **
1637 **	Returns:
1638 **		true if information was obtained successfully.
1639 **		false otherwise.
1640 **
1641 **	The whole environment has been set up and checked.
1642 */
1643 
1644 bool
execute(name,addr)1645 execute(name, addr)
1646 input char *name;			/* name to query about */
1647 input ipaddr_t addr;			/* explicit address of query */
1648 {
1649 	bool result;			/* result status of action taken */
1650 
1651 /*
1652  * Special mode to list contents of specified zone.
1653  */
1654 	if (listmode)
1655 	{
1656 		result = list_zone(name);
1657 		return(result);
1658 	}
1659 
1660 /*
1661  * Special mode to check reverse mappings of host addresses.
1662  */
1663 	if (addrmode)
1664 	{
1665 		if (addr == NOT_DOTTED_QUAD)
1666 			result = check_addr(name);
1667 		else
1668 			result = check_name(addr);
1669 		return(result);
1670 	}
1671 
1672 /*
1673  * Regular mode to query about specified host.
1674  */
1675 	result = host_query(name, addr);
1676 	return(result);
1677 }
1678 
1679 /*
1680 ** HOST_QUERY -- Regular mode to query about specified host
1681 ** --------------------------------------------------------
1682 **
1683 **	Returns:
1684 **		true if information was obtained successfully.
1685 **		false otherwise.
1686 */
1687 
1688 bool
host_query(name,addr)1689 host_query(name, addr)
1690 input char *name;			/* name to query about */
1691 input ipaddr_t addr;			/* explicit address of query */
1692 {
1693 	struct hostent *hp;
1694 	struct in_addr inaddr;
1695 	char newnamebuf[MAXDNAME+1];
1696 	char *newname = NULL;		/* name to which CNAME is aliased */
1697 	int ncnames = 0;		/* count of CNAMEs in chain */
1698 	bool result;			/* result status of action taken */
1699 
1700 	inaddr.s_addr = addr;
1701 
1702 	result = false;
1703 	h_errno = TRY_AGAIN;
1704 
1705 	/* retry until positive result or permanent failure */
1706 	while (result == false && h_errno == TRY_AGAIN)
1707 	{
1708 		/* reset before each query to avoid stale data */
1709 		errno = 0;
1710 		realname = NULL;
1711 
1712 		if (addr == NOT_DOTTED_QUAD)
1713 		{
1714 			/* reset CNAME indicator */
1715 			cname = NULL;
1716 
1717 			/* lookup the name in question */
1718 			if (newname == NULL)
1719 				result = get_hostinfo(name, false);
1720 			else
1721 				result = get_hostinfo(newname, true);
1722 
1723 			/* recurse on CNAMEs, but not too deep */
1724 			if (cname && (querytype != T_CNAME))
1725 			{
1726 				newname = strxcpy(newnamebuf, cname, MAXDNAME + 1);
1727 
1728 				if (ncnames++ > MAXCHAIN)
1729 				{
1730 					errmsg("Possible CNAME loop");
1731 					return(false);
1732 				}
1733 
1734 				result = false;
1735 				h_errno = TRY_AGAIN;
1736 				continue;
1737 			}
1738 		}
1739 		else
1740 		{
1741 			hp = geth_byaddr((char *)&inaddr, INADDRSZ, AF_INET);
1742 			if (hp != NULL)
1743 			{
1744 				print_host("Name", hp);
1745 				result = true;
1746 			}
1747 		}
1748 
1749 		/* only retry if so requested */
1750 		if (!waitmode)
1751 			break;
1752 	}
1753 
1754 	/* use actual name if available */
1755 	if (realname != NULL)
1756 		name = realname;
1757 
1758 	/* explain the reason of a failure */
1759 	if (result == false)
1760 		ns_error(name, querytype, queryclass, server);
1761 
1762 	return(result);
1763 }
1764 
1765 /*
1766 ** MYHOSTNAME -- Determine our own fully qualified host name
1767 ** ---------------------------------------------------------
1768 **
1769 **	Returns:
1770 **		Pointer to own host name.
1771 **		Aborts if host name could not be determined.
1772 */
1773 
1774 char *
myhostname()1775 myhostname()
1776 {
1777 	struct hostent *hp;
1778 	static char mynamebuf[MAXDNAME+1];
1779 	static char *myname = NULL;
1780 
1781 	if (myname == NULL)
1782 	{
1783 		if (gethostname(mynamebuf, MAXDNAME) < 0)
1784 		{
1785 			perror("gethostname");
1786 			exit(EX_OSERR);
1787 		}
1788 		mynamebuf[MAXDNAME] = '\0';
1789 
1790 		hp = gethostbyname(mynamebuf);
1791 		if (hp == NULL)
1792 		{
1793 			ns_error(mynamebuf, T_A, C_IN, server);
1794 			errmsg("Error in looking up own name");
1795 			exit(EX_NOHOST);
1796 		}
1797 
1798 		/* cache the result */
1799 		myname = strncpy(mynamebuf, hp->h_name, MAXDNAME);
1800 		myname[MAXDNAME] = '\0';
1801 	}
1802 
1803 	return(myname);
1804 }
1805 
1806 /*
1807 ** SET_SERVER -- Override default nameserver with explicit server
1808 ** --------------------------------------------------------------
1809 **
1810 **	Returns:
1811 **		None.
1812 **		Aborts the program if an unknown host was given.
1813 **
1814 **	Side effects:
1815 **		The global variable ``server'' is set to indicate
1816 **		that an explicit server is being used.
1817 **
1818 **	The default nameserver addresses in the resolver database
1819 **	which are initialized by res_init() from /etc/resolv.conf
1820 **	are replaced with the (possibly multiple) addresses of an
1821 **	explicitly named server host. If a dotted quad is given,
1822 **	only that single address will be used.
1823 **
1824 **	The answers from such server must be interpreted with some
1825 **	care if we don't know beforehand whether it can be trusted.
1826 */
1827 
1828 void
set_server(name)1829 set_server(name)
1830 input char *name;			/* name of server to be queried */
1831 {
1832 	register int i;
1833 	struct hostent *hp;
1834 	struct in_addr inaddr;
1835 	ipaddr_t addr;			/* explicit address of server */
1836 
1837 	/* check for nonsense input name */
1838 	if (strlength(name) > MAXDNAME)
1839 	{
1840 		errmsg("Server name %s too long", name);
1841 		exit(EX_USAGE);
1842 	}
1843 
1844 /*
1845  * Overrule the default nameserver addresses.
1846  */
1847 	addr = inet_addr(name);
1848 	inaddr.s_addr = addr;
1849 
1850 	if (addr == NOT_DOTTED_QUAD)
1851 	{
1852 		/* lookup all of its addresses; this must not fail */
1853 		hp = gethostbyname(name);
1854 		if (hp == NULL)
1855 		{
1856 			ns_error(name, T_A, C_IN, server);
1857 			errmsg("Error in looking up server name");
1858 			exit(EX_NOHOST);
1859 		}
1860 
1861 		for (i = 0; i < MAXNS && hp->h_addr_list[i]; i++)
1862 		{
1863 			nslist(i).sin_family = AF_INET;
1864 			nslist(i).sin_port = htons(NAMESERVER_PORT);
1865 			nslist(i).sin_addr = incopy(hp->h_addr_list[i]);
1866 		}
1867 		_res.nscount = i;
1868 	}
1869 	else
1870 	{
1871 		/* lookup the name, but use only the given address */
1872 		hp = gethostbyaddr((char *)&inaddr, INADDRSZ, AF_INET);
1873 
1874 		nslist(0).sin_family = AF_INET;
1875 		nslist(0).sin_port = htons(NAMESERVER_PORT);
1876 		nslist(0).sin_addr = inaddr;
1877 		_res.nscount = 1;
1878 	}
1879 
1880 /*
1881  * Indicate the use of an explicit server.
1882  */
1883 	if (hp != NULL)
1884 	{
1885 		server = strncpy(serverbuf, hp->h_name, MAXDNAME);
1886 		server[MAXDNAME] = '\0';
1887 
1888 		if (verbose)
1889 			print_host("Server", hp);
1890 	}
1891 	else
1892 	{
1893 		server = strxcpy(serverbuf, inet_ntoa(inaddr), MAXDNAME+1);
1894 
1895 		if (verbose)
1896 			printf("Server: %s\n\n", server);
1897 	}
1898 }
1899 
1900 /*
1901 ** SET_LOGFILE -- Initialize optional log file
1902 ** -------------------------------------------
1903 **
1904 **	Returns:
1905 **		None.
1906 **		Aborts the program if the file could not be created.
1907 **
1908 **	Side effects:
1909 **		The global variable ``logfile'' is set to indicate
1910 **		that resource record output is to be written to it.
1911 **
1912 **	Swap ordinary stdout and log file output if so requested.
1913 */
1914 
1915 void
set_logfile(filename)1916 set_logfile(filename)
1917 input char *filename;			/* name of log file */
1918 {
1919 	if (logexchange)
1920 	{
1921 		logfile = fdopen(dup(STDOUT), "w");
1922 		if (logfile == NULL)
1923 		{
1924 			perror("fdopen");
1925 			exit(EX_OSERR);
1926 		}
1927 
1928 		if (freopen(filename, "w", stdout) == NULL)
1929 		{
1930 			perror(filename);
1931 			exit(EX_CANTCREAT);
1932 		}
1933 	}
1934 	else
1935 	{
1936 		logfile = fopen(filename, "w");
1937 		if (logfile == NULL)
1938 		{
1939 			perror(filename);
1940 			exit(EX_CANTCREAT);
1941 		}
1942 	}
1943 }
1944 
1945 /*
1946 ** FATAL -- Abort program when illegal option encountered
1947 ** ------------------------------------------------------
1948 **
1949 **	Returns:
1950 **		Aborts after issuing error message.
1951 */
1952 
1953 void /*VARARGS1*/
fatal(fmt,a,b,c,d)1954 fatal(fmt, a, b, c, d)
1955 input char *fmt;			/* format of message */
1956 input char *a, *b, *c, *d;		/* optional arguments */
1957 {
1958 	(void) fprintf(stderr, fmt, a, b, c, d);
1959 	(void) fprintf(stderr, "\n");
1960 	exit(EX_USAGE);
1961 }
1962 
1963 
1964 /*
1965 ** ERRMSG -- Issue error message to error output
1966 ** ---------------------------------------------
1967 **
1968 **	Returns:
1969 **		None.
1970 **
1971 **	Side effects:
1972 **		Increments the global error count.
1973 */
1974 
1975 void /*VARARGS1*/
errmsg(fmt,a,b,c,d)1976 errmsg(fmt, a, b, c, d)
1977 input char *fmt;			/* format of message */
1978 input char *a, *b, *c, *d;		/* optional arguments */
1979 {
1980 	(void) fprintf(stderr, fmt, a, b, c, d);
1981 	(void) fprintf(stderr, "\n");
1982 
1983 	/* flag an error */
1984 	errorcount++;
1985 }
1986 
1987 /*
1988 ** GET_HOSTINFO -- Principal routine to query about given name
1989 ** -----------------------------------------------------------
1990 **
1991 **	Returns:
1992 **		true if requested info was obtained successfully.
1993 **		false otherwise.
1994 **
1995 **	This is the equivalent of the resolver module res_search().
1996 **
1997 **	In this program RES_DEFNAMES is always on, and RES_DNSRCH
1998 **	is off by default. This means that single names without dot
1999 **	are always, and only, tried within the own default domain,
2000 **	and compound names are assumed to be already fully qualified.
2001 **
2002 **	The default BIND behavior can be simulated by turning on
2003 **	RES_DNSRCH with -R. The given name, whether or not compound,
2004 **	is then	first tried within the possible search domains.
2005 **
2006 **	Note. In the latter case, the search terminates in case the
2007 **	specified name exists but does not have the desired type.
2008 **	The BIND behavior is to continue the search. This can be
2009 **	simulated with the undocumented option -B.
2010 */
2011 
2012 bool
get_hostinfo(name,qualified)2013 get_hostinfo(name, qualified)
2014 input char *name;			/* name to query about */
2015 input bool qualified;			/* assume fully qualified if set */
2016 {
2017 	register char **domain;
2018 	register char *cp;
2019 	const char *hp;
2020 	int dot;			/* number of dots in query name */
2021 	bool result;			/* result status of action taken */
2022 	char oldnamebuf[2*MAXDNAME+2];
2023 	char *oldname = NULL;		/* saved actual name when NO_DATA */
2024 	int nodata = 0;			/* NO_DATA status during DNSRCH */
2025 	int nquery = 0;			/* number of extra search queries */
2026 
2027 /*
2028  * Single dot means root zone.
2029  */
2030 	if (sameword(name, "."))
2031 		qualified = true;
2032 
2033 /*
2034  * Names known to be fully qualified are just tried ``as is''.
2035  */
2036 	if (qualified)
2037 	{
2038 		result = get_domaininfo(name, (char *)NULL);
2039 		return(result);
2040 	}
2041 
2042 /*
2043  * Count number of dots. Move to the end of the name.
2044  */
2045 	for (dot = 0, cp = name; *cp != '\0'; cp++)
2046 		if (*cp == '.')
2047 			dot++;
2048 
2049 /*
2050  * Check for aliases of single name.
2051  * Note that the alias is supposed to be fully qualified.
2052  */
2053 	if (dot == 0 && (hp = hostalias(name)) != NULL)
2054 	{
2055 		if (verbose)
2056 			printf("Aliased %s to %s\n", name, hp);
2057 
2058 		result = get_domaininfo(hp, (char *)NULL);
2059 		return(result);
2060 	}
2061 
2062 /*
2063  * Trailing dot means absolute (fully qualified) address.
2064  */
2065 	if (dot != 0 && cp[-1] == '.')
2066 	{
2067 		cp[-1] = '\0';
2068 		result = get_domaininfo(name, (char *)NULL);
2069 		cp[-1] = '.';
2070 		return(result);
2071 	}
2072 
2073 /*
2074  * Append own default domain and other search domains if appropriate.
2075  */
2076 	if ((dot == 0 && bitset(RES_DEFNAMES, _res.options)) ||
2077 	    (dot != 0 && bitset(RES_DNSRCH, _res.options)))
2078 	{
2079 		for (domain = _res.dnsrch; *domain; domain++)
2080 		{
2081 			result = get_domaininfo(name, *domain);
2082 			if (result)
2083 				return(result);
2084 
2085 			/* keep count of extra search queries */
2086 			nquery++;
2087 
2088 			/* in case nameserver not present */
2089 			if (errno == ECONNREFUSED)
2090 				return(false);
2091 
2092 			/* if no further search desired (single name) */
2093 	    		if (!bitset(RES_DNSRCH, _res.options))
2094 				break;
2095 
2096 			/* if name exists but has not requested type */
2097 			if (h_errno == NO_DATA || h_errno == NO_RREC)
2098 			{
2099 				if (bindcompat)
2100 				{
2101 					/* remember status and search up */
2102 					oldname = strxcpy(oldnamebuf, realname, 2*MAXDNAME+2);
2103 					nodata = h_errno;
2104 					continue;
2105 				}
2106 
2107 				return(false);
2108 			}
2109 
2110 			/* retry only if name does not exist at all */
2111 			if (h_errno != HOST_NOT_FOUND && h_errno != NO_HOST)
2112 				break;
2113 		}
2114 	}
2115 
2116 /*
2117  * Single name lookup failed.
2118  */
2119 	if (dot == 0)
2120 	{
2121 		/* unclear what actual name should be */
2122 		if (nquery != 1)
2123 			realname = NULL;
2124 
2125 		/* restore nodata status from search */
2126 		if (bindcompat && nodata)
2127 		{
2128 			realname = strxcpy(realnamebuf, oldname, 2*MAXDNAME+2);
2129 			h_errno = nodata;
2130 		}
2131 
2132 		/* set status in case we never queried */
2133 		if (!bitset(RES_DEFNAMES, _res.options))
2134 			h_errno = HOST_NOT_FOUND;
2135 
2136 		return(false);
2137 	}
2138 
2139 /*
2140  * Rest means fully qualified.
2141  */
2142 	result = get_domaininfo(name, (char *)NULL);
2143 
2144 	/* restore nodata status from search */
2145 	if (!result && bindcompat && nodata)
2146 	{
2147 		realname = strxcpy(realnamebuf, oldname, 2*MAXDNAME+2);
2148 		h_errno = nodata;
2149 	}
2150 
2151 	return(result);
2152 }
2153 
2154 /*
2155 ** GET_DOMAININFO -- Fetch and print desired info about name in domain
2156 ** -------------------------------------------------------------------
2157 **
2158 **	Returns:
2159 **		true if requested info was obtained successfully.
2160 **		false otherwise.
2161 **
2162 **	Side effects:
2163 **		Sets global variable ``realname'' to actual name queried.
2164 **
2165 **	This is the equivalent of the resolver module res_querydomain().
2166 **
2167 **	Things get a little complicated in case RES_DNSRCH is on.
2168 **	If we get an answer but the data is corrupted, an error will be
2169 **	returned and NO_RECOVERY will be set. This will terminate the
2170 **	extra search loop, but a compound name will still be tried as-is.
2171 **	The same holds if the query times out or we have a server failure,
2172 **	in which case an error will be returned and TRY_AGAIN will be set.
2173 **	For now we take this for granted. Normally RES_DNSRCH is disabled.
2174 **	In this default case we do only one query and we have no problem.
2175 */
2176 
2177 bool
get_domaininfo(name,domain)2178 get_domaininfo(name, domain)
2179 input char *name;			/* name to query about */
2180 input char *domain;			/* domain to which name is relative */
2181 {
2182 	char namebuf[2*MAXDNAME+2];	/* buffer to store full domain name */
2183 	querybuf answer;
2184 	register int n;
2185 	bool result;			/* result status of action taken */
2186 
2187 /*
2188  * Show what we are about to query.
2189  */
2190 	if (verbose)
2191 	{
2192 		if (domain == NULL || domain[0] == '\0')
2193 			printf("Trying %s", name);
2194 		else
2195 			printf("Trying %s within %s", name, domain);
2196 
2197 		if (server && (verbose > 1))
2198 			printf(" at server %s", server);
2199 
2200 		printf(" ...\n");
2201 	}
2202 
2203 /*
2204  * Construct the actual domain name.
2205  * A null domain means the given name is already fully qualified.
2206  * If the composite name is too long, res_mkquery() will fail.
2207  */
2208 	if (domain == NULL || domain[0] == '\0')
2209 		(void) snprintf(namebuf, sizeof namebuf, "%.*s", MAXDNAME, name);
2210 	else
2211 		(void) snprintf(namebuf, sizeof namebuf, "%.*s.%.*s",
2212 				MAXDNAME, name, MAXDNAME, domain);
2213 	name = namebuf;
2214 
2215 /*
2216  * Fetch the desired info.
2217  */
2218 	n = get_info(&answer, name, querytype, queryclass);
2219 	result = (n < 0) ? false : true;
2220 
2221 /*
2222  * Print the relevant data.
2223  * If we got a positive answer, the data may still be corrupted.
2224  */
2225 	if (result)
2226 	    result = print_info(&answer, n, name, querytype, queryclass, true);
2227 
2228 /*
2229  * Remember the actual name that was queried.
2230  * Must be at the end to avoid clobbering during recursive calls.
2231  */
2232 	realname = strxcpy(realnamebuf, name, 2*MAXDNAME+2);
2233 
2234 	return(result);
2235 }
2236 
2237 /*
2238 ** GET_INFO -- Basic routine to issue a nameserver query
2239 ** -----------------------------------------------------
2240 **
2241 **	Returns:
2242 **		Length of nameserver answer buffer, if obtained.
2243 **		-1 if an error occurred (h_errno is set appropriately).
2244 **
2245 **	This is the equivalent of the resolver module res_query().
2246 */
2247 
2248 int
get_info(answerbuf,name,type,class)2249 get_info(answerbuf, name, type, class)
2250 output querybuf *answerbuf;		/* location of buffer to store answer */
2251 input char *name;			/* full name to query about */
2252 input int type;				/* specific resource record type */
2253 input int class;			/* specific resource record class */
2254 {
2255 	querybuf query;
2256 	HEADER *bp;
2257 	int ancount;
2258 	register int n;
2259 
2260 /*
2261  * Construct query, and send it to the nameserver.
2262  * res_send() will fail if no nameserver responded. In the BIND version the
2263  * possible values for errno are ECONNREFUSED and ETIMEDOUT. If we did get
2264  * an answer, errno should be reset, since res_send() may have left an errno
2265  * in case it has used datagrams. Our private version of res_send() will leave
2266  * also other error statuses, and will clear errno if an answer was obtained.
2267  */
2268 	errno = 0;	/* reset before querying nameserver */
2269 
2270 	n = res_mkquery(QUERY, name, class, type, (qbuf_t *)NULL, 0,
2271 			(rrec_t *)NULL, (qbuf_t *)&query, sizeof(querybuf));
2272 	if (n < 0)
2273 	{
2274 		if (debug)
2275 			printf("%sres_mkquery failed\n", dbprefix);
2276 		h_errno = NO_RECOVERY;
2277 		return(-1);
2278 	}
2279 
2280 	n = res_send((qbuf_t *)&query, n, (qbuf_t *)answerbuf, sizeof(querybuf));
2281 	if (n < 0)
2282 	{
2283 		if (debug)
2284 			printf("%sres_send failed\n", dbprefix);
2285 		h_errno = TRY_AGAIN;
2286 		return(-1);
2287 	}
2288 
2289 	errno = 0;	/* reset after we got an answer */
2290 
2291 	if (n < HFIXEDSZ)
2292 	{
2293 		pr_error("answer length %s too short after %s query for %s",
2294 			itoa(n), pr_type(type), name);
2295 		h_errno = NO_RECOVERY;
2296 		return(-1);
2297 	}
2298 
2299 /*
2300  * Analyze the status of the answer from the nameserver.
2301  */
2302 	if ((verbose > print_level) || debug)
2303 		print_status(answerbuf, n);
2304 
2305 	bp = (HEADER *)answerbuf;
2306 	ancount = ntohs(bp->ancount);
2307 
2308 	if (bp->rcode != NOERROR || ancount == 0)
2309 	{
2310 		switch (bp->rcode)
2311 		{
2312 		    case NXDOMAIN:
2313 			/* distinguish between authoritative or not */
2314 			h_errno = bp->aa ? HOST_NOT_FOUND : NO_HOST;
2315 			break;
2316 
2317 		    case NOERROR:
2318 			/* distinguish between authoritative or not */
2319 			h_errno = bp->aa ? NO_DATA : NO_RREC;
2320 			break;
2321 
2322 		    case SERVFAIL:
2323 			h_errno = SERVER_FAILURE; /* instead of TRY_AGAIN */
2324 			break;
2325 
2326 		    case REFUSED:
2327 			h_errno = QUERY_REFUSED; /* instead of NO_RECOVERY */
2328 			break;
2329 
2330 		    default:
2331 			h_errno = NO_RECOVERY; /* FORMERR NOTIMP NOCHANGE */
2332 			break;
2333 		}
2334 		return(-1);
2335 	}
2336 
2337 	/* valid answer received, avoid buffer overrun */
2338 	h_errno = 0;
2339 	return(querysize(n));
2340 }
2341 
2342 /*
2343 ** PRINT_INFO -- Check resource records in answer and print relevant data
2344 ** ----------------------------------------------------------------------
2345 **
2346 **	Returns:
2347 **		true if answer buffer was processed successfully.
2348 **		false otherwise.
2349 **
2350 **	Side effects:
2351 **		Will recurse on MAILB records if appropriate.
2352 **		See also side effects of the print_rrec() routine.
2353 */
2354 
2355 bool
print_info(answerbuf,answerlen,name,type,class,regular)2356 print_info(answerbuf, answerlen, name, type, class, regular)
2357 input querybuf *answerbuf;		/* location of answer buffer */
2358 input int answerlen;			/* length of answer buffer */
2359 input char *name;			/* full name we are querying about */
2360 input int type;				/* record type we are querying about */
2361 input int class;			/* record class we are querying about */
2362 input bool regular;			/* set if this is a regular lookup */
2363 {
2364 	HEADER *bp;
2365 	int qdcount, ancount, nscount, arcount;
2366 	u_char *msg, *eom;
2367 	register u_char *cp;
2368 
2369 	bp = (HEADER *)answerbuf;
2370 	qdcount = ntohs(bp->qdcount);
2371 	ancount = ntohs(bp->ancount);
2372 	nscount = ntohs(bp->nscount);
2373 	arcount = ntohs(bp->arcount);
2374 
2375 	msg = (u_char *)answerbuf;
2376 	eom = (u_char *)answerbuf + answerlen;
2377 	cp  = (u_char *)answerbuf + HFIXEDSZ;
2378 
2379 /*
2380  * Skip the query section in the response (present only in normal queries).
2381  */
2382 	if (qdcount)
2383 	{
2384 		while (qdcount > 0 && cp < eom)	/* process all records */
2385 		{
2386 			cp = skip_qrec(name, type, class, cp, msg, eom);
2387 			if (cp == NULL)
2388 				return(false);
2389 			qdcount--;
2390 		}
2391 
2392 		if (qdcount)
2393 		{
2394 			pr_error("invalid qdcount after %s query for %s",
2395 				pr_type(type), name);
2396 			h_errno = NO_RECOVERY;
2397 			return(false);
2398 		}
2399 	}
2400 
2401 /*
2402  * Process the actual answer section in the response.
2403  * During zone transfers, this is the only section available.
2404  */
2405 	if (ancount)
2406 	{
2407 		if ((type != T_AXFR) && verbose && !bp->aa)
2408 			printf("The following answer is not authoritative:\n");
2409 
2410 		while (ancount > 0 && cp < eom)
2411 		{
2412 			/* reset for each record during zone listings */
2413 			soaname = NULL, subname = NULL, adrname = NULL, address = 0;
2414 
2415 			print_level++;
2416 			cp = print_rrec(name, type, class, cp, msg, eom, regular);
2417 			print_level--;
2418 			if (cp == NULL)
2419 				return(false);
2420 			ancount--;
2421 
2422 			/* update zone information during zone listings */
2423 			if (type == T_AXFR)
2424 				update_zone(name);
2425 
2426 			/* we trace down CNAME chains ourselves */
2427 			if (regular && !verbose && cname)
2428 				return(true);
2429 
2430 			/* recursively expand MR/MG records into MB records */
2431 			if (regular && mailmode && mname)
2432 				(void) get_recursive(&mname);
2433 		}
2434 
2435 		if (ancount)
2436 		{
2437 			pr_error("invalid ancount after %s query for %s",
2438 				pr_type(type), name);
2439 			h_errno = NO_RECOVERY;
2440 			return(false);
2441 		}
2442 	}
2443 
2444 /*
2445  * The nameserver and additional info section are normally not processed.
2446  * Both sections shouldn't exist in zone transfers.
2447  */
2448 	if (!verbose || exclusive)
2449 		return(true);
2450 
2451 	if (nscount)
2452 	{
2453 		printf("Authoritative nameservers:\n");
2454 
2455 		while (nscount > 0 && cp < eom)
2456 		{
2457 			print_level++;
2458 			cp = print_rrec(name, type, class, cp, msg, eom, false);
2459 			print_level--;
2460 			if (cp == NULL)
2461 				return(false);
2462 			nscount--;
2463 		}
2464 
2465 		if (nscount)
2466 		{
2467 			pr_error("invalid nscount after %s query for %s",
2468 				pr_type(type), name);
2469 			h_errno = NO_RECOVERY;
2470 			return(false);
2471 		}
2472 	}
2473 
2474 	if (arcount)
2475 	{
2476 		printf("Additional information:\n");
2477 
2478 		while (arcount > 0 && cp < eom)
2479 		{
2480 			print_level++;
2481 			cp = print_rrec(name, type, class, cp, msg, eom, false);
2482 			print_level--;
2483 			if (cp == NULL)
2484 				return(false);
2485 			arcount--;
2486 		}
2487 
2488 		if (arcount)
2489 		{
2490 			pr_error("invalid arcount after %s query for %s",
2491 				pr_type(type), name);
2492 			h_errno = NO_RECOVERY;
2493 			return(false);
2494 		}
2495 	}
2496 
2497 	/* all sections were processed successfully */
2498 	return(true);
2499 }
2500 
2501 /*
2502 ** PRINT_DATA -- Output resource record data if this record is wanted
2503 ** ------------------------------------------------------------------
2504 **
2505 **	Returns:
2506 **		None.
2507 **
2508 **	Inputs:
2509 **		The global variable ``doprint'' is set by print_rrec()
2510 **		if we need to print the data.
2511 */
2512 
2513 static bool doprint;		/* indicates whether or not to print */
2514 
2515 void /*VARARGS1*/
print_data(fmt,a,b,c,d)2516 print_data(fmt, a, b, c, d)
2517 input char *fmt;			/* format of message */
2518 input char *a, *b, *c, *d;		/* optional arguments */
2519 {
2520 	/* if (doprint) */
2521 	{
2522 		if (!suppress)
2523 			printf(fmt, a, b, c, d);
2524 
2525 		if (logfile != NULL)
2526 			(void) fprintf(logfile, fmt, a, b, c, d);
2527 	}
2528 }
2529 
2530 #define doprintf(x)\
2531 {\
2532 	if (doprint)\
2533 	{\
2534 		print_data x ;\
2535 	}\
2536 }
2537 
2538 /*
2539 ** PRINT_RREC -- Decode single resource record and output relevant data
2540 ** --------------------------------------------------------------------
2541 **
2542 **	Returns:
2543 **		Pointer to position in answer buffer after current record.
2544 **		NULL if there was a format error in the current record.
2545 **
2546 **	Outputs:
2547 **		The global variable ``doprint'' is set appropriately
2548 **		for use by print_data().
2549 **
2550 **	Side effects:
2551 **		Updates resource record statistics in record_stats[].
2552 **		Sets ``soaname'' if this is an SOA record.
2553 **		Sets ``subname'' if this is an NS record.
2554 **		Sets ``adrname'' if this is an A record.
2555 **		Sets ``address'' if this is an A record.
2556 **		Sets ``cname'' if this is a valid CNAME record.
2557 **		Sets ``mname'' if this is a valid MAILB record.
2558 **		These variables must have been cleared before calling
2559 **		print_info() and may be checked afterwards.
2560 */
2561 
2562 /* print domain names after certain conversions */
2563 #define pr_name(x)	pr_domain(x, listing)
2564 
2565 /* check the LHS record name of these records for invalid characters */
2566 #define test_valid(t)	(((t == T_A) && !reverse) || t == T_MX || t == T_AAAA)
2567 
2568 /* check the RHS domain name of these records for canonical host names */
2569 #define test_canon(t)	(t == T_NS || t == T_MX)
2570 
2571 u_char *
print_rrec(name,qtype,qclass,cp,msg,eom,regular)2572 print_rrec(name, qtype, qclass, cp, msg, eom, regular)
2573 input char *name;			/* full name we are querying about */
2574 input int qtype;			/* record type we are querying about */
2575 input int qclass;			/* record class we are querying about */
2576 register u_char *cp;			/* current position in answer buf */
2577 input u_char *msg, *eom;		/* begin and end of answer buf */
2578 input bool regular;			/* set if this is a regular lookup */
2579 {
2580 	char rname[MAXDNAME+1];		/* record name in LHS */
2581 	char dname[MAXDNAME+1];		/* domain name in RHS */
2582 	int type, class, ttl, dlen;	/* fixed values in every record */
2583 	u_char *eor;			/* predicted position of next record */
2584 	bool classmatch;		/* set if we want to see this class */
2585 	bool listing;			/* set if this is a zone listing */
2586 	char *host = listhost;		/* contacted host for zone listings */
2587 	register int n, c;
2588 	struct in_addr inaddr;
2589 	struct protoent *protocol;
2590 	struct servent *service;
2591 
2592 /*
2593  * Pickup the standard values present in each resource record.
2594  */
2595 	n = expand_name(name, T_NONE, cp, msg, eom, rname);
2596 	if (n < 0)
2597 		return(NULL);
2598 	cp += n;
2599 
2600 	n = 3*INT16SZ + INT32SZ;
2601 	if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
2602 		return(NULL);
2603 
2604 	type = _getshort(cp);
2605 	cp += INT16SZ;
2606 
2607 	class = _getshort(cp);
2608 	cp += INT16SZ;
2609 
2610 	ttl = _getlong(cp);
2611 	cp += INT32SZ;
2612 
2613 	dlen = _getshort(cp);
2614 	cp += INT16SZ;
2615 
2616 	eor = cp + dlen;
2617 
2618 /*
2619  * Decide whether or not to print this resource record.
2620  */
2621 	listing = (qtype == T_AXFR || qtype == T_IXFR) ? true : false;
2622 
2623 	if (listing)
2624 	{
2625 		classmatch = want_class(class, queryclass);
2626 		doprint = classmatch && want_type(type, querytype);
2627 	}
2628 	else
2629 	{
2630 		classmatch = want_class(class, C_ANY);
2631 		doprint = classmatch && want_type(type, T_ANY);
2632 	}
2633 
2634 	if (doprint && exclusive && !indomain(rname, name, true))
2635 		doprint = false;
2636 
2637 	if (doprint && exclusive && fakename(rname))
2638 		doprint = false;
2639 
2640 	if (doprint && wildcards && !in_string(rname, '*'))
2641 		doprint = false;
2642 	if (namelen && (strlength(rname) < namelen))
2643 		doprint = false;
2644 
2645 /*
2646  * Print name and common values, if appropriate.
2647  */
2648 	doprintf(("%-20s", pr_name(rname)))
2649 
2650 	if (verbose || ttlprint)
2651 		doprintf(("\t%s", itoa(ttl)))
2652 
2653 	if (verbose || classprint || (class != qclass))
2654 		doprintf(("\t%s", pr_class(class)))
2655 
2656 	doprintf(("\t%s", pr_type(type)))
2657 
2658 /*
2659  * Update resource record statistics for zone listing.
2660  */
2661 	if (listing && classmatch)
2662 	{
2663 		if (type >= T_FIRST && type <= T_LAST)
2664 			record_stats[type]++;
2665 	}
2666 
2667 /*
2668  * Save the domain name of an SOA or NS or A record for zone listing.
2669  */
2670 	if (listing && classmatch)
2671 	{
2672 		if (type == T_A)
2673 			adrname = strxcpy(adrnamebuf, rname, MAXDNAME+1);
2674 
2675 		else if (type == T_NS)
2676 			subname = strxcpy(subnamebuf, rname, MAXDNAME+1);
2677 
2678 		else if (type == T_SOA)
2679 			soaname = strxcpy(soanamebuf, rname, MAXDNAME+1);
2680 	}
2681 
2682 /*
2683  * Print type specific data, if appropriate.
2684  */
2685 	switch (type)
2686 	{
2687 	    case T_A:
2688 		if (class == C_IN || class == C_HS)
2689 		{
2690 			if (dlen == INADDRSZ)
2691 			{
2692 				memmove((char *)&inaddr, (char *)cp, INADDRSZ);
2693 				address = inaddr.s_addr;
2694 				doprintf(("\t%s", inet_ntoa(inaddr)))
2695 				cp += INADDRSZ;
2696 				break;
2697 			}
2698 			address = 0;
2699 			break;
2700 		}
2701 		address = 0;
2702 		cp += dlen;
2703 		break;
2704 
2705 	    case T_MX:
2706 		if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
2707 			break;
2708 		n = _getshort(cp);
2709 		doprintf(("\t%s", itoa(n)))
2710 		cp += INT16SZ;
2711 
2712 		n = expand_name(rname, type, cp, msg, eom, dname);
2713 		if (n < 0)
2714 			break;
2715 		doprintf((" %s", pr_name(dname)))
2716 		cp += n;
2717 		break;
2718 
2719 	    case T_NS:
2720 	    case T_PTR:
2721 	    case T_CNAME:
2722 		n = expand_name(rname, type, cp, msg, eom, dname);
2723 		if (n < 0)
2724 			break;
2725 		doprintf(("\t%s", pr_name(dname)))
2726 		cp += n;
2727 		break;
2728 
2729 	    case T_HINFO:
2730 		if (check_size(rname, type, cp, msg, eor, 1) < 0)
2731 			break;
2732 		n = *cp++;
2733 		doprintf(("\t\"%s\"", stoa(cp, n, true)))
2734 		cp += n;
2735 
2736 		if (check_size(rname, type, cp, msg, eor, 1) < 0)
2737 			break;
2738 		n = *cp++;
2739 		doprintf(("\t\"%s\"", stoa(cp, n, true)))
2740 		cp += n;
2741 		break;
2742 
2743 	    case T_SOA:
2744 		n = expand_name(rname, type, cp, msg, eom, dname);
2745 		if (n < 0)
2746 			break;
2747 		doprintf(("\t%s", pr_name(dname)))
2748 		cp += n;
2749 
2750 		n = expand_name(rname, type, cp, msg, eom, dname);
2751 		if (n < 0)
2752 			break;
2753 		doprintf((" %s", pr_name(dname)))
2754 		cp += n;
2755 
2756 		n = 5*INT32SZ;
2757 		if (check_size(rname, type, cp, msg, eor, n) < 0)
2758 			break;
2759 		doprintf((" ("))
2760 
2761 		n = _getlong(cp);
2762 		doprintf(("\n\t\t\t%s", utoa(n)))
2763 		doprintf(("\t;serial (version)"))
2764 		cp += INT32SZ;
2765 
2766 		n = _getlong(cp);
2767 		doprintf(("\n\t\t\t%s", itoa(n)))
2768 		doprintf(("\t;refresh period (%s)", pr_time(n, false)))
2769 		cp += INT32SZ;
2770 
2771 		n = _getlong(cp);
2772 		doprintf(("\n\t\t\t%s", itoa(n)))
2773 		doprintf(("\t;retry interval (%s)", pr_time(n, false)))
2774 		cp += INT32SZ;
2775 
2776 		n = _getlong(cp);
2777 		doprintf(("\n\t\t\t%s", itoa(n)))
2778 		doprintf(("\t;expire time (%s)", pr_time(n, false)))
2779 		cp += INT32SZ;
2780 
2781 		n = _getlong(cp);
2782 		doprintf(("\n\t\t\t%s", itoa(n)))
2783 		doprintf(("\t;default ttl (%s)", pr_time(n, false)))
2784 		cp += INT32SZ;
2785 
2786 		doprintf(("\n\t\t\t)"))
2787 		break;
2788 
2789 	    case T_WKS:
2790 		if (check_size(rname, type, cp, msg, eor, INADDRSZ) < 0)
2791 			break;
2792 		memmove((char *)&inaddr, (char *)cp, INADDRSZ);
2793 		doprintf(("\t%s", inet_ntoa(inaddr)))
2794 		cp += INADDRSZ;
2795 
2796 		if (check_size(rname, type, cp, msg, eor, 1) < 0)
2797 			break;
2798 		n = *cp++;
2799 
2800 		protocol = getprotobynumber(n);
2801 		if (protocol != NULL)
2802 			doprintf((" %s", protocol->p_name))
2803 		else
2804 			doprintf((" %s", itoa(n)))
2805 
2806 		doprintf((" ("))
2807 		n = 0;
2808 		while (cp < eor)
2809 		{
2810 		    c = *cp++;
2811 		    do
2812 		    {
2813  			if (c & 0200)
2814 			{
2815 			    int port;
2816 
2817 			    port = htons(n);
2818 			    if (protocol != NULL)
2819 				    service = getservbyport(port, protocol->p_name);
2820 			    else
2821 				    service = NULL;
2822 
2823 			    if (service != NULL)
2824 				    doprintf((" %s", service->s_name))
2825 			    else
2826 				    doprintf((" %s", itoa(n)))
2827 			}
2828  			c <<= 1;
2829 		    } while (++n & 07);
2830 		}
2831 		doprintf((" )"))
2832 		break;
2833 
2834 
2835 	    case T_TXT:
2836 		if (check_size(rname, type, cp, msg, eor, 1) < 0)
2837 			break;
2838 		n = *cp++;
2839 		doprintf(("\t\"%s\"", stoa(cp, n, true)))
2840 		cp += n;
2841 
2842 		while (cp < eor)
2843 		{
2844 			if (check_size(rname, type, cp, msg, eor, 1) < 0)
2845 				break;
2846 			n = *cp++;
2847 			doprintf((" \"%s\"", stoa(cp, n, true)))
2848 			cp += n;
2849 		}
2850 		break;
2851 
2852 	    case T_MINFO:
2853 		n = expand_name(rname, type, cp, msg, eom, dname);
2854 		if (n < 0)
2855 			break;
2856 		doprintf(("\t%s", pr_name(dname)))
2857 		cp += n;
2858 
2859 		n = expand_name(rname, type, cp, msg, eom, dname);
2860 		if (n < 0)
2861 			break;
2862 		doprintf((" %s", pr_name(dname)))
2863 		cp += n;
2864 		break;
2865 
2866 	    case T_MB:
2867 	    case T_MG:
2868 	    case T_MR:
2869 	    case T_MD:
2870 	    case T_MF:
2871 		n = expand_name(rname, type, cp, msg, eom, dname);
2872 		if (n < 0)
2873 			break;
2874 		doprintf(("\t%s", pr_name(dname)))
2875 		cp += n;
2876 		break;
2877 
2878 	    case T_UID:
2879 	    case T_GID:
2880 		if (dlen == INT32SZ)
2881 		{
2882 			n = _getlong(cp);
2883 			doprintf(("\t%s", itoa(n)))
2884 			cp += INT32SZ;
2885 		}
2886 		break;
2887 
2888 	    case T_UINFO:
2889 		doprintf(("\t\"%s\"", stoa(cp, dlen, true)))
2890 		cp += dlen;
2891 		break;
2892 
2893 	    case T_RP:
2894 		n = expand_name(rname, type, cp, msg, eom, dname);
2895 		if (n < 0)
2896 			break;
2897 		doprintf(("\t%s", pr_name(dname)))
2898 		cp += n;
2899 
2900 		n = expand_name(rname, type, cp, msg, eom, dname);
2901 		if (n < 0)
2902 			break;
2903 		doprintf((" %s", pr_name(dname)))
2904 		cp += n;
2905 		break;
2906 
2907 	    case T_RT:
2908 		if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
2909 			break;
2910 		n = _getshort(cp);
2911 		doprintf(("\t%s", itoa(n)))
2912 		cp += INT16SZ;
2913 
2914 		n = expand_name(rname, type, cp, msg, eom, dname);
2915 		if (n < 0)
2916 			break;
2917 		doprintf((" %s", pr_name(dname)))
2918 		cp += n;
2919 		break;
2920 
2921 	    case T_AFSDB:
2922 		if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
2923 			break;
2924 		n = _getshort(cp);
2925 		doprintf(("\t%s", itoa(n)))
2926 		cp += INT16SZ;
2927 
2928 		n = expand_name(rname, type, cp, msg, eom, dname);
2929 		if (n < 0)
2930 			break;
2931 		doprintf((" %s", pr_name(dname)))
2932 		cp += n;
2933 		break;
2934 
2935 	    case T_X25:
2936 		if (check_size(rname, type, cp, msg, eor, 1) < 0)
2937 			break;
2938 		n = *cp++;
2939 		doprintf(("\t%s", stoa(cp, n, false)))
2940 		cp += n;
2941 		break;
2942 
2943 	    case T_ISDN:
2944 		if (check_size(rname, type, cp, msg, eor, 1) < 0)
2945 			break;
2946 		n = *cp++;
2947 		doprintf(("\t%s", stoa(cp, n, false)))
2948 		cp += n;
2949 
2950 		if (cp < eor)
2951 		{
2952 			if (check_size(rname, type, cp, msg, eor, 1) < 0)
2953 				break;
2954 			n = *cp++;
2955 			doprintf((" %s", stoa(cp, n, false)))
2956 			cp += n;
2957 		}
2958 		break;
2959 
2960 	    case T_NSAP:
2961 		doprintf(("\t0x%s", nsap_ntoa(cp, dlen)))
2962 		cp += dlen;
2963 		break;
2964 
2965 	    case T_NSAPPTR:
2966 		n = expand_name(rname, type, cp, msg, eom, dname);
2967 		if (n < 0)
2968 			break;
2969 		doprintf(("\t%s", pr_name(dname)))
2970 		cp += n;
2971 		break;
2972 
2973 	    case T_PX:
2974 		if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
2975 			break;
2976 		n = _getshort(cp);
2977 		doprintf(("\t%s", itoa(n)))
2978 		cp += INT16SZ;
2979 
2980 		n = expand_name(rname, type, cp, msg, eom, dname);
2981 		if (n < 0)
2982 			break;
2983 		doprintf((" %s", pr_name(dname)))
2984 		cp += n;
2985 
2986 		n = expand_name(rname, type, cp, msg, eom, dname);
2987 		if (n < 0)
2988 			break;
2989 		doprintf((" %s", pr_name(dname)))
2990 		cp += n;
2991 		break;
2992 
2993 	    case T_GPOS:
2994 		if (check_size(rname, type, cp, msg, eor, 1) < 0)
2995 			break;
2996 		n = *cp++;
2997 		doprintf(("\t%s", stoa(cp, n, false)))
2998 		cp += n;
2999 
3000 		if (check_size(rname, type, cp, msg, eor, 1) < 0)
3001 			break;
3002 		n = *cp++;
3003 		doprintf(("\t%s", stoa(cp, n, false)))
3004 		cp += n;
3005 
3006 		if (check_size(rname, type, cp, msg, eor, 1) < 0)
3007 			break;
3008 		n = *cp++;
3009 		doprintf(("\t%s", stoa(cp, n, false)))
3010 		cp += n;
3011 		break;
3012 
3013 	    case T_LOC:
3014 		if ((n = *cp) != T_LOC_VERSION)
3015 		{
3016 			pr_error("invalid version %s in %s record for %s",
3017 				itoa(n), pr_type(type), rname);
3018 			cp += dlen;
3019 			break;
3020 		}
3021 
3022 		n = INT32SZ + 3*INT32SZ;
3023 		if (check_size(rname, type, cp, msg, eor, n) < 0)
3024 			break;
3025 		c = _getlong(cp);
3026 		cp += INT32SZ;
3027 
3028 		n = _getlong(cp);
3029 		doprintf(("\t%s ", pr_spherical(n, "N", "S")))
3030 		cp += INT32SZ;
3031 
3032 		n = _getlong(cp);
3033 		doprintf((" %s ", pr_spherical(n, "E", "W")))
3034 		cp += INT32SZ;
3035 
3036 		n = _getlong(cp);
3037 		doprintf((" %sm ", pr_vertical(n, "", "-")))
3038 		cp += INT32SZ;
3039 
3040 		doprintf((" %sm", pr_precision((c >> 16) & 0xff)))
3041 		doprintf((" %sm", pr_precision((c >>  8) & 0xff)))
3042 		doprintf((" %sm", pr_precision((c >>  0) & 0xff)))
3043 		break;
3044 
3045 	    case T_UNSPEC:
3046 	    case T_NULL:
3047 		cp += dlen;
3048 		break;
3049 
3050 	    case T_AAAA:
3051 		if (dlen == IPNGSIZE)
3052 		{
3053 			doprintf(("\t%s", ipng_ntoa(cp)))
3054 			cp += IPNGSIZE;
3055 		}
3056 		break;
3057 
3058 	    case T_SIG:
3059 		if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
3060 			break;
3061 		n = _getshort(cp);
3062 		doprintf(("\t%s", pr_type(n)))
3063 		cp += INT16SZ;
3064 
3065 		if (check_size(rname, type, cp, msg, eor, 1) < 0)
3066 			break;
3067 		n = *cp++;
3068 		doprintf((" %s", itoa(n)))
3069 
3070 		n = 1 + 3*INT32SZ + INT16SZ;
3071 		if (check_size(rname, type, cp, msg, eor, n) < 0)
3072 			break;
3073 		doprintf((" ("))
3074 
3075 		n = *cp++;
3076 		doprintf(("\n\t\t\t; %s", itoa(n)))
3077 		doprintf(("\t\t;labels"))
3078 
3079 		n = _getlong(cp);
3080 		doprintf(("\n\t\t\t%s", itoa(n)))
3081 		doprintf(("\t\t;original ttl"))
3082 		cp += INT32SZ;
3083 
3084 		n = _getlong(cp);
3085 		doprintf(("\n\t\t\t%s", pr_date(n)))
3086 		doprintf(("\t;signature expiration"))
3087 		cp += INT32SZ;
3088 
3089 		n = _getlong(cp);
3090 		doprintf(("\n\t\t\t%s", pr_date(n)))
3091 		doprintf(("\t;signature signed time"))
3092 		cp += INT32SZ;
3093 
3094 		n = _getshort(cp);
3095 		doprintf(("\n\t\t\t%s", itoa(n)))
3096 		doprintf(("\t\t;key footprint"))
3097 		cp += INT16SZ;
3098 
3099 		n = expand_name(rname, type, cp, msg, eom, dname);
3100 		if (n < 0)
3101 			break;
3102 		doprintf(("\n\t\t\t%s", pr_name(dname)))
3103 		cp += n;
3104 
3105 		if (cp < eor)
3106 		{
3107 			register char *buf;
3108 			register int size;
3109 
3110 			n = eor - cp;
3111 			buf = base_ntoa(cp, n);
3112 			size = strlength(buf);
3113 			cp += n;
3114 
3115 			while ((n = (size > 64) ? 64 : size) > 0)
3116 			{
3117 				doprintf(("\n\t%s", stoa((u_char *)buf, n, false)))
3118 				buf += n; size -= n;
3119 			}
3120 		}
3121 
3122 		doprintf(("\n\t\t\t)"))
3123 		break;
3124 
3125 	    case T_KEY:
3126 		if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
3127 			break;
3128 		n = _getshort(cp);
3129 		doprintf(("\t0x%s", xtoa(n)))
3130 		cp += INT16SZ;
3131 
3132 		if (check_size(rname, type, cp, msg, eor, 1) < 0)
3133 			break;
3134 		n = *cp++;
3135 		doprintf((" %s", itoa(n)))
3136 
3137 		if (check_size(rname, type, cp, msg, eor, 1) < 0)
3138 			break;
3139 		n = *cp++;
3140 		doprintf((" %s", itoa(n)))
3141 
3142 		if (cp < eor)
3143 		{
3144 			register char *buf;
3145 			register int size;
3146 
3147 			n = eor - cp;
3148 			buf = base_ntoa(cp, n);
3149 			size = strlength(buf);
3150 			cp += n;
3151 
3152 			doprintf((" ("))
3153 			while ((n = (size > 64) ? 64 : size) > 0)
3154 			{
3155 				doprintf(("\n\t%s", stoa((u_char *)buf, n, false)))
3156 				buf += n; size -= n;
3157 			}
3158 			doprintf(("\n\t\t\t)"))
3159 		}
3160 		break;
3161 
3162 	    case T_NXT:
3163 		n = expand_name(rname, type, cp, msg, eom, dname);
3164 		if (n < 0)
3165 			break;
3166 		doprintf(("\t%s", pr_name(dname)))
3167 		cp += n;
3168 
3169 		n = 0;
3170 		while (cp < eor)
3171 		{
3172 		    c = *cp++;
3173 		    do
3174 		    {
3175  			if (c & 0200)
3176 			{
3177 			    doprintf((" %s", pr_type(n)))
3178 			}
3179  			c <<= 1;
3180 		    } while (++n & 07);
3181 		}
3182 		break;
3183 
3184 	    case T_SRV:
3185 		if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
3186 			break;
3187 		n = _getshort(cp);
3188 		doprintf(("\t%s", itoa(n)))
3189 		cp += INT16SZ;
3190 
3191 		if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
3192 			break;
3193 		n = _getshort(cp);
3194 		doprintf((" %s", itoa(n)))
3195 		cp += INT16SZ;
3196 
3197 		if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
3198 			break;
3199 		n = _getshort(cp);
3200 		doprintf((" %s", itoa(n)))
3201 		cp += INT16SZ;
3202 
3203 		n = expand_name(rname, type, cp, msg, eom, dname);
3204 		if (n < 0)
3205 			break;
3206 		doprintf((" %s", pr_name(dname)))
3207 		cp += n;
3208 		break;
3209 
3210 	    case T_EID:
3211 	    case T_NIMLOC:
3212 	    case T_ATMA:
3213 		doprintf(("\t\"not yet implemented\""))
3214 		cp += dlen;
3215 		break;
3216 
3217 	    case T_NAPTR:
3218 		if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
3219 			break;
3220 		n = _getshort(cp);
3221 		doprintf(("\t%s", itoa(n)))
3222 		cp += INT16SZ;
3223 
3224 		if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
3225 			break;
3226 		n = _getshort(cp);
3227 		doprintf((" %s", itoa(n)))
3228 		cp += INT16SZ;
3229 
3230 		if (check_size(rname, type, cp, msg, eor, 1) < 0)
3231 			break;
3232 		n = *cp++;
3233 		doprintf((" \"%s\"", stoa(cp, n, true)))
3234 		cp += n;
3235 
3236 		if (check_size(rname, type, cp, msg, eor, 1) < 0)
3237 			break;
3238 		n = *cp++;
3239 		doprintf((" \"%s\"", stoa(cp, n, true)))
3240 		cp += n;
3241 
3242 		if (check_size(rname, type, cp, msg, eor, 1) < 0)
3243 			break;
3244 		n = *cp++;
3245 		doprintf((" \"%s\"", stoa(cp, n, true)))
3246 		cp += n;
3247 
3248 		n = expand_name(rname, type, cp, msg, eom, dname);
3249 		if (n < 0)
3250 			break;
3251 		doprintf((" %s", pr_name(dname)))
3252 		cp += n;
3253 		break;
3254 	    default:
3255 		doprintf(("\t\"???\""))
3256 		cp += dlen;
3257 		break;
3258 	}
3259 
3260 /*
3261  * End of specific data type processing.
3262  * Terminate resource record printout.
3263  */
3264 	doprintf(("\n"))
3265 
3266 /*
3267  * Check whether we have reached the exact end of this resource record.
3268  * If not, we cannot be sure that the record has been decoded correctly,
3269  * and therefore the subsequent tests will be skipped.
3270  */
3271 	if (cp != eor)
3272 	{
3273 		pr_error("size error in %s record for %s, off by %s",
3274 			pr_type(type), rname, itoa(cp - eor));
3275 
3276 		/* we believe value of dlen; should perhaps return(NULL) */
3277 		return(eor);
3278 	}
3279 
3280 /*
3281  * Save the CNAME alias for cname chain tracing.
3282  * Save the MR or MG alias for MB chain tracing.
3283  * These features can be enabled only in normal mode.
3284  */
3285 	if (regular && classmatch)
3286 	{
3287 		if (type == T_CNAME)
3288 			cname = strxcpy(cnamebuf, dname, MAXDNAME+1);
3289 
3290 		else if (type == T_MR || type == T_MG)
3291 			mname = strxcpy(mnamebuf, dname, MAXDNAME+1);
3292 	}
3293 
3294 /*
3295  * Suppress the subsequent checks in quiet mode.
3296  * This can safely be done as there are no side effects.
3297  * It may speedup things, and nothing would be printed anyway.
3298  */
3299 	if (quiet)
3300 		return(cp);
3301 
3302 /*
3303  * In zone listings, resource records with the same name/type/class
3304  * must have the same ttl value. Maintain and check list of record info.
3305  * This is done on a per-zone basis.
3306  */
3307 	if (listing && !check_ttl(rname, type, class, ttl))
3308 	{
3309 		pr_warning("%s %s records have different ttl within %s from %s",
3310 			rname, pr_type(type), name, host);
3311 	}
3312 
3313 /*
3314  * Check validity of 'host' related domain names in certain resource records.
3315  * These include LHS record names and RHS domain names of selected records.
3316  * Currently underscores are not reported during deep recursive listings.
3317  */
3318 	if (test_valid(type) && !valid_name(rname, true, false, recurskip))
3319 	{
3320 		pr_warning("%s %s record has illegal name",
3321 			rname, pr_type(type));
3322 	}
3323 
3324 	if (test_canon(type) && !valid_name(dname, false, false, recurskip))
3325 	{
3326 		pr_warning("%s %s host %s has illegal name",
3327 			rname, pr_type(type), dname);
3328 	}
3329 
3330 /*
3331  * The RHS of various resource records should refer to a canonical host name,
3332  * i.e. it should exist and have an A record and not be a CNAME.
3333  * Currently this test is suppressed during deep recursive zone listings.
3334  */
3335 	if (!recurskip && test_canon(type) && ((n = check_canon(dname)) != 0))
3336 	{
3337 		/* only report definitive target host failures */
3338 		if (n == HOST_NOT_FOUND)
3339 			pr_warning("%s %s host %s does not exist",
3340 				rname, pr_type(type), dname);
3341 		else if (n == NO_DATA)
3342 			pr_warning("%s %s host %s has no A record",
3343 				rname, pr_type(type), dname);
3344 		else if (n == HOST_NOT_CANON)
3345 			pr_warning("%s %s host %s is not canonical",
3346 				rname, pr_type(type), dname);
3347 
3348 		/* authoritative failure to find nameserver target host */
3349 		if (type == T_NS && (n == NO_DATA || n == HOST_NOT_FOUND))
3350 		{
3351 			if (server == NULL)
3352 				errmsg("%s has lame delegation to %s",
3353 					rname, dname);
3354 		}
3355 	}
3356 
3357 /*
3358  * On request, reverse map the address of an A record, and verify that
3359  * it is registered and maps back to the name of the A record.
3360  * Currently this option has effect here only during zone listings.
3361  */
3362 	if (addrmode && ((type == T_A) && !reverse) && !fakeaddr(address))
3363 	{
3364 		host = mapreverse(rname, inaddr);
3365 		if (host == NULL)
3366 			pr_warning("%s address %s is not registered",
3367 				rname, inet_ntoa(inaddr));
3368 		else if (host != rname)
3369 			pr_warning("%s address %s maps to %s",
3370 				rname, inet_ntoa(inaddr), host);
3371 	}
3372 
3373 /*
3374  * This record was processed successfully.
3375  */
3376 	return(cp);
3377 }
3378 
3379 /*
3380 ** SKIP_QREC -- Skip the query record in the nameserver answer buffer
3381 ** ------------------------------------------------------------------
3382 **
3383 **	Returns:
3384 **		Pointer to position in answer buffer after current record.
3385 **		NULL if there was a format error in the current record.
3386 */
3387 
3388 u_char *
skip_qrec(name,qtype,qclass,cp,msg,eom)3389 skip_qrec(name, qtype, qclass, cp, msg, eom)
3390 input char *name;			/* full name we are querying about */
3391 input int qtype;			/* record type we are querying about */
3392 input int qclass;			/* record class we are querying about */
3393 register u_char *cp;			/* current position in answer buf */
3394 input u_char *msg, *eom;		/* begin and end of answer buf */
3395 {
3396 	char rname[MAXDNAME+1];		/* record name in LHS */
3397 	int type, class;		/* fixed values in query record */
3398 	register int n;
3399 
3400 /*
3401  * Pickup the standard values present in the query section.
3402  */
3403 	n = expand_name(name, T_NONE, cp, msg, eom, rname);
3404 	if (n < 0)
3405 		return(NULL);
3406 	cp += n;
3407 
3408 	n = 2*INT16SZ;
3409 	if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
3410 		return(NULL);
3411 
3412 	type = _getshort(cp);
3413 	cp += INT16SZ;
3414 
3415 	class = _getshort(cp);
3416 	cp += INT16SZ;
3417 
3418 #ifdef lint
3419 	if (verbose)
3420 		printf("%-20s\t%s\t%s\n",
3421 			rname, pr_class(class), pr_type(type));
3422 #endif
3423 
3424 /*
3425  * The values in the answer should match those in the query.
3426  * If there is a mismatch, we just signal an error, but don't abort.
3427  * For regular queries there is exactly one record in the query section.
3428  */
3429 	if (!sameword(rname, name))
3430 		pr_error("invalid answer name %s after %s query for %s",
3431 			rname, pr_type(qtype), name);
3432 
3433 	if (type != qtype)
3434 		pr_error("invalid answer type %s after %s query for %s",
3435 			pr_type(type), pr_type(qtype), name);
3436 
3437 	if (class != qclass)
3438 		pr_error("invalid answer class %s after %s query for %s",
3439 			pr_class(class), pr_type(qtype), name);
3440 
3441 	return(cp);
3442 }
3443 
3444 /*
3445 ** GET_RECURSIVE -- Wrapper for get_hostinfo() during recursion
3446 ** ------------------------------------------------------------
3447 **
3448 **	Returns:
3449 **		true if requested info was obtained successfully.
3450 **		false otherwise.
3451 */
3452 
3453 bool
get_recursive(name)3454 get_recursive(name)
3455 input char **name;			/* name to query about */
3456 {
3457 	static int level = 0;		/* recursion level */
3458 	char newnamebuf[MAXDNAME+1];
3459 	char *newname;			/* new name to look up */
3460 	bool result;			/* result status of action taken */
3461 	int save_errno;
3462 	int save_herrno;
3463 
3464 	if (level > MAXCHAIN)
3465 	{
3466 		errmsg("Recursion too deep");
3467 		return(false);
3468 	}
3469 
3470 	/* save local copy, and reset indicator */
3471 	newname = strxcpy(newnamebuf, *name, MAXDNAME+1);
3472 	*name = NULL;
3473 
3474 	save_errno = errno;
3475 	save_herrno = h_errno;
3476 
3477 	level++;
3478 	result = get_hostinfo(newname, true);
3479 	level--;
3480 
3481 	errno = save_errno;
3482 	h_errno = save_herrno;
3483 
3484 	return(result);
3485 }
3486 
3487 
3488 /*
3489  * Nameserver information.
3490  * Stores names and addresses of all servers that are to be queried
3491  * for a zone transfer of the desired zone. Normally these are the
3492  * authoritative primary and/or secondary nameservers for the zone.
3493  */
3494 
3495 char nsname[MAXNSNAME][MAXDNAME+1];		/* nameserver host name */
3496 struct in_addr ipaddr[MAXNSNAME][MAXIPADDR];	/* nameserver addresses */
3497 int naddrs[MAXNSNAME];				/* count of addresses */
3498 int nservers = 0;				/* count of nameservers */
3499 
3500 bool authserver;		/* server is supposed to be authoritative */
3501 bool lameserver;		/* server could not provide SOA service */
3502 
3503 /*
3504  * Host information.
3505  * Stores names and (single) addresses encountered during the zone listing
3506  * of all A records that belong to the zone. Non-authoritative glue records
3507  * that do not belong to the zone are not stored. Glue records that belong
3508  * to a delegated zone will be filtered out later during the host count scan.
3509  * The host names are allocated dynamically.
3510  * The list itself is also allocated dynamically, to avoid static limits,
3511  * and to keep the initial bss of the executable to a reasonable size.
3512  * Allocation is done in chunks, to reduce considerable malloc overhead.
3513  * Note that the list will not shrink during recursive processing.
3514  */
3515 
3516 typedef struct host_data {
3517 	char *hd_hostname;	/* host name of host in zone */
3518 	ipaddr_t hd_hostaddr;	/* first host address */
3519 	bool hd_multaddr;	/* set if this is a multiple address host */
3520 } host_data_t;
3521 
3522 host_data_t *hostlist = NULL;	/* info on hosts in zone */
3523 int hostcount = 0;		/* count of hosts in zone */
3524 
3525 int maxhosts = 0;		/* number of allocated hostlist entries */
3526 
3527 #define MAXHOSTINCR	4096	/* chunk size to increment hostlist */
3528 
3529 #define hostname(i)	hostlist[i].hd_hostname
3530 #define hostaddr(i)	hostlist[i].hd_hostaddr
3531 #define multaddr(i)	hostlist[i].hd_multaddr
3532 
3533 /*
3534  * Delegated zone information.
3535  * Stores the names of the delegated zones encountered during the zone
3536  * listing. The names and the list itself are allocated dynamically.
3537  */
3538 
3539 char **zonename = NULL;		/* names of delegated zones within zone */
3540 int zonecount = 0;		/* count of delegated zones within zone */
3541 
3542 /*
3543  * Address information.
3544  * Stores the (single) addresses of hosts found in all zones traversed.
3545  * Used to search for duplicate hosts (same address but different name).
3546  * The list of addresses is allocated dynamically, and remains allocated.
3547  * This has now been implemented as a hashed list, using the low-order
3548  * address bits as the hash key.
3549  */
3550 
3551 /*
3552  * SOA record information.
3553  */
3554 
3555 soa_data_t soa;			/* buffer to store soa data */
3556 
3557 int soacount = 0;		/* count of SOA records during listing */
3558 
3559 /*
3560  * Nameserver preference.
3561  * As per BIND 4.9.* resource records may be returned after round-robin
3562  * reshuffling each time they are retrieved. For NS records, this may
3563  * lead to an unfavorable order for doing zone transfers.
3564  * We apply some heuristic to sort the NS records according to their
3565  * preference with respect to a given list of preferred server domains.
3566  */
3567 
3568 int nsrank[MAXNSNAME];		/* nameserver ranking after sorting */
3569 int nspref[MAXNSNAME];		/* nameserver preference value */
3570 
3571 /*
3572 ** LIST_ZONE -- Basic routine to do complete zone listing and checking
3573 ** -------------------------------------------------------------------
3574 **
3575 **	Returns:
3576 **		true if the requested info was processed successfully.
3577 **		false otherwise.
3578 */
3579 
3580 int total_calls = 0;		/* number of calls for zone processing */
3581 int total_check = 0;		/* number of zones successfully processed */
3582 int total_tries = 0;		/* number of zone transfer attempts */
3583 int total_zones = 0;		/* number of successful zone transfers */
3584 int total_hosts = 0;		/* number of hosts in all traversed zones */
3585 int total_dupls = 0;		/* number of duplicates in all zones */
3586 
3587 char longname[MAXDNAME+1];	/* longest host name found */
3588 int longsize = 0;		/* size of longest host name */
3589 
3590 bool
list_zone(name)3591 list_zone(name)
3592 input char *name;			/* name of zone to process */
3593 {
3594 	register int n;
3595 	register int i;
3596 	int nzones;			/* count of delegated zones */
3597 	int nhosts;			/* count of real host names */
3598 	int ndupls;			/* count of duplicate hosts */
3599 	int nextrs;			/* count of extrazone hosts */
3600 	int ngates;			/* count of gateway hosts */
3601 
3602 	total_calls += 1;		/* update zone processing calls */
3603 
3604 /*
3605  * Normalize to not have trailing dot, unless it is the root zone.
3606  */
3607 	n = strlength(name);
3608 	if (n > 1 && name[n-1] == '.')
3609 		name[n-1] = '\0';
3610 
3611 /*
3612  * Indicate whether we are processing an in-addr.arpa reverse zone.
3613  * In this case we will suppress accumulating host count statistics.
3614  */
3615 	reverse = indomain(name, ARPA_ROOT, false);
3616 
3617 /*
3618  * Suppress various checks if working beyond the recursion skip level.
3619  * This affects processing in print_rrec(). It may need refinement.
3620  */
3621 	recurskip = ((recursion_level > skip_level) && !addrmode) ? true : false;
3622 
3623 /*
3624  * Find the nameservers for the given zone.
3625  */
3626 	(void) find_servers(name);
3627 
3628 	if (nservers < 1)
3629 	{
3630 		errmsg("No nameservers for %s found", name);
3631 		return(false);
3632 	}
3633 
3634 /*
3635  * Make sure we have an address for at least one nameserver.
3636  */
3637 	for (n = 0; n < nservers; n++)
3638 		if (naddrs[n] > 0)
3639 			break;
3640 
3641 	if (n >= nservers)
3642 	{
3643 		errmsg("No addresses of nameservers for %s found", name);
3644 		return(false);
3645 	}
3646 
3647 /*
3648  * Without an explicit server on the command line, the servers we
3649  * have looked up are supposed to be authoritative for the zone.
3650  */
3651 	authserver = (server && !primary) ? false : true;
3652 
3653 /*
3654  * Check SOA records at each of the nameservers if so requested.
3655  */
3656 	if (checkmode)
3657 	{
3658 		do_check(name);
3659 
3660 		total_check += 1;	/* update zones processed */
3661 
3662 		/* all done if maximum recursion level reached */
3663 		if (!recursive || (recursion_level >= recursive))
3664 			return((errorcount == 0) ? true : false);
3665 	}
3666 
3667 /*
3668  * The zone transfer for certain zones can be skipped.
3669  * Currently this must be indicated on the command line.
3670  */
3671 	if (skip_transfer(name))
3672 	{
3673 		if (verbose || statistics || checkmode || hostmode)
3674 			printf("Skipping zone transfer for %s\n", name);
3675 		return(false);
3676 	}
3677 
3678 /*
3679  * Ask zone transfer to the nameservers, until one responds.
3680  */
3681 	total_tries += 1;		/* update zone transfer attempts */
3682 
3683 	if (!do_transfer(name))
3684 		return(false);
3685 
3686 	total_zones += 1;		/* update successful zone transfers */
3687 
3688 /*
3689  * Print resource record statistics if so requested.
3690  */
3691 	if (statistics)
3692 		print_statistics(name, querytype, queryclass);
3693 
3694 /*
3695  * Accumulate host count statistics for this zone.
3696  * Do this only in modes in which such output would be printed.
3697  */
3698 	nzones = zonecount;
3699 
3700 	nhosts = 0, ndupls = 0, nextrs = 0, ngates = 0;
3701 
3702 	i = (verbose || statistics || hostmode) ? 0 : hostcount;
3703 
3704 	for (n = i; n < hostcount; n++)
3705 	{
3706 		/* skip fake hosts using a very rudimentary test */
3707 		if (fakename(hostname(n)) || fakeaddr(hostaddr(n)))
3708 			continue;
3709 		/* save longest host name encountered so far */
3710 		if (verbose && ((i = strlength(hostname(n))) > longsize))
3711 		{
3712 			longsize = i;
3713 			(void) strlcpy(longname, hostname(n), MAXDNAME+1);
3714 		}
3715 		/* skip apparent glue records */
3716 		if (gluerecord(hostname(n), name, zonename, nzones))
3717 		{
3718 			if (verbose > 1)
3719 				printf("%s is glue record\n", hostname(n));
3720 			continue;
3721 		}
3722 
3723 		/* otherwise count as host */
3724 		nhosts++;
3725 
3726 	/*
3727 	 * Mark hosts not residing directly in the zone as extrazone host.
3728 	 */
3729 		if (!samedomain(hostname(n), name, true))
3730 		{
3731 			nextrs++;
3732 			if (extrmode || (verbose > 1))
3733 				printf("%s is extrazone host\n", hostname(n));
3734 		}
3735 
3736 	/*
3737 	 * Mark hosts with more than one address as gateway host.
3738 	 * These are not checked for duplicate addresses.
3739 	 */
3740 		if (multaddr(n))
3741 		{
3742 			ngates++;
3743 			if (gatemode || (verbose > 1))
3744 				printf("%s is gateway host\n", hostname(n));
3745 		}
3746 
3747 	/*
3748 	 * Compare single address hosts against global list of addresses.
3749 	 * Multiple address hosts are too complicated to handle this way.
3750 	 */
3751 		else if (check_dupl(hostaddr(n)))
3752 		{
3753 			struct in_addr inaddr;
3754 			inaddr.s_addr = hostaddr(n);
3755 
3756 			ndupls++;
3757 			if (duplmode || (verbose > 1))
3758 				printf("%s is duplicate host with address %s\n",
3759 					hostname(n), inet_ntoa(inaddr));
3760 		}
3761 	}
3762 
3763 /*
3764  * Print statistics for this zone.
3765  */
3766 	if (verbose || statistics || hostmode)
3767 	{
3768 		printf("Found %d host%s within %s\n",
3769 			nhosts, plural(nhosts), name);
3770 
3771 	    if ((ndupls > 0) || duplmode || (verbose > 1))
3772 		printf("Found %d duplicate host%s within %s\n",
3773 			ndupls, plural(ndupls), name);
3774 
3775 	    if ((nextrs > 0) || extrmode || (verbose > 1))
3776 		printf("Found %d extrazone host%s within %s\n",
3777 			nextrs, plural(nextrs), name);
3778 
3779 	    if ((ngates > 0) || gatemode || (verbose > 1))
3780 		printf("Found %d gateway host%s within %s\n",
3781 			ngates, plural(ngates), name);
3782 	}
3783 
3784 	total_hosts += nhosts;		/* update total number of hosts */
3785 	total_dupls += ndupls;		/* update total number of duplicates */
3786 
3787 	if (!checkmode)
3788 		total_check += 1;	/* update zones processed */
3789 
3790 	if (verbose || statistics)
3791 		printf("Found %d delegated zone%s within %s\n",
3792 			nzones, plural(nzones), name);
3793 
3794 /*
3795  * Sort the encountered delegated zones alphabetically.
3796  * Note that this precludes further use of the zone_index() function.
3797  */
3798 	if ((nzones > 1) && (recursive || listzones || mxdomains))
3799 		qsort((ptr_t *)zonename, nzones, sizeof(char *), compare_name);
3800 
3801 /*
3802  * The names of the hosts were allocated dynamically.
3803  */
3804 	for (n = 0; n < hostcount; n++)
3805 		xfree(hostname(n));
3806 
3807 /*
3808  * Check for mailable delegated zones within this zone.
3809  * This is based on ordinary MX lookup, and not on the MX info
3810  * which may be present in the zone listing, to reduce zone transfers.
3811  */
3812 	if (mxdomains)
3813 	{
3814 		if (recursion_level == 0)
3815 		{
3816 			if (verbose)
3817 				printf("\n");
3818 
3819 			if (!get_mxrec(name))
3820 				ns_error(name, T_MX, queryclass, server);
3821 		}
3822 
3823 		for (n = 0; n < nzones; n++)
3824 		{
3825 			if (verbose)
3826 				printf("\n");
3827 
3828 			if (!get_mxrec(zonename[n]))
3829 				ns_error(zonename[n], T_MX, queryclass, server);
3830 		}
3831 	}
3832 
3833 /*
3834  * Do recursion on delegated zones if requested and any were found.
3835  * Temporarily save zonename list, and force allocation of new list.
3836  */
3837 	if (recursive && (recursion_level < recursive))
3838 	{
3839 		for (n = 0; n < nzones; n++)
3840 		{
3841 			char **newzone;		/* local copy of list */
3842 
3843 			newzone = zonename;
3844 			zonename = NULL;	/* allocate new list */
3845 
3846 			if (verbose || statistics || checkmode || hostmode)
3847 				printf("\n");
3848 
3849 			if (listzones)
3850 			{
3851 				for (i = 0; i <= recursion_level; i++)
3852 					printf("%s", (i == 0) ? "\t" : "  ");
3853 				printf("%s\n", newzone[n]);
3854 			}
3855 
3856 			if (verbose)
3857 				printf("Entering zone %s\n", newzone[n]);
3858 
3859 			recursion_level++;
3860 			(void) list_zone(newzone[n]);
3861 			recursion_level--;
3862 
3863 			zonename = newzone;	/* restore */
3864 		}
3865 	}
3866 	else if (listzones)
3867 	{
3868 		for (n = 0; n < nzones; n++)
3869 		{
3870 			for (i = 0; i <= recursion_level; i++)
3871 				printf("%s", (i == 0) ? "\t" : "  ");
3872 			printf("%s\n", zonename[n]);
3873 		}
3874 	}
3875 
3876 /*
3877  * The names of the delegated zones were allocated dynamically.
3878  * The list of delegated zone names was also allocated dynamically.
3879  */
3880 	for (n = 0; n < nzones; n++)
3881 		xfree(zonename[n]);
3882 
3883 	if (zonename != NULL)
3884 		xfree(zonename);
3885 
3886 	zonename = NULL;
3887 
3888 /*
3889  * Print final overall statistics.
3890  */
3891 	if (recursive && (recursion_level == 0))
3892 	{
3893 		if (verbose || statistics || checkmode || hostmode)
3894 			printf("\n");
3895 
3896 		if (verbose || statistics || hostmode)
3897 			printf("Encountered %d host%s in %d zone%s within %s\n",
3898 				total_hosts, plural(total_hosts),
3899 				total_zones, plural(total_zones),
3900 				name);
3901 
3902 		if (verbose || statistics || hostmode)
3903 			printf("Encountered %d duplicate host%s in %d zone%s within %s\n",
3904 				total_dupls, plural(total_dupls),
3905 				total_zones, plural(total_zones),
3906 				name);
3907 
3908 		if (verbose || statistics || checkmode)
3909 			printf("Transferred %d zone%s out of %d attempt%s\n",
3910 				total_zones, plural(total_zones),
3911 				total_tries, plural(total_tries));
3912 
3913 		if (verbose || statistics || checkmode)
3914 			printf("Processed %d zone%s out of %d request%s\n",
3915 				total_check, plural(total_check),
3916 				total_calls, plural(total_calls));
3917 		if (verbose && (longsize > 0))
3918 			printf("Longest hostname %s\t%d\n",
3919 				longname, longsize);
3920 	}
3921 
3922 	/* indicate whether any errors were encountered */
3923 	return((errorcount == 0) ? true : false);
3924 }
3925 
3926 /*
3927 ** FIND_SERVERS -- Fetch names and addresses of authoritative servers
3928 ** ------------------------------------------------------------------
3929 **
3930 **	Returns:
3931 **		true if servers could be determined successfully.
3932 **		false otherwise.
3933 **
3934 **	Inputs:
3935 **		The global variable ``server'', if set, contains the
3936 **		name of the explicit server to be contacted.
3937 **		The global variable ``primary'', if set, indicates
3938 **		that we must use the primary nameserver for the zone.
3939 **		If both are set simultaneously, the explicit server
3940 **		is contacted to retrieve the desired servers.
3941 **
3942 **	Outputs:
3943 **		The count of nameservers is stored in ``nservers''.
3944 **		Names are stored in the nsname[] database.
3945 **		Addresses are stored in the ipaddr[] database.
3946 **		Address counts are stored in the naddrs[] database.
3947 */
3948 
3949 bool
find_servers(name)3950 find_servers(name)
3951 input char *name;			/* name of zone to find servers for */
3952 {
3953 	struct hostent *hp;
3954 	register int n, i;
3955 
3956 /*
3957  * Use the explicit server if given on the command line.
3958  * Its addresses are stored in the resolver state struct.
3959  * This server may not be authoritative for the given zone.
3960  */
3961 	if (server && !primary)
3962 	{
3963 		(void) strlcpy(nsname[0], server, MAXDNAME+1);
3964 
3965 		for (i = 0; i < MAXIPADDR && i < _res.nscount; i++)
3966 			ipaddr[0][i] = nslist(i).sin_addr;
3967 		naddrs[0] = i;
3968 
3969 		nservers = 1;
3970 		return(true);
3971 	}
3972 
3973 /*
3974  * Fetch primary nameserver info if so requested.
3975  * Get its name from the SOA record for the zone, and do a regular
3976  * host lookup to fetch its addresses. We are assuming here that the
3977  * SOA record is a proper one. This is not necessarily true.
3978  * Obviously this server should be authoritative.
3979  */
3980 	if (primary && !server)
3981 	{
3982 		char *primaryname;
3983 
3984 		primaryname = get_primary(name);
3985 		if (primaryname == NULL)
3986 		{
3987 			ns_error(name, T_SOA, queryclass, server);
3988 			nservers = 0;
3989 			return(false);
3990 		}
3991 
3992 		hp = geth_byname(primaryname);
3993 		if (hp == NULL)
3994 		{
3995 			ns_error(primaryname, T_A, C_IN, server);
3996 			nservers = 0;
3997 			return(false);
3998 		}
3999 
4000 		primaryname = strncpy(nsname[0], hp->h_name, MAXDNAME);
4001 		primaryname[MAXDNAME] = '\0';
4002 
4003 		for (i = 0; i < MAXIPADDR && hp->h_addr_list[i]; i++)
4004 			ipaddr[0][i] = incopy(hp->h_addr_list[i]);
4005 		naddrs[0] = i;
4006 
4007 		if (verbose)
4008 			printf("Found %d address%s for %s\n",
4009 				naddrs[0], plurale(naddrs[0]), nsname[0]);
4010 		nservers = 1;
4011 		return(true);
4012 	}
4013 
4014 /*
4015  * Otherwise we have to find the nameservers for the zone.
4016  * These are supposed to be authoritative, but sometimes we
4017  * encounter lame delegations, perhaps due to misconfiguration.
4018  */
4019 	if (!get_servers(name))
4020 	{
4021 		ns_error(name, T_NS, queryclass, server);
4022 		nservers = 0;
4023 		return(false);
4024 	}
4025 
4026 /*
4027  * Usually we'll get addresses for all the servers in the additional
4028  * info section.  But in case we don't, look up their addresses.
4029  * Addresses could be missing because there is no room in the answer.
4030  * No address is present if the name of a server is not canonical.
4031  * If we get no addresses by extra query, and this is authoritative,
4032  * we flag a lame delegation to that server.
4033  */
4034 	for (n = 0; n < nservers; n++)
4035 	{
4036 	    if (naddrs[n] == 0)
4037 	    {
4038 		hp = geth_byname(nsname[n]);
4039 		if (hp != NULL)
4040 		{
4041 			for (i = 0; i < MAXIPADDR && hp->h_addr_list[i]; i++)
4042 				ipaddr[n][i] = incopy(hp->h_addr_list[i]);
4043 			naddrs[n] = i;
4044 		}
4045 
4046 		if (verbose)
4047 			printf("Found %d address%s for %s by extra query\n",
4048 				naddrs[n], plurale(naddrs[n]), nsname[n]);
4049 
4050 		if (hp == NULL)
4051 		{
4052 			/* server name lookup failed */
4053 			ns_error(nsname[n], T_A, C_IN, server);
4054 
4055 			/* authoritative denial: probably misconfiguration */
4056 			if (h_errno == NO_DATA || h_errno == HOST_NOT_FOUND)
4057 			{
4058 				if (server == NULL)
4059 					errmsg("%s has lame delegation to %s",
4060 						name, nsname[n]);
4061 			}
4062 		}
4063 
4064 		if ((hp != NULL) && !sameword(hp->h_name, nsname[n]))
4065 			pr_warning("%s nameserver %s is not canonical (%s)",
4066 				name, nsname[n], hp->h_name);
4067 	    }
4068 	    else
4069 	    {
4070 		if (verbose)
4071 			printf("Found %d address%s for %s\n",
4072 				naddrs[n], plurale(naddrs[n]), nsname[n]);
4073 	    }
4074 	}
4075 
4076 /*
4077  * Issue warning if only one server has been discovered.
4078  * This is not an error per se, but not much redundancy in that case.
4079  */
4080 	if (nservers == 1)
4081 		pr_warning("%s has only one nameserver %s",
4082 			name, nsname[0]);
4083 
4084 	return((nservers > 0) ? true : false);
4085 }
4086 
4087 /*
4088 ** GET_SERVERS -- Fetch names and addresses of authoritative servers
4089 ** -----------------------------------------------------------------
4090 **
4091 **	Returns:
4092 **		true if servers could be determined successfully.
4093 **		false otherwise.
4094 **
4095 **	Side effects:
4096 **		The count of nameservers is stored in ``nservers''.
4097 **		Names are stored in the nsname[] database.
4098 **		Addresses are stored in the ipaddr[] database.
4099 **		Address counts are stored in the naddrs[] database.
4100 */
4101 
4102 bool
get_servers(name)4103 get_servers(name)
4104 input char *name;			/* name of zone to find servers for */
4105 {
4106 	querybuf answer;
4107 	register int n;
4108 	bool result;			/* result status of action taken */
4109 
4110 	if (verbose)
4111 		printf("Finding nameservers for %s ...\n", name);
4112 
4113 	n = get_info(&answer, name, T_NS, queryclass);
4114 	if (n < 0)
4115 		return(false);
4116 
4117 	if (verbose > 1)
4118 		(void) print_info(&answer, n, name, T_NS, queryclass, false);
4119 
4120 	result = get_nsinfo(&answer, n, name);
4121 	return(result);
4122 }
4123 
4124 /*
4125 ** GET_NSINFO -- Extract nameserver data from nameserver answer buffer
4126 ** -------------------------------------------------------------------
4127 **
4128 **	Returns:
4129 **		true if the answer buffer was processed successfully.
4130 **		false otherwise.
4131 **
4132 **	Outputs:
4133 **		The count of nameservers is stored in ``nservers''.
4134 **		Names are stored in the nsname[] database.
4135 **		Addresses are stored in the ipaddr[] database.
4136 **		Address counts are stored in the naddrs[] database.
4137 */
4138 
4139 bool
get_nsinfo(answerbuf,answerlen,name)4140 get_nsinfo(answerbuf, answerlen, name)
4141 input querybuf *answerbuf;		/* location of answer buffer */
4142 input int answerlen;			/* length of answer buffer */
4143 input char *name;			/* name of zone to find servers for */
4144 {
4145 	HEADER *bp;
4146 	int qdcount, ancount, nscount, arcount, rrcount;
4147 	u_char *msg, *eom;
4148 	register u_char *cp;
4149 	register int i;
4150 
4151 	nservers = 0;			/* count of nameservers */
4152 
4153 	bp = (HEADER *)answerbuf;
4154 	qdcount = ntohs(bp->qdcount);
4155 	ancount = ntohs(bp->ancount);
4156 	nscount = ntohs(bp->nscount);
4157 	arcount = ntohs(bp->arcount);
4158 
4159 	msg = (u_char *)answerbuf;
4160 	eom = (u_char *)answerbuf + answerlen;
4161 	cp  = (u_char *)answerbuf + HFIXEDSZ;
4162 
4163 	if (qdcount > 0 && cp < eom)	/* should be exactly one record */
4164 	{
4165 		cp = skip_qrec(name, T_NS, queryclass, cp, msg, eom);
4166 		if (cp == NULL)
4167 			return(false);
4168 		qdcount--;
4169 	}
4170 
4171 	if (qdcount)
4172 	{
4173 		pr_error("invalid qdcount after %s query for %s",
4174 			pr_type(T_NS), name);
4175 		h_errno = NO_RECOVERY;
4176 		return(false);
4177 	}
4178 
4179 /*
4180  * If the answer is authoritative, the names are found in the
4181  * answer section, and the nameserver section is empty.
4182  * If not, there may be duplicate names in both sections.
4183  * Addresses are found in the additional info section both cases.
4184  */
4185 	rrcount = ancount + nscount + arcount;
4186 	while (rrcount > 0 && cp < eom)
4187 	{
4188 		char rname[MAXDNAME+1];
4189 		char dname[MAXDNAME+1];
4190 		int type, class, ttl, dlen;
4191 		u_char *eor;
4192 		register int n;
4193 		struct in_addr inaddr;
4194 
4195 		n = expand_name(name, T_NONE, cp, msg, eom, rname);
4196 		if (n < 0)
4197 			return(false);
4198 		cp += n;
4199 
4200 		n = 3*INT16SZ + INT32SZ;
4201 		if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
4202 			return(false);
4203 
4204 		type = _getshort(cp);
4205 		cp += INT16SZ;
4206 
4207 		class = _getshort(cp);
4208 		cp += INT16SZ;
4209 
4210 		ttl = _getlong(cp);
4211 		cp += INT32SZ;
4212 
4213 		dlen = _getshort(cp);
4214 		cp += INT16SZ;
4215 
4216 		eor = cp + dlen;
4217 #ifdef lint
4218 		if (verbose)
4219 			printf("%-20s\t%d\t%s\t%s\n",
4220 				rname, ttl, pr_class(class), pr_type(type));
4221 #endif
4222 		if ((type == T_NS) && sameword(rname, name))
4223 		{
4224 			n = expand_name(rname, type, cp, msg, eom, dname);
4225 			if (n < 0)
4226 				return(false);
4227 			cp += n;
4228 
4229 			for (i = 0; i < nservers; i++)
4230 				if (sameword(nsname[i], dname))
4231 					break;	/* duplicate */
4232 
4233 			if (i >= nservers && nservers < MAXNSNAME)
4234 			{
4235 				(void) strlcpy(nsname[nservers], dname, MAXDNAME+1);
4236 				naddrs[nservers] = 0;
4237 				nservers++;
4238 			}
4239 		}
4240 		else if ((type == T_A) && (dlen == INADDRSZ))
4241 		{
4242 			for (i = 0; i < nservers; i++)
4243 				if (sameword(nsname[i], rname))
4244 					break;	/* found */
4245 
4246 			if (i < nservers && naddrs[i] < MAXIPADDR)
4247 			{
4248 				memmove((char *)&inaddr, (char *)cp, INADDRSZ);
4249 				ipaddr[i][naddrs[i]] = inaddr;
4250 				naddrs[i]++;
4251 			}
4252 
4253 			cp += dlen;
4254 		}
4255 		else
4256 		{
4257 			/* just ignore other records */
4258 			cp += dlen;
4259 		}
4260 
4261 		if (cp != eor)
4262 		{
4263 			pr_error("size error in %s record for %s, off by %s",
4264 				pr_type(type), rname, itoa(cp - eor));
4265 			h_errno = NO_RECOVERY;
4266 			return(false);
4267 		}
4268 
4269 		rrcount--;
4270 	}
4271 
4272 	if (rrcount)
4273 	{
4274 		pr_error("invalid rrcount after %s query for %s",
4275 			pr_type(T_NS), name);
4276 		h_errno = NO_RECOVERY;
4277 		return(false);
4278 	}
4279 
4280 	/* set proper status if no answers found */
4281 	h_errno = (nservers > 0) ? 0 : TRY_AGAIN;
4282 	return(true);
4283 }
4284 
4285 /*
4286 ** SORT_SERVERS -- Sort set of nameservers according to preference
4287 ** ---------------------------------------------------------------
4288 **
4289 **	Returns:
4290 **		None.
4291 **
4292 **	Inputs:
4293 **		Set of nameservers as determined by find_servers().
4294 **		The global variable ``prefserver'', if set, contains
4295 **		a list of preferred server domains to compare against.
4296 **
4297 **	Outputs:
4298 **		Stores the preferred nameserver order in nsrank[].
4299 */
4300 
4301 void
sort_servers()4302 sort_servers()
4303 {
4304 	register int i, j;
4305 	register int n, pref;
4306 	register char *p, *q;
4307 
4308 /*
4309  * Initialize the default ranking.
4310  */
4311 	for (n = 0; n < nservers; n++)
4312 	{
4313 		nsrank[n] = n;
4314 		nspref[n] = 0;
4315 	}
4316 
4317 /*
4318  * Determine the nameserver preference.
4319  * Compare against a list of comma-separated preferred server domains.
4320  * Use the maximum value of all comparisons.
4321  */
4322 	for (q = NULL, p = prefserver; p != NULL; p = q)
4323 	{
4324 		q = index(p, ',');
4325 		if (q != NULL)
4326 			*q = '\0';
4327 
4328 		for (n = 0; n < nservers; n++)
4329 		{
4330 			pref = matchlabels(nsname[n], p);
4331 			if (pref > nspref[n])
4332 				nspref[n] = pref;
4333 		}
4334 
4335 		if (q != NULL)
4336 			*q++ = ',';
4337 	}
4338 
4339 /*
4340  * Sort the set according to preference.
4341  * Keep the rest as much as possible in original order.
4342  */
4343 	for (i = 0; i < nservers; i++)
4344 	{
4345 		for (j = i + 1; j < nservers; j++)
4346 		{
4347 			if (nspref[j] > nspref[i])
4348 			{
4349 				pref = nspref[j];
4350 				/* nspref[j] = nspref[i]; */
4351 				for (n = j; n > i; n--)
4352 					nspref[n] = nspref[n-1];
4353 				nspref[i] = pref;
4354 
4355 				pref = nsrank[j];
4356 				/* nsrank[j] = nsrank[i]; */
4357 				for (n = j; n > i; n--)
4358 					nsrank[n] = nsrank[n-1];
4359 				nsrank[i] = pref;
4360 			}
4361 		}
4362 	}
4363 }
4364 
4365 /*
4366 ** SKIP_TRANSFER -- Check whether a zone transfer should be skipped
4367 ** ----------------------------------------------------------------
4368 **
4369 **	Returns:
4370 **		true if a transfer for this zone should be skipped.
4371 **		false if the zone transfer should proceed.
4372 **
4373 **	Inputs:
4374 **		The global variable ``skipzone'', if set, contains
4375 **		a list of zone names to be skipped.
4376 **
4377 **	Certain zones are known to contain bogus information, and
4378 **	can be requested to be excluded from further processing.
4379 **	The zone transfer for such zones and its delegated zones
4380 **	will be skipped.
4381 */
4382 
4383 bool
skip_transfer(name)4384 skip_transfer(name)
4385 input char *name;			/* name of zone to process */
4386 {
4387 	register char *p, *q;
4388 	bool skip = false;
4389 
4390 	for (q = NULL, p = skipzone; p != NULL; p = q)
4391 	{
4392 		q = index(p, ',');
4393 		if (q != NULL)
4394 			*q = '\0';
4395 
4396 		if (sameword(name, p))
4397 			skip = true;
4398 
4399 		if (q != NULL)
4400 			*q++ = ',';
4401 	}
4402 
4403 	return(skip);
4404 }
4405 
4406 /*
4407 ** DO_CHECK -- Check SOA records at each of the nameservers
4408 ** --------------------------------------------------------
4409 **
4410 **	Returns:
4411 **		None.
4412 **
4413 **	Inputs:
4414 **		The count of nameservers is stored in ``nservers''.
4415 **		Names are stored in the nsname[] database.
4416 **		Addresses are stored in the ipaddr[] database.
4417 **		Address counts are stored in the naddrs[] database.
4418 **
4419 **	The SOA record of the zone is checked at each nameserver.
4420 **	Nameserver recursion is turned off to make sure that the
4421 **	answer is authoritative.
4422 */
4423 
4424 void
do_check(name)4425 do_check(name)
4426 input char *name;			/* name of zone to process */
4427 {
4428 	res_state_t save_res;		/* saved copy of resolver database */
4429 	char *save_server;		/* saved copy of server name */
4430 	register int n;
4431 	register int i;
4432 
4433 	/* save resolver database */
4434 	save_res = _res;
4435 	save_server = server;
4436 
4437 	/* turn off nameserver recursion */
4438 	_res.options &= ~RES_RECURSE;
4439 
4440 	for (n = 0; n < nservers; n++)
4441 	{
4442 		if (naddrs[n] < 1)
4443 			continue;	/* shortcut */
4444 
4445 		server = nsname[n];
4446 		for (i = 0; i < MAXNS && i < naddrs[n]; i++)
4447 		{
4448 			nslist(i).sin_family = AF_INET;
4449 			nslist(i).sin_port = htons(NAMESERVER_PORT);
4450 			nslist(i).sin_addr = ipaddr[n][i];
4451 		}
4452 		_res.nscount = i;
4453 
4454 		/* retrieve and check SOA */
4455 		if (check_zone(name))
4456 			continue;
4457 
4458 		/* SOA query failed */
4459 		ns_error(name, T_SOA, queryclass, server);
4460 
4461 		/* explicit server failure: possibly data expired */
4462 		lameserver = (h_errno == SERVER_FAILURE) ? true : false;
4463 
4464 		/* non-authoritative denial: assume lame delegation */
4465 		if (h_errno == NO_RREC || h_errno == NO_HOST)
4466 			lameserver = true;
4467 
4468 		/* authoritative denial: probably misconfiguration */
4469 		if (h_errno == NO_DATA || h_errno == HOST_NOT_FOUND)
4470 			lameserver = true;
4471 
4472 		/* flag an error if server should not have failed */
4473 		if (lameserver && authserver)
4474 			errmsg("%s has lame delegation to %s",
4475 				name, server);
4476 	}
4477 
4478 	/* restore resolver database */
4479 	_res = save_res;
4480 	server = save_server;
4481 }
4482 
4483 /*
4484 ** DO_TRANSFER -- Perform a zone transfer from any of its nameservers
4485 ** ------------------------------------------------------------------
4486 **
4487 **	Returns:
4488 **		true if the zone data have been retrieved successfully.
4489 **		false if none of the servers responded.
4490 **
4491 **	Inputs:
4492 **		The count of nameservers is stored in ``nservers''.
4493 **		Names are stored in the nsname[] database.
4494 **		Addresses are stored in the ipaddr[] database.
4495 **		Address counts are stored in the naddrs[] database.
4496 **
4497 **	Ask zone transfer to the nameservers, until one responds.
4498 **	The list of nameservers is sorted according to preference.
4499 **	An authoritative server should always respond positively.
4500 **	If it responds with an error, we may have a lame delegation.
4501 **	Always retry with the next server to avoid missing entire zones.
4502 */
4503 
4504 bool
do_transfer(name)4505 do_transfer(name)
4506 input char *name;			/* name of zone to do zone xfer for */
4507 {
4508 	register int n, ns;
4509 	register int i;
4510 
4511 	for (sort_servers(), ns = 0; ns < nservers; ns++)
4512 	{
4513 	    for (n = nsrank[ns], i = 0; i < naddrs[n]; i++)
4514 	    {
4515 		if (verbose)
4516 			printf("Trying server %s (%s) ...\n",
4517 				inet_ntoa(ipaddr[n][i]), nsname[n]);
4518 
4519 		if (transfer_zone(name, ipaddr[n][i], nsname[n]))
4520 			goto done;	/* double break */
4521 
4522 		/* zone transfer failed */
4523 		if ((h_errno != TRY_AGAIN) || verbose)
4524 			ns_error(name, T_AXFR, queryclass, nsname[n]);
4525 
4526 		/* zone transfer request was explicitly refused */
4527 		if (h_errno == QUERY_REFUSED)
4528 			break;
4529 
4530 		/* explicit server failure: possibly data expired */
4531 		lameserver = (h_errno == SERVER_FAILURE) ? true : false;
4532 
4533 		/* non-authoritative denial: assume lame delegation */
4534 		if (h_errno == NO_RREC || h_errno == NO_HOST)
4535 			lameserver = true;
4536 
4537 		/* authoritative denial: probably misconfiguration */
4538 		if (h_errno == NO_DATA || h_errno == HOST_NOT_FOUND)
4539 			lameserver = true;
4540 
4541 		/* flag an error if server should not have failed */
4542 		if (lameserver && authserver)
4543 			errmsg("%s has lame delegation to %s",
4544 				name, nsname[n]);
4545 
4546 		/* try next server if this one is sick */
4547 		if (lameserver)
4548 			break;
4549 
4550 		/* terminate on irrecoverable errors */
4551 		if (h_errno != TRY_AGAIN)
4552 			return(false);
4553 
4554 		/* in case nameserver not present */
4555 		if (errno == ECONNREFUSED)
4556 			break;
4557 	    }
4558 	}
4559 done:
4560 	if (ns >= nservers)
4561 	{
4562 		if ((h_errno == TRY_AGAIN) && !verbose)
4563 			ns_error(name, T_AXFR, queryclass, (char *)NULL);
4564 		errmsg("No nameservers for %s responded", name);
4565 		return(false);
4566 	}
4567 
4568 	return(true);
4569 }
4570 
4571 /*
4572 ** TRANSFER_ZONE -- Wrapper for get_zone() to hide administrative tasks
4573 ** --------------------------------------------------------------------
4574 **
4575 **	Returns:
4576 **		See get_zone() for details.
4577 **
4578 **	Side effects:
4579 **		See get_zone() for details.
4580 **
4581 **	This routine may be called repeatedly with different server
4582 **	addresses, until one of the servers responds. Various items
4583 **	must be reset on every try to continue with a clean slate.
4584 */
4585 
4586 bool
transfer_zone(name,inaddr,host)4587 transfer_zone(name, inaddr, host)
4588 input char *name;			/* name of zone to do zone xfer for */
4589 input struct in_addr inaddr;		/* address of server to be queried */
4590 input char *host;			/* name of server to be queried */
4591 {
4592 	register int n;
4593 
4594 /*
4595  * Reset the resource record statistics before each try.
4596  */
4597 	clear_statistics();
4598 
4599 /*
4600  * Reset the hash tables of saved resource record information.
4601  * These tables are used only during the zone transfer itself.
4602  */
4603 	clear_ttltab();
4604 	clear_hosttab();
4605 	clear_zonetab();
4606 
4607 /*
4608  * Perform the actual zone transfer.
4609  * All error reporting is done by get_zone().
4610  */
4611 	if (get_zone(name, inaddr, host))
4612 		return(true);
4613 
4614 /*
4615  * Failure to get the zone. Free any memory that may have been allocated.
4616  * On success it is the responsibility of the caller to free the memory.
4617  * The information gathered is used by list_zone() after the zone transfer.
4618  */
4619 	for (n = 0; n < hostcount; n++)
4620 		xfree(hostname(n));
4621 
4622 	for (n = 0; n < zonecount; n++)
4623 		xfree(zonename[n]);
4624 
4625 	if (zonename != NULL)
4626 		xfree(zonename);
4627 
4628 	zonename = NULL;
4629 
4630 	return(false);
4631 }
4632 
4633 /*
4634 ** GET_ZONE -- Perform a zone transfer from server at specific address
4635 ** -------------------------------------------------------------------
4636 **
4637 **	Returns:
4638 **		true if the zone data have been retrieved successfully.
4639 **		false if an error occurred (h_errno is set appropriately).
4640 **		Set TRY_AGAIN wherever possible to try the next server.
4641 **
4642 **	Side effects:
4643 **		Stores list of delegated zones found in zonename[],
4644 **		and the count of delegated zones in ``zonecount''.
4645 **		Stores list of host names found in hostname[],
4646 **		and the count of host names in ``hostcount''.
4647 **		Updates resource record statistics in record_stats[].
4648 **		This array must have been cleared before.
4649 */
4650 
4651 bool
get_zone(name,inaddr,host)4652 get_zone(name, inaddr, host)
4653 input char *name;			/* name of zone to do zone xfer for */
4654 input struct in_addr inaddr;		/* address of server to be queried */
4655 input char *host;			/* name of server to be queried */
4656 {
4657 	querybuf query;
4658 	querybuf answer;
4659 	HEADER *bp;
4660 	int ancount;
4661 	int sock;
4662 	struct sockaddr_in sin;
4663 	register int n, i;
4664 	int nrecords = 0;		/* number of records processed */
4665 	int npackets = 0;		/* number of packets received */
4666 
4667 	/* clear global counts */
4668 	soacount = 0;			/* count of SOA records */
4669 	zonecount = 0;			/* count of delegated zones */
4670 	hostcount = 0;			/* count of host names */
4671 
4672 /*
4673  * Construct query, and connect to the given server.
4674  */
4675 	errno = 0;	/* reset before querying nameserver */
4676 
4677 	n = res_mkquery(QUERY, name, queryclass, T_AXFR, (qbuf_t *)NULL, 0,
4678 			(rrec_t *)NULL, (qbuf_t *)&query, sizeof(querybuf));
4679 	if (n < 0)
4680 	{
4681 		if (debug)
4682 			printf("%sres_mkquery failed\n", dbprefix);
4683 		h_errno = NO_RECOVERY;
4684 		return(false);
4685 	}
4686 
4687 	if (debug)
4688 	{
4689 		printf("%sget_zone()\n", dbprefix);
4690 		pr_query((qbuf_t *)&query, n, stdout);
4691 	}
4692 
4693 	/* setup destination address */
4694 	bzero((char *)&sin, sizeof(sin));
4695 
4696 	sin.sin_family = AF_INET;
4697 	sin.sin_port = htons(NAMESERVER_PORT);
4698 	sin.sin_addr = inaddr;
4699 
4700 	sock = socket(AF_INET, SOCK_STREAM, 0);
4701 	if (sock < 0)
4702 	{
4703 		_res_perror(&sin, host, "socket");
4704 		h_errno = TRY_AGAIN;
4705 		return(false);
4706 	}
4707 
4708 	if (_res_connect(sock, &sin, sizeof(sin)) < 0)
4709 	{
4710 		if (verbose || debug)
4711 			_res_perror(&sin, host, "connect");
4712 		(void) close(sock);
4713 		h_errno = TRY_AGAIN;
4714 		return(false);
4715 	}
4716 
4717 	if (verbose)
4718 		printf("Asking zone transfer for %s ...\n", name);
4719 
4720 /*
4721  * Send the query buffer.
4722  */
4723 	if (_res_write(sock, &sin, host, (char *)&query, n) < 0)
4724 	{
4725 		(void) close(sock);
4726 		h_errno = TRY_AGAIN;
4727 		return(false);
4728 	}
4729 
4730 /*
4731  * Process all incoming packets, usually one record in a separate packet.
4732  */
4733 	while ((n = _res_read(sock, &sin, host, (char *)&answer, sizeof(querybuf))) != 0)
4734 	{
4735 		if (n < 0)
4736 		{
4737 			(void) close(sock);
4738 			h_errno = TRY_AGAIN;
4739 			return(false);
4740 		}
4741 
4742 		errno = 0;	/* reset after we got an answer */
4743 
4744 		if (n < HFIXEDSZ)
4745 		{
4746 			pr_error("answer length %s too short during %s for %s from %s",
4747 				itoa(n), pr_type(T_AXFR), name, host);
4748 			(void) close(sock);
4749 			h_errno = TRY_AGAIN;
4750 			return(false);
4751 		}
4752 
4753 		if (debug > 1)
4754 		{
4755 			printf("%sgot answer, %d bytes:\n", dbprefix, n);
4756 			pr_query((qbuf_t *)&answer, querysize(n), stdout);
4757 		}
4758 
4759 	/*
4760 	 * Analyze the contents of the answer and check for errors.
4761 	 * An error can be expected only in the very first packet.
4762 	 * The query section should be empty except in the first packet.
4763 	 * Note the special error status codes for specific failures.
4764 	 */
4765 		bp = (HEADER *)&answer;
4766 		ancount = ntohs(bp->ancount);
4767 
4768 		if (bp->rcode != NOERROR || ancount == 0)
4769 		{
4770 			if (verbose || debug)
4771 				print_status(&answer, n);
4772 
4773 			switch (bp->rcode)
4774 			{
4775 			    case NXDOMAIN:
4776 				/* distinguish between authoritative or not */
4777 				h_errno = bp->aa ? HOST_NOT_FOUND : NO_HOST;
4778 				break;
4779 
4780 			    case NOERROR:
4781 				/* distinguish between authoritative or not */
4782 				h_errno = bp->aa ? NO_DATA : NO_RREC;
4783 				break;
4784 
4785 			    case REFUSED:
4786 				/* special status if zone transfer refused */
4787 				h_errno = QUERY_REFUSED;
4788 				break;
4789 
4790 			    case SERVFAIL:
4791 				/* special status upon explicit failure */
4792 				h_errno = SERVER_FAILURE;
4793 				break;
4794 
4795 			    default:
4796 				/* all other errors will cause a retry */
4797 				h_errno = TRY_AGAIN;
4798 				break;
4799 			}
4800 
4801 			if (npackets != 0)
4802 				pr_error("unexpected error during %s for %s from %s",
4803 					pr_type(T_AXFR), name, host);
4804 
4805 			(void) close(sock);
4806 			return(false);
4807 		}
4808 
4809 		/* valid answer received, avoid buffer overrun */
4810 		h_errno = 0;
4811 		n = querysize(n);
4812 
4813 	/*
4814 	 * The nameserver and additional info section should be empty.
4815 	 * There may be multiple answers in the answer section.
4816 	 */
4817 		if (ntohs(bp->nscount) != 0)
4818 			pr_error("nonzero nscount during %s for %s from %s",
4819 				pr_type(T_AXFR), name, host);
4820 
4821 		if (ntohs(bp->arcount) != 0)
4822 			pr_error("nonzero arcount during %s for %s from %s",
4823 				pr_type(T_AXFR), name, host);
4824 
4825 	/*
4826 	 * Valid packet received. Print contents if appropriate.
4827 	 * Specific zone information will be saved by update_zone().
4828 	 */
4829 		npackets += 1;
4830 		nrecords += ancount;
4831 
4832 		soaname = NULL, subname = NULL, adrname = NULL, address = 0;
4833 		listhost = host;
4834 
4835 		(void) print_info(&answer, n, name, T_AXFR, queryclass, false);
4836 
4837 	/*
4838 	 * Terminate upon the second SOA record for this zone.
4839 	 */
4840 		if (soacount > 1)
4841 			break;
4842 	}
4843 
4844 /*
4845  * End of zone transfer at second SOA record or zero length read.
4846  */
4847 	(void) close(sock);
4848 
4849 /*
4850  * Check for the anomaly that the whole transfer consisted of the
4851  * SOA records only. Could occur if we queried the victim of a lame
4852  * delegation which happened to have the SOA record present.
4853  */
4854 	if (nrecords <= soacount)
4855 	{
4856 		pr_error("empty zone transfer for %s from %s",
4857 			name, host);
4858 		h_errno = NO_RREC;
4859 		return(false);
4860 	}
4861 
4862 /*
4863  * Do an extra check for delegated zones that also have an A record.
4864  * Those may have been defined in the child zone, and crept in the
4865  * parent zone, or may have been defined as glue records.
4866  * This is not necessarily an error, but the host count may be wrong.
4867  * Note that an A record for the current zone has been ignored above.
4868  */
4869 	for (n = 0; n < zonecount; n++)
4870 	{
4871 		i = host_index(zonename[n], false);
4872 		if (i < hostcount)
4873 			pr_warning("%s has both NS and A records within %s from %s",
4874 				zonename[n], name, host);
4875 	}
4876 
4877 /*
4878  * The zone transfer has been successful.
4879  */
4880 	if (verbose)
4881 	{
4882 		printf("Transfer complete, %d record%s received for %s\n",
4883 			nrecords, plural(nrecords), name);
4884 		if (npackets != nrecords)
4885 			printf("Transfer consisted of %d packet%s from %s\n",
4886 				npackets, plural(npackets), host);
4887 	}
4888 
4889 	return(true);
4890 }
4891 
4892 /*
4893 ** UPDATE_ZONE -- Save zone information during zone listings
4894 ** ---------------------------------------------------------
4895 **
4896 **	Returns:
4897 **		None.
4898 **
4899 **	Side effects:
4900 **		Stores list of delegated zones found in zonename[],
4901 **		and the count of delegated zones in ``zonecount''.
4902 **		Stores list of host names found in hostname[],
4903 **		and the count of host names in ``hostcount''.
4904 **		Stores the count of SOA records in ``soacount''.
4905 **
4906 **	This routine is called by print_info() for each resource record.
4907 */
4908 
4909 void
update_zone(name)4910 update_zone(name)
4911 input char *name;			/* name of zone to do zone xfer for */
4912 {
4913 	char *host = listhost;		/* contacted host for zone listings */
4914 	register int i;
4915 
4916 /*
4917  * Terminate upon the second SOA record for this zone.
4918  */
4919 	if (soaname && sameword(soaname, name))
4920 		soacount++;
4921 
4922 	/* the nameserver balks on this one */
4923 	else if (soaname && !sameword(soaname, name))
4924 		pr_warning("extraneous SOA record for %s within %s from %s",
4925 			soaname, name, host);
4926 
4927 /*
4928  * Save encountered delegated zone name for recursive listing.
4929  */
4930 	if (subname && indomain(subname, name, false))
4931 	{
4932 		i = zone_index(subname, true);
4933 		if (i >= zonecount)
4934 		{
4935 			zonename = newlist(zonename, zonecount+1, char *);
4936 			zonename[zonecount] = newstr(subname);
4937 			zonecount++;
4938 		}
4939 	}
4940 
4941 	/* warn about strange delegated zones */
4942 	else if (subname && !indomain(subname, name, true))
4943 		pr_warning("extraneous NS record for %s within %s from %s",
4944 			subname, name, host);
4945 
4946 /*
4947  * Save encountered name of A record for host name count.
4948  */
4949 	if (adrname && indomain(adrname, name, false) && !reverse)
4950 	{
4951 		i = host_index(adrname, true);
4952 		if (i >= hostcount)
4953 		{
4954 			if (hostcount >= maxhosts)
4955 			{
4956 				maxhosts += MAXHOSTINCR;
4957 				hostlist = newlist(hostlist, maxhosts, host_data_t);
4958 			}
4959 			hostname(hostcount) = newstr(adrname);
4960 			hostaddr(hostcount) = address;
4961 			multaddr(hostcount) = false;
4962 			hostcount++;
4963 		}
4964 		else if (address != hostaddr(i))
4965 			multaddr(i) = true;
4966 	}
4967 
4968 	/* check for unauthoritative glue records */
4969 	else if (adrname && !indomain(adrname, name, true))
4970 		pr_warning("extraneous glue record for %s within %s from %s",
4971 			adrname, name, host);
4972 }
4973 
4974 /*
4975 ** GET_MXREC -- Fetch MX records of a domain
4976 ** -----------------------------------------
4977 **
4978 **	Returns:
4979 **		true if MX records were found.
4980 **		false otherwise.
4981 */
4982 
4983 bool
get_mxrec(name)4984 get_mxrec(name)
4985 input char *name;			/* domain name to get mx for */
4986 {
4987 	querybuf answer;
4988 	register int n;
4989 
4990 	if (verbose)
4991 		printf("Finding MX records for %s ...\n", name);
4992 
4993 	n = get_info(&answer, name, T_MX, queryclass);
4994 	if (n < 0)
4995 		return(false);
4996 
4997 	(void) print_info(&answer, n, name, T_MX, queryclass, false);
4998 
4999 	return(true);
5000 }
5001 
5002 /*
5003 ** GET_PRIMARY -- Fetch name of primary nameserver for a zone
5004 ** ----------------------------------------------------------
5005 **
5006 **	Returns:
5007 **		Pointer to the name of the primary server, if found.
5008 **		NULL if the server could not be determined.
5009 */
5010 
5011 char *
get_primary(name)5012 get_primary(name)
5013 input char *name;			/* name of zone to get soa for */
5014 {
5015 	querybuf answer;
5016 	register int n;
5017 
5018 	if (verbose)
5019 		printf("Finding primary nameserver for %s ...\n", name);
5020 
5021 	n = get_info(&answer, name, T_SOA, queryclass);
5022 	if (n < 0)
5023 		return(NULL);
5024 
5025 	if (verbose > 1)
5026 		(void) print_info(&answer, n, name, T_SOA, queryclass, false);
5027 
5028 	soaname = NULL;
5029 	(void) get_soainfo(&answer, n, name);
5030 	if (soaname == NULL)
5031 		return(NULL);
5032 
5033 	return(soa.primary);
5034 }
5035 
5036 /*
5037 ** CHECK_ZONE -- Fetch and analyze SOA record of a zone
5038 ** ----------------------------------------------------
5039 **
5040 **	Returns:
5041 **		true if the SOA record was found at the given server.
5042 **		false otherwise.
5043 **
5044 **	Inputs:
5045 **		The global variable ``server'' must contain the name
5046 **		of the server that was queried.
5047 */
5048 
5049 bool
check_zone(name)5050 check_zone(name)
5051 input char *name;			/* name of zone to get soa for */
5052 {
5053 	querybuf answer;
5054 	register int n;
5055 
5056 	if (verbose)
5057 		printf("Checking SOA for %s at server %s ...\n", name, server);
5058 	else if (authserver)
5059 		printf("%-20s\tNS\t%s\n", name, server);
5060 	else
5061 		printf("%s\t(%s)\n", name, server);
5062 
5063 	n = get_info(&answer, name, T_SOA, queryclass);
5064 	if (n < 0)
5065 		return(false);
5066 
5067 	if (verbose > 1)
5068 		(void) print_info(&answer, n, name, T_SOA, queryclass, false);
5069 
5070 	soaname = NULL;
5071 	(void) get_soainfo(&answer, n, name);
5072 	if (soaname == NULL)
5073 		return(false);
5074 
5075 	check_soa(&answer, name);
5076 
5077 	return(true);
5078 }
5079 
5080 /*
5081 ** GET_SOAINFO -- Extract SOA data from nameserver answer buffer
5082 ** -------------------------------------------------------------
5083 **
5084 **	Returns:
5085 **		true if the answer buffer was processed successfully.
5086 **		false otherwise.
5087 **
5088 **	Outputs:
5089 **		The global struct ``soa'' is filled with the soa data.
5090 **
5091 **	Side effects:
5092 **		Sets ``soaname'' if there is a valid SOA record.
5093 **		This variable must have been cleared before calling
5094 **		get_soainfo() and may be checked afterwards.
5095 */
5096 
5097 bool
get_soainfo(answerbuf,answerlen,name)5098 get_soainfo(answerbuf, answerlen, name)
5099 input querybuf *answerbuf;		/* location of answer buffer */
5100 input int answerlen;			/* length of answer buffer */
5101 input char *name;			/* name of zone to get soa for */
5102 {
5103 	HEADER *bp;
5104 	int qdcount, ancount;
5105 	u_char *msg, *eom;
5106 	register u_char *cp;
5107 
5108 	bp = (HEADER *)answerbuf;
5109 	qdcount = ntohs(bp->qdcount);
5110 	ancount = ntohs(bp->ancount);
5111 
5112 	msg = (u_char *)answerbuf;
5113 	eom = (u_char *)answerbuf + answerlen;
5114 	cp  = (u_char *)answerbuf + HFIXEDSZ;
5115 
5116 	if (qdcount > 0 && cp < eom)	/* should be exactly one record */
5117 	{
5118 		cp = skip_qrec(name, T_SOA, queryclass, cp, msg, eom);
5119 		if (cp == NULL)
5120 			return(false);
5121 		qdcount--;
5122 	}
5123 
5124 	if (qdcount)
5125 	{
5126 		pr_error("invalid qdcount after %s query for %s",
5127 			pr_type(T_SOA), name);
5128 		h_errno = NO_RECOVERY;
5129 		return(false);
5130 	}
5131 
5132 /*
5133  * Check answer section only.
5134  * Check that answers match the requested zone. Ignore other entries.
5135  * The nameserver section may contain the nameservers for the zone,
5136  * and the additional section their addresses, but not guaranteed.
5137  * Those sections are usually empty for authoritative answers.
5138  */
5139 	while (ancount > 0 && cp < eom)
5140 	{
5141 		char rname[MAXDNAME+1];
5142 		int type, class, ttl, dlen;
5143 		u_char *eor;
5144 		register int n;
5145 
5146 		n = expand_name(name, T_NONE, cp, msg, eom, rname);
5147 		if (n < 0)
5148 			return(false);
5149 		cp += n;
5150 
5151 		n = 3*INT16SZ + INT32SZ;
5152 		if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
5153 			return(false);
5154 
5155 		type = _getshort(cp);
5156 		cp += INT16SZ;
5157 
5158 		class = _getshort(cp);
5159 		cp += INT16SZ;
5160 
5161 		ttl = _getlong(cp);
5162 		cp += INT32SZ;
5163 
5164 		dlen = _getshort(cp);
5165 		cp += INT16SZ;
5166 
5167 		eor = cp + dlen;
5168 #ifdef lint
5169 		if (verbose)
5170 			printf("%-20s\t%d\t%s\t%s\n",
5171 				rname, ttl, pr_class(class), pr_type(type));
5172 #endif
5173 		if ((type == T_SOA) && sameword(rname, name))
5174 		{
5175 			n = expand_name(rname, type, cp, msg, eom, soa.primary);
5176 			if (n < 0)
5177 				return(false);
5178 			cp += n;
5179 
5180 			n = expand_name(rname, type, cp, msg, eom, soa.hostmaster);
5181 			if (n < 0)
5182 				return(false);
5183 			cp += n;
5184 
5185 			n = 5*INT32SZ;
5186 			if (check_size(rname, type, cp, msg, eor, n) < 0)
5187 				return(false);
5188 			soa.serial = _getlong(cp);
5189 			cp += INT32SZ;
5190 			soa.refresh = _getlong(cp);
5191 			cp += INT32SZ;
5192 			soa.retry = _getlong(cp);
5193 			cp += INT32SZ;
5194 			soa.expire = _getlong(cp);
5195 			cp += INT32SZ;
5196 			soa.defttl = _getlong(cp);
5197 			cp += INT32SZ;
5198 
5199 			/* valid complete soa record found */
5200 			soaname = strxcpy(soanamebuf, rname, MAXDNAME+1);
5201 		}
5202 		else
5203 		{
5204 			/* just ignore other records */
5205 			cp += dlen;
5206 		}
5207 
5208 		if (cp != eor)
5209 		{
5210 			pr_error("size error in %s record for %s, off by %s",
5211 				pr_type(type), rname, itoa(cp - eor));
5212 			h_errno = NO_RECOVERY;
5213 			return(false);
5214 		}
5215 
5216 		ancount--;
5217 	}
5218 
5219 	if (ancount)
5220 	{
5221 		pr_error("invalid ancount after %s query for %s",
5222 			pr_type(T_SOA), name);
5223 		h_errno = NO_RECOVERY;
5224 		return(false);
5225 	}
5226 
5227 	/* set proper status if no answers found */
5228 	h_errno = (soaname != NULL) ? 0 : TRY_AGAIN;
5229 	return(true);
5230 }
5231 
5232 /*
5233 ** CHECK_SOA -- Analyze retrieved SOA records of a zone
5234 ** ----------------------------------------------------
5235 **
5236 **	Returns:
5237 **		None.
5238 **
5239 **	Inputs:
5240 **		The global variable ``server'' must contain the
5241 **		name of the server that was queried.
5242 **		The global struct ``soa'' must contain the soa data.
5243 */
5244 
5245 void
check_soa(answerbuf,name)5246 check_soa(answerbuf, name)
5247 input querybuf *answerbuf;		/* location of answer buffer */
5248 input char *name;			/* name of zone to check soa for */
5249 {
5250 	static char oldnamebuf[MAXDNAME+1];
5251 	static char *oldname = NULL;	/* previous name of zone */
5252 	static char *oldserver = NULL;	/* previous name of server */
5253 	static soa_data_t oldsoa;	/* previous soa data */
5254 	register int n;
5255 	HEADER *bp;
5256 
5257 /*
5258  * Print the various SOA fields in abbreviated form.
5259  * Values are actually unsigned, but we print them as signed integers,
5260  * apart from the serial which really becomes that big sometimes.
5261  * In the latter case we print a warning below.
5262  */
5263 	printf("%s\t%s\t(%u %d %d %d %d)\n",
5264 		soa.primary, soa.hostmaster, (unsigned)soa.serial,
5265 		soa.refresh, soa.retry, soa.expire, soa.defttl);
5266 
5267 /*
5268  * We are supposed to have queried an authoritative nameserver, and since
5269  * nameserver recursion has been turned off, answer must be authoritative.
5270  */
5271 	bp = (HEADER *)answerbuf;
5272 	if (!bp->aa)
5273 	{
5274 		if (authserver)
5275 			pr_error("%s SOA record at %s is not authoritative",
5276 				name, server);
5277 		else
5278 			pr_warning("%s SOA record at %s is not authoritative",
5279 				name, server);
5280 
5281 		if (authserver)
5282 			errmsg("%s has lame delegation to %s",
5283 				name, server);
5284 	}
5285 
5286 /*
5287  * Check whether we are switching to a new zone.
5288  * The old name must have been saved in static storage.
5289  */
5290 	if ((oldname != NULL) && !sameword(name, oldname))
5291 		oldname = NULL;
5292 
5293 /*
5294  * Make few timer consistency checks only for the first one in a series.
5295  * Compare the primary field against the list of authoritative servers.
5296  * Explicitly check the hostmaster field for illegal characters ('@').
5297  * Yell if the serial has the high bit set (not always intentional).
5298  */
5299 	if (oldname == NULL)
5300 	{
5301 		for (n = 0; n < nservers; n++)
5302 			if (sameword(soa.primary, nsname[n]))
5303 				break;	/* found */
5304 
5305 		if ((n >= nservers) && authserver)
5306 			pr_warning("%s SOA primary %s is not advertised via NS",
5307 				name, soa.primary);
5308 
5309 		if (!valid_name(soa.primary, false, false, false))
5310 			pr_warning("%s SOA primary %s has illegal name",
5311 				name, soa.primary);
5312 
5313 		if (!valid_name(soa.hostmaster, false, true, false))
5314 			pr_warning("%s SOA hostmaster %s has illegal mailbox",
5315 				name, soa.hostmaster);
5316 
5317 		if (bitset(0x80000000, soa.serial))
5318 			pr_warning("%s SOA serial has high bit set",
5319 				name);
5320 
5321 		if (soa.retry > soa.refresh)
5322 			pr_warning("%s SOA retry exceeds refresh",
5323 				name);
5324 
5325 		if (soa.refresh + soa.retry > soa.expire)
5326 			pr_warning("%s SOA refresh+retry exceeds expire",
5327 				name);
5328 	}
5329 
5330 /*
5331  * Compare various fields with those of the previous query, if any.
5332  * Different serial numbers may be present if secondaries have not yet
5333  * refreshed the data from the primary. Issue only a warning in that case.
5334  */
5335 	if (oldname != NULL)
5336 	{
5337 		if (!sameword(soa.primary, oldsoa.primary))
5338 			pr_error("%s and %s have different primary for %s",
5339 				server, oldserver, name);
5340 
5341 		if (!sameword(soa.hostmaster, oldsoa.hostmaster))
5342 			pr_error("%s and %s have different hostmaster for %s",
5343 				server, oldserver, name);
5344 
5345 		if (soa.serial != oldsoa.serial)
5346 			pr_warning("%s and %s have different serial for %s",
5347 				server, oldserver, name);
5348 
5349 		if (soa.refresh != oldsoa.refresh)
5350 			pr_error("%s and %s have different refresh for %s",
5351 				server, oldserver, name);
5352 
5353 		if (soa.retry != oldsoa.retry)
5354 			pr_error("%s and %s have different retry for %s",
5355 				server, oldserver, name);
5356 
5357 		if (soa.expire != oldsoa.expire)
5358 			pr_error("%s and %s have different expire for %s",
5359 				server, oldserver, name);
5360 
5361 		if (soa.defttl != oldsoa.defttl)
5362 			pr_error("%s and %s have different defttl for %s",
5363 				server, oldserver, name);
5364 	}
5365 
5366 /*
5367  * Save the current information.
5368  */
5369 	oldname = strxcpy(oldnamebuf, name, MAXDNAME+1);
5370 	oldserver = server;
5371 	oldsoa = soa;
5372 }
5373 
5374 /*
5375 ** CHECK_DUPL -- Check global address list for duplicates
5376 ** ------------------------------------------------------
5377 **
5378 **	Returns:
5379 **		true if the given host address already exists.
5380 **		false otherwise.
5381 **
5382 **	Side effects:
5383 **		Adds the host address to the list if not present.
5384 **
5385 **	The information in this table is global, and is not cleared.
5386 */
5387 
5388 #define AHASHSIZE	0x2000
5389 #define AHASHMASK	0x1fff
5390 
5391 typedef struct addr_tab {
5392 	ipaddr_t *addrlist;		/* global list of addresses */
5393 	int addrcount;			/* count of global addresses */
5394 } addr_tab_t;
5395 
5396 addr_tab_t addrtab[AHASHSIZE];		/* hash list of global addresses */
5397 
5398 bool
check_dupl(addr)5399 check_dupl(addr)
5400 input ipaddr_t addr;			/* address of host to check */
5401 {
5402  	register int i;
5403 	register addr_tab_t *s;
5404 
5405 	s = &addrtab[ntohl(addr) & AHASHMASK];
5406 
5407 	for (i = 0; i < s->addrcount; i++)
5408 		if (s->addrlist[i] == addr)
5409 			return(true);	/* duplicate */
5410 
5411 	s->addrlist = newlist(s->addrlist, s->addrcount+1, ipaddr_t);
5412 	s->addrlist[s->addrcount] = addr;
5413 	s->addrcount++;
5414 	return(false);
5415 }
5416 
5417 /*
5418 ** CHECK_TTL -- Check list of records for different ttl values
5419 ** -----------------------------------------------------------
5420 **
5421 **	Returns:
5422 **		true if the ttl value matches the first record
5423 **		already listed with the same name/type/class.
5424 **		false only when the first discrepancy is found.
5425 **
5426 **	Side effects:
5427 **		Adds the record data to the list if not present.
5428 */
5429 
5430 #define THASHSIZE	2003
5431 
5432 typedef struct ttl_tab {
5433 	struct ttl_tab *next;		/* next entry in chain */
5434 	char *name;			/* name of resource record */
5435 	int type;			/* resource record type */
5436 	int class;			/* resource record class */
5437 	int ttl;			/* time_to_live value */
5438 	int count;			/* count of different ttl values */
5439 } ttl_tab_t;
5440 
5441 ttl_tab_t *ttltab[THASHSIZE];		/* hash list of record info */
5442 
5443 bool
check_ttl(name,type,class,ttl)5444 check_ttl(name, type, class, ttl)
5445 input char *name;			/* resource record name */
5446 input int type, class, ttl;		/* resource record fixed values */
5447 {
5448 	register ttl_tab_t *s;
5449 	register ttl_tab_t **ps;
5450 	register unsigned int hfunc;
5451 	register char *p;
5452 	register char c;
5453 
5454 /*
5455  * Compute the hash function for this resource record.
5456  * Look it up in the appropriate hash chain.
5457  */
5458 	for (hfunc = type, p = name; (c = *p) != '\0'; p++)
5459 	{
5460 		hfunc = ((hfunc << 1) ^ (lowercase(c) & 0377)) % THASHSIZE;
5461 	}
5462 
5463 	for (ps = &ttltab[hfunc]; (s = *ps) != NULL; ps = &s->next)
5464 	{
5465 		if (s->type != type || s->class != class)
5466 			continue;
5467 		if (sameword(s->name, name))
5468 			break;
5469 	}
5470 
5471 /*
5472  * Allocate new entry if not found.
5473  */
5474 	if (s == NULL)
5475 	{
5476 		/* ps = &ttltab[hfunc]; */
5477 		s = newstruct(ttl_tab_t);
5478 
5479 		/* initialize new entry */
5480 		s->name = newstr(name);
5481 		s->type = type;
5482 		s->class = class;
5483 		s->ttl = ttl;
5484 		s->count = 0;
5485 
5486 		/* link it in */
5487 		s->next = *ps;
5488 		*ps = s;
5489 	}
5490 
5491 /*
5492  * Check whether the ttl value matches the first recorded one.
5493  * If not, signal only the first discrepancy encountered, so
5494  * only one warning message will be printed.
5495  */
5496 	if (s->ttl == ttl)
5497 		return(true);
5498 
5499 	s->count += 1;
5500 	return((s->count == 1) ? false : true);
5501 }
5502 
5503 /*
5504 ** CLEAR_TTLTAB -- Clear resource record list for ttl checking
5505 ** -----------------------------------------------------------
5506 **
5507 **	Returns:
5508 **		None.
5509 **
5510 **	An entry on the hash list, and the host name in each
5511 **	entry, have been allocated in dynamic memory.
5512 **
5513 **	The information in this table is on a per-zone basis.
5514 **	It must be cleared before any subsequent zone transfers.
5515 */
5516 
5517 void
clear_ttltab()5518 clear_ttltab()
5519 {
5520 	register int i;
5521 	register ttl_tab_t *s, *t;
5522 
5523 	for (i = 0; i < THASHSIZE; i++)
5524 	{
5525 		if (ttltab[i] != NULL)
5526 		{
5527 			/* free chain of entries */
5528 			for (t = NULL, s = ttltab[i]; s != NULL; s = t)
5529 			{
5530 				t = s->next;
5531 				xfree(s->name);
5532 				xfree(s);
5533 			}
5534 
5535 			/* reset hash chain */
5536 			ttltab[i] = NULL;
5537 		}
5538 	}
5539 }
5540 
5541 /*
5542 ** HOST_INDEX -- Check list of host names for name being present
5543 ** -------------------------------------------------------------
5544 **
5545 **	Returns:
5546 **		Index into hostname[] table, if found.
5547 **		Current ``hostcount'' value, if not found.
5548 **
5549 **	Side effects:
5550 **		May add an entry to the hash list if not present.
5551 **
5552 **	A linear search through the master table becomes very
5553 **	costly for zones with more than a few thousand hosts.
5554 **	Maintain a hash list with indexes into the master table.
5555 **	Caller should update the master table after this call.
5556 */
5557 
5558 #define HHASHSIZE	2003
5559 
5560 typedef struct host_tab {
5561 	struct host_tab *next;		/* next entry in chain */
5562 	int slot;			/* slot in host name table */
5563 } host_tab_t;
5564 
5565 host_tab_t *hosttab[HHASHSIZE];		/* hash list of host name info */
5566 
5567 int
host_index(name,enter)5568 host_index(name, enter)
5569 input char *name;			/* the host name to check */
5570 input bool enter;			/* add to table if not found */
5571 {
5572 	register host_tab_t *s;
5573 	register host_tab_t **ps;
5574 	register unsigned int hfunc;
5575 	register char *p;
5576 	register char c;
5577 
5578 /*
5579  * Compute the hash function for this host name.
5580  * Look it up in the appropriate hash chain.
5581  */
5582 	for (hfunc = 0, p = name; (c = *p) != '\0'; p++)
5583 	{
5584 		hfunc = ((hfunc << 1) ^ (lowercase(c) & 0377)) % HHASHSIZE;
5585 	}
5586 
5587 	for (ps = &hosttab[hfunc]; (s = *ps) != NULL; ps = &s->next)
5588 	{
5589 		if (s->slot >= hostcount)
5590 			continue;
5591 		if (sameword(hostname(s->slot), name))
5592 			break;
5593 	}
5594 
5595 /*
5596  * Allocate new entry if not found.
5597  */
5598 	if ((s == NULL) && enter)
5599 	{
5600 		/* ps = &hosttab[hfunc]; */
5601 		s = newstruct(host_tab_t);
5602 
5603 		/* initialize new entry */
5604 		s->slot = hostcount;
5605 
5606 		/* link it in */
5607 		s->next = *ps;
5608 		*ps = s;
5609 	}
5610 
5611 	return((s != NULL) ? s->slot : hostcount);
5612 }
5613 
5614 /*
5615 ** CLEAR_HOSTTAB -- Clear hash list for host name checking
5616 ** -------------------------------------------------------
5617 **
5618 **	Returns:
5619 **		None.
5620 **
5621 **	A hash list entry has been allocated in dynamic memory.
5622 **
5623 **	The information in this table is on a per-zone basis.
5624 **	It must be cleared before any subsequent zone transfers.
5625 */
5626 
5627 void
clear_hosttab()5628 clear_hosttab()
5629 {
5630 	register int i;
5631 	register host_tab_t *s, *t;
5632 
5633 	for (i = 0; i < HHASHSIZE; i++)
5634 	{
5635 		if (hosttab[i] != NULL)
5636 		{
5637 			/* free chain of entries */
5638 			for (t = NULL, s = hosttab[i]; s != NULL; s = t)
5639 			{
5640 				t = s->next;
5641 				xfree(s);
5642 			}
5643 
5644 			/* reset hash chain */
5645 			hosttab[i] = NULL;
5646 		}
5647 	}
5648 }
5649 
5650 /*
5651 ** ZONE_INDEX -- Check list of zone names for name being present
5652 ** -------------------------------------------------------------
5653 **
5654 **	Returns:
5655 **		Index into zonename[] table, if found.
5656 **		Current ``zonecount'' value, if not found.
5657 **
5658 **	Side effects:
5659 **		May add an entry to the hash list if not present.
5660 **
5661 **	A linear search through the master table becomes very
5662 **	costly for more than a few thousand delegated zones.
5663 **	Maintain a hash list with indexes into the master table.
5664 **	Caller should update the master table after this call.
5665 */
5666 
5667 #define ZHASHSIZE	2003
5668 
5669 typedef struct zone_tab {
5670 	struct zone_tab *next;		/* next entry in chain */
5671 	int slot;			/* slot in zone name table */
5672 } zone_tab_t;
5673 
5674 zone_tab_t *zonetab[ZHASHSIZE];		/* hash list of zone name info */
5675 
5676 int
zone_index(name,enter)5677 zone_index(name, enter)
5678 input char *name;			/* the zone name to check */
5679 input bool enter;			/* add to table if not found */
5680 {
5681 	register zone_tab_t *s;
5682 	register zone_tab_t **ps;
5683 	register unsigned int hfunc;
5684 	register char *p;
5685 	register char c;
5686 
5687 /*
5688  * Compute the hash function for this zone name.
5689  * Look it up in the appropriate hash chain.
5690  */
5691 	for (hfunc = 0, p = name; (c = *p) != '\0'; p++)
5692 	{
5693 		hfunc = ((hfunc << 1) ^ (lowercase(c) & 0377)) % ZHASHSIZE;
5694 	}
5695 
5696 	for (ps = &zonetab[hfunc]; (s = *ps) != NULL; ps = &s->next)
5697 	{
5698 		if (s->slot >= zonecount)
5699 			continue;
5700 		if (sameword(zonename[s->slot], name))
5701 			break;
5702 	}
5703 
5704 /*
5705  * Allocate new entry if not found.
5706  */
5707 	if ((s == NULL) && enter)
5708 	{
5709 		/* ps = &zonetab[hfunc]; */
5710 		s = newstruct(zone_tab_t);
5711 
5712 		/* initialize new entry */
5713 		s->slot = zonecount;
5714 
5715 		/* link it in */
5716 		s->next = *ps;
5717 		*ps = s;
5718 	}
5719 
5720 	return((s != NULL) ? s->slot : zonecount);
5721 }
5722 
5723 /*
5724 ** CLEAR_ZONETAB -- Clear hash list for zone name checking
5725 ** -------------------------------------------------------
5726 **
5727 **	Returns:
5728 **		None.
5729 **
5730 **	A hash list entry has been allocated in dynamic memory.
5731 **
5732 **	The information in this table is on a per-zone basis.
5733 **	It must be cleared before any subsequent zone transfers.
5734 */
5735 
5736 void
clear_zonetab()5737 clear_zonetab()
5738 {
5739 	register int i;
5740 	register zone_tab_t *s, *t;
5741 
5742 	for (i = 0; i < ZHASHSIZE; i++)
5743 	{
5744 		if (zonetab[i] != NULL)
5745 		{
5746 			/* free chain of entries */
5747 			for (t = NULL, s = zonetab[i]; s != NULL; s = t)
5748 			{
5749 				t = s->next;
5750 				xfree(s);
5751 			}
5752 
5753 			/* reset hash chain */
5754 			zonetab[i] = NULL;
5755 		}
5756 	}
5757 }
5758 
5759 /*
5760 ** CHECK_CANON -- Check list of domain names for name being canonical
5761 ** ------------------------------------------------------------------
5762 **
5763 **	Returns:
5764 **		Nonzero if the name is definitely not canonical.
5765 **		0 if it is canonical, or if it remains undecided.
5766 **
5767 **	Side effects:
5768 **		Adds the domain name to the list if not present.
5769 **
5770 **	The information in this table is global, and is not cleared
5771 **	(which may be necessary if the checking algorithm changes).
5772 */
5773 
5774 #define CHASHSIZE	2003
5775 
5776 typedef struct canon_tab {
5777 	struct canon_tab *next;		/* next entry in chain */
5778 	char *name;			/* domain name */
5779 	int status;			/* nonzero if not canonical */
5780 } canon_tab_t;
5781 
5782 canon_tab_t *canontab[CHASHSIZE];	/* hash list of domain name info */
5783 
5784 int
check_canon(name)5785 check_canon(name)
5786 input char *name;			/* the domain name to check */
5787 {
5788 	register canon_tab_t *s;
5789 	register canon_tab_t **ps;
5790 	register unsigned int hfunc;
5791 	register char *p;
5792 	register char c;
5793 
5794 /*
5795  * Compute the hash function for this domain name.
5796  * Look it up in the appropriate hash chain.
5797  */
5798 	for (hfunc = 0, p = name; (c = *p) != '\0'; p++)
5799 	{
5800 		hfunc = ((hfunc << 1) ^ (lowercase(c) & 0377)) % CHASHSIZE;
5801 	}
5802 
5803 	for (ps = &canontab[hfunc]; (s = *ps) != NULL; ps = &s->next)
5804 	{
5805 		if (sameword(s->name, name))
5806 			break;
5807 	}
5808 
5809 /*
5810  * Allocate new entry if not found.
5811  * Only then is the actual check carried out.
5812  */
5813 	if (s == NULL)
5814 	{
5815 		/* ps = &canontab[hfunc]; */
5816 		s = newstruct(canon_tab_t);
5817 
5818 		/* initialize new entry */
5819 		s->name = newstr(name);
5820 		s->status = canonical(name);
5821 
5822 		/* link it in */
5823 		s->next = *ps;
5824 		*ps = s;
5825 	}
5826 
5827 	return(s->status);
5828 }
5829 
5830 /*
5831 ** CHECK_ADDR -- Check whether reverse address mappings revert to host
5832 ** -------------------------------------------------------------------
5833 **
5834 **	Returns:
5835 **		true if all addresses of host map back to host.
5836 **		false otherwise.
5837 */
5838 
5839 bool
check_addr(name)5840 check_addr(name)
5841 input char *name;			/* host name to check addresses for */
5842 {
5843 	struct hostent *hp;
5844 	register int i;
5845 	struct in_addr inaddr[MAXADDRS];
5846 	int naddress;
5847 	char hnamebuf[MAXDNAME+1];
5848 	char *hname;
5849 	char inamebuf[MAXDNAME+1];
5850 	char *iname;
5851 	int matched;
5852 
5853 /*
5854  * Look up the specified host to fetch its addresses.
5855  */
5856 	hp = gethostbyname(name);
5857 	if (hp == NULL)
5858 	{
5859 		ns_error(name, T_A, C_IN, server);
5860 		return(false);
5861 	}
5862 
5863 	hname = strncpy(hnamebuf, hp->h_name, MAXDNAME);
5864 	hname[MAXDNAME] = '\0';
5865 
5866 	for (i = 0; i < MAXADDRS && hp->h_addr_list[i]; i++)
5867 		inaddr[i] = incopy(hp->h_addr_list[i]);
5868 	naddress = i;
5869 
5870 	if (verbose)
5871 		printf("Found %d address%s for %s\n",
5872 			naddress, plurale(naddress), hname);
5873 
5874 /*
5875  * Map back the addresses found, and check whether they revert to host.
5876  */
5877 	for (matched = 0, i = 0; i < naddress; i++)
5878 	{
5879 		iname = strxcpy(inamebuf, inet_ntoa(inaddr[i]), MAXDNAME+1);
5880 
5881 		if (verbose)
5882 			printf("Checking %s address %s\n", hname, iname);
5883 
5884 		hp = gethostbyaddr((char *)&inaddr[i], INADDRSZ, AF_INET);
5885 		if (hp == NULL)
5886 			ns_error(iname, T_PTR, C_IN, server);
5887 		else if (!sameword(hp->h_name, hname))
5888 			pr_warning("%s address %s maps to %s",
5889 				hname, iname, hp->h_name);
5890 		else
5891 			matched++;
5892 	}
5893 
5894 	return((matched == naddress) ? true : false);
5895 }
5896 
5897 /*
5898 ** CHECK_NAME -- Check whether address belongs to host addresses
5899 ** -------------------------------------------------------------
5900 **
5901 **	Returns:
5902 **		true if given address was found among host addresses.
5903 **		false otherwise.
5904 */
5905 
5906 bool
check_name(addr)5907 check_name(addr)
5908 input ipaddr_t addr;			/* address of host to check */
5909 {
5910 	struct hostent *hp;
5911 	register int i;
5912 	struct in_addr inaddr;
5913 	char hnamebuf[MAXDNAME+1];
5914 	char *hname;
5915 	char inamebuf[MAXDNAME+1];
5916 	char *iname;
5917 	int matched;
5918 
5919 /*
5920  * Check whether the address is registered by fetching its host name.
5921  */
5922 	inaddr.s_addr = addr;
5923 	iname = strxcpy(inamebuf, inet_ntoa(inaddr), MAXDNAME+1);
5924 
5925 	hp = gethostbyaddr((char *)&inaddr, INADDRSZ, AF_INET);
5926 	if (hp == NULL)
5927 	{
5928 		ns_error(iname, T_PTR, C_IN, server);
5929 		return(false);
5930 	}
5931 
5932 	hname = strncpy(hnamebuf, hp->h_name, MAXDNAME);
5933 	hname[MAXDNAME] = '\0';
5934 
5935 	if (verbose)
5936 		printf("Address %s maps to %s\n", iname, hname);
5937 
5938 /*
5939  * Lookup the host name found to fetch its addresses.
5940  */
5941 	hp = gethostbyname(hname);
5942 	if (hp == NULL)
5943 	{
5944 		ns_error(hname, T_A, C_IN, server);
5945 		return(false);
5946 	}
5947 
5948 /*
5949  * Verify whether the mapped host name is canonical.
5950  */
5951 	if (!sameword(hp->h_name, hname))
5952 		pr_warning("%s host %s is not canonical (%s)",
5953 			iname, hname, hp->h_name);
5954 
5955 /*
5956  * Check whether the given address is listed among the known addresses.
5957  */
5958 	for (matched = 0, i = 0; hp->h_addr_list[i]; i++)
5959 	{
5960 		inaddr = incopy(hp->h_addr_list[i]);
5961 
5962 		if (verbose)
5963 			printf("Checking %s address %s\n",
5964 				hname, inet_ntoa(inaddr));
5965 
5966 		if (inaddr.s_addr == addr)
5967 			matched++;
5968 	}
5969 
5970 	if (!matched)
5971 		pr_error("address %s does not belong to %s",
5972 			iname, hname);
5973 
5974 	return(matched ? true : false);
5975 }
5976 
5977 /*
5978 ** GETH_BYNAME -- Wrapper for gethostbyname
5979 ** ----------------------------------------
5980 **
5981 **	Returns:
5982 **		Pointer to struct hostent if lookup was successful.
5983 **		NULL otherwise.
5984 **
5985 **	Note. This routine works for fully qualified names only.
5986 **	The entire special res_search() processing can be skipped.
5987 */
5988 
5989 struct hostent *
geth_byname(name)5990 geth_byname(name)
5991 input const char *name;			/* name to do forward lookup for */
5992 {
5993 	querybuf answer;
5994 	struct hostent *hp;
5995 	register int n;
5996 
5997 	hp = gethostbyname(name);
5998 	if (hp != NULL)
5999 		return(hp);
6000 
6001 	if (verbose > print_level)
6002 		printf("Finding addresses for %s ...\n", name);
6003 
6004 	n = get_info(&answer, name, T_A, C_IN);
6005 	if (n < 0)
6006 		return(NULL);
6007 
6008 	if ((verbose > print_level + 1) && (print_level < 1))
6009 		(void) print_info(&answer, n, name, T_A, C_IN, false);
6010 
6011 	hp = gethostbyname(name);
6012 	return(hp);
6013 }
6014 
6015 /*
6016 ** GETH_BYADDR -- Wrapper for gethostbyaddr
6017 ** ----------------------------------------
6018 **
6019 **	Returns:
6020 **		Pointer to struct hostent if lookup was successful.
6021 **		NULL otherwise.
6022 */
6023 
6024 struct hostent *
geth_byaddr(addr,size,family)6025 geth_byaddr(addr, size, family)
6026 input const char *addr;			/* address to do reverse mapping for */
6027 input int size;				/* size of the address */
6028 input int family;			/* address family */
6029 {
6030 	char addrbuf[4*4 + sizeof(ARPA_ROOT) + 1];
6031 	char *name = addrbuf;
6032 	u_char *a = (u_char *)addr;
6033 	querybuf answer;
6034 	struct hostent *hp;
6035 	register int n;
6036 
6037 	if (size != INADDRSZ || family != AF_INET)
6038 	{
6039 		hp = gethostbyaddr(addr, size, family);
6040 		return(hp);
6041 	}
6042 
6043 	hp = gethostbyaddr(addr, size, family);
6044 	if (hp != NULL)
6045 		return(hp);
6046 
6047 	/* construct absolute reverse name *without* trailing dot */
6048 	(void) snprintf(addrbuf, sizeof addrbuf, "%u.%u.%u.%u.%s",
6049 		a[3]&0xff, a[2]&0xff, a[1]&0xff, a[0]&0xff, ARPA_ROOT);
6050 
6051 	if (verbose > print_level)
6052 		printf("Finding reverse mapping for %s ...\n",
6053 			inet_ntoa(incopy(addr)));
6054 
6055 	n = get_info(&answer, name, T_PTR, C_IN);
6056 	if (n < 0)
6057 		return(NULL);
6058 
6059 	if ((verbose > print_level + 1) && (print_level < 1))
6060 		(void) print_info(&answer, n, name, T_PTR, C_IN, false);
6061 
6062 	hp = gethostbyaddr(addr, size, family);
6063 	return(hp);
6064 }
6065 
6066 /*
6067 ** PARSE_TYPE -- Decode rr type from input string
6068 ** ----------------------------------------------
6069 **
6070 **	Returns:
6071 **		Value of resource record type.
6072 **		-1 if specified record name is invalid.
6073 **
6074 **	Note.	Several types are deprecated or obsolete, but recognized.
6075 **		T_AXFR/T_IXFR is not allowed to be specified as query type.
6076 */
6077 
6078 int
parse_type(str)6079 parse_type(str)
6080 input char *str;			/* input string with record type */
6081 {
6082 	register int type;
6083 
6084 		/* standard types */
6085 
6086 	if (sameword(str, "A"))		return(T_A);
6087 	if (sameword(str, "NS"))	return(T_NS);
6088 	if (sameword(str, "MD"))	return(T_MD);		/* obsolete */
6089 	if (sameword(str, "MF"))	return(T_MF);		/* obsolete */
6090 	if (sameword(str, "CNAME"))	return(T_CNAME);
6091 	if (sameword(str, "SOA"))	return(T_SOA);
6092 	if (sameword(str, "MB"))	return(T_MB);		/* deprecated */
6093 	if (sameword(str, "MG"))	return(T_MG);		/* deprecated */
6094 	if (sameword(str, "MR"))	return(T_MR);		/* deprecated */
6095 	if (sameword(str, "NULL"))	return(T_NULL);		/* obsolete */
6096 	if (sameword(str, "WKS"))	return(T_WKS);
6097 	if (sameword(str, "PTR"))	return(T_PTR);
6098 	if (sameword(str, "HINFO"))	return(T_HINFO);
6099 	if (sameword(str, "MINFO"))	return(T_MINFO);	/* deprecated */
6100 	if (sameword(str, "MX"))	return(T_MX);
6101 	if (sameword(str, "TXT"))	return(T_TXT);
6102 
6103 		/* new types */
6104 
6105 	if (sameword(str, "RP"))	return(T_RP);
6106 	if (sameword(str, "AFSDB"))	return(T_AFSDB);
6107 	if (sameword(str, "X25"))	return(T_X25);
6108 	if (sameword(str, "ISDN"))	return(T_ISDN);
6109 	if (sameword(str, "RT"))	return(T_RT);
6110 	if (sameword(str, "NSAP"))	return(T_NSAP);
6111 	if (sameword(str, "NSAP-PTR"))	return(T_NSAPPTR);
6112 	if (sameword(str, "SIG"))	return(T_SIG);
6113 	if (sameword(str, "KEY"))	return(T_KEY);
6114 	if (sameword(str, "PX"))	return(T_PX);
6115 	if (sameword(str, "GPOS"))	return(T_GPOS);		/* withdrawn */
6116 	if (sameword(str, "AAAA"))	return(T_AAAA);
6117 	if (sameword(str, "LOC"))	return(T_LOC);
6118 	if (sameword(str, "NXT"))	return(T_NXT);
6119 	if (sameword(str, "EID"))	return(T_EID);
6120 	if (sameword(str, "NIMLOC"))	return(T_NIMLOC);
6121 	if (sameword(str, "SRV"))	return(T_SRV);
6122 	if (sameword(str, "ATMA"))	return(T_ATMA);
6123 	if (sameword(str, "NAPTR"))	return(T_NAPTR);
6124 
6125 		/* nonstandard types */
6126 
6127 	if (sameword(str, "UINFO"))	return(T_UINFO);
6128 	if (sameword(str, "UID"))	return(T_UID);
6129 	if (sameword(str, "GID"))	return(T_GID);
6130 	if (sameword(str, "UNSPEC"))	return(T_UNSPEC);
6131 
6132 		/* filters */
6133 
6134 	if (sameword(str, "IXFR"))	return(-1);		/* illegal */
6135 	if (sameword(str, "AXFR"))	return(-1);		/* illegal */
6136 	if (sameword(str, "MAILB"))	return(T_MAILB);
6137 	if (sameword(str, "MAILA"))	return(T_MAILA);	/* obsolete */
6138 	if (sameword(str, "ANY"))	return(T_ANY);
6139 	if (sameword(str, "*"))		return(T_ANY);
6140 
6141 		/* unknown types */
6142 
6143 	type = atoi(str);
6144 	if (type >= T_FIRST && type <= T_LAST)
6145 		return(type);
6146 
6147 	return(-1);
6148 }
6149 
6150 /*
6151 ** PARSE_CLASS -- Decode rr class from input string
6152 ** ------------------------------------------------
6153 **
6154 **	Returns:
6155 **		Value of resource class.
6156 **		-1 if specified class name is invalid.
6157 **
6158 **	Note.	C_CSNET is obsolete, but recognized.
6159 */
6160 
6161 int
parse_class(str)6162 parse_class(str)
6163 input char *str;			/* input string with resource class */
6164 {
6165 	register int class;
6166 
6167 	if (sameword(str, "IN"))	return(C_IN);
6168 	if (sameword(str, "INTERNET"))	return(C_IN);
6169 	if (sameword(str, "CS"))	return(C_CSNET);	/* obsolete */
6170 	if (sameword(str, "CSNET"))	return(C_CSNET);	/* obsolete */
6171 	if (sameword(str, "CH"))	return(C_CHAOS);
6172 	if (sameword(str, "CHAOS"))	return(C_CHAOS);
6173 	if (sameword(str, "HS"))	return(C_HS);
6174 	if (sameword(str, "HESIOD"))	return(C_HS);
6175 
6176 	if (sameword(str, "ANY"))	return(C_ANY);
6177 	if (sameword(str, "*"))		return(C_ANY);
6178 
6179 	class = atoi(str);
6180 	if (class > 0)
6181 		return(class);
6182 
6183 	return(-1);
6184 }
6185 
6186 /*
6187 ** IN_ADDR_ARPA -- Convert dotted quad string to reverse in-addr.arpa
6188 ** ------------------------------------------------------------------
6189 **
6190 **	Returns:
6191 **		Pointer to appropriate reverse in-addr.arpa name
6192 **		with trailing dot to force absolute domain name.
6193 **		NULL in case of invalid dotted quad input string.
6194 */
6195 
6196 char *
in_addr_arpa(dottedquad)6197 in_addr_arpa(dottedquad)
6198 input char *dottedquad;			/* input string with dotted quad */
6199 {
6200 	static char addrbuf[4*4 + sizeof(ARPA_ROOT) + 2];
6201 	unsigned int a[4];
6202 	register int n;
6203 
6204 	n = sscanf(dottedquad, "%u.%u.%u.%u", &a[0], &a[1], &a[2], &a[3]);
6205 	switch (n)
6206 	{
6207 	    case 4:
6208 		(void) snprintf(addrbuf, sizeof addrbuf, "%u.%u.%u.%u.%s.",
6209 			a[3]&0xff, a[2]&0xff, a[1]&0xff, a[0]&0xff, ARPA_ROOT);
6210 		break;
6211 
6212 	    case 3:
6213 		(void) snprintf(addrbuf, sizeof addrbuf, "%u.%u.%u.%s.",
6214 			a[2]&0xff, a[1]&0xff, a[0]&0xff, ARPA_ROOT);
6215 		break;
6216 
6217 	    case 2:
6218 		(void) snprintf(addrbuf, sizeof addrbuf, "%u.%u.%s.",
6219 			a[1]&0xff, a[0]&0xff, ARPA_ROOT);
6220 		break;
6221 
6222 	    case 1:
6223 		(void) snprintf(addrbuf, sizeof addrbuf, "%u.%s.",
6224 			a[0]&0xff, ARPA_ROOT);
6225 		break;
6226 
6227 	    default:
6228 		return(NULL);
6229 	}
6230 
6231 	while (--n >= 0)
6232 		if (a[n] > 255)
6233 			return(NULL);
6234 
6235 	return(addrbuf);
6236 }
6237 
6238 /*
6239 ** NSAP_INT -- Convert dotted nsap address string to reverse nsap.int
6240 ** ------------------------------------------------------------------
6241 **
6242 **	Returns:
6243 **		Pointer to appropriate reverse nsap.int name
6244 **		with trailing dot to force absolute domain name.
6245 **		NULL in case of invalid nsap address input string.
6246 */
6247 
6248 char *
nsap_int(name)6249 nsap_int(name)
6250 input char *name;			/* input string with dotted nsap */
6251 {
6252 	static char addrbuf[4*MAXNSAP + sizeof(NSAP_ROOT) + 2];
6253 	register int n;
6254 	register int i;
6255 
6256 	/* skip optional leading hex indicator */
6257 	if (samehead(name, "0x"))
6258 		name += 2;
6259 
6260 	for (n = 0, i = strlength(name)-1; i >= 0; --i)
6261 	{
6262 		/* skip optional interspersed separators */
6263 		if (name[i] == '.' || name[i] == '+' || name[i] == '/')
6264 			continue;
6265 
6266 		/* must consist of hex digits only */
6267 		if (!is_xdigit(name[i]))
6268 			return(NULL);
6269 
6270 		/* but not too many */
6271 		if (n >= 4*MAXNSAP)
6272 			return(NULL);
6273 
6274 		addrbuf[n++] = name[i];
6275 		addrbuf[n++] = '.';
6276 	}
6277 
6278 	/* must have an even number of hex digits */
6279 	if (n == 0 || (n % 4) != 0)
6280 		return(NULL);
6281 
6282 	(void) snprintf(&addrbuf[n], (sizeof addrbuf)-n, "%s.", NSAP_ROOT);
6283 	return(addrbuf);
6284 }
6285 
6286 /*
6287 ** PRINT_HOST -- Print host name and address of hostent struct
6288 ** -----------------------------------------------------------
6289 **
6290 **	Returns:
6291 **		None.
6292 */
6293 
6294 void
print_host(heading,hp)6295 print_host(heading, hp)
6296 input char *heading;			/* header string */
6297 input struct hostent *hp;		/* location of hostent struct */
6298 {
6299 	register char **ap;
6300 
6301 	printf("%s: %s", heading, hp->h_name);
6302 
6303 	for (ap = hp->h_addr_list; ap && *ap; ap++)
6304 	{
6305 		if (ap == hp->h_addr_list)
6306 			printf("\nAddress:");
6307 
6308 		printf(" %s", inet_ntoa(incopy(*ap)));
6309 	}
6310 
6311 	for (ap = hp->h_aliases; ap && *ap && **ap; ap++)
6312 	{
6313 		if (ap == hp->h_aliases)
6314 			printf("\nAliases:");
6315 
6316 		printf(" %s", *ap);
6317 	}
6318 
6319 	printf("\n\n");
6320 }
6321 
6322 /*
6323 ** SHOW_RES -- Show resolver database information
6324 ** ----------------------------------------------
6325 **
6326 **	Returns:
6327 **		None.
6328 **
6329 **	Inputs:
6330 **		The resolver database _res is localized in the resolver.
6331 */
6332 
6333 void
show_res()6334 show_res()
6335 {
6336 	register int i;
6337 	register char **domain;
6338 
6339 /*
6340  * The default domain is defined by the "domain" entry in /etc/resolv.conf
6341  * if not overridden by the environment variable "LOCALDOMAIN".
6342  * If still not defined, gethostname() may yield a fully qualified host name.
6343  */
6344 	printf("Default domain:");
6345 	if (_res.defdname[0] != '\0')
6346 		printf(" %s", _res.defdname);
6347 	printf("\n");
6348 
6349 /*
6350  * The search domains are extracted from the default domain components,
6351  * but may be overridden by "search" directives in /etc/resolv.conf
6352  * since 4.8.3.
6353  */
6354 	printf("Search domains:");
6355 	for (domain = _res.dnsrch; *domain; domain++)
6356 		printf(" %s", *domain);
6357 	printf("\n");
6358 
6359 /*
6360  * The routine res_send() will do _res.retry tries to contact each of the
6361  * _res.nscount nameserver addresses before giving up when using datagrams.
6362  * The first try will timeout after _res.retrans seconds. Each following
6363  * try will timeout after ((_res.retrans << try) / _res.nscount) seconds.
6364  * Note. When we contact an explicit server the addresses will be replaced
6365  * by the multiple addresses of the same server.
6366  * When doing a zone transfer _res.retrans is used for the connect timeout.
6367  */
6368 	printf("Timeout per retry: %d secs\n", _res.retrans);
6369 	printf("Number of retries: %d\n", _res.retry);
6370 
6371 	printf("Number of addresses: %d\n", _res.nscount);
6372 	for (i = 0; i < _res.nscount; i++)
6373 		printf("%s\n", inet_ntoa(nslist(i).sin_addr));
6374 
6375 /*
6376  * The resolver options are initialized by res_init() to contain the
6377  * defaults settings (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
6378  * The various options have the following meaning:
6379  *
6380  *	RES_INIT	set after res_init() has been called
6381  *	RES_DEBUG	let the resolver modules print debugging info
6382  *	RES_AAONLY	want authoritative answers only (not implemented)
6383  *	RES_USEVC	use tcp virtual circuit instead of udp datagrams
6384  *	RES_PRIMARY	use primary nameserver only (not implemented)
6385  *	RES_IGNTC	ignore datagram truncation; don't switch to tcp
6386  *	RES_RECURSE	forward query if answer not locally available
6387  *	RES_DEFNAMES	add default domain to queryname without dot
6388  *	RES_STAYOPEN	keep tcp socket open for subsequent queries
6389  *	RES_DNSRCH	append search domains even to queryname with dot
6390  */
6391 	printf("Options set:");
6392 	if (bitset(RES_INIT,      _res.options)) printf(" INIT");
6393 	if (bitset(RES_DEBUG,     _res.options)) printf(" DEBUG");
6394 	if (bitset(RES_AAONLY,    _res.options)) printf(" AAONLY");
6395 	if (bitset(RES_USEVC,     _res.options)) printf(" USEVC");
6396 	if (bitset(RES_PRIMARY,   _res.options)) printf(" PRIMARY");
6397 	if (bitset(RES_IGNTC,     _res.options)) printf(" IGNTC");
6398 	if (bitset(RES_RECURSE,   _res.options)) printf(" RECURSE");
6399 	if (bitset(RES_DEFNAMES,  _res.options)) printf(" DEFNAMES");
6400 	if (bitset(RES_STAYOPEN,  _res.options)) printf(" STAYOPEN");
6401 	if (bitset(RES_DNSRCH,    _res.options)) printf(" DNSRCH");
6402 	printf("\n");
6403 
6404 	printf("Options clr:");
6405 	if (!bitset(RES_INIT,     _res.options)) printf(" INIT");
6406 	if (!bitset(RES_DEBUG,    _res.options)) printf(" DEBUG");
6407 	if (!bitset(RES_AAONLY,   _res.options)) printf(" AAONLY");
6408 	if (!bitset(RES_USEVC,    _res.options)) printf(" USEVC");
6409 	if (!bitset(RES_PRIMARY,  _res.options)) printf(" PRIMARY");
6410 	if (!bitset(RES_IGNTC,    _res.options)) printf(" IGNTC");
6411 	if (!bitset(RES_RECURSE,  _res.options)) printf(" RECURSE");
6412 	if (!bitset(RES_DEFNAMES, _res.options)) printf(" DEFNAMES");
6413 	if (!bitset(RES_STAYOPEN, _res.options)) printf(" STAYOPEN");
6414 	if (!bitset(RES_DNSRCH,   _res.options)) printf(" DNSRCH");
6415 	printf("\n");
6416 
6417 /*
6418  * The new BIND 4.9.3 has additional features which are not (yet) used.
6419  */
6420 	printf("\n");
6421 }
6422 
6423 /*
6424 ** PRINT_STATISTICS -- Print resource record statistics
6425 ** ----------------------------------------------------
6426 **
6427 **	Returns:
6428 **		None.
6429 **
6430 **	Inputs:
6431 **		The record_stats[] counts have been updated by print_rrec().
6432 */
6433 
6434 void
print_statistics(name,filter,class)6435 print_statistics(name, filter, class)
6436 input char *name;			/* name of zone we are listing */
6437 input int filter;			/* type of records we want to see */
6438 input int class;			/* class of records we want to see */
6439 {
6440 	register int type;
6441 	int nrecords;
6442 
6443 	for (type = T_FIRST; type <= T_LAST; type++)
6444 	{
6445 		nrecords = record_stats[type];
6446 		if (nrecords > 0 || ((filter != T_ANY) && want_type(type, filter)))
6447 		{
6448 			printf("Found %4d %-5s record%-1s", nrecords,
6449 				pr_type(type), plural(nrecords));
6450 
6451 			if (class != C_IN)
6452 				printf(" in class %s", pr_class(class));
6453 
6454 			printf(" within %s\n", name);
6455 		}
6456 	}
6457 }
6458 
6459 
6460 /*
6461 ** CLEAR_STATISTICS -- Clear resource record statistics
6462 ** ----------------------------------------------------
6463 **
6464 **	Returns:
6465 **		None.
6466 */
6467 
6468 void
clear_statistics()6469 clear_statistics()
6470 {
6471 	bzero((char *)record_stats, sizeof(record_stats));
6472 }
6473 
6474 /*
6475 ** SHOW_TYPES -- Show resource record types wanted
6476 ** -----------------------------------------------
6477 **
6478 **	Returns:
6479 **		None.
6480 */
6481 
6482 void
show_types(name,filter,class)6483 show_types(name, filter, class)
6484 input char *name;			/* name we want to query about */
6485 input int filter;			/* type of records we want to see */
6486 input int class;			/* class of records we want to see */
6487 {
6488 	register int type;
6489 
6490 	if (filter >= T_NONE)
6491 	{
6492 		printf("Query about %s for record types", name);
6493 
6494 		if (filter == T_ANY)
6495 			printf(" %s", pr_type(T_ANY));
6496 		else
6497 			for (type = T_FIRST; type <= T_LAST; type++)
6498 				if (want_type(type, filter))
6499 					printf(" %s", pr_type(type));
6500 
6501 		if (class != C_IN)
6502 			printf(" in class %s", pr_class(class));
6503 
6504 		printf("\n");
6505 	}
6506 }
6507 
6508 /*
6509 ** NS_ERROR -- Print error message from errno and h_errno
6510 ** ------------------------------------------------------
6511 **
6512 **	Returns:
6513 **		None.
6514 **
6515 ** If BIND res_send() fails, it will leave errno in either of the first
6516 ** two following states when using datagrams. Note that this depends on
6517 ** the proper handling of connected datagram sockets, which is usually
6518 ** true if BSD >= 43 (see res_send.c for details; it may need a patch).
6519 ** Note. If the 4.8 version succeeds, it may leave errno as EAFNOSUPPORT
6520 ** if it has disconnected a previously connected datagram socket, since
6521 ** the dummy address used to disconnect does not have a proper family set.
6522 ** Always clear errno after getting a reply, or patch res_send().
6523 ** Our private version of res_send() will leave also other error statuses.
6524 */
6525 
6526 void
ns_error(name,type,class,host)6527 ns_error(name, type, class, host)
6528 input char *name;			/* full name we queried about */
6529 input int type;				/* record type we queried about */
6530 input int class;			/* record class we queried about */
6531 input char *host;			/* set if explicit server was used */
6532 {
6533 	static char *auth = "Authoritative answer";
6534 
6535 /*
6536  * Print the message associated with the network related errno values.
6537  */
6538 	switch (errno)
6539 	{
6540 	    case ECONNREFUSED:
6541 		/*
6542 		 * The contacted host does not have a nameserver running.
6543 		 * The standard res_send() also returns this if none of
6544 		 * the intended hosts could be reached via datagrams.
6545 		 */
6546 		if (host != NULL)
6547 			errmsg("Nameserver %s not running", host);
6548 		else
6549 			errmsg("Nameserver not running");
6550 		break;
6551 
6552 	    case ETIMEDOUT:
6553 		/*
6554 		 * The contacted server did not give any reply at all
6555 		 * within the specified time frame.
6556 		 */
6557 		if (host != NULL)
6558 			errmsg("Nameserver %s not responding", host);
6559 		else
6560 			errmsg("Nameserver not responding");
6561 		break;
6562 
6563 	    case ENETDOWN:
6564 	    case ENETUNREACH:
6565 	    case EHOSTDOWN:
6566 	    case EHOSTUNREACH:
6567 		/*
6568 		 * The host to be contacted or its network can not be reached.
6569 		 * Our private res_send() also returns this using datagrams.
6570 		 */
6571 		if (host != NULL)
6572 			errmsg("Nameserver %s not reachable", host);
6573 		else
6574 			errmsg("Nameserver not reachable");
6575 		break;
6576 	}
6577 
6578 /*
6579  * Print the message associated with the particular nameserver error.
6580  */
6581 	switch (h_errno)
6582 	{
6583 	    case HOST_NOT_FOUND:
6584 		/*
6585 		 * The specified name does definitely not exist at all.
6586 		 * In this case the answer is always authoritative.
6587 		 * Nameserver status: NXDOMAIN
6588 		 */
6589 		if (class != C_IN)
6590 			errmsg("%s does not exist in class %s (%s)",
6591 				name, pr_class(class), auth);
6592 		else if (host != NULL)
6593 			errmsg("%s does not exist at %s (%s)",
6594 				name, host, auth);
6595 		else
6596 			errmsg("%s does not exist (%s)",
6597 				name, auth);
6598 		break;
6599 
6600 	    case NO_HOST:
6601 		/*
6602 		 * The specified name does not exist, but the answer
6603 		 * was not authoritative, so it is still undecided.
6604 		 * Nameserver status: NXDOMAIN
6605 		 */
6606 		if (class != C_IN)
6607 			errmsg("%s does not exist in class %s, try again",
6608 				name, pr_class(class));
6609 		else if (host != NULL)
6610 			errmsg("%s does not exist at %s, try again",
6611 				name, host);
6612 		else
6613 			errmsg("%s does not exist, try again",
6614 				name);
6615 		break;
6616 
6617 	    case NO_DATA:
6618 		/*
6619 		 * The name is valid, but the specified type does not exist.
6620 		 * This status is here returned only in case authoritative.
6621 		 * Nameserver status: NOERROR
6622 		 */
6623 		if (class != C_IN)
6624 			errmsg("%s has no %s record in class %s (%s)",
6625 				name, pr_type(type), pr_class(class), auth);
6626 		else if (host != NULL)
6627 			errmsg("%s has no %s record at %s (%s)",
6628 				name, pr_type(type), host, auth);
6629 		else
6630 			errmsg("%s has no %s record (%s)",
6631 				name, pr_type(type), auth);
6632 		break;
6633 
6634 	    case NO_RREC:
6635 		/*
6636 		 * The specified type does not exist, but we don't know whether
6637 		 * the name is valid or not. The answer was not authoritative.
6638 		 * Perhaps recursion was off, and no data was cached locally.
6639 		 * Nameserver status: NOERROR
6640 		 */
6641 		if (class != C_IN)
6642 			errmsg("%s %s record in class %s currently not present",
6643 				name, pr_type(type), pr_class(class));
6644 		else if (host != NULL)
6645 			errmsg("%s %s record currently not present at %s",
6646 				name, pr_type(type), host);
6647 		else
6648 			errmsg("%s %s record currently not present",
6649 				name, pr_type(type));
6650 		break;
6651 
6652 	    case TRY_AGAIN:
6653 		/*
6654 		 * Some intermediate failure, e.g. connect timeout,
6655 		 * or some local operating system transient errors.
6656 		 * General failure to reach any appropriate servers.
6657 		 * The status SERVFAIL now yields a separate error code.
6658 		 * Nameserver status: (SERVFAIL)
6659 		 */
6660 		if (class != C_IN)
6661 			errmsg("%s %s record in class %s not found, try again",
6662 				name, pr_type(type), pr_class(class));
6663 		else if (host != NULL)
6664 			errmsg("%s %s record not found at %s, try again",
6665 				name, pr_type(type), host);
6666 		else
6667 			errmsg("%s %s record not found, try again",
6668 				name, pr_type(type));
6669 		break;
6670 
6671 	    case SERVER_FAILURE:
6672 		/*
6673 		 * Explicit server failure status. This will be returned upon
6674 		 * some internal server errors, forwarding failures, or when
6675 		 * the server is not authoritative for a specific class.
6676 		 * Also if the zone data has expired at a secondary server.
6677 		 * Nameserver status: SERVFAIL
6678 		 */
6679 		if (class != C_IN)
6680 			errmsg("%s %s record in class %s not found, server failure",
6681 				name, pr_type(type), pr_class(class));
6682 		else if (host != NULL)
6683 			errmsg("%s %s record not found at %s, server failure",
6684 				name, pr_type(type), host);
6685 		else
6686 			errmsg("%s %s record not found, server failure",
6687 				name, pr_type(type));
6688 		break;
6689 
6690 	    case NO_RECOVERY:
6691 		/*
6692 		 * Some irrecoverable format error, or server refusal.
6693 		 * The status REFUSED now yields a separate error code.
6694 		 * Nameserver status: (REFUSED) FORMERR NOTIMP NOCHANGE
6695 		 */
6696 		if (class != C_IN)
6697 			errmsg("%s %s record in class %s not found, no recovery",
6698 				name, pr_type(type), pr_class(class));
6699 		else if (host != NULL)
6700 			errmsg("%s %s record not found at %s, no recovery",
6701 				name, pr_type(type), host);
6702 		else
6703 			errmsg("%s %s record not found, no recovery",
6704 				name, pr_type(type));
6705 		break;
6706 
6707 	    case QUERY_REFUSED:
6708 		/*
6709 		 * The server explicitly refused to answer the query.
6710 		 * Servers can be configured to disallow zone transfers.
6711 		 * Nameserver status: REFUSED
6712 		 */
6713 		if (class != C_IN)
6714 			errmsg("%s %s record in class %s query refused",
6715 				name, pr_type(type), pr_class(class));
6716 		else if (host != NULL)
6717 			errmsg("%s %s record query refused by %s",
6718 				name, pr_type(type), host);
6719 		else
6720 			errmsg("%s %s record query refused",
6721 				name, pr_type(type));
6722 		break;
6723 
6724 	    default:
6725 		/*
6726 		 * Unknown cause for server failure.
6727 		 */
6728 		if (class != C_IN)
6729 			errmsg("%s %s record in class %s not found",
6730 				name, pr_type(type), pr_class(class));
6731 		else if (host != NULL)
6732 			errmsg("%s %s record not found at %s",
6733 				name, pr_type(type), host);
6734 		else
6735 			errmsg("%s %s record not found",
6736 				name, pr_type(type));
6737 		break;
6738 	}
6739 }
6740 
6741 /*
6742 ** DECODE_ERROR -- Convert nameserver error code to error message
6743 ** --------------------------------------------------------------
6744 **
6745 **	Returns:
6746 **		Pointer to appropriate error message.
6747 */
6748 
6749 char *
decode_error(rcode)6750 decode_error(rcode)
6751 input int rcode;			/* error code from bp->rcode */
6752 {
6753 	switch (rcode)
6754 	{
6755 	    case NOERROR: 	return("no error");
6756 	    case FORMERR:	return("format error");
6757 	    case SERVFAIL:	return("server failure");
6758 	    case NXDOMAIN:	return("non-existent domain");
6759 	    case NOTIMP:	return("not implemented");
6760 	    case REFUSED:	return("query refused");
6761 	    case NOCHANGE:	return("no change");
6762 	}
6763 
6764 	return("unknown error");
6765 }
6766 
6767 /*
6768 ** PRINT_STATUS -- Print result status after nameserver query
6769 ** ----------------------------------------------------------
6770 **
6771 **	Returns:
6772 **		None.
6773 **
6774 **	Conditions:
6775 **		The size of the answer buffer must have been
6776 **		checked before to be of sufficient length,
6777 **		i.e. to contain at least the buffer header.
6778 */
6779 
6780 void
print_status(answerbuf,answerlen)6781 print_status(answerbuf, answerlen)
6782 input querybuf *answerbuf;		/* location of answer buffer */
6783 input int answerlen;			/* length of answer buffer */
6784 {
6785 	HEADER *bp;
6786 	int ancount;
6787 	bool failed;
6788 
6789 	bp = (HEADER *)answerbuf;
6790 	ancount = ntohs(bp->ancount);
6791 	failed = (bp->rcode != NOERROR || ancount == 0);
6792 
6793 	printf("Query %s", failed ? "failed" : "done");
6794 
6795 	if (bp->tc || (answerlen > PACKETSZ))
6796 		printf(", %d byte%s", answerlen, plural(answerlen));
6797 
6798 	if (bp->tc)
6799 	{
6800 		if (answerlen > sizeof(querybuf))
6801 			printf(" (truncated to %zu)", sizeof (querybuf));
6802 		else
6803 			printf(" (truncated)");
6804 	}
6805 
6806 	printf(", %d answer%s", ancount, plural(ancount));
6807 
6808 	printf(", %s", bp->aa ? "authoritative " : "");
6809 
6810 	printf("status: %s\n", decode_error((int)bp->rcode));
6811 }
6812 
6813 /*
6814 ** PR_ERROR -- Print error message about encountered inconsistencies
6815 ** -----------------------------------------------------------------
6816 **
6817 **	We are supposed to have an error condition which is fatal
6818 **	for normal continuation, and the message is always printed.
6819 **
6820 **	Returns:
6821 **		None.
6822 **
6823 **	Side effects:
6824 **		Increments the global error count.
6825 */
6826 
6827 void /*VARARGS1*/
pr_error(fmt,a,b,c,d)6828 pr_error(fmt, a, b, c, d)
6829 input char *fmt;			/* format of message */
6830 input char *a, *b, *c, *d;		/* optional arguments */
6831 {
6832 	(void) fprintf(stderr, " *** ");
6833 	(void) fprintf(stderr, fmt, a, b, c, d);
6834 	(void) fprintf(stderr, "\n");
6835 
6836 	/* flag an error */
6837 	errorcount++;
6838 }
6839 
6840 
6841 /*
6842 ** PR_WARNING -- Print warning message about encountered inconsistencies
6843 ** ---------------------------------------------------------------------
6844 **
6845 **	We are supposed to have an error condition which is non-fatal
6846 **	for normal continuation, and the message is suppressed in case
6847 **	quiet mode has been selected.
6848 **
6849 **	Returns:
6850 **		None.
6851 */
6852 
6853 void /*VARARGS1*/
pr_warning(fmt,a,b,c,d)6854 pr_warning(fmt, a, b, c, d)
6855 input char *fmt;			/* format of message */
6856 input char *a, *b, *c, *d;		/* optional arguments */
6857 {
6858 	if (!quiet)
6859 	{
6860 		(void) fprintf(stderr, " !!! ");
6861 		(void) fprintf(stderr, fmt, a, b, c, d);
6862 		(void) fprintf(stderr, "\n");
6863 	}
6864 }
6865 
6866 /*
6867 ** WANT_TYPE -- Indicate whether the rr type matches the desired filter
6868 ** --------------------------------------------------------------------
6869 **
6870 **	Returns:
6871 **		true if the resource record type matches the filter.
6872 **		false otherwise.
6873 **
6874 **	In regular mode, the querytype is used to formulate the query,
6875 **	and the filter is set to T_ANY to filter out any response.
6876 **	In listmode, we get everything, so the filter is set to the
6877 **	querytype to filter out the proper responses.
6878 **	Note that T_NONE is the default querytype in listmode.
6879 */
6880 
6881 bool
want_type(type,filter)6882 want_type(type, filter)
6883 input int type;				/* resource record type */
6884 input int filter;			/* type of records we want to see */
6885 {
6886 	if (type == filter)
6887 		return(true);
6888 
6889 	if (filter == T_ANY)
6890 		return(true);
6891 
6892 	if (filter == T_NONE &&
6893 	   (type == T_A || type == T_NS || type == T_PTR))
6894 		return(true);
6895 
6896 	if (filter == T_MAILB &&
6897 	   (type == T_MB || type == T_MR || type == T_MG || type == T_MINFO))
6898 		return(true);
6899 
6900 	if (filter == T_MAILA &&
6901 	   (type == T_MD || type == T_MF))
6902 		return(true);
6903 
6904 	return(false);
6905 }
6906 
6907 /*
6908 ** WANT_CLASS -- Indicate whether the rr class matches the desired filter
6909 ** ----------------------------------------------------------------------
6910 **
6911 **	Returns:
6912 **		true if the resource record class matches the filter.
6913 **		false otherwise.
6914 **
6915 **	In regular mode, the queryclass is used to formulate the query,
6916 **	and the filter is set to C_ANY to filter out any response.
6917 **	In listmode, we get everything, so the filter is set to the
6918 **	queryclass to filter out the proper responses.
6919 **	Note that C_IN is the default queryclass in listmode.
6920 */
6921 
6922 bool
want_class(class,filter)6923 want_class(class, filter)
6924 input int class;			/* resource record class */
6925 input int filter;			/* class of records we want to see */
6926 {
6927 	if (class == filter)
6928 		return(true);
6929 
6930 	if (filter == C_ANY)
6931 		return(true);
6932 
6933 	return(false);
6934 }
6935 
6936 /*
6937 ** INDOMAIN -- Check whether a name belongs to a zone
6938 ** --------------------------------------------------
6939 **
6940 **	Returns:
6941 **		true if the given name lies anywhere in the zone, or
6942 **		if the given name is the same as the zone and may be so.
6943 **		false otherwise.
6944 */
6945 
6946 bool
indomain(name,domain,equal)6947 indomain(name, domain, equal)
6948 input char *name;			/* the name under consideration */
6949 input char *domain;			/* the name of the zone */
6950 input bool equal;			/* set if name may be same as zone */
6951 {
6952 	register char *dot;
6953 
6954 	if (sameword(name, domain))
6955 		return(equal);
6956 
6957 	if (sameword(domain, "."))
6958 		return(true);
6959 
6960 	dot = index(name, '.');
6961 	while (dot != NULL)
6962 	{
6963 		if (!is_quoted(dot, name))
6964 		{
6965 			if (sameword(dot+1, domain))
6966 				return(true);
6967 		}
6968 
6969 		dot = index(dot+1, '.');
6970 	}
6971 
6972 	return(false);
6973 }
6974 
6975 /*
6976 ** SAMEDOMAIN -- Check whether a name belongs to a zone
6977 ** ----------------------------------------------------
6978 **
6979 **	Returns:
6980 **		true if the given name lies directly in the zone, or
6981 **		if the given name is the same as the zone and may be so.
6982 **		false otherwise.
6983 */
6984 
6985 bool
samedomain(name,domain,equal)6986 samedomain(name, domain, equal)
6987 input char *name;			/* the name under consideration */
6988 input char *domain;			/* the name of the zone */
6989 input bool equal;			/* set if name may be same as zone */
6990 {
6991 	register char *dot;
6992 
6993 	if (sameword(name, domain))
6994 		return(equal);
6995 
6996 	dot = index(name, '.');
6997 	while (dot != NULL)
6998 	{
6999 		if (!is_quoted(dot, name))
7000 		{
7001 			if (sameword(dot+1, domain))
7002 				return(true);
7003 
7004 			return(false);
7005 		}
7006 
7007 		dot = index(dot+1, '.');
7008 	}
7009 
7010 	if (sameword(domain, "."))
7011 		return(true);
7012 
7013 	return(false);
7014 }
7015 
7016 /*
7017 ** GLUERECORD -- Check whether a name is a glue record
7018 ** ---------------------------------------------------
7019 **
7020 **	Returns:
7021 **		true is this is a glue record.
7022 **		false otherwise.
7023 **
7024 **	The name is supposed to be the name of an address record.
7025 **	If it lies directly in the given zone, it is considered
7026 **	an ordinary host within that zone, and not a glue record.
7027 **	If it does not belong to the given zone at all, is it
7028 **	here considered to be a glue record.
7029 **	If it lies in the given zone, but not directly, it is
7030 **	considered a glue record if it belongs to any of the known
7031 **	delegated zones of the given zone.
7032 **	In the root zone itself are no hosts, only glue records.
7033 */
7034 
7035 bool
gluerecord(name,domain,zone,nzones)7036 gluerecord(name, domain, zone, nzones)
7037 input char *name;			/* the name under consideration */
7038 input char *domain;			/* name of zone being processed */
7039 input char *zone[];			/* list of known delegated zones */
7040 input int nzones;			/* number of known delegated zones */
7041 {
7042 	register int n;
7043 
7044 	if (sameword(domain, "."))
7045 		return(true);
7046 
7047 	if (samedomain(name, domain, true))
7048 		return(false);
7049 
7050 	if (!indomain(name, domain, true))
7051 		return(true);
7052 
7053 	for (n = 0; n < nzones; n++)
7054 		if (indomain(name, zone[n], true))
7055 			return(true);
7056 
7057 	return(false);
7058 }
7059 
7060 /*
7061 ** MATCHLABELS -- Determine number of matching domain name labels
7062 ** --------------------------------------------------------------
7063 **
7064 **	Returns:
7065 **		Number of shared trailing components in both names.
7066 **
7067 **	Note. This routine is currently used only to compare nameserver
7068 **	names in the RHS of NS records, so there is no need to check
7069 **	for embedded quoted dots.
7070 */
7071 
7072 int
matchlabels(name,domain)7073 matchlabels(name, domain)
7074 input char *name;			/* domain name to check */
7075 input char *domain;			/* domain name to compare against */
7076 {
7077 	register int i, j;
7078 	int matched = 0;
7079 
7080 	i = strlength(name);
7081 	j = strlength(domain);
7082 
7083 	while (--i >= 0 && --j >= 0)
7084 	{
7085 		if (lowercase(name[i]) != lowercase(domain[j]))
7086 			break;
7087 		if (domain[j] == '.')
7088 			matched++;
7089 		else if (j == 0 && (i == 0 || name[i-1] == '.'))
7090 			matched++;
7091 	}
7092 
7093 	return(matched);
7094 }
7095 
7096 /*
7097 ** PR_DOMAIN -- Convert domain name according to printing options
7098 ** --------------------------------------------------------------
7099 **
7100 **	Returns:
7101 **		Pointer to new domain name, if conversion was done.
7102 **		Pointer to original name, if no conversion necessary.
7103 */
7104 
7105 char *
pr_domain(name,listing)7106 pr_domain(name, listing)
7107 input char *name;			/* domain name to be printed */
7108 input bool listing;			/* set if this is a zone listing */
7109 {
7110 	char *newname;			/* converted domain name */
7111 
7112 /*
7113  * Print reverse nsap.int name in forward notation, unless prohibited.
7114  */
7115 	if (revnsap && !dotprint)
7116 	{
7117 		newname = pr_nsap(name);
7118 		if (newname != name)
7119 			return(newname);
7120 	}
7121 
7122 /*
7123  * Print domain names with trailing dot if necessary.
7124  */
7125 	if (listing || dotprint)
7126 	{
7127 		newname = pr_dotname(name);
7128 		if (newname != name)
7129 			return(newname);
7130 	}
7131 
7132 /*
7133  * No conversion was required, use original name.
7134  */
7135 	return(name);
7136 }
7137 
7138 /*
7139 ** PR_DOTNAME -- Return domain name with trailing dot
7140 ** --------------------------------------------------
7141 **
7142 **	Returns:
7143 **		Pointer to new domain name, if dot was added.
7144 **		Pointer to original name, if dot was already present.
7145 */
7146 
7147 char *
pr_dotname(name)7148 pr_dotname(name)
7149 input char *name;			/* domain name to append to */
7150 {
7151 	static char buf[MAXDNAME+2];	/* buffer to store new domain name */
7152 	register int n;
7153 
7154 	n = strlength(name);
7155 	if (n > 0 && name[n-1] == '.')
7156 		return(name);
7157 
7158 	if (n > MAXDNAME)
7159 		n = MAXDNAME;
7160 
7161 	memmove(buf, name, n);
7162 	buf[n] = '.';
7163 	buf[n+1] = '\0';
7164 	return(buf);
7165 }
7166 
7167 /*
7168 ** PR_NSAP -- Convert reverse nsap.int to dotted forward notation
7169 ** --------------------------------------------------------------
7170 **
7171 **	Returns:
7172 **		Pointer to new dotted nsap, if converted.
7173 **		Pointer to original name otherwise.
7174 */
7175 
7176 char *
pr_nsap(name)7177 pr_nsap(name)
7178 input char *name;			/* potential reverse nsap.int name */
7179 {
7180 	static char buf[3*MAXNSAP+1];
7181 	register char *p;
7182 	register int n;
7183 	register int i;
7184 
7185 	/* must begin with single hex digits separated by dots */
7186 	for (i = 0; is_xdigit(name[i]) && name[i+1] == '.'; i += 2)
7187 		continue;
7188 
7189 	/* must have an even number of hex digits */
7190 	if (i == 0 || (i % 4) != 0)
7191 		return(name);
7192 
7193 	/* but not too many */
7194 	if (i > 4*MAXNSAP)
7195 		return(name);
7196 
7197 	/* must end in the appropriate root domain */
7198 	if (!sameword(&name[i], NSAP_ROOT))
7199 		return(name);
7200 
7201 	for (p = buf, n = 0; i >= 4; i -= 4, n++)
7202 	{
7203 		*p++ = name[i-2];
7204 		*p++ = name[i-4];
7205 
7206 		/* add dots for readability */
7207 		if ((n % 2) == 0 && (i - 4) > 0)
7208 			*p++ = '.';
7209 	}
7210 	*p = '\0';
7211 
7212 	return(buf);
7213 }
7214 
7215 /*
7216 ** PR_TYPE -- Return name of resource record type
7217 ** ----------------------------------------------
7218 **
7219 **	Returns:
7220 **		Pointer to name of resource record type.
7221 **
7222 **	Note.	All possible (even obsolete) types are recognized.
7223 */
7224 
7225 char *
pr_type(type)7226 pr_type(type)
7227 input int type;				/* resource record type */
7228 {
7229 	static char buf[30];		/* sufficient for 64-bit values */
7230 
7231 	switch (type)
7232 	{
7233 		/* standard types */
7234 
7235 	    case T_A:       return("A");	/* internet address */
7236 	    case T_NS:      return("NS");	/* authoritative server */
7237 	    case T_MD:      return("MD");	/* mail destination */
7238 	    case T_MF:      return("MF");	/* mail forwarder */
7239 	    case T_CNAME:   return("CNAME");	/* canonical name */
7240 	    case T_SOA:     return("SOA");	/* start of auth zone */
7241 	    case T_MB:      return("MB");	/* mailbox domain name */
7242 	    case T_MG:      return("MG");	/* mail group member */
7243 	    case T_MR:      return("MR");	/* mail rename name */
7244 	    case T_NULL:    return("NULL");	/* null resource record */
7245 	    case T_WKS:     return("WKS");	/* well known service */
7246 	    case T_PTR:     return("PTR");	/* domain name pointer */
7247 	    case T_HINFO:   return("HINFO");	/* host information */
7248 	    case T_MINFO:   return("MINFO");	/* mailbox information */
7249 	    case T_MX:      return("MX");	/* mail routing info */
7250 	    case T_TXT:     return("TXT");	/* descriptive text */
7251 
7252 		/* new types */
7253 
7254 	    case T_RP:      return("RP");	/* responsible person */
7255 	    case T_AFSDB:   return("AFSDB");	/* afs database location */
7256 	    case T_X25:     return("X25");	/* x25 address */
7257 	    case T_ISDN:    return("ISDN");	/* isdn address */
7258 	    case T_RT:      return("RT");	/* route through host */
7259 	    case T_NSAP:    return("NSAP");	/* nsap address */
7260 	    case T_NSAPPTR: return("NSAP-PTR");	/* nsap pointer */
7261 	    case T_SIG:     return("SIG");	/* security signature */
7262 	    case T_KEY:     return("KEY");	/* security key */
7263 	    case T_PX:      return("PX");	/* rfc822 - x400 mapping */
7264 	    case T_GPOS:    return("GPOS");	/* geographical position */
7265 	    case T_AAAA:    return("AAAA");	/* ip v6 address */
7266 	    case T_LOC:     return("LOC");	/* geographical location */
7267 	    case T_NXT:     return("NXT");	/* next valid name */
7268 	    case T_EID:     return("EID");	/* endpoint identifier */
7269 	    case T_NIMLOC:  return("NIMLOC");	/* nimrod locator */
7270 	    case T_SRV:     return("SRV");	/* service info */
7271 	    case T_ATMA:    return("ATMA");	/* atm address */
7272 	    case T_NAPTR:   return("NAPTR");	/* naming authority urn */
7273 
7274 		/* nonstandard types */
7275 
7276 	    case T_UINFO:   return("UINFO");	/* user information */
7277 	    case T_UID:     return("UID");	/* user ident */
7278 	    case T_GID:     return("GID");	/* group ident */
7279 	    case T_UNSPEC:  return("UNSPEC");	/* unspecified binary data */
7280 
7281 		/* filters */
7282 
7283 	    case T_IXFR:    return("IXFR");	/* incremental zone transfer */
7284 	    case T_AXFR:    return("AXFR");	/* zone transfer */
7285 	    case T_MAILB:   return("MAILB");	/* matches MB/MR/MG/MINFO */
7286 	    case T_MAILA:   return("MAILA");	/* matches MD/MF */
7287 	    case T_ANY:     return("ANY");	/* matches any type */
7288 
7289 	    case T_NONE:    return("resource");	/* not yet determined */
7290 	}
7291 
7292 	/* unknown type */
7293 	(void) snprintf(buf, sizeof buf, "%d", type);
7294 	return(buf);
7295 }
7296 
7297 /*
7298 ** PR_CLASS -- Return name of resource record class
7299 ** ------------------------------------------------
7300 **
7301 **	Returns:
7302 **		Pointer to name of resource record class.
7303 */
7304 
7305 char *
pr_class(class)7306 pr_class(class)
7307 input int class;			/* resource record class */
7308 {
7309 	static char buf[30];		/* sufficient for 64-bit values */
7310 
7311 	switch (class)
7312 	{
7313 	    case C_IN:      return("IN");	/* internet */
7314 	    case C_CSNET:   return("CS");	/* csnet */
7315 	    case C_CHAOS:   return("CH");	/* chaosnet */
7316 	    case C_HS:      return("HS");	/* hesiod */
7317 	    case C_ANY:     return("ANY");	/* any class */
7318 	}
7319 
7320 	/* unknown class */
7321 	(void) snprintf(buf, sizeof buf, "%d", class);
7322 	return(buf);
7323 }
7324 
7325 /*
7326 ** EXPAND_NAME -- Expand compressed domain name in a resource record
7327 ** -----------------------------------------------------------------
7328 **
7329 **	Returns:
7330 **		Number of bytes advanced in answer buffer.
7331 **		-1 if there was a format error.
7332 **
7333 **	It is assumed that the specified buffer is of a fixed size
7334 **	MAXDNAME+1 that should be sufficient to store the data.
7335 */
7336 
7337 int
expand_name(name,type,cp,msg,eom,namebuf)7338 expand_name(name, type, cp, msg, eom, namebuf)
7339 input char *name;			/* name of resource record */
7340 input int type;				/* type of resource record */
7341 input u_char *cp;			/* current position in answer buf */
7342 input u_char *msg, *eom;		/* begin and end of answer buf */
7343 output char *namebuf;			/* location of buf to expand name in */
7344 {
7345 	register int n;
7346 
7347 	n = dn_expand(msg, eom, cp, (nbuf_t *)namebuf, MAXDNAME);
7348 	if (n < 0)
7349 	{
7350 		pr_error("expand error in %s record for %s, offset %s",
7351 			pr_type(type), name, itoa(cp - msg));
7352 		h_errno = NO_RECOVERY;
7353 		return(-1);
7354 	}
7355 
7356 	/* should not be necessary, but who knows */
7357 	namebuf[MAXDNAME] = '\0';
7358 
7359 	/* change root to single dot */
7360 	if (namebuf[0] == '\0')
7361 	{
7362 		namebuf[0] = '.';
7363 		namebuf[1] = '\0';
7364 	}
7365 
7366 	return(n);
7367 }
7368 
7369 /*
7370 ** CHECK_SIZE -- Check whether resource record is of sufficient length
7371 ** -------------------------------------------------------------------
7372 **
7373 **	Returns:
7374 **		Requested size if current record is long enough.
7375 **		-1 if current record does not have this many bytes.
7376 **
7377 **	Note that HINFO records are very often incomplete since only
7378 **	one of the two data fields has been filled in and the second
7379 **	field is missing. So we generate only a warning message.
7380 */
7381 
7382 int
check_size(name,type,cp,msg,eor,size)7383 check_size(name, type, cp, msg, eor, size)
7384 input char *name;			/* name of resource record */
7385 input int type;				/* type of resource record */
7386 input u_char *cp;			/* current position in answer buf */
7387 input u_char *msg;			/* begin of answer buf */
7388 input u_char *eor;			/* predicted position of next record */
7389 input int size;				/* required record size remaining */
7390 {
7391 	if (cp + size > eor)
7392 	{
7393 		if (type != T_HINFO)
7394 			pr_error("incomplete %s record for %s, offset %s",
7395 				pr_type(type), name, itoa(cp - msg));
7396 		else
7397 			pr_warning("incomplete %s record for %s",
7398 				pr_type(type), name);
7399 		h_errno = NO_RECOVERY;
7400 		return(-1);
7401 	}
7402 
7403 	return(size);
7404 }
7405 
7406 /*
7407 ** VALID_NAME -- Check whether domain name contains invalid characters
7408 ** -------------------------------------------------------------------
7409 **
7410 **	Returns:
7411 **		true if the name is valid.
7412 **		false otherwise.
7413 **
7414 **	The total size of a compound name should not exceed MAXDNAME.
7415 **	We assume that this is true. Its individual components between
7416 **	dots should not be longer than 64. This is not checked here.
7417 **
7418 **	Only alphanumeric characters and dash '-' may be used (dash
7419 **	only in the middle). We only check the individual characters.
7420 **	Strictly speaking, this restriction is only for ``host names''.
7421 **	The underscore is illegal, at least not recommended, but is
7422 **	so abundant that it requires special processing.
7423 **
7424 **	If the domain name represents a mailbox specification, the
7425 **	first label up to the first (unquoted) dot is the local part
7426 **	of a mail address, which should adhere to the RFC 822 specs.
7427 **	This first dot takes the place of the RFC 822 '@' sign.
7428 **
7429 **	The label '*' can in principle be used anywhere to indicate
7430 **	wildcarding. It is valid only in the LHS resource record name,
7431 **	in definitions in zone files only as the first component.
7432 **	Used primarily in wildcard MX record definitions.
7433 **
7434 **	Note. This routine is much too liberal.
7435 */
7436 
7437 char *specials = ".()<>@,;:\\\"[]";	/* RFC 822 specials */
7438 
7439 bool
valid_name(name,wildcard,localpart,underscore)7440 valid_name(name, wildcard, localpart, underscore)
7441 input char *name;			/* domain name to check */
7442 input bool wildcard;			/* set if wildcard is allowed */
7443 input bool localpart;			/* set if this is a mailbox spec */
7444 input bool underscore;			/* set if underscores are allowed */
7445 {
7446 	bool backslash = false;
7447 	bool quoting = false;
7448 	register char *p;
7449 	register char c;
7450 
7451 	for (p = name; (c = *p) != '\0'; p++)
7452 	{
7453 		/* special check for local part in mailbox */
7454 		if (localpart)
7455 		{
7456 			if (backslash)
7457 				backslash = false;	/* escape this char */
7458 			else if (c == '\\')
7459 				backslash = true;	/* escape next char */
7460 			else if (c == '"')
7461 				quoting = !quoting;	/* start/stop quoting */
7462 			else if (quoting)
7463 				continue;		/* allow quoted chars */
7464 			else if (c == '.')
7465 				localpart = false;	/* instead of '@' */
7466 			else if (c == '@')
7467 				return(false);		/* should be '.' */
7468 			else if (in_string(specials, c))
7469 				return(false);		/* must be escaped */
7470 			else if (is_space(c))
7471 				return(false);		/* must be escaped */
7472 			continue;
7473 		}
7474 
7475 		/* basic character set */
7476 		if (is_alnum(c) || (c == '-'))
7477 			continue;
7478 
7479 		/* start of a new component */
7480 		if (c == '.')
7481 			continue;
7482 
7483 		/* allow '*' for use in wildcard names */
7484 		if ((c == '*') && (p == name && p[1] == '.') && wildcard)
7485 			continue;
7486 
7487 		/* ignore underscore in certain circumstances */
7488 		if ((c == '_') && underscore && !illegal)
7489 			continue;
7490 
7491 		/* silently allowed widespread exceptions */
7492 		if (illegal && in_string(illegal, c))
7493 			continue;
7494 
7495 		return(false);
7496 	}
7497 
7498 	/* must be beyond the local part in a mailbox */
7499 	if (localpart)
7500 		return(false);
7501 
7502 	return(true);
7503 }
7504 
7505 /*
7506 ** CANONICAL -- Check whether domain name is a canonical host name
7507 ** ---------------------------------------------------------------
7508 **
7509 **	Returns:
7510 **		Nonzero if the name is definitely not canonical.
7511 **		0 if it is canonical, or if it remains undecided.
7512 */
7513 
7514 int
canonical(name)7515 canonical(name)
7516 input char *name;			/* the domain name to check */
7517 {
7518 	struct hostent *hp;
7519 	int status;
7520 	int save_errno;
7521 	int save_herrno;
7522 
7523 /*
7524  * Preserve state when querying, to avoid clobbering current values.
7525  */
7526 	save_errno = errno;
7527 	save_herrno = h_errno;
7528 
7529 	hp = geth_byname(name);
7530 	status = h_errno;
7531 
7532 	errno = save_errno;
7533 	h_errno = save_herrno;
7534 
7535 /*
7536  * Indicate negative result only after definitive lookup failures.
7537  */
7538 	if (hp == NULL)
7539 	{
7540 		/* authoritative denial -- not existing or no A record */
7541 		if (status == NO_DATA || status == HOST_NOT_FOUND)
7542 			return(status);
7543 
7544 		/* nameserver failure -- still undecided, assume ok */
7545 		return(0);
7546 	}
7547 
7548 /*
7549  * The given name exists and there is an associated A record.
7550  * The name of this A record should be the name we queried about.
7551  * If this is not the case we probably supplied a CNAME.
7552  */
7553 	status = sameword(hp->h_name, name) ? 0 : HOST_NOT_CANON;
7554 	return(status);
7555 }
7556 
7557 /*
7558 ** MAPREVERSE -- Check whether address maps back to given domain
7559 ** -------------------------------------------------------------
7560 **
7561 **	Returns:
7562 **		NULL if address could definitively not be mapped.
7563 **		Given name if the address maps back properly, or
7564 **		in case of transient nameserver failures.
7565 **		Reverse name if it differs from the given name.
7566 */
7567 
7568 char *
mapreverse(name,inaddr)7569 mapreverse(name, inaddr)
7570 input char *name;			/* domain name of A record */
7571 input struct in_addr inaddr;		/* address of A record to check */
7572 {
7573 	struct hostent *hp;
7574 	int status;
7575 	int save_errno;
7576 	int save_herrno;
7577 
7578 /*
7579  * Preserve state when querying, to avoid clobbering current values.
7580  */
7581 	save_errno = errno;
7582 	save_herrno = h_errno;
7583 
7584 	hp = geth_byaddr((char *)&inaddr, INADDRSZ, AF_INET);
7585 	status = h_errno;
7586 
7587 	errno = save_errno;
7588 	h_errno = save_herrno;
7589 
7590 /*
7591  * Indicate negative result only after definitive lookup failures.
7592  */
7593 	if (hp == NULL)
7594 	{
7595 		/* authoritative denial -- not existing or no PTR record */
7596 		if (status == NO_DATA || status == HOST_NOT_FOUND)
7597 			return(NULL);
7598 
7599 		/* nameserver failure -- still undecided, assume ok */
7600 		return(name);
7601 	}
7602 
7603 /*
7604  * Indicate whether the reverse mapping yields the given name.
7605  */
7606 	return(sameword(hp->h_name, name) ? name : hp->h_name);
7607 }
7608 
7609 /*
7610 ** COMPARE_NAME -- Compare two names wrt alphabetical order
7611 ** --------------------------------------------------------
7612 **
7613 **	Returns:
7614 **		Value of case-insensitive comparison.
7615 */
7616 
7617 int
compare_name(a,b)7618 compare_name(a, b)
7619 input const ptr_t *a;			/* first name */
7620 input const ptr_t *b;			/* second name */
7621 {
7622 	return(strcasecmp(*(char **)a, *(char **)b));
7623 }
7624 
7625 /*
7626 ** XALLOC -- Allocate or reallocate additional memory
7627 ** --------------------------------------------------
7628 **
7629 **	Returns:
7630 **		Pointer to (re)allocated buffer space.
7631 **		Aborts if the requested memory could not be obtained.
7632 */
7633 
7634 ptr_t *
xalloc(buf,size)7635 xalloc(buf, size)
7636 register ptr_t *buf;			/* current start of buffer space */
7637 input siz_t size;			/* number of bytes to allocate */
7638 {
7639 	if (buf == NULL)
7640 		buf = malloc(size);
7641 	else
7642 		buf = realloc(buf, size);
7643 
7644 	if (buf == NULL)
7645 	{
7646 		errmsg("Out of memory");
7647 		exit(EX_OSERR);
7648 	}
7649 
7650 	return(buf);
7651 }
7652 
7653 /*
7654 ** ITOA -- Convert value to decimal integer ascii string
7655 ** -----------------------------------------------------
7656 **
7657 **	Returns:
7658 **		Pointer to string.
7659 */
7660 
7661 char *
itoa(n)7662 itoa(n)
7663 input int n;				/* value to convert */
7664 {
7665 	static char buf[30];		/* sufficient for 64-bit values */
7666 
7667 	(void) snprintf(buf, sizeof buf, "%d", n);
7668 	return(buf);
7669 }
7670 
7671 /*
7672 ** UTOA -- Convert value to unsigned decimal ascii string
7673 ** ------------------------------------------------------
7674 **
7675 **	Returns:
7676 **		Pointer to string.
7677 */
7678 
7679 char *
utoa(n)7680 utoa(n)
7681 input int n;				/* value to convert */
7682 {
7683 	static char buf[30];		/* sufficient for 64-bit values */
7684 
7685 	(void) snprintf(buf, sizeof buf, "%u", (unsigned)n);
7686 	return(buf);
7687 }
7688 
7689 /*
7690 ** XTOA -- Convert value to hexadecimal ascii string
7691 ** -------------------------------------------------
7692 **
7693 **	Returns:
7694 **		Pointer to string.
7695 */
7696 
7697 char *
xtoa(n)7698 xtoa(n)
7699 input int n;				/* value to convert */
7700 {
7701 	static char buf[17];		/* sufficient for 64-bit values */
7702 
7703 	(void) snprintf(buf, sizeof buf, "%X", (unsigned)n);
7704 	return(buf);
7705 }
7706 
7707 /*
7708 ** STOA -- Extract partial ascii string, escape if necessary
7709 ** ---------------------------------------------------------
7710 **
7711 **	Returns:
7712 **		Pointer to string.
7713 */
7714 
7715 char *
stoa(cp,size,escape)7716 stoa(cp, size, escape)
7717 input u_char *cp;			/* current position in answer buf */
7718 input int size;				/* number of bytes to extract */
7719 input bool escape;			/* escape special characters if set */
7720 {
7721 	static char buf[2*MAXDLEN+1];
7722 	register char *p;
7723 	register char c;
7724 	register int i;
7725 
7726 	if (size > MAXDLEN)
7727 		size = MAXDLEN;
7728 
7729 	for (p = buf, i = 0; i < size; i++)
7730 	{
7731 		c = *cp++;
7732 		if (escape && (c == '\n' || c == '\\' || c == '"'))
7733 			*p++ = '\\';
7734 		*p++ = c;
7735 	}
7736 	*p = '\0';
7737 
7738 	return(buf);
7739 }
7740 
7741 /*
7742 ** BASE_NTOA -- Convert binary data to base64 ascii
7743 ** ------------------------------------------------
7744 **
7745 **	Returns:
7746 **		Pointer to string.
7747 **
7748 **	This routine is used to convert encoded keys and signatures
7749 **	in T_KEY and T_SIG resource records.
7750 */
7751 
7752 char b64tab[] =
7753 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7754 
7755 char *
base_ntoa(cp,size)7756 base_ntoa(cp, size)
7757 input u_char *cp;			/* current position in answer buf */
7758 input int size;				/* number of bytes to extract */
7759 {
7760 	static char buf[MAXB64SIZE+1];
7761 	register char *p;
7762 	int c1, c2, c3, c4;
7763 
7764 	if (size > MAXMD5SIZE)
7765 		size = MAXMD5SIZE;
7766 
7767 	for (p = buf; size > 2; cp += 3, size -= 3)
7768 	{
7769 		c1 = (((int)cp[0] >> 2) & 0x3f);
7770 		c2 = (((int)cp[0] & 0x03) << 4) + (((int)cp[1] >> 4) & 0x0f);
7771 		c3 = (((int)cp[1] & 0x0f) << 2) + (((int)cp[2] >> 6) & 0x03);
7772 		c4 =  ((int)cp[2] & 0x3f);
7773 
7774 		*p++ = b64tab[c1];
7775 		*p++ = b64tab[c2];
7776 		*p++ = b64tab[c3];
7777 		*p++ = b64tab[c4];
7778 	}
7779 
7780 	if (size == 2)
7781 	{
7782 		c1 = (((int)cp[0] >> 2) & 0x3f);
7783 		c2 = (((int)cp[0] & 0x03) << 4) + (((int)cp[1] >> 4) & 0x0f);
7784 		c3 = (((int)cp[1] & 0x0f) << 2);
7785 
7786 		*p++ = b64tab[c1];
7787 		*p++ = b64tab[c2];
7788 		*p++ = b64tab[c3];
7789 		*p++ = '=';
7790 	}
7791 	else if (size == 1)
7792 	{
7793 		c1 = (((int)cp[0] >> 2) & 0x3f);
7794 		c2 = (((int)cp[0] & 0x03) << 4);
7795 
7796 		*p++ = b64tab[c1];
7797 		*p++ = b64tab[c2];
7798 		*p++ = '=';
7799 		*p++ = '=';
7800 	}
7801 	*p = '\0';
7802 
7803 	return(buf);
7804 }
7805 
7806 /*
7807 ** NSAP_NTOA -- Convert binary nsap address to ascii
7808 ** -------------------------------------------------
7809 **
7810 **	Returns:
7811 **		Pointer to string.
7812 **
7813 **	As per RFC 1637 an nsap address is encoded in binary form
7814 **	in the resource record. It was unclear from RFC 1348 how
7815 **	the encoding should be. RFC 1629 defines an upper bound
7816 **	of 20 bytes to the size of a binary nsap address.
7817 */
7818 
7819 char *
nsap_ntoa(cp,size)7820 nsap_ntoa(cp, size)
7821 input u_char *cp;			/* current position in answer buf */
7822 input int size;				/* number of bytes to extract */
7823 {
7824 	static char buf[3*MAXNSAP+1];
7825 	register char *p;
7826 	register int n;
7827 	register int i;
7828 
7829 	if (size > MAXNSAP)
7830 		size = MAXNSAP;
7831 
7832 	for (p = buf, i = 0; i < size; i++, cp++)
7833 	{
7834 		n = ((int)(*cp) >> 4) & 0x0f;
7835 		*p++ = hexdigit(n);
7836 		n = ((int)(*cp) >> 0) & 0x0f;
7837 		*p++ = hexdigit(n);
7838 
7839 		/* add dots for readability */
7840 		if ((i % 2) == 0 && (i + 1) < size)
7841 			*p++ = '.';
7842 	}
7843 	*p = '\0';
7844 
7845 	return(buf);
7846 }
7847 
7848 /*
7849 ** IPNG_NTOA -- Convert binary ip v6 address to ascii
7850 ** --------------------------------------------------
7851 **
7852 **	Returns:
7853 **		Pointer to string.
7854 **
7855 **	As per RFC 1886 an ip v6 address is encoded in binary form
7856 **	in the resource record. The size is fixed.
7857 */
7858 
7859 char *
ipng_ntoa(cp)7860 ipng_ntoa(cp)
7861 input u_char *cp;			/* current position in answer buf */
7862 {
7863 	static char buf[5*(IPNGSIZE/2)+1];
7864 	register char *p;
7865 	register int n;
7866 	register int i;
7867 
7868 	for (p = buf, i = 0; i < IPNGSIZE/2; i++)
7869 	{
7870 		n = _getshort(cp);
7871 		cp += INT16SZ;
7872 
7873 		(void) snprintf(p, 6, ":%X", n);
7874 		p += strlength(p);
7875 	}
7876 	*p = '\0';
7877 
7878 	return(buf + 1);
7879 }
7880 
7881 /*
7882 ** PR_DATE -- Produce printable version of a clock value
7883 ** -----------------------------------------------------
7884 **
7885 **	Returns:
7886 **		Pointer to string.
7887 **
7888 **	The value is a standard absolute clock value.
7889 */
7890 
7891 char *
pr_date(value)7892 pr_date(value)
7893 input int value;			/* the clock value to be converted */
7894 {
7895 	static char buf[sizeof("YYYYMMDDHHMMSS")+1];
7896 	time_t clocktime = value;
7897 	struct tm *t;
7898 
7899 	t = gmtime(&clocktime);
7900 
7901 	(void) snprintf(buf, sizeof buf, "%04lld%02d%02d%02d%02d%02d",
7902 		(int64_t)t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
7903 		t->tm_hour, t->tm_min, t->tm_sec);
7904 
7905 	return(buf);
7906 }
7907 
7908 /*
7909 ** PR_TIME -- Produce printable version of a time interval
7910 ** -------------------------------------------------------
7911 **
7912 **	Returns:
7913 **		Pointer to a string version of interval.
7914 **
7915 **	The value is a time interval expressed in seconds.
7916 */
7917 
7918 char *
pr_time(value,brief)7919 pr_time(value, brief)
7920 input int value;			/* the interval to be converted */
7921 input bool brief;			/* use brief format if set */
7922 {
7923 	static char buf[256];
7924 	register char *p = buf;
7925 	int week = 0, days, hour, mins, secs;
7926 
7927 	/* special cases */
7928 	if (value < 0)
7929 		return("negative");
7930 	if ((value == 0) && !brief)
7931 		return("zero seconds");
7932 
7933 /*
7934  * Decode the components.
7935  */
7936 	secs = value % 60; value /= 60;
7937 	mins = value % 60; value /= 60;
7938 	hour = value % 24; value /= 24;
7939 	days = value;
7940 
7941 	if (!brief)
7942 	{
7943 		days = value % 7; value /= 7;
7944 		week = value;
7945 	}
7946 
7947 /*
7948  * Now turn it into a sexy form.
7949  */
7950 	if (brief)
7951 	{
7952 		if (days > 0)
7953 		{
7954 			(void) snprintf(p, (sizeof p)-strlength(p), "%d+", days);
7955 			p += strlength(p);
7956 		}
7957 
7958 		(void) snprintf(p, (sizeof p)-strlength(p), "%02d:%02d:%02d", hour, mins, secs);
7959 		return(buf);
7960 	}
7961 
7962 	if (week > 0)
7963 	{
7964 		(void) snprintf(p, (sizeof p)-strlength(p), ", %d week%s", week, plural(week));
7965 		p += strlength(p);
7966 	}
7967 
7968 	if (days > 0)
7969 	{
7970 		(void) snprintf(p, (sizeof p)-strlength(p), ", %d day%s", days, plural(days));
7971 		p += strlength(p);
7972 	}
7973 
7974 	if (hour > 0)
7975 	{
7976 		(void) snprintf(p, (sizeof p)-strlength(p), ", %d hour%s", hour, plural(hour));
7977 		p += strlength(p);
7978 	}
7979 
7980 	if (mins > 0)
7981 	{
7982 		(void) snprintf(p, (sizeof p)-strlength(p), ", %d minute%s", mins, plural(mins));
7983 		p += strlength(p);
7984 	}
7985 
7986 	if (secs > 0)
7987 	{
7988 		(void) snprintf(p, (sizeof p)-strlength(p), ", %d second%s", secs, plural(secs));
7989 		/* p += strlength(p); */
7990 	}
7991 
7992 	return(buf + 2);
7993 }
7994 
7995 /*
7996 ** PR_SPHERICAL -- Produce printable version of a spherical location
7997 ** -----------------------------------------------------------------
7998 **
7999 **	Returns:
8000 **		Pointer to a string version of location.
8001 **
8002 **	The value is a spherical location (latitude or longitude)
8003 **	expressed in thousandths of a second of arc.
8004 **	The value 2^31 represents zero (equator or prime meridian).
8005 */
8006 
8007 char *
pr_spherical(value,pos,neg)8008 pr_spherical(value, pos, neg)
8009 input int value;			/* the location to be converted */
8010 input char *pos;			/* suffix if value positive */
8011 input char *neg;			/* suffix if value negative */
8012 {
8013 	static char buf[256];
8014 	register char *p = buf;
8015 	char *direction;
8016 	int degrees, minutes, seconds, fracsec;
8017 
8018 /*
8019  * Normalize.
8020  */
8021 	value -= (int)((unsigned)1 << 31);
8022 
8023 	direction = pos;
8024 	if (value < 0)
8025 	{
8026 		direction = neg;
8027 		value = -value;
8028 	}
8029 
8030 /*
8031  * Decode the components.
8032  */
8033 	fracsec = value % 1000; value /= 1000;
8034 	seconds = value % 60;   value /= 60;
8035 	minutes = value % 60;   value /= 60;
8036 	degrees = value;
8037 
8038 /*
8039  * Construct output string.
8040  */
8041 	(void) snprintf(p, (sizeof p)-strlength(p), "%d", degrees);
8042 	p += strlength(p);
8043 
8044 	if (minutes > 0 || seconds > 0 || fracsec > 0)
8045 	{
8046 		(void) snprintf(p, (sizeof p)-strlength(p), " %02d", minutes);
8047 		p += strlength(p);
8048 	}
8049 
8050 	if (seconds > 0 || fracsec > 0)
8051 	{
8052 		(void) snprintf(p, (sizeof p)-strlength(p), " %02d", seconds);
8053 		p += strlength(p);
8054 	}
8055 
8056 	if (fracsec > 0)
8057 	{
8058 		(void) snprintf(p, (sizeof p)-strlength(p), ".%03d", fracsec);
8059 		p += strlength(p);
8060 	}
8061 
8062 	(void) snprintf(p, (sizeof p)-strlength(p), " %s", direction);
8063 
8064 	return(buf);
8065 }
8066 
8067 /*
8068 ** PR_VERTICAL -- Produce printable version of a vertical location
8069 ** ---------------------------------------------------------------
8070 **
8071 **	Returns:
8072 **		Pointer to a string version of location.
8073 **
8074 **	The value is an altitude expressed in centimeters, starting
8075 **	from a base 100000 meters below the GPS reference spheroid.
8076 **	This allows for the actual range [-10000000 .. 4293967296].
8077 */
8078 
8079 char *
pr_vertical(value,pos,neg)8080 pr_vertical(value, pos, neg)
8081 input int value;			/* the location to be converted */
8082 input char *pos;			/* prefix if value positive */
8083 input char *neg;			/* prefix if value negative */
8084 {
8085 	static char buf[256];
8086 	register char *p = buf;
8087 	char *direction;
8088 	int meters, centimeters;
8089 	unsigned int altitude;
8090 	unsigned int reference;
8091 
8092 /*
8093  * Normalize.
8094  */
8095 	altitude = value;
8096 	reference = 100000*100;
8097 
8098 	if (altitude < reference)
8099 	{
8100 		direction = neg;
8101 		altitude = reference - altitude;
8102 	}
8103 	else
8104 	{
8105 		direction = pos;
8106 		altitude = altitude - reference;
8107 	}
8108 
8109 /*
8110  * Decode the components.
8111  */
8112 	centimeters = altitude % 100; altitude /= 100;
8113 	meters = altitude;
8114 
8115 /*
8116  * Construct output string.
8117  */
8118 	(void) snprintf(p, (sizeof p)-strlength(p), "%s%d", direction, meters);
8119 	p += strlength(p);
8120 
8121 	if (centimeters > 0)
8122 		(void) snprintf(p, (sizeof p)-strlength(p), ".%02d", centimeters);
8123 
8124 	return(buf);
8125 }
8126 
8127 /*
8128 ** PR_PRECISION -- Produce printable version of a location precision
8129 ** -----------------------------------------------------------------
8130 **
8131 **	Returns:
8132 **		Pointer to a string version of precision.
8133 **
8134 **	The value is a precision expressed in centimeters, encoded
8135 **	as 4-bit mantissa and 4-bit power of 10 (each ranging 0-9).
8136 */
8137 
8138 unsigned int poweroften[10] =
8139 {1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
8140 
8141 char *
pr_precision(value)8142 pr_precision(value)
8143 input int value;			/* the precision to be converted */
8144 {
8145 	static char buf[256];
8146 	register char *p = buf;
8147 	int meters, centimeters;
8148 	unsigned int precision;
8149 	register int mantissa;
8150 	register int exponent;
8151 
8152 /*
8153  * Normalize.
8154  */
8155 	mantissa = ((value >> 4) & 0x0f) % 10;
8156 	exponent = ((value >> 0) & 0x0f) % 10;
8157 	precision = mantissa * poweroften[exponent];
8158 
8159 /*
8160  * Decode the components.
8161  */
8162 	centimeters = precision % 100; precision /= 100;
8163 	meters = precision;
8164 
8165 /*
8166  * Construct output string.
8167  */
8168 	(void) snprintf(p, (sizeof p)-strlength(p), "%d", meters);
8169 	p += strlength(p);
8170 
8171 	if (centimeters > 0)
8172 		(void) snprintf(p, (sizeof p)-strlength(p), ".%02d", centimeters);
8173 
8174 	return(buf);
8175 }
8176 
8177 /*
8178 ** _RES_CONNECT -- Connect to a stream (virtual circuit) socket
8179 ** ------------------------------------------------------------
8180 **
8181 **	Returns:
8182 **		0 if successfully connected.
8183 **		-1 in case of failure or timeout.
8184 **
8185 **	Note that we use _res.retrans to override the default
8186 **	connect timeout value.
8187 */
8188 
8189 static jmp_buf timer_buf;
8190 
8191 static sigtype_t
8192 /*ARGSUSED*/
timer(sig)8193 timer(sig)
8194 int sig;
8195 {
8196 	longjmp(timer_buf, 1);
8197 	/*NOTREACHED*/
8198 }
8199 
8200 
8201 int
_res_connect(sock,addr,addrlen)8202 _res_connect(sock, addr, addrlen)
8203 input int sock;
8204 input struct sockaddr_in *addr;		/* the server address to connect to */
8205 input int addrlen;
8206 {
8207 	if (setjmp(timer_buf) != 0)
8208 	{
8209 		errno = ETIMEDOUT;
8210 		setalarm(0);
8211 		return(-1);
8212 	}
8213 
8214 	(void) signal(SIGALRM, timer);
8215 	setalarm(_res.retrans);
8216 
8217 	if (connect(sock, (struct sockaddr *)addr, addrlen) < 0)
8218 	{
8219 		if (errno == EINTR)
8220 			errno = ETIMEDOUT;
8221 		setalarm(0);
8222 		return(-1);
8223 	}
8224 
8225 	setalarm(0);
8226 	return(0);
8227 }
8228 
8229 /*
8230 ** _RES_WRITE -- Write the query buffer via a stream socket
8231 ** --------------------------------------------------------
8232 **
8233 **	Returns:
8234 **		Length of buffer if successfully transmitted.
8235 **		-1 in case of failure (error message is issued).
8236 **
8237 **	The query is sent in two steps: first a single word with
8238 **	the length of the buffer, followed by the buffer itself.
8239 */
8240 
8241 int
_res_write(sock,addr,host,buf,bufsize)8242 _res_write(sock, addr, host, buf, bufsize)
8243 input int sock;
8244 input struct sockaddr_in *addr;		/* the server address to connect to */
8245 input char *host;			/* name of server to connect to */
8246 input char *buf;			/* location of formatted query buffer */
8247 input int bufsize;			/* length of query buffer */
8248 {
8249 	u_short len;
8250 
8251 /*
8252  * Write the length of the query buffer.
8253  */
8254 	/* len = htons(bufsize); */
8255 	putshort((u_short)bufsize, (u_char *)&len);
8256 
8257 	if (write(sock, (char *)&len, INT16SZ) != INT16SZ)
8258 	{
8259 		_res_perror(addr, host, "write query length");
8260 		return(-1);
8261 	}
8262 
8263 /*
8264  * Write the query buffer itself.
8265  */
8266 	if (write(sock, buf, bufsize) != bufsize)
8267 	{
8268 		_res_perror(addr, host, "write query");
8269 		return(-1);
8270 	}
8271 
8272 	return(bufsize);
8273 }
8274 
8275 /*
8276 ** _RES_READ -- Read the answer buffer via a stream socket
8277 ** -------------------------------------------------------
8278 **
8279 **	Returns:
8280 **		Length of (untruncated) answer if successfully received.
8281 **		-1 in case of failure (error message is issued).
8282 **
8283 **	The answer is read in two steps: first a single word which
8284 **	gives the length of the buffer, followed by the buffer itself.
8285 **	If the answer is too long to fit into the supplied buffer,
8286 **	only the portion that fits will be stored, the residu will be
8287 **	flushed, and the truncation flag will be set.
8288 **
8289 **	Note. The returned length is that of the *un*truncated answer,
8290 **	however, and not the amount of data that is actually available.
8291 **	This may give the caller a hint about new buffer reallocation.
8292 */
8293 
8294 int
_res_read(sock,addr,host,buf,bufsize)8295 _res_read(sock, addr, host, buf, bufsize)
8296 input int sock;
8297 input struct sockaddr_in *addr;		/* the server address to connect to */
8298 input char *host;			/* name of server to connect to */
8299 output char *buf;			/* location of buffer to store answer */
8300 input int bufsize;			/* maximum size of answer buffer */
8301 {
8302 	u_short len;
8303 	char *buffer;
8304 	int buflen;
8305 	int reslen;
8306 	register int n;
8307 
8308 	/* set stream timeout for recv_sock() */
8309 	timeout = READTIMEOUT;
8310 
8311 /*
8312  * Read the length of answer buffer.
8313  */
8314 	buffer = (char *)&len;
8315 	buflen = INT16SZ;
8316 
8317 	while (buflen > 0 && (n = recv_sock(sock, buffer, buflen)) > 0)
8318 	{
8319 		buffer += n;
8320 		buflen -= n;
8321 	}
8322 
8323 	if (buflen != 0)
8324 	{
8325 		_res_perror(addr, host, "read answer length");
8326 		return(-1);
8327 	}
8328 
8329 /*
8330  * Terminate if length is zero.
8331  */
8332 	/* len = ntohs(len); */
8333 	len = _getshort((u_char *)&len);
8334 	if (len == 0)
8335 		return(0);
8336 
8337 /*
8338  * Check for truncation.
8339  * Do not chop the returned length in case of buffer overflow.
8340  */
8341 	reslen = 0;
8342 	if ((int)len > bufsize)
8343 	{
8344 		reslen = len - bufsize;
8345 		/* len = bufsize; */
8346 	}
8347 
8348 /*
8349  * Read the answer buffer itself.
8350  * Truncate the answer is the supplied buffer is not big enough.
8351  */
8352 	buffer = buf;
8353 	buflen = (reslen > 0) ? bufsize : len;
8354 
8355 	while (buflen > 0 && (n = recv_sock(sock, buffer, buflen)) > 0)
8356 	{
8357 		buffer += n;
8358 		buflen -= n;
8359 	}
8360 
8361 	if (buflen != 0)
8362 	{
8363 		_res_perror(addr, host, "read answer");
8364 		return(-1);
8365 	}
8366 
8367 /*
8368  * Discard the residu to keep connection in sync.
8369  */
8370 	if (reslen > 0)
8371 	{
8372 		HEADER *bp = (HEADER *)buf;
8373 		char resbuf[PACKETSZ];
8374 
8375 		buffer = resbuf;
8376 		buflen = (reslen < sizeof(resbuf)) ? reslen : sizeof(resbuf);
8377 
8378 		while (reslen > 0 && (n = recv_sock(sock, buffer, buflen)) > 0)
8379 		{
8380 			reslen -= n;
8381 			buflen = (reslen < sizeof(resbuf)) ? reslen : sizeof(resbuf);
8382 		}
8383 
8384 		if (reslen != 0)
8385 		{
8386 			_res_perror(addr, host, "read residu");
8387 			return(-1);
8388 		}
8389 
8390 		if (bitset(RES_DEBUG, _res.options))
8391 			printf("%sresponse truncated to %d bytes\n", dbprefix, bufsize);
8392 
8393 		/* set truncation flag */
8394 		bp->tc = 1;
8395 	}
8396 
8397 	return(len);
8398 }
8399 
8400 /*
8401 ** RECV_SOCK -- Read from stream or datagram socket with timeout
8402 ** -------------------------------------------------------------
8403 **
8404 **	Returns:
8405 **		Length of buffer if successfully received.
8406 **		-1 in case of failure or timeout.
8407 **	Inputs:
8408 **		The global variable ``timeout'' should have been
8409 **		set with the desired timeout value in seconds.
8410 **	Outputs:
8411 **		Sets ``from'' to the address of the packet sender.
8412 */
8413 
8414 static int
recv_sock(sock,buffer,buflen)8415 recv_sock(sock, buffer, buflen)
8416 input int sock;
8417 output char *buffer;			/* current buffer address */
8418 input int buflen;			/* remaining buffer size */
8419 {
8420 	fd_set fds;
8421 	struct timeval wait;
8422 	socklen_t fromlen;
8423 	register int n;
8424 
8425 	wait.tv_sec = timeout;
8426 	wait.tv_usec = 0;
8427 rewait:
8428 	/* FD_ZERO(&fds); */
8429 	bzero((char *)&fds, sizeof(fds));
8430 	FD_SET(sock, &fds);
8431 
8432 	/* wait for the arrival of data, or timeout */
8433 	n = select(FD_SETSIZE, &fds, (fd_set *)NULL, (fd_set *)NULL, &wait);
8434 	if (n <= 0)
8435 	{
8436 		if (n < 0 && errno == EINTR)
8437 			goto rewait;
8438 		if (n == 0)
8439 			errno = ETIMEDOUT;
8440 		return(-1);
8441 	}
8442 reread:
8443 	/* fake an error if nothing was actually read */
8444 	fromlen = sizeof(from);
8445 	n = recvfrom(sock, buffer, buflen, 0, from_sa, &fromlen);
8446 	if (n < 0 && errno == EINTR)
8447 		goto reread;
8448 	if (n == 0)
8449 		errno = ECONNRESET;
8450 	return(n);
8451 }
8452 
8453 /*
8454  * Alternative version for systems with broken networking code.
8455  *
8456  * The select() system call may fail on the solaris 2.4 platform
8457  * without appropriate patches. However, these patches are reported
8458  * to break client NFS.
8459  *
8460  * This version uses an alarm() instead of select(). This introduces
8461  * additional system call overhead.
8462  */
8463 
8464 #ifdef BROKEN_SELECT
8465 
8466 static int
recv_sock(sock,buffer,buflen)8467 recv_sock(sock, buffer, buflen)
8468 input int sock;
8469 output char *buffer;			/* current buffer address */
8470 input int buflen;			/* remaining buffer size */
8471 {
8472 	int fromlen;
8473 	register int n;
8474 
8475 	if (setjmp(timer_buf) != 0)
8476 	{
8477 		errno = ETIMEDOUT;
8478 		setalarm(0);
8479 		return(-1);
8480 	}
8481 
8482 	(void) signal(SIGALRM, timer);
8483 	setalarm(timeout);
8484 reread:
8485 	/* fake an error if nothing was actually read */
8486 	fromlen = sizeof(from);
8487 	n = recvfrom(sock, buffer, buflen, 0, from_sa, &fromlen);
8488 	if (n < 0 && errno == EINTR)
8489 		goto reread;
8490 	if (n == 0)
8491 		errno = ECONNRESET;
8492 	setalarm(0);
8493 	return(n);
8494 }
8495 
8496 #endif /*BROKEN_SELECT*/
8497 
8498 /*
8499 ** _RES_PERROR -- Issue perror message including host info
8500 ** -------------------------------------------------------
8501 **
8502 **	Returns:
8503 **		None.
8504 */
8505 
8506 void
_res_perror(addr,host,message)8507 _res_perror(addr, host, message)
8508 input struct sockaddr_in *addr;		/* the server address to connect to */
8509 input char *host;			/* name of server to connect to */
8510 input char *message;			/* perror message string */
8511 {
8512 	int save_errno = errno;		/* preserve state */
8513 
8514 	/* prepend server address and name */
8515 	if (addr != NULL)
8516 		(void) fprintf(stderr, "%s ", inet_ntoa(addr->sin_addr));
8517 	if (host != NULL)
8518 		(void) fprintf(stderr, "(%s) ", host);
8519 
8520 	/* issue actual message */
8521 	errno = save_errno;
8522 	perror(message);
8523 
8524 	/* restore state */
8525 	errno = save_errno;
8526 }
8527