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