home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / n / bind / bind-4.001 / bind-4~ / bind-4.9.3-BETA9 / contrib / host / host.c < prev    next >
C/C++ Source or Header  |  1994-06-23  |  137KB  |  5,569 lines

  1. /*
  2.  * Copyright (c) 1985, 1989 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that: (1) source distributions retain this entire copyright
  7.  * notice and comment, and (2) distributions including binaries display
  8.  * the following acknowledgement:  ``This product includes software
  9.  * developed by the University of California, Berkeley and its contributors''
  10.  * in the documentation or other materials provided with the distribution
  11.  * and in all advertising materials mentioning features or use of this
  12.  * software. Neither the name of the University nor the names of its
  13.  * contributors may be used to endorse or promote products derived
  14.  * from this software without specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19.  
  20. /*
  21.  * Originally, this program came from Rutgers University, however it
  22.  * is based on nslookup and other pieces of named tools, so it needs
  23.  * that copyright notice.
  24.  */
  25.  
  26. /*
  27.  * Rewritten by Eric Wassenaar, Nikhef-H, <e07@nikhef.nl>
  28.  *
  29.  * The officially maintained source of this program is available
  30.  * via anonymous ftp from machine 'ftp.nikhef.nl' [192.16.199.1]
  31.  * in the directory '/pub/network' as 'host.tar.Z'
  32.  *
  33.  * You are kindly requested to report bugs and make suggestions
  34.  * for improvements to the author at the given email address,
  35.  * and to not re-distribute your own modifications to others.
  36.  */
  37.  
  38. #ifndef lint
  39. static char Version[] = "@(#)host.c    e07@nikhef.nl (Eric Wassenaar) 940623";
  40. #endif
  41.  
  42. #if defined(apollo) && defined(lint)
  43. #define __attribute(x)
  44. #endif
  45.  
  46. #define justfun            /* this is only for fun */
  47. #undef  obsolete        /* old code left as a reminder */
  48. #undef  notyet            /* new code for possible future use */
  49.  
  50. /*
  51.  *            New features
  52.  *
  53.  * - Major overhaul of the entire code.
  54.  * - Very rigid error checking, with more verbose error messages.
  55.  * - Zone listing section completely rewritten.
  56.  * - It is now possible to do recursive listings into delegated zones.
  57.  * - Maintain resource record statistics during zone listings.
  58.  * - Maintain count of hosts during zone listings.
  59.  * - Check for various extraneous conditions during zone listings.
  60.  * - Exploit multiple server addresses if available.
  61.  * - Option to exploit only primary server for zone transfers.
  62.  * - Option to exclude info from names that do not reside in a zone.
  63.  * - Implement timeout handling during connect and read.
  64.  * - Write resource record output to optional log file.
  65.  * - Special MB tracing by recursively expanding MR and MG records.
  66.  * - Special mode to check SOA records at each nameserver for a zone.
  67.  * - Special mode to check reverse mappings of host addresses.
  68.  * - Extended syntax allows multiple arguments on command line or stdin.
  69.  * - Configurable default options in HOST_DEFAULTS environment variable.
  70.  * - Implement new resource record types from RFC 1183 and 1348.
  71.  * - Code is extensively documented.
  72.  */
  73.  
  74. /*
  75.  *            Publication history
  76.  *
  77.  * This information has been moved to the RELEASE_NOTES file.
  78.  */
  79.  
  80. /*
  81.  *            Compilation options
  82.  *
  83.  * This program usually compiles without special compilation options,
  84.  * but for some platforms you may have to define special settings.
  85.  * See the Makefile and the header file port.h for details.
  86.  */
  87.  
  88. /*
  89.  *            Miscellaneous notes
  90.  *
  91.  * This program should be linked explicitly with the BIND resolver library
  92.  * in case the default gethostbyname() or gethostbyaddr() routines use a
  93.  * non-standard strategy for retrieving information. These functions in the
  94.  * resolver library call on the nameserver, and fall back on the hosts file
  95.  * only if no nameserver is running (ECONNREFUSED).
  96.  *
  97.  * You may also want to link this program with the BIND resolver library if
  98.  * your default library has not been compiled with DEBUG printout enabled.
  99.  *
  100.  * The version of the resolver should be BIND 4.8.2 or later. The crucial
  101.  * include files are <netdb.h>, (resolv.h>, <arpa/nameser.h>. These files
  102.  * are assumed to be present in the /usr/include directory.
  103.  *
  104.  * The resolver code depends on the definition of the BSD pre-processor
  105.  * variable. This variable is usually defined in the file <sys/param.h>.
  106.  *
  107.  * The definition of this variable determines the method how to handle
  108.  * datagram connections. This may not work properly on all platforms.
  109.  *
  110.  * The hostent struct defined in <netdb.h> is assumed to handle multiple
  111.  * addresses in h_addr_list[]. Usually this is true if BSD >= 43.
  112.  *
  113.  * Your version of the nameserver may not handle queries about top-level
  114.  * zones properly. It needs a patch if it appends the default domain
  115.  * to single names for which it has no data cached. A fix for this is
  116.  * available.
  117.  *
  118.  * The treatment of TXT records has changed from 4.8.2 to 4.8.3. Formerly,
  119.  * the data consisted simply of the text string. Now, the text string is
  120.  * preceded by the character count with a maximum of 255, and multiple
  121.  * strings are embedded if the total character count exceeds 255.
  122.  * We handle only the new situation in this program, assuming that nobody
  123.  * uses TXT records before 4.8.3 (unfortunately this is not always true:
  124.  * current vendor supplied software may sometimes be even pre-BIND 4.8.2).
  125.  *
  126.  * Note that in 4.8.3 PACKETSZ from nameser.h is still at 512, which is
  127.  * the maximum possible packet size for datagrams, whereas MAXDATA from
  128.  * db.h has increased from 256 to 2048. The resolver defines MAXPACKET
  129.  * as 1024. The nameserver reads queries in a buffer of size BUFSIZ.
  130.  *
  131.  * The gethostbyname() routine in 4.8.3 interprets dotted quads (if not
  132.  * terminated with a dot) and simulates a gethostbyaddr(), but we will
  133.  * not rely on it, and handle dotted quads ourselves.
  134.  *
  135.  * On some systems a bug in the _doprnt() routine exists which prevents
  136.  * printf("%.*s", n, string) to be printed correctly if n == 0.
  137.  *
  138.  * This program has not been optimized for speed. Especially the memory
  139.  * management is simple and straightforward.
  140.  */
  141.  
  142. /*
  143.  *            Terminology used
  144.  *
  145.  * Gateway hosts.
  146.  * These are hosts that have more than one address registered under
  147.  * the same name. Obviously we cannot recognize a gateway host if it
  148.  * has different names associated with its different addresses.
  149.  *
  150.  * Duplicate hosts.
  151.  * These are non-gateway hosts of which the address was found earlier
  152.  * but with a different name, possibly in a totally different zone.
  153.  * Such hosts should not be counted again in the overall host count.
  154.  * This situation notably occurs in e.g. the "ac.uk" domain which has
  155.  * many names registered in both the long and the abbreviated form,
  156.  * such as 'host.department.university.ac.uk' and 'host.dept.un.ac.uk'.
  157.  * This is probably not an error per se. It is an error if some domain
  158.  * has registered a foreign address under a name within its own domain.
  159.  * To recognize duplicate hosts when traversing many zones, we have to
  160.  * maintain a global list of host addresses. To simplify things, only
  161.  * single-address hosts are handled as such.
  162.  *
  163.  * Extrazone hosts.
  164.  * These are hosts which belong to a zone but which are not residing
  165.  * directly within the zone under consideration and which are not
  166.  * glue records for a delegated zone of the given zone. E.g. if we are
  167.  * processing the zone 'bar' and find 'host.foo.bar' but 'foo.bar' is not
  168.  * an NS registered delegated zone of 'bar' then it is considered to be
  169.  * an extrazone host. This is not necessarily an error, but it could be.
  170.  *
  171.  * Lame delegations.
  172.  * If we query the SOA record of a zone at a supposedly authoritative
  173.  * nameserver for that zone (listed in the NS records for the zone),
  174.  * the SOA record should be present and the answer authoritative.
  175.  * If not, we flag a lame delegation of the zone to that nameserver.
  176.  * This may need refinement in some special cases.
  177.  * A lame delegation is also flagged if we discover that a nameserver
  178.  * mentioned in an NS record does not exist when looking up its address.
  179.  */
  180.  
  181. /*
  182.  *        Usage: host [options] name [server]
  183.  *        Usage: host [options] -x [name ...]
  184.  *        Usage: host [options] -X server [name ...]
  185.  *
  186.  * Regular command line options:
  187.  * ----------------------------
  188.  *
  189.  * -t type    specify query type; default is T_A for normal mode
  190.  *
  191.  * -a        specify query type T_ANY
  192.  *
  193.  * -v        print verbose messages (-vv is very verbose)
  194.  *
  195.  * -d        print debugging output (-dd prints even more)
  196.  *
  197.  * Special mode options.
  198.  * --------------------
  199.  *
  200.  * -l        special mode to generate zone listing for a zone
  201.  *
  202.  * -L level    do recursive zone listing/checking this level deep
  203.  *
  204.  * -p        use primary nameserver of zone for zone transfers
  205.  *
  206.  * -S        print zone resource record statistics
  207.  *
  208.  * -H        special mode to count hosts residing in a zone
  209.  *
  210.  * -G        same as -H but lists gateway hosts in addition
  211.  *
  212.  * -E        same as -H but lists extrazone hosts in addition
  213.  *
  214.  * -D        same as -H but lists duplicate hosts in addition
  215.  *
  216.  * -C        special mode to check SOA records for a zone
  217.  *
  218.  * -A        special mode to check reverse mappings of host addresses
  219.  *
  220.  * Miscellaneous options.
  221.  * ---------------------
  222.  *
  223.  * -e        exclude info from names that do not reside in the zone
  224.  *
  225.  * -f file    log resource record output also in given file
  226.  *
  227.  * -F file    same as -f, but exchange role of stdout and log file
  228.  *
  229.  * -i        generate reverse in-addr.arpa query for dotted quad
  230.  *
  231.  * -q        be quiet about some non-fatal errors
  232.  *
  233.  * -T        print ttl value or MX pref during non-verbose output
  234.  *
  235.  * -Z        print selected RR output in full zone file format
  236.  *
  237.  * Seldom used options.
  238.  * -------------------
  239.  *
  240.  * -c class    specify query class; default is C_IN
  241.  *
  242.  * -m        specify query type T_MAILB and trace MB records
  243.  *
  244.  * -o        suppress resource record output to stdout
  245.  *
  246.  * -r        do not use recursion when querying nameserver
  247.  *
  248.  * -R        repeatedly add search domains to qualify queryname
  249.  *
  250.  * -s secs    specify timeout value in seconds; default is 2 * 5
  251.  *
  252.  * -u        use virtual circuit instead of datagram for queries
  253.  *
  254.  * -w        wait until nameserver becomes available
  255.  *
  256.  * Undocumented options. (Experimental, subject to change)
  257.  * --------------------
  258.  *
  259.  * -g length    only select names that are at least this long
  260.  *
  261.  * -B        enforce full BIND behaviour during DNSRCH
  262.  *
  263.  * -I chars    print illegal resource record names, but allow chars
  264.  *
  265.  * -M        special mode to list mailable delegated zones of zone
  266.  */
  267.  
  268. static char Usage[] =
  269. "\
  270. Usage:      host [-v] [-a] [-t querytype] [options]  name  [server]\n\
  271. Listing:    host [-v] [-a] [-t querytype] [options]  -l zone  [server]\n\
  272. Hostcount:  host [-v] [options] -H [-D] [-E] [-G] zone\n\
  273. Check soa:  host [-v] [options] -C zone\n\
  274. Addrcheck:  host [-v] [options] -A host\n\
  275. Listing options: [-L level] [-S] [-p]\n\
  276. Common options:  [-d] [-e] [-f logfile] [-F logfile] [-i] [-q] [-T] [-Z]\n\
  277. Other options:   [-c class] [-m] [-o] [-r] [-R] [-s secs] [-u] [-w]\n\
  278. Extended usage:  [-x [name ...]] [-X server [name ...]]\
  279. ";
  280.  
  281. #include <stdio.h>
  282. #include <string.h>
  283. #include <ctype.h>
  284. #include <errno.h>
  285. #include <netdb.h>
  286.  
  287. #include <sys/types.h>        /* not always automatically included */
  288. #include <sys/param.h>
  289. #include <sys/socket.h>
  290. #include <netinet/in.h>
  291.  
  292. #undef NOERROR            /* in <sys/streams.h> on solaris 2.x */
  293. #include <arpa/nameser.h>
  294. #include <resolv.h>
  295.  
  296. #include "type.h"        /* types should be in <arpa/nameser.h> */
  297. #include "exit.h"        /* exit codes come from <sysexits.h> */
  298. #include "port.h"        /* various portability definitions */
  299.  
  300. #define input            /* read-only input parameter */
  301. #define output            /* modified output parameter */
  302.  
  303. #define STDIN    0
  304. #define STDOUT    1
  305. #define STDERR    2
  306.  
  307. typedef int    bool;        /* boolean type */
  308. #define TRUE    1
  309. #define FALSE    0
  310.  
  311. #ifndef NO_DATA
  312. #define NO_DATA    NO_ADDRESS    /* used here only in case authoritative */
  313. #endif
  314.  
  315. #define NO_RREC    (NO_DATA + 1)    /* used for non-authoritative NO_DATA */
  316. #define NO_HOST    (NO_DATA + 2)    /* used for non-authoritative HOST_NOT_FOUND */
  317.  
  318. #define T_NONE    0        /* yet unspecified resource record type */
  319. #define T_FIRST    T_A        /* first possible type in resource record */
  320. #define T_LAST    (T_AXFR - 1)    /* last  possible type in resource record */
  321.  
  322. #define MAXADDRS 35        /* max address count from gethostnamadr.c */
  323.  
  324. #define NOT_DOTTED_QUAD ((ipaddr_t)-1)
  325. #define LOCALHOST_ADDR    ((ipaddr_t)0x7f000001)
  326.  
  327. #define is_space(c)    (isascii(c) && isspace(c))
  328. #define is_alnum(c)    (isascii(c) && isalnum(c))
  329. #define bitset(a,b)    (((a) & (b)) != 0)
  330. #define sameword(a,b)    (strcasecmp(a,b) == 0)
  331. #define samepart(a,b)    (strncasecmp(a,b,strlen(b)) == 0)
  332. #define samehead(a,b)    (strncasecmp(a,b,sizeof(b)-1) == 0)
  333.  
  334. #define fakename(a)    (samehead(a,"localhost.") || samehead(a,"loopback."))
  335. #define fakeaddr(a)    (((a) == 0) || ((a) == htonl(LOCALHOST_ADDR)))
  336. #define incopy(a)    *((struct in_addr *)a)
  337.  
  338. #define newlist(a,n,t)    (t *)xalloc((ptr_t *)a, (siz_t)((n)*sizeof(t)))
  339. #define newstring(a)    (char *)xalloc((ptr_t *)NULL, (siz_t)(strlen(a)+1))
  340. #define newstr(a)    strcpy(newstring(a), a)
  341. #define xfree(a)    (void) free((ptr_t *)a)
  342. #define strlength(a)    (int)strlen(a)
  343.  
  344. #if PACKETSZ > 1024
  345. #define MAXPACKET PACKETSZ
  346. #else
  347. #define MAXPACKET 1024
  348. #endif
  349.  
  350. typedef union {
  351.     HEADER header;
  352.     u_char packet[MAXPACKET];
  353. } querybuf;
  354.  
  355. #ifndef HFIXEDSZ
  356. #define HFIXEDSZ 12        /* actually sizeof(HEADER) */
  357. #endif
  358.  
  359. #define MAXDLEN (MAXPACKET - HFIXEDSZ)
  360.  
  361. #include "rrec.h"        /* resource record structures */
  362.  
  363. #ifdef lint
  364. #define EXTERN
  365. #else
  366. #define EXTERN extern
  367. #endif
  368.  
  369. EXTERN int errno;
  370. EXTERN int h_errno;        /* defined in gethostnamadr.c */
  371. EXTERN res_state_t _res;    /* defined in res_init.c */
  372.  
  373. extern char *version;        /* program version number */
  374.  
  375. char **optargv = NULL;        /* argument list including default options */
  376. int optargc = 0;        /* number of arguments in new argument list */
  377.  
  378. int Errors = 0;            /* global error count */
  379.  
  380. int record_stats[T_ANY+1];    /* count of resource records per type */
  381.  
  382. char cnamebuf[MAXDNAME+1];
  383. char *cname = NULL;        /* name to which CNAME is aliased */
  384.  
  385. char mnamebuf[MAXDNAME+1];
  386. char *mname = NULL;        /* name to which MR or MG is aliased */
  387.  
  388. char soanamebuf[MAXDNAME+1];
  389. char *soaname = NULL;        /* domain name of SOA record */
  390.  
  391. char subnamebuf[MAXDNAME+1];
  392. char *subname = NULL;        /* domain name of NS record */
  393.  
  394. char adrnamebuf[MAXDNAME+1];
  395. char *adrname = NULL;        /* domain name of A record */
  396.  
  397. ipaddr_t address;        /* internet address of A record */
  398.  
  399. char serverbuf[MAXDNAME+1];
  400. char *server = NULL;        /* name of explicit server to query */
  401.  
  402. char realnamebuf[2*MAXDNAME+2];
  403. char *realname = NULL;        /* the actual name that was queried */
  404.  
  405. FILE *logfile = NULL;        /* default is stdout only */
  406. bool logexchange = FALSE;    /* exchange role of log file and stdout */
  407.  
  408. char *illegal = NULL;        /* give warning about illegal domain names */
  409.  
  410. char *queryname = NULL;        /* the name about which to query */
  411. int querytype = T_NONE;        /* the type of the query */
  412. int queryclass = C_IN;        /* the class of the query */
  413. ipaddr_t queryaddr;        /* set if name to query is dotted quad */
  414.  
  415. int debug = 0;            /* print resolver debugging output */
  416. int verbose = 0;        /* verbose mode for extra output */
  417. #ifdef justfun
  418. int namelen = 0;        /* select records exceeding this length */
  419. #endif
  420. int recursive = 0;        /* recursive listmode maximum level */
  421.  
  422. bool quiet = FALSE;        /* suppress non-fatal warning messages */
  423. bool reverse = FALSE;        /* generate reverse in-addr.arpa queries */
  424. bool primary = FALSE;        /* use primary server for zone transfers */
  425. bool suppress = FALSE;        /* suppress resource record output */
  426. bool dotprint = FALSE;        /* print trailing dot in non-listing mode */
  427. bool ttlprint = FALSE;        /* print ttl value in non-verbose mode */
  428. bool waitmode = FALSE;        /* wait until server becomes available */
  429. bool mailmode = FALSE;        /* trace MG and MR into MB records */
  430. bool addrmode = FALSE;        /* check reverse mappings of addresses */
  431. bool listmode = FALSE;        /* generate zone listing of a zone */
  432. bool hostmode = FALSE;        /* count real hosts residing within zone */
  433. bool duplmode = FALSE;        /* list duplicate hosts within zone */
  434. bool extrmode = FALSE;        /* list extrazone hosts within zone */
  435. bool gatemode = FALSE;        /* list gateway hosts within zone */
  436. bool checkmode = FALSE;        /* check SOA records at each nameserver */
  437. bool mxrecmode = FALSE;        /* list MX records for each delegated zone */
  438. bool exclusive = FALSE;        /* exclude records that are not in zone */
  439. bool statistics = FALSE;    /* print resource record statistics */
  440. bool bindcompat = FALSE;    /* enforce full BIND DNSRCH compatibility */
  441. bool classprint = FALSE;    /* print class value in non-verbose mode */
  442.  
  443. #include "defs.h"        /* declaration of functions */
  444.  
  445. #ifdef DEBUG
  446. #define assert(condition)\
  447. {\
  448.     if (!(condition))\
  449.     {\
  450.         (void) fprintf(stderr, "assertion botch: ");\
  451.         (void) fprintf(stderr, "%s(%d): ", __FILE__, __LINE__);\
  452.         (void) fprintf(stderr, "%s\n", "condition");\
  453.         exit(EX_SOFTWARE);\
  454.     }\
  455. }
  456. #else
  457. #define assert(condition)
  458. #endif
  459.  
  460. /*
  461. ** MAIN -- Start of program host
  462. ** -----------------------------
  463. **
  464. **    Exits:
  465. **        EX_OK        Operation successfully completed
  466. **        EX_UNAVAILABLE    Could not obtain requested information
  467. **        EX_CANTCREAT    Could not create specified log file
  468. **        EX_NOINPUT    No input arguments were found
  469. **        EX_NOHOST    Could not lookup explicit server
  470. **        EX_OSERR    Could not obtain resources
  471. **        EX_USAGE    Improper parameter/option specified
  472. **        EX_SOFTWARE    Assertion botch in DEBUG mode
  473. */
  474.  
  475. int
  476. main(argc, argv)
  477. input int argc;
  478. input char *argv[];
  479. {
  480.     register char *option;
  481.     res_state_t new_res;        /* new resolver database */
  482.     int result;            /* result status of action taken */
  483.     char *program;            /* name that host was called with */
  484.     char *servername = NULL;    /* name of explicit server */
  485.     char *logfilename = NULL;    /* name of log file */
  486.     bool extended = FALSE;        /* accept extended argument syntax */
  487.  
  488. #ifdef obsolete
  489.     assert(sizeof(u_int) == 4);    /* probably paranoid */
  490.     assert(sizeof(u_short) == 2);    /* perhaps less paranoid */
  491.     assert(sizeof(ipaddr_t) == 4);    /* but this is critical */
  492. #endif /*obsolete*/
  493.  
  494. /*
  495.  * Synchronize stdout and stderr in case output is redirected.
  496.  */
  497.     linebufmode(stdout);
  498.  
  499. /*
  500.  * Initialize resolver. See show_res() for details.
  501.  * Pickup current values and set new defaults.
  502.  * Query for optional server is also done with new defaults.
  503.  * Old defaults are (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
  504.  */
  505.     (void) res_init();
  506.  
  507.     /* we handle default domains ourselves, thank you */
  508.     _res.options |=  RES_DEFNAMES;
  509.     _res.options &= ~RES_DNSRCH;
  510.  
  511.     _res.options |=  RES_RECURSE;
  512.     _res.options &= ~RES_DEBUG;
  513.     _res.options &= ~RES_USEVC;
  514.  
  515.     _res.retry = 2;        /* number  of retries, default = 4 */
  516.     _res.retrans = 5;    /* timeout in seconds, default = 5 or 6 */
  517.  
  518.     /* initialize packet id */
  519.     _res.id = getpid() & 0x7fff;
  520.  
  521.     /* save new defaults */
  522.     new_res = _res;
  523.  
  524. /*
  525.  * Check whether host was called with a different name.
  526.  * Interpolate default options and parameters.
  527.  */
  528.     option = getenv("HOST_DEFAULTS");
  529.     if (option != NULL)
  530.     {
  531.         set_defaults(option, argc, argv);
  532.         argc = optargc; argv = optargv;
  533.     }
  534.  
  535.     program = rindex(argv[0], '/');
  536.     if (program++ == NULL)
  537.         program = argv[0];
  538.  
  539.     /* check for resource record names */
  540.     querytype = parse_type(program);
  541.     if (querytype < 0)
  542.         querytype = T_NONE;
  543.  
  544.     /* check for zone listing abbreviation */
  545.     if (sameword(program, "zone"))
  546.         listmode = TRUE;
  547.  
  548. /*
  549.  * Scan command line options and flags.
  550.  */
  551.     while (argc > 1 && argv[1][0] == '-')
  552.     {
  553.         for (option = &argv[1][1]; *option != '\0'; option++)
  554.         {
  555.         switch (*option)
  556.         {
  557.             case 'w' :
  558.             waitmode = TRUE;
  559.             new_res.retry = 2;
  560.             new_res.retrans = 5;
  561.             break;
  562.  
  563.             case 's' :
  564.             if (argv[2] == NULL || argv[2][0] == '-')
  565.                 fatal("Missing timeout value");
  566.             new_res.retry = 2;
  567.             new_res.retrans = atoi(argv[2]);
  568.             if (new_res.retrans <= 0)
  569.                 fatal("Invalid timeout value %s", argv[2]);
  570.             argv++; argc--;
  571.             break;
  572.  
  573.             case 'r' :
  574.             new_res.options &= ~RES_RECURSE;
  575.             break;
  576.  
  577.             case 'B' :
  578.             bindcompat = TRUE;
  579.             /* fall through */
  580.  
  581.             case 'R' :
  582.             new_res.options |= RES_DNSRCH;
  583.             break;
  584.  
  585.             case 'u' :
  586.             new_res.options |= RES_USEVC;
  587.             break;
  588.  
  589.             case 'd' :
  590.             new_res.options |= RES_DEBUG;
  591.             debug++;        /* increment debugging level */
  592.             break;
  593.  
  594.             case 'v' :
  595.             verbose++;        /* increment verbosity level */
  596.             break;
  597.  
  598.             case 'q' :
  599.             quiet = TRUE;
  600.             break;
  601.  
  602.             case 'i' :
  603.             reverse = TRUE;
  604.             break;
  605.  
  606.             case 'p' :
  607.             primary = TRUE;
  608.             break;
  609.  
  610.             case 'o' :
  611.             suppress = TRUE;
  612.             break;
  613.  
  614.             case 'e' :
  615.             exclusive = TRUE;
  616.             break;
  617.  
  618.             case 'S' :
  619.             statistics = TRUE;
  620.             break;
  621.  
  622.             case 'T' :
  623.             ttlprint = TRUE;
  624.             break;
  625.  
  626.             case 'Z' :
  627.             dotprint = TRUE;
  628.             ttlprint = TRUE;
  629.             classprint = TRUE;
  630.             break;
  631.  
  632.             case 'A' :
  633.             addrmode = TRUE;
  634.             break;
  635.  
  636.             case 'D':
  637.             case 'E':
  638.             case 'G':
  639.             if (*option == 'D')
  640.                 duplmode = TRUE;
  641.             if (*option == 'E')
  642.                 extrmode = TRUE;
  643.             if (*option == 'G')
  644.                 gatemode = TRUE;
  645.             /* fall through */
  646.  
  647.             case 'H' :
  648.             hostmode = TRUE;
  649.             listmode = TRUE;
  650.             if (querytype == T_NONE)
  651.                 querytype = -1;    /* suppress zone data output */
  652.             break;
  653.  
  654.             case 'C' :
  655.             checkmode = TRUE;
  656.             listmode = TRUE;
  657.             if (querytype == T_NONE)
  658.                 querytype = -1;    /* suppress zone data output */
  659.             break;
  660.  
  661.             case 'M' :
  662.             mxrecmode = TRUE;
  663.             listmode = TRUE;
  664.             if (querytype == T_NONE)
  665.                 querytype = -1;    /* suppress zone data output */
  666.             break;
  667.  
  668.             case 'l' :
  669.             listmode = TRUE;
  670.             break;
  671.  
  672.             case 'L' :
  673.             if (argv[2] == NULL || argv[2][0] == '-')
  674.                 fatal("Missing recursion level");
  675.             recursive = atoi(argv[2]);
  676.             if (recursive <= 0)
  677.                 fatal("Invalid recursion level %s", argv[2]);
  678.             argv++; argc--;
  679.             break;
  680.  
  681.             case 'F' :
  682.             logexchange = TRUE;
  683.             /* fall through */
  684.  
  685.             case 'f' :
  686.             if (argv[2] == NULL || argv[2][0] == '-')
  687.                 fatal("Missing log file name");
  688.             logfilename = argv[2];
  689.             argv++; argc--;
  690.             break;
  691.  
  692.             case 'I' :
  693.             if (argv[2] == NULL || argv[2][0] == '-')
  694.                 fatal("Missing allowed chars");
  695.             illegal = argv[2];
  696.             argv++; argc--;
  697.             break;
  698.  
  699.             case 'c' :
  700.             if (argv[2] == NULL || argv[2][0] == '-')
  701.                 fatal("Missing query class");
  702.             queryclass = parse_class(argv[2]);
  703.             if (queryclass < 0)
  704.                 fatal("Invalid query class %s", argv[2]);
  705.             argv++; argc--;
  706.             break;
  707.  
  708.             case 't' :
  709.             if (argv[2] == NULL || argv[2][0] == '-')
  710.                 fatal("Missing query type");
  711.             querytype = parse_type(argv[2]);
  712.             if (querytype < 0)
  713.                 fatal("Invalid query type %s", argv[2]);
  714.             argv++; argc--;
  715.             break;
  716.  
  717.             case 'a' :
  718.             querytype = T_ANY;    /* filter anything available */
  719.             break;
  720.  
  721.             case 'm' :
  722.             mailmode = TRUE;
  723.             querytype = T_MAILB;    /* filter MINFO/MG/MR/MB data */
  724.             break;
  725. #ifdef justfun
  726.             case 'g' :
  727.             if (argv[2] == NULL || argv[2][0] == '-')
  728.                 fatal("Missing minimum length");
  729.             namelen = atoi(argv[2]);
  730.             if (namelen <= 0)
  731.                 fatal("Invalid minimum length %s", argv[2]);
  732.             argv++; argc--;
  733.             break;
  734. #endif
  735.             case 'X' :
  736.             if (argv[2] == NULL || argv[2][0] == '-')
  737.                 fatal("Missing server name");
  738.             servername = argv[2];
  739.             argv++; argc--;
  740.             /* fall through */
  741.  
  742.             case 'x' :
  743.             extended = TRUE;
  744.             break;
  745.  
  746.             case 'V' :
  747.             printf("Version %s\n", version);
  748.             exit(EX_OK);
  749.  
  750.             default:
  751.             fatal(Usage);
  752.         }
  753.         }
  754.  
  755.         argv++; argc--;
  756.     }
  757.  
  758. /*
  759.  * Check the remaining arguments.
  760.  */
  761.     /* old syntax must have at least one argument */
  762.     if (!extended && (argc < 2 || argc > 3))
  763.         fatal(Usage);
  764.  
  765.     /* old syntax has explicit server as second argument */
  766.     if (!extended && (argc > 2))
  767.         servername = argv[2];
  768.  
  769. /*
  770.  * Open log file if requested.
  771.  * Exchange role of stdout and log file if so specified.
  772.  */
  773.     if (logfilename != NULL)
  774.         set_logfile(logfilename);
  775.  
  776. /*
  777.  * Check for possible alternative server.
  778.  */
  779.     if (servername != NULL)
  780.         set_server(servername);
  781.  
  782. /*
  783.  * Do final resolver initialization.
  784.  */
  785.     /* set new resolver values changed by command options */
  786.     _res.retry = new_res.retry;
  787.     _res.retrans = new_res.retrans;
  788.     _res.options = new_res.options;
  789.  
  790.     /* show the new resolver database */
  791.     if (debug > 1 || verbose > 1)
  792.         show_res();
  793.  
  794.     /* show customized default domain */
  795.     option = getenv("LOCALDOMAIN");
  796.     if (option != NULL && verbose > 1)
  797.         printf("Explicit local domain %s\n\n", option);
  798.  
  799. /*
  800.  * Process command line argument(s) depending on syntax.
  801.  */
  802.     if (!extended) /* only one argument */
  803.         result = process_name(argv[1]);
  804.  
  805.     else if (argc < 2) /* no arguments */
  806.         result = process_file(stdin);
  807.  
  808.     else /* multiple command line arguments */
  809.         result = process_argv(argc, argv);
  810.  
  811.     exit(result);
  812.     /*NOTREACHED*/
  813. }
  814.  
  815. /*
  816. ** SET_DEFAULTS -- Interpolate default options and parameters in argv
  817. ** ------------------------------------------------------------------
  818. **
  819. **    Returns:
  820. **        None.
  821. **
  822. **    Outputs:
  823. **        Creates ``optargv'' vector with ``optargc'' arguments.
  824. */
  825.  
  826. void
  827. set_defaults(option, argc, argv)
  828. input char *option;            /* option string */
  829. input int argc;
  830. input char *argv[];
  831. {
  832.     register char *p, *q;
  833.     register int i;
  834.  
  835. /*
  836.  * Allocate new argument vector.
  837.  */
  838.     optargv = newlist(NULL, 2, char *);
  839.     optargv[0] = argv[0];
  840.     optargc = 1;
  841.  
  842. /*
  843.  * Construct argument list from option string.
  844.  */
  845.     for (p = newstr(option); *p != '\0'; p = q)
  846.     {
  847.         while (is_space(*p))
  848.             p++;
  849.  
  850.         if (*p == '\0')
  851.             break;
  852.  
  853.         for (q = p; *q != '\0' && !is_space(*q); q++)
  854.             continue;
  855.  
  856.         if (*q != '\0')
  857.             *q++ = '\0';
  858.  
  859.         optargv = newlist(optargv, optargc+2, char *);
  860.         optargv[optargc] = p;
  861.         optargc++;
  862.     }
  863.  
  864. /*
  865.  * Append command line arguments.
  866.  */
  867.     for (i = 1; i < argc; i++)
  868.     {
  869.         optargv = newlist(optargv, optargc+2, char *);
  870.         optargv[optargc] = argv[i];
  871.         optargc++;
  872.     }
  873.  
  874.     /* and terminate */
  875.     optargv[optargc] = NULL;
  876. }
  877.  
  878. /*
  879. ** PROCESS_ARGV -- Process command line arguments
  880. ** ----------------------------------------------
  881. **
  882. **    Returns:
  883. **        EX_OK if information was obtained successfully.
  884. **        Appropriate exit code otherwise.
  885. */
  886.  
  887. int
  888. process_argv(argc, argv)
  889. input int argc;
  890. input char *argv[];
  891. {
  892.     register int i;
  893.     int result;            /* result status of action taken */
  894.     int excode = EX_NOINPUT;    /* overall result status */
  895.  
  896.     for (i = 1; i < argc; i++)
  897.     {
  898.         /* process a single argument */
  899.         result = process_name(argv[i]);
  900.  
  901.         /* maintain overall result */
  902.         if (result != EX_OK || excode == EX_NOINPUT)
  903.             excode = result;
  904.     }
  905.  
  906.     /* return overall result */
  907.     return(excode);
  908. }
  909.  
  910. /*
  911. ** PROCESS_FILE -- Process arguments from input file
  912. ** -------------------------------------------------
  913. **
  914. **    Returns:
  915. **        EX_OK if information was obtained successfully.
  916. **        Appropriate exit code otherwise.
  917. */
  918.  
  919. int
  920. process_file(fp)
  921. input FILE *fp;                /* input file with query names */
  922. {
  923.     register char *p, *q;
  924.     char buf[BUFSIZ];
  925.     int result;            /* result status of action taken */
  926.     int excode = EX_NOINPUT;    /* overall result status */
  927.  
  928.     while (fgets(buf, sizeof(buf), fp) != NULL)
  929.     {
  930.         p = index(buf, '\n');
  931.         if (p != NULL)
  932.             *p = '\0';
  933.  
  934.         /* extract names separated by whitespace */
  935.         for (p = buf; *p != '\0'; p = q)
  936.         {
  937.             while (is_space(*p))
  938.                 p++;
  939.  
  940.             /* ignore comment lines */
  941.             if (*p == '\0' || *p == '#' || *p == ';')
  942.                 break;
  943.  
  944.             for (q = p; *q != '\0' && !is_space(*q); q++)
  945.                 continue;
  946.  
  947.             if (*q != '\0')
  948.                 *q++ = '\0';
  949.  
  950.             /* process a single argument */
  951.             result = process_name(p);
  952.  
  953.             /* maintain overall result */
  954.             if (result != EX_OK || excode == EX_NOINPUT)
  955.                 excode = result;
  956.         }
  957.     }
  958.  
  959.     /* return overall result */
  960.     return(excode);
  961. }
  962.  
  963. /*
  964. ** PROCESS_NAME -- Process a single command line argument
  965. ** ------------------------------------------------------
  966. **
  967. **    Returns:
  968. **        EX_OK if information was obtained successfully.
  969. **        Appropriate exit code otherwise.
  970. **
  971. **    Wrapper for execute_name() to hide administrative tasks.
  972. */
  973.  
  974. int
  975. process_name(name)
  976. input char *name;            /* command line argument */
  977. {
  978.     int result;            /* result status of action taken */
  979.     static int save_querytype;
  980.     static bool save_reverse;
  981.     static bool firstname = TRUE;
  982.  
  983.     /* separate subsequent pieces of output */
  984.     if (!firstname && (verbose || debug || checkmode))
  985.         printf("\n");
  986.  
  987. /*
  988.  * Some global variables are redefined further on. Save their initial
  989.  * values in the first pass, and restore them during subsequent passes.
  990.  */
  991.     if (firstname)
  992.     {
  993.         save_querytype = querytype;
  994.         save_reverse = reverse;
  995.         firstname = FALSE;
  996.     }
  997.     else
  998.     {
  999.         querytype = save_querytype;
  1000.         reverse = save_reverse;
  1001.     }
  1002.  
  1003. /*
  1004.  * Do the real work.
  1005.  */
  1006.     result = execute_name(name);
  1007.     return(result);
  1008. }
  1009.  
  1010. /*
  1011. ** EXECUTE_NAME -- Process a single command line argument
  1012. ** ------------------------------------------------------
  1013. **
  1014. **    Returns:
  1015. **        EX_OK if information was obtained successfully.
  1016. **        Appropriate exit code otherwise.
  1017. **
  1018. **    Outputs:
  1019. **        Defines ``queryname'' and ``queryaddr'' appropriately.
  1020. **
  1021. **    Side effects:
  1022. **        May redefine ``querytype'' and ``reverse'' if necessary.
  1023. */
  1024.  
  1025. int
  1026. execute_name(name)
  1027. input char *name;            /* command line argument */
  1028. {
  1029.     bool result;            /* result status of action taken */
  1030.  
  1031.     /* check for nonsense input name */
  1032.     if (strlength(name) > MAXDNAME)
  1033.     {
  1034.         errmsg("Query name %s too long", name);
  1035.         return(EX_USAGE);
  1036.     }
  1037.  
  1038. /*
  1039.  * Analyze name and type to be queried about.
  1040.  * In regular mode, the querytype is used to formulate the nameserver
  1041.  * query, and any response is filtered out when processing the answer.
  1042.  * In listmode, the querytype is used to filter out the proper records.
  1043.  */
  1044.     queryname = name;
  1045.     if (queryname[0] == '\0')
  1046.         queryname = ".";
  1047.  
  1048.     if (sameword(queryname, "."))
  1049.         queryaddr = NOT_DOTTED_QUAD;
  1050.     else
  1051.         queryaddr = inet_addr(queryname);
  1052.  
  1053.     /* invert dotted quad if so requested */
  1054.     if ((queryaddr != NOT_DOTTED_QUAD) && reverse)
  1055.     {
  1056.         queryname = in_addr_arpa(queryname);
  1057.         if (queryname == NULL)
  1058.         {
  1059.             errmsg("Invalid dotted quad %s", name);
  1060.             return(EX_USAGE);
  1061.         }
  1062.  
  1063.         queryaddr = NOT_DOTTED_QUAD;
  1064.     }
  1065.     else
  1066.         reverse = FALSE;
  1067.  
  1068.     /* set querytype for regular mode if unspecified */
  1069.     if ((querytype == T_NONE) && !listmode)
  1070.     {
  1071.         if ((queryaddr != NOT_DOTTED_QUAD) || reverse)
  1072.             querytype = T_PTR;
  1073.         else
  1074.             querytype = T_A;
  1075.     }
  1076.  
  1077.     /* cannot have dotted quad in listmode */
  1078.     if (listmode && (queryaddr != NOT_DOTTED_QUAD))
  1079.     {
  1080.         errmsg("Invalid query name %s", queryname);
  1081.         return(EX_USAGE);
  1082.     }
  1083.  
  1084.     /* must have regular name or dotted quad in addrmode */
  1085.     if (addrmode && reverse)
  1086.     {
  1087.         errmsg("Invalid query name %s", queryname);
  1088.         return(EX_USAGE);
  1089.     }
  1090.  
  1091.     /* show what we are going to query about */
  1092.     if (verbose)
  1093.         show_types(queryname, querytype, queryclass);
  1094.  
  1095. /*
  1096.  * All set. Perform requested function.
  1097.  */
  1098.     result = execute(queryname, queryaddr);
  1099.     return(result ? EX_OK : EX_UNAVAILABLE);
  1100. }
  1101.  
  1102. /*
  1103. ** EXECUTE -- Perform the requested function
  1104. ** -----------------------------------------
  1105. **
  1106. **    Returns:
  1107. **        TRUE if information was obtained successfully.
  1108. **        FALSE otherwise.
  1109. **
  1110. **    The whole environment has been set up and checked.
  1111. */
  1112.  
  1113. bool
  1114. execute(name, addr)
  1115. input char *name;            /* name to query about */
  1116. input ipaddr_t addr;            /* explicit address of query */
  1117. {
  1118.     bool result;            /* result status of action taken */
  1119.  
  1120. /*
  1121.  * Special mode to check reverse mappings of host addresses.
  1122.  */
  1123.     if (addrmode)
  1124.     {
  1125.         if (addr == NOT_DOTTED_QUAD)
  1126.             result = check_addr(name);
  1127.         else
  1128.             result = check_name(addr);
  1129.         return(result);
  1130.     }
  1131.  
  1132. /*
  1133.  * Special mode to list contents of specified zone.
  1134.  */
  1135.     if (listmode)
  1136.     {
  1137.         result = list_zone(name);
  1138.         return(result);
  1139.     }
  1140.  
  1141. /*
  1142.  * Regular mode to query about specified host.
  1143.  */
  1144.     result = host_query(name, addr);
  1145.     return(result);
  1146. }
  1147.  
  1148. /*
  1149. ** HOST_QUERY -- Regular mode to query about specified host
  1150. ** --------------------------------------------------------
  1151. **
  1152. **    Returns:
  1153. **        TRUE if information was obtained successfully.
  1154. **        FALSE otherwise.
  1155. */
  1156.  
  1157. bool
  1158. host_query(name, addr)
  1159. input char *name;            /* name to query about */
  1160. input ipaddr_t addr;            /* explicit address of query */
  1161. {
  1162.     struct hostent *hp;
  1163.     struct in_addr inaddr;
  1164.     char newnamebuf[MAXDNAME+1];
  1165.     char *newname = NULL;        /* name to which CNAME is aliased */
  1166.     int ncnames = 0;        /* count of CNAMEs in chain */
  1167.     bool result;            /* result status of action taken */
  1168.  
  1169.     inaddr.s_addr = addr;
  1170.  
  1171.     result = FALSE;
  1172.     h_errno = TRY_AGAIN;
  1173.  
  1174.     /* retry until positive result or permanent failure */
  1175.     while (result == FALSE && h_errno == TRY_AGAIN)
  1176.     {
  1177.         /* reset before each query to avoid stale data */
  1178.         errno = 0;
  1179.         realname = NULL;
  1180.  
  1181.         if (addr == NOT_DOTTED_QUAD)
  1182.         {
  1183.             /* reset CNAME indicator */
  1184.             cname = NULL;
  1185.  
  1186.             /* lookup the name in question */
  1187.             if (newname == NULL)
  1188.                 result = get_hostinfo(name);
  1189.             else
  1190.                 result = get_hostinfo(newname);
  1191.  
  1192.             /* recurse on CNAMEs, but not too deep */
  1193.             if (cname && (querytype != T_CNAME))
  1194.             {
  1195.                 newname = strcpy(newnamebuf, cname);
  1196.  
  1197.                 if (++ncnames > 5)
  1198.                 {
  1199.                     errmsg("Possible CNAME loop");
  1200.                     return(FALSE);
  1201.                 }
  1202.  
  1203.                 result = FALSE;
  1204.                 h_errno = TRY_AGAIN;
  1205.                 continue;
  1206.             }
  1207.         }
  1208.         else
  1209.         {
  1210.             hp = gethostbyaddr((char *)&inaddr, INADDRSZ, AF_INET);
  1211.             if (hp != NULL)
  1212.             {
  1213.                 print_host("Name", hp);
  1214.                 result = TRUE;
  1215.             }
  1216.         }
  1217.  
  1218.         /* only retry if so requested */
  1219.         if (!waitmode)
  1220.             break;
  1221.     }
  1222.  
  1223.     /* use actual name if available */
  1224.     if (realname != NULL)
  1225.         name = realname;
  1226.  
  1227.     /* explain the reason of a failure */
  1228.     if (result == FALSE)
  1229.         ns_error(name, querytype, queryclass);
  1230.  
  1231.     return(result);
  1232. }
  1233.  
  1234. /*
  1235. ** SET_SERVER -- Override default nameserver with explicit server
  1236. ** --------------------------------------------------------------
  1237. **
  1238. **    Returns:
  1239. **        None.
  1240. **        Aborts the program if an unknown host was given.
  1241. **
  1242. **    Side effects:
  1243. **        The global variable ``server'' is set to indicate
  1244. **        that an explicit server is being used.
  1245. **
  1246. **    The default nameserver addresses in the resolver database
  1247. **    which are initialized by res_init() from /etc/resolv.conf
  1248. **    are replaced with the (possibly multiple) addresses of an
  1249. **    explicitly named server host. If a dotted quad is given,
  1250. **    only that single address will be used.
  1251. */
  1252.  
  1253. void
  1254. set_server(name)
  1255. input char *name;            /* name of server to be queried */
  1256. {
  1257.     register int i;
  1258.     struct hostent *hp;
  1259.     struct in_addr inaddr;
  1260.     ipaddr_t addr;            /* explicit address of server */
  1261.  
  1262.     /* check for nonsense input name */
  1263.     if (strlength(name) > MAXDNAME)
  1264.     {
  1265.         errmsg("Server name %s too long", name);
  1266.         exit(EX_USAGE);
  1267.     }
  1268.  
  1269.     addr = inet_addr(name);
  1270.     inaddr.s_addr = addr;
  1271.  
  1272.     if (addr == NOT_DOTTED_QUAD)
  1273.     {
  1274.         /* lookup all of its addresses; this must not fail */
  1275.         hp = gethostbyname(name);
  1276.         if (hp == NULL)
  1277.         {
  1278.             ns_error(name, T_A, C_IN);
  1279.             errmsg("Error in looking up server name");
  1280.             exit(EX_NOHOST);
  1281.         }
  1282.  
  1283.         for (i = 0; i < MAXNS && hp->h_addr_list[i]; i++)
  1284.         {
  1285.             nslist(i).sin_family = AF_INET;
  1286.             nslist(i).sin_port = htons(NAMESERVER_PORT);
  1287.             nslist(i).sin_addr = incopy(hp->h_addr_list[i]);
  1288.         }
  1289.         _res.nscount = i;
  1290.     }
  1291.     else
  1292.     {
  1293.         /* lookup the name, but use only the given address */
  1294.         hp = gethostbyaddr((char *)&inaddr, INADDRSZ, AF_INET);
  1295.  
  1296.         nslist(0).sin_family = AF_INET;
  1297.         nslist(0).sin_port = htons(NAMESERVER_PORT);
  1298.         nslist(0).sin_addr = inaddr;
  1299.         _res.nscount = 1;
  1300.     }
  1301.  
  1302.     if (hp != NULL)
  1303.     {
  1304.         server = strcpy(serverbuf, hp->h_name);
  1305.         if (verbose)
  1306.             print_host("Server", hp);
  1307.     }
  1308.     else
  1309.     {
  1310.         server = strcpy(serverbuf, inet_ntoa(inaddr));
  1311.         if (verbose)
  1312.             printf("Server: %s\n\n", server);
  1313.     }
  1314. }
  1315.  
  1316. /*
  1317. ** SET_LOGFILE -- Initialize optional log file
  1318. ** -------------------------------------------
  1319. **
  1320. **    Returns:
  1321. **        None.
  1322. **        Aborts the program if the file could not be created.
  1323. **
  1324. **    Side effects:
  1325. **        The global variable ``logfile'' is set to indicate
  1326. **        that resource record output is to be written to it.
  1327. **
  1328. **    Swap ordinary stdout and log file output if so requested.
  1329. */
  1330.  
  1331. void
  1332. set_logfile(filename)
  1333. input char *filename;            /* name of log file */
  1334. {
  1335.     if (logexchange)
  1336.     {
  1337.         logfile = fdopen(dup(STDOUT), "w");
  1338.         if (logfile == NULL)
  1339.         {
  1340.             perror("fdopen");
  1341.             exit(EX_OSERR);
  1342.         }
  1343.  
  1344.         if (freopen(filename, "w", stdout) == NULL)
  1345.         {
  1346.             perror(filename);
  1347.             exit(EX_CANTCREAT);
  1348.         }
  1349.     }
  1350.     else
  1351.     {
  1352.         logfile = fopen(filename, "w");
  1353.         if (logfile == NULL)
  1354.         {
  1355.             perror(filename);
  1356.             exit(EX_CANTCREAT);
  1357.         }
  1358.     }
  1359. }
  1360.  
  1361. /*
  1362. ** FATAL -- Abort program when illegal option encountered
  1363. ** ------------------------------------------------------
  1364. **
  1365. **    Returns:
  1366. **        Aborts after issuing error message.
  1367. */
  1368.  
  1369. void /*VARARGS1*/
  1370. fatal(fmt, a, b, c, d)
  1371. input char *fmt;            /* format of message */
  1372. input char *a, *b, *c, *d;        /* optional arguments */
  1373. {
  1374.     (void) fprintf(stderr, fmt, a, b, c, d);
  1375.     (void) fprintf(stderr, "\n");
  1376.     exit(EX_USAGE);
  1377. }
  1378.  
  1379.  
  1380. /*
  1381. ** ERRMSG -- Issue error message to error output
  1382. ** ---------------------------------------------
  1383. **
  1384. **    Returns:
  1385. **        None.
  1386. **
  1387. **    Side effects:
  1388. **        Increments the global error count.
  1389. */
  1390.  
  1391. void /*VARARGS1*/
  1392. errmsg(fmt, a, b, c, d)
  1393. input char *fmt;            /* format of message */
  1394. input char *a, *b, *c, *d;        /* optional arguments */
  1395. {
  1396.     (void) fprintf(stderr, fmt, a, b, c, d);
  1397.     (void) fprintf(stderr, "\n");
  1398.  
  1399.     /* flag an error */
  1400.     Errors++;
  1401. }
  1402.  
  1403. /*
  1404. ** GET_HOSTINFO -- Principal routine to query about given name
  1405. ** -----------------------------------------------------------
  1406. **
  1407. **    Returns:
  1408. **        TRUE if requested info was obtained successfully.
  1409. **        FALSE otherwise.
  1410. **
  1411. **    This is the equivalent of the resolver module res_search().
  1412. **
  1413. **    In this program RES_DEFNAMES is always on, and RES_DNSRCH
  1414. **    is off by default. This means that single names without dot
  1415. **    are always, and only, tried within the own default domain,
  1416. **    and compound names are assumed to be already fully qualified.
  1417. **
  1418. **    The default BIND behaviour can be simulated by turning on
  1419. **    RES_DNSRCH with -R. The given name, whether or not compound,
  1420. **    is then    first tried within the possible search domains.
  1421. **
  1422. **    Note. In the latter case, the search terminates in case the
  1423. **    specified name exists but does not have the desired type.
  1424. **    The BIND behaviour is to continue the search. This can be
  1425. **    simulated with the undocumented option -B.
  1426. */
  1427.  
  1428. bool
  1429. get_hostinfo(name)
  1430. input char *name;            /* name to query about */
  1431. {
  1432.     register char **domain;
  1433.     register char *cp;
  1434.     int dot;            /* number of dots in query name */
  1435.     bool result;            /* result status of action taken */
  1436.     char oldnamebuf[2*MAXDNAME+2];
  1437.     char *oldname;            /* saved actual name when NO_DATA */
  1438.     int nodata = 0;            /* NO_DATA status during DNSRCH */
  1439.     int nquery = 0;            /* number of extra search queries */
  1440.  
  1441. /*
  1442.  * Single dot means root zone.
  1443.  */
  1444.     if (sameword(name, "."))
  1445.     {
  1446.         result = get_domaininfo(name, (char *)NULL);
  1447.         return(result);
  1448.     }
  1449.  
  1450. /*
  1451.  * Count number of dots. Move to the end of the name.
  1452.  */
  1453.     for (dot = 0, cp = name; *cp != '\0'; cp++)
  1454.         if (*cp == '.')
  1455.             dot++;
  1456.  
  1457. /*
  1458.  * Check for aliases of single name.
  1459.  * Note that the alias is supposed to be fully qualified.
  1460.  */
  1461.     if (dot == 0 && (cp = hostalias(name)) != NULL)
  1462.     {
  1463.         if (verbose)
  1464.             printf("Aliased to \"%s\"\n", cp);
  1465.  
  1466.         result = get_domaininfo(cp, (char *)NULL);
  1467.         return(result);
  1468.     }
  1469.  
  1470. /*
  1471.  * Trailing dot means absolute (fully qualified) address.
  1472.  */
  1473.     if (dot != 0 && cp[-1] == '.')
  1474.     {
  1475.         cp[-1] = '\0';
  1476.         result = get_domaininfo(name, (char *)NULL);
  1477.         cp[-1] = '.';
  1478.         return(result);
  1479.     }
  1480.  
  1481. /*
  1482.  * Append own default domain and other search domains if appropriate.
  1483.  */
  1484.     if ((dot == 0 && bitset(RES_DEFNAMES, _res.options)) ||
  1485.         (dot != 0 && bitset(RES_DNSRCH, _res.options)))
  1486.     {
  1487.         for (domain = _res.dnsrch; *domain; domain++)
  1488.         {
  1489.             result = get_domaininfo(name, *domain);
  1490.             if (result)
  1491.                 return(result);
  1492.  
  1493.             /* keep count of extra search queries */
  1494.             nquery++;
  1495.  
  1496.             /* in case nameserver not present */
  1497.             if (errno == ECONNREFUSED)
  1498.                 return(FALSE);
  1499.  
  1500.             /* if no further search desired (single name) */
  1501.                 if (!bitset(RES_DNSRCH, _res.options))
  1502.                 break;
  1503.  
  1504.             /* if name exists but has not requested type */
  1505.             if (h_errno == NO_DATA || h_errno == NO_RREC)
  1506.             {
  1507.                 if (bindcompat)
  1508.                 {
  1509.                     /* remember status and search up */
  1510.                     oldname = strcpy(oldnamebuf, realname);
  1511.                     nodata = h_errno;
  1512.                     continue;
  1513.                 }
  1514.  
  1515.                 return(FALSE);
  1516.             }
  1517.  
  1518.             /* retry only if name does not exist at all */
  1519.             if (h_errno != HOST_NOT_FOUND && h_errno != NO_HOST)
  1520.                 break;
  1521.         }
  1522.     }
  1523.  
  1524. /*
  1525.  * Single name lookup failed.
  1526.  */
  1527.     if (dot == 0)
  1528.     {
  1529.         /* unclear what actual name should be */
  1530.         if (nquery != 1)
  1531.             realname = NULL;
  1532.  
  1533.         /* restore nodata status from search */
  1534.         if (bindcompat && nodata)
  1535.         {
  1536.             realname = strcpy(realnamebuf, oldname);
  1537.             h_errno = nodata;
  1538.         }
  1539.  
  1540.         /* set status in case we never queried */
  1541.         if (!bitset(RES_DEFNAMES, _res.options))
  1542.             h_errno = HOST_NOT_FOUND;
  1543.  
  1544.         return(FALSE);
  1545.     }
  1546.  
  1547. /*
  1548.  * Rest means fully qualified.
  1549.  */
  1550.     result = get_domaininfo(name, (char *)NULL);
  1551.  
  1552.     /* restore nodata status from search */
  1553.     if (!result && bindcompat && nodata)
  1554.     {
  1555.         realname = strcpy(realnamebuf, oldname);
  1556.         h_errno = nodata;
  1557.     }
  1558.  
  1559.     return(result);
  1560. }
  1561.  
  1562. /*
  1563. ** GET_DOMAININFO -- Fetch and print desired info about name in domain
  1564. ** -------------------------------------------------------------------
  1565. **
  1566. **    Returns:
  1567. **        TRUE if requested info was obtained successfully.
  1568. **        FALSE otherwise.
  1569. **
  1570. **    Side effects:
  1571. **        Sets global variable ``realname'' to actual name queried.
  1572. **
  1573. **    This is the equivalent of the resolver module res_querydomain().
  1574. **
  1575. **    Things get a little complicated in case RES_DNSRCH is on.
  1576. **    If we get an answer but the data is corrupted, an error will be
  1577. **    returned and NO_RECOVERY will be set. This will terminate the
  1578. **    extra search loop, but a compound name will still be tried as-is.
  1579. **    The same holds if the query times out or we have a server failure,
  1580. **    in which case an error will be returned and TRY_AGAIN will be set.
  1581. **    For now we take this for granted. Normally RES_DNSRCH is disabled.
  1582. **    In this default case we do only one query and we have no problem.
  1583. */
  1584.  
  1585. bool
  1586. get_domaininfo(name, domain)
  1587. input char *name;            /* name to query about */
  1588. input char *domain;            /* domain to which name is relative */
  1589. {
  1590.     char namebuf[2*MAXDNAME+2];    /* buffer to store full domain name */
  1591.     querybuf answer;
  1592.     int anslen;
  1593.     bool result;            /* result status of action taken */
  1594.  
  1595. /*
  1596.  * Show what we are about to query.
  1597.  */
  1598.     if (verbose)
  1599.     {
  1600.         if (domain == NULL || domain[0] == '\0')
  1601.             printf("Trying %s", name);
  1602.         else
  1603.             printf("Trying %s within %s", name, domain);
  1604.  
  1605.         if (server && (verbose > 1))
  1606.             printf(" at server %s", server);
  1607.  
  1608.         printf(" ...\n");
  1609.     }
  1610.  
  1611. /*
  1612.  * Construct the actual domain name.
  1613.  * A null domain means the given name is already fully qualified.
  1614.  * If the composite name is too long, res_mkquery() will fail.
  1615.  */
  1616.     if (domain == NULL || domain[0] == '\0')
  1617.         (void) sprintf(namebuf, "%.*s", MAXDNAME, name);
  1618.     else
  1619.         (void) sprintf(namebuf, "%.*s.%.*s",
  1620.                 MAXDNAME, name, MAXDNAME, domain);
  1621.     name = namebuf;
  1622.  
  1623. /*
  1624.  * Fetch the desired info.
  1625.  */
  1626.     anslen = get_info(&answer, name, querytype, queryclass);
  1627.     result = anslen < 0 ? FALSE : TRUE;
  1628.  
  1629. /*
  1630.  * Print the relevant data.
  1631.  * If we got a positive answer, the data may still be corrupted.
  1632.  */
  1633.     if (result)
  1634.         result = print_info(&answer, anslen, name, FALSE);
  1635.  
  1636. /*
  1637.  * Remember the actual name that was queried.
  1638.  * Must be at the end to avoid clobbering during recursive calls.
  1639.  */
  1640.     realname = strcpy(realnamebuf, name);
  1641.  
  1642.     return(result);
  1643. }
  1644.  
  1645. /*
  1646. ** GET_INFO -- Basic routine to issue a nameserver query
  1647. ** -----------------------------------------------------
  1648. **
  1649. **    Returns:
  1650. **        Length of nameserver answer buffer, if obtained.
  1651. **        -1 if an error occurred (h_errno is set appropriately).
  1652. **
  1653. **    This is the equivalent of the resolver module res_query().
  1654. */
  1655.  
  1656. int
  1657. get_info(answerbuf, name, type, class)
  1658. output querybuf *answerbuf;        /* address of buffer to store answer */
  1659. input char *name;            /* full name to query about */
  1660. input int type;                /* specific resource record type */
  1661. input int class;            /* specific resource record class */
  1662. {
  1663.     querybuf query;
  1664.     HEADER *bp;
  1665.     int ancount;
  1666.     register int n;
  1667.  
  1668. /*
  1669.  * Construct query, and send it to the nameserver.
  1670.  * res_send() will fail if no nameserver responded. In the BIND version the
  1671.  * possible values for errno are ECONNREFUSED and ETIMEDOUT. If we did get
  1672.  * an answer, errno should be reset, since res_send() may have left an errno
  1673.  * in case it has used datagrams. Our private version of res_send() will leave
  1674.  * also other error statuses, and will clear errno if an answer was obtained.
  1675.  */
  1676.     errno = 0;    /* reset before querying nameserver */
  1677.  
  1678.     n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0,
  1679.             (rrec_data_t *)NULL, (char *)&query, sizeof(querybuf));
  1680.     if (n < 0)
  1681.     {
  1682.         if (debug)
  1683.             (void) fprintf(stderr, "res_mkquery failed\n");
  1684.         h_errno = NO_RECOVERY;
  1685.         return(-1);
  1686.     }
  1687.  
  1688.     n = res_send((char *)&query, n, (char *)answerbuf, sizeof(querybuf));
  1689.     if (n < 0)
  1690.     {
  1691.         if (debug)
  1692.             (void) fprintf(stderr, "res_send failed\n");
  1693.         h_errno = TRY_AGAIN;
  1694.         return(-1);
  1695.     }
  1696.  
  1697.     errno = 0;    /* reset after we got an answer */
  1698.  
  1699.     if (n < HFIXEDSZ)
  1700.     {
  1701.         pr_error("answer length %s too short", itoa(n));
  1702.         h_errno = NO_RECOVERY;
  1703.         return(-1);
  1704.     }
  1705.  
  1706. /*
  1707.  * Analyze the status of the answer from the nameserver.
  1708.  */
  1709.     if (debug || verbose)
  1710.         print_status(answerbuf);
  1711.  
  1712.     bp = (HEADER *)answerbuf;
  1713.     ancount = ntohs(bp->ancount);
  1714.  
  1715.     if (bp->rcode != NOERROR || ancount == 0)
  1716.     {
  1717.         switch (bp->rcode)
  1718.         {
  1719.             case NXDOMAIN:
  1720.             /* distinguish between authoritative or not */
  1721.             h_errno = bp->aa ? HOST_NOT_FOUND : NO_HOST;
  1722.             break;
  1723.  
  1724.             case NOERROR:
  1725.             /* distinguish between authoritative or not */
  1726.             h_errno = bp->aa ? NO_DATA : NO_RREC;
  1727.             break;
  1728.  
  1729.             case SERVFAIL:
  1730.             h_errno = TRY_AGAIN;
  1731.             break;
  1732.  
  1733.             case FORMERR:
  1734.             case NOTIMP:
  1735.             case REFUSED:
  1736.             case NOCHANGE:
  1737.             h_errno = NO_RECOVERY;
  1738.             break;
  1739.  
  1740.             default:
  1741.             h_errno = NO_RECOVERY;
  1742.             break;
  1743.         }
  1744.         return(-1);
  1745.     }
  1746.  
  1747.     h_errno = 0;
  1748.     return(n);
  1749. }
  1750.  
  1751. /*
  1752. ** PRINT_INFO -- Check resource records in answer and print relevant data
  1753. ** ----------------------------------------------------------------------
  1754. **
  1755. **    Returns:
  1756. **        TRUE if answer buffer was processed successfully.
  1757. **        FALSE otherwise.
  1758. **
  1759. **    Side effects:
  1760. **        Will recurse on MAILB records if appropriate.
  1761. **        See also side effects of the print_rrec() routine.
  1762. */
  1763.  
  1764. bool
  1765. print_info(answerbuf, answerlen, name, listing)
  1766. input querybuf *answerbuf;        /* address of answer buffer */
  1767. input int answerlen;            /* length of answer buffer */
  1768. input char *name;            /* full name we are querying about */
  1769. input bool listing;            /* set if this is a zone listing */
  1770. {
  1771.     HEADER *bp;
  1772.     int qdcount, ancount, nscount, arcount;
  1773.     u_char *msg, *eom;
  1774.     register u_char *cp;
  1775.  
  1776.     bp = (HEADER *)answerbuf;
  1777.     qdcount = ntohs(bp->qdcount);
  1778.     ancount = ntohs(bp->ancount);
  1779.     nscount = ntohs(bp->nscount);
  1780.     arcount = ntohs(bp->arcount);
  1781.  
  1782.     msg = (u_char *)answerbuf;
  1783.     eom = (u_char *)answerbuf + answerlen;
  1784.     cp  = (u_char *)answerbuf + HFIXEDSZ;
  1785.  
  1786. /*
  1787.  * Skip the query section in the response (present only in normal queries).
  1788.  */
  1789.     if (qdcount)
  1790.     {
  1791.         while (qdcount > 0 && cp < eom)
  1792.         {
  1793.             /* cp += dn_skipname(cp, eom) + QFIXEDSZ; */
  1794.  
  1795.             cp = skip_qrec(name, cp, msg, eom);
  1796.             if (cp == NULL)
  1797.                 return(FALSE);
  1798.             qdcount--;
  1799.         }
  1800.  
  1801.         if (qdcount)
  1802.         {
  1803.             pr_error("invalid qdcount in response");
  1804.             h_errno = NO_RECOVERY;
  1805.             return(FALSE);
  1806.         }
  1807.     }
  1808.  
  1809. /*
  1810.  * Process the actual answer section in the response.
  1811.  * During zone transfers, this is the only section available.
  1812.  */
  1813.     if (ancount)
  1814.     {
  1815.         if (!listing && verbose && !bp->aa)
  1816.             printf("The following answer is not authoritative:\n");
  1817.  
  1818.         while (ancount > 0 && cp < eom)
  1819.         {
  1820.             cp = print_rrec(name, cp, msg, eom, listing);
  1821.             if (cp == NULL)
  1822.                 return(FALSE);
  1823.             ancount--;
  1824.  
  1825.         /*
  1826.          * When we ask for address and there is a CNAME, it returns
  1827.          * both the CNAME and the address.  Since we trace down the
  1828.          * CNAME chain ourselves, we don't really want to print the
  1829.          * address at this point.
  1830.          */
  1831.             if (!listmode && !verbose && cname)
  1832.                 return(TRUE);
  1833.  
  1834.         /*
  1835.          * Recursively expand MR or MG records into MB records.
  1836.          */
  1837.             if (!listmode && mailmode && mname)
  1838.             {
  1839.                 char newnamebuf[MAXDNAME+1];
  1840.                 char *newname;
  1841.  
  1842.                 newname = strcpy(newnamebuf, mname);
  1843.                 mname = NULL;
  1844.  
  1845.                 (void) get_recursive(newname);
  1846.             }
  1847.         }
  1848.  
  1849.         if (ancount)
  1850.         {
  1851.             pr_error("invalid ancount in response");
  1852.             h_errno = NO_RECOVERY;
  1853.             return(FALSE);
  1854.         }
  1855.     }
  1856.  
  1857. /*
  1858.  * The nameserver and additional info section are normally not processed.
  1859.  * Both sections shouldn't exist in zone transfers.
  1860.  */
  1861.     if (!verbose || exclusive)
  1862.         return(TRUE);
  1863.  
  1864.     if (nscount)
  1865.     {
  1866.         printf("Authoritative nameservers:\n");
  1867.  
  1868.         while (nscount > 0 && cp < eom)
  1869.         {
  1870.             cp = print_rrec(name, cp, msg, eom, FALSE);
  1871.             if (cp == NULL)
  1872.                 return(FALSE);
  1873.             nscount--;
  1874.         }
  1875.  
  1876.         if (nscount)
  1877.         {
  1878.             pr_error("invalid nscount in response");
  1879.             h_errno = NO_RECOVERY;
  1880.             return(FALSE);
  1881.         }
  1882.     }
  1883.  
  1884.     if (arcount)
  1885.     {
  1886.         printf("Additional information:\n");
  1887.  
  1888.         while (arcount > 0 && cp < eom)
  1889.         {
  1890.             cp = print_rrec(name, cp, msg, eom, FALSE);
  1891.             if (cp == NULL)
  1892.                 return(FALSE);
  1893.             arcount--;
  1894.         }
  1895.  
  1896.         if (arcount)
  1897.         {
  1898.             pr_error("invalid arcount in response");
  1899.             h_errno = NO_RECOVERY;
  1900.             return(FALSE);
  1901.         }
  1902.     }
  1903.  
  1904.     return(TRUE);
  1905. }
  1906.  
  1907. /*
  1908. ** PRINT_DATA -- Output resource record data if this record is wanted
  1909. ** ------------------------------------------------------------------
  1910. **
  1911. **    Returns:
  1912. **        None.
  1913. **
  1914. **    Inputs:
  1915. **        The global variable ``doprint'' is set by print_rrec()
  1916. **        if we need to print the data.
  1917. */
  1918.  
  1919. static bool doprint;        /* indicates whether or not to print */
  1920.  
  1921. void /*VARARGS1*/
  1922. print_data(fmt, a, b, c, d)
  1923. input char *fmt;            /* format of message */
  1924. input char *a, *b, *c, *d;        /* optional arguments */
  1925. {
  1926.     /* if (doprint) */
  1927.     {
  1928.         if (!suppress)
  1929.             printf(fmt, a, b, c, d);
  1930.  
  1931.         if (logfile != NULL)
  1932.             (void) fprintf(logfile, fmt, a, b, c, d);
  1933.     }
  1934. }
  1935.  
  1936. #define doprintf(x)\
  1937. {\
  1938.     if (doprint)\
  1939.     {\
  1940.         print_data x ;\
  1941.     }\
  1942. }
  1943.  
  1944. /*
  1945. ** PRINT_RREC -- Decode single resource record and output relevant data
  1946. ** --------------------------------------------------------------------
  1947. **
  1948. **    Returns:
  1949. **        Pointer to position in answer buffer after current record.
  1950. **        NULL if there was a format error in the current record.
  1951. **
  1952. **    Outputs:
  1953. **        The global variable ``doprint'' is set appropriately
  1954. **        for use by print_data().
  1955. **
  1956. **    Side effects:
  1957. **        Updates resource record statistics in record_stats[].
  1958. **        Sets ``soaname'' if this is an SOA record.
  1959. **        Sets ``subname'' if this is an NS record.
  1960. **        Sets ``adrname'' if this is an A record.
  1961. **        Sets ``address'' if this is an A record.
  1962. **        Sets ``cname'' if this is a valid CNAME record.
  1963. **        Sets ``mname'' if this is a valid MAILB record.
  1964. **        These variables must have been cleared before calling
  1965. **        print_info() and may be checked afterwards.
  1966. */
  1967.  
  1968. #define pr_name(x)    ((listing || dotprint) ? pr_dotname(x) : x)
  1969.  
  1970. u_char *
  1971. print_rrec(name, cp, msg, eom, listing)
  1972. input char *name;            /* full name we are querying about */
  1973. register u_char *cp;            /* current position in answer buf */
  1974. input u_char *msg, *eom;        /* begin and end of answer buf */
  1975. input bool listing;            /* set if this is a zone listing */
  1976. {
  1977.     char rname[MAXDNAME+1];        /* record name in LHS */
  1978.     char dname[MAXDNAME+1];        /* domain name in RHS */
  1979.     int type, class, ttl, dlen;    /* fixed values in every record */
  1980.     u_char *eor;            /* predicted position of next record */
  1981.     bool classmatch;        /* set if we want to see this class */
  1982.     register int n;
  1983.     struct in_addr inaddr;
  1984.     struct protoent *protocol;
  1985.     struct servent *service;
  1986.  
  1987. /*
  1988.  * Pickup the standard values present in each resource record.
  1989.  */
  1990.     n = expand_name(name, T_NONE, cp, msg, eom, rname);
  1991.     if (n < 0)
  1992.         return(NULL);
  1993.     cp += n;
  1994.  
  1995.     n = 3*INT16SZ + INT32SZ;
  1996.     if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
  1997.         return(NULL);
  1998.  
  1999.     type = _getshort(cp);
  2000.     cp += INT16SZ;
  2001.  
  2002.     class = _getshort(cp);
  2003.     cp += INT16SZ;
  2004.  
  2005.     ttl = _getlong(cp);
  2006.     cp += INT32SZ;
  2007.  
  2008.     dlen = _getshort(cp);
  2009.     cp += INT16SZ;
  2010.  
  2011.     eor = cp + dlen;
  2012.  
  2013. /*
  2014.  * Decide whether or not to print this resource record.
  2015.  */
  2016.     if (listing)
  2017.     {
  2018.         classmatch = want_class(class, queryclass);
  2019.         doprint = classmatch && want_type(type, querytype);
  2020.     }
  2021.     else
  2022.     {
  2023.         classmatch = want_class(class, C_ANY);
  2024.         doprint = classmatch && want_type(type, T_ANY);
  2025.     }
  2026.  
  2027. #ifdef obsolete
  2028.     if (doprint && exclusive && !samedomain(rname, name, TRUE))
  2029.         doprint = FALSE;
  2030. #endif
  2031.     if (doprint && exclusive && !indomain(rname, name, TRUE))
  2032.         doprint = FALSE;
  2033.  
  2034.     if (doprint && exclusive && fakename(rname))
  2035.         doprint = FALSE;
  2036.  
  2037. #ifdef justfun
  2038.     if (namelen && (strlength(rname) < namelen))
  2039.         doprint = FALSE;
  2040. #endif
  2041.  
  2042. /*
  2043.  * Print name and common values, if appropriate.
  2044.  */
  2045.     doprintf(("%-20s", pr_name(rname)))
  2046.  
  2047.     if (verbose || ttlprint)
  2048.         doprintf(("\t%s", itoa(ttl)))
  2049.  
  2050.     if (verbose || classprint || (class != queryclass))
  2051.         doprintf(("\t%s", pr_class(class)))
  2052.  
  2053.     doprintf(("\t%s", pr_type(type)))
  2054.  
  2055. /*
  2056.  * Update resource record statistics for zone listing.
  2057.  */
  2058.     if (listing && classmatch)
  2059.     {
  2060.         if (type >= T_FIRST && type <= T_LAST)
  2061.             record_stats[type]++;
  2062.     }
  2063.  
  2064. /*
  2065.  * Save the domain name of an SOA or NS or A record for zone listing.
  2066.  */
  2067.     if (listing && classmatch)
  2068.     {
  2069.         if (type == T_A)
  2070.             adrname = strcpy(adrnamebuf, rname);
  2071.         else if (type == T_NS)
  2072.             subname = strcpy(subnamebuf, rname);
  2073.         else if (type == T_SOA)
  2074.             soaname = strcpy(soanamebuf, rname);
  2075.     }
  2076.  
  2077. /*
  2078.  * Print type specific data, if appropriate.
  2079.  */
  2080.     switch (type)
  2081.     {
  2082.         case T_A:
  2083.         switch (class)
  2084.         {
  2085.             case C_IN:
  2086.             case C_HS:
  2087.             if (dlen == INADDRSZ)
  2088.             {
  2089.                 bcopy((char *)cp, (char *)&inaddr, INADDRSZ);
  2090.                 address = inaddr.s_addr;
  2091.                 doprintf(("\t%s", inet_ntoa(inaddr)))
  2092.                 cp += INADDRSZ;
  2093.                 break;
  2094.             }
  2095.             else if (dlen == INADDRSZ + 1 + INT16SZ)
  2096.             {
  2097.                 bcopy((char *)cp, (char *)&inaddr, INADDRSZ);
  2098.                 address = inaddr.s_addr;
  2099.                 doprintf(("\t%s", inet_ntoa(inaddr)))
  2100.                 cp += INADDRSZ;
  2101.  
  2102.                 n = *cp++;
  2103.                 doprintf((", protocol = %s", itoa(n)))
  2104.  
  2105.                 n = _getshort(cp);
  2106.                 doprintf((", port = %s", itoa(n)))
  2107.                 cp += INT16SZ;
  2108.                 break;
  2109.             }
  2110.             address = 0;
  2111.             break;
  2112.  
  2113.             default:
  2114.             address = 0;
  2115.             cp += dlen;
  2116.             break;
  2117.         }
  2118.         break;
  2119.  
  2120.         case T_MX:
  2121.         if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
  2122.             break;
  2123.         n = _getshort(cp);
  2124.         if (verbose || ttlprint)
  2125.             doprintf(("\t%s ", itoa(n)))
  2126.         else
  2127.             doprintf(("\t"))
  2128.         cp += INT16SZ;
  2129.  
  2130.         n = expand_name(rname, type, cp, msg, eom, dname);
  2131.         if (n < 0)
  2132.             break;
  2133.         doprintf(("%s", pr_name(dname)))
  2134.         cp += n;
  2135.         break;
  2136.  
  2137.         case T_NS:
  2138.         case T_PTR:
  2139.         case T_CNAME:
  2140.         n = expand_name(rname, type, cp, msg, eom, dname);
  2141.         if (n < 0)
  2142.             break;
  2143.         doprintf(("\t%s", pr_name(dname)))
  2144.         cp += n;
  2145.         break;
  2146.  
  2147.         case T_SOA:
  2148.         n = expand_name(rname, type, cp, msg, eom, dname);
  2149.         if (n < 0)
  2150.             break;
  2151.         doprintf(("\t%s", pr_name(dname)))
  2152.         cp += n;
  2153.  
  2154.         n = expand_name(rname, type, cp, msg, eom, dname);
  2155.         if (n < 0)
  2156.             break;
  2157.         doprintf((" %s", pr_name(dname)))
  2158.         cp += n;
  2159.  
  2160.         n = 5*INT32SZ;
  2161.         if (check_size(rname, type, cp, msg, eor, n) < 0)
  2162.             break;
  2163.         n = _getlong(cp);
  2164.         doprintf((" (\n\t\t\t%s\t;serial (version)", utoa(n)))
  2165.         cp += INT32SZ;
  2166.         n = _getlong(cp);
  2167.         doprintf(("\n\t\t\t%s\t;refresh period", itoa(n)))
  2168.         cp += INT32SZ;
  2169.         n = _getlong(cp);
  2170.         doprintf(("\n\t\t\t%s\t;retry refresh time", itoa(n)))
  2171.         cp += INT32SZ;
  2172.         n = _getlong(cp);
  2173.         doprintf(("\n\t\t\t%s\t;expiration period", itoa(n)))
  2174.         cp += INT32SZ;
  2175.         n = _getlong(cp);
  2176.         doprintf(("\n\t\t\t%s\t;default ttl\n\t\t\t)", itoa(n)))
  2177.         cp += INT32SZ;
  2178.         break;
  2179.  
  2180.         case T_WKS:
  2181.         if (check_size(rname, type, cp, msg, eor, INADDRSZ) < 0)
  2182.             break;
  2183.         bcopy((char *)cp, (char *)&inaddr, INADDRSZ);
  2184.         doprintf(("\t%s", inet_ntoa(inaddr)))
  2185.         cp += INADDRSZ;
  2186.  
  2187.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2188.             break;
  2189.         n = *cp++;
  2190.         protocol = getprotobynumber(n);
  2191.         if (protocol != NULL)
  2192.             doprintf((" %s", protocol->p_name))
  2193.         else
  2194.             doprintf((" %s", itoa(n)))
  2195.  
  2196.         doprintf((" ("))
  2197.         n = 0;
  2198.         while (cp < eor)
  2199.         {
  2200.             register int c;
  2201.             int port;
  2202.  
  2203.             c = *cp++;
  2204.             do
  2205.             {
  2206.              if (c & 0200)
  2207.             {
  2208.                 port = htons(n);
  2209.                 if (protocol != NULL)
  2210.                     service = getservbyport(port, protocol->p_name);
  2211.                 else
  2212.                     service = NULL;
  2213.                 if (service != NULL)
  2214.                     doprintf((" %s", service->s_name))
  2215.                 else
  2216.                     doprintf((" %s", itoa(n)))
  2217.             }
  2218.              c <<= 1;
  2219.             } while (++n & 07);
  2220.         }
  2221.         doprintf((" )"))
  2222.         break;
  2223.  
  2224.         case T_HINFO:
  2225.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2226.             break;
  2227.         n = *cp++;
  2228.         doprintf(("\t\"%s\"", stoa(cp, n)))
  2229.         cp += n;
  2230.  
  2231.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2232.             break;
  2233.         n = *cp++;
  2234.         doprintf(("\t\"%s\"", stoa(cp, n)))
  2235.         cp += n;
  2236.         break;
  2237.  
  2238.         case T_MINFO:
  2239.         n = expand_name(rname, type, cp, msg, eom, dname);
  2240.         if (n < 0)
  2241.             break;
  2242.         doprintf(("\t%s", pr_name(dname)))
  2243.         cp += n;
  2244.  
  2245.         n = expand_name(rname, type, cp, msg, eom, dname);
  2246.         if (n < 0)
  2247.             break;
  2248.         doprintf((" %s", pr_name(dname)))
  2249.         cp += n;
  2250.         break;
  2251.  
  2252.         case T_MB:
  2253.         case T_MG:
  2254.         case T_MR:
  2255.         case T_MD:
  2256.         case T_MF:
  2257.         n = expand_name(rname, type, cp, msg, eom, dname);
  2258.         if (n < 0)
  2259.             break;
  2260.         doprintf(("\t%s", pr_name(dname)))
  2261.         cp += n;
  2262.         break;
  2263.  
  2264. #ifdef obsolete
  2265.         case T_TXT:
  2266.         if (dlen > 0)
  2267.         {
  2268.             doprintf(("\t%s", stoa(cp, dlen)))
  2269.             cp += dlen;
  2270.         }
  2271.         break;
  2272. #endif
  2273.         case T_TXT:
  2274.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2275.             break;
  2276.         n = *cp++;
  2277.         doprintf(("\t\"%s", stoa(cp, n)))
  2278.         cp += n;
  2279.  
  2280.         while (cp < eor)
  2281.         {
  2282.             if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2283.                 break;
  2284.             n = *cp++;
  2285.             doprintf(("%s", stoa(cp, n)))
  2286.             cp += n;
  2287.         }
  2288.  
  2289.         doprintf(("\""))
  2290.         break;
  2291.  
  2292.         case T_UINFO:
  2293.         doprintf(("\t\"%s\"", stoa(cp, dlen)))
  2294.         cp += dlen;
  2295.         break;
  2296.  
  2297.         case T_UID:
  2298.         case T_GID:
  2299.         if (dlen == INT32SZ)
  2300.         {
  2301.             n = _getlong(cp);
  2302.             doprintf(("\t%s", itoa(n)))
  2303.             cp += INT32SZ;
  2304.         }
  2305.         break;
  2306.  
  2307.         case T_UNSPEC:
  2308.         case T_NULL:
  2309.         cp += dlen;
  2310.         break;
  2311.  
  2312.         case T_RP:
  2313.         n = expand_name(rname, type, cp, msg, eom, dname);
  2314.         if (n < 0)
  2315.             break;
  2316.         doprintf(("\t%s", pr_name(dname)))
  2317.         cp += n;
  2318.  
  2319.         n = expand_name(rname, type, cp, msg, eom, dname);
  2320.         if (n < 0)
  2321.             break;
  2322.         doprintf((" %s", pr_name(dname)))
  2323.         cp += n;
  2324.         break;
  2325.  
  2326.         case T_RT:
  2327.         case T_AFSDB:
  2328.         if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
  2329.             break;
  2330.         n = _getshort(cp);
  2331.         if (verbose || ttlprint)
  2332.             doprintf(("\t%s ", itoa(n)))
  2333.         else
  2334.             doprintf(("\t"))
  2335.         cp += INT16SZ;
  2336.  
  2337.         n = expand_name(rname, type, cp, msg, eom, dname);
  2338.         if (n < 0)
  2339.             break;
  2340.         doprintf(("%s", pr_name(dname)))
  2341.         cp += n;
  2342.         break;
  2343.  
  2344.         case T_X25:
  2345.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2346.             break;
  2347.         n = *cp++;
  2348.         if (n > 0)
  2349.         {
  2350.             doprintf(("\t%s", stoa(cp, n)))
  2351.             cp += n;
  2352.         }
  2353.         break;
  2354.  
  2355.         case T_ISDN:
  2356.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2357.             break;
  2358.         n = *cp++;
  2359.         if (n > 0)
  2360.         {
  2361.             doprintf(("\t%s", stoa(cp, n)))
  2362.             cp += n;
  2363.         }
  2364.  
  2365.         if (cp < eor)
  2366.         {
  2367.             if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2368.                 break;
  2369.             n = *cp++;
  2370.             if (n > 0)
  2371.             {
  2372.                 doprintf(("\t%s", stoa(cp, n)))
  2373.                 cp += n;
  2374.             }
  2375.         }
  2376.         break;
  2377.  
  2378.         case T_NSAPPTR:
  2379.         n = expand_name(rname, type, cp, msg, eom, dname);
  2380.         if (n < 0)
  2381.             break;
  2382.         doprintf(("\t%s", pr_name(dname)))
  2383.         cp += n;
  2384.         break;
  2385.  
  2386.         case T_NSAP:
  2387.         if (dlen > 0)
  2388.         {
  2389.             doprintf(("\t%s", nsap_ntoa(cp, dlen)))
  2390.             cp += dlen;
  2391.         }
  2392.         break;
  2393.  
  2394.         default:
  2395.         doprintf(("\t???"))
  2396.         cp += dlen;
  2397.         break;
  2398.     }
  2399.  
  2400.     doprintf(("\n"))
  2401.  
  2402. /*
  2403.  * Check validity of the name of this resource record.
  2404.  * Currently only during zone listing and if requested.
  2405.  */
  2406.     if (listing && illegal && !valid_name(rname, TRUE))
  2407.     {
  2408.         pr_warning("illegal %s record name %s",
  2409.             pr_type(type), rname);
  2410.     }
  2411.  
  2412. /*
  2413.  * Save the CNAME alias for cname chain tracing.
  2414.  * Save the MR or MG alias for MB chain tracing.
  2415.  */
  2416.     if (!listmode && classmatch)
  2417.     {
  2418.         if ((type == T_CNAME) && n > 0 && cp == eor)
  2419.             cname = strcpy(cnamebuf, dname);
  2420.         else if ((type == T_MR || type == T_MG) && n > 0 && cp == eor)
  2421.             mname = strcpy(mnamebuf, dname);
  2422.     }
  2423.  
  2424. /*
  2425.  * Check whether we have reached the exact end of this record.
  2426.  */
  2427.     if (cp != eor)
  2428.     {
  2429.         pr_error("size error in %s record for %s, off by %s",
  2430.             pr_type(type), rname, itoa(cp - eor));
  2431.  
  2432.         /* we believe value of dlen; should perhaps return(NULL) */
  2433.         cp = eor;
  2434.     }
  2435.  
  2436.     return(cp);
  2437. }
  2438.  
  2439. /*
  2440. ** SKIP_QREC -- Skip the query record in the nameserver answer buffer
  2441. ** ------------------------------------------------------------------
  2442. **
  2443. **    Returns:
  2444. **        Pointer to position in answer buffer after current record.
  2445. **        NULL if there was a format error in the current record.
  2446. */
  2447.  
  2448. u_char *
  2449. skip_qrec(name, cp, msg, eom)
  2450. input char *name;            /* full name we are querying about */
  2451. register u_char *cp;            /* current position in answer buf */
  2452. input u_char *msg, *eom;        /* begin and end of answer buf */
  2453. {
  2454.     char rname[MAXDNAME+1];        /* record name in LHS */
  2455.     int type, class;        /* fixed values in query record */
  2456.     register int n;
  2457.  
  2458.     n = expand_name(name, T_NONE, cp, msg, eom, rname);
  2459.     if (n < 0)
  2460.         return(NULL);
  2461.     cp += n;
  2462.  
  2463.     n = 2*INT16SZ;
  2464.     if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
  2465.         return(NULL);
  2466.  
  2467.     type = _getshort(cp);
  2468.     cp += INT16SZ;
  2469.  
  2470.     class = _getshort(cp);
  2471.     cp += INT16SZ;
  2472.  
  2473. #ifdef lint
  2474.     if (verbose)
  2475.         printf("%-20s\t%s\t%s\n",
  2476.             rname, pr_class(class), pr_type(type));
  2477. #endif
  2478.     return(cp);
  2479. }
  2480.  
  2481. /*
  2482. ** GET_RECURSIVE -- Wrapper for get_hostinfo() during recursion
  2483. ** ------------------------------------------------------------
  2484. **
  2485. **    Returns:
  2486. **        TRUE if requested info was obtained successfully.
  2487. **        FALSE otherwise.
  2488. */
  2489.  
  2490. bool
  2491. get_recursive(name)
  2492. input char *name;            /* name to query about */
  2493. {
  2494.     static int level = 0;        /* recursion level */
  2495.     bool result;            /* result status of action taken */
  2496.     int save_errno;
  2497.     int save_herrno;
  2498.  
  2499.     if (level > 5)
  2500.     {
  2501.         errmsg("Recursion too deep");
  2502.         return(FALSE);
  2503.     }
  2504.  
  2505.     save_errno = errno;
  2506.     save_herrno = h_errno;
  2507.  
  2508.     level++;
  2509.     result = get_hostinfo(name);
  2510.     level--;
  2511.  
  2512.     errno = save_errno;
  2513.     h_errno = save_herrno;
  2514.  
  2515.     return(result);
  2516. }
  2517.  
  2518.  
  2519. /*
  2520.  * Nameserver information.
  2521.  * Stores names and addresses of all servers that are to be queried
  2522.  * for a zone transfer of the desired zone. Normally these are the
  2523.  * authoritative primary and/or secondary nameservers for the zone.
  2524.  */
  2525.  
  2526. #define MAXNSNAME 16        /* maximum count of nameservers per zone */
  2527. #define MAXIPADDR 10        /* maximum count of addresses per nameserver */
  2528.  
  2529. char nsname[MAXNSNAME][MAXDNAME+1];        /* nameserver hostname */
  2530. struct in_addr ipaddr[MAXNSNAME][MAXIPADDR];    /* nameserver addresses */
  2531. int naddrs[MAXNSNAME];                /* count of addresses */
  2532. int nservers = 0;                /* count of nameservers */
  2533.  
  2534. #ifdef notyet
  2535. typedef struct srvr_data {
  2536.     char nsname[MAXDNAME+1];        /* nameserver hostname */
  2537.     struct in_addr ipaddr[MAXIPADDR];    /* nameserver addresses */
  2538.     int naddrs;                /* count of addresses */
  2539. } srvr_data_t;
  2540.  
  2541. srvr_data_t nsinfo[MAXNSNAME];    /* nameserver info */
  2542. #endif
  2543.  
  2544. bool authserver;        /* server is supposed to be authoritative */
  2545.  
  2546. /*
  2547.  * Host information.
  2548.  * Stores names and (single) addresses encountered during the zone listing
  2549.  * of all A records that belong to the zone. Non-authoritative glue records
  2550.  * that do not belong to the zone are not stored. Glue records that belong
  2551.  * to a delegated zone will be filtered out later during the host count scan.
  2552.  * The host names are allocated dynamically.
  2553. #ifdef notyet
  2554.  * The host data should have been allocated dynamically to avoid static
  2555.  * limits, but this is less important since it is not saved across calls.
  2556. #endif
  2557.  */
  2558.  
  2559. #define MAXHOSTS 25000        /* maximum count of hostnames per zone */
  2560.  
  2561. char *hostname[MAXHOSTS];    /* hostname of host in zone */
  2562. ipaddr_t hostaddr[MAXHOSTS];    /* first host address */
  2563. bool multaddr[MAXHOSTS];    /* set if this is a multiple address host */
  2564. int hostcount = 0;        /* count of hosts in zone */
  2565.  
  2566. #ifdef notyet
  2567. typedef struct host_data {
  2568.     char *hostname;        /* hostname of host in zone */
  2569.     ipaddr_t hostaddr;    /* first host address */
  2570.     bool multaddr;        /* set if this is a multiple address host */
  2571. } host_data_t;
  2572.  
  2573. host_data_t hostlist[MAXHOSTS];    /* info on hosts in zone */
  2574. #endif
  2575.  
  2576. /*
  2577.  * Delegated zone information.
  2578.  * Stores the names of the delegated zones encountered during the zone
  2579.  * listing. The names and the list itself are allocated dynamically.
  2580.  */
  2581.  
  2582. char **zonename = NULL;        /* names of delegated zones within zone */
  2583. int zonecount = 0;        /* count of delegated zones within zone */
  2584.  
  2585. /*
  2586.  * Address information.
  2587.  * Stores the (single) addresses of hosts found in all zones traversed.
  2588.  * Used to search for duplicate hosts (same address but different name).
  2589.  * The list of addresses is allocated dynamically, and remains allocated.
  2590.  * This has now been implemented as a hashed list, using the low-order
  2591.  * address bits as the hash key.
  2592.  */
  2593.  
  2594. #ifdef obsolete
  2595. ipaddr_t *addrlist = NULL;    /* global list of addresses */
  2596. int addrcount = 0;        /* count of global addresses */
  2597. #endif
  2598.  
  2599. typedef struct addr_data {
  2600.     ipaddr_t *addrlist;    /* global list of addresses */
  2601.     int addrcount;        /* count of global addresses */
  2602. } addr_data_t;
  2603.  
  2604. #define AHASHSIZE    0x2000
  2605. #define AHASHMASK    0x1fff
  2606.  
  2607. addr_data_t hlist[AHASHSIZE];    /* hash list of global addresses */
  2608.  
  2609. /*
  2610.  * SOA record information.
  2611.  */
  2612.  
  2613. soa_data_t soa;            /* buffer to store soa data */
  2614.  
  2615. /*
  2616. ** LIST_ZONE -- Basic routine to do complete zone listing and checking
  2617. ** -------------------------------------------------------------------
  2618. **
  2619. **    Returns:
  2620. **        TRUE if the requested info was processed successfully.
  2621. **        FALSE otherwise.
  2622. */
  2623.  
  2624. int total_calls = 0;        /* number of calls for zone processing */
  2625. int total_check = 0;        /* number of zones successfully processed */
  2626. int total_tries = 0;        /* number of zone transfer attempts */
  2627. int total_zones = 0;        /* number of successful zone transfers */
  2628. int total_hosts = 0;        /* number of hosts in all traversed zones */
  2629. int total_dupls = 0;        /* number of duplicates in all zones */
  2630.  
  2631. #ifdef justfun
  2632. char longname[MAXDNAME+1];    /* longest hostname found */
  2633. int longsize = 0;        /* size of longest hostname */
  2634. #endif
  2635.  
  2636. int recursion_level = 0;    /* current recursion level */
  2637.  
  2638. bool
  2639. list_zone(name)
  2640. input char *name;            /* name of zone to process */
  2641. {
  2642.     register int n;
  2643.     register int i;
  2644.     int nzones;            /* count of delegated zones */
  2645.     int nhosts;            /* count of real hostnames */
  2646.     int ndupls;            /* count of duplicate hosts */
  2647.     int nextrs;            /* count of extrazone hosts */
  2648.     int ngates;            /* count of gateway hosts */
  2649.  
  2650.     total_calls += 1;        /* update zone processing calls */
  2651.  
  2652. /*
  2653.  * Normalize to not have trailing dot, unless it is the root zone.
  2654.  */
  2655.     n = strlength(name);
  2656.     if (n > 1 && name[n-1] == '.')
  2657.         name[n-1] = '\0';
  2658.  
  2659. /*
  2660.  * Indicate whether we are processing an "in-addr.arpa" reverse zone.
  2661.  * In this case we will suppress accumulating host count statistics.
  2662.  */
  2663.     reverse = indomain(name, "in-addr.arpa", FALSE);
  2664.  
  2665. /*
  2666.  * Find the nameservers for the given zone.
  2667.  */
  2668.     (void) find_servers(name);
  2669.     if (nservers < 1)
  2670.     {
  2671.         errmsg("No nameservers for %s found", name);
  2672.         return(FALSE);
  2673.     }
  2674.  
  2675. /*
  2676.  * Make sure we have an address for at least one nameserver.
  2677.  */
  2678.     for (n = 0; n < nservers; n++)
  2679.         if (naddrs[n] > 0)
  2680.             break;
  2681.  
  2682.     if (n >= nservers)
  2683.     {
  2684.         errmsg("No addresses of nameservers for %s found", name);
  2685.         return(FALSE);
  2686.     }
  2687.  
  2688. /*
  2689.  * Without an explicit server on the command line, the servers we
  2690.  * have looked up are supposed to be authoritative for the zone.
  2691.  */
  2692.     authserver = server ? FALSE : TRUE;
  2693.  
  2694. /*
  2695.  * Check SOA records at each of the nameservers.
  2696.  * Temporarily save our current server info from the resolver database.
  2697.  * Turn off nameserver recursion and make sure answer is authoritative.
  2698.  */
  2699.     if (checkmode)
  2700.     {
  2701.         res_state_t save_res;    /* saved copy of resolver database */
  2702.         char *save_server;    /* saved copy of server name */
  2703.  
  2704.         /* save resolver database */
  2705.         save_res = _res;
  2706.         save_server = server;
  2707.  
  2708.         /* turn off nameserver recursion */
  2709.         _res.options &= ~RES_RECURSE;
  2710.  
  2711.         for (n = 0; n < nservers; n++)
  2712.         {
  2713.             if (naddrs[n] < 1)
  2714.                 continue;    /* shortcut */
  2715.  
  2716.             server = nsname[n];
  2717.             for (i = 0; i < MAXNS && i < naddrs[n]; i++)
  2718.             {
  2719.                 nslist(i).sin_family = AF_INET;
  2720.                 nslist(i).sin_port = htons(NAMESERVER_PORT);
  2721.                 nslist(i).sin_addr = ipaddr[n][i];
  2722.             }
  2723.             _res.nscount = i;
  2724.  
  2725.             if (check_zone(name))
  2726.                 continue;
  2727.  
  2728.             /* SOA query failed */
  2729.             ns_error(name, T_SOA, queryclass);
  2730.  
  2731.             /* non-authoritative denial: assume lame delegation */
  2732.             if (h_errno == NO_RREC || h_errno == NO_HOST)
  2733.             {
  2734.                 if (authserver)
  2735.                     errmsg("%s has lame delegation to %s",
  2736.                         name, server);
  2737.                 continue;
  2738.             }
  2739.  
  2740.             /* authoritative denial: probably misconfiguration */
  2741.             if (h_errno == NO_DATA || h_errno == HOST_NOT_FOUND)
  2742.             {
  2743.                 if (authserver)
  2744.                     errmsg("%s has lame delegation to %s",
  2745.                         name, server);
  2746.                 continue;
  2747.             }
  2748.         }
  2749.  
  2750.         /* restore resolver database */
  2751.         _res = save_res;
  2752.         server = save_server;
  2753.  
  2754.         total_check += 1;    /* update zones processed */
  2755.  
  2756.         /* all done if maximum recursion level reached */
  2757.         if (!recursive || (recursion_level >= recursive))
  2758.             return(Errors == 0 ? TRUE : FALSE);
  2759.     }
  2760.  
  2761. /*
  2762.  * Ask zone transfer to the nameservers, until one responds.
  2763.  * If we have queried an authoritative server, it should respond positively.
  2764.  * If it responds with an error, we may have a lame delegation.
  2765.  * Always continue with the next server to avoid missing entire zones.
  2766.  */
  2767.     total_tries += 1;        /* update zone transfer attempts */
  2768.  
  2769.     for (n = 0; n < nservers; n++)
  2770.     {
  2771.         for (i = 0; i < naddrs[n]; i++)
  2772.         {
  2773.         if (verbose)
  2774.             printf("Trying server %s (%s) ...\n",
  2775.                 inet_ntoa(ipaddr[n][i]), nsname[n]);
  2776.  
  2777.         if (transfer_zone(name, queryclass, ipaddr[n][i], nsname[n]))
  2778.             goto done;    /* double break */
  2779.  
  2780.         /* zone transfer failed */
  2781.         if (h_errno != TRY_AGAIN)
  2782.             ns_error(name, T_AXFR, queryclass);
  2783.  
  2784.         /* non-authoritative denial: assume lame delegation */
  2785.         if (h_errno == NO_RREC || h_errno == NO_HOST)
  2786.         {
  2787.             if (authserver)
  2788.                 errmsg("%s has lame delegation to %s",
  2789.                     name, nsname[n]);
  2790.             break;
  2791.         }
  2792.  
  2793.         /* authoritative denial: probably misconfiguration */
  2794.         if (h_errno == NO_DATA || h_errno == HOST_NOT_FOUND)
  2795.         {
  2796.             if (authserver)
  2797.                 errmsg("%s has lame delegation to %s",
  2798.                     name, nsname[n]);
  2799.             break;
  2800.         }
  2801.  
  2802.         /* terminate on irrecoverable errors */
  2803.         if (h_errno != TRY_AGAIN)
  2804.             return(FALSE);
  2805.  
  2806.         /* in case nameserver not present */
  2807.         if (errno == ECONNREFUSED)
  2808.             break;
  2809.         }
  2810.     }
  2811. done:
  2812.     if (n >= nservers)
  2813.     {
  2814.         if (h_errno == TRY_AGAIN)
  2815.             ns_error(name, T_AXFR, queryclass);
  2816.         errmsg("No nameservers for %s responded", name);
  2817.         return(FALSE);
  2818.     }
  2819.  
  2820.     total_zones += 1;        /* update successful zone transfers */
  2821.  
  2822. /*
  2823.  * Print resource record statistics if so requested.
  2824.  */
  2825.     if (statistics)
  2826.         print_statistics(name, querytype, queryclass);
  2827.  
  2828. /*
  2829.  * Accumulate host count statistics for this zone.
  2830.  */
  2831.     nzones = zonecount;
  2832.  
  2833.     nhosts = 0, ndupls = 0, nextrs = 0, ngates = 0;
  2834.  
  2835.     i = (verbose || statistics || hostmode) ? 0 : hostcount;
  2836.  
  2837.     for (n = i; n < hostcount; n++)
  2838.     {
  2839.         struct in_addr inaddr;
  2840.  
  2841.         /* skip fake hosts using a very rudimentary test */
  2842.         if (fakename(hostname[n]) || fakeaddr(hostaddr[n]))
  2843.             continue;
  2844. #ifdef justfun
  2845.         /* save longest hostname encountered so far */
  2846.         if (verbose && ((i = strlength(hostname[n])) > longsize))
  2847.         {
  2848.             longsize = i;
  2849.             (void) strcpy(longname, hostname[n]);
  2850.         }
  2851. #endif
  2852.         /* skip apparent glue records */
  2853.         if (gluerecord(hostname[n], name, zonename, nzones))
  2854.         {
  2855.             if (verbose > 1)
  2856.                 printf("%s is glue record\n", hostname[n]);
  2857.             continue;
  2858.         }
  2859.  
  2860.         /* otherwise count as host */
  2861.         nhosts++;
  2862.         inaddr.s_addr = hostaddr[n];
  2863.  
  2864.     /*
  2865.      * Mark hosts not residing directly in the zone as extrazone host.
  2866.      */
  2867.         if (!samedomain(hostname[n], name, TRUE))
  2868.         {
  2869.             nextrs++;
  2870.             if (extrmode || (verbose > 1))
  2871.                 printf("%s is extrazone host\n", hostname[n]);
  2872.         }
  2873.  
  2874.     /*
  2875.      * Mark hosts with more than one address as gateway host.
  2876.      * These are not checked for duplicate addresses.
  2877.      */
  2878.         if (multaddr[n])
  2879.         {
  2880.             ngates++;
  2881.             if (gatemode || (verbose > 1))
  2882.                 printf("%s is gateway host\n", hostname[n]);
  2883.             continue;
  2884.         }
  2885.         
  2886.     /*
  2887.      * Compare single address hosts against global list of addresses.
  2888.      * Multiple address hosts are too complicated to handle this way.
  2889.      */
  2890.         if (check_dupl(hostaddr[n]))
  2891.         {
  2892.             ndupls++;
  2893.             if (duplmode || (verbose > 1))
  2894.                 printf("%s is duplicate host with address %s\n",
  2895.                     hostname[n], inet_ntoa(inaddr));
  2896.         }
  2897.     }
  2898.  
  2899. /*
  2900.  * Print statistics for this zone.
  2901.  */
  2902.     if (verbose || statistics || hostmode)
  2903.     {
  2904.         printf("Found %d host%s within %s\n",
  2905.             nhosts, nhosts == 1 ? "" : "s", name);
  2906.  
  2907.         if ((ndupls > 0) || duplmode || (verbose > 1))
  2908.         printf("Found %d duplicate host%s within %s\n",
  2909.             ndupls, ndupls == 1 ? "" : "s", name);
  2910.  
  2911.         if ((nextrs > 0) || extrmode || (verbose > 1))
  2912.         printf("Found %d extrazone host%s within %s\n",
  2913.             nextrs, nextrs == 1 ? "" : "s", name);
  2914.  
  2915.         if ((ngates > 0) || gatemode || (verbose > 1))
  2916.         printf("Found %d gateway host%s within %s\n",
  2917.             ngates, ngates == 1 ? "" : "s", name);
  2918.     }
  2919.  
  2920.     total_hosts += nhosts;        /* update total number of hosts */
  2921.     total_dupls += ndupls;        /* update total number of duplicates */
  2922.  
  2923.     if (!checkmode)
  2924.         total_check += 1;    /* update zones processed */
  2925.  
  2926.     if (verbose || statistics)
  2927.         printf("Found %d delegated zone%s within %s\n",
  2928.             nzones, nzones == 1 ? "" : "s", name);
  2929.  
  2930. /*
  2931.  * The names of the hosts were allocated dynamically.
  2932.  */
  2933.     for (n = 0; n < hostcount; n++)
  2934.         xfree(hostname[n]);
  2935.  
  2936. /*
  2937.  * Check for mailable delegated zones within this zone.
  2938.  * This is based on ordinary MX lookup, and not on the MX info
  2939.  * which may be present in the zone listing, to reduce zone transfers.
  2940.  */
  2941.     if (mxrecmode)
  2942.     {
  2943.         if (recursion_level == 0)
  2944.         {
  2945.             if (verbose)
  2946.                 printf("\n");
  2947.  
  2948.             if (!get_mxrec(name))
  2949.                 ns_error(name, T_MX, queryclass);
  2950.         }
  2951.  
  2952.         for (n = 0; n < nzones; n++)
  2953.         {
  2954.             if (verbose)
  2955.                 printf("\n");
  2956.  
  2957.             if (!get_mxrec(zonename[n]))
  2958.                 ns_error(zonename[n], T_MX, queryclass);
  2959.         }
  2960.     }
  2961.  
  2962. /*
  2963.  * Do recursion on delegated zones if requested and any were found.
  2964.  * Temporarily save zonename list, and force allocation of new list.
  2965.  */
  2966.     if (recursive && (recursion_level < recursive))
  2967.     {
  2968.         for (n = 0; n < nzones; n++)
  2969.         {
  2970.             char **newzone;        /* local copy of list */
  2971.  
  2972.             newzone = zonename;
  2973.             zonename = NULL;    /* allocate new list */
  2974.  
  2975.             if (verbose || statistics || checkmode || hostmode)
  2976.                 printf("\n");
  2977.  
  2978.             if (verbose)
  2979.                 printf("Entering zone %s\n", newzone[n]);
  2980.  
  2981.             recursion_level++;
  2982.             (void) list_zone(newzone[n]);
  2983.             recursion_level--;
  2984.  
  2985.             zonename = newzone;    /* restore */
  2986.         }
  2987.     }
  2988.  
  2989. /*
  2990.  * The names of the delegated zones were allocated dynamically.
  2991.  * The list of delegated zone names was also allocated dynamically.
  2992.  */
  2993.     for (n = 0; n < nzones; n++)
  2994.         xfree(zonename[n]);
  2995.  
  2996.     if (zonename != NULL)
  2997.         xfree(zonename);
  2998.  
  2999.     zonename = NULL;
  3000.  
  3001. /*
  3002.  * Print final overall statistics.
  3003.  */
  3004.     if (recursive && (recursion_level == 0))
  3005.     {
  3006.         if (verbose || statistics || checkmode || hostmode)
  3007.             printf("\n");
  3008.  
  3009.         if (verbose || statistics || hostmode)
  3010.             printf("Encountered %d host%s in %d zone%s within %s\n",
  3011.                 total_hosts, total_hosts == 1 ? "" : "s",
  3012.                 total_zones, total_zones == 1 ? "" : "s",
  3013.                 name);
  3014.  
  3015.         if (verbose || statistics || hostmode)
  3016.             printf("Encountered %d duplicate host%s in %d zone%s within %s\n",
  3017.                 total_dupls, total_dupls == 1 ? "" : "s",
  3018.                 total_zones, total_zones == 1 ? "" : "s",
  3019.                 name);
  3020.  
  3021.         if (verbose || statistics || checkmode)
  3022.             printf("Transferred %d zone%s out of %d attempt%s\n",
  3023.                 total_zones, total_zones == 1 ? "" : "s",
  3024.                 total_tries, total_tries == 1 ? "" : "s");
  3025.  
  3026.         if (verbose || statistics || checkmode)
  3027.             printf("Processed %d zone%s out of %d request%s\n",
  3028.                 total_check, total_check == 1 ? "" : "s",
  3029.                 total_calls, total_calls == 1 ? "" : "s");
  3030. #ifdef justfun
  3031.         if (verbose && (longsize > 0))
  3032.             printf("Longest hostname %s\t%d\n",
  3033.                 longname, longsize);
  3034. #endif
  3035.     }
  3036.  
  3037.     /* indicate whether any errors were encountered */
  3038.     return(Errors == 0 ? TRUE : FALSE);
  3039. }
  3040.  
  3041. /*
  3042. ** FIND_SERVERS -- Fetch names and addresses of authoritative servers
  3043. ** ------------------------------------------------------------------
  3044. **
  3045. **    Returns:
  3046. **        TRUE if servers could be determined successfully.
  3047. **        FALSE otherwise.
  3048. **
  3049. **    Inputs:
  3050. **        The global variable ``server'', if set, contains the
  3051. **        name of the explicit server to be contacted.
  3052. **        The global variable ``primary'', if set, indicates
  3053. **        that we must use the primary nameserver for the zone.
  3054. **        If both are set simultaneously, the explicit server
  3055. **        is contacted to retrieve the desired servers.
  3056. **
  3057. **    Outputs:
  3058. **        Names are stored in the nsname[] database.
  3059. **        Addresses are stored in the ipaddr[] database.
  3060. **        Address counts are stored in the naddrs[] database.
  3061. **        The count of nameservers is stored in ``nservers''.
  3062. */
  3063.  
  3064. bool
  3065. find_servers(name)
  3066. input char *name;            /* name of zone to find servers for */
  3067. {
  3068.     struct hostent *hp;
  3069.     register int n;
  3070.     register int i;
  3071.  
  3072. /*
  3073.  * Use the explicit server if given on the command line.
  3074.  * Its addresses are stored in the resolver state struct.
  3075.  * This server may not be authoritative for the given zone.
  3076.  */
  3077.     if (server && !primary)
  3078.     {
  3079.         (void) strcpy(nsname[0], server);
  3080.         for (i = 0; i < MAXIPADDR && i < _res.nscount; i++)
  3081.             ipaddr[0][i] = nslist(i).sin_addr;
  3082.         naddrs[0] = i;
  3083.  
  3084.         nservers = 1;
  3085.         return(TRUE);
  3086.     }
  3087.  
  3088. /*
  3089.  * Fetch primary nameserver info if so requested.
  3090.  * Get its name from the SOA record for the zone, and do a regular
  3091.  * host lookup to fetch its addresses. We are assuming here that the
  3092.  * SOA record is a proper one. This is not necessarily true.
  3093.  * Obviously this server should be authoritative.
  3094.  */
  3095.     if (primary && !server)
  3096.     {
  3097.         char *primaryname;
  3098.  
  3099.         primaryname = get_primary(name);
  3100.         if (primaryname == NULL)
  3101.         {
  3102.             ns_error(name, T_SOA, queryclass);
  3103.             nservers = 0;
  3104.             return(FALSE);
  3105.         }
  3106.  
  3107.         hp = gethostbyname(primaryname);
  3108.         if (hp == NULL)
  3109.         {
  3110.             ns_error(primaryname, T_A, C_IN);
  3111.             nservers = 0;
  3112.             return(FALSE);
  3113.         }
  3114.  
  3115.         (void) strcpy(nsname[0], hp->h_name);
  3116.         for (i = 0; i < MAXIPADDR && hp->h_addr_list[i]; i++)
  3117.             ipaddr[0][i] = incopy(hp->h_addr_list[i]);
  3118.         naddrs[0] = i;
  3119.  
  3120.         if (verbose)
  3121.             printf("Found %d address%s for %s\n",
  3122.                 naddrs[0], naddrs[0] == 1 ? "  " : "es",
  3123.                 nsname[0]);
  3124.  
  3125.         nservers = 1;
  3126.         return(TRUE);
  3127.     }
  3128.  
  3129. /*
  3130.  * Otherwise we have to find the nameservers for the zone.
  3131.  * These are supposed to be authoritative, but sometimes we
  3132.  * encounter lame delegations, perhaps due to misconfiguration.
  3133.  */
  3134.     if (!get_servers(name))
  3135.     {
  3136.         ns_error(name, T_NS, queryclass);
  3137.         nservers = 0;
  3138.         return(FALSE);
  3139.     }
  3140.  
  3141. /*
  3142.  * Usually we'll get addresses for all the servers in the additional
  3143.  * info section.  But in case we don't, look up their addresses.
  3144.  * If we get no addresses by extra query, and this is authoritative,
  3145.  * we flag a lame delegation to that server.
  3146.  */
  3147.     for (n = 0; n < nservers; n++)
  3148.     {
  3149.         if (naddrs[n] == 0)
  3150.         {
  3151.         hp = gethostbyname(nsname[n]);
  3152.         if (hp != NULL)
  3153.         {
  3154.             for (i = 0; i < MAXIPADDR && hp->h_addr_list[i]; i++)
  3155.                 ipaddr[n][i] = incopy(hp->h_addr_list[i]);
  3156.             naddrs[n] = i;
  3157.         }
  3158.  
  3159.         if (verbose)
  3160.             printf("Found %d address%s for %s by extra query\n",
  3161.                 naddrs[n], naddrs[n] == 1 ? "  " : "es",
  3162.                 nsname[n]);
  3163.  
  3164.         if (hp == NULL)
  3165.         {
  3166.             /* server name lookup failed */
  3167.             ns_error(nsname[n], T_A, C_IN);
  3168.  
  3169.             /* authoritative denial: probably misconfiguration */
  3170.             if (h_errno == NO_DATA || h_errno == HOST_NOT_FOUND)
  3171.             {
  3172.                 errmsg("%s has lame delegation to %s",
  3173.                     name, nsname[n]);
  3174.             }
  3175.         }
  3176.         }
  3177.         else
  3178.         {
  3179.         if (verbose)
  3180.             printf("Found %d address%s for %s\n",
  3181.                 naddrs[n], naddrs[n] == 1 ? "  " : "es",
  3182.                 nsname[n]);
  3183.         }
  3184.     }
  3185.  
  3186. /*
  3187.  * Issue warning if only one server has been discovered.
  3188.  * This is not an error per se, but not much redundancy in that case.
  3189.  */
  3190.     if (nservers == 1)
  3191.         pr_warning("only one nameserver for %s found", name);
  3192.  
  3193.     return(nservers > 0);
  3194. }
  3195.  
  3196. /*
  3197. ** GET_SERVERS -- Fetch names and addresses of authoritative servers
  3198. ** -----------------------------------------------------------------
  3199. **
  3200. **    Returns:
  3201. **        TRUE if servers could be determined successfully.
  3202. **        FALSE otherwise.
  3203. **
  3204. **    Side effects:
  3205. **        Names are stored in the nsname[] database.
  3206. **        Addresses are stored in the ipaddr[] database.
  3207. **        Address counts are stored in the naddrs[] database.
  3208. **        The count of nameservers is stored in ``nservers''.
  3209. */
  3210.  
  3211. bool
  3212. get_servers(name)
  3213. input char *name;            /* name of zone to find servers for */
  3214. {
  3215.     querybuf answer;
  3216.     int anslen;
  3217.     bool result;            /* result status of action taken */
  3218.  
  3219.     if (verbose)
  3220.         printf("Finding nameservers for %s ...\n", name);
  3221.  
  3222.     anslen = get_info(&answer, name, T_NS, queryclass);
  3223.     if (anslen < 0)
  3224.         return(FALSE);
  3225.  
  3226.     if (verbose > 1)
  3227.         (void) print_info(&answer, anslen, name, FALSE);
  3228.  
  3229.     result = get_nsinfo(&answer, anslen, name);
  3230.     return(result);
  3231. }
  3232.  
  3233. /*
  3234. ** GET_NSINFO -- Extract nameserver data from nameserver answer buffer
  3235. ** -------------------------------------------------------------------
  3236. **
  3237. **    Returns:
  3238. **        TRUE if servers could be determined successfully.
  3239. **        FALSE otherwise.
  3240. **
  3241. **    Outputs:
  3242. **        Names are stored in the nsname[] database.
  3243. **        Addresses are stored in the ipaddr[] database.
  3244. **        Address counts are stored in the naddrs[] database.
  3245. **        The count of nameservers is stored in ``nservers''.
  3246. */
  3247.  
  3248. bool
  3249. get_nsinfo(answerbuf, answerlen, name)
  3250. input querybuf *answerbuf;        /* address of answer buffer */
  3251. input int answerlen;            /* length of answer buffer */
  3252. input char *name;            /* name of zone to find servers for */
  3253. {
  3254.     HEADER *bp;
  3255.     int qdcount, ancount, nscount, arcount;
  3256.     int rrcount;
  3257.     u_char *msg, *eom;
  3258.     register u_char *cp;
  3259.     register int i;
  3260.  
  3261.     nservers = 0;            /* count of nameservers */
  3262.  
  3263.     bp = (HEADER *)answerbuf;
  3264.     qdcount = ntohs(bp->qdcount);
  3265.     ancount = ntohs(bp->ancount);
  3266.     nscount = ntohs(bp->nscount);
  3267.     arcount = ntohs(bp->arcount);
  3268.  
  3269.     msg = (u_char *)answerbuf;
  3270.     eom = (u_char *)answerbuf + answerlen;
  3271.     cp  = (u_char *)answerbuf + HFIXEDSZ;
  3272.  
  3273.     while (qdcount > 0 && cp < eom)
  3274.     {
  3275.         cp = skip_qrec(name, cp, msg, eom);
  3276.         if (cp == NULL)
  3277.             return(FALSE);
  3278.         qdcount--;
  3279.     }
  3280.  
  3281.     if (qdcount)
  3282.     {
  3283.         pr_error("invalid qdcount in response");
  3284.         h_errno = NO_RECOVERY;
  3285.         return(FALSE);
  3286.     }
  3287.  
  3288. /*
  3289.  * If the answer is authoritative, the names are found in the
  3290.  * answer section, and the nameserver section is empty.
  3291.  * If not, there may be duplicate names in both sections.
  3292.  * Addresses are found in the additional info section both cases.
  3293.  */
  3294.     rrcount = ancount + nscount + arcount;
  3295.     while (rrcount > 0 && cp < eom)
  3296.     {
  3297.         char rname[MAXDNAME+1];
  3298.         char dname[MAXDNAME+1];
  3299.         int type, class, ttl, dlen;
  3300.         u_char *eor;
  3301.         register int n;
  3302.         struct in_addr inaddr;
  3303.  
  3304.         n = expand_name(name, T_NONE, cp, msg, eom, rname);
  3305.         if (n < 0)
  3306.             return(FALSE);
  3307.         cp += n;
  3308.  
  3309.         n = 3*INT16SZ + INT32SZ;
  3310.         if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
  3311.             return(FALSE);
  3312.  
  3313.         type = _getshort(cp);
  3314.         cp += INT16SZ;
  3315.  
  3316.         class = _getshort(cp);
  3317.         cp += INT16SZ;
  3318.  
  3319.         ttl = _getlong(cp);
  3320.         cp += INT32SZ;
  3321.  
  3322.         dlen = _getshort(cp);
  3323.         cp += INT16SZ;
  3324.  
  3325.         eor = cp + dlen;
  3326. #ifdef lint
  3327.         if (verbose)
  3328.             printf("%-20s\t%d\t%s\t%s\n",
  3329.                 rname, ttl, pr_class(class), pr_type(type));
  3330. #endif
  3331.         if ((type == T_NS) && sameword(rname, name))
  3332.         {
  3333.             n = expand_name(rname, type, cp, msg, eom, dname);
  3334.             if (n < 0)
  3335.                 return(FALSE);
  3336.             cp += n;
  3337.  
  3338.             for (i = 0; i < nservers; i++)
  3339.                 if (sameword(nsname[i], dname))
  3340.                     break;    /* duplicate */
  3341.  
  3342.             if (i >= nservers && nservers < MAXNSNAME)
  3343.             {
  3344.                 (void) strcpy(nsname[nservers], dname);
  3345.                 naddrs[nservers] = 0;
  3346.                 nservers++;
  3347.             }
  3348.         }
  3349.         else if ((type == T_A) && dlen == INADDRSZ)
  3350.         {
  3351.             for (i = 0; i < nservers; i++)
  3352.                 if (sameword(nsname[i], rname))
  3353.                     break;    /* found */
  3354.  
  3355.             if (i < nservers && naddrs[i] < MAXIPADDR)
  3356.             {
  3357.                 bcopy((char *)cp, (char *)&inaddr, INADDRSZ);
  3358.                 ipaddr[i][naddrs[i]] = inaddr;
  3359.                 naddrs[i]++;
  3360.             }
  3361.  
  3362.             cp += dlen;
  3363.         }
  3364.         else
  3365.             cp += dlen;
  3366.  
  3367.         if (cp != eor)
  3368.         {
  3369.             pr_error("size error in %s record for %s, off by = %s",
  3370.                 pr_type(type), rname, itoa(cp - eor));
  3371.             return(FALSE);
  3372.         }
  3373.  
  3374.         rrcount--;
  3375.     }
  3376.  
  3377.     if (rrcount)
  3378.     {
  3379.         pr_error("invalid rrcount in response");
  3380.         h_errno = NO_RECOVERY;
  3381.         return(FALSE);
  3382.     }
  3383.  
  3384.     return(TRUE);
  3385. }
  3386.  
  3387. /*
  3388. ** TRANSFER_ZONE -- Wrapper for get_zone() to hide administrative tasks
  3389. ** --------------------------------------------------------------------
  3390. **
  3391. **    Returns:
  3392. **        See get_zone() for details.
  3393. **
  3394. **    Side effects:
  3395. **        See get_zone() for details.
  3396. **
  3397. **    This routine may be called repeatedly with different server
  3398. **    addresses, until one of the servers responds. Various items
  3399. **    must be reset on every try to continue with a clean slate.
  3400. */
  3401.  
  3402. bool
  3403. transfer_zone(name, class, inaddr, host)
  3404. input char *name;            /* name of zone to do zone xfer for */
  3405. input int class;            /* specific resource record class */
  3406. input struct in_addr inaddr;        /* address of server to be queried */
  3407. input char *host;            /* name of server to be queried */
  3408. {
  3409.     register int n;
  3410.  
  3411. /*
  3412.  * Reset the resource record statistics before each try.
  3413.  */
  3414.     clear_statistics();
  3415.  
  3416. /*
  3417.  * Perform the actual zone transfer.
  3418.  */
  3419.     if (get_zone(name, class, inaddr, host))
  3420.         return(TRUE);
  3421.  
  3422. /*
  3423.  * Failure to get the zone. Free any memory that may have been allocated.
  3424.  * On success it is the responsibility of the caller to free the memory.
  3425.  */
  3426.     for (n = 0; n < hostcount; n++)
  3427.         xfree(hostname[n]);
  3428.  
  3429.     for (n = 0; n < zonecount; n++)
  3430.         xfree(zonename[n]);
  3431.  
  3432.     if (zonename != NULL)
  3433.         xfree(zonename);
  3434.  
  3435.     zonename = NULL;
  3436.  
  3437.     return(FALSE);
  3438. }
  3439.  
  3440. /*
  3441. ** GET_ZONE -- Perform a zone transfer from server at specific address
  3442. ** -------------------------------------------------------------------
  3443. **
  3444. **    Returns:
  3445. **        TRUE if the zone data have been retrieved successfully.
  3446. **        FALSE if an error occurred (h_errno is set appropriately).
  3447. **        Set TRY_AGAIN wherever possible to try the next server.
  3448. **
  3449. **    Side effects:
  3450. **        Stores list of delegated zones found in zonename[],
  3451. **        and the count of delegated zones in ``zonecount''.
  3452. **        Stores list of hostnames  found in hostname[],
  3453. **        and the count of hostnames in ``hostcount''.
  3454. **        Updates resource record statistics in record_stats[].
  3455. **        This array must have been cleared before.
  3456. */
  3457.  
  3458. bool
  3459. get_zone(name, class, inaddr, host)
  3460. input char *name;            /* name of zone to do zone xfer for */
  3461. input int class;            /* specific resource record class */
  3462. input struct in_addr inaddr;        /* address of server to be queried */
  3463. input char *host;            /* name of server to be queried */
  3464. {
  3465.     querybuf query;
  3466.     querybuf answer;
  3467.     HEADER *bp;
  3468.     int ancount;
  3469.     int sock;
  3470.     struct sockaddr_in sin;
  3471.     register int n;
  3472.     register int i;
  3473.     int nrecords = 0;        /* number of records processed */
  3474.     int soacount = 0;        /* count of SOA records */
  3475.  
  3476.     zonecount = 0;            /* count of delegated zones */
  3477.     hostcount = 0;            /* count of hostnames */
  3478.  
  3479. /*
  3480.  * Construct query, and connect to the given server.
  3481.  */
  3482.     errno = 0;
  3483.  
  3484.     n = res_mkquery(QUERY, name, class, T_AXFR, (char *)NULL, 0,
  3485.             (rrec_data_t *)NULL, (char *)&query, sizeof(querybuf));
  3486.     if (n < 0)
  3487.     {
  3488.         if (debug)
  3489.             (void) fprintf(stderr, "res_mkquery failed\n");
  3490.         h_errno = NO_RECOVERY;
  3491.         return(FALSE);
  3492.     }
  3493.  
  3494.     if (debug)
  3495.     {
  3496.         printf("get_zone()\n");
  3497.         fp_query((char *)&query, stdout);
  3498.     }
  3499.  
  3500.     sin.sin_family = AF_INET;
  3501.     sin.sin_port = htons(NAMESERVER_PORT);
  3502.     sin.sin_addr = inaddr;
  3503.     _res_setaddr(&sin, host);
  3504.  
  3505.     sock = socket(AF_INET, SOCK_STREAM, 0);
  3506.     if (sock < 0)
  3507.     {
  3508.         _res_perror("socket");
  3509.         h_errno = TRY_AGAIN;
  3510.         return(FALSE);
  3511.     }
  3512.  
  3513.     if (_res_connect(sock, &sin, sizeof(sin)) < 0)
  3514.     {
  3515.         if (debug || verbose)
  3516.             _res_perror("connect");
  3517.         (void) close(sock);
  3518.         h_errno = TRY_AGAIN;
  3519.         return(FALSE);
  3520.     }
  3521.  
  3522.     if (verbose)
  3523.         printf("Asking zone transfer for %s ...\n", name);
  3524.  
  3525. /*
  3526.  * Send the query buffer.
  3527.  */
  3528.     if (_res_write(sock, (char *)&query, n) < 0)
  3529.     {
  3530.         (void) close(sock);
  3531.         h_errno = TRY_AGAIN;
  3532.         return(FALSE);
  3533.     }
  3534.  
  3535. /*
  3536.  * Process all incoming records, each record in a separate packet.
  3537.  */
  3538.     while ((n = _res_read(sock, (char *)&answer, sizeof(querybuf))) != 0)
  3539.     {
  3540.         if (n < 0)
  3541.         {
  3542.             (void) close(sock);
  3543.             h_errno = TRY_AGAIN;
  3544.             return(FALSE);
  3545.         }
  3546.  
  3547.         if (n < HFIXEDSZ)
  3548.         {
  3549.             pr_error("answer length %s too short", itoa(n));
  3550.             (void) close(sock);
  3551.             h_errno = TRY_AGAIN;
  3552.             return(FALSE);
  3553.         }
  3554.  
  3555.         if (debug > 1)
  3556.         {
  3557.             printf("got answer, %d bytes:\n", n);
  3558.             fp_query((char *)&answer, stdout);
  3559.         }
  3560.  
  3561.     /*
  3562.      * Analyze the contents of the answer and check for errors.
  3563.      * An error can be expected only in the very first packet.
  3564.      */
  3565.         bp = (HEADER *)&answer;
  3566.         ancount = ntohs(bp->ancount);
  3567.  
  3568.         if (bp->rcode != NOERROR || ancount == 0)
  3569.         {
  3570.             if (verbose)
  3571.                 print_status(&answer);
  3572.  
  3573.             switch (bp->rcode)
  3574.             {
  3575.                 case NXDOMAIN:
  3576.                 /* distinguish between authoritative or not */
  3577.                 h_errno = bp->aa ? HOST_NOT_FOUND : NO_HOST;
  3578.                 break;
  3579.  
  3580.                 case NOERROR:
  3581.                 /* distinguish between authoritative or not */
  3582.                 h_errno = bp->aa ? NO_DATA : NO_RREC;
  3583.                 break;
  3584.  
  3585.                 default:
  3586.                 h_errno = TRY_AGAIN;
  3587.                 break;
  3588.             }
  3589.  
  3590.             if (nrecords != 0)
  3591.                 pr_error("unexpected error in answer");
  3592.  
  3593.             (void) close(sock);
  3594.             return(FALSE);
  3595.         }
  3596.  
  3597.         h_errno = 0;
  3598.  
  3599.         i = ntohs(bp->nscount);
  3600.         if (i != 0)
  3601.             pr_error("nonzero nscount in answer");
  3602.  
  3603.         i = ntohs(bp->arcount);
  3604.         if (i != 0)
  3605.             pr_error("nonzero arcount in answer");
  3606.  
  3607.     /*
  3608.      * Valid packet received. Print contents if appropriate.
  3609.      */
  3610.         nrecords++;
  3611.         soaname = NULL;
  3612.         subname = NULL;
  3613.         adrname = NULL;
  3614.  
  3615.         (void) print_info(&answer, n, name, TRUE);
  3616.  
  3617.     /*
  3618.      * Terminate upon the second SOA record for this zone.
  3619.      */
  3620.         if (soaname && sameword(soaname, name))
  3621.             if (soacount++)
  3622.                 break;
  3623.  
  3624.         /* the nameserver balks on this one */
  3625.         if (soaname && !sameword(soaname, name))
  3626.             pr_warning("extraneous SOA record for %s within %s",
  3627.                 soaname, name);
  3628.  
  3629.     /*
  3630.      * Save encountered delegated zone name for recursive listing.
  3631.      */
  3632.         if (subname && indomain(subname, name, FALSE))
  3633.         {
  3634.             for (i = 0; i < zonecount; i++)
  3635.                 if (sameword(zonename[i], subname))
  3636.                     break;    /* duplicate */
  3637.  
  3638.             if (i >= zonecount)
  3639.             {
  3640.                 zonename = newlist(zonename, zonecount+1, char *);
  3641.                 zonename[zonecount] = newstr(subname);
  3642.                 zonecount++;
  3643.             }
  3644.         }
  3645. #ifdef obsolete
  3646.         /* not sure whether this is illegal or not (no, it's not) */
  3647.         if (subname && !samedomain(subname, name, TRUE))
  3648.             pr_warning("extraneous NS record for %s within %s",
  3649.                 subname, name);
  3650. #endif
  3651.         /* warn about strange delegated zones */
  3652.         if (subname && !indomain(subname, name, TRUE))
  3653.             pr_warning("extraneous NS record for %s within %s",
  3654.                 subname, name);
  3655.  
  3656.     /*
  3657.      * Save encountered name of A record for hostname count.
  3658.      */
  3659.         if (adrname && indomain(adrname, name, FALSE) && !reverse)
  3660.         {
  3661.             for (i = 0; i < hostcount; i++)
  3662.                 if (sameword(hostname[i], adrname))
  3663.                     break;    /* duplicate */
  3664.  
  3665.             if (i < hostcount && address != hostaddr[i])
  3666.                 multaddr[i] = TRUE;
  3667.  
  3668.             if (i >= hostcount && hostcount < MAXHOSTS)
  3669.             {
  3670.                 hostname[hostcount] = newstr(adrname);
  3671.                 hostaddr[hostcount] = address;
  3672.                 multaddr[hostcount] = FALSE;
  3673.                 hostcount++;
  3674.  
  3675.                 if (hostcount == MAXHOSTS)
  3676.                     pr_error("maximum number of %s hostnames reached", itoa(hostcount));
  3677.             }
  3678.         }
  3679.  
  3680.         /* check for unauthoritative glue records */
  3681.         if (adrname && !indomain(adrname, name, TRUE))
  3682.             pr_warning("extraneous glue record for %s within %s",
  3683.                 adrname, name);
  3684.     }
  3685.  
  3686. /*
  3687.  * End of zone transfer at second SOA record or zero length read.
  3688.  */
  3689.     (void) close(sock);
  3690.  
  3691. /*
  3692.  * Check for the anomaly that the whole transfer consisted of the
  3693.  * SOA records only. Could occur if we queried the victim of a lame
  3694.  * delegation which happened to have the SOA record present.
  3695.  */
  3696.     if (nrecords <= soacount)
  3697.     {
  3698.         pr_error("empty transfer for %s from %s", name, host);
  3699.         h_errno = NO_RREC;
  3700.         return(FALSE);
  3701.     }
  3702.  
  3703. /*
  3704.  * Do extra check for hostnames also defined as delegated zones.
  3705.  * They may have been defined in the child zone, and crept in
  3706.  * the parent zone, or may have been defined as glue records.
  3707.  * This is not necessarily an error, but the hostname count may
  3708.  * be actually wrong. Leave it in for the time being.
  3709.  */
  3710.     for (n = 0; n < hostcount; n++)
  3711.     {
  3712.         for (i = 0; i < zonecount; i++)
  3713.         {
  3714.         if (sameword(hostname[n], zonename[i]))
  3715.             pr_warning("extraneous A record for %s within %s",
  3716.                 hostname[n], name);
  3717.         }
  3718.     }
  3719.  
  3720.     if (verbose)
  3721.         printf("Transfer complete, %d records received for %s\n",
  3722.             nrecords, name);
  3723.  
  3724.     return(TRUE);
  3725. }
  3726.  
  3727. /*
  3728. ** GET_MXREC -- Fetch MX records of a domain
  3729. ** -----------------------------------------
  3730. **
  3731. **    Returns:
  3732. **        TRUE if MX records were found.
  3733. **        FALSE otherwise.
  3734. */
  3735.  
  3736. bool
  3737. get_mxrec(name)
  3738. input char *name;            /* domain name to get mx for */
  3739. {
  3740.     querybuf answer;
  3741.     int anslen;
  3742.  
  3743.     if (verbose)
  3744.         printf("Finding MX records for %s ...\n", name);
  3745.  
  3746.     anslen = get_info(&answer, name, T_MX, queryclass);
  3747.     if (anslen < 0)
  3748.         return(FALSE);
  3749.  
  3750.     (void) print_info(&answer, anslen, name, FALSE);
  3751.  
  3752.     return(TRUE);
  3753. }
  3754.  
  3755. /*
  3756. ** GET_PRIMARY -- Fetch name of primary nameserver for a zone
  3757. ** ----------------------------------------------------------
  3758. **
  3759. **    Returns:
  3760. **        Pointer to the name of the primary server, if found.
  3761. **        NULL if the server could not be determined.
  3762. */
  3763.  
  3764. char *
  3765. get_primary(name)
  3766. input char *name;            /* name of zone to get soa for */
  3767. {
  3768.     querybuf answer;
  3769.     int anslen;
  3770.  
  3771.     if (verbose)
  3772.         printf("Finding primary nameserver for %s ...\n", name);
  3773.  
  3774.     anslen = get_info(&answer, name, T_SOA, queryclass);
  3775.     if (anslen < 0)
  3776.         return(NULL);
  3777.  
  3778.     if (verbose > 1)
  3779.         (void) print_info(&answer, anslen, name, FALSE);
  3780.  
  3781.     soaname = NULL;
  3782.     (void) get_soainfo(&answer, anslen, name);
  3783.     if (soaname == NULL)
  3784.         return(NULL);
  3785.  
  3786.     return(soa.primary);
  3787. }
  3788.  
  3789. /*
  3790. ** CHECK_ZONE -- Fetch and analyze SOA record of a zone
  3791. ** ----------------------------------------------------
  3792. **
  3793. **    Returns:
  3794. **        TRUE if the SOA record was found at the given server.
  3795. **        FALSE otherwise.
  3796. **
  3797. **    Inputs:
  3798. **        The global variable ``server'' must contain the name
  3799. **        of the server that was queried.
  3800. */
  3801.  
  3802. bool
  3803. check_zone(name)
  3804. input char *name;            /* name of zone to get soa for */
  3805. {
  3806.     querybuf answer;
  3807.     int anslen;
  3808.  
  3809.     if (verbose)
  3810.         printf("Checking SOA for %s at server %s\n", name, server);
  3811.     else if (authserver)
  3812.         printf("%-20s\tNS\t%s\n", name, server);
  3813.     else
  3814.         printf("%s\t(%s)\n", name, server);
  3815.  
  3816.     anslen = get_info(&answer, name, T_SOA, queryclass);
  3817.     if (anslen < 0)
  3818.         return(FALSE);
  3819.  
  3820.     if (verbose > 1)
  3821.         (void) print_info(&answer, anslen, name, FALSE);
  3822.  
  3823.     soaname = NULL;
  3824.     (void) get_soainfo(&answer, anslen, name);
  3825.     if (soaname == NULL)
  3826.         return(FALSE);
  3827.  
  3828.     check_soa(&answer, name);
  3829.  
  3830.     return(TRUE);
  3831. }
  3832.  
  3833. /*
  3834. ** GET_SOAINFO -- Extract SOA data from nameserver answer buffer
  3835. ** -------------------------------------------------------------
  3836. **
  3837. **    Returns:
  3838. **        TRUE if the SOA record was found successfully.
  3839. **        FALSE otherwise.
  3840. **
  3841. **    Outputs:
  3842. **        The global struct ``soa'' is filled with the soa data.
  3843. **
  3844. **    Side effects:
  3845. **        Sets ``soaname'' if this is a valid SOA record.
  3846. **        This variable must have been cleared before calling
  3847. **        get_soainfo() and may be checked afterwards.
  3848. */
  3849.  
  3850. bool
  3851. get_soainfo(answerbuf, answerlen, name)
  3852. input querybuf *answerbuf;        /* address of answer buffer */
  3853. input int answerlen;            /* length of answer buffer */
  3854. input char *name;            /* name of zone to get soa for */
  3855. {
  3856.     HEADER *bp;
  3857.     int qdcount, ancount;
  3858.     u_char *msg, *eom;
  3859.     register u_char *cp;
  3860.  
  3861.     bp = (HEADER *)answerbuf;
  3862.     qdcount = ntohs(bp->qdcount);
  3863.     ancount = ntohs(bp->ancount);
  3864.  
  3865.     msg = (u_char *)answerbuf;
  3866.     eom = (u_char *)answerbuf + answerlen;
  3867.     cp  = (u_char *)answerbuf + HFIXEDSZ;
  3868.  
  3869.     while (qdcount > 0 && cp < eom)
  3870.     {
  3871.         cp = skip_qrec(name, cp, msg, eom);
  3872.         if (cp == NULL)
  3873.             return(FALSE);
  3874.         qdcount--;
  3875.     }
  3876.  
  3877.     if (qdcount)
  3878.     {
  3879.         pr_error("invalid qdcount in response");
  3880.         h_errno = NO_RECOVERY;
  3881.         return(FALSE);
  3882.     }
  3883.  
  3884. /*
  3885.  * Check answer section only.
  3886.  * The nameserver section may contain the nameservers for the zone,
  3887.  * and the additional section their addresses, but not guaranteed.
  3888.  */
  3889.     while (ancount > 0 && cp < eom)
  3890.     {
  3891.         char rname[MAXDNAME+1];
  3892.         int type, class, ttl, dlen;
  3893.         u_char *eor;
  3894.         register int n;
  3895.  
  3896.         n = expand_name(name, T_NONE, cp, msg, eom, rname);
  3897.         if (n < 0)
  3898.             return(FALSE);
  3899.         cp += n;
  3900.  
  3901.         n = 3*INT16SZ + INT32SZ;
  3902.         if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
  3903.             return(FALSE);
  3904.  
  3905.         type = _getshort(cp);
  3906.         cp += INT16SZ;
  3907.  
  3908.         class = _getshort(cp);
  3909.         cp += INT16SZ;
  3910.  
  3911.         ttl = _getlong(cp);
  3912.         cp += INT32SZ;
  3913.  
  3914.         dlen = _getshort(cp);
  3915.         cp += INT16SZ;
  3916.  
  3917.         eor = cp + dlen;
  3918. #ifdef lint
  3919.         if (verbose)
  3920.             printf("%-20s\t%d\t%s\t%s\n",
  3921.                 rname, ttl, pr_class(class), pr_type(type));
  3922. #endif
  3923.         switch (type)
  3924.         {
  3925.             case T_SOA:
  3926.             n = expand_name(rname, type, cp, msg, eom, soa.primary);
  3927.             if (n < 0)
  3928.                 return(FALSE);
  3929.             cp += n;
  3930.  
  3931.             n = expand_name(rname, type, cp, msg, eom, soa.hostmaster);
  3932.             if (n < 0)
  3933.                 return(FALSE);
  3934.             cp += n;
  3935.  
  3936.             n = 5*INT32SZ;
  3937.             if (check_size(rname, type, cp, msg, eor, n) < 0)
  3938.                 return(FALSE);
  3939.             soa.serial = _getlong(cp);
  3940.             cp += INT32SZ;
  3941.             soa.refresh = _getlong(cp);
  3942.             cp += INT32SZ;
  3943.             soa.retry = _getlong(cp);
  3944.             cp += INT32SZ;
  3945.             soa.expire = _getlong(cp);
  3946.             cp += INT32SZ;
  3947.             soa.defttl = _getlong(cp);
  3948.             cp += INT32SZ;
  3949.  
  3950.             /* valid complete soa record found */
  3951.             soaname = strcpy(soanamebuf, rname);
  3952.             break;
  3953.  
  3954.             default:
  3955.             cp += dlen;
  3956.             break;
  3957.         }
  3958.  
  3959.         if (cp != eor)
  3960.         {
  3961.             pr_error("size error in %s record for %s, off by = %s",
  3962.                 pr_type(type), rname, itoa(cp - eor));
  3963.             return(FALSE);
  3964.         }
  3965.  
  3966.         ancount--;
  3967.     }
  3968.  
  3969.     if (ancount)
  3970.     {
  3971.         pr_error("invalid ancount in response");
  3972.         h_errno = NO_RECOVERY;
  3973.         return(FALSE);
  3974.     }
  3975.  
  3976.     return(TRUE);
  3977. }
  3978.  
  3979. /*
  3980. ** CHECK_SOA -- Analyze retrieved SOA records of a zone
  3981. ** ----------------------------------------------------
  3982. **
  3983. **    Returns:
  3984. **        None.
  3985. **
  3986. **    Inputs:
  3987. **        The global variable ``server'' must contain the
  3988. **        name of the server that was queried.
  3989. **        The global struct ``soa'' must contain the soa data.
  3990. */
  3991.  
  3992. void
  3993. check_soa(answerbuf, name)
  3994. input querybuf *answerbuf;        /* address of answer buffer */
  3995. input char *name;            /* name of zone to check soa for */
  3996. {
  3997.     static char oldnamebuf[MAXDNAME+1];
  3998.     static char *oldname = NULL;    /* previous name of zone */
  3999.     static char *oldserver = NULL;    /* previous name of server */
  4000.     static soa_data_t oldsoa;    /* previous soa data */
  4001.     register int n;
  4002.     HEADER *bp;
  4003.  
  4004. /*
  4005.  * Print the various SOA fields in abbreviated form.
  4006.  * Values are actually unsigned, but we print them as signed integers,
  4007.  * apart from the serial which really becomes that big sometimes.
  4008.  * In the latter case we print a warning below.
  4009.  */
  4010.     printf("%s\t%s\t(%u %d %d %d %d)\n",
  4011.         soa.primary, soa.hostmaster, (unsigned)soa.serial,
  4012.         soa.refresh, soa.retry, soa.expire, soa.defttl);
  4013.  
  4014. /*
  4015.  * We are supposed to have queried an authoritative nameserver, and since
  4016.  * nameserver recursion has been turned off, answer must be authoritative.
  4017.  */
  4018.     bp = (HEADER *)answerbuf;
  4019.     if (!bp->aa)
  4020.     {
  4021.         if (authserver)
  4022.             pr_error("SOA record for %s at %s is not authoritative",
  4023.                 name, server);
  4024.         else
  4025.             pr_warning("SOA record for %s at %s is not authoritative",
  4026.                 name, server);
  4027.  
  4028.         if (authserver)
  4029.             errmsg("%s has lame delegation to %s",
  4030.                 name, server);
  4031.     }
  4032.  
  4033. /*
  4034.  * Check whether we are switching to a new zone.
  4035.  * The old name must have been saved in static storage.
  4036.  */
  4037.     if (oldname != NULL && !sameword(name, oldname))
  4038.         oldname = NULL;
  4039.  
  4040. /*
  4041.  * Make few timer consistency checks only for the first one in a series.
  4042.  * Compare the primary field against the list of authoritative servers.
  4043.  * Explicitly check the hostmaster field for illegal characters ('@').
  4044.  * Yell if the serial has the high bit set (not always intentional).
  4045.  */
  4046.     if (oldname == NULL)
  4047.     {
  4048.         for (n = 0; n < nservers; n++)
  4049.             if (sameword(soa.primary, nsname[n]))
  4050.                 break;    /* found */
  4051.  
  4052.         if (n >= nservers && authserver)
  4053.             pr_warning("SOA for %s has extraneous primary", name);
  4054.  
  4055.         if (!valid_name(soa.hostmaster, FALSE))
  4056.             pr_warning("SOA for %s has illegal hostmaster", name);
  4057.  
  4058.         if (bitset(0x80000000, soa.serial))
  4059.             pr_warning("SOA for %s has extraordinary serial", name);
  4060.  
  4061.         if (soa.retry > soa.refresh)
  4062.             pr_warning("SOA for %s has retry exceeding refresh", name);
  4063.  
  4064.         if (soa.refresh + soa.retry > soa.expire)
  4065.             pr_warning("SOA for %s has refresh+retry exceeding expire", name);
  4066.     }
  4067.  
  4068. /*
  4069.  * Compare various fields with those of the previous query, if any.
  4070.  * Different serial numbers may be present if secondaries have not yet
  4071.  * refreshed the data from the primary. Issue only a warning in that case.
  4072.  */
  4073.     if (oldname != NULL)
  4074.     {
  4075.         if (!sameword(soa.primary, oldsoa.primary))
  4076.             pr_error("%s has different primary than %s",
  4077.                 server, oldserver);
  4078.  
  4079.         if (!sameword(soa.hostmaster, oldsoa.hostmaster))
  4080.             pr_error("%s has different hostmaster than %s",
  4081.                 server, oldserver);
  4082.  
  4083.         if (soa.serial != oldsoa.serial)
  4084.             pr_warning("%s has different serial than %s",
  4085.                 server, oldserver);
  4086.  
  4087.         if (soa.refresh != oldsoa.refresh)
  4088.             pr_error("%s has different refresh than %s",
  4089.                 server, oldserver);
  4090.  
  4091.         if (soa.retry != oldsoa.retry)
  4092.             pr_error("%s has different retry than %s",
  4093.                 server, oldserver);
  4094.  
  4095.         if (soa.expire != oldsoa.expire)
  4096.             pr_error("%s has different expire than %s",
  4097.                 server, oldserver);
  4098.  
  4099.         if (soa.defttl != oldsoa.defttl)
  4100.             pr_error("%s has different defttl than %s",
  4101.                 server, oldserver);
  4102.     }
  4103.  
  4104. /*
  4105.  * Save the current information.
  4106.  */
  4107.     oldname = strcpy(oldnamebuf, name);
  4108.     oldserver = server;
  4109.     oldsoa = soa;
  4110. }
  4111.  
  4112. /*
  4113. ** CHECK_DUPL -- Check global address list for duplicates
  4114. ** ------------------------------------------------------
  4115. **
  4116. **    Returns:
  4117. **        TRUE if the given host address already exists.
  4118. **        FALSE otherwise.
  4119. **
  4120. **    Side effects:
  4121. **        Adds the host address to the list if not present.
  4122. */
  4123.  
  4124. bool
  4125. check_dupl(addr)
  4126. input ipaddr_t addr;            /* address of host to check */
  4127. {
  4128.      register int i;
  4129.     register addr_data_t *h;
  4130.  
  4131.     h = &hlist[ntohl(addr) & AHASHMASK];
  4132.  
  4133.     for (i = 0; i < h->addrcount; i++)
  4134.         if (h->addrlist[i] == addr)
  4135.             return(TRUE);    /* duplicate */
  4136.  
  4137.     h->addrlist = newlist(h->addrlist, h->addrcount+1, ipaddr_t);
  4138.     h->addrlist[h->addrcount] = addr;
  4139.     h->addrcount++;
  4140.     return(FALSE);
  4141. }
  4142.  
  4143.  
  4144. #ifdef obsolete
  4145.  
  4146. #define NETWORK_MASK    ((ipaddr_t)0xffff0000)
  4147. #define nethash(a)    ((a) & htonl(NETWORK_MASK))
  4148.  
  4149. bool
  4150. check_dupl(addr)
  4151. input ipaddr_t addr;            /* address of host to check */
  4152. {
  4153.     ipaddr_t network;
  4154.     register int n;
  4155.      register int i;
  4156.     register net_data_t *h;
  4157.  
  4158. /*
  4159.  * Extract the (peudo) network part from the address.
  4160.  */
  4161.     network = nethash(addr);
  4162.  
  4163. /*
  4164.  * Check whether we already have a list for this network.
  4165.  * If not, allocate a new empty address list.
  4166.  */
  4167.     for (n = 0; n < netcount; n++)
  4168.         if (netlist[n].network == network)
  4169.             break;  /* network is known */
  4170.  
  4171.     if (n >= netcount)
  4172.     {
  4173.         netlist = newlist(netlist, netcount+1, net_data_t);
  4174.         netlist[netcount].network = network;
  4175.         netlist[netcount].addrlist = NULL;
  4176.         netlist[netcount].addrcount = 0;
  4177.         netcount++;
  4178.     }
  4179.  
  4180.     /* the hash list for this network */
  4181.     h = &netlist[n];
  4182.  
  4183. /*
  4184.  * Check whether the address exists on the list for that network.
  4185.  * If not, add it to the address list.
  4186.  */
  4187.     for (i = 0; i < h->addrcount; i++)
  4188.         if (h->addrlist[i] == addr)
  4189.             return(TRUE);    /* duplicate */
  4190.  
  4191.     h->addrlist = newlist(h->addrlist, h->addrcount+1, ipaddr_t);
  4192.     h->addrlist[h->addrcount] = addr;
  4193.     h->addrcount++;
  4194.     return(FALSE);
  4195. }
  4196.  
  4197.  
  4198. bool
  4199. check_dupl(addr)
  4200. input ipaddr_t addr;            /* address of host to check */
  4201. {
  4202.     register int i;
  4203.  
  4204.     for (i = 0; i < addrcount; i++)
  4205.         if (addrlist[i] == addr)
  4206.             return(TRUE);    /* duplicate */
  4207.  
  4208.     addrlist = newlist(addrlist, addrcount+1, ipaddr_t);
  4209.     addrlist[addrcount] = addr;
  4210.     addrcount++;
  4211.     return(FALSE);
  4212. }
  4213.  
  4214. #endif
  4215.  
  4216. /*
  4217. ** CHECK_ADDR -- Check whether reverse address mappings revert to host
  4218. ** -------------------------------------------------------------------
  4219. **
  4220. **    Returns:
  4221. **        TRUE if all addresses of host map back to host.
  4222. **        FALSE otherwise.
  4223. */
  4224.  
  4225. bool
  4226. check_addr(name)
  4227. input char *name;            /* hostname to check addresses for */
  4228. {
  4229.     struct hostent *hp;
  4230.     register int i;
  4231.     struct in_addr inaddr[MAXADDRS];
  4232.     int naddr;
  4233.     char hnamebuf[MAXDNAME+1];
  4234.     char *hname;
  4235.     char inamebuf[MAXDNAME+1];
  4236.     char *iname;
  4237.     int matched;
  4238.  
  4239. /*
  4240.  * Look up the specified host to fetch its addresses.
  4241.  */
  4242.     hp = gethostbyname(name);
  4243.     if (hp == NULL)
  4244.     {
  4245.         ns_error(name, T_A, C_IN);
  4246.         return(FALSE);
  4247.     }
  4248.  
  4249.     hname = strcpy(hnamebuf, hp->h_name);
  4250.  
  4251.     for (i = 0; i < MAXADDRS && hp->h_addr_list[i]; i++)
  4252.         inaddr[i] = incopy(hp->h_addr_list[i]);
  4253.     naddr = i;
  4254.  
  4255.     if (verbose)
  4256.         printf("Found %d address%s for %s\n",
  4257.             naddr, naddr == 1 ? "" : "es", hname);
  4258.  
  4259. /*
  4260.  * Map back the addresses found, and check whether they revert to host.
  4261.  */
  4262.     for (matched = 0, i = 0; i < naddr; i++)
  4263.     {
  4264.         iname = strcpy(inamebuf, inet_ntoa(inaddr[i]));
  4265.  
  4266.         if (verbose)
  4267.             printf("Checking %s address %s\n", hname, iname);
  4268.  
  4269.         hp = gethostbyaddr((char *)&inaddr[i], INADDRSZ, AF_INET);
  4270.         if (hp == NULL)
  4271.             ns_error(iname, T_PTR, C_IN);
  4272.         else if (!sameword(hp->h_name, hname))
  4273.             pr_error("address %s of %s maps to %s",
  4274.                 iname, hname, hp->h_name);
  4275.         else
  4276.             matched++;
  4277.     }
  4278.  
  4279.     return(matched == naddr ? TRUE : FALSE);
  4280. }
  4281.  
  4282. /*
  4283. ** CHECK_NAME -- Check whether address belongs to host addresses
  4284. ** -------------------------------------------------------------
  4285. **
  4286. **    Returns:
  4287. **        TRUE if given address was found among host addresses.
  4288. **        FALSE otherwise.
  4289. */
  4290.  
  4291. bool
  4292. check_name(addr)
  4293. input ipaddr_t addr;            /* address of host to check */
  4294. {
  4295.     struct hostent *hp;
  4296.     register int i;
  4297.     struct in_addr inaddr;
  4298.     char hnamebuf[MAXDNAME+1];
  4299.     char *hname;
  4300.     char inamebuf[MAXDNAME+1];
  4301.     char *iname;
  4302.     int matched;
  4303.  
  4304. /*
  4305.  * Check whether the address is registered by fetching its hostname.
  4306.  */
  4307.     inaddr.s_addr = addr;
  4308.     iname = strcpy(inamebuf, inet_ntoa(inaddr));
  4309.  
  4310.     hp = gethostbyaddr((char *)&inaddr, INADDRSZ, AF_INET);
  4311.     if (hp == NULL)
  4312.     {
  4313.         ns_error(iname, T_PTR, C_IN);
  4314.         return(FALSE);
  4315.     }
  4316.  
  4317.     hname = strcpy(hnamebuf, hp->h_name);
  4318.  
  4319.     if (verbose)
  4320.         printf("Address %s maps to %s\n", iname, hname);
  4321.  
  4322. /*
  4323.  * Lookup the hostname found to fetch its addresses.
  4324.  * Check whether the given address is listed among the known addresses.
  4325.  */
  4326.     hp = gethostbyname(hname);
  4327.     if (hp == NULL)
  4328.     {
  4329.         ns_error(hname, T_A, C_IN);
  4330.         return(FALSE);
  4331.     }
  4332.  
  4333.     for (matched = 0, i = 0; hp->h_addr_list[i]; i++)
  4334.     {
  4335.         inaddr = incopy(hp->h_addr_list[i]);
  4336.  
  4337.         if (verbose)
  4338.             printf("Checking %s address %s\n",
  4339.                 hname, inet_ntoa(inaddr));
  4340.  
  4341.         if (inaddr.s_addr == addr)
  4342.             matched++;
  4343.     }
  4344.  
  4345.     if (!matched)
  4346.         pr_error("address %s does not belong to %s", iname, hname);
  4347.  
  4348.     return(matched ? TRUE : FALSE);
  4349. }
  4350.  
  4351. /*
  4352. ** PARSE_TYPE -- Decode rr type from input string
  4353. ** ----------------------------------------------
  4354. **
  4355. **    Returns:
  4356. **        Value of resource record type.
  4357. **        -1 if specified record name is invalid.
  4358. **
  4359. **    Note.    T_MD, T_MF, T_MAILA are obsolete, but recognized.
  4360. **        T_AXFR is not allowed to be specified as query type.
  4361. */
  4362.  
  4363. int
  4364. parse_type(str)
  4365. input char *str;            /* input string with record type */
  4366. {
  4367.     register int type;
  4368.  
  4369.     if (sameword(str, "A"))        return(T_A);
  4370.     if (sameword(str, "NS"))    return(T_NS);
  4371.     if (sameword(str, "MD"))    return(T_MD);        /* obsolete */
  4372.     if (sameword(str, "MF"))    return(T_MF);        /* obsolete */
  4373.     if (sameword(str, "CNAME"))    return(T_CNAME);
  4374.     if (sameword(str, "SOA"))    return(T_SOA);
  4375.     if (sameword(str, "MB"))    return(T_MB);
  4376.     if (sameword(str, "MG"))    return(T_MG);
  4377.     if (sameword(str, "MR"))    return(T_MR);
  4378.     if (sameword(str, "NULL"))    return(T_NULL);
  4379.     if (sameword(str, "WKS"))    return(T_WKS);
  4380.     if (sameword(str, "PTR"))    return(T_PTR);
  4381.     if (sameword(str, "HINFO"))    return(T_HINFO);
  4382.     if (sameword(str, "MINFO"))    return(T_MINFO);
  4383.     if (sameword(str, "MX"))    return(T_MX);
  4384.     if (sameword(str, "TXT"))    return(T_TXT);
  4385.  
  4386.     if (sameword(str, "RP"))    return(T_RP);
  4387.     if (sameword(str, "AFSDB"))    return(T_AFSDB);
  4388.     if (sameword(str, "X25"))    return(T_X25);
  4389.     if (sameword(str, "ISDN"))    return(T_ISDN);
  4390.     if (sameword(str, "RT"))    return(T_RT);
  4391.     if (sameword(str, "NSAP"))    return(T_NSAP);
  4392.     if (sameword(str, "NSAP-PTR"))    return(T_NSAPPTR);
  4393.  
  4394.     if (sameword(str, "UINFO"))    return(T_UINFO);
  4395.     if (sameword(str, "UID"))    return(T_UID);
  4396.     if (sameword(str, "GID"))    return(T_GID);
  4397.     if (sameword(str, "UNSPEC"))    return(T_UNSPEC);
  4398.  
  4399.     if (sameword(str, "AXFR"))    return(-1);        /* illegal */
  4400.     if (sameword(str, "MAILB"))    return(T_MAILB);
  4401.     if (sameword(str, "MAILA"))    return(T_MAILA);    /* obsolete */
  4402.     if (sameword(str, "ANY"))    return(T_ANY);
  4403.     if (sameword(str, "*"))        return(T_ANY);
  4404.  
  4405.     type = atoi(str);
  4406.     if (type >= T_FIRST && type <= T_LAST)
  4407.         return(type);
  4408.  
  4409.     return(-1);
  4410. }
  4411.  
  4412. /*
  4413. ** PARSE_CLASS -- Decode rr class from input string
  4414. ** ------------------------------------------------
  4415. **
  4416. **    Returns:
  4417. **        Value of resource class.
  4418. **        -1 if specified class name is invalid.
  4419. **
  4420. **    Note.    C_CSNET is obsolete, but recognized.
  4421. */
  4422.  
  4423. int
  4424. parse_class(str)
  4425. input char *str;            /* input string with resource class */
  4426. {
  4427.     register int class;
  4428.  
  4429.     if (sameword(str, "IN"))    return(C_IN);
  4430.     if (sameword(str, "INTERNET"))    return(C_IN);
  4431.     if (sameword(str, "CS"))    return(C_CSNET);    /* obsolete */
  4432.     if (sameword(str, "CSNET"))    return(C_CSNET);    /* obsolete */
  4433.     if (sameword(str, "CH"))    return(C_CHAOS);
  4434.     if (sameword(str, "CHAOS"))    return(C_CHAOS);
  4435.     if (sameword(str, "HS"))    return(C_HS);
  4436.     if (sameword(str, "HESIOD"))    return(C_HS);
  4437.  
  4438.     if (sameword(str, "ANY"))    return(C_ANY);
  4439.     if (sameword(str, "*"))        return(C_ANY);
  4440.  
  4441.     class = atoi(str);
  4442.     if (class > 0)
  4443.         return(class);
  4444.  
  4445.     return(-1);
  4446. }
  4447.  
  4448. /*
  4449. ** IN_ADDR_ARPA -- Convert dotted quad string to reverse in-addr.arpa
  4450. ** ------------------------------------------------------------------
  4451. **
  4452. **    Returns:
  4453. **        Pointer to reverse in-addr.arpa. zone name
  4454. **        with trailing dot to force absolute domain name.
  4455. **        NULL in case of invalid dotted quad input string.
  4456. */
  4457.  
  4458. char *
  4459. in_addr_arpa(dottedquad)
  4460. input char *dottedquad;            /* input string with dotted quad */
  4461. {
  4462.     static char addrbuf[32];
  4463.     unsigned int a[4];
  4464.     register int n;
  4465.  
  4466.     n = sscanf(dottedquad, "%u.%u.%u.%u", &a[0], &a[1], &a[2], &a[3]);
  4467.     switch (n)
  4468.     {
  4469.         case 4:
  4470.         (void) sprintf(addrbuf, "%u.%u.%u.%u.in-addr.arpa.",
  4471.             a[3]&0xff, a[2]&0xff, a[1]&0xff, a[0]&0xff);
  4472.         break;
  4473.  
  4474.         case 3:
  4475.         (void) sprintf(addrbuf, "%u.%u.%u.in-addr.arpa.",
  4476.             a[2]&0xff, a[1]&0xff, a[0]&0xff);
  4477.         break;
  4478.  
  4479.         case 2:
  4480.         (void) sprintf(addrbuf, "%u.%u.in-addr.arpa.",
  4481.             a[1]&0xff, a[0]&0xff);
  4482.         break;
  4483.  
  4484.         case 1:
  4485.         (void) sprintf(addrbuf, "%u.in-addr.arpa.",
  4486.             a[0]&0xff);
  4487.         break;
  4488.  
  4489.         default:
  4490.         return(NULL);
  4491.     }
  4492.  
  4493.     while (--n >= 0)
  4494.         if (a[n] > 255)
  4495.             return(NULL);
  4496.  
  4497.     return(addrbuf);
  4498. }
  4499.  
  4500. /*
  4501. ** PRINT_HOST -- Print hostname and address of hostent struct
  4502. ** ----------------------------------------------------------
  4503. **
  4504. **    Returns:
  4505. **        None.
  4506. */
  4507.  
  4508. void
  4509. print_host(heading, hp)
  4510. input char *heading;            /* header string */
  4511. input struct hostent *hp;        /* address of hostent struct */
  4512. {
  4513.     register char **ap;
  4514.  
  4515.     printf("%s: %s", heading, hp->h_name);
  4516.  
  4517.     for (ap = hp->h_addr_list; ap && *ap; ap++)
  4518.     {
  4519.         if (ap == hp->h_addr_list)
  4520.             printf("\nAddress:");
  4521.  
  4522.         printf(" %s", inet_ntoa(incopy(*ap)));
  4523.     }
  4524.  
  4525.     for (ap = hp->h_aliases; ap && *ap && **ap; ap++)
  4526.     {
  4527.         if (ap == hp->h_aliases)
  4528.             printf("\nAliases:");
  4529.  
  4530.         printf(" %s", *ap);
  4531.     }
  4532.  
  4533.     printf("\n\n");
  4534. }
  4535.  
  4536. /*
  4537. ** SHOW_RES -- Show resolver database information
  4538. ** ----------------------------------------------
  4539. **
  4540. **    Returns:
  4541. **        None.
  4542. **
  4543. **    Inputs:
  4544. **        The resolver database _res is localized in the resolver.
  4545. */
  4546.  
  4547. void
  4548. show_res()
  4549. {
  4550.     register int i;
  4551.     register char **domain;
  4552.  
  4553. /*
  4554.  * The default domain is defined by the "domain" entry in /etc/resolv.conf
  4555.  * if not overridden by the environment variable "LOCALDOMAIN".
  4556.  * If still not defined, gethostname() may yield a fully qualified hostname.
  4557.  */
  4558.     printf("Default domain:");
  4559.     if (_res.defdname[0] != '\0')
  4560.         printf(" %s", _res.defdname);
  4561.     printf("\n");
  4562.  
  4563. /*
  4564.  * The search domains are extracted from the default domain components,
  4565.  * but may be overridden by "search" directives in /etc/resolv.conf
  4566.  * since 4.8.3.
  4567.  */
  4568.     printf("Search domains:");
  4569.     for (domain = _res.dnsrch; *domain; domain++)
  4570.         printf(" %s", *domain);
  4571.     printf("\n");
  4572.  
  4573. /*
  4574.  * The routine res_send() will do _res.retry tries to contact each of the
  4575.  * _res.nscount nameserver addresses before giving up when using datagrams.
  4576.  * The first try will timeout after _res.retrans seconds. Each following
  4577.  * try will timeout after ((_res.retrans << try) / _res.nscount) seconds.
  4578.  * Note. When we contact an explicit server the addresses will be replaced
  4579.  * by the multiple addresses of the same server.
  4580.  * When doing a zone transfer _res.retrans is used for the connect timeout.
  4581.  */
  4582.     printf("Timeout per retry: %d secs\n", _res.retrans);
  4583.     printf("Number of retries: %d\n", _res.retry);
  4584.  
  4585.     printf("Number of addresses: %d\n", _res.nscount);
  4586.     for (i = 0; i < _res.nscount; i++)
  4587.         printf("%s\n", inet_ntoa(nslist(i).sin_addr));
  4588.  
  4589. /*
  4590.  * The resolver options are initialized by res_init() to contain the
  4591.  * defaults settings (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
  4592.  * The various options have the following meaning:
  4593.  *
  4594.  *    RES_INIT    set after res_init() has been called
  4595.  *    RES_DEBUG    let the resolver modules print debugging info
  4596.  *    RES_AAONLY    want authoritative answers only (not implemented)
  4597.  *    RES_USEVC    use tcp virtual circuit instead of udp datagrams
  4598.  *    RES_PRIMARY    use primary nameserver only (not implemented)
  4599.  *    RES_IGNTC    ignore datagram truncation; don't switch to tcp
  4600.  *    RES_RECURSE    forward query if answer not locally available
  4601.  *    RES_DEFNAMES    add default domain to queryname without dot
  4602.  *    RES_STAYOPEN    keep tcp socket open for subsequent queries
  4603.  *    RES_DNSRCH    append search domains even to queryname with dot
  4604.  */
  4605.     printf("Options set:");
  4606.     if (bitset(RES_INIT,      _res.options)) printf(" INIT");
  4607.     if (bitset(RES_DEBUG,     _res.options)) printf(" DEBUG");
  4608.     if (bitset(RES_AAONLY,    _res.options)) printf(" AAONLY");
  4609.     if (bitset(RES_USEVC,     _res.options)) printf(" USEVC");
  4610.     if (bitset(RES_PRIMARY,   _res.options)) printf(" PRIMARY");
  4611.     if (bitset(RES_IGNTC,     _res.options)) printf(" IGNTC");
  4612.     if (bitset(RES_RECURSE,   _res.options)) printf(" RECURSE");
  4613.     if (bitset(RES_DEFNAMES,  _res.options)) printf(" DEFNAMES");
  4614.     if (bitset(RES_STAYOPEN,  _res.options)) printf(" STAYOPEN");
  4615.     if (bitset(RES_DNSRCH,    _res.options)) printf(" DNSRCH");
  4616.     printf("\n");
  4617.  
  4618.     printf("Options clr:");
  4619.     if (!bitset(RES_INIT,     _res.options)) printf(" INIT");
  4620.     if (!bitset(RES_DEBUG,    _res.options)) printf(" DEBUG");
  4621.     if (!bitset(RES_AAONLY,   _res.options)) printf(" AAONLY");
  4622.     if (!bitset(RES_USEVC,    _res.options)) printf(" USEVC");
  4623.     if (!bitset(RES_PRIMARY,  _res.options)) printf(" PRIMARY");
  4624.     if (!bitset(RES_IGNTC,    _res.options)) printf(" IGNTC");
  4625.     if (!bitset(RES_RECURSE,  _res.options)) printf(" RECURSE");
  4626.     if (!bitset(RES_DEFNAMES, _res.options)) printf(" DEFNAMES");
  4627.     if (!bitset(RES_STAYOPEN, _res.options)) printf(" STAYOPEN");
  4628.     if (!bitset(RES_DNSRCH,   _res.options)) printf(" DNSRCH");
  4629.     printf("\n");
  4630.  
  4631.     printf("\n");
  4632. }
  4633.  
  4634. /*
  4635. ** PRINT_STATISTICS -- Print resource record statistics
  4636. ** ----------------------------------------------------
  4637. **
  4638. **    Returns:
  4639. **        None.
  4640. **
  4641. **    Inputs:
  4642. **        The record_stats[] counts have been updated by print_rrec().
  4643. */
  4644.  
  4645. void
  4646. print_statistics(name, filter, class)
  4647. input char *name;            /* name of zone we are listing */
  4648. input int filter;            /* type of records we want to see */
  4649. input int class;            /* class of records we want to see */
  4650. {
  4651.     register int type;
  4652.     int nrecords;
  4653.  
  4654.     for (type = T_FIRST; type <= T_LAST; type++)
  4655.     {
  4656.         nrecords = record_stats[type];
  4657.         if (nrecords > 0 || (filter != T_ANY && want_type(type, filter)))
  4658.         {
  4659.             printf("Found %4d %-5s record%s", nrecords,
  4660.                 pr_type(type), nrecords == 1 ? " " : "s");
  4661.  
  4662.             if (class != C_IN)
  4663.                 printf(" in class %s", pr_class(class));
  4664.  
  4665.             printf(" within %s\n", name);
  4666.         }
  4667.     }
  4668. }
  4669.  
  4670.  
  4671. /*
  4672. ** CLEAR_STATISTICS -- Clear resource record statistics
  4673. ** ----------------------------------------------------
  4674. **
  4675. **    Returns:
  4676. **        None.
  4677. */
  4678.  
  4679. void
  4680. clear_statistics()
  4681. {
  4682.     bzero((char *)record_stats, sizeof(record_stats));
  4683. }
  4684.  
  4685. /*
  4686. ** SHOW_TYPES -- Show resource record types wanted
  4687. ** -----------------------------------------------
  4688. **
  4689. **    Returns:
  4690. **        None.
  4691. */
  4692.  
  4693. void
  4694. show_types(name, filter, class)
  4695. input char *name;            /* name we want to query about */
  4696. input int filter;            /* type of records we want to see */
  4697. input int class;            /* class of records we want to see */
  4698. {
  4699.     register int type;
  4700.  
  4701.     if (filter >= T_NONE)
  4702.     {
  4703.         printf("Query about %s for record types", name);
  4704.  
  4705.         if (filter == T_ANY)
  4706.             printf(" %s", pr_type(T_ANY));
  4707.         else
  4708.             for (type = T_FIRST; type <= T_LAST; type++)
  4709.                 if (want_type(type, filter))
  4710.                     printf(" %s", pr_type(type));
  4711.  
  4712.         if (class != C_IN)
  4713.             printf(" in class %s", pr_class(class));
  4714.  
  4715.         printf("\n");
  4716.     }
  4717. }
  4718.  
  4719. /*
  4720. ** NS_ERROR -- Print error message from errno and h_errno
  4721. ** ------------------------------------------------------
  4722. **
  4723. **    Returns:
  4724. **        None.
  4725. **
  4726. **    Inputs:
  4727. **        The global variable ``server'', if set, contains
  4728. **        the name of the server that was contacted.
  4729. */
  4730.  
  4731. void
  4732. ns_error(name, type, class) 
  4733. input char *name;            /* full name we queried about */
  4734. input int type;                /* record type we queried about */
  4735. input int class;            /* record class we queried about */
  4736. {
  4737.     static char *auth = "Authoritative answer";
  4738.  
  4739. /*
  4740.  * If BIND res_send() fails, it will leave errno in either of the first two
  4741.  * following states when using datagrams. Note that this depends on the
  4742.  * proper handling of connected datagram sockets, which is usually true
  4743.  * if BSD >= 43 (see res_send.c for details; it may need a patch).
  4744.  * Note. If the 4.8 version succeeds, it may leave errno as EAFNOSUPPORT
  4745.  * if it has disconnected a previously connected datagram socket, since
  4746.  * the dummy address used to disconnect does not have a proper family set.
  4747.  * Always clear errno after getting a reply, or patch res_send().
  4748.  * Our private version of res_send() will leave also other error statuses.
  4749.  */
  4750.     switch (errno)
  4751.     {
  4752.         case ECONNREFUSED:
  4753.         /*
  4754.          * The contacted host does not have a nameserver running.
  4755.          * The standard res_send() also returns this if none of
  4756.          * the intended hosts could be reached via datagrams.
  4757.          */
  4758.         if (server)
  4759.             errmsg("Nameserver %s not running", server);
  4760.         else
  4761.             errmsg("Nameserver not running");
  4762.         break;
  4763.  
  4764.         case ETIMEDOUT:
  4765.         /*
  4766.          * The contacted server did not give any reply at all
  4767.          * within the specified time frame.
  4768.          */
  4769.         if (server)
  4770.             errmsg("Nameserver %s not responding", server);
  4771.         else
  4772.             errmsg("Nameserver not responding");
  4773.         break;
  4774.  
  4775.         case ENETDOWN:
  4776.         case ENETUNREACH:
  4777.         case EHOSTDOWN:
  4778.         case EHOSTUNREACH:
  4779.         /*
  4780.          * The host to be contacted or its network can not be reached.
  4781.          * Our private res_send() also returns this using datagrams.
  4782.          */
  4783.         if (server)
  4784.             errmsg("Nameserver %s not reachable", server);
  4785.         else
  4786.             errmsg("Nameserver not reachable");
  4787.         break;
  4788.     }
  4789.  
  4790. /*
  4791.  * Print the message associated with the particular nameserver error.
  4792.  */
  4793.     switch (h_errno)
  4794.     {
  4795.         case HOST_NOT_FOUND:
  4796.         /*
  4797.          * The specified name does definitely not exist at all.
  4798.          * In this case the answer is always authoritative.
  4799.          * Nameserver status: NXDOMAIN
  4800.          */
  4801.         if (class != C_IN)
  4802.             errmsg("%s does not exist in class %s (%s)",
  4803.                 name, pr_class(class), auth);
  4804.         else
  4805.             errmsg("%s does not exist (%s)",
  4806.                 name, auth);
  4807.         break;
  4808.  
  4809.         case NO_HOST:
  4810.         /*
  4811.          * The specified name does not exist, but the answer
  4812.          * was not authoritative, so it is still undecided.
  4813.          * Happens when querying unknown name for class C_ANY.
  4814.          * Nameserver status: NXDOMAIN
  4815.          */
  4816.         if (class != C_IN)
  4817.             errmsg("%s does not exist in class %s, try again",
  4818.                 name, pr_class(class));
  4819.         else
  4820.             errmsg("%s does not exist, try again",
  4821.                 name);
  4822.         break;
  4823.  
  4824.         case TRY_AGAIN:
  4825.         /*
  4826.          * Some intermediate server failure, e.g. timeout, or when
  4827.          * the server is not authoritative for a specific class.
  4828.          * Nameserver status: SERVFAIL
  4829.          */
  4830.         if (class != C_IN)
  4831.             errmsg("%s %s record in class %s not found, try again",
  4832.                 name, pr_type(type), pr_class(class));
  4833.         else
  4834.             errmsg("%s %s record not found, try again",
  4835.                 name, pr_type(type));
  4836.         break;
  4837.  
  4838.         case NO_RECOVERY:
  4839.         /*
  4840.          * Some irrecoverable format error, or server refusal.
  4841.          * Nameserver status: FORMERR NOTIMP REFUSED NOCHANGE
  4842.          */
  4843.         if (class != C_IN)
  4844.             errmsg("%s %s record in class %s not found, no recovery",
  4845.                 name, pr_type(type), pr_class(class));
  4846.         else
  4847.             errmsg("%s %s record not found, no recovery",
  4848.                 name, pr_type(type));
  4849.         break;
  4850.  
  4851.         case NO_DATA:
  4852.         /*
  4853.          * The name is valid, but the specified type does not exist.
  4854.          * This status is here returned only in case authoritative.
  4855.          * Nameserver status: NOERROR
  4856.          */
  4857.         if (class != C_IN)
  4858.             errmsg("%s has no %s record in class %s (%s)",
  4859.                 name, pr_type(type), pr_class(class), auth);
  4860.         else
  4861.             errmsg("%s has no %s record (%s)",
  4862.                 name, pr_type(type), auth);
  4863.         break;
  4864.  
  4865.         case NO_RREC:
  4866.         /*
  4867.          * The specified type does not exist, but we don't know whether
  4868.          * the name is valid or not. The answer was not authoritative.
  4869.          * Perhaps recursion was off, and no data was cached locally.
  4870.          * Nameserver status: NOERROR
  4871.          */
  4872.         if (class != C_IN)
  4873.             errmsg("%s %s record in class %s currently not present",
  4874.                 name, pr_type(type), pr_class(class));
  4875.         else
  4876.             errmsg("%s %s record currently not present",
  4877.                 name, pr_type(type));
  4878.         break;
  4879.  
  4880.         default:
  4881.         /*
  4882.          * Unknown cause for server failure.
  4883.          */
  4884.         if (class != C_IN)
  4885.             errmsg("%s %s record in class %s not found",
  4886.                 name, pr_type(type), pr_class(class));
  4887.         else
  4888.             errmsg("%s %s record not found",
  4889.                 name, pr_type(type));
  4890.         break;
  4891.     }
  4892. }
  4893.  
  4894. /*
  4895. ** DECODE_ERROR -- Convert nameserver error code to error message
  4896. ** --------------------------------------------------------------
  4897. **
  4898. **    Returns:
  4899. **        Pointer to appropriate error message.
  4900. */
  4901.  
  4902. char *
  4903. decode_error(rcode)
  4904. input int rcode;            /* error code from bp->rcode */
  4905. {
  4906.     switch (rcode)
  4907.     {
  4908.         case NOERROR:     return("no error");
  4909.         case FORMERR:    return("format error");
  4910.         case SERVFAIL:    return("server failed");
  4911.         case NXDOMAIN:    return("non-existent domain");
  4912.         case NOTIMP:    return("not implemented");
  4913.         case REFUSED:    return("query refused");
  4914.         case NOCHANGE:    return("no change");
  4915.     }
  4916.  
  4917.     return("unknown error");
  4918. }
  4919.  
  4920. /*
  4921. ** PRINT_STATUS -- Print result status after nameserver query
  4922. ** ----------------------------------------------------------
  4923. **
  4924. **    Returns:
  4925. **        None.
  4926. **
  4927. **    Conditions:
  4928. **        The size of the answer buffer must have been
  4929. **        checked before to be of sufficient length,
  4930. **        i.e. to contain at least the buffer header.
  4931. */
  4932.  
  4933. void
  4934. print_status(answerbuf)
  4935. input querybuf *answerbuf;        /* address of answer buffer */
  4936. {
  4937.     HEADER *bp;
  4938.     int ancount;
  4939.     bool failed;
  4940.  
  4941.     bp = (HEADER *)answerbuf;
  4942.     ancount = ntohs(bp->ancount);
  4943.     failed = (bp->rcode != NOERROR || ancount == 0);
  4944.  
  4945.     printf("Query %s, %d answer%s%s, %sstatus: %s\n",
  4946.         failed ? "failed" : "done",
  4947.         ancount, ancount == 1 ? "" : "s",
  4948.         bp->tc ? " (truncated)" : "",
  4949.         bp->aa ? "authoritative " : "",
  4950.         decode_error((int)bp->rcode));
  4951. }
  4952.  
  4953. /*
  4954. ** PR_ERROR -- Print error message about encountered inconsistencies
  4955. ** -----------------------------------------------------------------
  4956. **
  4957. **    We are supposed to have an error condition which is fatal
  4958. **    for normal continuation, and the message is always printed.
  4959. **
  4960. **    Returns:
  4961. **        None.
  4962. **
  4963. **    Side effects:
  4964. **        Increments the global error count.
  4965. */
  4966.  
  4967. void /*VARARGS1*/
  4968. pr_error(fmt, a, b, c, d)
  4969. input char *fmt;            /* format of message */
  4970. input char *a, *b, *c, *d;        /* optional arguments */
  4971. {
  4972.     (void) fprintf(stderr, " *** ");
  4973.     (void) fprintf(stderr, fmt, a, b, c, d);
  4974.     (void) fprintf(stderr, "\n");
  4975.  
  4976.     /* flag an error */
  4977.     Errors++;
  4978. }
  4979.  
  4980.  
  4981. /*
  4982. ** PR_WARNING -- Print warning message about encountered inconsistencies
  4983. ** ---------------------------------------------------------------------
  4984. **
  4985. **    We are supposed to have an error condition which is non-fatal
  4986. **    for normal continuation, and the message is suppressed in case
  4987. **    quiet mode has been selected.
  4988. **
  4989. **    Returns:
  4990. **        None.
  4991. */
  4992.  
  4993. void /*VARARGS1*/
  4994. pr_warning(fmt, a, b, c, d)
  4995. input char *fmt;            /* format of message */
  4996. input char *a, *b, *c, *d;        /* optional arguments */
  4997. {
  4998.     if (!quiet)
  4999.     {
  5000.         (void) fprintf(stderr, " !!! ");
  5001.         (void) fprintf(stderr, fmt, a, b, c, d);
  5002.         (void) fprintf(stderr, "\n");
  5003.     }
  5004. }
  5005.  
  5006. /*
  5007. ** WANT_TYPE -- Indicate whether the rr type matches the desired filter
  5008. ** --------------------------------------------------------------------
  5009. **
  5010. **    Returns:
  5011. **        TRUE if the resource record type matches the filter.
  5012. **        FALSE otherwise.
  5013. **
  5014. **    In regular mode, the querytype is used to formulate the query,
  5015. **    and the filter is set to T_ANY to filter out any response.
  5016. **    In listmode, we get everything, so the filter is set to the
  5017. **    querytype to filter out the proper responses.
  5018. **    Note that T_NONE is the default querytype in listmode.
  5019. */
  5020.  
  5021. bool
  5022. want_type(type, filter)
  5023. input int type;                /* resource record type */
  5024. input int filter;            /* type of records we want to see */
  5025. {
  5026.     if (type == filter)
  5027.         return(TRUE);
  5028.  
  5029.     if (filter == T_ANY)
  5030.         return(TRUE);
  5031.  
  5032.     if (filter == T_NONE &&
  5033.        (type == T_A || type == T_NS || type == T_PTR))
  5034.         return(TRUE);
  5035.  
  5036.     if (filter == T_MAILB &&
  5037.        (type == T_MB || type == T_MR || type == T_MG || type == T_MINFO))
  5038.         return(TRUE);
  5039.  
  5040.     if (filter == T_MAILA &&
  5041.        (type == T_MD || type == T_MF))
  5042.         return(TRUE);
  5043.  
  5044.     return(FALSE);
  5045. }
  5046.  
  5047. /*
  5048. ** WANT_CLASS -- Indicate whether the rr class matches the desired filter
  5049. ** ----------------------------------------------------------------------
  5050. **
  5051. **    Returns:
  5052. **        TRUE if the resource record class matches the filter.
  5053. **        FALSE otherwise.
  5054. **
  5055. **    In regular mode, the queryclass is used to formulate the query,
  5056. **    and the filter is set to C_ANY to filter out any response.
  5057. **    In listmode, we get everything, so the filter is set to the
  5058. **    queryclass to filter out the proper responses.
  5059. **    Note that C_IN is the default queryclass in listmode.
  5060. */
  5061.  
  5062. bool
  5063. want_class(class, filter)
  5064. input int class;            /* resource record class */
  5065. input int filter;            /* class of records we want to see */
  5066. {
  5067.     if (class == filter)
  5068.         return(TRUE);
  5069.  
  5070.     if (filter == C_ANY)
  5071.         return(TRUE);
  5072.  
  5073.     return(FALSE);
  5074. }
  5075.  
  5076. /*
  5077. ** INDOMAIN -- Check whether a name belongs to a zone
  5078. ** --------------------------------------------------
  5079. **
  5080. **    Returns:
  5081. **        TRUE if the given name lies anywhere in the zone, or
  5082. **        if the given name is the same as the zone and may be so.
  5083. **        FALSE otherwise.
  5084. */
  5085.  
  5086. bool
  5087. indomain(name, domain, equal)
  5088. input char *name;            /* the name under consideration */
  5089. input char *domain;            /* the name of the zone */
  5090. input bool equal;            /* set if name may be same as zone */
  5091. {
  5092.     register char *dot;
  5093.  
  5094.     if (sameword(name, domain))
  5095.         return(equal);
  5096.  
  5097.     if (sameword(domain, "."))
  5098.         return(TRUE);
  5099.  
  5100.     dot = index(name, '.');
  5101.     while (dot != NULL)
  5102.     {
  5103.         if (sameword(dot+1, domain))
  5104.             return(TRUE);
  5105.  
  5106.         dot = index(dot+1, '.');
  5107.     }
  5108.  
  5109.     return(FALSE);
  5110. }
  5111.  
  5112. /*
  5113. ** SAMEDOMAIN -- Check whether a name belongs to a zone
  5114. ** ----------------------------------------------------
  5115. **
  5116. **    Returns:
  5117. **        TRUE if the given name lies directly in the zone, or
  5118. **        if the given name is the same as the zone and may be so.
  5119. **        FALSE otherwise.
  5120. */
  5121.  
  5122. bool
  5123. samedomain(name, domain, equal)
  5124. input char *name;            /* the name under consideration */
  5125. input char *domain;            /* the name of the zone */
  5126. input bool equal;            /* set if name may be same as zone */
  5127. {
  5128.     register char *dot;
  5129.  
  5130.     if (sameword(name, domain))
  5131.         return(equal);
  5132.  
  5133.     dot = index(name, '.');
  5134.     if (dot == NULL)
  5135.         return(sameword(domain, "."));
  5136.  
  5137.     if (sameword(dot+1, domain))
  5138.         return(TRUE);
  5139.  
  5140.     return(FALSE);
  5141. }
  5142.  
  5143. /*
  5144. ** GLUERECORD -- Check whether a name is a glue record
  5145. ** ---------------------------------------------------
  5146. **
  5147. **    Returns:
  5148. **        TRUE is this is a glue record.
  5149. **        FALSE otherwise.
  5150. **
  5151. **    The name is supposed to be the name of an address record.
  5152. **    If it lies directly in the given zone, it is considered
  5153. **    an ordinary host within that zone, and not a glue record.
  5154. **    If it does not belong to the given zone at all, is it
  5155. **    here considered to be a glue record.
  5156. **    If it lies in the given zone, but not directly, it is
  5157. **    considered a glue record if it belongs to any of the known
  5158. **    delegated zones of the given zone.
  5159. **    In the root zone itself are no hosts, only glue records.
  5160. */
  5161.  
  5162. bool
  5163. gluerecord(name, domain, zone, nzones)
  5164. input char *name;            /* the name under consideration */
  5165. input char *domain;            /* name of zone being processed */
  5166. input char *zone[];            /* list of known delegated zones */
  5167. input int nzones;            /* number of known delegated zones */
  5168. {
  5169.     register int n;
  5170.  
  5171.     if (sameword(domain, "."))
  5172.         return(TRUE);
  5173.  
  5174.     if (samedomain(name, domain, TRUE))
  5175.         return(FALSE);
  5176.  
  5177.     if (!indomain(name, domain, TRUE))
  5178.         return(TRUE);
  5179.  
  5180.     for (n = 0; n < nzones; n++)
  5181.         if (indomain(name, zone[n], TRUE))
  5182.             return(TRUE);
  5183.  
  5184.     return(FALSE);
  5185. }
  5186.  
  5187. /*
  5188. ** PR_DOTNAME -- Return domain name with trailing dot
  5189. ** --------------------------------------------------
  5190. **
  5191. **    Returns:
  5192. **        Pointer to new domain name.
  5193. */
  5194.  
  5195. char *
  5196. pr_dotname(name)
  5197. input char *name;            /* domain name to append to */
  5198. {
  5199.     static char buf[MAXDNAME+2];    /* buffer to store new domain name */
  5200.     register int n;
  5201.  
  5202.     /* return original if trailing dot present */
  5203.     n = strlength(name);
  5204.     if (n > 0 && name[n-1] == '.')
  5205.         return(name);
  5206.  
  5207.     if (n > MAXDNAME)
  5208.         n = MAXDNAME;
  5209.  
  5210. #ifdef obsolete
  5211.     (void) sprintf(buf, "%.*s.", MAXDNAME, name);
  5212. #endif
  5213.     bcopy(name, buf, n);
  5214.     buf[n] = '.';
  5215.     buf[n+1] = '\0';
  5216.     return(buf);
  5217. }
  5218.  
  5219. /*
  5220. ** PR_TYPE -- Return name of resource record type
  5221. ** ----------------------------------------------
  5222. **
  5223. **    Returns:
  5224. **        Pointer to name of resource record type.
  5225. */
  5226.  
  5227. char *
  5228. pr_type(type)
  5229. input int type;                /* resource record type */
  5230. {
  5231.     static char buf[30];
  5232.  
  5233.     switch (type)
  5234.     {
  5235.         case T_A:       return("A");    /* internet address */
  5236.         case T_NS:      return("NS");    /* authoritative server */
  5237.         case T_MD:      return("MD");    /* mail destination */
  5238.         case T_MF:      return("MF");    /* mail forwarder */
  5239.         case T_CNAME:   return("CNAME");    /* canonical name */
  5240.         case T_SOA:     return("SOA");    /* start of auth zone */
  5241.         case T_MB:      return("MB");    /* mailbox domain name */
  5242.         case T_MG:      return("MG");    /* mail group member */
  5243.         case T_MR:      return("MR");    /* mail rename name */
  5244.         case T_NULL:    return("NULL");    /* null resource record */
  5245.         case T_WKS:     return("WKS");    /* well known service */
  5246.         case T_PTR:     return("PTR");    /* domain name pointer */
  5247.         case T_HINFO:   return("HINFO");    /* host information */
  5248.         case T_MINFO:   return("MINFO");    /* mailbox information */
  5249.         case T_MX:      return("MX");    /* mail routing info */
  5250.         case T_TXT:     return("TXT");    /* descriptive text */
  5251.  
  5252.         case T_RP:      return("RP");    /* responsible person */
  5253.         case T_AFSDB:   return("AFSDB");    /* afs database location */
  5254.         case T_X25:     return("X25");    /* x25 address */
  5255.         case T_ISDN:    return("ISDN");    /* isdn address */
  5256.         case T_RT:      return("RT");    /* route through host */
  5257.         case T_NSAP:    return("NSAP");    /* nsap address */
  5258.         case T_NSAPPTR: return("NSAP-PTR");    /* nsap pointer */
  5259.  
  5260.         case T_UINFO:   return("UINFO");    /* user information */
  5261.         case T_UID:     return("UID");    /* user ident */
  5262.         case T_GID:     return("GID");    /* group ident */
  5263.         case T_UNSPEC:  return("UNSPEC");    /* unspecified binary data */
  5264.  
  5265.         case T_AXFR:    return("AXFR");    /* zone transfer */
  5266.         case T_MAILB:   return("MAILB");    /* matches MB/MR/MG/MINFO */
  5267.         case T_MAILA:   return("MAILA");    /* matches MD/MF */
  5268.         case T_ANY:     return("ANY");    /* matches any type */
  5269.  
  5270.         case T_NONE:    return("resource");    /* not yet determined */
  5271.     }
  5272.  
  5273.     (void) sprintf(buf, "%d", type);
  5274.     return(buf);
  5275. }
  5276.  
  5277. /*
  5278. ** PR_CLASS -- Return name of resource record class
  5279. ** ------------------------------------------------
  5280. **
  5281. **    Returns:
  5282. **        Pointer to name of resource record class.
  5283. */
  5284.  
  5285. char *
  5286. pr_class(class)
  5287. input int class;            /* resource record class */
  5288. {
  5289.     static char buf[30];
  5290.  
  5291.     switch (class)
  5292.     {
  5293.         case C_IN:      return("IN");    /* internet */
  5294.         case C_CSNET:   return("CS");    /* csnet */
  5295.         case C_CHAOS:   return("CH");    /* chaosnet */
  5296.         case C_HS:      return("HS");    /* hesiod */
  5297.         case C_ANY:     return("ANY");    /* any class */
  5298.     }
  5299.  
  5300.     (void) sprintf(buf, "%d", class);
  5301.     return(buf);
  5302. }
  5303.  
  5304. /*
  5305. ** EXPAND_NAME -- Expand compressed domain name in a recource record
  5306. ** -----------------------------------------------------------------
  5307. **
  5308. **    Returns:
  5309. **        Number of bytes advanced in answer buffer.
  5310. **        -1 if there was a format error.
  5311. **
  5312. **    It is assumed that the specified buffer is of sufficient size.
  5313. */
  5314.  
  5315. int
  5316. expand_name(name, type, cp, msg, eom, namebuf)
  5317. input char *name;            /* name of resource record */
  5318. input int type;                /* type of resource record */
  5319. input u_char *cp;            /* current position in answer buf */
  5320. input u_char *msg, *eom;        /* begin and end of answer buf */
  5321. output char *namebuf;            /* address of buf to expand name in */
  5322. {
  5323.     register int n;
  5324.  
  5325.     n = dn_expand(msg, eom, cp, (u_char *)namebuf, MAXDNAME);
  5326.     if (n < 0)
  5327.     {
  5328.         pr_error("expand error in %s record for %s, offset = %s",
  5329.             pr_type(type), name, itoa(cp - msg));
  5330.         h_errno = NO_RECOVERY;
  5331.         return(-1);
  5332.     }
  5333.  
  5334.     /* change root to single dot */
  5335.     if (namebuf[0] == '\0')
  5336.     {
  5337.         namebuf[0] = '.';
  5338.         namebuf[1] = '\0';
  5339.     }
  5340.  
  5341. #ifdef notyet
  5342.     if ((type != T_NONE) && illegal && !valid_name(namebuf, FALSE))
  5343.     {
  5344.         pr_warning("illegal name %s in %s record for %s",
  5345.             namebuf, pr_type(type), name);
  5346.     }
  5347. #endif
  5348.     return(n);
  5349. }
  5350.  
  5351. /*
  5352. ** CHECK_SIZE -- Check whether resource record is of sufficient length
  5353. ** -------------------------------------------------------------------
  5354. **
  5355. **    Returns:
  5356. **        Requested size if current record is long enough.
  5357. **        -1 if current record does not have this many bytes.
  5358. **
  5359. **    Note that HINFO records are very often incomplete since only
  5360. **    one of the two data fields has been filled in and the second
  5361. **    field is missing. So we generate only a warning message.
  5362. */
  5363.  
  5364. int
  5365. check_size(name, type, cp, msg, eor, size)
  5366. input char *name;            /* name of resource record */
  5367. input int type;                /* type of resource record */
  5368. input u_char *cp;            /* current position in answer buf */
  5369. input u_char *msg, *eor;        /* begin and end of answer buf */
  5370. input int size;                /* required record size remaining */
  5371. {
  5372.     if (cp + size > eor)
  5373.     {
  5374.         if (type != T_HINFO)
  5375.             pr_error("incomplete %s record for %s, offset = %s",
  5376.                 pr_type(type), name, itoa(cp - msg));
  5377.         else
  5378.             pr_warning("incomplete %s record for %s, offset = %s",
  5379.                 pr_type(type), name, itoa(cp - msg));
  5380.         h_errno = NO_RECOVERY;
  5381.         return(-1);
  5382.     }
  5383.  
  5384.     return(size);
  5385. }
  5386.  
  5387. /*
  5388. ** VALID_NAME -- Check whether domain name contains invalid characters
  5389. ** -------------------------------------------------------------------
  5390. **
  5391. **    Returns:
  5392. **        TRUE if the name is valid.
  5393. **        FALSE otherwise.
  5394. **
  5395. **    The total size of a compound name should not exceed MAXDNAME.
  5396. **    We assume that this is true. Its individual components between
  5397. **    dots should not be longer than 64. This is not checked here.
  5398. **    Only alphanumeric characters and dash '-' may be used (dash
  5399. **    only in the middle). We only check the individual characters.
  5400. **
  5401. **    The label '*' can in principle be used anywhere to indicate
  5402. **    wildcarding. It is valid only in the LHS resource record name.
  5403. **    In definitions in zone files only as the first component.
  5404. **    Used primarily in wildcard MX record definitions.
  5405. */
  5406.  
  5407. bool
  5408. valid_name(name, wildcard)
  5409. input char *name;            /* domain name to check */
  5410. input bool wildcard;            /* set if wildcard is allowed */
  5411. {
  5412.     register char *p;
  5413.  
  5414.     for (p = name; *p != '\0'; p++)
  5415.     {
  5416.         if (is_alnum(*p) || (*p == '-'))
  5417.             continue;
  5418.  
  5419.         /* start of a new component */
  5420.         if (*p == '.')
  5421.             continue;
  5422.  
  5423.         /* allow '*' for use in wildcard names */
  5424.         if ((*p == '*') && wildcard)
  5425.             continue;
  5426.  
  5427.         /* silently allowed widespread exceptions */
  5428.         if (illegal && index(illegal, *p) != NULL)
  5429.             continue;
  5430.  
  5431.         return(FALSE);
  5432.     }
  5433.  
  5434.     return(TRUE);
  5435. }
  5436.  
  5437. /*
  5438. ** XALLOC -- Allocate or reallocate additional memory
  5439. ** --------------------------------------------------
  5440. **
  5441. **    Returns:
  5442. **        Pointer to (re)allocated buffer space.
  5443. **        Aborts if the requested memory could not be obtained.
  5444. */
  5445.  
  5446. ptr_t *
  5447. xalloc(buf, size)
  5448. register ptr_t *buf;            /* current start of buffer space */
  5449. input siz_t size;            /* number of bytes to allocate */
  5450. {
  5451.     if (buf == NULL)
  5452.         buf = malloc(size);
  5453.     else
  5454.         buf = realloc(buf, size);
  5455.  
  5456.     if (buf == NULL)
  5457.     {
  5458.         errmsg("Out of memory");
  5459.         exit(EX_OSERR);
  5460.     }
  5461.  
  5462.     return(buf);
  5463. }
  5464.  
  5465. /*
  5466. ** ITOA -- Convert integer value to ascii string
  5467. ** ---------------------------------------------
  5468. **
  5469. **    Returns:
  5470. **        Pointer to string.
  5471. */
  5472.  
  5473. char *
  5474. itoa(n)
  5475. input int n;                /* value to convert */
  5476. {
  5477.     static char buf[30];
  5478.  
  5479.     (void) sprintf(buf, "%d", n);
  5480.     return(buf);
  5481. }
  5482.  
  5483.  
  5484. /*
  5485. ** UTOA -- Convert unsigned integer value to ascii string
  5486. ** ------------------------------------------------------
  5487. **
  5488. **    Returns:
  5489. **        Pointer to string.
  5490. */
  5491.  
  5492. char *
  5493. utoa(n)
  5494. input int n;                /* value to convert */
  5495. {
  5496.     static char buf[30];
  5497.  
  5498.     (void) sprintf(buf, "%u", (unsigned)n);
  5499.     return(buf);
  5500. }
  5501.  
  5502. /*
  5503. ** STOA -- Extract partial ascii string
  5504. ** ------------------------------------
  5505. **
  5506. **    Returns:
  5507. **        Pointer to string.
  5508. */
  5509.  
  5510. char *
  5511. stoa(cp, size)
  5512. input u_char *cp;            /* current position in answer buf */
  5513. input int size;                /* number of bytes to extract */
  5514. {
  5515.     static char buf[MAXDLEN+1];
  5516.  
  5517.     if (size > MAXDLEN)
  5518.         size = MAXDLEN;
  5519.  
  5520. #ifdef obsolete
  5521.     if (size > 0)
  5522.         (void) sprintf(buf, "%.*s", size, (char *)cp);
  5523.     else
  5524.         (void) sprintf(buf, "%s", "");
  5525. #endif
  5526.     bcopy((char *)cp, buf, size);
  5527.     buf[size] = '\0';
  5528.     return(buf);
  5529. }
  5530.  
  5531. /*
  5532. ** NSAP_NTOA -- Convert binary nsap address to ascii
  5533. ** -------------------------------------------------
  5534. **
  5535. **    Returns:
  5536. **        Pointer to string.
  5537. **
  5538. **    This is experimental. It assumes that an nsap address
  5539. **    is encoded in binary form in the resource record.
  5540. **    It in unclear from RFC 1348 how the encoding should be.
  5541. **    Also the hierarchical structure remains undecided.
  5542. */
  5543.  
  5544. #define hexdigit(x)     ((x) < 10 ? '0' + (x) : 'A' + (x) - 10);
  5545.  
  5546. char *
  5547. nsap_ntoa(cp, size)
  5548. input u_char *cp;            /* current position in answer buf */
  5549. input int size;                /* number of bytes to extract */
  5550. {
  5551.     static char buf[2*MAXDLEN+1];
  5552.     register char *p;
  5553.     register int i, n;
  5554.  
  5555.     if (size > MAXDLEN)
  5556.         size = MAXDLEN;
  5557.  
  5558.     for (p = buf, i = 0; i < size; i++, cp++)
  5559.     {
  5560.         n = ((int)(*cp) >> 4) & 0x0f;
  5561.         *p++ = hexdigit(n);
  5562.         n = (int)(*cp) & 0x0f;
  5563.         *p++ = hexdigit(n);
  5564.     }
  5565.     *p = '\0';
  5566.  
  5567.     return(buf);
  5568. }
  5569.