home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / dns / host / host.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-04  |  102.5 KB  |  4,210 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.  * Extensively modified by E. 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.  * Also available in this directory are patched versions of the
  34.  * BIND 4.8.3 nameserver and resolver library which you may need
  35.  * to fully exploit the features of this program, although they
  36.  * are not mandatory. See the file 'README_FIRST' for details.
  37.  *
  38.  * You are kindly requested to report bugs and make suggestions
  39.  * for improvements to the author at the given email address,
  40.  * and to not re-distribute your own modifications to others.
  41.  */
  42.  
  43. /*
  44.  *            New features
  45.  *
  46.  * - Major overhaul of the whole code.
  47.  * - Very rigid error checking, with more verbose error messages.
  48.  * - Zone listing section completely rewritten.
  49.  * - It is now possible to do recursive listings into subdomains.
  50.  * - Maintain resource record statistics during zone listings.
  51.  * - Maintain count of hosts during zone listings.
  52.  * - Exploit multiple server addresses if available.
  53.  * - Option to exploit only primary server for zone transfers.
  54.  * - Option to exclude info from names that do not reside in a domain.
  55.  * - Implement timeout handling during connect and read.
  56.  * - Write resource record output to optional logfile.
  57.  * - Special MB tracing by recursively expanding MR and MG records.
  58.  * - Special mode to check SOA records at each nameserver for domain.
  59.  * - Special mode to check inverse mappings of host addresses.
  60.  * - Code is extensively documented.
  61.  */
  62.  
  63. /*
  64.  *            Publication history
  65.  *
  66.  * Revision:    910129
  67.  *            Maintain count of hosts during domain listings.
  68.  *            Check for hosts with same name as subdomain.
  69.  *            Add -H option for special host count mode.
  70.  *            Recognize obsolete T_MAILA.
  71.  * Revision:    910415
  72.  *            Improve finding of subdomain names.
  73.  *            Allow subdomains not directly within domain.
  74.  *            Check for unauthoritative glue records.
  75.  *            Add -T option to print ttl when non-verbose.
  76.  *            Improve connect timeout handling.
  77.  *            Improve dotted quad parsing.
  78.  *            Minimum ttl is now called default ttl.
  79.  * Revision:    910905
  80.  *            Improve counting of hosts within domain.
  81.  *            Allow hosts not directly within domain.
  82.  *            Increase (static) maximum number of hosts.
  83.  * Revision:    910923
  84.  *            Count gateway hosts (with multiple addresses).
  85.  *            Add -G option to list gateway hosts.
  86.  * Revision:    911010
  87.  *            Don't recurse on cnames if querytype is cname.
  88.  * Revision:    911201
  89.  *            Option -T also prints MX preference value.
  90.  *            Save name of longest hostname found (just for fun).
  91.  *            Undocumented option -g to select long names (fun).
  92.  * Revision:    920315
  93.  *            Improve counting of hosts within domain.
  94.  *            Discard glue records not directly within domain.
  95.  *            Keep track of hosts with duplicate address.
  96.  *            Add -D option to list duplicate hosts.
  97.  *            Add -E option to list extrazone hosts.
  98.  *            Miscellaneous casting and typing cleanup.
  99.  *            Increase (static) number of possible subdomains.
  100.  * Revision:    920616
  101.  *            Allocate list of zonenames dynamically, not statically.
  102.  *            Move and slightly modify the test for fake hosts.
  103.  *            Suppress host count statistics during inverse listing.
  104.  *            Miscellaneous documentation updates.
  105.  * Revision:    920624
  106.  *            Lookup server name before changing nameserver address.
  107.  *            Handle possible truncation in zone transfers.
  108.  *            Provide private simplified version of res_send().
  109.  *            Add -u option to force virtual circuit connections.
  110.  *            Move all socket I/O routines to separate send.c.
  111.  * Revision:    920702
  112.  *            Recognize alternative program call names.
  113.  *            Distinguish between auth and non-auth NO_DATA.
  114.  * Revision:    921005
  115.  *            Anticipate ultrix specific resolv.h
  116.  *            Miscellaneous declaration changes.
  117.  *            Some reshuffling of code.
  118.  */
  119.  
  120. #ifndef lint
  121. static char Version[] = "@(#)host.c    e07@nikhef.nl (Eric Wassenaar) 921005";
  122. #endif
  123.  
  124. /*
  125.  *            Compilation options
  126.  *
  127.  * This program usually compiles without special compilation options,
  128.  * but for some platforms you have to define the following settings:
  129.  *
  130.  * #if defined(_AIX)
  131.  *    DEFS = -D_BSD -D_BSD_INCLUDES -U__STR__ -DBIT_ZERO_ON_LEFT
  132.  *
  133.  * #if defined(hpux)
  134.  *    DEFS = -DSYSV_SETVBUF
  135.  *
  136.  * #if defined(ultrix)
  137.  *    DEFS = -DULTRIX_RESOLV
  138.  *    Only if you are using the default ultrix <resolv.h>
  139.  */
  140.  
  141. /*
  142.  *            Miscellaneous notes
  143.  *
  144.  * This program should be linked explicitly with the BIND resolver library
  145.  * in case the default gethostbyname() or gethostbyaddr() routines use a
  146.  * non-standard strategy for retrieving information. These functions in the
  147.  * resolver library call on the nameserver, and fall back on the hosts file
  148.  * only if no nameserver is running (ECONNREFUSED).
  149.  *
  150.  * You may also want to link this program with the BIND resolver library if
  151.  * your default library has not been compiled with DEBUG printout enabled.
  152.  *
  153.  * The version of the resolver should be BIND 4.8.2 or later. The crucial
  154.  * include files are <netdb.h>, (resolv.h>, <arpa/nameser.h>. These files
  155.  * are assumed to be present in the /usr/include directory.
  156.  *
  157.  * The resolver code depends on the definition of the BSD pre-processor
  158.  * variable. This variable is usually defined in the file <sys/param.h>.
  159.  *
  160.  * The definition of this variable determines the method how to handle
  161.  * datagram connections. This may not work properly on all platforms
  162.  * (e.g. sun). A fix for this is available (see above).
  163.  *
  164.  * The hostent struct defined in <netdb.h> is assumed to handle multiple
  165.  * addresses in h_addr_list[]. Usually this is true if BSD >= 43.
  166.  *
  167.  * Your version of the nameserver may not handle queries about top-level
  168.  * domains properly. It needs a patch if it appends the default domain
  169.  * to single names for which it has no data cached. A fix for this is
  170.  * available (see above).
  171.  *
  172.  * For smooth porting to both BSD and SYSV environments:
  173.  * - Do not use the function value returned by sprintf().
  174.  *   It is of different type in the two environments.
  175.  * - Use <string.h> instead of <strings.h>.
  176.  *
  177.  * The treatment of TXT records has changed from 4.8.2 to 4.8.3. Formerly,
  178.  * the data consisted simply of the text string. Now, the text string is
  179.  * preceded by the character count with a maximum of 255, and multiple
  180.  * strings are embedded if the total character count exceeds 255.
  181.  * We handle only the new situation in this program, assuming that nobody
  182.  * uses TXT records before 4.8.3.
  183.  *
  184.  * Note that in 4.8.3 PACKETSZ from nameser.h is still at 512, which is
  185.  * the maximum possible packet size for datagrams, whereas MAXDATA from
  186.  * db.h has increased from 256 to 2048.
  187.  * The nameserver reads queries in a buffer of size BUFSIZ.
  188.  *
  189.  * The gethostbyname() routine in 4.8.3 interprets dotted quads (if not
  190.  * terminated with a dot) and simulates a gethostbyaddr(), but we will
  191.  * not rely on it, and handle dotted quads ourselves.
  192.  *
  193.  * On some systems a bug in the _doprnt() routine exists which prevents
  194.  * printf("%.*s", n, string) to be printed correctly if n == 0.
  195.  *
  196.  * This program has not been optimized for speed. Especially the memory
  197.  * management is simple and straightforward.
  198.  */
  199.  
  200. /*
  201.  *            Terminology used
  202.  *
  203.  * Gateway hosts.
  204.  * These are hosts that have more that one address registered under
  205.  * the same name. Obviously we cannot recognize a gateway host if it
  206.  * has different names associated with its different addresses.
  207.  *
  208.  * Duplicate hosts.
  209.  * These are non-gateway hosts of which the address was found earlier
  210.  * but with a different name, possibly in a totally different domain.
  211.  * Such hosts should not be counted again in the overall host count.
  212.  * This situation notably occurs in e.g. the "ac.uk" domain which has
  213.  * many names registered in both the long and the abbreviated form,
  214.  * such as 'host.department.university.ac.uk' and 'host.dept.un.ac.uk'.
  215.  * This is probably not an error per se. It is an error if some domain
  216.  * has registered a foreign address under a name within its own domain.
  217.  * To recognize duplicate hosts when traversing many zones, we have to
  218.  * maintain a global list of host addresses. To simplify things, only
  219.  * single address hosts are handled as such.
  220.  *
  221.  * Extrazone hosts.
  222.  * These are hosts which belong to a domain but which are not residing
  223.  * directly within the domain under consideration and which are not
  224.  * glue records for a subdomain of the given domain. E.g. if we are
  225.  * processing the domain 'bar' and find 'host.foo.bar' but 'foo.bar'
  226.  * is not a registered subdomain of 'bar' then it is considered to be
  227.  * an extrazone host. This is not necessarily an error, but it could be.
  228.  */
  229.  
  230. /*
  231.  *        Usage: host [options] name [server]
  232.  *
  233.  * Regular command line options:
  234.  * ----------------------------
  235.  *
  236.  * -t type    specify query type; default is T_A for normal mode
  237.  *
  238.  * -a        specify query type T_ANY
  239.  *
  240.  * -v        print verbose messages (-vv is very verbose)
  241.  *
  242.  * -d        print debugging output (-dd prints even more)
  243.  *
  244.  * Special mode options.
  245.  * --------------------
  246.  *
  247.  * -l        special mode to generate zone listing for domain
  248.  *
  249.  * -L level    do recursive domain listing/checking this levels deep
  250.  *
  251.  * -p        use primary nameserver of domain for zone transfers
  252.  *
  253.  * -S        print zone resource record statistics
  254.  *
  255.  * -H        special mode to count hosts residing in domain
  256.  *
  257.  * -G        same as -H but lists gateway hosts in addition
  258.  *
  259.  * -E        same as -H but lists extrazone hosts in addition
  260.  *
  261.  * -D        same as -H but lists duplicate hosts in addition
  262.  *
  263.  * -C        special mode to check SOA records for domain
  264.  *
  265.  * -A        special mode to check reverse mappings of host addresses
  266.  *
  267.  * Miscellaneous options.
  268.  * ---------------------
  269.  *
  270.  * -T        print ttl value during non-verbose output
  271.  *
  272.  * -e        exclude info from names that do not reside in domain
  273.  *
  274.  * -f file    log resource record output also in given file
  275.  *
  276.  * -i        generate inverse in-addr.arpa query for dotted quad
  277.  *
  278.  * -m        specify query type T_MAILB and trace MB records
  279.  *
  280.  * -q        be quiet about some non-fatal errors
  281.  *
  282.  * Seldom used options.
  283.  * -------------------
  284.  *
  285.  * -c class    specify query class; default is C_IN
  286.  *
  287.  * -r        do not use recursion when querying nameserver
  288.  *
  289.  * -s secs    specify timeout value in seconds; default is 2 * 5
  290.  *
  291.  * -u        use virtual circuit instead of datagram for queries
  292.  *
  293.  * -w        wait until nameserver becomes available
  294.  *
  295.  */
  296.  
  297. static char Usage[] =
  298. "\
  299. Usage:      host [-v] [-a] [-t querytype]  name  [server]\n\
  300. Listing:    host [-v] [-a] [-t querytype]  -l domain  [server]\n\
  301. Hostcount:  host [-v] -H [-D] [-E] [-G] domain\n\
  302. Check soa:  host [-v] -C domain\n\
  303. Addrcheck:  host [-v] -A host\n\
  304. Special options: [-L level] [-S] [-p]\n\
  305. Common  options: [-T] [-d] [-e] [-f logfile] [-i] [-m] [-q]\n\
  306. Other   options: [-c class] [-r] [-s secs] [-u] [-w]\
  307. ";
  308.  
  309. #define justfun            /* this is only for fun */
  310.  
  311. #ifdef DEBUG
  312. #define assert(condition)\
  313. {\
  314.     if (!(condition))\
  315.     {\
  316.         (void) fprintf(stderr, "assertion botch: ");\
  317.         (void) fprintf(stderr, "%s(%d): ", __FILE__, __LINE__);\
  318.         (void) fprintf(stderr, "%s\n", "condition");\
  319.         exit(EX_SOFTWARE);\
  320.     }\
  321. }
  322. #else
  323. #define assert(condition)
  324. #endif
  325.  
  326. #include <stdio.h>
  327. #include <string.h>
  328. #include <ctype.h>
  329. #include <errno.h>
  330. #include <sysexits.h>
  331. #include <netdb.h>
  332.  
  333. #include <sys/param.h>
  334. #include <sys/socket.h>
  335. #include <netinet/in.h>
  336. #include <arpa/nameser.h>
  337. #include <resolv.h>
  338.  
  339. #define input            /* read-only input parameter */
  340. #define output            /* modified output parameter */
  341.  
  342. typedef char    ptr_t;        /* generic pointer type; will become void */
  343. typedef u_int    siz_t;        /* general size type; will become int */
  344.  
  345. typedef int    bool;        /* boolean type */
  346. #define TRUE    1
  347. #define FALSE    0
  348.  
  349. #ifndef T_TXT
  350. #define T_TXT    16
  351. #endif
  352. #ifndef C_HS
  353. #define C_HS    4
  354. #endif
  355. #ifndef NO_DATA
  356. #define NO_DATA    NO_ADDRESS    /* used here only in case authoritative */
  357. #endif
  358. #define NO_RREC    5        /* used for non-authoritative NO_DATA */
  359.  
  360. #define T_NONE    0        /* yet unspecified resource record type */
  361. #define T_FIRST    T_A        /* first possible type in resource record */
  362. #define T_LAST    T_AXFR - 1    /* last  possible type in resource record */
  363.  
  364. #define MAXADDRS 35        /* max address count from gethostnamadr.c */
  365.  
  366. #define NOT_DOTTED_QUAD ((u_long)-1)
  367. #define LOCALHOST_ADDR    ((u_long)0x7f000001)
  368.  
  369. #define bitset(a,b)    (((a) & (b)) != 0)
  370. #define sameword(a,b)    (strcasecmp(a,b) == 0)
  371. #define samepart(a,b)    (strncasecmp(a,b,strlen(b)) == 0)
  372. #define fakename(a)    (samepart(a,"localhost.") || samepart(a,"loopback."))
  373. #define fakeaddr(a)    (((a) == 0) || ((a) == htonl(LOCALHOST_ADDR)))
  374.  
  375. #define newstr(a)    strcpy((char *)xalloc((ptr_t *)NULL, strlen(a)+1), a)
  376. #define newblk(a,n,t)    (t *)xalloc((ptr_t *)a, (int)((n)*sizeof(t)))
  377. #define xfree(a)    (void) free((ptr_t *)a)
  378. #define incopy(a)    *((struct in_addr *)a)
  379.  
  380. #ifdef ULTRIX_RESOLV
  381. #define nslist(i)    _res.ns_list[i].addr
  382. #else
  383. #define nslist(i)    _res.nsaddr_list[i]
  384. #endif
  385.  
  386. #if PACKETSZ > 1024
  387. #define MAXPACKET PACKETSZ
  388. #else
  389. #define MAXPACKET 1024
  390. #endif
  391.  
  392. typedef union {
  393.     HEADER header;
  394.     u_char packet[MAXPACKET];
  395. } querybuf;
  396.  
  397. #ifdef lint
  398. #define EXTERN
  399. #else
  400. #define EXTERN extern
  401. #endif
  402.  
  403. EXTERN int errno;
  404. EXTERN int h_errno;        /* defined in gethostnamadr.c */
  405. EXTERN struct state _res;    /* defined in res_init.c */
  406.  
  407. int record_stats[T_ANY+1];    /* count of resource records per type */
  408.  
  409. char cnamebuf[MAXDNAME+1];
  410. char *cname = NULL;        /* name to which CNAME is aliased */
  411.  
  412. char mnamebuf[MAXDNAME+1];
  413. char *mname = NULL;        /* name to which MR or MG is aliased */
  414.  
  415. char soanamebuf[MAXDNAME+1];
  416. char *soaname = NULL;        /* domain name of SOA record */
  417.  
  418. char subnamebuf[MAXDNAME+1];
  419. char *subname = NULL;        /* domain name of NS record */
  420.  
  421. char adrnamebuf[MAXDNAME+1];
  422. char *adrname = NULL;        /* domain name of A record */
  423.  
  424. u_long address;            /* internet address of A record */
  425.  
  426. char servername[MAXDNAME+1];
  427. char *server = NULL;        /* name of explicit server to query */
  428.  
  429. char *logfilename = NULL;    /* name of log file */
  430. FILE *logfile = NULL;        /* default is stdout only */
  431.  
  432. char *queryname = NULL;        /* the name about which to query */
  433. int querytype = T_NONE;        /* the type of the query */
  434. int queryclass = C_IN;        /* the class of the query */
  435.  
  436. int debug = 0;            /* print resolver debugging output */
  437. int verbose = 0;        /* verbose mode for extra output */
  438. bool quiet = FALSE;        /* suppress some warning messages */
  439. bool inverse = FALSE;        /* generate inverse in-addr.arpa queries */
  440. bool primary = FALSE;        /* use primary server for zone transfers */
  441. bool ttlprint = FALSE;        /* print ttl value in non-verbose mode */
  442. bool waitmode = FALSE;        /* wait until server becomes available */
  443. bool mailmode = FALSE;        /* trace MG and MR into MB records */
  444. bool addrmode = FALSE;        /* check reverse mappings of addresses */
  445. bool listmode = FALSE;        /* generate zone listing of domain */
  446. bool hostmode = FALSE;        /* count real hosts residing within domain */
  447. bool duplmode = FALSE;        /* list duplicate hosts within domain */
  448. bool extrmode = FALSE;        /* list extrazone hosts within domain */
  449. bool gatemode = FALSE;        /* list gateway hosts within domain */
  450. bool checkmode = FALSE;        /* check SOA records at each nameserver */
  451. int recursive = 0;        /* recursive listmode maximum level */
  452. bool exclusive = FALSE;        /* exclude records that are not in domain */
  453. bool statistics = FALSE;    /* print resource record statistics */
  454. #ifdef justfun
  455. int namelen = 0;        /* select records exceeding this length */
  456. #endif
  457.  
  458. extern u_long inet_addr();    /* (char *) */
  459. extern char *inet_ntoa();    /* (struct in_addr) */
  460. extern char *strcpy();        /* (char *, char *) */
  461. extern char *rindex();        /* (char *, char) */
  462. extern char *index();        /* (char *, char) */
  463. extern void exit();        /* (int) */
  464.  
  465. /* main.c */
  466. int main();            /* (int, char **) */
  467. bool execute();            /* (u_long) */
  468. void set_server();        /* (char *) */
  469. void fatal();            /* (char *, ...) */
  470. void errmsg();            /* (char *, ...) */
  471.  
  472. /* info.c */
  473. bool get_hostinfo();        /* (char *) */
  474. bool get_domaininfo();        /* (char *, char*) */
  475. int get_info();            /* (querybuf *, char *, int, int) */
  476. int print_info();        /* (querybuf *, int, char *, int) */
  477. void doprintf();        /* (char *, ...) */
  478. u_char *next_rr();        /* (char *, u_char*, u_char*, u_char*, int) */
  479. u_char *skip_qr();        /* (char *, u_char*, u_char*, u_char*) */
  480.  
  481. /* list.c */
  482. bool list_domain();        /* (char *) */
  483. int find_servers();        /* (char *) */
  484. int get_servers();        /* (char *) */
  485. int get_nsinfo();        /* (querybuf *, int, char *) */
  486. bool transfer_zone();        /* (char *, int, struct in_addr) */
  487. bool get_zone();        /* (char *, int, struct in_addr) */
  488. char *get_primary();        /* (char *) */
  489. bool check_domain();        /* (char *) */
  490. int get_soainfo();        /* (querybuf *, int, char *) */
  491. void check_soa();        /* (char *) */
  492.  
  493. /* addr.c */
  494. bool check_addr();        /* (char *) */
  495. bool check_name();        /* (u_long) */
  496.  
  497. /* util.c */
  498. int parse_type();        /* (char *) */
  499. int parse_class();        /* (char *) */
  500. char *in_addr_arpa();        /* (char *) */
  501. void print_host();        /* (char *, struct hostent *) */
  502. void print_res();        /* (void) */
  503. void print_statistics();    /* (char *, int) */
  504. void clear_statistics();    /* (void) */
  505. void print_types();        /* (char *, int) */
  506. void ns_error();        /* (char *, int) */
  507. char *decode_error();        /* (int) */
  508. void print_status();        /* (querybuf *) */
  509. void pr_error();        /* (char *, ...) */
  510. void pr_warning();        /* (char *, ...) */
  511. bool want_rr();            /* (int, int) */
  512. bool indomain();        /* (char *, char *, bool) */
  513. bool samedomain();        /* (char *, char *, bool) */
  514. bool gluerecord();        /* (char *, char *, char **, int) */
  515. char *pr_type();        /* (int) */
  516. char *pr_class();        /* (int) */
  517. int expand();            /* (char *, int, u_char*, u_char*, u_char*, char *) */
  518. int check_size();        /* (char *, int, u_char*, u_char*, u_char*, int) */
  519. ptr_t *xalloc();        /* (ptr_t *, int) */
  520.  
  521. /* send.c */
  522. int res_send();            /* (char *, int, char *, int) */
  523. int _res_connect();        /* (int, struct sockaddr_in *, int) */
  524. int _res_write();        /* (int, char *, int) */
  525. int _res_read();        /* (int, char *, int) */
  526.  
  527. /*
  528. ** MAIN -- Start of program host
  529. ** -----------------------------
  530. **
  531. **    Exits:
  532. **        EX_OK        Operation successfully completed
  533. **        EX_UNAVAILABLE    Could not obtain requested information
  534. **        EX_CANTCREAT    Could not create specified logfile
  535. **        EX_OSERR    Could not obtain resources
  536. **        EX_USAGE    Improper parameter/option specified
  537. **        EX_SOFTWARE    Assertion botch in DEBUG mode
  538. */
  539.  
  540. int
  541. main(argc, argv)
  542. int argc;
  543. char *argv[];
  544. {
  545.     register char *option;
  546.     u_long addr;            /* explicit address of query */
  547.     bool result;            /* result status of action taken */
  548.     char *program;            /* name that host was called with */
  549.  
  550. /*
  551.  * Synchronize stdout and stderr in case output is redirected.
  552.  * Note that some SYSV implementations may have setlinebuf().
  553.  */
  554. #if defined(SYSV_SETVBUF)
  555.     setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
  556. #else
  557.     setlinebuf(stdout);
  558. #endif
  559.  
  560. /*
  561.  * Initialize resolver. See print_res() for details.
  562.  * Pickup current values and set new defaults.
  563.  * Query for optional server is also done with new defaults.
  564.  * Old defaults are (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
  565.  */
  566.     (void) res_init();
  567.  
  568.     /* we handle default domains ourselves, thank you */
  569.     _res.options |=  RES_DEFNAMES;
  570.     _res.options &= ~RES_DNSRCH;
  571.  
  572.     _res.options |=  RES_RECURSE;
  573.     _res.options &= ~RES_DEBUG;
  574.     _res.options &= ~RES_USEVC;
  575.  
  576.     _res.retry = 2;        /* number  of retries, default = 4 */
  577.     _res.retrans = 5;    /* timeout in seconds, default = 5 or 6 */
  578.  
  579. /*
  580.  * Check if host was called with a different name.
  581.  */
  582.     program = rindex(argv[0], '/');
  583.     if (program++ == NULL)
  584.         program = argv[0];
  585.  
  586.     /* check for resource record names */
  587.     querytype = parse_type(program);
  588.     if (querytype < 0)
  589.         querytype = T_NONE;
  590.  
  591.     /* check for zone listing abbreviation */
  592.     if (sameword(program, "zone"))
  593.         listmode = TRUE;
  594.  
  595. /*
  596.  * Scan command line options and flags.
  597.  */
  598.     while (argc > 2 && argv[1][0] == '-')
  599.     {
  600.         for (option = &argv[1][1]; *option != '\0'; option++)
  601.         {
  602.         switch (*option)
  603.         {
  604.             case 'w' :
  605.             waitmode = TRUE;
  606.             _res.retry = 2;
  607.             _res.retrans = 5;
  608.             break;
  609.  
  610.             case 's' :
  611.             _res.retry = 2;
  612.             _res.retrans = atoi(argv[2]);
  613.             if (_res.retrans <= 0)
  614.                 fatal("Invalid timeout value %s", argv[2]);
  615.             argv++; argc--;
  616.             break;
  617.  
  618.             case 'r' :
  619.             _res.options &= ~RES_RECURSE;
  620.             break;
  621.  
  622.             case 'u' :
  623.             _res.options |= RES_USEVC;
  624.             break;
  625.  
  626.             case 'd' :
  627.             debug++;        /* increment debugging level */
  628.             _res.options |= RES_DEBUG;
  629.             break;
  630.  
  631.             case 'v' :
  632.             verbose++;        /* increment verbosity level */
  633.             break;
  634.  
  635.             case 'q' :
  636.             quiet = TRUE;
  637.             break;
  638.  
  639.             case 'i' :
  640.             inverse = TRUE;
  641.             break;
  642.  
  643.             case 'p' :
  644.             primary = TRUE;
  645.             break;
  646.  
  647.             case 'e' :
  648.             exclusive = TRUE;
  649.             break;
  650.  
  651.             case 'S' :
  652.             statistics = TRUE;
  653.             break;
  654.  
  655.             case 'T' :
  656.             ttlprint = TRUE;
  657.             break;
  658.  
  659.             case 'A' :
  660.             addrmode = TRUE;
  661.             break;
  662.  
  663.             case 'D':
  664.             case 'E':
  665.             case 'G':
  666.             if (*option == 'D')
  667.                 duplmode = TRUE;
  668.             if (*option == 'E')
  669.                 extrmode = TRUE;
  670.             if (*option == 'G')
  671.                 gatemode = TRUE;
  672.             /* fall through */
  673.  
  674.             case 'H' :
  675.             hostmode = TRUE;
  676.             listmode = TRUE;
  677.             if (querytype == T_NONE)
  678.                 querytype = -1;    /* suppress zone data output */
  679.             break;
  680.  
  681.             case 'C' :
  682.             checkmode = TRUE;
  683.             listmode = TRUE;
  684.             if (querytype == T_NONE)
  685.                 querytype = -1;    /* suppress zone data output */
  686.             break;
  687.  
  688.             case 'l' :
  689.             listmode = TRUE;
  690.             break;
  691.  
  692.             case 'L' :
  693.             recursive = atoi(argv[2]);
  694.             if (recursive <= 0)
  695.                 fatal("Invalid recursion level %s", argv[2]);
  696.             argv++; argc--;
  697.             break;
  698.  
  699.             case 'f' :
  700.             logfilename = argv[2];
  701.             argv++; argc--;
  702.             break;
  703.  
  704.             case 'c' :
  705.             queryclass = parse_class(argv[2]);
  706.             if (queryclass < 0)
  707.                 fatal("Invalid query class %s", argv[2]);
  708.             argv++; argc--;
  709.             break;
  710.  
  711.             case 't' :
  712.             querytype = parse_type(argv[2]);
  713.             if (querytype < 0)
  714.                 fatal("Invalid query type %s", argv[2]);
  715.             argv++; argc--;
  716.             break;
  717.  
  718.             case 'a' :
  719.             querytype = T_ANY;    /* filter anything available */
  720.             break;
  721.  
  722.             case 'm' :
  723.             mailmode = TRUE;
  724.             querytype = T_MAILB;    /* filter MINFO/MG/MR/MB data */
  725.             break;
  726. #ifdef justfun
  727.             case 'g' :
  728.             namelen = atoi(argv[2]);
  729.             if (namelen <= 0)
  730.                 fatal("Invalid length %s", argv[2]);
  731.             argv++; argc--;
  732.             break;
  733. #endif
  734.             default:
  735.             fatal(Usage);
  736.         }
  737.         }
  738.  
  739.         argv++; argc--;
  740.     }
  741.  
  742.     /* must have at least one argument */
  743.     if (argc < 2 || argv[1][0] == '-')
  744.         fatal(Usage);
  745.  
  746.     /* check for nonsense input names */
  747.     if (strlen(argv[1]) > MAXDNAME)
  748.         fatal("Query name %s too long", argv[1]);
  749.  
  750.     if (argc > 2 && strlen(argv[2]) > MAXDNAME)
  751.         fatal("Server name %s too long", argv[2]);
  752.  
  753. /*
  754.  * Analyze name and type to be queried about.
  755.  * In regular mode, the querytype is used to formulate the nameserver
  756.  * query, and any response is filtered out when processing the answer.
  757.  * In listmode, the querytype is used to filter out the proper records.
  758.  */
  759.     queryname = argv[1];
  760.     if (queryname[0] == '\0')
  761.         queryname = ".";
  762.  
  763.     if (sameword(queryname, "."))
  764.         addr = NOT_DOTTED_QUAD;
  765.     else
  766.         addr = inet_addr(queryname);
  767.  
  768.     /* invert dotted quad if so requested */
  769.     if ((addr != NOT_DOTTED_QUAD) && inverse)
  770.     {
  771.         queryname = in_addr_arpa(queryname);
  772.         if (queryname == NULL)
  773.             fatal("Invalid dotted quad %s", argv[1]);
  774.  
  775.         addr = NOT_DOTTED_QUAD;
  776.     }
  777.     else
  778.         inverse = FALSE;
  779.  
  780.     /* set querytype for regular mode if unspecified */
  781.     if ((querytype == T_NONE) && !listmode)
  782.     {
  783.         if ((addr != NOT_DOTTED_QUAD) || inverse)
  784.             querytype = T_PTR;
  785.         else
  786.             querytype = T_A;
  787.     }
  788.  
  789.     /* cannot have dotted quad in listmode */
  790.     if (listmode && (addr != NOT_DOTTED_QUAD))
  791.         fatal("Invalid query name %s", queryname);
  792.  
  793.     /* must have regular name or dotted quad in addrmode */
  794.     if (addrmode && inverse)
  795.         fatal("Invalid query name %s", queryname);
  796.  
  797.     /* show what we are going to query about */
  798.     if (verbose)
  799.         print_types(queryname, querytype);
  800.  
  801. /*
  802.  * Check for possible alternative server.
  803.  */
  804.     if (argc > 2)
  805.         set_server(argv[2]);
  806.  
  807.     /* show the new resolver database */
  808.     if (debug > 1 || verbose > 1)
  809.         print_res();
  810.  
  811. /*
  812.  * Open log file if requested.
  813.  */
  814.     if (logfilename)
  815.     {
  816.         logfile = fopen(logfilename, "w");
  817.         if (logfile == NULL)
  818.         {
  819.             perror(logfilename);
  820.             exit(EX_CANTCREAT);
  821.         }
  822.     }
  823.  
  824. /*
  825.  * All set. Perform requested function.
  826.  */
  827.     result = execute(addr);
  828.  
  829.     if (result == FALSE)
  830.         exit(EX_UNAVAILABLE);
  831.  
  832.     exit(EX_OK);
  833.     /*NOTREACHED*/
  834. }
  835.  
  836. /*
  837. ** EXECUTE -- Perform the requested function
  838. ** -----------------------------------------
  839. **
  840. **    Returns:
  841. **        TRUE if information was obtained successfully.
  842. **        FALSE otherwise.
  843. **
  844. **    The whole environment has been set up and checked for
  845. **    legality and consistency.
  846. */
  847.  
  848. bool
  849. execute(addr)
  850. input u_long addr;            /* explicit address of query */
  851. {
  852.     struct hostent *hp;
  853.     char newnamebuf[MAXDNAME+1];
  854.     char *newname = NULL;        /* name to which CNAME is aliased */
  855.     int ncnames = 0;        /* count of CNAMEs in chain */
  856.     bool result;            /* result status of action taken */
  857.  
  858. /*
  859.  * Special mode to check inverse mappings of host addresses.
  860.  */
  861.     if (addrmode)
  862.     {
  863.         if (addr == NOT_DOTTED_QUAD)
  864.             result = check_addr(queryname);
  865.         else
  866.             result = check_name(addr);
  867.         return(result);
  868.     }
  869.  
  870. /*
  871.  * Special mode to list contents of specified domain.
  872.  */
  873.     if (listmode)
  874.     {
  875.         result = list_domain(queryname);
  876.         return(result);
  877.     }
  878.  
  879. /*
  880.  * Regular mode to query about specified host.
  881.  */
  882.     result = FALSE;
  883.     h_errno = TRY_AGAIN;
  884.  
  885.     /* retry until positive result or permanent failure */
  886.     while (result == FALSE && h_errno == TRY_AGAIN)
  887.     {
  888.         if (addr == NOT_DOTTED_QUAD)
  889.         {
  890.             /* reset CNAME indicator */
  891.             cname = NULL;
  892.  
  893.             /* lookup the name in question */
  894.             if (newname == NULL)
  895.                 result = get_hostinfo(queryname);
  896.             else
  897.                 result = get_hostinfo(newname);
  898.  
  899.             /* recurse on CNAMEs, but not too deep */
  900.             if (cname && (querytype != T_CNAME))
  901.             {
  902.                 newname = strcpy(newnamebuf, cname);
  903.  
  904.                 ncnames++;
  905.                 if (ncnames > 5)
  906.                 {
  907.                     errmsg("Possible CNAME loop");
  908.                     return(FALSE);
  909.                 }
  910.  
  911.                 result = FALSE;
  912.                 h_errno = TRY_AGAIN;
  913.                 continue;
  914.             }
  915.         }
  916.         else
  917.         {
  918.             hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
  919.             if (hp != NULL)
  920.             {
  921.                 print_host("Name", hp);
  922.                 result = TRUE;
  923.             }
  924.         }
  925.  
  926.         /* only retry if so requested */
  927.         if (!waitmode)
  928.             break;
  929.     }
  930.  
  931.     /* explain the reason of a failure */
  932.     if (result == FALSE)
  933.         ns_error(queryname, querytype);
  934.  
  935.     return(result);
  936. }
  937.  
  938. /*
  939. ** SET_SERVER -- Override default nameserver with explicit server
  940. ** --------------------------------------------------------------
  941. **
  942. **    Returns:
  943. **        None.
  944. **        Aborts the program if an unknown host was given.
  945. **
  946. **    Side effects:
  947. **        The global variable server is set to indicate
  948. **        that an explicit server is being used.
  949. **
  950. **    The default nameserver addresses in the resolver database
  951. **    which are initialized by res_init() from /etc/resolv.conf
  952. **    are replaced with the (possibly multiple) addresses of an
  953. **    explicitly named server host. If a dotted quad is given,
  954. **    only that single address will be used.
  955. */
  956.  
  957. void
  958. set_server(name)
  959. input char *name;            /* name of server to be queried */
  960. {
  961.     register int i;
  962.     struct hostent *hp;
  963.     struct in_addr inaddr;
  964.     u_long addr;            /* explicit address of server */
  965.  
  966.     addr = inet_addr(name);
  967.     inaddr.s_addr = addr;
  968.     if (addr == NOT_DOTTED_QUAD)
  969.     {
  970.         /* lookup all of its addresses; this must not fail */
  971.         hp = gethostbyname(name);
  972.         if (hp == NULL)
  973.         {
  974.             errmsg("Error in looking up server name");
  975.             ns_error(name, T_A);
  976.             exit(EX_UNAVAILABLE);
  977.         }
  978.  
  979.         for (i = 0; i < MAXNS && hp->h_addr_list[i]; i++)
  980.         {
  981.             nslist(i).sin_family = AF_INET;
  982.             nslist(i).sin_port = htons(NAMESERVER_PORT);
  983.             nslist(i).sin_addr = incopy(hp->h_addr_list[i]);
  984.         }
  985.         _res.nscount = i;
  986.     }
  987.     else
  988.     {
  989.         /* lookup the name, but use only the given address */
  990.         hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
  991.  
  992.         nslist(0).sin_family = AF_INET;
  993.         nslist(0).sin_port = htons(NAMESERVER_PORT);
  994.         nslist(0).sin_addr = inaddr;
  995.         _res.nscount = 1;
  996.     }
  997.  
  998.     if (hp != NULL)
  999.     {
  1000.         server = strcpy(servername, hp->h_name);
  1001.         print_host("Server", hp);
  1002.     }
  1003.     else
  1004.     {
  1005.         server = strcpy(servername, inet_ntoa(inaddr));
  1006.         printf("Server: %s\n\n", server);
  1007.     }
  1008. }
  1009.  
  1010. /*
  1011. ** FATAL -- Abort program when illegal option encountered
  1012. ** ------------------------------------------------------
  1013. **
  1014. **    Returns:
  1015. **        Aborts after issuing error message.
  1016. */
  1017.  
  1018. /*VARARGS1*/
  1019. void
  1020. fatal(fmt, a, b, c, d)
  1021. input char *fmt;            /* format of message */
  1022. {
  1023.     (void) fprintf(stderr, fmt, a, b, c, d);
  1024.     (void) fprintf(stderr, "\n");
  1025.     exit(EX_USAGE);
  1026. }
  1027.  
  1028.  
  1029. /*
  1030. ** ERRMSG -- Issue error message to error output
  1031. ** ---------------------------------------------
  1032. **
  1033. **    Returns:
  1034. **        None.
  1035. */
  1036.  
  1037. /*VARARGS1*/
  1038. void
  1039. errmsg(fmt, a, b, c, d)
  1040. input char *fmt;            /* format of message */
  1041. {
  1042.     (void) fprintf(stderr, fmt, a, b, c, d);
  1043.     (void) fprintf(stderr, "\n");
  1044. }
  1045.  
  1046. /*
  1047. ** GET_HOSTINFO -- Principal routine to query about given name
  1048. ** -----------------------------------------------------------
  1049. **
  1050. **    Returns:
  1051. **        TRUE if requested info was obtained successfully.
  1052. **        FALSE otherwise.
  1053. **
  1054. **    This is the equivalent of the resolver module res_search().
  1055. */
  1056.  
  1057. bool
  1058. get_hostinfo(name)
  1059. input char *name;            /* name to query about */
  1060. {
  1061.     extern char *hostalias();
  1062.     register char **domain;
  1063.     register char *cp;
  1064.     int dot;            /* number of dots in query name */
  1065.     bool result;            /* result status of action taken */
  1066.  
  1067. /*
  1068.  * Single dot means root domain.
  1069.  */
  1070.     if (sameword(name, "."))
  1071.     {
  1072.         result = get_domaininfo(name, (char *)NULL);
  1073.         return(result);
  1074.     }
  1075.  
  1076. /*
  1077.  * Count number of dots.
  1078.  */
  1079.     for (dot = 0, cp = name; *cp != '\0'; cp++)
  1080.         if (*cp == '.')
  1081.             dot++;
  1082.  
  1083. /*
  1084.  * Check for aliases of single name.
  1085.  */
  1086.     if (dot == 0 && (cp = hostalias(name)) != NULL)
  1087.     {
  1088.         if (verbose)
  1089.             printf("Aliased to \"%s\"\n", cp);
  1090.  
  1091.         result = get_domaininfo(cp, (char *)NULL);
  1092.         return(result);
  1093.     }
  1094.  
  1095. /*
  1096.  * Trailing dot means absolute address.
  1097.  */
  1098.     if (dot != 0 && cp[-1] == '.')
  1099.     {
  1100.         cp[-1] = '\0';
  1101.         result = get_domaininfo(name, (char *)NULL);
  1102.         cp[-1] = '.';
  1103.         return(result);
  1104.     }
  1105.  
  1106. /*
  1107.  * Append own domain if appropriate.
  1108.  */
  1109.     if ((dot == 0 && bitset(RES_DEFNAMES, _res.options)) ||
  1110.         (dot != 0 && bitset(RES_DNSRCH, _res.options)))
  1111.     {
  1112.         for (domain = _res.dnsrch; *domain; domain++)
  1113.         {
  1114.             result = get_domaininfo(name, *domain);
  1115.             if (result)
  1116.                 return(result);
  1117.  
  1118.             /* in case nameserver not present */
  1119.             if (errno == ECONNREFUSED)
  1120.                 return(FALSE);
  1121.         }
  1122.     }
  1123.  
  1124. /*
  1125.  * Single hostname lookup failed.
  1126.  */
  1127.     if (dot == 0)
  1128.     {
  1129.         /* set status in case we never queried */
  1130.         if (!bitset(RES_DEFNAMES, _res.options))
  1131.             h_errno = HOST_NOT_FOUND;
  1132.  
  1133.         return(FALSE);
  1134.     }
  1135.  
  1136. /*
  1137.  * Rest means fully qualified.
  1138.  */
  1139.     result = get_domaininfo(name, (char *)NULL);
  1140.     return(result);
  1141. }
  1142.  
  1143. /*
  1144. ** GET_DOMAININFO -- Fetch and print desired info about name in domain
  1145. ** -------------------------------------------------------------------
  1146. **
  1147. **    Returns:
  1148. **        TRUE if requested info was obtained successfully.
  1149. **        FALSE otherwise.
  1150. **
  1151. **    This is the equivalent of the resolver module res_querydomain().
  1152. */
  1153.  
  1154. bool
  1155. get_domaininfo(name, domain)
  1156. input char *name;            /* name to query about */
  1157. input char *domain;            /* domain to which name is relative */
  1158. {
  1159.     char namebuf[2*MAXDNAME+2];    /* buffer to store full domain name */
  1160.     querybuf answer;
  1161.     int anslen;
  1162.     int result;
  1163.  
  1164.     if (verbose)
  1165.     {
  1166.         if (domain == NULL || domain[0] == '\0')
  1167.             printf("Trying %s ...\n", name);
  1168.         else
  1169.             printf("Trying %s within %s ...\n", name, domain);
  1170.     }
  1171.  
  1172. /*
  1173.  * Construct the actual domain name.
  1174.  * A null domain means the given name is already fully qualified.
  1175.  */
  1176.     if (domain == NULL || domain[0] == '\0')
  1177.         (void) sprintf(namebuf, "%.*s", MAXDNAME, name);
  1178.     else
  1179.         (void) sprintf(namebuf, "%.*s.%.*s", MAXDNAME, name, MAXDNAME, domain);
  1180.     name = namebuf;
  1181.  
  1182. /*
  1183.  * Fetch the desired info, and print any relevant data.
  1184.  */
  1185.     anslen = get_info(&answer, name, querytype, queryclass);
  1186.     if (anslen < 0)
  1187.         return(FALSE);
  1188.  
  1189.     result = print_info(&answer, anslen, name, T_ANY);
  1190.     return(result == NOERROR ? TRUE : FALSE);
  1191. }
  1192.  
  1193. /*
  1194. ** GET_INFO -- Basic routine to issue a nameserver query
  1195. ** -----------------------------------------------------
  1196. **
  1197. **    Returns:
  1198. **        Length of nameserver answer buffer, if obtained.
  1199. **        -1 if an error occurred (h_errno is set appropriately).
  1200. **
  1201. **    This is the equivalent of the resolver module res_query().
  1202. */
  1203.  
  1204. int
  1205. get_info(answerbuf, name, type, class)
  1206. output querybuf *answerbuf;        /* address of buffer to store answer */
  1207. input char *name;            /* full name to query about */
  1208. input int type;                /* specific resource record type */
  1209. input int class;            /* specific resource record class */
  1210. {
  1211.     querybuf query;
  1212.     HEADER *bp;
  1213.     int ancount;
  1214.     register int n;
  1215.  
  1216. /*
  1217.  * Construct query, and send it to the nameserver.
  1218.  * res_send() will fail if no nameserver responded. In this case the possible
  1219.  * values for errno are ECONNREFUSED and ETIMEDOUT. If we did get an answer,
  1220.  * errno should be reset, since res_send() may have left an errno in case it
  1221.  * has used datagrams. Our private version of res_send() will leave also other
  1222.  * error statuses, and will clear errno if an answer was obtained.
  1223.  */
  1224.     errno = 0;    /* reset before querying nameserver */
  1225.  
  1226.     n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0,
  1227.             (struct rrec *)NULL, (char *)&query, sizeof(querybuf));
  1228.     if (n < 0)
  1229.     {
  1230.         if (debug)
  1231.             (void) fprintf(stderr, "res_mkquery failed\n");
  1232.         h_errno = NO_RECOVERY;
  1233.         return(-1);
  1234.     }
  1235.  
  1236.     n = res_send((char *)&query, n, (char *)answerbuf, sizeof(querybuf));
  1237.     if (n < 0)
  1238.     {
  1239.         if (debug)
  1240.             (void) fprintf(stderr, "res_send failed\n");
  1241.         h_errno = TRY_AGAIN;
  1242.         return(-1);
  1243.     }
  1244.  
  1245.     errno = 0;    /* reset after we got an answer */
  1246.  
  1247.     if (n < sizeof(HEADER))
  1248.     {
  1249.         pr_error("answer length %d too short", n);
  1250.         h_errno = NO_RECOVERY;
  1251.         return(-1);
  1252.     }
  1253.  
  1254. /*
  1255.  * Analyze the status of the answer from the nameserver.
  1256.  */
  1257.     if (debug || verbose)
  1258.         print_status(answerbuf);
  1259.  
  1260.     bp = (HEADER *)answerbuf;
  1261.     ancount = ntohs(bp->ancount);
  1262.  
  1263.     if (bp->rcode != NOERROR || ancount == 0)
  1264.     {
  1265.         switch (bp->rcode)
  1266.         {
  1267.             case NXDOMAIN:
  1268.             /* distinguish between authoritative or not */
  1269.             h_errno = bp->aa ? HOST_NOT_FOUND : TRY_AGAIN;
  1270.             break;
  1271.  
  1272.             case NOERROR:
  1273.             /* distinguish between authoritative or not */
  1274.             h_errno = bp->aa ? NO_DATA : NO_RREC;
  1275.             break;
  1276.  
  1277.             case SERVFAIL:
  1278.             h_errno = TRY_AGAIN;
  1279.             break;
  1280.  
  1281.             case FORMERR:
  1282.             case NOTIMP:
  1283.             case REFUSED:
  1284.             case NOCHANGE:
  1285.             h_errno = NO_RECOVERY;
  1286.             break;
  1287.  
  1288.             default:
  1289.             h_errno = NO_RECOVERY;
  1290.             break;
  1291.         }
  1292.         return(-1);
  1293.     }
  1294.  
  1295.     h_errno = 0;
  1296.     return(n);
  1297. }
  1298.  
  1299. /*
  1300. ** PRINT_INFO -- Check resource records in answer and print relevant data
  1301. ** ----------------------------------------------------------------------
  1302. **
  1303. **    Returns:
  1304. **        NOERROR if answer buffer was processed successfully.
  1305. **        FORMERR otherwise.
  1306. **
  1307. **    Side effects:
  1308. **        Will recurse on MAILB records if appropriate.
  1309. **        See also side effects of the next_rr() routine.
  1310. */
  1311.  
  1312. int
  1313. print_info(answerbuf, answerlen, name, filter)
  1314. input querybuf *answerbuf;        /* address of answer buffer */
  1315. input int answerlen;            /* length of answer buffer */
  1316. input char *name;            /* full name we are querying about */
  1317. input int filter;            /* type of records we want to see */
  1318. {
  1319.     HEADER *bp;
  1320.     int qdcount, ancount, nscount, arcount;
  1321.     u_char *msg, *eom;
  1322.     register u_char *cp;
  1323.  
  1324.     bp = (HEADER *)answerbuf;
  1325.     qdcount = ntohs(bp->qdcount);
  1326.     ancount = ntohs(bp->ancount);
  1327.     nscount = ntohs(bp->nscount);
  1328.     arcount = ntohs(bp->arcount);
  1329.  
  1330.     msg = (u_char *)answerbuf;
  1331.     eom = (u_char *)answerbuf + answerlen;
  1332.     cp  = (u_char *)answerbuf + sizeof(HEADER);
  1333.  
  1334. /*
  1335.  * Skip the query section in the response (present only in normal queries).
  1336.  */
  1337.     if (qdcount)
  1338.     {
  1339.         while (qdcount > 0 && cp < eom)
  1340.         {
  1341.             /* cp += dn_skipname(cp, eom) + QFIXEDSZ; */
  1342.  
  1343.             cp = skip_qr(name, cp, msg, eom);
  1344.             if (cp == NULL)
  1345.                 return(FORMERR);
  1346.             qdcount--;
  1347.         }
  1348.  
  1349.         if (qdcount)
  1350.         {
  1351.             pr_error("invalid qdcount in response");
  1352.             return(FORMERR);
  1353.         }
  1354.     }
  1355.  
  1356. /*
  1357.  * Process the actual answer section in the response.
  1358.  * During zone transfers, this is the only section available.
  1359.  */
  1360.     if (ancount)
  1361.     {
  1362.         if (!listmode && verbose && !bp->aa)
  1363.             printf("The following answer is not authoritative:\n");
  1364.  
  1365.         while (ancount > 0 && cp < eom)
  1366.         {
  1367.             cp = next_rr(name, cp, msg, eom, filter);
  1368.             if (cp == NULL)
  1369.                 return(FORMERR);
  1370.             ancount--;
  1371.  
  1372.         /*
  1373.          * When we ask for address and there is a CNAME, it returns
  1374.          * both the CNAME and the address.  Since we trace down the
  1375.          * CNAME chain ourselves, we don't really want to print the
  1376.          * address at this point.
  1377.          */
  1378.             if (!listmode && !verbose && cname)
  1379.                 return(NOERROR);
  1380.  
  1381.         /*
  1382.          * Recursively expand MR or MG records into MB records.
  1383.          */
  1384.             if (mailmode && !listmode && mname)
  1385.             {
  1386.                 char newnamebuf[MAXDNAME+1];
  1387.                 char *newname;
  1388.  
  1389.                 newname = strcpy(newnamebuf, mname);
  1390.                 mname = NULL;
  1391.  
  1392.                 (void) get_hostinfo(newname);
  1393.             }
  1394.         }
  1395.  
  1396.         if (ancount)
  1397.         {
  1398.             pr_error("invalid ancount in response");
  1399.             return(FORMERR);
  1400.         }
  1401.     }
  1402.  
  1403. /*
  1404.  * The nameserver and additional info section are normally not processed.
  1405.  */
  1406.     if (!verbose || exclusive)
  1407.         return(NOERROR);
  1408.  
  1409.     if (nscount)
  1410.     {
  1411.         printf("Authoritative nameservers:\n");
  1412.  
  1413.         while (nscount > 0 && cp < eom)
  1414.         {
  1415.             cp = next_rr(name, cp, msg, eom, filter);
  1416.             if (cp == NULL)
  1417.                 return(FORMERR);
  1418.             nscount--;
  1419.         }
  1420.  
  1421.         if (nscount)
  1422.         {
  1423.             pr_error("invalid nscount in response");
  1424.             return(FORMERR);
  1425.         }
  1426.     }
  1427.  
  1428.     if (arcount)
  1429.     {
  1430.         printf("Additional information:\n");
  1431.  
  1432.         while (arcount > 0 && cp < eom)
  1433.         {
  1434.             cp = next_rr(name, cp, msg, eom, filter);
  1435.             if (cp == NULL)
  1436.                 return(FORMERR);
  1437.             arcount--;
  1438.         }
  1439.  
  1440.         if (arcount)
  1441.         {
  1442.             pr_error("invalid arcount in response");
  1443.             return(FORMERR);
  1444.         }
  1445.     }
  1446.  
  1447.     return(NOERROR);
  1448. }
  1449.  
  1450. /*
  1451. ** DOPRINT -- Output resource record data if this record is wanted
  1452. ** ---------------------------------------------------------------
  1453. **
  1454. **    Returns:
  1455. **        None.
  1456. **
  1457. **    Inputs:
  1458. **        The global variable doprint is set by next_rr()
  1459. **        if we need to print the data.
  1460. */
  1461.  
  1462. static bool doprint;        /* indicates whether or not to print */
  1463.  
  1464. /*VARARGS1*/
  1465. void
  1466. doprintf(fmt, a, b, c, d)
  1467. input char *fmt;            /* format of message */
  1468. {
  1469.     if (doprint)
  1470.     {
  1471.         printf(fmt, a, b, c, d);
  1472.  
  1473.         if (logfile)
  1474.             (void) fprintf(logfile, fmt, a, b, c, d);
  1475.     }
  1476. }
  1477.  
  1478. /*
  1479. ** NEXT_RR -- Decode single resource record and output relevant data
  1480. ** -----------------------------------------------------------------
  1481. **
  1482. **    Returns:
  1483. **        Pointer to position in answer buffer after current record.
  1484. **        NULL if there was a format error in the current record.
  1485. **
  1486. **    Outputs:
  1487. **        The global variable doprint is set appropriately
  1488. **        for use by doprintf().
  1489. **
  1490. **    Side effects:
  1491. **        Updates resource record statistics in record_stats[].
  1492. **        Sets soaname if this is an SOA record.
  1493. **        Sets subname if this is an NS record.
  1494. **        Sets adrname if this is an A record.
  1495. **        Sets address if this is an A record.
  1496. **        Sets cname if this is a valid CNAME record.
  1497. **        Sets mname if this is a valid MAILB record.
  1498. **        These variables must have been cleared before calling
  1499. **        print_info() and may be checked afterwards.
  1500. */
  1501.  
  1502. u_char *
  1503. next_rr(name, cp, msg, eom, filter)
  1504. input char *name;            /* full name we are querying about */
  1505. register u_char *cp;            /* current position in answer buf */
  1506. input u_char *msg, *eom;        /* begin and end of answer buf */
  1507. input int filter;            /* type of records we want to see */
  1508. {
  1509.     char rname[MAXDNAME+1];        /* record name in LHS */
  1510.     char dname[MAXDNAME+1];        /* domain name in RHS */
  1511.     int type, class, ttl, dlen;    /* fixed values in every record */
  1512.     u_char *eor;            /* predicted position of next record */
  1513.     register int n;
  1514.     struct in_addr inaddr;
  1515.     struct protoent *protocol;
  1516.     struct servent *service;
  1517.  
  1518. /*
  1519.  * Pickup the standard values present in each resource record.
  1520.  */
  1521.     n = expand(name, T_NONE, cp, msg, eom, rname);
  1522.     if (n < 0)
  1523.         return(NULL);
  1524.     cp += n;
  1525.  
  1526.     n = 3*sizeof(u_short) + sizeof(u_long);
  1527.     if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
  1528.         return(NULL);
  1529.  
  1530.     type = _getshort(cp);
  1531.     cp += sizeof(u_short);
  1532.  
  1533.     class = _getshort(cp);
  1534.     cp += sizeof(u_short);
  1535.  
  1536.     ttl = _getlong(cp);
  1537.     cp += sizeof(u_long);
  1538.  
  1539.     dlen = _getshort(cp);
  1540.     cp += sizeof(u_short);
  1541.  
  1542.     eor = cp + dlen;
  1543.  
  1544. /*
  1545.  * Decide whether or not to print this resource record.
  1546.  */
  1547.     doprint = want_rr(type, filter);
  1548.  
  1549. #ifdef obsolete
  1550.     if (doprint && exclusive && !samedomain(rname, name, TRUE))
  1551.         doprint = FALSE;
  1552. #endif
  1553.     if (doprint && exclusive && !indomain(rname, name, TRUE))
  1554.         doprint = FALSE;
  1555.  
  1556.     if (doprint && exclusive && fakename(rname))
  1557.         doprint = FALSE;
  1558.  
  1559. #ifdef justfun
  1560.     if (namelen && (strlen(rname) < namelen))
  1561.         doprint = FALSE;
  1562. #endif
  1563.  
  1564. /*
  1565.  * Print name and common values, if appropriate.
  1566.  */
  1567.     if (verbose)
  1568.         doprintf("%-20s\t%d\t%s\t%s",
  1569.             rname, ttl, pr_class(class), pr_type(type));
  1570.     else if (ttlprint)
  1571.         doprintf("%-20s\t%d\t%s",
  1572.             rname, ttl, pr_type(type));
  1573.     else
  1574.         doprintf("%-20s\t%s",
  1575.             rname, pr_type(type));
  1576.  
  1577. /*
  1578.  * Update resource record statistics for zone listing.
  1579.  */
  1580.     if (type >= T_FIRST && type <= T_LAST)
  1581.         record_stats[type]++;
  1582.  
  1583. /*
  1584.  * Save the domain name of an SOA or NS or A record for zone listing.
  1585.  */
  1586.     if (type == T_A)
  1587.         adrname = strcpy(adrnamebuf, rname);
  1588.     else if (type == T_NS)
  1589.         subname = strcpy(subnamebuf, rname);
  1590.     else if (type == T_SOA)
  1591.         soaname = strcpy(soanamebuf, rname);
  1592.  
  1593. /*
  1594.  * Print type specific data, if appropriate.
  1595.  */
  1596.     switch (type)
  1597.     {
  1598.         case T_A:
  1599.         switch (class)
  1600.         {
  1601.             case C_IN:
  1602.             case C_HS:
  1603.             if (dlen == 4)
  1604.             {
  1605.                 bcopy((char *)cp, (char *)&inaddr, sizeof(inaddr));
  1606.                 address = inaddr.s_addr;
  1607.                 doprintf("\t%s", inet_ntoa(inaddr));
  1608.                 cp += dlen;
  1609.                 break;
  1610.             }
  1611.             else if (dlen == 7)
  1612.             {
  1613.                 bcopy((char *)cp, (char *)&inaddr, sizeof(inaddr));
  1614.                 address = inaddr.s_addr;
  1615.                 doprintf("\t%s", inet_ntoa(inaddr));
  1616.                 doprintf(", protocol = %d", cp[4]);
  1617.                 doprintf(", port = %d", (cp[5] << 8) + cp[6]);
  1618.                 cp += dlen;
  1619.                 break;
  1620.             }
  1621.             address = 0;
  1622.             break;
  1623.  
  1624.             default:
  1625.             address = 0;
  1626.             cp += dlen;
  1627.             break;
  1628.         }
  1629.         break;
  1630.  
  1631.         case T_MX:
  1632.         if (check_size(rname, type, cp, msg, eor, sizeof(u_short)) < 0)
  1633.             break;
  1634.         if (verbose || ttlprint)
  1635.             doprintf("\t%ld ", _getshort(cp));
  1636.         else
  1637.             doprintf("\t");
  1638.         cp += sizeof(u_short);
  1639.  
  1640.         n = expand(rname, type, cp, msg, eom, dname);
  1641.         if (n < 0)
  1642.             break;
  1643.         doprintf("%s", dname);
  1644.         cp += n;
  1645.         break;
  1646.  
  1647.         case T_NS:
  1648.         case T_PTR:
  1649.         case T_CNAME:
  1650.         n = expand(rname, type, cp, msg, eom, dname);
  1651.         if (n < 0)
  1652.             break;
  1653.         doprintf("\t%s", dname);
  1654.         cp += n;
  1655.         break;
  1656.  
  1657.         case T_SOA:
  1658.         n = expand(rname, type, cp, msg, eom, dname);
  1659.         if (n < 0)
  1660.             break;
  1661.         doprintf("\t%s", dname);
  1662.         cp += n;
  1663.  
  1664.         n = expand(rname, type, cp, msg, eom, dname);
  1665.         if (n < 0)
  1666.             break;
  1667.         doprintf(" %s", dname);
  1668.         cp += n;
  1669.  
  1670.         n = 5*sizeof(u_long);
  1671.         if (check_size(rname, type, cp, msg, eor, n) < 0)
  1672.             break;
  1673.         doprintf(" (\n\t\t\t%ld\t;serial (version)", _getlong(cp));
  1674.         cp += sizeof(u_long);
  1675.         doprintf("\n\t\t\t%ld\t;refresh period", _getlong(cp));
  1676.         cp += sizeof(u_long);
  1677.         doprintf("\n\t\t\t%ld\t;retry refresh time", _getlong(cp));
  1678.         cp += sizeof(u_long);
  1679.         doprintf("\n\t\t\t%ld\t;expiration period", _getlong(cp));
  1680.         cp += sizeof(u_long);
  1681.         doprintf("\n\t\t\t%ld\t;default ttl\n\t\t\t)", _getlong(cp));
  1682.         cp += sizeof(u_long);
  1683.         break;
  1684.  
  1685.         case T_WKS:
  1686.         if (check_size(rname, type, cp, msg, eor, sizeof(u_long)) < 0)
  1687.             break;
  1688.         bcopy((char *)cp, (char *)&inaddr, sizeof(inaddr));
  1689.         doprintf("\t%s", inet_ntoa(inaddr));
  1690.         cp += sizeof(u_long);
  1691.  
  1692.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  1693.             break;
  1694.         n = *cp++;
  1695.         protocol = getprotobynumber(n);
  1696.         if (protocol)
  1697.             doprintf(" %s", protocol->p_name);
  1698.         else
  1699.             doprintf(" %d", n);
  1700.  
  1701.         doprintf(" (");
  1702.         n = 0;
  1703.         while (cp < eor)
  1704.         {
  1705.             register int c;
  1706.  
  1707.             c = *cp++;
  1708.             do
  1709.             {
  1710.              if (c & 0200)
  1711.             {
  1712.                 if (protocol)
  1713.                     service = getservbyport(htons(n), protocol->p_name);
  1714.                 else
  1715.                     service = NULL;
  1716.                 if (service)
  1717.                     doprintf(" %s", service->s_name);
  1718.                 else
  1719.                     doprintf(" %d", n);
  1720.             }
  1721.              c <<= 1;
  1722.             } while (++n & 07);
  1723.         }
  1724.         doprintf(" )");
  1725.         break;
  1726.  
  1727.         case T_HINFO:
  1728.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  1729.             break;
  1730.         n = *cp++;
  1731.         if (n > 0)
  1732.         {
  1733.             doprintf("\t%.*s", n, cp);
  1734.             cp += n;
  1735.         }
  1736.  
  1737.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  1738.             break;
  1739.         n = *cp++;
  1740.         if (n > 0)
  1741.         {
  1742.             doprintf("\t%.*s", n, cp);
  1743.             cp += n;
  1744.         }
  1745.         break;
  1746.  
  1747.         case T_MINFO:
  1748.         n = expand(rname, type, cp, msg, eom, dname);
  1749.         if (n < 0)
  1750.             break;
  1751.         doprintf("\t%s", dname);
  1752.         cp += n;
  1753.  
  1754.         n = expand(rname, type, cp, msg, eom, dname);
  1755.         if (n < 0)
  1756.             break;
  1757.         doprintf(" %s", dname);
  1758.         cp += n;
  1759.         break;
  1760.  
  1761.         case T_MB:
  1762.         case T_MG:
  1763.         case T_MR:
  1764.         case T_MD:
  1765.         case T_MF:
  1766.         n = expand(rname, type, cp, msg, eom, dname);
  1767.         if (n < 0)
  1768.             break;
  1769.         doprintf("\t%s", dname);
  1770.         cp += n;
  1771.         break;
  1772.  
  1773. #ifdef obsolete
  1774.         case T_TXT:
  1775.         if (dlen > 0)
  1776.         {
  1777.             doprintf("\t%.*s", dlen, cp);
  1778.             cp += dlen;
  1779.         }
  1780.         break;
  1781. #endif
  1782.         case T_TXT:
  1783.         while (cp < eor)
  1784.         {
  1785.             if (check_size(rname, type, cp, msg, eor, 1) < 0)
  1786.                 break;
  1787.             n = *cp++;
  1788.             if (n > 0)
  1789.             {
  1790.                 doprintf("\t%.*s", n, cp);
  1791.                 cp += n;
  1792.             }
  1793.         }
  1794.         break;
  1795.  
  1796.         case T_UINFO:
  1797.         if (dlen > 0)
  1798.         {
  1799.             doprintf("\t%.*s", dlen, cp);
  1800.             cp += dlen;
  1801.         }
  1802.         break;
  1803.  
  1804.         case T_UID:
  1805.         case T_GID:
  1806.         if (dlen == 4)
  1807.         {
  1808.             doprintf("\t%ld", _getlong(cp));
  1809.             cp += dlen;
  1810.         }
  1811.         break;
  1812.  
  1813.         case T_UNSPEC:
  1814.         case T_NULL:
  1815.         cp += dlen;
  1816.         break;
  1817.  
  1818.         default:
  1819.         doprintf("\t???");
  1820.         cp += dlen;
  1821.         break;
  1822.     }
  1823.  
  1824.     doprintf("\n");
  1825.  
  1826. /*
  1827.  * Save the CNAME alias for cname chain tracing.
  1828.  * Save the MR or MG alias for MB chain tracing.
  1829.  */
  1830.     if ((type == T_CNAME) && n > 0 && cp == eor)
  1831.         cname = strcpy(cnamebuf, dname);
  1832.     else if ((type == T_MR || type == T_MG) && n > 0 && cp == eor)
  1833.         mname = strcpy(mnamebuf, dname);
  1834.  
  1835. /*
  1836.  * Check if we have reached the exact end of this record.
  1837.  */
  1838.     if (cp != eor)
  1839.     {
  1840.         pr_error("size error in %s record for %s, dlen = %d, off by = %d",
  1841.             pr_type(type), rname, dlen, (cp - eor));
  1842.  
  1843.         /* we believe value of dlen; should perhaps return(NULL) */
  1844.         cp = eor;
  1845.     }
  1846.  
  1847.     return(cp);
  1848. }
  1849.  
  1850. /*
  1851. ** SKIP_QR -- Skip the query record in the nameserver answer buffer
  1852. ** ----------------------------------------------------------------
  1853. **
  1854. **    Returns:
  1855. **        Pointer to position in answer buffer after current record.
  1856. **        NULL if there was a format error in the current record.
  1857. */
  1858.  
  1859. u_char *
  1860. skip_qr(name, cp, msg, eom)
  1861. input char *name;            /* full name we are querying about */
  1862. register u_char *cp;            /* current position in answer buf */
  1863. input u_char *msg, *eom;        /* begin and end of answer buf */
  1864. {
  1865.     char rname[MAXDNAME+1];        /* record name in LHS */
  1866.     int type, class;        /* fixed values in query record */
  1867.     register int n;
  1868.  
  1869.     n = expand(name, T_NONE, cp, msg, eom, rname);
  1870.     if (n < 0)
  1871.         return(NULL);
  1872.     cp += n;
  1873.  
  1874.     n = 2*sizeof(u_short);
  1875.     if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
  1876.         return(NULL);
  1877.  
  1878.     type = _getshort(cp);
  1879.     cp += sizeof(u_short);
  1880.  
  1881.     class = _getshort(cp);
  1882.     cp += sizeof(u_short);
  1883.  
  1884. #ifdef lint
  1885.     if (verbose)
  1886.         printf("%-20s\t%s\t%s\n",
  1887.             rname, pr_class(class), pr_type(type));
  1888. #endif
  1889.     return(cp);
  1890. }
  1891.  
  1892.  
  1893. /*
  1894.  * Nameserver information.
  1895.  * Stores the names and addresses of all servers that are to be queried
  1896.  * for a zone transfer of the desired domain. Normally these are the
  1897.  * authoritative primary and/or secondary nameservers for the domain.
  1898.  */
  1899.  
  1900. #define MAXNSNAME 12        /* maximum count of nameservers per domain */
  1901. #define MAXIPADDR 10        /* maximum count of addresses per nameserver */
  1902.  
  1903. char nsname[MAXNSNAME][MAXDNAME+1];        /* nameserver hostname */
  1904. struct in_addr ipaddr[MAXNSNAME][MAXIPADDR];    /* nameserver addresses */
  1905. int naddrs[MAXNSNAME];                /* count of addresses */
  1906.  
  1907. #ifdef notyet
  1908. struct nsdata
  1909. {
  1910.     char nsname[MAXDNAME+1];        /* nameserver hostname */
  1911.     struct in_addr ipaddr[MAXIPADDR];    /* nameserver addresses */
  1912.     int naddrs;                /* count of addresses */
  1913. };
  1914.  
  1915. struct nsdata ns[MAXNSNAME];    /* nameserver info */
  1916. #endif
  1917.  
  1918. /*
  1919.  * Host information.
  1920.  * Stores names and (single) addresses encountered during the zone listing
  1921.  * of all A records that belong to the domain. Non-authoritative glue records
  1922.  * that do not belong to the domain are not stored. Glue records that belong
  1923.  * to a subdomain will be filtered out later during the host count scan.
  1924.  */
  1925.  
  1926. #define MAXHOSTS 25000        /* maximum count of hostnames per zone */
  1927.  
  1928. char *hostname[MAXHOSTS];    /* hostname of host in domain */
  1929. u_long hostaddr[MAXHOSTS];    /* first host address */
  1930. bool multaddr[MAXHOSTS];    /* set if this is a multiple address host */
  1931. int hostcount = 0;        /* count of hosts in domain */
  1932.  
  1933. #ifdef notyet
  1934. struct hsdata
  1935. {
  1936.     char *hostname;        /* hostname of host in domain */
  1937.     u_long hostaddr;    /* first host address */
  1938.     bool multaddr;        /* set if this is a multiple address host */
  1939. };
  1940.  
  1941. struct hsdata hs[MAXHOSTS];    /* info on hosts in domain */
  1942. int hostcount = 0;        /* count of hosts in domain */
  1943. #endif
  1944.  
  1945. #ifdef notyet
  1946. /*
  1947.  * The maximum count of subdomains per zone doesn't apply any more,
  1948.  * since the list of zonenames is now allocated dynamically, but the
  1949.  * host data could have been allocated dynamically instead of statically,
  1950.  * although this is less important since it is not saved across calls.
  1951.  */
  1952. #endif
  1953.  
  1954. /*
  1955.  * Subdomain information.
  1956.  * Stores the names of the subdomains encountered during the zone listing.
  1957.  */
  1958.  
  1959. char **zonename = NULL;        /* names of subdomains in domain */
  1960. int zonecount = 0;        /* count of subdomains in domain */
  1961.  
  1962. /*
  1963.  * Address information.
  1964.  * Stores the (single) addresses of hosts found in all domains traversed.
  1965.  * Used to search for duplicate hosts (same address but different name).
  1966.  */
  1967.  
  1968. u_long *addrlist = NULL;    /* global list of addresses */
  1969. int addrcount = 0;        /* count of global addresses */
  1970.  
  1971. /*
  1972.  * SOA record information.
  1973.  */
  1974.  
  1975. struct soa_data
  1976. {
  1977.     char sname[MAXDNAME+1];    /* name of primary server */
  1978.     char mname[MAXDNAME+1];    /* name of hostmaster mailbox */
  1979.     int serial;        /* serial (version) number */
  1980.     int refresh;        /* refresh time in seconds */
  1981.     int retry;        /* refresh retry time in seconds */
  1982.     int expire;        /* expiration time in seconds */
  1983.     int defttl;        /* default time_to_live */
  1984. };
  1985.  
  1986. struct soa_data soa;        /* buffer to store soa data */
  1987.  
  1988. /*
  1989. ** LIST_DOMAIN -- Basic routine to do complete zone listing and checking
  1990. ** ---------------------------------------------------------------------
  1991. **
  1992. **    Returns:
  1993. **        TRUE if the requested info was processed successfully.
  1994. **        FALSE otherwise.
  1995. */
  1996.  
  1997. int total_calls = 0;        /* number of calls for possible zones */
  1998. int total_zones = 0;        /* number of zones successfully read */
  1999. int total_hosts = 0;        /* number of hosts in all subdomains */
  2000. int total_dupls = 0;        /* number of duplicates in all subdomains */
  2001.  
  2002. #ifdef justfun
  2003. char longname[MAXDNAME+1];    /* longest hostname found */
  2004. int longsize = 0;        /* size of longest hostname */
  2005. #endif
  2006.  
  2007. int recursion_level = 0;    /* current recursion level */
  2008.  
  2009. bool
  2010. list_domain(name)
  2011. input char *name;            /* name of domain to list */
  2012. {
  2013.     register int n;
  2014.     register int i;
  2015.     int nservers;            /* count of nameservers */
  2016.     int nzones;            /* count of subdomains */
  2017.     int nhosts;            /* count of real hostnames */
  2018.     int ndupls;            /* count of duplicate hosts */
  2019.     int nextrs;            /* count of extrazone hosts */
  2020.     int ngates;            /* count of gateway hosts */
  2021.  
  2022.     total_calls += 1;        /* new attempt */
  2023.  
  2024. /*
  2025.  * Normalize to not have trailing dot, unless it is the root domain.
  2026.  */
  2027.     n = strlen(name);
  2028.     if (n > 1 && name[n-1] == '.')
  2029.         name[n-1] = '\0';
  2030.  
  2031. /*
  2032.  * Indicate whether we are processing an "in-addr.arpa" inverse domain.
  2033.  * In this case we will suppress accumulating host count statistics.
  2034.  */
  2035.     inverse = indomain(name, "in-addr.arpa", FALSE);
  2036.  
  2037. /*
  2038.  * Find the nameservers for the given domain.
  2039.  */
  2040.     nservers = find_servers(name);
  2041.     if (nservers < 1)
  2042.     {
  2043.         errmsg("No nameservers for %s found", name);
  2044.         return(FALSE);
  2045.     }
  2046.  
  2047. /*
  2048.  * Make sure we have an address for at least one nameserver.
  2049.  */
  2050.     for (n = 0; n < nservers; n++)
  2051.         if (naddrs[n] > 0)
  2052.             break;
  2053.  
  2054.     if (n >= nservers)
  2055.     {
  2056.         errmsg("No addresses of nameservers for %s found", name);
  2057.         return(FALSE);
  2058.     }
  2059.  
  2060. /*
  2061.  * Check SOA records at each of the nameservers.
  2062.  * Temporarily save our current server info from the resolver database.
  2063.  */
  2064.     if (checkmode)
  2065.     {
  2066.         struct state save_res;    /* saved copy of resolver database */
  2067.         char *save_server;    /* saved copy of server name */
  2068.  
  2069.         save_res = _res;
  2070.         save_server = server;
  2071.  
  2072.         for (n = 0; n < nservers; n++)
  2073.         {
  2074.             if (naddrs[n] < 1)
  2075.                 continue;    /* shortcut */
  2076.  
  2077.             server = nsname[n];
  2078.             for (i = 0; i < MAXNS && i < naddrs[n]; i++)
  2079.             {
  2080.                 nslist(i).sin_family = AF_INET;
  2081.                 nslist(i).sin_port = htons(NAMESERVER_PORT);
  2082.                 nslist(i).sin_addr = ipaddr[n][i];
  2083.             }
  2084.             _res.nscount = i;
  2085.  
  2086.             if (check_domain(name) == FALSE)
  2087.                 ns_error(name, T_SOA);
  2088.         }
  2089.  
  2090.         _res = save_res;
  2091.         server = save_server;
  2092.  
  2093.         /* all done if maximum recursion level reached */
  2094.         if (!recursive || (recursion_level >= recursive))
  2095.             return(TRUE);
  2096.     }
  2097.  
  2098. /*
  2099.  * Ask zone transfer to the nameservers, until one responds.
  2100.  */
  2101.     for (n = 0; n < nservers; n++)
  2102.     {
  2103.         for (i = 0; i < naddrs[n]; i++)
  2104.         {
  2105.         if (verbose)
  2106.             printf("Trying server %s (%s) ...\n",
  2107.                 inet_ntoa(ipaddr[n][i]), nsname[n]);
  2108.  
  2109.         if (transfer_zone(name, queryclass, ipaddr[n][i]))
  2110.             goto done;    /* double break */
  2111.  
  2112.         if (h_errno != TRY_AGAIN)
  2113.         {
  2114.             ns_error(name, T_AXFR);
  2115.             return(FALSE);
  2116.         }
  2117. #ifdef notyet
  2118.         /* in case nameserver not present */
  2119.         if (errno == ECONNREFUSED)
  2120.             break;
  2121. #endif
  2122.         }
  2123.     }
  2124. done:
  2125.     if (n >= nservers)
  2126.     {
  2127.         ns_error(name, T_AXFR);
  2128.         errmsg("No nameservers for %s responded", name);
  2129.         return(FALSE);
  2130.     }
  2131.  
  2132. /*
  2133.  * Print resource record statistics if so requested.
  2134.  */
  2135.     if (statistics)
  2136.         print_statistics(name, querytype);
  2137.  
  2138. /*
  2139.  * Accumulate host count statistics for this domain.
  2140.  */
  2141.     nzones = zonecount;
  2142.  
  2143.     nhosts = 0, ndupls = 0, nextrs = 0, ngates = 0;
  2144.  
  2145.     for (n = 0; n < hostcount; n++)
  2146.     {
  2147.         /* skip fake hosts using a very rudimentary test */
  2148.         if (fakename(hostname[n]) || fakeaddr(hostaddr[n]))
  2149.             continue;
  2150. #ifdef justfun
  2151.         /* save longest hostname encountered so far */
  2152.         if (strlen(hostname[n]) > longsize)
  2153.         {
  2154.             longsize = strlen(hostname[n]);
  2155.             (void) strcpy(longname, hostname[n]);
  2156.         }
  2157. #endif
  2158.         /* skip apparent glue records */
  2159.         if (gluerecord(hostname[n], name, zonename, nzones))
  2160.         {
  2161.             if (verbose > 1)
  2162.                 printf("%s is glue record\n", hostname[n]);
  2163.             continue;
  2164.         }
  2165.  
  2166.         /* otherwise count as host */
  2167.         nhosts++;
  2168.  
  2169.     /*
  2170.      * Mark hosts not residing directly in domain as extrazone host.
  2171.      */
  2172.         if (!samedomain(hostname[n], name, TRUE))
  2173.         {
  2174.             nextrs++;
  2175.             if (extrmode || (verbose > 1))
  2176.                 printf("%s is extrazone host\n", hostname[n]);
  2177.         }
  2178.  
  2179.     /*
  2180.      * Mark hosts with more than one address as gateway host.
  2181.      * These are not checked for duplicate addresses.
  2182.      */
  2183.         if (multaddr[n])
  2184.         {
  2185.             ngates++;
  2186.             if (gatemode || (verbose > 1))
  2187.                 printf("%s is gateway host\n", hostname[n]);
  2188.             continue;
  2189.         }
  2190.         
  2191.     /*
  2192.      * Compare single address hosts against global list of addresses.
  2193.      * Multiple address hosts are too complicated to handle this way.
  2194.      */
  2195.         for (i = 0; i < addrcount; i++)
  2196.             if (addrlist[i] == hostaddr[n])
  2197.                 break;    /* duplicate */
  2198.  
  2199.         if (i < addrcount)
  2200.         {
  2201.             ndupls++;
  2202.             if (duplmode || (verbose > 1))
  2203.                 printf("%s is duplicate host\n", hostname[n]);
  2204.         }
  2205.  
  2206.         if (i >= addrcount)
  2207.         {
  2208.             addrlist = newblk(addrlist, addrcount+1, u_long);
  2209.             addrlist[addrcount] = hostaddr[n];
  2210.             addrcount++;
  2211.         }
  2212.     }
  2213.  
  2214. /*
  2215.  * Print statistics for this domain.
  2216.  */
  2217.     if (verbose || statistics || hostmode)
  2218.     {
  2219.         printf("Found %d host%s within %s\n",
  2220.             nhosts, nhosts == 1 ? "" : "s", name);
  2221.  
  2222.         if ((ndupls > 0) || duplmode || (verbose > 1))
  2223.         printf("Found %d duplicate host%s within %s\n",
  2224.             ndupls, ndupls == 1 ? "" : "s", name);
  2225.  
  2226.         if ((nextrs > 0) || extrmode || (verbose > 1))
  2227.         printf("Found %d extrazone host%s within %s\n",
  2228.             nextrs, nextrs == 1 ? "" : "s", name);
  2229.  
  2230.         if ((ngates > 0) || gatemode || (verbose > 1))
  2231.         printf("Found %d gateway host%s within %s\n",
  2232.             ngates, ngates == 1 ? "" : "s", name);
  2233.     }
  2234.  
  2235.     total_zones += 1;        /* update total zones processed */
  2236.     total_hosts += nhosts;        /* update total number of hosts */
  2237.     total_dupls += ndupls;        /* update total number of duplicates */
  2238.  
  2239. /*
  2240.  * The names of the hosts were allocated dynamically.
  2241.  */
  2242.     for (n = 0; n < hostcount; n++)
  2243.         xfree(hostname[n]);
  2244.  
  2245. /*
  2246.  * Do recursion on subdomains if requested and any were found.
  2247.  * Temporarily save subdomain list, and force allocation of new list.
  2248.  */
  2249.     if (verbose || statistics)
  2250.         printf("Found %d subdomain%s within %s\n",
  2251.             nzones, nzones == 1 ? "" : "s", name);
  2252.  
  2253.     if (recursive && (recursion_level < recursive))
  2254.     {
  2255.         char **subdomain;        /* local copy of list */
  2256.  
  2257.         for (n = 0; n < nzones; n++)
  2258.         {
  2259.             subdomain = zonename;
  2260.             zonename = NULL;    /* allocate new list */
  2261.  
  2262.             if (verbose || statistics || checkmode)
  2263.                 printf("\n");
  2264.  
  2265.             if (verbose)
  2266.                 printf("Entering subdomain %s\n", subdomain[n]);
  2267.  
  2268.             recursion_level++;
  2269.             (void) list_domain(subdomain[n]);
  2270.             recursion_level--;
  2271.  
  2272.             zonename = subdomain;
  2273.         }
  2274.     }
  2275.  
  2276. /*
  2277.  * The names of the subdomains were allocated dynamically.
  2278.  * The list of subdomain names was also allocated dynamically.
  2279.  */
  2280.     for (n = 0; n < nzones; n++)
  2281.         xfree(zonename[n]);
  2282.  
  2283.     if (zonename != NULL)
  2284.         xfree(zonename);
  2285.  
  2286.     zonename = NULL;
  2287.  
  2288. /*
  2289.  * Print final overall statistics.
  2290.  */
  2291.     if (recursive && (recursion_level == 0))
  2292.     {
  2293.         if (verbose || statistics || checkmode)
  2294.             printf("\n");
  2295.  
  2296.         if (verbose || statistics || hostmode)
  2297.             printf("Encountered %d host%s in %d domain%s within %s\n",
  2298.                 total_hosts, total_hosts == 1 ? "" : "s",
  2299.                 total_zones, total_zones == 1 ? "" : "s",
  2300.                 name);
  2301.  
  2302.         if (verbose || statistics || hostmode)
  2303.             printf("Encountered %d duplicate host%s in %d domain%s within %s\n",
  2304.                 total_dupls, total_dupls == 1 ? "" : "s",
  2305.                 total_zones, total_zones == 1 ? "" : "s",
  2306.                 name);
  2307.  
  2308.         if (verbose || statistics || checkmode)
  2309.             printf("Processed %d domain%s out of %d attempt%s\n",
  2310.                 total_zones, total_zones == 1 ? "" : "s",
  2311.                 total_calls, total_calls == 1 ? "" : "s");
  2312. #ifdef justfun
  2313.         if (verbose && (longsize > 0))
  2314.             printf("Longest hostname %s\t%d\n",
  2315.                 longname, longsize);
  2316. #endif
  2317.     }
  2318.  
  2319.     return(TRUE);
  2320. }
  2321.  
  2322. /*
  2323. ** FIND_SERVERS -- Fetch names and addresses of authoritative servers
  2324. ** ------------------------------------------------------------------
  2325. **
  2326. **    Returns:
  2327. **        The number of servers found.
  2328. **        0 if no servers could be determined successfully.
  2329. **
  2330. **    Inputs:
  2331. **        The global variable server, if set, contains the name
  2332. **        of the explicit server to be contacted.
  2333. **        The global variable primary, if set, indicates that
  2334. **        we must use the primary nameserver for the domain.
  2335. **
  2336. **    Outputs:
  2337. **        Names are stored in the nsname[] database.
  2338. **        Addresses are stored in the ipaddr[] database.
  2339. **        Address counts are stored in the naddrs[] database.
  2340. */
  2341.  
  2342. int
  2343. find_servers(name)
  2344. input char *name;            /* name of domain to find servers for */
  2345. {
  2346.     struct hostent *hp;
  2347.     register int n;
  2348.     register int i;
  2349.     int nservers;            /* count of nameservers */
  2350.  
  2351. /*
  2352.  * Use the explicit server if given on the command line.
  2353.  * Its addresses are stored in the resolver state struct.
  2354.  * This server may not be authoritative for the given domain.
  2355.  */
  2356.     if (server)
  2357.     {
  2358.         (void) strcpy(nsname[0], server);
  2359.         for (i = 0; i < MAXIPADDR && i < _res.nscount; i++)
  2360.             ipaddr[0][i] = nslist(i).sin_addr;
  2361.         naddrs[0] = i;
  2362.  
  2363.         nservers = 1;
  2364.         return(nservers);
  2365.     }
  2366.  
  2367. /*
  2368.  * Fetch primary nameserver info if so requested.
  2369.  * Get its name from the SOA record for the domain,
  2370.  * and do a regular host lookup to fetch its addresses.
  2371.  */
  2372.     if (primary)
  2373.     {
  2374.         char *primaryname;
  2375.  
  2376.         primaryname = get_primary(name);
  2377.         if (primaryname == NULL)
  2378.         {
  2379.             ns_error(name, T_SOA);
  2380.             return(0);
  2381.         }
  2382.  
  2383.         hp = gethostbyname(primaryname);
  2384.         if (hp == NULL)
  2385.         {
  2386.             ns_error(primaryname, T_A);
  2387.             return(0);
  2388.         }
  2389.  
  2390.         (void) strcpy(nsname[0], hp->h_name);
  2391.         for (i = 0; i < MAXIPADDR && hp->h_addr_list[i]; i++)
  2392.             ipaddr[0][i] = incopy(hp->h_addr_list[i]);
  2393.         naddrs[0] = i;
  2394.  
  2395.         if (verbose)
  2396.             printf("Found %d address%s for %s\n",
  2397.                 naddrs[0], naddrs[0] == 1 ? "  " : "es",
  2398.                 nsname[0]);
  2399.  
  2400.         nservers = 1;
  2401.         return(nservers);
  2402.     }
  2403.  
  2404. /*
  2405.  * Otherwise we have to find the nameservers for the domain.
  2406.  */
  2407.     nservers = get_servers(name);
  2408.     if (nservers < 1)
  2409.     {
  2410.         ns_error(name, T_NS);
  2411.         return(0);
  2412.     }
  2413.  
  2414. /*
  2415.  * Usually we'll get addresses for all the servers in the additional
  2416.  * info section.  But in case we don't, look up their addresses.
  2417.  */
  2418.     for (n = 0; n < nservers; n++)
  2419.     {
  2420.         if (naddrs[n] == 0)
  2421.         {
  2422.         hp = gethostbyname(nsname[n]);
  2423.         if (hp != NULL)
  2424.         {
  2425.             for (i = 0; i < MAXIPADDR && hp->h_addr_list[i]; i++)
  2426.                 ipaddr[n][i] = incopy(hp->h_addr_list[i]);
  2427.             naddrs[n] = i;
  2428.         }
  2429.  
  2430.         if (verbose)
  2431.             printf("Found %d address%s for %s by extra query\n",
  2432.                 naddrs[n], naddrs[n] == 1 ? "  " : "es",
  2433.                 nsname[n]);
  2434.         }
  2435.         else
  2436.         {
  2437.         if (verbose)
  2438.             printf("Found %d address%s for %s\n",
  2439.                 naddrs[n], naddrs[n] == 1 ? "  " : "es",
  2440.                 nsname[n]);
  2441.         }
  2442.     }
  2443.  
  2444.     return(nservers);
  2445. }
  2446.  
  2447. /*
  2448. ** GET_SERVERS -- Fetch names and addresses of authoritative servers
  2449. ** -----------------------------------------------------------------
  2450. **
  2451. **    Returns:
  2452. **        The number of servers found.
  2453. **        0 if no servers could be determined successfully.
  2454. **
  2455. **    Side effects:
  2456. **        Names are stored in the nsname[] database.
  2457. **        Addresses are stored in the ipaddr[] database.
  2458. **        Address counts are stored in the naddrs[] database.
  2459. */
  2460.  
  2461. int
  2462. get_servers(name)
  2463. input char *name;            /* name of domain to find servers for */
  2464. {
  2465.     querybuf answer;
  2466.     int anslen;
  2467.     int nservers;            /* count of nameservers */
  2468.  
  2469.     if (verbose)
  2470.         printf("Finding nameservers for %s ...\n", name);
  2471.  
  2472.     anslen = get_info(&answer, name, T_NS, queryclass);
  2473.     if (anslen < 0)
  2474.         return(0);
  2475.  
  2476.     if (verbose > 1)
  2477.         (void) print_info(&answer, anslen, name, T_ANY);
  2478.  
  2479.     nservers = get_nsinfo(&answer, anslen, name);
  2480.     return(nservers);
  2481. }
  2482.  
  2483. /*
  2484. ** GET_NSINFO -- Extract nameserver data from nameserver answer buffer
  2485. ** -------------------------------------------------------------------
  2486. **
  2487. **    Returns:
  2488. **        The number of servers found.
  2489. **        0 if no servers could be determined successfully.
  2490. **
  2491. **    Outputs:
  2492. **        Names are stored in the nsname[] database.
  2493. **        Addresses are stored in the ipaddr[] database.
  2494. **        Address counts are stored in the naddrs[] database.
  2495. */
  2496.  
  2497. int
  2498. get_nsinfo(answerbuf, answerlen, name)
  2499. input querybuf *answerbuf;        /* address of answer buffer */
  2500. input int answerlen;            /* length of answer buffer */
  2501. input char *name;            /* name of domain to find servers for */
  2502. {
  2503.     HEADER *bp;
  2504.     int qdcount, ancount, nscount, arcount;
  2505.     int rrcount;
  2506.     u_char *msg, *eom;
  2507.     register u_char *cp;
  2508.     register int i;
  2509.     int nservers = 0;        /* count of nameservers */
  2510.  
  2511.     bp = (HEADER *)answerbuf;
  2512.     qdcount = ntohs(bp->qdcount);
  2513.     ancount = ntohs(bp->ancount);
  2514.     nscount = ntohs(bp->nscount);
  2515.     arcount = ntohs(bp->arcount);
  2516.  
  2517.     msg = (u_char *)answerbuf;
  2518.     eom = (u_char *)answerbuf + answerlen;
  2519.     cp  = (u_char *)answerbuf + sizeof(HEADER);
  2520.  
  2521.     while (qdcount > 0 && cp < eom)
  2522.     {
  2523.         cp = skip_qr(name, cp, msg, eom);
  2524.         if (cp == NULL)
  2525.             return(0);
  2526.         qdcount--;
  2527.     }
  2528.  
  2529. /*
  2530.  * If the answer is authoritative, the names are found in the
  2531.  * answer section, and the nameserver section is empty.
  2532.  * If not, there may be duplicate names in both sections.
  2533.  * Addresses are found in the additional info section both cases.
  2534.  */
  2535.     rrcount = ancount + nscount + arcount;
  2536.     while (rrcount > 0 && cp < eom)
  2537.     {
  2538.         char rname[MAXDNAME+1];
  2539.         char dname[MAXDNAME+1];
  2540.         int type, class, ttl, dlen;
  2541.         register int n;
  2542.         struct in_addr inaddr;
  2543.  
  2544.         n = expand(name, T_NONE, cp, msg, eom, rname);
  2545.         if (n < 0)
  2546.             break;
  2547.         cp += n;
  2548.  
  2549.         n = 3*sizeof(u_short) + sizeof(u_long);
  2550.         if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
  2551.             break;
  2552.  
  2553.         type = _getshort(cp);
  2554.         cp += sizeof(u_short);
  2555.  
  2556.         class = _getshort(cp);
  2557.         cp += sizeof(u_short);
  2558.  
  2559.         ttl = _getlong(cp);
  2560.         cp += sizeof(u_long);
  2561.  
  2562.         dlen = _getshort(cp);
  2563.         cp += sizeof(u_short);
  2564. #ifdef lint
  2565.         if (verbose)
  2566.             printf("%-20s\t%d\t%s\t%s\n",
  2567.                 rname, ttl, pr_class(class), pr_type(type));
  2568. #endif
  2569.         if ((type == T_NS) && sameword(rname, name))
  2570.         {
  2571.             n = expand(rname, type, cp, msg, eom, dname);
  2572.             if (n < 0)
  2573.                 break;
  2574.  
  2575.             for (i = 0; i < nservers; i++)
  2576.                 if (sameword(nsname[i], dname))
  2577.                     break;    /* duplicate */
  2578.  
  2579.             if (i >= nservers && nservers < MAXNSNAME)
  2580.             {
  2581.                 (void) strcpy(nsname[nservers], dname);
  2582.                 naddrs[nservers] = 0;
  2583.                 nservers++;
  2584.             }
  2585.         }
  2586.         else if ((type == T_A) && dlen == 4)
  2587.         {
  2588.             for (i = 0; i < nservers; i++)
  2589.                 if (sameword(nsname[i], rname))
  2590.                     break;    /* found */
  2591.  
  2592.             if (i < nservers && naddrs[i] < MAXIPADDR)
  2593.             {
  2594.                 bcopy((char *)cp, (char *)&inaddr, sizeof(inaddr));
  2595.                 ipaddr[i][naddrs[i]] = inaddr;
  2596.                 naddrs[i]++;
  2597.             }
  2598.         }
  2599.  
  2600.         cp += dlen;
  2601.         rrcount--;
  2602.     }
  2603.  
  2604.     return(nservers);
  2605. }
  2606.  
  2607. /*
  2608. ** TRANSFER_ZONE -- Wrapper for get_zone() to hide administrative tasks
  2609. ** --------------------------------------------------------------------
  2610. **
  2611. **    Returns:
  2612. **        See get_zone() for details.
  2613. **
  2614. **    Side effects:
  2615. **        See get_zone() for details.
  2616. **
  2617. **    This routine may be called repeatedly with different server
  2618. **    addresses, until one of the servers responds. Various items
  2619. **    must be reset on every try to continue with a clean slate.
  2620. */
  2621.  
  2622. bool
  2623. transfer_zone(name, class, inaddr)
  2624. input char *name;            /* name of domain to do zone xfer for */
  2625. input int class;            /* specific resource record class */
  2626. input struct in_addr inaddr;        /* address of server to be queried */
  2627. {
  2628.     register int n;
  2629.  
  2630. /*
  2631.  * Reset the resource record statistics before each try.
  2632.  */
  2633.     clear_statistics();
  2634.  
  2635. /*
  2636.  * Perform the actual zone transfer.
  2637.  */
  2638.     if (get_zone(name, class, inaddr))
  2639.         return(TRUE);
  2640.  
  2641. /*
  2642.  * Failure to get the zone. Free any memory that may have been allocated.
  2643.  * On success it is the responsibility of the caller to free the memory.
  2644.  */
  2645.     for (n = 0; n < hostcount; n++)
  2646.         xfree(hostname[n]);
  2647.  
  2648.     for (n = 0; n < zonecount; n++)
  2649.         xfree(zonename[n]);
  2650.  
  2651.     if (zonename != NULL)
  2652.         xfree(zonename);
  2653.  
  2654.     zonename = NULL;
  2655.  
  2656.     return(FALSE);
  2657. }
  2658.  
  2659. /*
  2660. ** GET_ZONE -- Perform a zone transfer from server at specific address
  2661. ** -------------------------------------------------------------------
  2662. **
  2663. **    Returns:
  2664. **        TRUE if the zone data have been retrieved successfully.
  2665. **        FALSE if an error occurred (h_errno is set appropriately).
  2666. **        Set TRY_AGAIN wherever possible to try the next server.
  2667. **
  2668. **    Side effects:
  2669. **        Stores list of subdomains found in zonename[],
  2670. **        and the count of subdomains in zonecount.
  2671. **        Stores list of hostnames  found in hostname[],
  2672. **        and the count of hostnames in hostcount.
  2673. **        Updates resource record statistics in record_stats[].
  2674. **        This array must have been cleared before.
  2675. */
  2676.  
  2677. bool
  2678. get_zone(name, class, inaddr)
  2679. input char *name;            /* name of domain to do zone xfer for */
  2680. input int class;            /* specific resource record class */
  2681. input struct in_addr inaddr;        /* address of server to be queried */
  2682. {
  2683.     querybuf query;
  2684.     querybuf answer;
  2685.     HEADER *bp;
  2686.     int ancount;
  2687.     int sock;
  2688.     struct sockaddr_in sin;
  2689.     register int n;
  2690.     register int i;
  2691.     int nrecords = 0;        /* number of records processed */
  2692.     int soacount = 0;        /* count of SOA records */
  2693.  
  2694.     zonecount = 0;            /* count of subdomains */
  2695.     hostcount = 0;            /* count of hostnames */
  2696.  
  2697. /*
  2698.  * Construct query, and connect to the given server.
  2699.  */
  2700.     errno = 0;
  2701.  
  2702.     n = res_mkquery(QUERY, name, class, T_AXFR, (char *)NULL, 0,
  2703.             (struct rrec *)NULL, (char *)&query, sizeof(querybuf));
  2704.     if (n < 0)
  2705.     {
  2706.         if (debug)
  2707.             (void) fprintf(stderr, "res_mkquery failed\n");
  2708.         h_errno = NO_RECOVERY;
  2709.         return(FALSE);
  2710.     }
  2711.  
  2712.     if (debug)
  2713.     {
  2714.         printf("get_zone()\n");
  2715.         p_query((char *)&query);
  2716.     }
  2717.  
  2718.     sock = socket(AF_INET, SOCK_STREAM, 0);
  2719.     if (sock < 0)
  2720.     {
  2721.         perror("socket");
  2722.         h_errno = TRY_AGAIN;
  2723.         return(FALSE);
  2724.     }
  2725.  
  2726.     sin.sin_family = AF_INET;
  2727.     sin.sin_port = htons(NAMESERVER_PORT);
  2728.     sin.sin_addr = inaddr;
  2729.  
  2730.     if (_res_connect(sock, &sin, sizeof(sin)) < 0)
  2731.     {
  2732.         if (debug || verbose)
  2733.             perror("connect");
  2734.         (void) close(sock);
  2735.         h_errno = TRY_AGAIN;
  2736.         return(FALSE);
  2737.     }
  2738.  
  2739.     if (verbose)
  2740.         printf("Asking zone transfer for %s ...\n", name);
  2741.  
  2742. /*
  2743.  * Send the query buffer.
  2744.  */
  2745.     if (_res_write(sock, (char *)&query, n) < 0)
  2746.     {
  2747.         (void) close(sock);
  2748.         h_errno = TRY_AGAIN;
  2749.         return(FALSE);
  2750.     }
  2751.  
  2752. /*
  2753.  * Process all incoming records, each record in a separate packet.
  2754.  */
  2755.     while ((n = _res_read(sock, (char *)&answer, sizeof(querybuf))) != 0)
  2756.     {
  2757.         if (n < 0)
  2758.         {
  2759.             (void) close(sock);
  2760.             h_errno = TRY_AGAIN;
  2761.             return(FALSE);
  2762.         }
  2763.  
  2764.         if (n < sizeof(HEADER))
  2765.         {
  2766.             pr_error("answer length %d too short", n);
  2767.             (void) close(sock);
  2768.             h_errno = TRY_AGAIN;
  2769.             return(FALSE);
  2770.         }
  2771.  
  2772.         if (debug > 1)
  2773.         {
  2774.             printf("got answer:\n");
  2775.             p_query((char *)&answer);
  2776.         }
  2777.  
  2778.     /*
  2779.      * Analyze the contents of the answer and check for errors.
  2780.      */
  2781.         bp = (HEADER *)&answer;
  2782.         ancount = ntohs(bp->ancount);
  2783.  
  2784.         if (bp->rcode != NOERROR || ancount == 0)
  2785.         {
  2786.             if (verbose)
  2787.                 print_status(&answer);
  2788.  
  2789.             switch (bp->rcode)
  2790.             {
  2791.                 case NXDOMAIN:
  2792.                 /* distinguish between authoritative or not */
  2793.                 h_errno = bp->aa ? HOST_NOT_FOUND : TRY_AGAIN;
  2794.                 break;
  2795.  
  2796.                 case NOERROR:
  2797.                 /* distinguish between authoritative or not */
  2798.                 h_errno = bp->aa ? NO_DATA : NO_RREC;
  2799.                 break;
  2800.  
  2801.                 default:
  2802.                 h_errno = TRY_AGAIN;
  2803.                 break;
  2804.             }
  2805.  
  2806.             (void) close(sock);
  2807.             return(FALSE);
  2808.         }
  2809.  
  2810.         h_errno = 0;
  2811.  
  2812.     /*
  2813.      * Valid packet received. Print contents if appropriate.
  2814.      */
  2815.         nrecords++;
  2816.         soaname = NULL;
  2817.         subname = NULL;
  2818.         adrname = NULL;
  2819.  
  2820.         (void) print_info(&answer, n, name, querytype);
  2821.  
  2822.     /*
  2823.      * Terminate upon the second SOA record for this domain.
  2824.      */
  2825.         if (soaname && sameword(soaname, name))
  2826.             if (soacount++)
  2827.                 break;
  2828.  
  2829.         /* the nameserver balks on this one */
  2830.         if (soaname && !sameword(soaname, name))
  2831.             pr_warning("extraneous SOA record for %s within %s", soaname, name);
  2832.  
  2833.     /*
  2834.      * Save encountered subdomain name for recursive listing.
  2835.      */
  2836.         if (subname && indomain(subname, name, FALSE))
  2837.         {
  2838.             for (i = 0; i < zonecount; i++)
  2839.                 if (sameword(zonename[i], subname))
  2840.                     break;    /* duplicate */
  2841.  
  2842.             if (i >= zonecount)
  2843.             {
  2844.                 zonename = newblk(zonename, zonecount+1, char *);
  2845.                 zonename[zonecount] = newstr(subname);
  2846.                 zonecount++;
  2847.             }
  2848.         }
  2849. #ifdef obsolete
  2850.         /* not sure whether this is illegal or not (no, it's not) */
  2851.         if (subname && !samedomain(subname, name, TRUE))
  2852.             pr_warning("extraneous NS record for %s within %s", subname, name);
  2853. #endif
  2854.         /* warn about strange subdomains */
  2855.         if (subname && !indomain(subname, name, TRUE))
  2856.             pr_warning("extraneous NS record for %s within %s", subname, name);
  2857.  
  2858.     /*
  2859.      * Save encountered name of A record for hostname count.
  2860.      */
  2861.         if (adrname && indomain(adrname, name, FALSE) && !inverse)
  2862.         {
  2863.             for (i = 0; i < hostcount; i++)
  2864.                 if (sameword(hostname[i], adrname))
  2865.                     break;    /* duplicate */
  2866.  
  2867.             if (i < hostcount && address != hostaddr[i])
  2868.                 multaddr[i] = TRUE;
  2869.  
  2870.             if (i >= hostcount && hostcount < MAXHOSTS)
  2871.             {
  2872.                 hostname[hostcount] = newstr(adrname);
  2873.                 hostaddr[hostcount] = address;
  2874.                 multaddr[hostcount] = FALSE;
  2875.                 hostcount++;
  2876.  
  2877.                 if (hostcount == MAXHOSTS)
  2878.                     pr_error("maximum number of %d hostnames reached", hostcount);
  2879.             }
  2880.         }
  2881.  
  2882.         /* check for unauthoritative glue records */
  2883.         if (adrname && !indomain(adrname, name, TRUE))
  2884.             pr_warning("extraneous glue record for %s within %s", adrname, name);
  2885.     }
  2886.  
  2887. /*
  2888.  * End of zone transfer at second SOA record or zero length read.
  2889.  */
  2890.     (void) close(sock);
  2891.  
  2892. /*
  2893.  * Do extra check for hostnames also defined as subdomains.
  2894.  * They may have been defined in the child domain, and crept in
  2895.  * the parent domain, or may have been defined as glue records.
  2896.  * This is not necessarily an error, but the hostname count may
  2897.  * be actually wrong. Leave it in for the time being.
  2898.  */
  2899.     for (n = 0; n < hostcount; n++)
  2900.     {
  2901.         for (i = 0; i < zonecount; i++)
  2902.         {
  2903.         if (sameword(hostname[n], zonename[i]))
  2904.             pr_warning("extraneous A record for %s within %s", hostname[n], name);
  2905.         }
  2906.     }
  2907.  
  2908.     if (verbose)
  2909.         printf("Transfer complete, %d records received for %s\n", nrecords, name);
  2910.  
  2911.     return(TRUE);
  2912. }
  2913.  
  2914. /*
  2915. ** GET_PRIMARY -- Fetch name of primary nameserver for a domain
  2916. ** ------------------------------------------------------------
  2917. **
  2918. **    Returns:
  2919. **        Pointer to the name of the primary server, if found.
  2920. **        NULL if the server could not be determined.
  2921. */
  2922.  
  2923. char *
  2924. get_primary(name)
  2925. input char *name;            /* name of domain to get soa for */
  2926. {
  2927.     querybuf answer;
  2928.     int anslen;
  2929.  
  2930.     if (verbose)
  2931.         printf("Finding primary nameserver for %s ...\n", name);
  2932.  
  2933.     anslen = get_info(&answer, name, T_SOA, queryclass);
  2934.     if (anslen < 0)
  2935.         return(NULL);
  2936.  
  2937.     if (verbose > 1)
  2938.         (void) print_info(&answer, anslen, name, T_ANY);
  2939.  
  2940.     soaname = NULL;
  2941.     (void) get_soainfo(&answer, anslen, name);
  2942.     if (soaname == NULL)
  2943.         return(NULL);
  2944.  
  2945.     return(soa.sname);
  2946. }
  2947.  
  2948. /*
  2949. ** CHECK_DOMAIN -- Fetch and analyse SOA record of a domain
  2950. ** --------------------------------------------------------
  2951. **
  2952. **    Returns:
  2953. **        TRUE if the SOA record was found at the given server.
  2954. **        FALSE otherwise.
  2955. **
  2956. **    Inputs:
  2957. **        The global variable server must contain the name
  2958. **        of the server that was queried.
  2959. */
  2960.  
  2961. bool
  2962. check_domain(name)
  2963. input char *name;            /* name of domain to get soa for */
  2964. {
  2965.     querybuf answer;
  2966.     int anslen;
  2967.  
  2968.     if (verbose)
  2969.         printf("Checking SOA for %s at server %s\n", name, server);
  2970.     else
  2971.         printf("%s (%s)\n", name, server);
  2972.  
  2973.     anslen = get_info(&answer, name, T_SOA, queryclass);
  2974.     if (anslen < 0)
  2975.         return(FALSE);
  2976.  
  2977.     if (verbose > 1)
  2978.         (void) print_info(&answer, anslen, name, T_ANY);
  2979.  
  2980.     soaname = NULL;
  2981.     (void) get_soainfo(&answer, anslen, name);
  2982.     if (soaname == NULL)
  2983.         return(FALSE);
  2984.  
  2985.     printf("%s\t%s\t(%d %d %d %d %d)\n", soa.sname, soa.mname,
  2986.         soa.serial, soa.refresh, soa.retry, soa.expire, soa.defttl);
  2987.  
  2988.     check_soa(name);
  2989.     return(TRUE);
  2990. }
  2991.  
  2992. /*
  2993. ** GET_SOAINFO -- Extract SOA data from nameserver answer buffer
  2994. ** -------------------------------------------------------------
  2995. **
  2996. **    Returns:
  2997. **        NOERROR if the SOA record was found successfully.
  2998. **        FORMERR otherwise.
  2999. **
  3000. **    Outputs:
  3001. **        The global struct soa is filled with the soa data.
  3002. **
  3003. **    Side effects:
  3004. **        Sets soaname if this is a valid SOA record.
  3005. **        This variable must have been cleared before calling
  3006. **        get_soainfo() and may be checked afterwards.
  3007. */
  3008.  
  3009. int
  3010. get_soainfo(answerbuf, answerlen, name)
  3011. input querybuf *answerbuf;        /* address of answer buffer */
  3012. input int answerlen;            /* length of answer buffer */
  3013. input char *name;            /* name of domain to get soa for */
  3014. {
  3015.     HEADER *bp;
  3016.     int qdcount, ancount;
  3017.     u_char *msg, *eom;
  3018.     register u_char *cp;
  3019.  
  3020.     bp = (HEADER *)answerbuf;
  3021.     qdcount = ntohs(bp->qdcount);
  3022.     ancount = ntohs(bp->ancount);
  3023.  
  3024.     msg = (u_char *)answerbuf;
  3025.     eom = (u_char *)answerbuf + answerlen;
  3026.     cp  = (u_char *)answerbuf + sizeof(HEADER);
  3027.  
  3028.     while (qdcount > 0 && cp < eom)
  3029.     {
  3030.         cp = skip_qr(name, cp, msg, eom);
  3031.         if (cp == NULL)
  3032.             return(FORMERR);
  3033.         qdcount--;
  3034.     }
  3035.  
  3036.     if (qdcount)
  3037.     {
  3038.         pr_error("invalid qdcount in response");
  3039.         return(FORMERR);
  3040.     }
  3041.  
  3042. /*
  3043.  * Check answer section only.
  3044.  * The nameserver section may contain the nameservers for the domain,
  3045.  * and the additional section their addresses, but not guaranteed.
  3046.  */
  3047.     while (ancount > 0 && cp < eom)
  3048.     {
  3049.         char rname[MAXDNAME+1];
  3050.         int type, class, ttl, dlen;
  3051.         register int n;
  3052.         u_char *eor;
  3053.  
  3054.         n = expand(name, T_NONE, cp, msg, eom, rname);
  3055.         if (n < 0)
  3056.             return(FORMERR);
  3057.         cp += n;
  3058.  
  3059.         n = 3*sizeof(u_short) + sizeof(u_long);
  3060.         if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
  3061.             return(FORMERR);
  3062.  
  3063.         type = _getshort(cp);
  3064.         cp += sizeof(u_short);
  3065.  
  3066.         class = _getshort(cp);
  3067.         cp += sizeof(u_short);
  3068.  
  3069.         ttl = _getlong(cp);
  3070.         cp += sizeof(u_long);
  3071.  
  3072.         dlen = _getshort(cp);
  3073.         cp += sizeof(u_short);
  3074.  
  3075.         eor = cp + dlen;
  3076. #ifdef lint
  3077.         if (verbose)
  3078.             printf("%-20s\t%d\t%s\t%s\n",
  3079.                 rname, ttl, pr_class(class), pr_type(type));
  3080. #endif
  3081.         switch (type)
  3082.         {
  3083.             case T_SOA:
  3084.             n = expand(rname, type, cp, msg, eom, soa.sname);
  3085.             if (n < 0)
  3086.                 break;
  3087.             cp += n;
  3088.  
  3089.             n = expand(rname, type, cp, msg, eom, soa.mname);
  3090.             if (n < 0)
  3091.                 break;
  3092.             cp += n;
  3093.  
  3094.             n = 5*sizeof(u_long);
  3095.             if (check_size(rname, type, cp, msg, eor, n) < 0)
  3096.                 break;
  3097.             soa.serial = _getlong(cp);
  3098.             cp += sizeof(u_long);
  3099.             soa.refresh = _getlong(cp);
  3100.             cp += sizeof(u_long);
  3101.             soa.retry = _getlong(cp);
  3102.             cp += sizeof(u_long);
  3103.             soa.expire = _getlong(cp);
  3104.             cp += sizeof(u_long);
  3105.             soa.defttl = _getlong(cp);
  3106.             cp += sizeof(u_long);
  3107.  
  3108.             /* valid complete soa record found */
  3109.             soaname = strcpy(soanamebuf, rname);
  3110.             break;
  3111.  
  3112.             default:
  3113.             cp += dlen;
  3114.             break;
  3115.         }
  3116.  
  3117.         if (cp != eor)
  3118.         {
  3119.             pr_error("size error in %s record for %s, dlen = %d, off by = %d",
  3120.                 pr_type(type), rname, dlen, (cp - eor));
  3121.             return(FORMERR);
  3122.         }
  3123.  
  3124.         ancount--;
  3125.     }
  3126.  
  3127.     if (ancount)
  3128.     {
  3129.         pr_error("invalid ancount in response");
  3130.         return(FORMERR);
  3131.     }
  3132.  
  3133.     return(NOERROR);
  3134. }
  3135.  
  3136. /*
  3137. ** CHECK_SOA -- Compare new SOA record with previous SOA record
  3138. ** ------------------------------------------------------------
  3139. **
  3140. **    Returns:
  3141. **        None.
  3142. **
  3143. **    Inputs:
  3144. **        The global variable server must contain the name
  3145. **        of the server that was queried.
  3146. **        The global struct soa must contain the soa data.
  3147. */
  3148.  
  3149. void
  3150. check_soa(name)
  3151. input char *name;            /* name of domain to check soa for */
  3152. {
  3153.     static char *oldname = NULL;    /* previous name of domain */
  3154.     static char *oldserver = NULL;    /* previous name of server */
  3155.     static struct soa_data oldsoa;    /* previous soa data */
  3156.  
  3157.     if (oldname && !sameword(name, oldname))
  3158.         oldname = NULL;
  3159.  
  3160.     if (oldname)
  3161.     {
  3162.         if (soa.serial != oldsoa.serial)
  3163.             pr_error("%s has different serial than %s",
  3164.                 server, oldserver);
  3165.  
  3166.         if (!sameword(soa.sname, oldsoa.sname))
  3167.             pr_error("%s has different primary than %s",
  3168.                 server, oldserver);
  3169.  
  3170.         if (!sameword(soa.mname, oldsoa.mname))
  3171.             pr_error("%s has different hostmaster than %s",
  3172.                 server, oldserver);
  3173.     }
  3174.  
  3175.     oldname = name;
  3176.     oldserver = server;
  3177.     oldsoa = soa;
  3178. }
  3179.  
  3180. /*
  3181. ** CHECK_ADDR -- Check if reverse address mappings revert to host
  3182. ** --------------------------------------------------------------
  3183. **
  3184. **    Returns:
  3185. **        TRUE if all addresses of host map back to host.
  3186. **        FALSE otherwise.
  3187. */
  3188.  
  3189. bool
  3190. check_addr(name)
  3191. input char *name;            /* hostname to check addresses for */
  3192. {
  3193.     struct hostent *hp;
  3194.     register int i;
  3195.     struct in_addr inaddr[MAXADDRS];
  3196.     int naddr;
  3197.     char hnamebuf[MAXDNAME+1];
  3198.     char *hname;
  3199.     int matched;
  3200.  
  3201. /*
  3202.  * Look up the specified host to fetch its addresses.
  3203.  */
  3204.     hp = gethostbyname(name);
  3205.     if (hp == NULL)
  3206.     {
  3207.         ns_error(name, T_A);
  3208.         return(FALSE);
  3209.     }
  3210.  
  3211.     hname = strcpy(hnamebuf, hp->h_name);
  3212.     for (i = 0; i < MAXADDRS && hp->h_addr_list[i]; i++)
  3213.         inaddr[i] = incopy(hp->h_addr_list[i]);
  3214.     naddr = i;
  3215.  
  3216.     if (verbose)
  3217.         printf("Found %d address%s for %s\n",
  3218.             naddr, naddr == 1 ? "" : "es", hname);
  3219.  
  3220. /*
  3221.  * Map back the addresses found, and check if they revert to host.
  3222.  */
  3223.     for (matched = 0, i = 0; i < naddr; i++)
  3224.     {
  3225.         char *iname = inet_ntoa(inaddr[i]);
  3226.         u_long addr = inaddr[i].s_addr;
  3227.  
  3228.         if (verbose)
  3229.             printf("Checking %s address %s\n", hname, iname);
  3230.  
  3231.         hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
  3232.         if (hp == NULL)
  3233.             ns_error(iname, T_PTR);
  3234.         else if (!sameword(hp->h_name, hname))
  3235.             pr_error("address %s of %s maps to %s", iname, hname, hp->h_name);
  3236.         else
  3237.             matched++;
  3238.     }
  3239.  
  3240.     return(matched == naddr ? TRUE : FALSE);
  3241. }
  3242.  
  3243. /*
  3244. ** CHECK_NAME -- Check if address belongs to host addresses
  3245. ** --------------------------------------------------------
  3246. **
  3247. **    Returns:
  3248. **        TRUE if given address was found among host addresses.
  3249. **        FALSE otherwise.
  3250. */
  3251.  
  3252. bool
  3253. check_name(addr)
  3254. input u_long addr;            /* address of host to check */
  3255. {
  3256.     struct hostent *hp;
  3257.     register int i;
  3258.     struct in_addr inaddr;
  3259.     char hnamebuf[MAXDNAME+1];
  3260.     char *hname;
  3261.     char inamebuf[MAXDNAME+1];
  3262.     char *iname;
  3263.     int matched;
  3264.  
  3265. /*
  3266.  * Check if the address is registered by fetching its hostname.
  3267.  */
  3268.     inaddr.s_addr = addr;
  3269.     iname = strcpy(inamebuf, inet_ntoa(inaddr));
  3270.  
  3271.     hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
  3272.     if (hp == NULL)
  3273.     {
  3274.         ns_error(iname, T_PTR);
  3275.         return(FALSE);
  3276.     }
  3277.  
  3278.     hname = strcpy(hnamebuf, hp->h_name);
  3279.  
  3280.     if (verbose)
  3281.         printf("Address %s maps to %s\n", iname, hname);
  3282.  
  3283. /*
  3284.  * Lookup the hostname found to fetch its addresses.
  3285.  * Check if the given address is listed among the known addresses.
  3286.  */
  3287.     hp = gethostbyname(hname);
  3288.     if (hp == NULL)
  3289.     {
  3290.         ns_error(hname, T_A);
  3291.         return(FALSE);
  3292.     }
  3293.  
  3294.     for (matched = 0, i = 0; hp->h_addr_list[i]; i++)
  3295.     {
  3296.         inaddr = incopy(hp->h_addr_list[i]);
  3297.  
  3298.         if (verbose)
  3299.             printf("Checking %s address %s\n", hname, inet_ntoa(inaddr));
  3300.  
  3301.         if (inaddr.s_addr == addr)
  3302.             matched++;
  3303.     }
  3304.  
  3305.     if (!matched)
  3306.         pr_error("address %s does not belong to %s", iname, hname);
  3307.  
  3308.     return(matched ? TRUE : FALSE);
  3309. }
  3310.  
  3311. /*
  3312. ** PARSE_TYPE -- Decode rr type from input string
  3313. ** ----------------------------------------------
  3314. **
  3315. **    Returns:
  3316. **        Value of resource record type.
  3317. **        -1 if specified record name is invalid.
  3318. **
  3319. **    Note.    T_MD, T_MF, T_MAILA are obsolete, but recognized.
  3320. **        T_AXFR is not allowed to be specified as query type.
  3321. */
  3322.  
  3323. int
  3324. parse_type(string)
  3325. input char *string;            /* input string with record type */
  3326. {
  3327.     register int type;
  3328.  
  3329.     if (sameword(string, "A"))    return(T_A);
  3330.     if (sameword(string, "NS"))    return(T_NS);
  3331.     if (sameword(string, "MD"))    return(T_MD);        /* obsolete */
  3332.     if (sameword(string, "MF"))    return(T_MF);        /* obsolete */
  3333.     if (sameword(string, "CNAME"))    return(T_CNAME);
  3334.     if (sameword(string, "SOA"))    return(T_SOA);
  3335.     if (sameword(string, "MB"))    return(T_MB);
  3336.     if (sameword(string, "MG"))    return(T_MG);
  3337.     if (sameword(string, "MR"))    return(T_MR);
  3338.     if (sameword(string, "NULL"))    return(T_NULL);
  3339.     if (sameword(string, "WKS"))    return(T_WKS);
  3340.     if (sameword(string, "PTR"))    return(T_PTR);
  3341.     if (sameword(string, "HINFO"))    return(T_HINFO);
  3342.     if (sameword(string, "MINFO"))    return(T_MINFO);
  3343.     if (sameword(string, "MX"))    return(T_MX);
  3344.     if (sameword(string, "TXT"))    return(T_TXT);
  3345.  
  3346.     if (sameword(string, "UINFO"))    return(T_UINFO);
  3347.     if (sameword(string, "UID"))    return(T_UID);
  3348.     if (sameword(string, "GID"))    return(T_GID);
  3349.     if (sameword(string, "UNSPEC"))    return(T_UNSPEC);
  3350.  
  3351.     if (sameword(string, "AXFR"))    return(-1);        /* illegal */
  3352.     if (sameword(string, "MAILB"))    return(T_MAILB);
  3353.     if (sameword(string, "MAILA"))    return(T_MAILA);    /* obsolete */
  3354.     if (sameword(string, "ANY"))    return(T_ANY);
  3355.     if (sameword(string, "*"))    return(T_ANY);
  3356.  
  3357.     type = atoi(string);
  3358.     if (type >= T_FIRST && type <= T_LAST)
  3359.         return(type);
  3360.  
  3361.     return(-1);
  3362. }
  3363.  
  3364. /*
  3365. ** PARSE_CLASS -- Decode rr class from input string
  3366. ** ------------------------------------------------
  3367. **
  3368. **    Returns:
  3369. **        Value of resource class.
  3370. **        -1 if specified class name is invalid.
  3371. */
  3372.  
  3373. int
  3374. parse_class(string)
  3375. input char *string;            /* input string with resource class */
  3376. {
  3377.     register int class;
  3378.  
  3379.     if (sameword(string, "IN"))    return(C_IN);
  3380.     if (sameword(string, "CHAOS"))    return(C_CHAOS);
  3381.     if (sameword(string, "HS"))    return(C_HS);
  3382.  
  3383.     if (sameword(string, "ANY"))    return(C_ANY);
  3384.     if (sameword(string, "*"))    return(C_ANY);
  3385.  
  3386.     class = atoi(string);
  3387.     if (class > 0)
  3388.         return(class);
  3389.  
  3390.     return(-1);
  3391. }
  3392.  
  3393. /*
  3394. ** IN_ADDR_ARPA -- Convert dotted quad string to inverse in-addr.arpa
  3395. ** ------------------------------------------------------------------
  3396. **
  3397. **    Returns:
  3398. **        Pointer to inverse in-addr.arpa. domain name
  3399. **        with trailing dot to force absolute domain name.
  3400. **        NULL in case of invalid dotted quad input string.
  3401. */
  3402.  
  3403. char *
  3404. in_addr_arpa(dottedquad)
  3405. input char *dottedquad;            /* input string with dotted quad */
  3406. {
  3407.     static char addrbuf[32];
  3408.     u_int a[4];
  3409.     register int n;
  3410.  
  3411.     n = sscanf(dottedquad, "%u.%u.%u.%u", &a[0], &a[1], &a[2], &a[3]);
  3412.     switch (n)
  3413.     {
  3414.         case 4:
  3415.         (void) sprintf(addrbuf, "%u.%u.%u.%u.in-addr.arpa.",
  3416.             a[3]&0xff, a[2]&0xff, a[1]&0xff, a[0]&0xff);
  3417.         break;
  3418.  
  3419.         case 3:
  3420.         (void) sprintf(addrbuf, "%u.%u.%u.in-addr.arpa.",
  3421.             a[2]&0xff, a[1]&0xff, a[0]&0xff);
  3422.         break;
  3423.  
  3424.         case 2:
  3425.         (void) sprintf(addrbuf, "%u.%u.in-addr.arpa.",
  3426.             a[1]&0xff, a[0]&0xff);
  3427.         break;
  3428.  
  3429.         case 1:
  3430.         (void) sprintf(addrbuf, "%u.in-addr.arpa.",
  3431.             a[0]&0xff);
  3432.         break;
  3433.  
  3434.         default:
  3435.         return(NULL);
  3436.     }
  3437.  
  3438.     while (--n >= 0)
  3439.         if (a[n] > 255)
  3440.             return(NULL);
  3441.  
  3442.     return(addrbuf);
  3443. }
  3444.  
  3445. /*
  3446. ** PRINT_HOST -- Print hostname and address of hostent struct
  3447. ** ----------------------------------------------------------
  3448. **
  3449. **    Returns:
  3450. **        None.
  3451. */
  3452.  
  3453. void
  3454. print_host(heading, hp)
  3455. input char *heading;            /* header string */
  3456. input struct hostent *hp;        /* address of hostent struct */
  3457. {
  3458.     register char **ap;
  3459.  
  3460.     printf("%s: %s", heading, hp->h_name);
  3461.  
  3462.     for (ap = hp->h_addr_list; ap && *ap; ap++)
  3463.     {
  3464.         if (ap == hp->h_addr_list)
  3465.             printf("\nAddress:");
  3466.  
  3467.         printf(" %s", inet_ntoa(incopy(*ap)));
  3468.     }
  3469.  
  3470.     for (ap = hp->h_aliases; ap && *ap && **ap; ap++)
  3471.     {
  3472.         if (ap == hp->h_aliases)
  3473.             printf("\nAliases:");
  3474.  
  3475.         printf(" %s", *ap);
  3476.     }
  3477.  
  3478.     printf("\n\n");
  3479. }
  3480.  
  3481. /*
  3482. ** PRINT_RES -- Print resolver database information
  3483. ** ------------------------------------------------
  3484. **
  3485. **    Returns:
  3486. **        None.
  3487. **
  3488. **    Inputs:
  3489. **        The resolver database _res is localized in the resolver.
  3490. */
  3491.  
  3492. void
  3493. print_res()
  3494. {
  3495.     register int i;
  3496.     register char **domain;
  3497.  
  3498. /*
  3499.  * The default domain is defined by the "domain" entry in /etc/resolv.conf
  3500.  * if not overridden by the environment variable "LOCALDOMAIN".
  3501.  * If still not defined, gethostname() may yield a fully qualified hostname.
  3502.  */
  3503.     printf("Default domain:");
  3504.     if (_res.defdname[0] != '\0')
  3505.         printf(" %s", _res.defdname);
  3506.     printf("\n");
  3507.  
  3508. /*
  3509.  * The search domains are extracted from the default domain components,
  3510.  * but may be overridden by "search" directives in /etc/resolv.conf
  3511.  * since 4.8.3.
  3512.  */
  3513.     printf("Search domains:");
  3514.     for (domain = _res.dnsrch; *domain; domain++)
  3515.         printf(" %s", *domain);
  3516.     printf("\n");
  3517.  
  3518. /*
  3519.  * The routine res_send() will do _res.retry tries to contact each of the
  3520.  * _res.nscount nameserver addresses before giving up when using datagrams.
  3521.  * The first try will timeout after _res.retrans seconds. Each following
  3522.  * try will timeout after ((_res.retrans << try) / _res.nscount) seconds.
  3523.  * Note. When we contact an explicit server the addresses will be replaced
  3524.  * by the multiple addresses of the same server.
  3525.  * When doing a zone transfer _res.retrans is used for the connect timeout.
  3526.  */
  3527.     printf("Timeout per retry: %d secs\n", _res.retrans);
  3528.     printf("Number of retries: %d\n", _res.retry);
  3529.  
  3530.     printf("Number of addresses: %d\n", _res.nscount);
  3531.     for (i = 0; i < _res.nscount; i++)
  3532.         printf("%s\n", inet_ntoa(nslist(i).sin_addr));
  3533.  
  3534. /*
  3535.  * The resolver options are initialized by res_init() to contain the
  3536.  * defaults settings (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
  3537.  * The various options have the following meaning:
  3538.  *
  3539.  *    RES_INIT    set after res_init() has been called
  3540.  *    RES_DEBUG    let the resolver modules print debugging info
  3541.  *    RES_AAONLY    want authoritative answers only (not implemented)
  3542.  *    RES_USEVC    use tcp virtual circuit instead of udp datagrams
  3543.  *    RES_PRIMARY    use primary nameserver only (not implemented)
  3544.  *    RES_IGNTC    ignore datagram truncation; don't switch to tcp
  3545.  *    RES_RECURSE    forward query if answer not locally available
  3546.  *    RES_DEFNAMES    add default domain to queryname without dot
  3547.  *    RES_STAYOPEN    keep tcp socket open for subsequent queries
  3548.  *    RES_DNSRCH    append search domains even to queryname with dot
  3549.  */
  3550.     printf("Options set:");
  3551.     if (bitset(RES_INIT,      _res.options)) printf(" INIT");
  3552.     if (bitset(RES_DEBUG,     _res.options)) printf(" DEBUG");
  3553.     if (bitset(RES_AAONLY,    _res.options)) printf(" AAONLY");
  3554.     if (bitset(RES_USEVC,     _res.options)) printf(" USEVC");
  3555.     if (bitset(RES_PRIMARY,   _res.options)) printf(" PRIMARY");
  3556.     if (bitset(RES_IGNTC,     _res.options)) printf(" IGNTC");
  3557.     if (bitset(RES_RECURSE,   _res.options)) printf(" RECURSE");
  3558.     if (bitset(RES_DEFNAMES,  _res.options)) printf(" DEFNAMES");
  3559.     if (bitset(RES_STAYOPEN,  _res.options)) printf(" STAYOPEN");
  3560.     if (bitset(RES_DNSRCH,    _res.options)) printf(" DNSRCH");
  3561.     printf("\n");
  3562.  
  3563.     printf("Options clr:");
  3564.     if (!bitset(RES_INIT,     _res.options)) printf(" INIT");
  3565.     if (!bitset(RES_DEBUG,    _res.options)) printf(" DEBUG");
  3566.     if (!bitset(RES_AAONLY,   _res.options)) printf(" AAONLY");
  3567.     if (!bitset(RES_USEVC,    _res.options)) printf(" USEVC");
  3568.     if (!bitset(RES_PRIMARY,  _res.options)) printf(" PRIMARY");
  3569.     if (!bitset(RES_IGNTC,    _res.options)) printf(" IGNTC");
  3570.     if (!bitset(RES_RECURSE,  _res.options)) printf(" RECURSE");
  3571.     if (!bitset(RES_DEFNAMES, _res.options)) printf(" DEFNAMES");
  3572.     if (!bitset(RES_STAYOPEN, _res.options)) printf(" STAYOPEN");
  3573.     if (!bitset(RES_DNSRCH,   _res.options)) printf(" DNSRCH");
  3574.     printf("\n");
  3575.  
  3576.     printf("\n");
  3577. }
  3578.  
  3579. /*
  3580. ** PRINT_STATISTICS -- Print resource record statistics
  3581. ** ----------------------------------------------------
  3582. **
  3583. **    Returns:
  3584. **        None.
  3585. **
  3586. **    Inputs:
  3587. **        The record_stats[] counts have been updated by next_rr().
  3588. */
  3589.  
  3590. void
  3591. print_statistics(name, filter)
  3592. input char *name;            /* name of domain we are listing */
  3593. input int filter;            /* type of records we want to see */
  3594. {
  3595.     register int type;
  3596.     int nrecords;
  3597.  
  3598.     for (type = T_FIRST; type <= T_LAST; type++)
  3599.     {
  3600.         nrecords = record_stats[type];
  3601.         if (nrecords > 0 || (filter != T_ANY && want_rr(type, filter)))
  3602.         {
  3603.             printf("Found %4d %-5.5s record%s within %s\n",
  3604.                 nrecords, pr_type(type),
  3605.                 nrecords == 1 ? " " : "s", name);
  3606.         }
  3607.     }
  3608. }
  3609.  
  3610.  
  3611. /*
  3612. ** CLEAR_STATISTICS -- Clear resource record statistics
  3613. ** ----------------------------------------------------
  3614. **
  3615. **    Returns:
  3616. **        None.
  3617. */
  3618.  
  3619. void
  3620. clear_statistics()
  3621. {
  3622.     bzero((char *)record_stats, sizeof(record_stats));
  3623. }
  3624.  
  3625. /*
  3626. ** PRINT_TYPES -- Print resource record types wanted
  3627. ** -------------------------------------------------
  3628. **
  3629. **    Returns:
  3630. **        None.
  3631. */
  3632.  
  3633. void
  3634. print_types(name, filter)
  3635. input char *name;            /* name we want to query about */
  3636. input int filter;            /* type of records we want to see */
  3637. {
  3638.     register int type;
  3639.  
  3640.     if (filter >= T_NONE)
  3641.     {
  3642.         printf("Query about %s for record types", name);
  3643.         if (filter == T_ANY)
  3644.             printf(" %s", pr_type(T_ANY));
  3645.         else
  3646.             for (type = T_FIRST; type <= T_LAST; type++)
  3647.                 if (want_rr(type, filter))
  3648.                     printf(" %s", pr_type(type));
  3649.         printf("\n");
  3650.     }
  3651. }
  3652.  
  3653. /*
  3654. ** NS_ERROR -- Print error message from errno and h_errno
  3655. ** ------------------------------------------------------
  3656. **
  3657. **    Returns:
  3658. **        None.
  3659. **
  3660. **    Inputs:
  3661. **        The global variable server, if set, contains
  3662. **        the name of the server that was contacted.
  3663. */
  3664.  
  3665. void
  3666. ns_error(name, type) 
  3667. input char *name;            /* full name we queried about */
  3668. input int type;                /* record type we queried about */
  3669. {
  3670. /*
  3671.  * If res_send() fails, it will leave errno in either of the first two
  3672.  * following states when using datagrams. Note that this depends on the
  3673.  * proper handling of connected datagram sockets, which is usually true
  3674.  * if BSD >= 43 (see res_send.c for details; it may need a patch).
  3675.  * Note. If it succeeds, it may leave errno in the state EAFNOSUPPORT
  3676.  * if it has disconnected a previously connected datagram socket, since
  3677.  * the dummy address used to disconnect does not have a proper family set.
  3678.  * Always clear errno after getting a reply, or patch res_send().
  3679.  * Our private version of res_send() will leave also other error statuses.
  3680.  */
  3681.     switch (errno)
  3682.     {
  3683.         case ECONNREFUSED:
  3684.         /*
  3685.          * The contacted host does not have a nameserver running.
  3686.          * The standard res_send() also returns this if none of
  3687.          * the intended hosts could be reached via datagrams.
  3688.          */
  3689.         if (server)
  3690.             errmsg("Nameserver %s not running", server);
  3691.         else
  3692.             errmsg("Nameserver not running");
  3693.         break;
  3694.  
  3695.         case ETIMEDOUT:
  3696.         /*
  3697.          * The contacted host did not give any reply at all.
  3698.          */
  3699.         if (server)
  3700.             errmsg("Nameserver %s not responding", server);
  3701.         else
  3702.             errmsg("Nameserver not responding");
  3703.         break;
  3704.  
  3705.         case ENETDOWN:
  3706.         case ENETUNREACH:
  3707.         case EHOSTDOWN:
  3708.         case EHOSTUNREACH:
  3709.         /*
  3710.          * The host to be contacted or its network can not be reached.
  3711.          * Our private res_send() also returns this using datagrams.
  3712.          */
  3713.         if (server)
  3714.             errmsg("Nameserver %s not reachable", server);
  3715.         else
  3716.             errmsg("Nameserver not reachable");
  3717.         break;
  3718.     }
  3719.  
  3720. /*
  3721.  * Print the message associated with the particular nameserver error.
  3722.  */
  3723.     switch (h_errno)
  3724.     {
  3725.         case HOST_NOT_FOUND:
  3726.         /*
  3727.          * The specified name does definitely not exist at all.
  3728.          * In this case the answer is always authoritative.
  3729.          */
  3730.         errmsg("%s not found (Authoritative answer)", name);
  3731.         break;
  3732.  
  3733.         case TRY_AGAIN:
  3734.         /*
  3735.          * Some intermediate server failure, e.g. timeout.
  3736.          */
  3737.         errmsg("%s %s record not found, try again", name, pr_type(type));
  3738.         break;
  3739.  
  3740.         case NO_RECOVERY:
  3741.         /*
  3742.          * Some irrecoverable format error, or server refusal.
  3743.          */
  3744.         errmsg("%s %s record not found, no recovery", name, pr_type(type));
  3745.         break;
  3746.  
  3747.         case NO_DATA:
  3748.         /*
  3749.          * The name is valid, but the specified type does not exist.
  3750.          * This status is here returned only in case authoritative.
  3751.          */
  3752.         errmsg("%s has no %s record", name, pr_type(type));
  3753.         break;
  3754.  
  3755.         case NO_RREC:
  3756.         /*
  3757.          * The specified type does not exist, but we don't know whether
  3758.          * the name is valid or not. The answer was not authoritative.
  3759.          * Perhaps recursion was off, and no data was cached locally.
  3760.          */
  3761.         errmsg("%s %s record not found", name, pr_type(type));
  3762.         break;
  3763.  
  3764.         default:
  3765.         /*
  3766.          * Unknown cause for server failure.
  3767.          */
  3768.         errmsg("%s %s record not found", name, pr_type(type));
  3769.         break;
  3770.     }
  3771. }
  3772.  
  3773. /*
  3774. ** DECODE_ERROR -- Convert nameserver error code to error message
  3775. ** --------------------------------------------------------------
  3776. **
  3777. **    Returns:
  3778. **        Pointer to appropriate error message.
  3779. */
  3780.  
  3781. char *
  3782. decode_error(error)
  3783. input int error;            /* error code from bp->rcode */
  3784. {
  3785.     switch (error)
  3786.     {
  3787.         case NOERROR:     return("no error");
  3788.         case FORMERR:    return("format error");
  3789.         case SERVFAIL:    return("server failed");
  3790.         case NXDOMAIN:    return("non-existent domain");
  3791.         case NOTIMP:    return("not implemented");
  3792.         case REFUSED:    return("query refused");
  3793.         case NOCHANGE:    return("no change");
  3794.     }
  3795.  
  3796.     return("unknown error");
  3797. }
  3798.  
  3799. /*
  3800. ** PRINT_STATUS -- Print result status after nameserver query
  3801. ** ----------------------------------------------------------
  3802. **
  3803. **    Returns:
  3804. **        None.
  3805. **
  3806. **    Conditions:
  3807. **        The size of the answer buffer must have been
  3808. **        checked before to be of sufficient length,
  3809. **        i.e. to contain at least the buffer header.
  3810. */
  3811.  
  3812. void
  3813. print_status(answerbuf)
  3814. input querybuf *answerbuf;        /* address of answer buffer */
  3815. {
  3816.     HEADER *bp;
  3817.     int ancount;
  3818.     bool failed;
  3819.  
  3820.     bp = (HEADER *)answerbuf;
  3821.     ancount = ntohs(bp->ancount);
  3822.     failed = (bp->rcode != NOERROR || ancount == 0);
  3823.  
  3824.     printf("Query %s, %d answer%s%s, %sstatus: %s\n",
  3825.         failed ? "failed" : "done",
  3826.         ancount, ancount == 1 ? "" : "s",
  3827.         bp->tc ? " (truncated)" : "",
  3828.         bp->aa ? "authoritative " : "",
  3829.         decode_error((int)bp->rcode));
  3830. }
  3831.  
  3832. /*
  3833. ** PR_ERROR -- Print error message about encountered inconsistencies
  3834. ** -----------------------------------------------------------------
  3835. **
  3836. **    We are supposed to have an error condition which is fatal
  3837. **    for normal continuation, and the message is always printed.
  3838. **
  3839. **    Returns:
  3840. **        None.
  3841. */
  3842.  
  3843. /*VARARGS1*/
  3844. void
  3845. pr_error(fmt, a, b, c, d)
  3846. input char *fmt;            /* format of message */
  3847. {
  3848.     (void) fprintf(stderr, " *** ");
  3849.     (void) fprintf(stderr, fmt, a, b, c, d);
  3850.     (void) fprintf(stderr, "\n");
  3851. }
  3852.  
  3853.  
  3854. /*
  3855. ** PR_WARNING -- Print warning message about encountered inconsistencies
  3856. ** ---------------------------------------------------------------------
  3857. **
  3858. **    We are supposed to have an error condition which is non-fatal
  3859. **    for normal continuation, and the message is suppressed in case
  3860. **    quiet mode has been selected.
  3861. **
  3862. **    Returns:
  3863. **        None.
  3864. */
  3865.  
  3866. /*VARARGS1*/
  3867. void
  3868. pr_warning(fmt, a, b, c, d)
  3869. input char *fmt;            /* format of message */
  3870. {
  3871.     if (!quiet)
  3872.     {
  3873.         (void) fprintf(stderr, " !!! ");
  3874.         (void) fprintf(stderr, fmt, a, b, c, d);
  3875.         (void) fprintf(stderr, "\n");
  3876.     }
  3877. }
  3878.  
  3879. /*
  3880. ** WANT_RR -- Indicate whether the rr type matches the desired filter
  3881. ** ------------------------------------------------------------------
  3882. **
  3883. **    Returns:
  3884. **        TRUE if the resource record type matches the filter.
  3885. **        FALSE otherwise.
  3886. **
  3887. **    In regular mode, the querytype is used to formulate the query,
  3888. **    and the filter is set to T_ANY to filter out any response.
  3889. **    In listmode, we get everything, so the filter is set to the
  3890. **    querytype to filter out the proper responses.
  3891. **    Note that T_NONE is the default querytype in listmode.
  3892. */
  3893.  
  3894. bool
  3895. want_rr(type, filter)
  3896. input int type;                /* resource record type */
  3897. input int filter;            /* type of records we want to see */
  3898. {
  3899.     if (type == filter)
  3900.         return(TRUE);
  3901.  
  3902.     if (filter == T_ANY)
  3903.         return(TRUE);
  3904.  
  3905.     if (filter == T_NONE &&
  3906.        (type == T_A || type == T_NS || type == T_PTR))
  3907.         return(TRUE);
  3908.  
  3909.     if (filter == T_MAILB &&
  3910.        (type == T_MB || type == T_MR || type == T_MG || type == T_MINFO))
  3911.         return(TRUE);
  3912.  
  3913.     if (filter == T_MAILA &&
  3914.        (type == T_MD || type == T_MF))
  3915.         return(TRUE);
  3916.  
  3917.     return(FALSE);
  3918. }
  3919.  
  3920. /*
  3921. ** INDOMAIN -- Check whether a name belongs to a domain
  3922. ** ----------------------------------------------------
  3923. **
  3924. **    Returns:
  3925. **        TRUE if the given name lies anywhere in the domain, or
  3926. **        if the given name is the same as the domain and may be so.
  3927. **        FALSE otherwise.
  3928. */
  3929.  
  3930. bool
  3931. indomain(name, domain, equal)
  3932. input char *name;            /* the name under consideration */
  3933. input char *domain;            /* the name of the domain */
  3934. input bool equal;            /* set if name may be same as domain */
  3935. {
  3936.     register char *dot;
  3937.  
  3938.     if (sameword(name, domain))
  3939.         return(equal);
  3940.  
  3941.     if (sameword(domain, "."))
  3942.         return(TRUE);
  3943.  
  3944.     dot = index(name, '.');
  3945.     while (dot != NULL)
  3946.     {
  3947.         if (sameword(dot+1, domain))
  3948.             return(TRUE);
  3949.  
  3950.         dot = index(dot+1, '.');
  3951.     }
  3952.  
  3953.     return(FALSE);
  3954. }
  3955.  
  3956. /*
  3957. ** SAMEDOMAIN -- Check whether a name belongs to a domain
  3958. ** ------------------------------------------------------
  3959. **
  3960. **    Returns:
  3961. **        TRUE if the given name lies directly in the domain, or
  3962. **        if the given name is the same as the domain and may be so.
  3963. **        FALSE otherwise.
  3964. */
  3965.  
  3966. bool
  3967. samedomain(name, domain, equal)
  3968. input char *name;            /* the name under consideration */
  3969. input char *domain;            /* the name of the domain */
  3970. input bool equal;            /* set if name may be same as domain */
  3971. {
  3972.     register char *dot;
  3973.  
  3974.     if (sameword(name, domain))
  3975.         return(equal);
  3976.  
  3977.     dot = index(name, '.');
  3978.     if (dot == NULL)
  3979.         return(sameword(domain, "."));
  3980.  
  3981.     if (sameword(dot+1, domain))
  3982.         return(TRUE);
  3983.  
  3984.     return(FALSE);
  3985. }
  3986.  
  3987. /*
  3988. ** GLUERECORD -- Check whether a name is a glue record
  3989. ** ---------------------------------------------------
  3990. **
  3991. **    Returns:
  3992. **        TRUE is this is a glue record.
  3993. **        FALSE otherwise.
  3994. **
  3995. **    The name is supposed to be the name of an address record.
  3996. **    If it lies directly in the given domain, it is considered
  3997. **    an ordinary host within that domain, and not a glue record.
  3998. **    If it does not belong to the given domain at all, is it
  3999. **    here considered to be a glue record.
  4000. **    If it lies in the given domain, but not directly, it is
  4001. **    considered a glue record if it belongs to any of the known
  4002. **    subdomains of the given domain.
  4003. **    In the root domain itself are no hosts, only glue records.
  4004. */
  4005.  
  4006. bool
  4007. gluerecord(name, domain, zone, nzones)
  4008. input char *name;            /* the name under consideration */
  4009. input char *domain;            /* name of domain being processed */
  4010. input char *zone[];            /* list of known subdomains */
  4011. input int nzones;            /* number of known subdomains */
  4012. {
  4013.     register int n;
  4014.  
  4015.     if (sameword(domain, "."))
  4016.         return(TRUE);
  4017.  
  4018.     if (samedomain(name, domain, TRUE))
  4019.         return(FALSE);
  4020.  
  4021.     if (!indomain(name, domain, TRUE))
  4022.         return(TRUE);
  4023.  
  4024.     for (n = 0; n < nzones; n++)
  4025.         if (indomain(name, zone[n], TRUE))
  4026.             return(TRUE);
  4027.  
  4028.     return(FALSE);
  4029. }
  4030.  
  4031. /*
  4032. ** PR_TYPE -- Return name of resource record type
  4033. ** ----------------------------------------------
  4034. **
  4035. **    Returns:
  4036. **        Pointer to name of resource record type.
  4037. */
  4038.  
  4039. char *
  4040. pr_type(type)
  4041. input int type;                /* resource record type */
  4042. {
  4043.     static char nbuf[20];
  4044.  
  4045.     switch (type)
  4046.     {
  4047.         case T_A:      return("A");        /* internet address */
  4048.         case T_NS:     return("NS");    /* authoritative server */
  4049.         case T_MD:     return("MD");    /* mail destination */
  4050.         case T_MF:     return("MF");    /* mail forwarder */
  4051.         case T_CNAME:  return("CNAME");    /* canonical name */
  4052.         case T_SOA:    return("SOA");    /* start of auth zone */
  4053.         case T_MB:     return("MB");    /* mailbox domain name */
  4054.         case T_MG:     return("MG");    /* mail group member */
  4055.         case T_MR:     return("MR");    /* mail rename name */
  4056.         case T_NULL:   return("NULL");    /* null resource record */
  4057.         case T_WKS:    return("WKS");    /* well known service */
  4058.         case T_PTR:    return("PTR");    /* domain name pointer */
  4059.         case T_HINFO:  return("HINFO");    /* host information */
  4060.         case T_MINFO:  return("MINFO");    /* mailbox information */
  4061.         case T_MX:     return("MX");    /* mail routing info */
  4062.         case T_TXT:    return("TXT");    /* descriptive text */
  4063.  
  4064.         case T_UINFO:  return("UINFO");    /* user information */
  4065.         case T_UID:    return("UID");    /* user ident */
  4066.         case T_GID:    return("GID");    /* group ident */
  4067.         case T_UNSPEC: return("UNSPEC");    /* unspecified binary data */
  4068.  
  4069.         case T_AXFR:   return("AXFR");    /* zone transfer */
  4070.         case T_MAILB:  return("MAILB");    /* matches MB/MR/MG/MINFO */
  4071.         case T_MAILA:  return("MAILA");    /* matches MD/MF */
  4072.         case T_ANY:    return("ANY");    /* matches any type */
  4073.  
  4074.         case T_NONE:   return("resource");    /* not yet determined */
  4075.     }
  4076.  
  4077.     (void) sprintf(nbuf, "%d", type);
  4078.     return(nbuf);
  4079. }
  4080.  
  4081. /*
  4082. ** PR_CLASS -- Return name of resource record class
  4083. ** ------------------------------------------------
  4084. **
  4085. **    Returns:
  4086. **        Pointer to name of resource record class.
  4087. */
  4088.  
  4089. char *
  4090. pr_class(class)
  4091. input int class;            /* resource record class */
  4092. {
  4093.     static char nbuf[20];
  4094.  
  4095.     switch (class)
  4096.     {
  4097.         case C_IN:       return("IN");    /* internet */
  4098.         case C_CHAOS:  return("CHAOS");    /* chaosnet */
  4099.         case C_HS:       return("HS");    /* hesiod */
  4100.         case C_ANY:       return("ANY");    /* any class */
  4101.     }
  4102.  
  4103.     (void) sprintf(nbuf, "%d", class);
  4104.     return(nbuf);
  4105. }
  4106.  
  4107. /*
  4108. ** EXPAND -- Expand compressed domain name in a recource record
  4109. ** ------------------------------------------------------------
  4110. **
  4111. **    Returns:
  4112. **        Number of bytes advanced in answer buffer.
  4113. **        -1 if there was a format error.
  4114. */
  4115.  
  4116. int
  4117. expand(name, type, cp, msg, eom, namebuf)
  4118. input char *name;            /* name of resource record */
  4119. input int type;                /* type of resource record */
  4120. input u_char *cp;            /* current position in answer buf */
  4121. input u_char *msg, *eom;        /* begin and end of answer buf */
  4122. output char *namebuf;            /* address of buf to expand name in */
  4123. {
  4124.     register int n;
  4125.  
  4126.     n = dn_expand(msg, eom, cp, (u_char *)namebuf, MAXDNAME);
  4127.     if (n < 0)
  4128.     {
  4129.         pr_error("expand error in %s record for %s, offset = %d",
  4130.             pr_type(type), name, (cp - msg));
  4131.         h_errno = NO_RECOVERY;
  4132.         return(-1);
  4133.     }
  4134.  
  4135.     if (namebuf[0] == '\0')
  4136.     {
  4137.         namebuf[0] = '.';
  4138.         namebuf[1] = '\0';
  4139.     }
  4140.  
  4141.     return(n);
  4142. }
  4143.  
  4144. /*
  4145. ** CHECK_SIZE -- Check whether resource record is of sufficient length
  4146. ** -------------------------------------------------------------------
  4147. **
  4148. **    Returns:
  4149. **        Requested size if current record is long enough.
  4150. **        -1 if current record does not have this many bytes.
  4151. **
  4152. **    Note that HINFO records are very often incomplete since only
  4153. **    one of the two data fields has been filled in and the second
  4154. **    field is missing. So we generate only a warning message.
  4155. */
  4156.  
  4157. int
  4158. check_size(name, type, cp, msg, eor, size)
  4159. input char *name;            /* name of resource record */
  4160. input int type;                /* type of resource record */
  4161. input u_char *cp;            /* current position in answer buf */
  4162. input u_char *msg, *eor;        /* begin and end of answer buf */
  4163. input int size;                /* required record size remaining */
  4164. {
  4165.     if (cp + size > eor)
  4166.     {
  4167.         if (type != T_HINFO)
  4168.             pr_error("incomplete %s record for %s, offset = %d",
  4169.                 pr_type(type), name, (cp - msg));
  4170.         else
  4171.             pr_warning("incomplete %s record for %s, offset = %d",
  4172.                 pr_type(type), name, (cp - msg));
  4173.         h_errno = NO_RECOVERY;
  4174.         return(-1);
  4175.     }
  4176.  
  4177.     return(size);
  4178. }
  4179.  
  4180. /*
  4181. ** XALLOC -- Allocate or reallocate additional memory
  4182. ** --------------------------------------------------
  4183. **
  4184. **    Returns:
  4185. **        Pointer to (re)allocated buffer space.
  4186. **        Aborts if the requested memory could not be obtained.
  4187. */
  4188.  
  4189. ptr_t *
  4190. xalloc(buf, size)
  4191. register ptr_t *buf;            /* current start of buffer space */
  4192. input int size;                /* number of bytes to allocate */
  4193. {
  4194.     extern ptr_t *malloc();
  4195.     extern ptr_t *realloc();
  4196.  
  4197.     if (buf == NULL)
  4198.         buf = malloc((siz_t)size);
  4199.     else
  4200.         buf = realloc(buf, (siz_t)size);
  4201.  
  4202.     if (buf == NULL)
  4203.     {
  4204.         errmsg("Out of memory");
  4205.         exit(EX_OSERR);
  4206.     }
  4207.  
  4208.     return(buf);
  4209. }
  4210.