00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
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
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
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
00155 static void
00156 version(void) {
00157 fputs("DiG " VERSION "\n", stderr);
00158 }
00159
00160
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
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
00321
00322
00323
00324 void
00325 trying(char *frm, dig_lookup_t *lookup) {
00326 UNUSED(frm);
00327 UNUSED(lookup);
00328 }
00329
00330
00331
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
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
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
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
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
00755
00756
00757
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':
00805 FULLCHECK2("aaonly", "aaflag");
00806 lookup->aaonly = state;
00807 break;
00808 case 'd':
00809 switch (cmd[2]) {
00810 case 'd':
00811 FULLCHECK("additional");
00812 lookup->section_additional = state;
00813 break;
00814 case 'f':
00815 case '\0':
00816 FULLCHECK("adflag");
00817 lookup->adflag = state;
00818 break;
00819 default:
00820 goto invalid_option;
00821 }
00822 break;
00823 case 'l':
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':
00835 FULLCHECK("answer");
00836 lookup->section_answer = state;
00837 break;
00838 case 'u':
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':
00849 FULLCHECK("besteffort");
00850 lookup->besteffort = state;
00851 break;
00852 case 'u':
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':
00871 switch (cmd[2]) {
00872 case 'f':
00873 case '\0':
00874 FULLCHECK("cdflag");
00875 lookup->cdflag = state;
00876 break;
00877 default:
00878 goto invalid_option;
00879 }
00880 break;
00881 case 'l':
00882 FULLCHECK("cl");
00883 noclass = ISC_TF(!state);
00884 break;
00885 case 'm':
00886 FULLCHECK("cmd");
00887 printcmd = state;
00888 break;
00889 case 'o':
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':
00906 FULLCHECK("defname");
00907 if (!lookup->trace) {
00908 usesearch = state;
00909 }
00910 break;
00911 case 'n':
00912 FULLCHECK("dnssec");
00913 if (state && lookup->edns == -1)
00914 lookup->edns = 0;
00915 lookup->dnssec = state;
00916 break;
00917 case 'o':
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':
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':
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':
01037 FULLCHECK("identify");
01038 lookup->identify = state;
01039 break;
01040 case 'g':
01041 default:
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':
01051 FULLCHECK("multiline");
01052 multiline = state;
01053 break;
01054 case 'n':
01055 switch (cmd[1]) {
01056 case 'd':
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':
01070 FULLCHECK("nsid");
01071 if (state && lookup->edns == -1)
01072 lookup->edns = 0;
01073 lookup->nsid = state;
01074 break;
01075 case 's':
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':
01108 FULLCHECK("qr");
01109 qr = state;
01110 break;
01111 case 'u':
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':
01126 FULLCHECK("recurse");
01127 lookup->recurse = state;
01128 break;
01129 case 't':
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':
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':
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':
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':
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':
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':
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':
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
01242
01243
01244
01245
01246
01247 if (splitwidth)
01248 splitwidth += 3;
01249 if (result != ISC_R_SUCCESS)
01250 fatal("Couldn't parse split");
01251 break;
01252 case 't':
01253 FULLCHECK("stats");
01254 lookup->stats = state;
01255 break;
01256 case 'u':
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':
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':
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':
01301 FULLCHECK("topdown");
01302 lookup->do_topdown = state;
01303 break;
01304 #endif
01305 case 'r':
01306 switch (cmd[2]) {
01307 case 'a':
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':
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':
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':
01360 FULLCHECK2("ttl", "ttlid");
01361 nottl = ISC_TF(!state);
01362 break;
01363 case 'u':
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':
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
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
01428
01429
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
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
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':
01471
01472 break;
01473 case 'n':
01474
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,":");
01626 if (ptr == NULL) {
01627 usage();
01628 }
01629 ptr2 = next_token(&value, ":");
01630 if (ptr2 == NULL)
01631 usage();
01632 ptr3 = next_token(&value,":");
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
01680 return (ISC_FALSE);
01681 }
01682
01683
01684
01685
01686
01687
01688
01689
01690
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
01742
01743
01744
01745
01746
01747
01748
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
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
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
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
01941 }
01942 }
01943
01944
01945
01946
01947
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
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
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
02010
02011
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
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 }