nslookup.c revision 254897
1226584Sdim/* 2226584Sdim * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") 3226584Sdim * Copyright (C) 2000-2003 Internet Software Consortium. 4226584Sdim * 5226584Sdim * Permission to use, copy, modify, and/or distribute this software for any 6226584Sdim * purpose with or without fee is hereby granted, provided that the above 7226584Sdim * copyright notice and this permission notice appear in all copies. 8226584Sdim * 9226584Sdim * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10226584Sdim * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11226584Sdim * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12226584Sdim * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13226584Sdim * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14226584Sdim * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15226584Sdim * PERFORMANCE OF THIS SOFTWARE. 16263508Sdim */ 17263508Sdim 18234353Sdim/* $Id: nslookup.c,v 1.130 2011/12/16 23:01:16 each Exp $ */ 19226584Sdim 20226584Sdim#include <config.h> 21226584Sdim 22226584Sdim#include <stdlib.h> 23226584Sdim#include <unistd.h> 24263508Sdim 25234353Sdim#include <isc/app.h> 26263508Sdim#include <isc/buffer.h> 27234353Sdim#include <isc/commandline.h> 28263508Sdim#include <isc/event.h> 29263508Sdim#include <isc/parseint.h> 30263508Sdim#include <isc/print.h> 31263508Sdim#include <isc/string.h> 32263508Sdim#include <isc/timer.h> 33263508Sdim#include <isc/util.h> 34263508Sdim#include <isc/task.h> 35263508Sdim#include <isc/netaddr.h> 36263508Sdim 37263508Sdim#include <dns/message.h> 38263508Sdim#include <dns/name.h> 39263508Sdim#include <dns/fixedname.h> 40263508Sdim#include <dns/rdata.h> 41263508Sdim#include <dns/rdataclass.h> 42263508Sdim#include <dns/rdataset.h> 43263508Sdim#include <dns/rdatastruct.h> 44263508Sdim#include <dns/rdatatype.h> 45263508Sdim#include <dns/byaddr.h> 46263508Sdim 47263508Sdim#include <dig/dig.h> 48263508Sdim 49263508Sdim#if defined(HAVE_READLINE) 50263508Sdim#include <readline/readline.h> 51263508Sdim#include <readline/history.h> 52263508Sdim#endif 53263508Sdim 54263508Sdimstatic isc_boolean_t short_form = ISC_TRUE, 55263508Sdim tcpmode = ISC_FALSE, 56263508Sdim identify = ISC_FALSE, stats = ISC_TRUE, 57263508Sdim comments = ISC_TRUE, section_question = ISC_TRUE, 58263508Sdim section_answer = ISC_TRUE, section_authority = ISC_TRUE, 59263508Sdim section_additional = ISC_TRUE, recurse = ISC_TRUE, 60263508Sdim aaonly = ISC_FALSE, nofail = ISC_TRUE; 61263508Sdim 62263508Sdimstatic isc_boolean_t interactive; 63263508Sdim 64263508Sdimstatic isc_boolean_t in_use = ISC_FALSE; 65263508Sdimstatic char defclass[MXRD] = "IN"; 66263508Sdimstatic char deftype[MXRD] = "A"; 67263508Sdimstatic isc_event_t *global_event = NULL; 68263508Sdimstatic int query_error = 1, print_error = 0; 69263508Sdim 70263508Sdimstatic char domainopt[DNS_NAME_MAXTEXT]; 71263508Sdim 72263508Sdimstatic const char *rcodetext[] = { 73263508Sdim "NOERROR", 74263508Sdim "FORMERR", 75263508Sdim "SERVFAIL", 76263508Sdim "NXDOMAIN", 77263508Sdim "NOTIMP", 78263508Sdim "REFUSED", 79263508Sdim "YXDOMAIN", 80263508Sdim "YXRRSET", 81263508Sdim "NXRRSET", 82263508Sdim "NOTAUTH", 83263508Sdim "NOTZONE", 84263508Sdim "RESERVED11", 85263508Sdim "RESERVED12", 86263508Sdim "RESERVED13", 87263508Sdim "RESERVED14", 88263508Sdim "RESERVED15", 89263508Sdim "BADVERS" 90263508Sdim}; 91263508Sdim 92263508Sdimstatic const char *rtypetext[] = { 93263508Sdim "rtype_0 = ", /* 0 */ 94263508Sdim "internet address = ", /* 1 */ 95263508Sdim "nameserver = ", /* 2 */ 96263508Sdim "md = ", /* 3 */ 97263508Sdim "mf = ", /* 4 */ 98263508Sdim "canonical name = ", /* 5 */ 99263508Sdim "soa = ", /* 6 */ 100234353Sdim "mb = ", /* 7 */ 101226584Sdim "mg = ", /* 8 */ 102226584Sdim "mr = ", /* 9 */ 103263508Sdim "rtype_10 = ", /* 10 */ 104263508Sdim "protocol = ", /* 11 */ 105263508Sdim "name = ", /* 12 */ 106263508Sdim "hinfo = ", /* 13 */ 107263508Sdim "minfo = ", /* 14 */ 108234353Sdim "mail exchanger = ", /* 15 */ 109263508Sdim "text = ", /* 16 */ 110263508Sdim "rp = ", /* 17 */ 111263508Sdim "afsdb = ", /* 18 */ 112263508Sdim "x25 address = ", /* 19 */ 113263508Sdim "isdn address = ", /* 20 */ 114263508Sdim "rt = ", /* 21 */ 115263508Sdim "nsap = ", /* 22 */ 116263508Sdim "nsap_ptr = ", /* 23 */ 117263508Sdim "signature = ", /* 24 */ 118226584Sdim "key = ", /* 25 */ 119263508Sdim "px = ", /* 26 */ 120226584Sdim "gpos = ", /* 27 */ 121226584Sdim "has AAAA address ", /* 28 */ 122226584Sdim "loc = ", /* 29 */ 123226584Sdim "next = ", /* 30 */ 124226584Sdim "rtype_31 = ", /* 31 */ 125226584Sdim "rtype_32 = ", /* 32 */ 126226584Sdim "service = ", /* 33 */ 127226584Sdim "rtype_34 = ", /* 34 */ 128226584Sdim "naptr = ", /* 35 */ 129226584Sdim "kx = ", /* 36 */ 130226584Sdim "cert = ", /* 37 */ 131226584Sdim "v6 address = ", /* 38 */ 132249423Sdim "dname = ", /* 39 */ 133249423Sdim "rtype_40 = ", /* 40 */ 134249423Sdim "optional = " /* 41 */ 135226584Sdim}; 136226584Sdim 137249423Sdim#define N_KNOWN_RRTYPES (sizeof(rtypetext) / sizeof(rtypetext[0])) 138226584Sdim 139226584Sdimstatic void flush_lookup_list(void); 140226584Sdimstatic void getinput(isc_task_t *task, isc_event_t *event); 141226584Sdim 142226584Sdimstatic char * 143226584Sdimrcode_totext(dns_rcode_t rcode) 144226584Sdim{ 145226584Sdim static char buf[sizeof("?65535")]; 146249423Sdim union { 147249423Sdim const char *consttext; 148249423Sdim char *deconsttext; 149249423Sdim } totext; 150249423Sdim 151249423Sdim if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) { 152249423Sdim snprintf(buf, sizeof(buf), "?%u", rcode); 153249423Sdim totext.deconsttext = buf; 154226584Sdim } else 155234353Sdim totext.consttext = rcodetext[rcode]; 156249423Sdim return totext.deconsttext; 157249423Sdim} 158249423Sdim 159263508Sdimvoid 160263508Sdimdighost_shutdown(void) { 161234353Sdim isc_event_t *event = global_event; 162226584Sdim 163226584Sdim flush_lookup_list(); 164226584Sdim debug("dighost_shutdown()"); 165226584Sdim 166226584Sdim if (!in_use) { 167226584Sdim isc_app_shutdown(); 168226584Sdim return; 169226584Sdim } 170226584Sdim 171263508Sdim isc_task_send(global_task, &event); 172263508Sdim} 173263508Sdim 174263508Sdimstatic void 175263508Sdimprintsoa(dns_rdata_t *rdata) { 176263508Sdim dns_rdata_soa_t soa; 177263508Sdim isc_result_t result; 178263508Sdim char namebuf[DNS_NAME_FORMATSIZE]; 179263508Sdim 180263508Sdim result = dns_rdata_tostruct(rdata, &soa, NULL); 181263508Sdim check_result(result, "dns_rdata_tostruct"); 182263508Sdim 183263508Sdim dns_name_format(&soa.origin, namebuf, sizeof(namebuf)); 184263508Sdim printf("\torigin = %s\n", namebuf); 185226584Sdim dns_name_format(&soa.contact, namebuf, sizeof(namebuf)); 186226584Sdim printf("\tmail addr = %s\n", namebuf); 187249423Sdim printf("\tserial = %u\n", soa.serial); 188249423Sdim printf("\trefresh = %u\n", soa.refresh); 189226584Sdim printf("\tretry = %u\n", soa.retry); 190249423Sdim printf("\texpire = %u\n", soa.expire); 191249423Sdim printf("\tminimum = %u\n", soa.minimum); 192226584Sdim dns_rdata_freestruct(&soa); 193226584Sdim} 194226584Sdim 195226584Sdimstatic void 196226584Sdimprinta(dns_rdata_t *rdata) { 197263508Sdim isc_result_t result; 198226584Sdim char text[sizeof("255.255.255.255")]; 199263508Sdim isc_buffer_t b; 200263508Sdim 201263508Sdim isc_buffer_init(&b, text, sizeof(text)); 202226584Sdim result = dns_rdata_totext(rdata, NULL, &b); 203226584Sdim check_result(result, "dns_rdata_totext"); 204226584Sdim printf("Address: %.*s\n", (int)isc_buffer_usedlength(&b), 205226584Sdim (char *)isc_buffer_base(&b)); 206234353Sdim} 207234353Sdim#ifdef DIG_SIGCHASE 208226584Sdim/* Just for compatibility : not use in host program */ 209226584Sdimisc_result_t 210263508Sdimprintrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset, 211263508Sdim isc_buffer_t *target) 212249423Sdim{ 213263508Sdim UNUSED(owner_name); 214249423Sdim UNUSED(rdataset); 215263508Sdim UNUSED(target); 216263508Sdim return(ISC_FALSE); 217249423Sdim} 218249423Sdim#endif 219263508Sdimstatic void 220249423Sdimprintrdata(dns_rdata_t *rdata) { 221249423Sdim isc_result_t result; 222249423Sdim isc_buffer_t *b = NULL; 223263508Sdim unsigned int size = 1024; 224263508Sdim isc_boolean_t done = ISC_FALSE; 225263508Sdim 226249423Sdim if (rdata->type < N_KNOWN_RRTYPES) 227249423Sdim printf("%s", rtypetext[rdata->type]); 228249423Sdim else 229249423Sdim printf("rdata_%d = ", rdata->type); 230263508Sdim 231263508Sdim while (!done) { 232263508Sdim result = isc_buffer_allocate(mctx, &b, size); 233263508Sdim if (result != ISC_R_SUCCESS) 234263508Sdim check_result(result, "isc_buffer_allocate"); 235263508Sdim result = dns_rdata_totext(rdata, NULL, b); 236263508Sdim if (result == ISC_R_SUCCESS) { 237263508Sdim printf("%.*s\n", (int)isc_buffer_usedlength(b), 238234353Sdim (char *)isc_buffer_base(b)); 239263508Sdim done = ISC_TRUE; 240263508Sdim } else if (result != ISC_R_NOSPACE) 241263508Sdim check_result(result, "dns_rdata_totext"); 242263508Sdim isc_buffer_free(&b); 243263508Sdim size *= 2; 244263508Sdim } 245263508Sdim} 246263508Sdim 247263508Sdimstatic isc_result_t 248263508Sdimprintsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, 249263508Sdim dns_section_t section) { 250263508Sdim isc_result_t result, loopresult; 251263508Sdim dns_name_t *name; 252263508Sdim dns_rdataset_t *rdataset = NULL; 253263508Sdim dns_rdata_t rdata = DNS_RDATA_INIT; 254263508Sdim char namebuf[DNS_NAME_FORMATSIZE]; 255263508Sdim 256263508Sdim UNUSED(query); 257263508Sdim UNUSED(headers); 258263508Sdim 259263508Sdim debug("printsection()"); 260263508Sdim 261263508Sdim result = dns_message_firstname(msg, section); 262263508Sdim if (result == ISC_R_NOMORE) 263249423Sdim return (ISC_R_SUCCESS); 264249423Sdim else if (result != ISC_R_SUCCESS) 265249423Sdim return (result); 266249423Sdim for (;;) { 267263508Sdim name = NULL; 268263508Sdim dns_message_currentname(msg, section, 269263508Sdim &name); 270263508Sdim for (rdataset = ISC_LIST_HEAD(name->list); 271263508Sdim rdataset != NULL; 272263508Sdim rdataset = ISC_LIST_NEXT(rdataset, link)) { 273263508Sdim loopresult = dns_rdataset_first(rdataset); 274263508Sdim while (loopresult == ISC_R_SUCCESS) { 275263508Sdim dns_rdataset_current(rdataset, &rdata); 276263508Sdim switch (rdata.type) { 277263508Sdim case dns_rdatatype_a: 278263508Sdim if (section != DNS_SECTION_ANSWER) 279263508Sdim goto def_short_section; 280263508Sdim dns_name_format(name, namebuf, 281263508Sdim sizeof(namebuf)); 282263508Sdim printf("Name:\t%s\n", namebuf); 283263508Sdim printa(&rdata); 284263508Sdim break; 285263508Sdim case dns_rdatatype_soa: 286263508Sdim dns_name_format(name, namebuf, 287263508Sdim sizeof(namebuf)); 288263508Sdim printf("%s\n", namebuf); 289263508Sdim printsoa(&rdata); 290263508Sdim break; 291263508Sdim default: 292263508Sdim def_short_section: 293263508Sdim dns_name_format(name, namebuf, 294263508Sdim sizeof(namebuf)); 295263508Sdim printf("%s\t", namebuf); 296263508Sdim printrdata(&rdata); 297263508Sdim break; 298263508Sdim } 299263508Sdim dns_rdata_reset(&rdata); 300263508Sdim loopresult = dns_rdataset_next(rdataset); 301263508Sdim } 302263508Sdim } 303263508Sdim result = dns_message_nextname(msg, section); 304263508Sdim if (result == ISC_R_NOMORE) 305263508Sdim break; 306263508Sdim else if (result != ISC_R_SUCCESS) { 307263508Sdim return (result); 308263508Sdim } 309226584Sdim } 310226584Sdim return (ISC_R_SUCCESS); 311226584Sdim} 312263508Sdim 313263508Sdimstatic isc_result_t 314263508Sdimdetailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, 315263508Sdim dns_section_t section) { 316263508Sdim isc_result_t result, loopresult; 317263508Sdim dns_name_t *name; 318263508Sdim dns_rdataset_t *rdataset = NULL; 319234353Sdim dns_rdata_t rdata = DNS_RDATA_INIT; 320263508Sdim char namebuf[DNS_NAME_FORMATSIZE]; 321234353Sdim 322226584Sdim UNUSED(query); 323226584Sdim 324226584Sdim debug("detailsection()"); 325263508Sdim 326226584Sdim if (headers) { 327226584Sdim switch (section) { 328234353Sdim case DNS_SECTION_QUESTION: 329249423Sdim puts(" QUESTIONS:"); 330234353Sdim break; 331234353Sdim case DNS_SECTION_ANSWER: 332226584Sdim puts(" ANSWERS:"); 333234353Sdim break; 334249423Sdim case DNS_SECTION_AUTHORITY: 335249423Sdim puts(" AUTHORITY RECORDS:"); 336249423Sdim break; 337249423Sdim case DNS_SECTION_ADDITIONAL: 338249423Sdim puts(" ADDITIONAL RECORDS:"); 339249423Sdim break; 340249423Sdim } 341249423Sdim } 342249423Sdim 343249423Sdim result = dns_message_firstname(msg, section); 344249423Sdim if (result == ISC_R_NOMORE) 345249423Sdim return (ISC_R_SUCCESS); 346249423Sdim else if (result != ISC_R_SUCCESS) 347249423Sdim return (result); 348234353Sdim for (;;) { 349249423Sdim name = NULL; 350234353Sdim dns_message_currentname(msg, section, 351249423Sdim &name); 352249423Sdim for (rdataset = ISC_LIST_HEAD(name->list); 353234353Sdim rdataset != NULL; 354249423Sdim rdataset = ISC_LIST_NEXT(rdataset, link)) { 355249423Sdim if (section == DNS_SECTION_QUESTION) { 356249423Sdim dns_name_format(name, namebuf, 357249423Sdim sizeof(namebuf)); 358249423Sdim printf("\t%s, ", namebuf); 359249423Sdim dns_rdatatype_format(rdataset->type, 360249423Sdim namebuf, 361249423Sdim sizeof(namebuf)); 362249423Sdim printf("type = %s, ", namebuf); 363249423Sdim dns_rdataclass_format(rdataset->rdclass, 364249423Sdim namebuf, 365249423Sdim sizeof(namebuf)); 366249423Sdim printf("class = %s\n", namebuf); 367249423Sdim } 368249423Sdim loopresult = dns_rdataset_first(rdataset); 369249423Sdim while (loopresult == ISC_R_SUCCESS) { 370249423Sdim dns_rdataset_current(rdataset, &rdata); 371249423Sdim 372249423Sdim dns_name_format(name, namebuf, 373263508Sdim sizeof(namebuf)); 374234353Sdim printf(" -> %s\n", namebuf); 375234353Sdim 376234353Sdim switch (rdata.type) { 377234353Sdim case dns_rdatatype_soa: 378234353Sdim printsoa(&rdata); 379234353Sdim break; 380234353Sdim default: 381234353Sdim printf("\t"); 382249423Sdim printrdata(&rdata); 383234353Sdim } 384234353Sdim dns_rdata_reset(&rdata); 385234353Sdim printf("\tttl = %u\n", rdataset->ttl); 386234353Sdim loopresult = dns_rdataset_next(rdataset); 387234353Sdim } 388263508Sdim } 389263508Sdim result = dns_message_nextname(msg, section); 390263508Sdim if (result == ISC_R_NOMORE) 391249423Sdim break; 392249423Sdim else if (result != ISC_R_SUCCESS) { 393249423Sdim return (result); 394249423Sdim } 395249423Sdim } 396249423Sdim return (ISC_R_SUCCESS); 397249423Sdim} 398249423Sdim 399249423Sdimvoid 400249423Sdimreceived(int bytes, isc_sockaddr_t *from, dig_query_t *query) 401249423Sdim{ 402249423Sdim UNUSED(bytes); 403249423Sdim UNUSED(from); 404249423Sdim UNUSED(query); 405249423Sdim} 406249423Sdim 407234353Sdimvoid 408234353Sdimtrying(char *frm, dig_lookup_t *lookup) { 409234353Sdim UNUSED(frm); 410234353Sdim UNUSED(lookup); 411263508Sdim 412263508Sdim} 413263508Sdim 414249423Sdimisc_result_t 415249423Sdimprintmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { 416249423Sdim char servtext[ISC_SOCKADDR_FORMATSIZE]; 417249423Sdim 418249423Sdim /* I've we've gotten this far, we've reached a server. */ 419249423Sdim query_error = 0; 420249423Sdim 421249423Sdim debug("printmessage()"); 422249423Sdim 423249423Sdim isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext)); 424249423Sdim printf("Server:\t\t%s\n", query->userarg); 425249423Sdim printf("Address:\t%s\n", servtext); 426234353Sdim 427234353Sdim puts(""); 428234353Sdim 429249423Sdim if (!short_form) { 430249423Sdim isc_boolean_t headers = ISC_TRUE; 431249423Sdim puts("------------"); 432249423Sdim /* detailheader(query, msg);*/ 433249423Sdim detailsection(query, msg, headers, DNS_SECTION_QUESTION); 434249423Sdim detailsection(query, msg, headers, DNS_SECTION_ANSWER); 435249423Sdim detailsection(query, msg, headers, DNS_SECTION_AUTHORITY); 436249423Sdim detailsection(query, msg, headers, DNS_SECTION_ADDITIONAL); 437249423Sdim puts("------------"); 438249423Sdim } 439249423Sdim 440249423Sdim if (msg->rcode != 0) { 441249423Sdim char nametext[DNS_NAME_FORMATSIZE]; 442249423Sdim dns_name_format(query->lookup->name, 443249423Sdim nametext, sizeof(nametext)); 444249423Sdim printf("** server can't find %s: %s\n", 445249423Sdim (msg->rcode != dns_rcode_nxdomain) ? nametext : 446249423Sdim query->lookup->textname, rcode_totext(msg->rcode)); 447263508Sdim debug("returning with rcode == 0"); 448263508Sdim 449263508Sdim /* the lookup failed */ 450263508Sdim print_error |= 1; 451 return (ISC_R_SUCCESS); 452 } 453 454 if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) 455 puts("Non-authoritative answer:"); 456 if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) 457 printsection(query, msg, headers, DNS_SECTION_ANSWER); 458 else 459 printf("*** Can't find %s: No answer\n", 460 query->lookup->textname); 461 462 if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) && 463 (query->lookup->rdtype != dns_rdatatype_a)) { 464 puts("\nAuthoritative answers can be found from:"); 465 printsection(query, msg, headers, 466 DNS_SECTION_AUTHORITY); 467 printsection(query, msg, headers, 468 DNS_SECTION_ADDITIONAL); 469 } 470 return (ISC_R_SUCCESS); 471} 472 473static void 474show_settings(isc_boolean_t full, isc_boolean_t serv_only) { 475 dig_server_t *srv; 476 isc_sockaddr_t sockaddr; 477 dig_searchlist_t *listent; 478 isc_result_t result; 479 480 srv = ISC_LIST_HEAD(server_list); 481 482 while (srv != NULL) { 483 char sockstr[ISC_SOCKADDR_FORMATSIZE]; 484 485 result = get_address(srv->servername, port, &sockaddr); 486 check_result(result, "get_address"); 487 488 isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr)); 489 printf("Default server: %s\nAddress: %s\n", 490 srv->userarg, sockstr); 491 if (!full) 492 return; 493 srv = ISC_LIST_NEXT(srv, link); 494 } 495 if (serv_only) 496 return; 497 printf("\nSet options:\n"); 498 printf(" %s\t\t\t%s\t\t%s\n", 499 tcpmode ? "vc" : "novc", 500 short_form ? "nodebug" : "debug", 501 debugging ? "d2" : "nod2"); 502 printf(" %s\t\t%s\n", 503 usesearch ? "search" : "nosearch", 504 recurse ? "recurse" : "norecurse"); 505 printf(" timeout = %d\t\tretry = %d\tport = %d\n", 506 timeout, tries, port); 507 printf(" querytype = %-8s\tclass = %s\n", deftype, defclass); 508 printf(" srchlist = "); 509 for (listent = ISC_LIST_HEAD(search_list); 510 listent != NULL; 511 listent = ISC_LIST_NEXT(listent, link)) { 512 printf("%s", listent->origin); 513 if (ISC_LIST_NEXT(listent, link) != NULL) 514 printf("/"); 515 } 516 printf("\n"); 517} 518 519static isc_boolean_t 520testtype(char *typetext) { 521 isc_result_t result; 522 isc_textregion_t tr; 523 dns_rdatatype_t rdtype; 524 525 tr.base = typetext; 526 tr.length = strlen(typetext); 527 result = dns_rdatatype_fromtext(&rdtype, &tr); 528 if (result == ISC_R_SUCCESS) 529 return (ISC_TRUE); 530 else { 531 printf("unknown query type: %s\n", typetext); 532 return (ISC_FALSE); 533 } 534} 535 536static isc_boolean_t 537testclass(char *typetext) { 538 isc_result_t result; 539 isc_textregion_t tr; 540 dns_rdataclass_t rdclass; 541 542 tr.base = typetext; 543 tr.length = strlen(typetext); 544 result = dns_rdataclass_fromtext(&rdclass, &tr); 545 if (result == ISC_R_SUCCESS) 546 return (ISC_TRUE); 547 else { 548 printf("unknown query class: %s\n", typetext); 549 return (ISC_FALSE); 550 } 551} 552 553static void 554set_port(const char *value) { 555 isc_uint32_t n; 556 isc_result_t result = parse_uint(&n, value, 65535, "port"); 557 if (result == ISC_R_SUCCESS) 558 port = (isc_uint16_t) n; 559} 560 561static void 562set_timeout(const char *value) { 563 isc_uint32_t n; 564 isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout"); 565 if (result == ISC_R_SUCCESS) 566 timeout = n; 567} 568 569static void 570set_tries(const char *value) { 571 isc_uint32_t n; 572 isc_result_t result = parse_uint(&n, value, INT_MAX, "tries"); 573 if (result == ISC_R_SUCCESS) 574 tries = n; 575} 576 577static void 578setoption(char *opt) { 579 if (strncasecmp(opt, "all", 4) == 0) { 580 show_settings(ISC_TRUE, ISC_FALSE); 581 } else if (strncasecmp(opt, "class=", 6) == 0) { 582 if (testclass(&opt[6])) 583 strlcpy(defclass, &opt[6], sizeof(defclass)); 584 } else if (strncasecmp(opt, "cl=", 3) == 0) { 585 if (testclass(&opt[3])) 586 strlcpy(defclass, &opt[3], sizeof(defclass)); 587 } else if (strncasecmp(opt, "type=", 5) == 0) { 588 if (testtype(&opt[5])) 589 strlcpy(deftype, &opt[5], sizeof(deftype)); 590 } else if (strncasecmp(opt, "ty=", 3) == 0) { 591 if (testtype(&opt[3])) 592 strlcpy(deftype, &opt[3], sizeof(deftype)); 593 } else if (strncasecmp(opt, "querytype=", 10) == 0) { 594 if (testtype(&opt[10])) 595 strlcpy(deftype, &opt[10], sizeof(deftype)); 596 } else if (strncasecmp(opt, "query=", 6) == 0) { 597 if (testtype(&opt[6])) 598 strlcpy(deftype, &opt[6], sizeof(deftype)); 599 } else if (strncasecmp(opt, "qu=", 3) == 0) { 600 if (testtype(&opt[3])) 601 strlcpy(deftype, &opt[3], sizeof(deftype)); 602 } else if (strncasecmp(opt, "q=", 2) == 0) { 603 if (testtype(&opt[2])) 604 strlcpy(deftype, &opt[2], sizeof(deftype)); 605 } else if (strncasecmp(opt, "domain=", 7) == 0) { 606 strlcpy(domainopt, &opt[7], sizeof(domainopt)); 607 set_search_domain(domainopt); 608 usesearch = ISC_TRUE; 609 } else if (strncasecmp(opt, "do=", 3) == 0) { 610 strlcpy(domainopt, &opt[3], sizeof(domainopt)); 611 set_search_domain(domainopt); 612 usesearch = ISC_TRUE; 613 } else if (strncasecmp(opt, "port=", 5) == 0) { 614 set_port(&opt[5]); 615 } else if (strncasecmp(opt, "po=", 3) == 0) { 616 set_port(&opt[3]); 617 } else if (strncasecmp(opt, "timeout=", 8) == 0) { 618 set_timeout(&opt[8]); 619 } else if (strncasecmp(opt, "t=", 2) == 0) { 620 set_timeout(&opt[2]); 621 } else if (strncasecmp(opt, "rec", 3) == 0) { 622 recurse = ISC_TRUE; 623 } else if (strncasecmp(opt, "norec", 5) == 0) { 624 recurse = ISC_FALSE; 625 } else if (strncasecmp(opt, "retry=", 6) == 0) { 626 set_tries(&opt[6]); 627 } else if (strncasecmp(opt, "ret=", 4) == 0) { 628 set_tries(&opt[4]); 629 } else if (strncasecmp(opt, "def", 3) == 0) { 630 usesearch = ISC_TRUE; 631 } else if (strncasecmp(opt, "nodef", 5) == 0) { 632 usesearch = ISC_FALSE; 633 } else if (strncasecmp(opt, "vc", 3) == 0) { 634 tcpmode = ISC_TRUE; 635 } else if (strncasecmp(opt, "novc", 5) == 0) { 636 tcpmode = ISC_FALSE; 637 } else if (strncasecmp(opt, "deb", 3) == 0) { 638 short_form = ISC_FALSE; 639 showsearch = ISC_TRUE; 640 } else if (strncasecmp(opt, "nodeb", 5) == 0) { 641 short_form = ISC_TRUE; 642 showsearch = ISC_FALSE; 643 } else if (strncasecmp(opt, "d2", 2) == 0) { 644 debugging = ISC_TRUE; 645 } else if (strncasecmp(opt, "nod2", 4) == 0) { 646 debugging = ISC_FALSE; 647 } else if (strncasecmp(opt, "search", 3) == 0) { 648 usesearch = ISC_TRUE; 649 } else if (strncasecmp(opt, "nosearch", 5) == 0) { 650 usesearch = ISC_FALSE; 651 } else if (strncasecmp(opt, "sil", 3) == 0) { 652 /* deprecation_msg = ISC_FALSE; */ 653 } else if (strncasecmp(opt, "fail", 3) == 0) { 654 nofail=ISC_FALSE; 655 } else if (strncasecmp(opt, "nofail", 3) == 0) { 656 nofail=ISC_TRUE; 657 } else { 658 printf("*** Invalid option: %s\n", opt); 659 } 660} 661 662static void 663addlookup(char *opt) { 664 dig_lookup_t *lookup; 665 isc_result_t result; 666 isc_textregion_t tr; 667 dns_rdatatype_t rdtype; 668 dns_rdataclass_t rdclass; 669 char store[MXNAME]; 670 671 debug("addlookup()"); 672 tr.base = deftype; 673 tr.length = strlen(deftype); 674 result = dns_rdatatype_fromtext(&rdtype, &tr); 675 if (result != ISC_R_SUCCESS) { 676 printf("unknown query type: %s\n", deftype); 677 rdclass = dns_rdatatype_a; 678 } 679 tr.base = defclass; 680 tr.length = strlen(defclass); 681 result = dns_rdataclass_fromtext(&rdclass, &tr); 682 if (result != ISC_R_SUCCESS) { 683 printf("unknown query class: %s\n", defclass); 684 rdclass = dns_rdataclass_in; 685 } 686 lookup = make_empty_lookup(); 687 if (get_reverse(store, sizeof(store), opt, lookup->ip6_int, ISC_TRUE) 688 == ISC_R_SUCCESS) { 689 strlcpy(lookup->textname, store, sizeof(lookup->textname)); 690 lookup->rdtype = dns_rdatatype_ptr; 691 lookup->rdtypeset = ISC_TRUE; 692 } else { 693 strlcpy(lookup->textname, opt, sizeof(lookup->textname)); 694 lookup->rdtype = rdtype; 695 lookup->rdtypeset = ISC_TRUE; 696 } 697 lookup->rdclass = rdclass; 698 lookup->rdclassset = ISC_TRUE; 699 lookup->trace = ISC_FALSE; 700 lookup->trace_root = lookup->trace; 701 lookup->ns_search_only = ISC_FALSE; 702 lookup->identify = identify; 703 lookup->recurse = recurse; 704 lookup->aaonly = aaonly; 705 lookup->retries = tries; 706 lookup->udpsize = 0; 707 lookup->comments = comments; 708 lookup->tcp_mode = tcpmode; 709 lookup->stats = stats; 710 lookup->section_question = section_question; 711 lookup->section_answer = section_answer; 712 lookup->section_authority = section_authority; 713 lookup->section_additional = section_additional; 714 lookup->new_search = ISC_TRUE; 715 if (nofail) 716 lookup->servfail_stops = ISC_FALSE; 717 ISC_LIST_INIT(lookup->q); 718 ISC_LINK_INIT(lookup, link); 719 ISC_LIST_APPEND(lookup_list, lookup, link); 720 lookup->origin = NULL; 721 ISC_LIST_INIT(lookup->my_server_list); 722 debug("looking up %s", lookup->textname); 723} 724 725static void 726do_next_command(char *input) { 727 char *ptr, *arg; 728 729 ptr = next_token(&input, " \t\r\n"); 730 if (ptr == NULL) 731 return; 732 arg = next_token(&input, " \t\r\n"); 733 if ((strcasecmp(ptr, "set") == 0) && 734 (arg != NULL)) 735 setoption(arg); 736 else if ((strcasecmp(ptr, "server") == 0) || 737 (strcasecmp(ptr, "lserver") == 0)) { 738 isc_app_block(); 739 set_nameserver(arg); 740 check_ra = ISC_FALSE; 741 isc_app_unblock(); 742 show_settings(ISC_TRUE, ISC_TRUE); 743 } else if (strcasecmp(ptr, "exit") == 0) { 744 in_use = ISC_FALSE; 745 } else if (strcasecmp(ptr, "help") == 0 || 746 strcasecmp(ptr, "?") == 0) { 747 printf("The '%s' command is not yet implemented.\n", ptr); 748 } else if (strcasecmp(ptr, "finger") == 0 || 749 strcasecmp(ptr, "root") == 0 || 750 strcasecmp(ptr, "ls") == 0 || 751 strcasecmp(ptr, "view") == 0) { 752 printf("The '%s' command is not implemented.\n", ptr); 753 } else 754 addlookup(ptr); 755} 756 757static void 758get_next_command(void) { 759 char *buf; 760 char *ptr; 761 762 fflush(stdout); 763 buf = isc_mem_allocate(mctx, COMMSIZE); 764 if (buf == NULL) 765 fatal("memory allocation failure"); 766 isc_app_block(); 767 if (interactive) { 768#ifdef HAVE_READLINE 769 ptr = readline("> "); 770 add_history(ptr); 771#else 772 fputs("> ", stderr); 773 fflush(stderr); 774 ptr = fgets(buf, COMMSIZE, stdin); 775#endif 776 } else 777 ptr = fgets(buf, COMMSIZE, stdin); 778 isc_app_unblock(); 779 if (ptr == NULL) { 780 in_use = ISC_FALSE; 781 } else 782 do_next_command(ptr); 783#ifdef HAVE_READLINE 784 if (interactive) 785 free(ptr); 786#endif 787 isc_mem_free(mctx, buf); 788} 789 790static void 791parse_args(int argc, char **argv) { 792 isc_boolean_t have_lookup = ISC_FALSE; 793 794 usesearch = ISC_TRUE; 795 for (argc--, argv++; argc > 0; argc--, argv++) { 796 debug("main parsing %s", argv[0]); 797 if (argv[0][0] == '-') { 798 if (argv[0][1] != 0) 799 setoption(&argv[0][1]); 800 else 801 have_lookup = ISC_TRUE; 802 } else { 803 if (!have_lookup) { 804 have_lookup = ISC_TRUE; 805 in_use = ISC_TRUE; 806 addlookup(argv[0]); 807 } else { 808 set_nameserver(argv[0]); 809 check_ra = ISC_FALSE; 810 } 811 } 812 } 813} 814 815static void 816flush_lookup_list(void) { 817 dig_lookup_t *l, *lp; 818 dig_query_t *q, *qp; 819 dig_server_t *s, *sp; 820 821 lookup_counter = 0; 822 l = ISC_LIST_HEAD(lookup_list); 823 while (l != NULL) { 824 q = ISC_LIST_HEAD(l->q); 825 while (q != NULL) { 826 if (q->sock != NULL) { 827 isc_socket_cancel(q->sock, NULL, 828 ISC_SOCKCANCEL_ALL); 829 isc_socket_detach(&q->sock); 830 } 831 if (ISC_LINK_LINKED(&q->recvbuf, link)) 832 ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf, 833 link); 834 if (ISC_LINK_LINKED(&q->lengthbuf, link)) 835 ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf, 836 link); 837 isc_buffer_invalidate(&q->recvbuf); 838 isc_buffer_invalidate(&q->lengthbuf); 839 qp = q; 840 q = ISC_LIST_NEXT(q, link); 841 ISC_LIST_DEQUEUE(l->q, qp, link); 842 isc_mem_free(mctx, qp); 843 } 844 s = ISC_LIST_HEAD(l->my_server_list); 845 while (s != NULL) { 846 sp = s; 847 s = ISC_LIST_NEXT(s, link); 848 ISC_LIST_DEQUEUE(l->my_server_list, sp, link); 849 isc_mem_free(mctx, sp); 850 851 } 852 if (l->sendmsg != NULL) 853 dns_message_destroy(&l->sendmsg); 854 if (l->timer != NULL) 855 isc_timer_detach(&l->timer); 856 lp = l; 857 l = ISC_LIST_NEXT(l, link); 858 ISC_LIST_DEQUEUE(lookup_list, lp, link); 859 isc_mem_free(mctx, lp); 860 } 861} 862 863static void 864getinput(isc_task_t *task, isc_event_t *event) { 865 UNUSED(task); 866 if (global_event == NULL) 867 global_event = event; 868 while (in_use) { 869 get_next_command(); 870 if (ISC_LIST_HEAD(lookup_list) != NULL) { 871 start_lookup(); 872 return; 873 } 874 } 875 isc_app_shutdown(); 876} 877 878int 879main(int argc, char **argv) { 880 isc_result_t result; 881 882 interactive = ISC_TF(isatty(0)); 883 884 ISC_LIST_INIT(lookup_list); 885 ISC_LIST_INIT(server_list); 886 ISC_LIST_INIT(search_list); 887 888 check_ra = ISC_TRUE; 889 890 result = isc_app_start(); 891 check_result(result, "isc_app_start"); 892 893 setup_libs(); 894 progname = argv[0]; 895 896 parse_args(argc, argv); 897 898 setup_system(); 899 if (domainopt[0] != '\0') 900 set_search_domain(domainopt); 901 if (in_use) 902 result = isc_app_onrun(mctx, global_task, onrun_callback, 903 NULL); 904 else 905 result = isc_app_onrun(mctx, global_task, getinput, NULL); 906 check_result(result, "isc_app_onrun"); 907 in_use = ISC_TF(!in_use); 908 909 (void)isc_app_run(); 910 911 puts(""); 912 debug("done, and starting to shut down"); 913 if (global_event != NULL) 914 isc_event_free(&global_event); 915 cancel_all(); 916 destroy_libs(); 917 isc_app_finish(); 918 919 return (query_error | print_error); 920} 921