dig.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2000-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*! \file */
00019 
00020 #include <config.h>
00021 #include <stdlib.h>
00022 #include <time.h>
00023 #include <ctype.h>
00024 
00025 #include <isc/app.h>
00026 #include <isc/netaddr.h>
00027 #include <isc/parseint.h>
00028 #include <isc/print.h>
00029 #include <isc/string.h>
00030 #include <isc/task.h>
00031 #include <isc/util.h>
00032 
00033 #include <dns/byaddr.h>
00034 #include <dns/fixedname.h>
00035 #include <dns/masterdump.h>
00036 #include <dns/message.h>
00037 #include <dns/name.h>
00038 #include <dns/rdata.h>
00039 #include <dns/rdataset.h>
00040 #include <dns/rdatatype.h>
00041 #include <dns/rdataclass.h>
00042 #include <dns/result.h>
00043 #include <dns/tsig.h>
00044 
00045 #include <dig/dig.h>
00046 
00047 #define ADD_STRING(b, s) {                              \
00048         if (strlen(s) >= isc_buffer_availablelength(b)) \
00049                 return (ISC_R_NOSPACE);                 \
00050         else                                            \
00051                 isc_buffer_putstr(b, s);                \
00052 }
00053 
00054 #define DIG_MAX_ADDRESSES 20
00055 
00056 dig_lookup_t *default_lookup = NULL;
00057 
00058 static char *batchname = NULL;
00059 static FILE *batchfp = NULL;
00060 static char *argv0;
00061 static int addresscount = 0;
00062 
00063 static char domainopt[DNS_NAME_MAXTEXT];
00064 #ifdef ISC_PLATFORM_USESIT
00065 static char sitvalue[256];
00066 #endif
00067 
00068 static isc_boolean_t short_form = ISC_FALSE, printcmd = ISC_TRUE,
00069         ip6_int = ISC_FALSE, plusquest = ISC_FALSE, pluscomm = ISC_FALSE,
00070         multiline = ISC_FALSE, nottl = ISC_FALSE, noclass = ISC_FALSE,
00071         onesoa = ISC_FALSE, rrcomments = ISC_FALSE, use_usec = ISC_FALSE,
00072         nocrypto = ISC_FALSE, ttlunits = ISC_FALSE;
00073 static isc_uint32_t splitwidth = 0xffffffff;
00074 
00075 /*% opcode text */
00076 static const char * const opcodetext[] = {
00077         "QUERY",
00078         "IQUERY",
00079         "STATUS",
00080         "RESERVED3",
00081         "NOTIFY",
00082         "UPDATE",
00083         "RESERVED6",
00084         "RESERVED7",
00085         "RESERVED8",
00086         "RESERVED9",
00087         "RESERVED10",
00088         "RESERVED11",
00089         "RESERVED12",
00090         "RESERVED13",
00091         "RESERVED14",
00092         "RESERVED15"
00093 };
00094 
00095 /*% return code text */
00096 static const char * const rcodetext[] = {
00097         "NOERROR",
00098         "FORMERR",
00099         "SERVFAIL",
00100         "NXDOMAIN",
00101         "NOTIMP",
00102         "REFUSED",
00103         "YXDOMAIN",
00104         "YXRRSET",
00105         "NXRRSET",
00106         "NOTAUTH",
00107         "NOTZONE",
00108         "RESERVED11",
00109         "RESERVED12",
00110         "RESERVED13",
00111         "RESERVED14",
00112         "RESERVED15",
00113         "BADVERS"
00114 };
00115 
00116 /*% safe rcodetext[] */
00117 static char *
00118 rcode_totext(dns_rcode_t rcode)
00119 {
00120         static char buf[sizeof("?65535")];
00121         union {
00122                 const char *consttext;
00123                 char *deconsttext;
00124         } totext;
00125 
00126         if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
00127                 snprintf(buf, sizeof(buf), "?%u", rcode);
00128                 totext.deconsttext = buf;
00129         } else
00130                 totext.consttext = rcodetext[rcode];
00131         return totext.deconsttext;
00132 }
00133 
00134 /*% print usage */
00135 static void
00136 print_usage(FILE *fp) {
00137         fputs(
00138 "Usage:  dig [@global-server] [domain] [q-type] [q-class] {q-opt}\n"
00139 "            {global-d-opt} host [@local-server] {local-d-opt}\n"
00140 "            [ host [@local-server] {local-d-opt} [...]]\n", fp);
00141 }
00142 
00143 ISC_PLATFORM_NORETURN_PRE static void
00144 usage(void) ISC_PLATFORM_NORETURN_POST;
00145 
00146 static void
00147 usage(void) {
00148         print_usage(stderr);
00149         fputs("\nUse \"dig -h\" (or \"dig -h | more\") "
00150               "for complete list of options\n", stderr);
00151         exit(1);
00152 }
00153 
00154 /*% version */
00155 static void
00156 version(void) {
00157         fputs("DiG " VERSION "\n", stderr);
00158 }
00159 
00160 /*% help */
00161 static void
00162 help(void) {
00163         print_usage(stdout);
00164         fputs(
00165 "Where:  domain   is in the Domain Name System\n"
00166 "        q-class  is one of (in,hs,ch,...) [default: in]\n"
00167 "        q-type   is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) [default:a]\n"
00168 "                 (Use ixfr=version for type ixfr)\n"
00169 "        q-opt    is one of:\n"
00170 "                 -x dot-notation     (shortcut for reverse lookups)\n"
00171 "                 -i                  (use IP6.INT for IPv6 reverse lookups)\n"
00172 "                 -f filename         (batch mode)\n"
00173 "                 -b address[#port]   (bind to source address/port)\n"
00174 "                 -p port             (specify port number)\n"
00175 "                 -q name             (specify query name)\n"
00176 "                 -t type             (specify query type)\n"
00177 "                 -c class            (specify query class)\n"
00178 "                 -u                  (display times in usec instead of msec)\n"
00179 "                 -k keyfile          (specify tsig key file)\n"
00180 "                 -y [hmac:]name:key  (specify named base64 tsig key)\n"
00181 "                 -4                  (use IPv4 query transport only)\n"
00182 "                 -6                  (use IPv6 query transport only)\n"
00183 "                 -m                  (enable memory usage debugging)\n"
00184 "        d-opt    is of the form +keyword[=value], where keyword is:\n"
00185 "                 +[no]vc             (TCP mode)\n"
00186 "                 +[no]tcp            (TCP mode, alternate syntax)\n"
00187 "                 +timeout=###        (Set query timeout) [5]\n"
00188 "                 +tries=###          (Set number of UDP attempts) [3]\n"
00189 "                 +retry=###          (Set number of UDP retries) [2]\n"
00190 "                 +domain=###         (Set default domainname)\n"
00191 "                 +bufsize=###        (Set EDNS0 Max UDP packet size)\n"
00192 "                 +ndots=###          (Set NDOTS value)\n"
00193 "                 +subnet=addr        (Set edns-client-subnet option)\n"
00194 "                 +[no]edns[=###]     (Set EDNS version) [0]\n"
00195 "                 +ednsflags=###      (Set EDNS flag bits)\n"
00196 "                 +ednsopt=###[:value] (Send specified EDNS option)\n"
00197 "                 +noednsopt          (Clear list of +ednsopt options)\n"
00198 "                 +[no]ednsnegotiation (Set EDNS version negotiation)\n"
00199 "                 +[no]search         (Set whether to use searchlist)\n"
00200 "                 +[no]showsearch     (Search with intermediate results)\n"
00201 "                 +[no]defname        (Ditto)\n"
00202 "                 +[no]recurse        (Recursive mode)\n"
00203 "                 +[no]ignore         (Don't revert to TCP for TC responses.)"
00204 "\n"
00205 "                 +[no]fail           (Don't try next server on SERVFAIL)\n"
00206 "                 +[no]besteffort     (Try to parse even illegal messages)\n"
00207 "                 +[no]aaonly         (Set AA flag in query (+[no]aaflag))\n"
00208 "                 +[no]adflag         (Set AD flag in query)\n"
00209 "                 +[no]cdflag         (Set CD flag in query)\n"
00210 "                 +[no]zflag          (Set Z flag in query)\n"
00211 "                 +[no]cl             (Control display of class in records)\n"
00212 "                 +[no]cmd            (Control display of command line)\n"
00213 "                 +[no]comments       (Control display of comment lines)\n"
00214 "                 +[no]rrcomments     (Control display of per-record "
00215                                        "comments)\n"
00216 "                 +[no]crypto         (Control display of cryptographic "
00217                                        "fields in records)\n"
00218 "                 +[no]question       (Control display of question)\n"
00219 "                 +[no]answer         (Control display of answer)\n"
00220 "                 +[no]authority      (Control display of authority)\n"
00221 "                 +[no]additional     (Control display of additional)\n"
00222 "                 +[no]stats          (Control display of statistics)\n"
00223 "                 +[no]short          (Disable everything except short\n"
00224 "                                      form of answer)\n"
00225 "                 +[no]ttlid          (Control display of ttls in records)\n"
00226 "                 +[no]ttlunits       (Display TTLs in human-readable units)\n"
00227 "                 +[no]all            (Set or clear all display flags)\n"
00228 "                 +[no]qr             (Print question before sending)\n"
00229 "                 +[no]nssearch       (Search all authoritative nameservers)\n"
00230 "                 +[no]identify       (ID responders in short answers)\n"
00231 "                 +[no]trace          (Trace delegation down from root [+dnssec])\n"
00232 "                 +[no]dnssec         (Request DNSSEC records)\n"
00233 "                 +[no]expire         (Request time to expire)\n"
00234 "                 +[no]nsid           (Request Name Server ID)\n"
00235 "                 +[no]header-only    (Send query without a question section)\n"
00236 #ifdef ISC_PLATFORM_USESIT
00237 "                 +[no]sit            (Request a Source Identity Token)\n"
00238 #endif
00239 #ifdef DIG_SIGCHASE
00240 "                 +[no]sigchase       (Chase DNSSEC signatures)\n"
00241 "                 +trusted-key=####   (Trusted Key when chasing DNSSEC sigs)\n"
00242 #if DIG_SIGCHASE_TD
00243 "                 +[no]topdown        (Do DNSSEC validation top down mode)\n"
00244 #endif
00245 #endif
00246 "                 +[no]split=##       (Split hex/base64 fields into chunks)\n"
00247 "                 +[no]multiline      (Print records in an expanded format)\n"
00248 "                 +[no]onesoa         (AXFR prints only one soa record)\n"
00249 "                 +[no]keepopen       (Keep the TCP socket open between queries)\n"
00250 "                 +[no]dscp[=###]     (Set the DSCP value to ### [0..63])\n"
00251 "        global d-opts and servers (before host name) affect all queries.\n"
00252 "        local d-opts and servers (after host name) affect only that lookup.\n"
00253 "        -h                           (print help and exit)\n"
00254 "        -v                           (print version and exit)\n",
00255         stdout);
00256 }
00257 
00258 /*%
00259  * Callback from dighost.c to print the received message.
00260  */
00261 void
00262 received(int bytes, isc_sockaddr_t *from, dig_query_t *query) {
00263         isc_uint64_t diff;
00264         time_t tnow;
00265         struct tm tmnow;
00266         char time_str[100];
00267         char fromtext[ISC_SOCKADDR_FORMATSIZE];
00268 
00269         isc_sockaddr_format(from, fromtext, sizeof(fromtext));
00270 
00271         if (query->lookup->stats && !short_form) {
00272                 diff = isc_time_microdiff(&query->time_recv, &query->time_sent);
00273                 if (use_usec)
00274                         printf(";; Query time: %ld usec\n", (long) diff);
00275                 else
00276                         printf(";; Query time: %ld msec\n", (long) diff / 1000);
00277                 printf(";; SERVER: %s(%s)\n", fromtext, query->servname);
00278                 time(&tnow);
00279                 tmnow  = *localtime(&tnow);
00280                 if (strftime(time_str, sizeof(time_str),
00281                              "%a %b %d %H:%M:%S %Z %Y", &tmnow) > 0U)
00282                         printf(";; WHEN: %s\n", time_str);
00283                 if (query->lookup->doing_xfr) {
00284                         printf(";; XFR size: %u records (messages %u, "
00285                                "bytes %" ISC_PRINT_QUADFORMAT "u)\n",
00286                                query->rr_count, query->msg_count,
00287                                query->byte_count);
00288                 } else {
00289                         printf(";; MSG SIZE  rcvd: %u\n", bytes);
00290                 }
00291                 if (key != NULL) {
00292                         if (!validated)
00293                                 puts(";; WARNING -- Some TSIG could not "
00294                                      "be validated");
00295                 }
00296                 if ((key == NULL) && (keysecret[0] != 0)) {
00297                         puts(";; WARNING -- TSIG key was not used.");
00298                 }
00299                 puts("");
00300         } else if (query->lookup->identify && !short_form) {
00301                 diff = isc_time_microdiff(&query->time_recv, &query->time_sent);
00302                 if (use_usec)
00303                         printf(";; Received %" ISC_PRINT_QUADFORMAT "u bytes "
00304                                "from %s(%s) in %ld us\n\n",
00305                                query->lookup->doing_xfr
00306                                  ? query->byte_count
00307                                  : (isc_uint64_t)bytes,
00308                                fromtext, query->userarg, (long) diff);
00309                 else
00310                         printf(";; Received %" ISC_PRINT_QUADFORMAT "u bytes "
00311                                "from %s(%s) in %ld ms\n\n",
00312                                query->lookup->doing_xfr
00313                                  ?  query->byte_count
00314                                  : (isc_uint64_t)bytes,
00315                                fromtext, query->userarg, (long) diff / 1000);
00316         }
00317 }
00318 
00319 /*
00320  * Callback from dighost.c to print that it is trying a server.
00321  * Not used in dig.
00322  * XXX print_trying
00323  */
00324 void
00325 trying(char *frm, dig_lookup_t *lookup) {
00326         UNUSED(frm);
00327         UNUSED(lookup);
00328 }
00329 
00330 /*%
00331  * Internal print routine used to print short form replies.
00332  */
00333 static isc_result_t
00334 say_message(dns_rdata_t *rdata, dig_query_t *query, isc_buffer_t *buf) {
00335         isc_result_t result;
00336         isc_uint64_t diff;
00337         char store[sizeof("12345678901234567890")];
00338         unsigned int styleflags = 0;
00339 
00340         if (query->lookup->trace || query->lookup->ns_search_only) {
00341                 result = dns_rdatatype_totext(rdata->type, buf);
00342                 if (result != ISC_R_SUCCESS)
00343                         return (result);
00344                 ADD_STRING(buf, " ");
00345         }
00346 
00347         if (rrcomments)
00348                 styleflags |= DNS_STYLEFLAG_RRCOMMENT;
00349         if (nocrypto)
00350                 styleflags |= DNS_STYLEFLAG_NOCRYPTO;
00351         result = dns_rdata_tofmttext(rdata, NULL, styleflags, 0,
00352                                      splitwidth, " ", buf);
00353         if (result == ISC_R_NOSPACE)
00354                 return (result);
00355         check_result(result, "dns_rdata_totext");
00356         if (query->lookup->identify) {
00357                 diff = isc_time_microdiff(&query->time_recv, &query->time_sent);
00358                 ADD_STRING(buf, " from server ");
00359                 ADD_STRING(buf, query->servname);
00360                 if (use_usec)
00361                         snprintf(store, 19, " in %ld us.", (long) diff);
00362                 else
00363                         snprintf(store, 19, " in %ld ms.", (long) diff / 1000);
00364                 ADD_STRING(buf, store);
00365         }
00366         ADD_STRING(buf, "\n");
00367         return (ISC_R_SUCCESS);
00368 }
00369 
00370 /*%
00371  * short_form message print handler.  Calls above say_message()
00372  */
00373 static isc_result_t
00374 short_answer(dns_message_t *msg, dns_messagetextflag_t flags,
00375              isc_buffer_t *buf, dig_query_t *query)
00376 {
00377         dns_name_t *name;
00378         dns_rdataset_t *rdataset;
00379         isc_result_t result, loopresult;
00380         dns_name_t empty_name;
00381         dns_rdata_t rdata = DNS_RDATA_INIT;
00382 
00383         UNUSED(flags);
00384 
00385         dns_name_init(&empty_name, NULL);
00386         result = dns_message_firstname(msg, DNS_SECTION_ANSWER);
00387         if (result == ISC_R_NOMORE)
00388                 return (ISC_R_SUCCESS);
00389         else if (result != ISC_R_SUCCESS)
00390                 return (result);
00391 
00392         for (;;) {
00393                 name = NULL;
00394                 dns_message_currentname(msg, DNS_SECTION_ANSWER, &name);
00395 
00396                 for (rdataset = ISC_LIST_HEAD(name->list);
00397                      rdataset != NULL;
00398                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
00399                         loopresult = dns_rdataset_first(rdataset);
00400                         while (loopresult == ISC_R_SUCCESS) {
00401                                 dns_rdataset_current(rdataset, &rdata);
00402                                 result = say_message(&rdata, query,
00403                                                      buf);
00404                                 if (result == ISC_R_NOSPACE)
00405                                         return (result);
00406                                 check_result(result, "say_message");
00407                                 loopresult = dns_rdataset_next(rdataset);
00408                                 dns_rdata_reset(&rdata);
00409                         }
00410                 }
00411                 result = dns_message_nextname(msg, DNS_SECTION_ANSWER);
00412                 if (result == ISC_R_NOMORE)
00413                         break;
00414                 else if (result != ISC_R_SUCCESS)
00415                         return (result);
00416         }
00417 
00418         return (ISC_R_SUCCESS);
00419 }
00420 #ifdef DIG_SIGCHASE
00421 isc_result_t
00422 printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset,
00423               isc_buffer_t *target)
00424 {
00425         isc_result_t result;
00426         dns_master_style_t *style = NULL;
00427         unsigned int styleflags = 0;
00428 
00429         if (rdataset == NULL || owner_name == NULL || target == NULL)
00430                 return(ISC_FALSE);
00431 
00432         styleflags |= DNS_STYLEFLAG_REL_OWNER;
00433         if (ttlunits)
00434                 styleflags |= DNS_STYLEFLAG_TTL_UNITS;
00435         if (nottl)
00436                 styleflags |= DNS_STYLEFLAG_NO_TTL;
00437         if (noclass)
00438                 styleflags |= DNS_STYLEFLAG_NO_CLASS;
00439         if (rrcomments)
00440                 styleflags |= DNS_STYLEFLAG_RRCOMMENT;
00441         if (nocrypto)
00442                 styleflags |= DNS_STYLEFLAG_NOCRYPTO;
00443         if (multiline) {
00444                 styleflags |= DNS_STYLEFLAG_OMIT_OWNER;
00445                 styleflags |= DNS_STYLEFLAG_OMIT_CLASS;
00446                 styleflags |= DNS_STYLEFLAG_REL_DATA;
00447                 styleflags |= DNS_STYLEFLAG_OMIT_TTL;
00448                 styleflags |= DNS_STYLEFLAG_TTL;
00449                 styleflags |= DNS_STYLEFLAG_MULTILINE;
00450                 styleflags |= DNS_STYLEFLAG_COMMENT;
00451                 styleflags |= DNS_STYLEFLAG_RRCOMMENT;
00452         }
00453 
00454         if (multiline || (nottl && noclass))
00455                 result = dns_master_stylecreate2(&style, styleflags,
00456                                                 24, 24, 24, 32, 80, 8,
00457                                                 splitwidth, mctx);
00458         else if (nottl || noclass)
00459                 result = dns_master_stylecreate2(&style, styleflags,
00460                                                 24, 24, 32, 40, 80, 8,
00461                                                 splitwidth, mctx);
00462         else
00463                 result = dns_master_stylecreate2(&style, styleflags,
00464                                                 24, 32, 40, 48, 80, 8,
00465                                                 splitwidth, mctx);
00466         check_result(result, "dns_master_stylecreate");
00467 
00468         result = dns_master_rdatasettotext(owner_name, rdataset, style, target);
00469 
00470         if (style != NULL)
00471                 dns_master_styledestroy(&style, mctx);
00472 
00473         return(result);
00474 }
00475 #endif
00476 
00477 /*
00478  * Callback from dighost.c to print the reply from a server
00479  */
00480 isc_result_t
00481 printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
00482         isc_result_t result;
00483         dns_messagetextflag_t flags;
00484         isc_buffer_t *buf = NULL;
00485         unsigned int len = OUTPUTBUF;
00486         dns_master_style_t *style = NULL;
00487         unsigned int styleflags = 0;
00488 
00489         styleflags |= DNS_STYLEFLAG_REL_OWNER;
00490         if (query->lookup->comments)
00491                 styleflags |= DNS_STYLEFLAG_COMMENT;
00492         if (rrcomments)
00493                 styleflags |= DNS_STYLEFLAG_RRCOMMENT;
00494         if (ttlunits)
00495                 styleflags |= DNS_STYLEFLAG_TTL_UNITS;
00496         if (nottl)
00497                 styleflags |= DNS_STYLEFLAG_NO_TTL;
00498         if (noclass)
00499                 styleflags |= DNS_STYLEFLAG_NO_CLASS;
00500         if (nocrypto)
00501                 styleflags |= DNS_STYLEFLAG_NOCRYPTO;
00502         if (multiline) {
00503                 styleflags |= DNS_STYLEFLAG_OMIT_OWNER;
00504                 styleflags |= DNS_STYLEFLAG_OMIT_CLASS;
00505                 styleflags |= DNS_STYLEFLAG_REL_DATA;
00506                 styleflags |= DNS_STYLEFLAG_OMIT_TTL;
00507                 styleflags |= DNS_STYLEFLAG_TTL;
00508                 styleflags |= DNS_STYLEFLAG_MULTILINE;
00509                 styleflags |= DNS_STYLEFLAG_RRCOMMENT;
00510         }
00511         if (multiline || (nottl && noclass))
00512                 result = dns_master_stylecreate2(&style, styleflags,
00513                                                  24, 24, 24, 32, 80, 8,
00514                                                  splitwidth, mctx);
00515         else if (nottl || noclass)
00516                 result = dns_master_stylecreate2(&style, styleflags,
00517                                                  24, 24, 32, 40, 80, 8,
00518                                                  splitwidth, mctx);
00519         else
00520                 result = dns_master_stylecreate2(&style, styleflags,
00521                                                  24, 32, 40, 48, 80, 8,
00522                                                  splitwidth, mctx);
00523         check_result(result, "dns_master_stylecreate");
00524 
00525         if (query->lookup->cmdline[0] != 0) {
00526                 if (!short_form)
00527                         fputs(query->lookup->cmdline, stdout);
00528                 query->lookup->cmdline[0]=0;
00529         }
00530         debug("printmessage(%s %s %s)", headers ? "headers" : "noheaders",
00531               query->lookup->comments ? "comments" : "nocomments",
00532               short_form ? "short_form" : "long_form");
00533 
00534         flags = 0;
00535         if (!headers) {
00536                 flags |= DNS_MESSAGETEXTFLAG_NOHEADERS;
00537                 flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS;
00538         }
00539         if (onesoa && query->lookup->rdtype == dns_rdatatype_axfr)
00540                 flags |= (query->msg_count == 0) ? DNS_MESSAGETEXTFLAG_ONESOA :
00541                                                    DNS_MESSAGETEXTFLAG_OMITSOA;
00542         if (!query->lookup->comments)
00543                 flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS;
00544 
00545         result = isc_buffer_allocate(mctx, &buf, len);
00546         check_result(result, "isc_buffer_allocate");
00547 
00548         if (query->lookup->comments && !short_form) {
00549                 if (query->lookup->cmdline[0] != 0)
00550                         printf("; %s\n", query->lookup->cmdline);
00551                 if (msg == query->lookup->sendmsg)
00552                         printf(";; Sending:\n");
00553                 else
00554                         printf(";; Got answer:\n");
00555 
00556                 if (headers) {
00557                         printf(";; ->>HEADER<<- opcode: %s, status: %s, "
00558                                "id: %u\n",
00559                                opcodetext[msg->opcode],
00560                                rcode_totext(msg->rcode),
00561                                msg->id);
00562                         printf(";; flags:");
00563                         if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
00564                                 printf(" qr");
00565                         if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
00566                                 printf(" aa");
00567                         if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
00568                                 printf(" tc");
00569                         if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
00570                                 printf(" rd");
00571                         if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
00572                                 printf(" ra");
00573                         if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
00574                                 printf(" ad");
00575                         if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
00576                                 printf(" cd");
00577                         if ((msg->flags & 0x0040U) != 0)
00578                                 printf("; MBZ: 0x4");
00579 
00580                         printf("; QUERY: %u, ANSWER: %u, "
00581                                "AUTHORITY: %u, ADDITIONAL: %u\n",
00582                                msg->counts[DNS_SECTION_QUESTION],
00583                                msg->counts[DNS_SECTION_ANSWER],
00584                                msg->counts[DNS_SECTION_AUTHORITY],
00585                                msg->counts[DNS_SECTION_ADDITIONAL]);
00586 
00587                         if (msg != query->lookup->sendmsg &&
00588                             (msg->flags & DNS_MESSAGEFLAG_RD) != 0 &&
00589                             (msg->flags & DNS_MESSAGEFLAG_RA) == 0)
00590                                 printf(";; WARNING: recursion requested "
00591                                        "but not available\n");
00592                 }
00593                 if (msg != query->lookup->sendmsg &&
00594                     query->lookup->edns != -1 && msg->opt == NULL &&
00595                     (msg->rcode == dns_rcode_formerr ||
00596                      msg->rcode == dns_rcode_notimp))
00597                         printf("\n;; WARNING: EDNS query returned status "
00598                                "%s - retry with '%s+noedns'\n",
00599                                rcode_totext(msg->rcode),
00600                                query->lookup->dnssec ? "+nodnssec ": "");
00601                 if (msg != query->lookup->sendmsg && extrabytes != 0U)
00602                         printf(";; WARNING: Message has %u extra byte%s at "
00603                                "end\n", extrabytes, extrabytes != 0 ? "s" : "");
00604         }
00605 
00606 repopulate_buffer:
00607 
00608         if (query->lookup->comments && headers && !short_form) {
00609                 result = dns_message_pseudosectiontotext(msg,
00610                          DNS_PSEUDOSECTION_OPT,
00611                          style, flags, buf);
00612                 if (result == ISC_R_NOSPACE) {
00613 buftoosmall:
00614                         len += OUTPUTBUF;
00615                         isc_buffer_free(&buf);
00616                         result = isc_buffer_allocate(mctx, &buf, len);
00617                         if (result == ISC_R_SUCCESS)
00618                                 goto repopulate_buffer;
00619                         else
00620                                 goto cleanup;
00621                 }
00622                 check_result(result,
00623                      "dns_message_pseudosectiontotext");
00624         }
00625 
00626         if (query->lookup->section_question && headers) {
00627                 if (!short_form) {
00628                         result = dns_message_sectiontotext(msg,
00629                                                        DNS_SECTION_QUESTION,
00630                                                        style, flags, buf);
00631                         if (result == ISC_R_NOSPACE)
00632                                 goto buftoosmall;
00633                         check_result(result, "dns_message_sectiontotext");
00634                 }
00635         }
00636         if (query->lookup->section_answer) {
00637                 if (!short_form) {
00638                         result = dns_message_sectiontotext(msg,
00639                                                        DNS_SECTION_ANSWER,
00640                                                        style, flags, buf);
00641                         if (result == ISC_R_NOSPACE)
00642                                 goto buftoosmall;
00643                         check_result(result, "dns_message_sectiontotext");
00644                 } else {
00645                         result = short_answer(msg, flags, buf, query);
00646                         if (result == ISC_R_NOSPACE)
00647                                 goto buftoosmall;
00648                         check_result(result, "short_answer");
00649                 }
00650         }
00651         if (query->lookup->section_authority) {
00652                 if (!short_form) {
00653                         result = dns_message_sectiontotext(msg,
00654                                                        DNS_SECTION_AUTHORITY,
00655                                                        style, flags, buf);
00656                         if (result == ISC_R_NOSPACE)
00657                                 goto buftoosmall;
00658                         check_result(result, "dns_message_sectiontotext");
00659                 }
00660         }
00661         if (query->lookup->section_additional) {
00662                 if (!short_form) {
00663                         result = dns_message_sectiontotext(msg,
00664                                                       DNS_SECTION_ADDITIONAL,
00665                                                       style, flags, buf);
00666                         if (result == ISC_R_NOSPACE)
00667                                 goto buftoosmall;
00668                         check_result(result, "dns_message_sectiontotext");
00669                         /*
00670                          * Only print the signature on the first record.
00671                          */
00672                         if (headers) {
00673                                 result = dns_message_pseudosectiontotext(
00674                                                    msg,
00675                                                    DNS_PSEUDOSECTION_TSIG,
00676                                                    style, flags, buf);
00677                                 if (result == ISC_R_NOSPACE)
00678                                         goto buftoosmall;
00679                                 check_result(result,
00680                                           "dns_message_pseudosectiontotext");
00681                                 result = dns_message_pseudosectiontotext(
00682                                                    msg,
00683                                                    DNS_PSEUDOSECTION_SIG0,
00684                                                    style, flags, buf);
00685                                 if (result == ISC_R_NOSPACE)
00686                                         goto buftoosmall;
00687                                 check_result(result,
00688                                            "dns_message_pseudosectiontotext");
00689                         }
00690                 }
00691         }
00692 
00693         if (headers && query->lookup->comments && !short_form)
00694                 printf("\n");
00695 
00696         printf("%.*s", (int)isc_buffer_usedlength(buf),
00697                (char *)isc_buffer_base(buf));
00698         isc_buffer_free(&buf);
00699 
00700 cleanup:
00701         if (style != NULL)
00702                 dns_master_styledestroy(&style, mctx);
00703         return (result);
00704 }
00705 
00706 /*%
00707  * print the greeting message when the program first starts up.
00708  */
00709 static void
00710 printgreeting(int argc, char **argv, dig_lookup_t *lookup) {
00711         int i;
00712         int remaining;
00713         static isc_boolean_t first = ISC_TRUE;
00714         char append[MXNAME];
00715 
00716         if (printcmd) {
00717                 lookup->cmdline[sizeof(lookup->cmdline) - 1] = 0;
00718                 snprintf(lookup->cmdline, sizeof(lookup->cmdline),
00719                          "%s; <<>> DiG " VERSION " <<>>",
00720                          first?"\n":"");
00721                 i = 1;
00722                 while (i < argc) {
00723                         snprintf(append, sizeof(append), " %s", argv[i++]);
00724                         remaining = sizeof(lookup->cmdline) -
00725                                     strlen(lookup->cmdline) - 1;
00726                         strncat(lookup->cmdline, append, remaining);
00727                 }
00728                 remaining = sizeof(lookup->cmdline) -
00729                             strlen(lookup->cmdline) - 1;
00730                 strncat(lookup->cmdline, "\n", remaining);
00731                 if (first && addresscount != 0) {
00732                         snprintf(append, sizeof(append),
00733                                  "; (%d server%s found)\n",
00734                                  addresscount,
00735                                  addresscount > 1 ? "s" : "");
00736                         remaining = sizeof(lookup->cmdline) -
00737                                     strlen(lookup->cmdline) - 1;
00738                         strncat(lookup->cmdline, append, remaining);
00739                 }
00740                 if (first) {
00741                         snprintf(append, sizeof(append),
00742                                  ";; global options:%s%s\n",
00743                                  short_form ? " +short" : "",
00744                                  printcmd ? " +cmd" : "");
00745                         first = ISC_FALSE;
00746                         remaining = sizeof(lookup->cmdline) -
00747                                     strlen(lookup->cmdline) - 1;
00748                         strncat(lookup->cmdline, append, remaining);
00749                 }
00750         }
00751 }
00752 
00753 /*%
00754  * We're not using isc_commandline_parse() here since the command line
00755  * syntax of dig is quite a bit different from that which can be described
00756  * by that routine.
00757  * XXX doc options
00758  */
00759 
00760 static void
00761 plus_option(char *option, isc_boolean_t is_batchfile,
00762             dig_lookup_t *lookup)
00763 {
00764         isc_result_t result;
00765         char option_store[256];
00766         char *cmd, *value, *ptr, *code;
00767         isc_uint32_t num;
00768         isc_boolean_t state = ISC_TRUE;
00769 #if defined(DIG_SIGCHASE) || defined(ISC_PLATFORM_USESIT)
00770         size_t n;
00771 #endif
00772 
00773         strncpy(option_store, option, sizeof(option_store));
00774         option_store[sizeof(option_store)-1]=0;
00775         ptr = option_store;
00776         cmd = next_token(&ptr,"=");
00777         if (cmd == NULL) {
00778                 printf(";; Invalid option %s\n", option_store);
00779                 return;
00780         }
00781         value = ptr;
00782         if (strncasecmp(cmd, "no", 2)==0) {
00783                 cmd += 2;
00784                 state = ISC_FALSE;
00785         }
00786 
00787 #define FULLCHECK(A) \
00788         do { \
00789                 size_t _l = strlen(cmd); \
00790                 if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \
00791                         goto invalid_option; \
00792         } while (0)
00793 #define FULLCHECK2(A, B) \
00794         do { \
00795                 size_t _l = strlen(cmd); \
00796                 if ((_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) && \
00797                     (_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0)) \
00798                         goto invalid_option; \
00799         } while (0)
00800 
00801         switch (cmd[0]) {
00802         case 'a':
00803                 switch (cmd[1]) {
00804                 case 'a': /* aaonly / aaflag */
00805                         FULLCHECK2("aaonly", "aaflag");
00806                         lookup->aaonly = state;
00807                         break;
00808                 case 'd':
00809                         switch (cmd[2]) {
00810                         case 'd': /* additional */
00811                                 FULLCHECK("additional");
00812                                 lookup->section_additional = state;
00813                                 break;
00814                         case 'f': /* adflag */
00815                         case '\0': /* +ad is a synonym for +adflag */
00816                                 FULLCHECK("adflag");
00817                                 lookup->adflag = state;
00818                                 break;
00819                         default:
00820                                 goto invalid_option;
00821                         }
00822                         break;
00823                 case 'l': /* all */
00824                         FULLCHECK("all");
00825                         lookup->section_question = state;
00826                         lookup->section_authority = state;
00827                         lookup->section_answer = state;
00828                         lookup->section_additional = state;
00829                         lookup->comments = state;
00830                         rrcomments = state;
00831                         lookup->stats = state;
00832                         printcmd = state;
00833                         break;
00834                 case 'n': /* answer */
00835                         FULLCHECK("answer");
00836                         lookup->section_answer = state;
00837                         break;
00838                 case 'u': /* authority */
00839                         FULLCHECK("authority");
00840                         lookup->section_authority = state;
00841                         break;
00842                 default:
00843                         goto invalid_option;
00844                 }
00845                 break;
00846         case 'b':
00847                 switch (cmd[1]) {
00848                 case 'e':/* besteffort */
00849                         FULLCHECK("besteffort");
00850                         lookup->besteffort = state;
00851                         break;
00852                 case 'u':/* bufsize */
00853                         FULLCHECK("bufsize");
00854                         if (value == NULL)
00855                                 goto need_value;
00856                         if (!state)
00857                                 goto invalid_option;
00858                         result = parse_uint(&num, value, COMMSIZE,
00859                                             "buffer size");
00860                         if (result != ISC_R_SUCCESS)
00861                                 fatal("Couldn't parse buffer size");
00862                         lookup->udpsize = num;
00863                         break;
00864                 default:
00865                         goto invalid_option;
00866                 }
00867                 break;
00868         case 'c':
00869                 switch (cmd[1]) {
00870                 case 'd':/* cdflag */
00871                         switch (cmd[2]) {
00872                         case 'f': /* cdflag */
00873                         case '\0': /* +cd is a synonym for +cdflag */
00874                                 FULLCHECK("cdflag");
00875                                 lookup->cdflag = state;
00876                                 break;
00877                         default:
00878                                 goto invalid_option;
00879                         }
00880                         break;
00881                 case 'l': /* cl */
00882                         FULLCHECK("cl");
00883                         noclass = ISC_TF(!state);
00884                         break;
00885                 case 'm': /* cmd */
00886                         FULLCHECK("cmd");
00887                         printcmd = state;
00888                         break;
00889                 case 'o': /* comments */
00890                         FULLCHECK("comments");
00891                         lookup->comments = state;
00892                         if (lookup == default_lookup)
00893                                 pluscomm = state;
00894                         break;
00895                 case 'r':
00896                         FULLCHECK("crypto");
00897                         nocrypto = ISC_TF(!state);
00898                         break;
00899                 default:
00900                         goto invalid_option;
00901                 }
00902                 break;
00903         case 'd':
00904                 switch (cmd[1]) {
00905                 case 'e': /* defname */
00906                         FULLCHECK("defname");
00907                         if (!lookup->trace) {
00908                                 usesearch = state;
00909                         }
00910                         break;
00911                 case 'n': /* dnssec */
00912                         FULLCHECK("dnssec");
00913                         if (state && lookup->edns == -1)
00914                                 lookup->edns = 0;
00915                         lookup->dnssec = state;
00916                         break;
00917                 case 'o': /* domain */
00918                         FULLCHECK("domain");
00919                         if (value == NULL)
00920                                 goto need_value;
00921                         if (!state)
00922                                 goto invalid_option;
00923                         strncpy(domainopt, value, sizeof(domainopt));
00924                         domainopt[sizeof(domainopt)-1] = '\0';
00925                         break;
00926                 case 's': /* dscp */
00927                         FULLCHECK("dscp");
00928                         if (!state) {
00929                                 lookup->dscp = -1;
00930                                 break;
00931                         }
00932                         if (value == NULL)
00933                                 goto need_value;
00934                         result = parse_uint(&num, value, 0x3f, "DSCP");
00935                         if (result != ISC_R_SUCCESS)
00936                                 fatal("Couldn't parse DSCP value");
00937                         lookup->dscp = num;
00938                         break;
00939                 default:
00940                         goto invalid_option;
00941                 }
00942                 break;
00943         case 'e':
00944                 switch (cmd[1]) {
00945                 case 'd':
00946                         switch(cmd[2]) {
00947                         case 'n':
00948                                 switch (cmd[3]) {
00949                                 case 's':
00950                                         switch (cmd[4]) {
00951                                         case 0:
00952                                                 FULLCHECK("edns");
00953                                                 if (!state) {
00954                                                         lookup->edns = -1;
00955                                                         break;
00956                                                 }
00957                                                 if (value == NULL) {
00958                                                         lookup->edns = 0;
00959                                                         break;
00960                                                 }
00961                                                 result = parse_uint(&num,
00962                                                                     value,
00963                                                                     255,
00964                                                                     "edns");
00965                                                 if (result != ISC_R_SUCCESS)
00966                                                         fatal("Couldn't parse "
00967                                                               "edns");
00968                                                 lookup->edns = num;
00969                                                 break;
00970                                         case 'f':
00971                                                 FULLCHECK("ednsflags");
00972                                                 if (!state) {
00973                                                         lookup->ednsflags = 0;
00974                                                         break;
00975                                                 }
00976                                                 if (value == NULL) {
00977                                                         lookup->ednsflags = 0;
00978                                                         break;
00979                                                 }
00980                                                 result = parse_xint(&num,
00981                                                                     value,
00982                                                                     0xffff,
00983                                                                   "ednsflags");
00984                                                 if (result != ISC_R_SUCCESS)
00985                                                         fatal("Couldn't parse "
00986                                                               "ednsflags");
00987                                                 lookup->ednsflags = num;
00988                                                 break;
00989                                         case 'n':
00990                                                 FULLCHECK("ednsnegotiation");
00991                                                 lookup->ednsneg = state;
00992                                                 break;
00993                                         case 'o':
00994                                                 FULLCHECK("ednsopt");
00995                                                 if (!state) {
00996                                                         lookup->ednsoptscnt = 0;
00997                                                         break;
00998                                                 }
00999                                                 if (value == NULL)
01000                                                         fatal("ednsopt no "
01001                                                               "code point "
01002                                                               "specified");
01003                                                 code = next_token(&value, ":");
01004                                                 save_opt(lookup, code, value);
01005                                                 break;
01006                                         default:
01007                                                 goto invalid_option;
01008                                         }
01009                                         break;
01010                                 default:
01011                                         goto invalid_option;
01012                                 }
01013                                 break;
01014                         default:
01015                                 goto invalid_option;
01016                         }
01017                         break;
01018                 case 'x':
01019                         FULLCHECK("expire");
01020                         lookup->expire = state;
01021                         break;
01022                 default:
01023                         goto invalid_option;
01024                 }
01025                 break;
01026         case 'f': /* fail */
01027                 FULLCHECK("fail");
01028                 lookup->servfail_stops = state;
01029                 break;
01030         case 'h':
01031                 FULLCHECK("header-only");
01032                 lookup->header_only = state;
01033                 break;
01034         case 'i':
01035                 switch (cmd[1]) {
01036                 case 'd': /* identify */
01037                         FULLCHECK("identify");
01038                         lookup->identify = state;
01039                         break;
01040                 case 'g': /* ignore */
01041                 default: /* Inherits default for compatibility */
01042                         FULLCHECK("ignore");
01043                         lookup->ignore = ISC_TRUE;
01044                 }
01045                 break;
01046         case 'k':
01047                 FULLCHECK("keepopen");
01048                 keep_open = state;
01049                 break;
01050         case 'm': /* multiline */
01051                 FULLCHECK("multiline");
01052                 multiline = state;
01053                 break;
01054         case 'n':
01055                 switch (cmd[1]) {
01056                 case 'd': /* ndots */
01057                         FULLCHECK("ndots");
01058                         if (value == NULL)
01059                                 goto need_value;
01060                         if (!state)
01061                                 goto invalid_option;
01062                         result = parse_uint(&num, value, MAXNDOTS, "ndots");
01063                         if (result != ISC_R_SUCCESS)
01064                                 fatal("Couldn't parse ndots");
01065                         ndots = num;
01066                         break;
01067                 case 's':
01068                         switch (cmd[2]) {
01069                         case 'i': /* nsid */
01070                                 FULLCHECK("nsid");
01071                                 if (state && lookup->edns == -1)
01072                                         lookup->edns = 0;
01073                                 lookup->nsid = state;
01074                                 break;
01075                         case 's': /* nssearch */
01076                                 FULLCHECK("nssearch");
01077                                 lookup->ns_search_only = state;
01078                                 if (state) {
01079                                         lookup->trace_root = ISC_TRUE;
01080                                         lookup->recurse = ISC_TRUE;
01081                                         lookup->identify = ISC_TRUE;
01082                                         lookup->stats = ISC_FALSE;
01083                                         lookup->comments = ISC_FALSE;
01084                                         rrcomments = ISC_FALSE;
01085                                         lookup->section_additional = ISC_FALSE;
01086                                         lookup->section_authority = ISC_FALSE;
01087                                         lookup->section_question = ISC_FALSE;
01088                                         lookup->rdtype = dns_rdatatype_ns;
01089                                         lookup->rdtypeset = ISC_TRUE;
01090                                         short_form = ISC_TRUE;
01091                                 }
01092                                 break;
01093                         default:
01094                                 goto invalid_option;
01095                         }
01096                         break;
01097                 default:
01098                         goto invalid_option;
01099                 }
01100                 break;
01101         case 'o':
01102                 FULLCHECK("onesoa");
01103                 onesoa = state;
01104                 break;
01105         case 'q':
01106                 switch (cmd[1]) {
01107                 case 'r': /* qr */
01108                         FULLCHECK("qr");
01109                         qr = state;
01110                         break;
01111                 case 'u': /* question */
01112                         FULLCHECK("question");
01113                         lookup->section_question = state;
01114                         if (lookup == default_lookup)
01115                                 plusquest = state;
01116                         break;
01117                 default:
01118                         goto invalid_option;
01119                 }
01120                 break;
01121         case 'r':
01122                 switch (cmd[1]) {
01123                 case 'e':
01124                         switch (cmd[2]) {
01125                         case 'c': /* recurse */
01126                                 FULLCHECK("recurse");
01127                                 lookup->recurse = state;
01128                                 break;
01129                         case 't': /* retry / retries */
01130                                 FULLCHECK2("retry", "retries");
01131                                 if (value == NULL)
01132                                         goto need_value;
01133                                 if (!state)
01134                                         goto invalid_option;
01135                                 result = parse_uint(&lookup->retries, value,
01136                                                     MAXTRIES - 1, "retries");
01137                                 if (result != ISC_R_SUCCESS)
01138                                         fatal("Couldn't parse retries");
01139                                 lookup->retries++;
01140                                 break;
01141                         default:
01142                                 goto invalid_option;
01143                         }
01144                         break;
01145                 case 'r': /* rrcomments */
01146                         FULLCHECK("rrcomments");
01147                         rrcomments = state;
01148                         break;
01149                 default:
01150                         goto invalid_option;
01151                 }
01152                 break;
01153         case 's':
01154                 switch (cmd[1]) {
01155                 case 'e': /* search */
01156                         FULLCHECK("search");
01157                         if (!lookup->trace) {
01158                                 usesearch = state;
01159                         }
01160                         break;
01161                 case 'h':
01162                         if (cmd[2] != 'o')
01163                                 goto invalid_option;
01164                         switch (cmd[3]) {
01165                         case 'r': /* short */
01166                                 FULLCHECK("short");
01167                                 short_form = state;
01168                                 if (state) {
01169                                         printcmd = ISC_FALSE;
01170                                         lookup->section_additional = ISC_FALSE;
01171                                         lookup->section_answer = ISC_TRUE;
01172                                         lookup->section_authority = ISC_FALSE;
01173                                         lookup->section_question = ISC_FALSE;
01174                                         lookup->comments = ISC_FALSE;
01175                                         rrcomments = ISC_FALSE;
01176                                         lookup->stats = ISC_FALSE;
01177                                 }
01178                                 break;
01179                         case 'w': /* showsearch */
01180                                 FULLCHECK("showsearch");
01181                                 if (!lookup->trace) {
01182                                         showsearch = state;
01183                                         usesearch = state;
01184                                 }
01185                                 break;
01186                         default:
01187                                 goto invalid_option;
01188                         }
01189                         break;
01190 #if defined(DIG_SIGCHASE) || defined(ISC_PLATFORM_USESIT)
01191                 case 'i':
01192                         switch (cmd[2]) {
01193 #ifdef DIG_SIGCHASE
01194                         case 'g': /* sigchase */
01195                                 FULLCHECK("sigchase");
01196                                 lookup->sigchase = state;
01197                                 if (lookup->sigchase)
01198                                         lookup->dnssec = ISC_TRUE;
01199                                 break;
01200 #endif
01201 #ifdef ISC_PLATFORM_USESIT
01202                         case 't': /* sit */
01203                                 FULLCHECK("sit");
01204                                 if (state && lookup->edns == -1)
01205                                         lookup->edns = 0;
01206                                 lookup->sit = state;
01207                                 if (value != NULL) {
01208                                         n = strlcpy(sitvalue, value,
01209                                                     sizeof(sitvalue));
01210                                         if (n >= sizeof(sitvalue))
01211                                                 fatal("SIT data too large");
01212                                         lookup->sitvalue = sitvalue;
01213                                 } else
01214                                         lookup->sitvalue = NULL;
01215                                 break;
01216 #endif
01217                         default:
01218                                 goto invalid_option;
01219                         }
01220                         break;
01221 #endif
01222                 case 'p': /* split */
01223                         FULLCHECK("split");
01224                         if (value != NULL && !state)
01225                                 goto invalid_option;
01226                         if (!state) {
01227                                 splitwidth = 0;
01228                                 break;
01229                         } else if (value == NULL)
01230                                 break;
01231 
01232                         result = parse_uint(&splitwidth, value,
01233                                             1023, "split");
01234                         if (splitwidth % 4 != 0) {
01235                                 splitwidth = ((splitwidth + 3) / 4) * 4;
01236                                 fprintf(stderr, ";; Warning, split must be "
01237                                                 "a multiple of 4; adjusting "
01238                                                 "to %d\n", splitwidth);
01239                         }
01240                         /*
01241                          * There is an adjustment done in the
01242                          * totext_<rrtype>() functions which causes
01243                          * splitwidth to shrink.  This is okay when we're
01244                          * using the default width but incorrect in this
01245                          * case, so we correct for it
01246                          */
01247                         if (splitwidth)
01248                                 splitwidth += 3;
01249                         if (result != ISC_R_SUCCESS)
01250                                 fatal("Couldn't parse split");
01251                         break;
01252                 case 't': /* stats */
01253                         FULLCHECK("stats");
01254                         lookup->stats = state;
01255                         break;
01256                 case 'u': /* subnet */
01257                         FULLCHECK("subnet");
01258                         if (state && value == NULL)
01259                                 goto need_value;
01260                         if (!state) {
01261                                 if (lookup->ecs_addr != NULL) {
01262                                         isc_mem_free(mctx, lookup->ecs_addr);
01263                                         lookup->ecs_addr = NULL;
01264                                 }
01265                                 break;
01266                         }
01267                         if (lookup->edns == -1)
01268                                 lookup->edns = 0;
01269                         result = parse_netprefix(&lookup->ecs_addr, value);
01270                         if (result != ISC_R_SUCCESS)
01271                                 fatal("Couldn't parse client");
01272                         break;
01273                 default:
01274                         goto invalid_option;
01275                 }
01276                 break;
01277         case 't':
01278                 switch (cmd[1]) {
01279                 case 'c': /* tcp */
01280                         FULLCHECK("tcp");
01281                         if (!is_batchfile) {
01282                                 lookup->tcp_mode = state;
01283                                 lookup->tcp_mode_set = ISC_TRUE;
01284                         }
01285                         break;
01286                 case 'i': /* timeout */
01287                         FULLCHECK("timeout");
01288                         if (value == NULL)
01289                                 goto need_value;
01290                         if (!state)
01291                                 goto invalid_option;
01292                         result = parse_uint(&timeout, value, MAXTIMEOUT,
01293                                             "timeout");
01294                         if (result != ISC_R_SUCCESS)
01295                                 fatal("Couldn't parse timeout");
01296                         if (timeout == 0)
01297                                 timeout = 1;
01298                         break;
01299 #if DIG_SIGCHASE_TD
01300                 case 'o': /* topdown */
01301                         FULLCHECK("topdown");
01302                         lookup->do_topdown = state;
01303                         break;
01304 #endif
01305                 case 'r':
01306                         switch (cmd[2]) {
01307                         case 'a': /* trace */
01308                                 FULLCHECK("trace");
01309                                 lookup->trace = state;
01310                                 lookup->trace_root = state;
01311                                 if (state) {
01312                                         lookup->recurse = ISC_FALSE;
01313                                         lookup->identify = ISC_TRUE;
01314                                         lookup->comments = ISC_FALSE;
01315                                         rrcomments = ISC_FALSE;
01316                                         lookup->stats = ISC_FALSE;
01317                                         lookup->section_additional = ISC_FALSE;
01318                                         lookup->section_authority = ISC_TRUE;
01319                                         lookup->section_question = ISC_FALSE;
01320                                         lookup->dnssec = ISC_TRUE;
01321                                         usesearch = ISC_FALSE;
01322                                 }
01323                                 break;
01324                         case 'i': /* tries */
01325                                 FULLCHECK("tries");
01326                                 if (value == NULL)
01327                                         goto need_value;
01328                                 if (!state)
01329                                         goto invalid_option;
01330                                 result = parse_uint(&lookup->retries, value,
01331                                                     MAXTRIES, "tries");
01332                                 if (result != ISC_R_SUCCESS)
01333                                         fatal("Couldn't parse tries");
01334                                 if (lookup->retries == 0)
01335                                         lookup->retries = 1;
01336                                 break;
01337 #ifdef DIG_SIGCHASE
01338                         case 'u': /* trusted-key */
01339                                 FULLCHECK("trusted-key");
01340                                 if (value == NULL)
01341                                         goto need_value;
01342                                 if (!state)
01343                                         goto invalid_option;
01344                                 n = strlcpy(trustedkey, ptr,
01345                                             sizeof(trustedkey));
01346                                 if (n >= sizeof(trustedkey))
01347                                         fatal("trusted key too large");
01348                                 break;
01349 #endif
01350                         default:
01351                                 goto invalid_option;
01352                         }
01353                         break;
01354                 case 't':
01355                         switch (cmd[2]) {
01356                         case 'l':
01357                                 switch (cmd[3]) {
01358                                 case 0:
01359                                 case 'i': /* ttlid */
01360                                         FULLCHECK2("ttl", "ttlid");
01361                                         nottl = ISC_TF(!state);
01362                                         break;
01363                                 case 'u': /* ttlunits */
01364                                         FULLCHECK("ttlunits");
01365                                         nottl = ISC_FALSE;
01366                                         ttlunits = ISC_TF(state);
01367                                         break;
01368                                 default:
01369                                         goto invalid_option;
01370                                 }
01371                                 break;
01372                         default:
01373                                 goto invalid_option;
01374                         }
01375                         break;
01376                 default:
01377                         goto invalid_option;
01378                 }
01379                 break;
01380         case 'v':
01381                 FULLCHECK("vc");
01382                 if (!is_batchfile) {
01383                         lookup->tcp_mode = state;
01384                         lookup->tcp_mode_set = ISC_TRUE;
01385                 }
01386                 break;
01387         case 'z': /* zflag */
01388                 FULLCHECK("zflag");
01389                 lookup->zflag = state;
01390                 break;
01391         default:
01392         invalid_option:
01393         need_value:
01394                 fprintf(stderr, "Invalid option: +%s\n",
01395                          option);
01396                 usage();
01397         }
01398         return;
01399 }
01400 
01401 /*%
01402  * #ISC_TRUE returned if value was used
01403  */
01404 static const char *single_dash_opts = "46dhimnuv";
01405 static const char *dash_opts = "46bcdfhikmnptvyx";
01406 static isc_boolean_t
01407 dash_option(char *option, char *next, dig_lookup_t **lookup,
01408             isc_boolean_t *open_type_class, isc_boolean_t *need_clone,
01409             isc_boolean_t config_only, int argc, char **argv,
01410             isc_boolean_t *firstarg)
01411 {
01412         char opt, *value, *ptr, *ptr2, *ptr3;
01413         isc_result_t result;
01414         isc_boolean_t value_from_next;
01415         isc_textregion_t tr;
01416         dns_rdatatype_t rdtype;
01417         dns_rdataclass_t rdclass;
01418         char textname[MXNAME];
01419         struct in_addr in4;
01420         struct in6_addr in6;
01421         in_port_t srcport;
01422         char *hash, *cmd;
01423         isc_uint32_t num;
01424 
01425         while (strpbrk(option, single_dash_opts) == &option[0]) {
01426                 /*
01427                  * Since the -[46dhimnuv] options do not take an argument,
01428                  * account for them (in any number and/or combination)
01429                  * if they appear as the first character(s) of a q-opt.
01430                  */
01431                 opt = option[0];
01432                 switch (opt) {
01433                 case '4':
01434                         if (have_ipv4) {
01435                                 isc_net_disableipv6();
01436                                 have_ipv6 = ISC_FALSE;
01437                         } else {
01438                                 fatal("can't find IPv4 networking");
01439                                 /* NOTREACHED */
01440                                 return (ISC_FALSE);
01441                         }
01442                         break;
01443                 case '6':
01444                         if (have_ipv6) {
01445                                 isc_net_disableipv4();
01446                                 have_ipv4 = ISC_FALSE;
01447                         } else {
01448                                 fatal("can't find IPv6 networking");
01449                                 /* NOTREACHED */
01450                                 return (ISC_FALSE);
01451                         }
01452                         break;
01453                 case 'd':
01454                         ptr = strpbrk(&option[1], dash_opts);
01455                         if (ptr != &option[1]) {
01456                                 cmd = option;
01457                                 FULLCHECK("debug");
01458                                 debugging = ISC_TRUE;
01459                                 return (ISC_FALSE);
01460                         } else
01461                                 debugging = ISC_TRUE;
01462                         break;
01463                 case 'h':
01464                         help();
01465                         exit(0);
01466                         break;
01467                 case 'i':
01468                         ip6_int = ISC_TRUE;
01469                         break;
01470                 case 'm': /* memdebug */
01471                         /* memdebug is handled in preparse_args() */
01472                         break;
01473                 case 'n':
01474                         /* deprecated */
01475                         break;
01476                 case 'u':
01477                         use_usec = ISC_TRUE;
01478                         break;
01479                 case 'v':
01480                         version();
01481                         exit(0);
01482                         break;
01483                 }
01484                 if (strlen(option) > 1U)
01485                         option = &option[1];
01486                 else
01487                         return (ISC_FALSE);
01488         }
01489         opt = option[0];
01490         if (strlen(option) > 1U) {
01491                 value_from_next = ISC_FALSE;
01492                 value = &option[1];
01493         } else {
01494                 value_from_next = ISC_TRUE;
01495                 value = next;
01496         }
01497         if (value == NULL)
01498                 goto invalid_option;
01499         switch (opt) {
01500         case 'b':
01501                 hash = strchr(value, '#');
01502                 if (hash != NULL) {
01503                         result = parse_uint(&num, hash + 1, MAXPORT,
01504                                             "port number");
01505                         if (result != ISC_R_SUCCESS)
01506                                 fatal("Couldn't parse port number");
01507                         srcport = num;
01508                         *hash = '\0';
01509                 } else
01510                         srcport = 0;
01511                 if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) {
01512                         isc_sockaddr_fromin6(&bind_address, &in6, srcport);
01513                         isc_net_disableipv4();
01514                 } else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) {
01515                         isc_sockaddr_fromin(&bind_address, &in4, srcport);
01516                         isc_net_disableipv6();
01517                 } else {
01518                         if (hash != NULL)
01519                                 *hash = '#';
01520                         fatal("invalid address %s", value);
01521                 }
01522                 if (hash != NULL)
01523                         *hash = '#';
01524                 specified_source = ISC_TRUE;
01525                 return (value_from_next);
01526         case 'c':
01527                 if ((*lookup)->rdclassset) {
01528                         fprintf(stderr, ";; Warning, extra class option\n");
01529                 }
01530                 *open_type_class = ISC_FALSE;
01531                 tr.base = value;
01532                 tr.length = strlen(value);
01533                 result = dns_rdataclass_fromtext(&rdclass,
01534                                                  (isc_textregion_t *)&tr);
01535                 if (result == ISC_R_SUCCESS) {
01536                         (*lookup)->rdclass = rdclass;
01537                         (*lookup)->rdclassset = ISC_TRUE;
01538                 } else
01539                         fprintf(stderr, ";; Warning, ignoring "
01540                                 "invalid class %s\n",
01541                                 value);
01542                 return (value_from_next);
01543         case 'f':
01544                 batchname = value;
01545                 return (value_from_next);
01546         case 'k':
01547                 strncpy(keyfile, value, sizeof(keyfile));
01548                 keyfile[sizeof(keyfile)-1]=0;
01549                 return (value_from_next);
01550         case 'p':
01551                 result = parse_uint(&num, value, MAXPORT, "port number");
01552                 if (result != ISC_R_SUCCESS)
01553                         fatal("Couldn't parse port number");
01554                 port = num;
01555                 return (value_from_next);
01556         case 'q':
01557                 if (!config_only) {
01558                         if (*need_clone)
01559                                 (*lookup) = clone_lookup(default_lookup,
01560                                                          ISC_TRUE);
01561                         *need_clone = ISC_TRUE;
01562                         strncpy((*lookup)->textname, value,
01563                                 sizeof((*lookup)->textname));
01564                         (*lookup)->textname[sizeof((*lookup)->textname)-1]=0;
01565                         (*lookup)->trace_root = ISC_TF((*lookup)->trace  ||
01566                                                      (*lookup)->ns_search_only);
01567                         (*lookup)->new_search = ISC_TRUE;
01568                         if (*firstarg) {
01569                                 printgreeting(argc, argv, *lookup);
01570                                 *firstarg = ISC_FALSE;
01571                         }
01572                         ISC_LIST_APPEND(lookup_list, (*lookup), link);
01573                         debug("looking up %s", (*lookup)->textname);
01574                 }
01575                 return (value_from_next);
01576         case 't':
01577                 *open_type_class = ISC_FALSE;
01578                 if (strncasecmp(value, "ixfr=", 5) == 0) {
01579                         rdtype = dns_rdatatype_ixfr;
01580                         result = ISC_R_SUCCESS;
01581                 } else {
01582                         tr.base = value;
01583                         tr.length = strlen(value);
01584                         result = dns_rdatatype_fromtext(&rdtype,
01585                                                 (isc_textregion_t *)&tr);
01586                         if (result == ISC_R_SUCCESS &&
01587                             rdtype == dns_rdatatype_ixfr) {
01588                                 result = DNS_R_UNKNOWN;
01589                         }
01590                 }
01591                 if (result == ISC_R_SUCCESS) {
01592                         if ((*lookup)->rdtypeset) {
01593                                 fprintf(stderr, ";; Warning, "
01594                                                 "extra type option\n");
01595                         }
01596                         if (rdtype == dns_rdatatype_ixfr) {
01597                                 isc_uint32_t serial;
01598                                 (*lookup)->rdtype = dns_rdatatype_ixfr;
01599                                 (*lookup)->rdtypeset = ISC_TRUE;
01600                                 result = parse_uint(&serial, &value[5],
01601                                            MAXSERIAL, "serial number");
01602                                 if (result != ISC_R_SUCCESS)
01603                                         fatal("Couldn't parse serial number");
01604                                 (*lookup)->ixfr_serial = serial;
01605                                 (*lookup)->section_question = plusquest;
01606                                 (*lookup)->comments = pluscomm;
01607                                 if (!(*lookup)->tcp_mode_set)
01608                                         (*lookup)->tcp_mode = ISC_TRUE;
01609                         } else {
01610                                 (*lookup)->rdtype = rdtype;
01611                                 if (!config_only)
01612                                         (*lookup)->rdtypeset = ISC_TRUE;
01613                                 if (rdtype == dns_rdatatype_axfr) {
01614                                         (*lookup)->section_question = plusquest;
01615                                         (*lookup)->comments = pluscomm;
01616                                 }
01617                                 (*lookup)->ixfr_serial = ISC_FALSE;
01618                         }
01619                 } else
01620                         fprintf(stderr, ";; Warning, ignoring "
01621                                  "invalid type %s\n",
01622                                  value);
01623                 return (value_from_next);
01624         case 'y':
01625                 ptr = next_token(&value,":");   /* hmac type or name */
01626                 if (ptr == NULL) {
01627                         usage();
01628                 }
01629                 ptr2 = next_token(&value, ":"); /* name or secret */
01630                 if (ptr2 == NULL)
01631                         usage();
01632                 ptr3 = next_token(&value,":"); /* secret or NULL */
01633                 if (ptr3 != NULL) {
01634                         parse_hmac(ptr);
01635                         ptr = ptr2;
01636                         ptr2 = ptr3;
01637                 } else  {
01638                         hmacname = DNS_TSIG_HMACMD5_NAME;
01639                         digestbits = 0;
01640                 }
01641                 strncpy(keynametext, ptr, sizeof(keynametext));
01642                 keynametext[sizeof(keynametext)-1]=0;
01643                 strncpy(keysecret, ptr2, sizeof(keysecret));
01644                 keysecret[sizeof(keysecret)-1]=0;
01645                 return (value_from_next);
01646         case 'x':
01647                 if (*need_clone)
01648                         *lookup = clone_lookup(default_lookup, ISC_TRUE);
01649                 *need_clone = ISC_TRUE;
01650                 if (get_reverse(textname, sizeof(textname), value,
01651                                 ip6_int, ISC_FALSE) == ISC_R_SUCCESS) {
01652                         strncpy((*lookup)->textname, textname,
01653                                 sizeof((*lookup)->textname));
01654                         (*lookup)->textname[sizeof((*lookup)->textname)-1] = 0;
01655                         debug("looking up %s", (*lookup)->textname);
01656                         (*lookup)->trace_root = ISC_TF((*lookup)->trace  ||
01657                                                 (*lookup)->ns_search_only);
01658                         (*lookup)->ip6_int = ip6_int;
01659                         if (!(*lookup)->rdtypeset)
01660                                 (*lookup)->rdtype = dns_rdatatype_ptr;
01661                         if (!(*lookup)->rdclassset)
01662                                 (*lookup)->rdclass = dns_rdataclass_in;
01663                         (*lookup)->new_search = ISC_TRUE;
01664                         if (*firstarg) {
01665                                 printgreeting(argc, argv, *lookup);
01666                                 *firstarg = ISC_FALSE;
01667                         }
01668                         ISC_LIST_APPEND(lookup_list, *lookup, link);
01669                 } else {
01670                         fprintf(stderr, "Invalid IP address %s\n", value);
01671                         exit(1);
01672                 }
01673                 return (value_from_next);
01674         invalid_option:
01675         default:
01676                 fprintf(stderr, "Invalid option: -%s\n", option);
01677                 usage();
01678         }
01679         /* NOTREACHED */
01680         return (ISC_FALSE);
01681 }
01682 
01683 /*%
01684  * Because we may be trying to do memory allocation recording, we're going
01685  * to need to parse the arguments for the -m *before* we start the main
01686  * argument parsing routine.
01687  *
01688  * I'd prefer not to have to do this, but I am not quite sure how else to
01689  * fix the problem.  Argument parsing in dig involves memory allocation
01690  * by its nature, so it can't be done in the main argument parser.
01691  */
01692 static void
01693 preparse_args(int argc, char **argv) {
01694         int rc;
01695         char **rv;
01696         char *option;
01697 
01698         rc = argc;
01699         rv = argv;
01700         for (rc--, rv++; rc > 0; rc--, rv++) {
01701                 if (rv[0][0] != '-')
01702                         continue;
01703                 option = &rv[0][1];
01704                 while (strpbrk(option, single_dash_opts) == &option[0]) {
01705                         if (option[0] == 'm') {
01706                                 memdebugging = ISC_TRUE;
01707                                 isc_mem_debugging = ISC_MEM_DEBUGTRACE |
01708                                         ISC_MEM_DEBUGRECORD;
01709                                 return;
01710                         }
01711                         option = &option[1];
01712                 }
01713         }
01714 }
01715 
01716 static void
01717 parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only,
01718            int argc, char **argv)
01719 {
01720         isc_result_t result;
01721         isc_textregion_t tr;
01722         isc_boolean_t firstarg = ISC_TRUE;
01723         dig_lookup_t *lookup = NULL;
01724         dns_rdatatype_t rdtype;
01725         dns_rdataclass_t rdclass;
01726         isc_boolean_t open_type_class = ISC_TRUE;
01727         char batchline[MXNAME];
01728         int bargc;
01729         char *bargv[64];
01730         int rc;
01731         char **rv;
01732 #ifndef NOPOSIX
01733         char *homedir;
01734         char rcfile[256];
01735 #endif
01736         char *input;
01737         int i;
01738         isc_boolean_t need_clone = ISC_TRUE;
01739 
01740         /*
01741          * The semantics for parsing the args is a bit complex; if
01742          * we don't have a host yet, make the arg apply globally,
01743          * otherwise make it apply to the latest host.  This is
01744          * a bit different than the previous versions, but should
01745          * form a consistent user interface.
01746          *
01747          * First, create a "default lookup" which won't actually be used
01748          * anywhere, except for cloning into new lookups
01749          */
01750 
01751         debug("parse_args()");
01752         if (!is_batchfile) {
01753                 debug("making new lookup");
01754                 default_lookup = make_empty_lookup();
01755                 default_lookup->adflag = ISC_TRUE;
01756                 default_lookup->edns = 0;
01757 
01758 #ifndef NOPOSIX
01759                 /*
01760                  * Treat ${HOME}/.digrc as a special batchfile
01761                  */
01762                 INSIST(batchfp == NULL);
01763                 homedir = getenv("HOME");
01764                 if (homedir != NULL) {
01765                         unsigned int n;
01766                         n = snprintf(rcfile, sizeof(rcfile), "%s/.digrc",
01767                                      homedir);
01768                         if (n < sizeof(rcfile))
01769                                 batchfp = fopen(rcfile, "r");
01770                 }
01771                 if (batchfp != NULL) {
01772                         while (fgets(batchline, sizeof(batchline),
01773                                      batchfp) != 0) {
01774                                 debug("config line %s", batchline);
01775                                 bargc = 1;
01776                                 input = batchline;
01777                                 bargv[bargc] = next_token(&input, " \t\r\n");
01778                                 while ((bargv[bargc] != NULL) &&
01779                                        (bargc < 62)) {
01780                                         bargc++;
01781                                         bargv[bargc] =
01782                                                 next_token(&input, " \t\r\n");
01783                                 }
01784 
01785                                 bargv[0] = argv[0];
01786                                 argv0 = argv[0];
01787 
01788                                 for(i = 0; i < bargc; i++)
01789                                         debug(".digrc argv %d: %s",
01790                                               i, bargv[i]);
01791                                 parse_args(ISC_TRUE, ISC_TRUE, bargc,
01792                                            (char **)bargv);
01793                         }
01794                         fclose(batchfp);
01795                 }
01796 #endif
01797         }
01798 
01799         if (is_batchfile && !config_only) {
01800                 /* Processing '-f batchfile'. */
01801                 lookup = clone_lookup(default_lookup, ISC_TRUE);
01802                 need_clone = ISC_FALSE;
01803         } else
01804                 lookup = default_lookup;
01805 
01806         rc = argc;
01807         rv = argv;
01808         for (rc--, rv++; rc > 0; rc--, rv++) {
01809                 debug("main parsing %s", rv[0]);
01810                 if (strncmp(rv[0], "%", 1) == 0)
01811                         break;
01812                 if (rv[0][0] == '@') {
01813 
01814                         if (is_batchfile && !config_only) {
01815                                 addresscount = getaddresses(lookup, &rv[0][1],
01816                                                              &result);
01817                                 if (result != ISC_R_SUCCESS) {
01818                                         fprintf(stderr, "couldn't get address "
01819                                                 "for '%s': %s: skipping "
01820                                                 "lookup\n", &rv[0][1],
01821                                                 isc_result_totext(result));
01822                                         if (ISC_LINK_LINKED(lookup, link))
01823                                                 ISC_LIST_DEQUEUE(lookup_list,
01824                                                                  lookup, link);
01825                                         destroy_lookup(lookup);
01826                                         return;
01827                                 }
01828                         } else
01829                                 addresscount = getaddresses(lookup, &rv[0][1],
01830                                                             NULL);
01831                 } else if (rv[0][0] == '+') {
01832                         plus_option(&rv[0][1], is_batchfile,
01833                                     lookup);
01834                 } else if (rv[0][0] == '-') {
01835                         if (rc <= 1) {
01836                                 if (dash_option(&rv[0][1], NULL,
01837                                                 &lookup, &open_type_class,
01838                                                 &need_clone, config_only,
01839                                                 argc, argv, &firstarg)) {
01840                                         rc--;
01841                                         rv++;
01842                                 }
01843                         } else {
01844                                 if (dash_option(&rv[0][1], rv[1],
01845                                                 &lookup, &open_type_class,
01846                                                 &need_clone, config_only,
01847                                                 argc, argv, &firstarg)) {
01848                                         rc--;
01849                                         rv++;
01850                                 }
01851                         }
01852                 } else {
01853                         /*
01854                          * Anything which isn't an option
01855                          */
01856                         if (open_type_class) {
01857                                 if (strncasecmp(rv[0], "ixfr=", 5) == 0) {
01858                                         rdtype = dns_rdatatype_ixfr;
01859                                         result = ISC_R_SUCCESS;
01860                                 } else {
01861                                         tr.base = rv[0];
01862                                         tr.length = strlen(rv[0]);
01863                                         result = dns_rdatatype_fromtext(&rdtype,
01864                                                 (isc_textregion_t *)&tr);
01865                                         if (result == ISC_R_SUCCESS &&
01866                                             rdtype == dns_rdatatype_ixfr) {
01867                                                 fprintf(stderr, ";; Warning, "
01868                                                         "ixfr requires a "
01869                                                         "serial number\n");
01870                                                 continue;
01871                                         }
01872                                 }
01873                                 if (result == ISC_R_SUCCESS) {
01874                                         if (lookup->rdtypeset) {
01875                                                 fprintf(stderr, ";; Warning, "
01876                                                         "extra type option\n");
01877                                         }
01878                                         if (rdtype == dns_rdatatype_ixfr) {
01879                                                 isc_uint32_t serial;
01880                                                 lookup->rdtype =
01881                                                         dns_rdatatype_ixfr;
01882                                                 lookup->rdtypeset = ISC_TRUE;
01883                                                 result = parse_uint(&serial,
01884                                                                     &rv[0][5],
01885                                                                     MAXSERIAL,
01886                                                               "serial number");
01887                                                 if (result != ISC_R_SUCCESS)
01888                                                         fatal("Couldn't parse "
01889                                                               "serial number");
01890                                                 lookup->ixfr_serial = serial;
01891                                                 lookup->section_question =
01892                                                         plusquest;
01893                                                 lookup->comments = pluscomm;
01894                                                 if (!lookup->tcp_mode_set)
01895                                                         lookup->tcp_mode = ISC_TRUE;
01896                                         } else {
01897                                                 lookup->rdtype = rdtype;
01898                                                 lookup->rdtypeset = ISC_TRUE;
01899                                                 if (rdtype ==
01900                                                     dns_rdatatype_axfr) {
01901                                                     lookup->section_question =
01902                                                                 plusquest;
01903                                                     lookup->comments = pluscomm;
01904                                                 }
01905                                                 lookup->ixfr_serial = ISC_FALSE;
01906                                         }
01907                                         continue;
01908                                 }
01909                                 result = dns_rdataclass_fromtext(&rdclass,
01910                                                      (isc_textregion_t *)&tr);
01911                                 if (result == ISC_R_SUCCESS) {
01912                                         if (lookup->rdclassset) {
01913                                                 fprintf(stderr, ";; Warning, "
01914                                                         "extra class option\n");
01915                                         }
01916                                         lookup->rdclass = rdclass;
01917                                         lookup->rdclassset = ISC_TRUE;
01918                                         continue;
01919                                 }
01920                         }
01921 
01922                         if (!config_only) {
01923                                 if (need_clone)
01924                                         lookup = clone_lookup(default_lookup,
01925                                                                       ISC_TRUE);
01926                                 need_clone = ISC_TRUE;
01927                                 strncpy(lookup->textname, rv[0],
01928                                         sizeof(lookup->textname));
01929                                 lookup->textname[sizeof(lookup->textname)-1]=0;
01930                                 lookup->trace_root = ISC_TF(lookup->trace  ||
01931                                                      lookup->ns_search_only);
01932                                 lookup->new_search = ISC_TRUE;
01933                                 if (firstarg) {
01934                                         printgreeting(argc, argv, lookup);
01935                                         firstarg = ISC_FALSE;
01936                                 }
01937                                 ISC_LIST_APPEND(lookup_list, lookup, link);
01938                                 debug("looking up %s", lookup->textname);
01939                         }
01940                         /* XXX Error message */
01941                 }
01942         }
01943 
01944         /*
01945          * If we have a batchfile, seed the lookup list with the
01946          * first entry, then trust the callback in dighost_shutdown
01947          * to get the rest
01948          */
01949         if ((batchname != NULL) && !(is_batchfile)) {
01950                 if (strcmp(batchname, "-") == 0)
01951                         batchfp = stdin;
01952                 else
01953                         batchfp = fopen(batchname, "r");
01954                 if (batchfp == NULL) {
01955                         perror(batchname);
01956                         if (exitcode < 8)
01957                                 exitcode = 8;
01958                         fatal("couldn't open specified batch file");
01959                 }
01960                 /* XXX Remove code dup from shutdown code */
01961         next_line:
01962                 if (fgets(batchline, sizeof(batchline), batchfp) != 0) {
01963                         bargc = 1;
01964                         debug("batch line %s", batchline);
01965                         if (batchline[0] == '\r' || batchline[0] == '\n'
01966                             || batchline[0] == '#' || batchline[0] == ';')
01967                                 goto next_line;
01968                         input = batchline;
01969                         bargv[bargc] = next_token(&input, " \t\r\n");
01970                         while ((bargv[bargc] != NULL) && (bargc < 14)) {
01971                                 bargc++;
01972                                 bargv[bargc] = next_token(&input, " \t\r\n");
01973                         }
01974 
01975                         bargv[0] = argv[0];
01976                         argv0 = argv[0];
01977 
01978                         for(i = 0; i < bargc; i++)
01979                                 debug("batch argv %d: %s", i, bargv[i]);
01980                         parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv);
01981                         return;
01982                 }
01983                 return;
01984         }
01985         /*
01986          * If no lookup specified, search for root
01987          */
01988         if ((lookup_list.head == NULL) && !config_only) {
01989                 if (need_clone)
01990                         lookup = clone_lookup(default_lookup, ISC_TRUE);
01991                 need_clone = ISC_TRUE;
01992                 lookup->trace_root = ISC_TF(lookup->trace ||
01993                                             lookup->ns_search_only);
01994                 lookup->new_search = ISC_TRUE;
01995                 strcpy(lookup->textname, ".");
01996                 lookup->rdtype = dns_rdatatype_ns;
01997                 lookup->rdtypeset = ISC_TRUE;
01998                 if (firstarg) {
01999                         printgreeting(argc, argv, lookup);
02000                         firstarg = ISC_FALSE;
02001                 }
02002                 ISC_LIST_APPEND(lookup_list, lookup, link);
02003         }
02004         if (!need_clone)
02005                 destroy_lookup(lookup);
02006 }
02007 
02008 /*
02009  * Callback from dighost.c to allow program-specific shutdown code.
02010  * Here, we're possibly reading from a batch file, then shutting down
02011  * for real if there's nothing in the batch file to read.
02012  */
02013 void
02014 dighost_shutdown(void) {
02015         char batchline[MXNAME];
02016         int bargc;
02017         char *bargv[16];
02018         char *input;
02019         int i;
02020 
02021         if (batchname == NULL) {
02022                 isc_app_shutdown();
02023                 return;
02024         }
02025 
02026         fflush(stdout);
02027         if (feof(batchfp)) {
02028                 batchname = NULL;
02029                 isc_app_shutdown();
02030                 if (batchfp != stdin)
02031                         fclose(batchfp);
02032                 return;
02033         }
02034 
02035         if (fgets(batchline, sizeof(batchline), batchfp) != 0) {
02036                 debug("batch line %s", batchline);
02037                 bargc = 1;
02038                 input = batchline;
02039                 bargv[bargc] = next_token(&input, " \t\r\n");
02040                 while ((bargv[bargc] != NULL) && (bargc < 14)) {
02041                         bargc++;
02042                         bargv[bargc] = next_token(&input, " \t\r\n");
02043                 }
02044 
02045                 bargv[0] = argv0;
02046 
02047                 for(i = 0; i < bargc; i++)
02048                         debug("batch argv %d: %s", i, bargv[i]);
02049                 parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv);
02050                 start_lookup();
02051         } else {
02052                 batchname = NULL;
02053                 if (batchfp != stdin)
02054                         fclose(batchfp);
02055                 isc_app_shutdown();
02056                 return;
02057         }
02058 }
02059 
02060 /*% Main processing routine for dig */
02061 int
02062 main(int argc, char **argv) {
02063         isc_result_t result;
02064 
02065         ISC_LIST_INIT(lookup_list);
02066         ISC_LIST_INIT(server_list);
02067         ISC_LIST_INIT(search_list);
02068 
02069         debug("main()");
02070         preparse_args(argc, argv);
02071         progname = argv[0];
02072         result = isc_app_start();
02073         check_result(result, "isc_app_start");
02074         setup_libs();
02075         setup_system();
02076         parse_args(ISC_FALSE, ISC_FALSE, argc, argv);
02077         if (keyfile[0] != 0)
02078                 setup_file_key();
02079         else if (keysecret[0] != 0)
02080                 setup_text_key();
02081         if (domainopt[0] != '\0') {
02082                 set_search_domain(domainopt);
02083                 usesearch = ISC_TRUE;
02084         }
02085         result = isc_app_onrun(mctx, global_task, onrun_callback, NULL);
02086         check_result(result, "isc_app_onrun");
02087         isc_app_run();
02088         destroy_lookup(default_lookup);
02089         if (batchname != NULL) {
02090                 if (batchfp != stdin)
02091                         fclose(batchfp);
02092                 batchname = NULL;
02093         }
02094 #ifdef DIG_SIGCHASE
02095         clean_trustedkey();
02096 #endif
02097         cancel_all();
02098         destroy_libs();
02099         isc_app_finish();
02100         return (exitcode);
02101 }

Generated on Tue Apr 28 17:40:53 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha