nslookup.c revision 143731
1135446Strhodes/* 2135446Strhodes * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2000-2003 Internet Software Consortium. 4135446Strhodes * 5135446Strhodes * Permission to use, copy, modify, and distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18143731Sdougb/* $Id: nslookup.c,v 1.90.2.4.2.8 2004/09/06 01:33:05 marka Exp $ */ 19135446Strhodes 20135446Strhodes#include <config.h> 21135446Strhodes 22135446Strhodes#include <stdlib.h> 23135446Strhodes 24135446Strhodes#include <isc/app.h> 25135446Strhodes#include <isc/buffer.h> 26135446Strhodes#include <isc/commandline.h> 27135446Strhodes#include <isc/event.h> 28135446Strhodes#include <isc/parseint.h> 29135446Strhodes#include <isc/string.h> 30135446Strhodes#include <isc/timer.h> 31135446Strhodes#include <isc/util.h> 32135446Strhodes#include <isc/task.h> 33135446Strhodes#include <isc/netaddr.h> 34135446Strhodes 35135446Strhodes#include <dns/message.h> 36135446Strhodes#include <dns/name.h> 37135446Strhodes#include <dns/fixedname.h> 38135446Strhodes#include <dns/rdata.h> 39135446Strhodes#include <dns/rdataclass.h> 40135446Strhodes#include <dns/rdataset.h> 41135446Strhodes#include <dns/rdatastruct.h> 42135446Strhodes#include <dns/rdatatype.h> 43135446Strhodes#include <dns/byaddr.h> 44135446Strhodes 45135446Strhodes#include <dig/dig.h> 46135446Strhodes 47135446Strhodesextern ISC_LIST(dig_lookup_t) lookup_list; 48135446Strhodesextern dig_serverlist_t server_list; 49135446Strhodesextern ISC_LIST(dig_searchlist_t) search_list; 50135446Strhodes 51135446Strhodesextern isc_boolean_t usesearch, debugging; 52135446Strhodesextern in_port_t port; 53135446Strhodesextern unsigned int timeout; 54135446Strhodesextern isc_mem_t *mctx; 55135446Strhodesextern int tries; 56135446Strhodesextern int lookup_counter; 57135446Strhodesextern isc_task_t *global_task; 58135446Strhodesextern char *progname; 59135446Strhodes 60135446Strhodesstatic isc_boolean_t short_form = ISC_TRUE, 61135446Strhodes tcpmode = ISC_FALSE, 62135446Strhodes identify = ISC_FALSE, stats = ISC_TRUE, 63135446Strhodes comments = ISC_TRUE, section_question = ISC_TRUE, 64135446Strhodes section_answer = ISC_TRUE, section_authority = ISC_TRUE, 65135446Strhodes section_additional = ISC_TRUE, recurse = ISC_TRUE, 66135446Strhodes aaonly = ISC_FALSE; 67135446Strhodesstatic isc_boolean_t in_use = ISC_FALSE; 68135446Strhodesstatic char defclass[MXRD] = "IN"; 69135446Strhodesstatic char deftype[MXRD] = "A"; 70135446Strhodesstatic isc_event_t *global_event = NULL; 71135446Strhodes 72135446Strhodesstatic char domainopt[DNS_NAME_MAXTEXT]; 73135446Strhodes 74135446Strhodesstatic const char *rcodetext[] = { 75135446Strhodes "NOERROR", 76135446Strhodes "FORMERR", 77135446Strhodes "SERVFAIL", 78135446Strhodes "NXDOMAIN", 79135446Strhodes "NOTIMP", 80135446Strhodes "REFUSED", 81135446Strhodes "YXDOMAIN", 82135446Strhodes "YXRRSET", 83135446Strhodes "NXRRSET", 84135446Strhodes "NOTAUTH", 85135446Strhodes "NOTZONE", 86135446Strhodes "RESERVED11", 87135446Strhodes "RESERVED12", 88135446Strhodes "RESERVED13", 89135446Strhodes "RESERVED14", 90135446Strhodes "RESERVED15", 91135446Strhodes "BADVERS" 92135446Strhodes}; 93135446Strhodes 94135446Strhodesstatic const char *rtypetext[] = { 95135446Strhodes "rtype_0 = ", /* 0 */ 96135446Strhodes "internet address = ", /* 1 */ 97135446Strhodes "nameserver = ", /* 2 */ 98135446Strhodes "md = ", /* 3 */ 99135446Strhodes "mf = ", /* 4 */ 100135446Strhodes "canonical name = ", /* 5 */ 101135446Strhodes "soa = ", /* 6 */ 102135446Strhodes "mb = ", /* 7 */ 103135446Strhodes "mg = ", /* 8 */ 104135446Strhodes "mr = ", /* 9 */ 105135446Strhodes "rtype_10 = ", /* 10 */ 106135446Strhodes "protocol = ", /* 11 */ 107135446Strhodes "name = ", /* 12 */ 108135446Strhodes "hinfo = ", /* 13 */ 109135446Strhodes "minfo = ", /* 14 */ 110135446Strhodes "mail exchanger = ", /* 15 */ 111135446Strhodes "text = ", /* 16 */ 112135446Strhodes "rp = ", /* 17 */ 113135446Strhodes "afsdb = ", /* 18 */ 114135446Strhodes "x25 address = ", /* 19 */ 115135446Strhodes "isdn address = ", /* 20 */ 116135446Strhodes "rt = ", /* 21 */ 117135446Strhodes "nsap = ", /* 22 */ 118135446Strhodes "nsap_ptr = ", /* 23 */ 119135446Strhodes "signature = ", /* 24 */ 120135446Strhodes "key = ", /* 25 */ 121135446Strhodes "px = ", /* 26 */ 122135446Strhodes "gpos = ", /* 27 */ 123135446Strhodes "has AAAA address ", /* 28 */ 124135446Strhodes "loc = ", /* 29 */ 125135446Strhodes "next = ", /* 30 */ 126135446Strhodes "rtype_31 = ", /* 31 */ 127135446Strhodes "rtype_32 = ", /* 32 */ 128135446Strhodes "service = ", /* 33 */ 129135446Strhodes "rtype_34 = ", /* 34 */ 130135446Strhodes "naptr = ", /* 35 */ 131135446Strhodes "kx = ", /* 36 */ 132135446Strhodes "cert = ", /* 37 */ 133135446Strhodes "v6 address = ", /* 38 */ 134135446Strhodes "dname = ", /* 39 */ 135135446Strhodes "rtype_40 = ", /* 40 */ 136135446Strhodes "optional = " /* 41 */ 137135446Strhodes}; 138135446Strhodes 139135446Strhodes#define N_KNOWN_RRTYPES (sizeof(rtypetext) / sizeof(rtypetext[0])) 140135446Strhodes 141135446Strhodesstatic void flush_lookup_list(void); 142135446Strhodesstatic void getinput(isc_task_t *task, isc_event_t *event); 143135446Strhodes 144135446Strhodesvoid 145135446Strhodesdighost_shutdown(void) { 146135446Strhodes isc_event_t *event = global_event; 147135446Strhodes 148135446Strhodes flush_lookup_list(); 149135446Strhodes debug("dighost_shutdown()"); 150135446Strhodes 151135446Strhodes if (!in_use) { 152135446Strhodes isc_app_shutdown(); 153135446Strhodes return; 154135446Strhodes } 155135446Strhodes 156135446Strhodes isc_task_send(global_task, &event); 157135446Strhodes} 158135446Strhodes 159135446Strhodesstatic void 160135446Strhodesprintsoa(dns_rdata_t *rdata) { 161135446Strhodes dns_rdata_soa_t soa; 162135446Strhodes isc_result_t result; 163135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 164135446Strhodes 165135446Strhodes result = dns_rdata_tostruct(rdata, &soa, NULL); 166135446Strhodes check_result(result, "dns_rdata_tostruct"); 167135446Strhodes 168135446Strhodes dns_name_format(&soa.origin, namebuf, sizeof(namebuf)); 169135446Strhodes printf("\torigin = %s\n", namebuf); 170135446Strhodes dns_name_format(&soa.contact, namebuf, sizeof(namebuf)); 171135446Strhodes printf("\tmail addr = %s\n", namebuf); 172135446Strhodes printf("\tserial = %u\n", soa.serial); 173135446Strhodes printf("\trefresh = %u\n", soa.refresh); 174135446Strhodes printf("\tretry = %u\n", soa.retry); 175135446Strhodes printf("\texpire = %u\n", soa.expire); 176135446Strhodes printf("\tminimum = %u\n", soa.minimum); 177135446Strhodes dns_rdata_freestruct(&soa); 178135446Strhodes} 179135446Strhodes 180135446Strhodesstatic void 181135446Strhodesprinta(dns_rdata_t *rdata) { 182135446Strhodes isc_result_t result; 183135446Strhodes char text[sizeof("255.255.255.255")]; 184135446Strhodes isc_buffer_t b; 185135446Strhodes 186135446Strhodes isc_buffer_init(&b, text, sizeof(text)); 187135446Strhodes result = dns_rdata_totext(rdata, NULL, &b); 188135446Strhodes check_result(result, "dns_rdata_totext"); 189135446Strhodes printf("Address: %.*s\n", (int)isc_buffer_usedlength(&b), 190135446Strhodes (char *)isc_buffer_base(&b)); 191135446Strhodes} 192135446Strhodes#ifdef DIG_SIGCHASE 193135446Strhodes/* Just for compatibility : not use in host program */ 194135446Strhodesisc_result_t 195135446Strhodesprintrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset, 196135446Strhodes isc_buffer_t *target) 197135446Strhodes{ 198135446Strhodes UNUSED(owner_name); 199135446Strhodes UNUSED(rdataset); 200135446Strhodes UNUSED(target); 201135446Strhodes return(ISC_FALSE); 202135446Strhodes} 203135446Strhodes#endif 204135446Strhodesstatic void 205135446Strhodesprintrdata(dns_rdata_t *rdata) { 206135446Strhodes isc_result_t result; 207135446Strhodes isc_buffer_t *b = NULL; 208135446Strhodes unsigned int size = 1024; 209135446Strhodes isc_boolean_t done = ISC_FALSE; 210135446Strhodes 211135446Strhodes if (rdata->type < N_KNOWN_RRTYPES) 212135446Strhodes printf("%s", rtypetext[rdata->type]); 213135446Strhodes else 214135446Strhodes printf("rdata_%d = ", rdata->type); 215135446Strhodes 216135446Strhodes while (!done) { 217135446Strhodes result = isc_buffer_allocate(mctx, &b, size); 218135446Strhodes if (result != ISC_R_SUCCESS) 219135446Strhodes check_result(result, "isc_buffer_allocate"); 220135446Strhodes result = dns_rdata_totext(rdata, NULL, b); 221135446Strhodes if (result == ISC_R_SUCCESS) { 222135446Strhodes printf("%.*s\n", (int)isc_buffer_usedlength(b), 223135446Strhodes (char *)isc_buffer_base(b)); 224135446Strhodes done = ISC_TRUE; 225135446Strhodes } else if (result != ISC_R_NOSPACE) 226135446Strhodes check_result(result, "dns_rdata_totext"); 227135446Strhodes isc_buffer_free(&b); 228135446Strhodes size *= 2; 229135446Strhodes } 230135446Strhodes} 231135446Strhodes 232135446Strhodesstatic isc_result_t 233135446Strhodesprintsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, 234135446Strhodes dns_section_t section) { 235135446Strhodes isc_result_t result, loopresult; 236135446Strhodes dns_name_t *name; 237135446Strhodes dns_rdataset_t *rdataset = NULL; 238135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 239135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 240135446Strhodes 241135446Strhodes UNUSED(query); 242135446Strhodes UNUSED(headers); 243135446Strhodes 244135446Strhodes debug("printsection()"); 245135446Strhodes 246135446Strhodes result = dns_message_firstname(msg, section); 247135446Strhodes if (result == ISC_R_NOMORE) 248135446Strhodes return (ISC_R_SUCCESS); 249135446Strhodes else if (result != ISC_R_SUCCESS) 250135446Strhodes return (result); 251135446Strhodes for (;;) { 252135446Strhodes name = NULL; 253135446Strhodes dns_message_currentname(msg, section, 254135446Strhodes &name); 255135446Strhodes for (rdataset = ISC_LIST_HEAD(name->list); 256135446Strhodes rdataset != NULL; 257135446Strhodes rdataset = ISC_LIST_NEXT(rdataset, link)) { 258135446Strhodes loopresult = dns_rdataset_first(rdataset); 259135446Strhodes while (loopresult == ISC_R_SUCCESS) { 260135446Strhodes dns_rdataset_current(rdataset, &rdata); 261135446Strhodes switch (rdata.type) { 262135446Strhodes case dns_rdatatype_a: 263135446Strhodes if (section != DNS_SECTION_ANSWER) 264135446Strhodes goto def_short_section; 265135446Strhodes dns_name_format(name, namebuf, 266135446Strhodes sizeof(namebuf)); 267135446Strhodes printf("Name:\t%s\n", namebuf); 268135446Strhodes printa(&rdata); 269135446Strhodes break; 270135446Strhodes case dns_rdatatype_soa: 271135446Strhodes dns_name_format(name, namebuf, 272135446Strhodes sizeof(namebuf)); 273135446Strhodes printf("%s\n", namebuf); 274135446Strhodes printsoa(&rdata); 275135446Strhodes break; 276135446Strhodes default: 277135446Strhodes def_short_section: 278135446Strhodes dns_name_format(name, namebuf, 279135446Strhodes sizeof(namebuf)); 280135446Strhodes printf("%s\t", namebuf); 281135446Strhodes printrdata(&rdata); 282135446Strhodes break; 283135446Strhodes } 284135446Strhodes dns_rdata_reset(&rdata); 285135446Strhodes loopresult = dns_rdataset_next(rdataset); 286135446Strhodes } 287135446Strhodes } 288135446Strhodes result = dns_message_nextname(msg, section); 289135446Strhodes if (result == ISC_R_NOMORE) 290135446Strhodes break; 291135446Strhodes else if (result != ISC_R_SUCCESS) { 292135446Strhodes return (result); 293135446Strhodes } 294135446Strhodes } 295135446Strhodes return (ISC_R_SUCCESS); 296135446Strhodes} 297135446Strhodes 298135446Strhodesstatic isc_result_t 299135446Strhodesdetailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, 300135446Strhodes dns_section_t section) { 301135446Strhodes isc_result_t result, loopresult; 302135446Strhodes dns_name_t *name; 303135446Strhodes dns_rdataset_t *rdataset = NULL; 304135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 305135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 306135446Strhodes 307135446Strhodes UNUSED(query); 308135446Strhodes 309135446Strhodes debug("detailsection()"); 310135446Strhodes 311135446Strhodes if (headers) { 312135446Strhodes switch (section) { 313135446Strhodes case DNS_SECTION_QUESTION: 314135446Strhodes puts(" QUESTIONS:"); 315135446Strhodes break; 316135446Strhodes case DNS_SECTION_ANSWER: 317135446Strhodes puts(" ANSWERS:"); 318135446Strhodes break; 319135446Strhodes case DNS_SECTION_AUTHORITY: 320135446Strhodes puts(" AUTHORITY RECORDS:"); 321135446Strhodes break; 322135446Strhodes case DNS_SECTION_ADDITIONAL: 323135446Strhodes puts(" ADDITIONAL RECORDS:"); 324135446Strhodes break; 325135446Strhodes } 326135446Strhodes } 327135446Strhodes 328135446Strhodes result = dns_message_firstname(msg, section); 329135446Strhodes if (result == ISC_R_NOMORE) 330135446Strhodes return (ISC_R_SUCCESS); 331135446Strhodes else if (result != ISC_R_SUCCESS) 332135446Strhodes return (result); 333135446Strhodes for (;;) { 334135446Strhodes name = NULL; 335135446Strhodes dns_message_currentname(msg, section, 336135446Strhodes &name); 337135446Strhodes for (rdataset = ISC_LIST_HEAD(name->list); 338135446Strhodes rdataset != NULL; 339135446Strhodes rdataset = ISC_LIST_NEXT(rdataset, link)) { 340135446Strhodes if (section == DNS_SECTION_QUESTION) { 341135446Strhodes dns_name_format(name, namebuf, 342135446Strhodes sizeof(namebuf)); 343135446Strhodes printf("\t%s, ", namebuf); 344135446Strhodes dns_rdatatype_format(rdataset->type, 345135446Strhodes namebuf, 346135446Strhodes sizeof(namebuf)); 347135446Strhodes printf("type = %s, ", namebuf); 348135446Strhodes dns_rdataclass_format(rdataset->rdclass, 349135446Strhodes namebuf, 350135446Strhodes sizeof(namebuf)); 351135446Strhodes printf("class = %s\n", namebuf); 352135446Strhodes } 353135446Strhodes loopresult = dns_rdataset_first(rdataset); 354135446Strhodes while (loopresult == ISC_R_SUCCESS) { 355135446Strhodes dns_rdataset_current(rdataset, &rdata); 356135446Strhodes 357135446Strhodes dns_name_format(name, namebuf, 358135446Strhodes sizeof(namebuf)); 359135446Strhodes printf(" -> %s\n", namebuf); 360135446Strhodes 361135446Strhodes switch (rdata.type) { 362135446Strhodes case dns_rdatatype_soa: 363135446Strhodes printsoa(&rdata); 364135446Strhodes break; 365135446Strhodes default: 366135446Strhodes printf("\t"); 367135446Strhodes printrdata(&rdata); 368135446Strhodes } 369135446Strhodes dns_rdata_reset(&rdata); 370135446Strhodes loopresult = dns_rdataset_next(rdataset); 371135446Strhodes } 372135446Strhodes } 373135446Strhodes result = dns_message_nextname(msg, section); 374135446Strhodes if (result == ISC_R_NOMORE) 375135446Strhodes break; 376135446Strhodes else if (result != ISC_R_SUCCESS) { 377135446Strhodes return (result); 378135446Strhodes } 379135446Strhodes } 380135446Strhodes return (ISC_R_SUCCESS); 381135446Strhodes} 382135446Strhodes 383135446Strhodesvoid 384135446Strhodesreceived(int bytes, isc_sockaddr_t *from, dig_query_t *query) 385135446Strhodes{ 386135446Strhodes UNUSED(bytes); 387135446Strhodes UNUSED(from); 388135446Strhodes UNUSED(query); 389135446Strhodes} 390135446Strhodes 391135446Strhodesvoid 392135446Strhodestrying(char *frm, dig_lookup_t *lookup) { 393135446Strhodes UNUSED(frm); 394135446Strhodes UNUSED(lookup); 395135446Strhodes 396135446Strhodes} 397135446Strhodes 398135446Strhodesisc_result_t 399135446Strhodesprintmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { 400135446Strhodes char servtext[ISC_SOCKADDR_FORMATSIZE]; 401135446Strhodes 402135446Strhodes debug("printmessage()"); 403135446Strhodes 404135446Strhodes isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext)); 405143731Sdougb printf("Server:\t\t%s\n", query->userarg); 406135446Strhodes printf("Address:\t%s\n", servtext); 407135446Strhodes 408135446Strhodes puts(""); 409135446Strhodes 410135446Strhodes if (!short_form) { 411135446Strhodes isc_boolean_t headers = ISC_TRUE; 412135446Strhodes puts("------------"); 413135446Strhodes /* detailheader(query, msg);*/ 414135446Strhodes detailsection(query, msg, headers, DNS_SECTION_QUESTION); 415135446Strhodes detailsection(query, msg, headers, DNS_SECTION_ANSWER); 416135446Strhodes detailsection(query, msg, headers, DNS_SECTION_AUTHORITY); 417135446Strhodes detailsection(query, msg, headers, DNS_SECTION_ADDITIONAL); 418135446Strhodes puts("------------"); 419135446Strhodes } 420135446Strhodes 421135446Strhodes if (msg->rcode != 0) { 422135446Strhodes char nametext[DNS_NAME_FORMATSIZE]; 423135446Strhodes dns_name_format(query->lookup->name, 424135446Strhodes nametext, sizeof(nametext)); 425135446Strhodes printf("** server can't find %s: %s\n", nametext, 426135446Strhodes rcodetext[msg->rcode]); 427135446Strhodes debug("returning with rcode == 0"); 428135446Strhodes return (ISC_R_SUCCESS); 429135446Strhodes } 430135446Strhodes 431135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) 432135446Strhodes puts("Non-authoritative answer:"); 433135446Strhodes if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) 434135446Strhodes printsection(query, msg, headers, DNS_SECTION_ANSWER); 435135446Strhodes else 436135446Strhodes printf("*** Can't find %s: No answer\n", 437135446Strhodes query->lookup->textname); 438135446Strhodes 439135446Strhodes if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) && 440135446Strhodes (query->lookup->rdtype != dns_rdatatype_a)) { 441135446Strhodes puts("\nAuthoritative answers can be found from:"); 442135446Strhodes printsection(query, msg, headers, 443135446Strhodes DNS_SECTION_AUTHORITY); 444135446Strhodes printsection(query, msg, headers, 445135446Strhodes DNS_SECTION_ADDITIONAL); 446135446Strhodes } 447135446Strhodes return (ISC_R_SUCCESS); 448135446Strhodes} 449135446Strhodes 450135446Strhodesstatic void 451135446Strhodesshow_settings(isc_boolean_t full, isc_boolean_t serv_only) { 452135446Strhodes dig_server_t *srv; 453135446Strhodes isc_sockaddr_t sockaddr; 454135446Strhodes dig_searchlist_t *listent; 455135446Strhodes 456135446Strhodes srv = ISC_LIST_HEAD(server_list); 457135446Strhodes 458135446Strhodes while (srv != NULL) { 459135446Strhodes char sockstr[ISC_SOCKADDR_FORMATSIZE]; 460135446Strhodes 461135446Strhodes get_address(srv->servername, port, &sockaddr); 462135446Strhodes isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr)); 463135446Strhodes printf("Default server: %s\nAddress: %s\n", 464143731Sdougb srv->userarg, sockstr); 465135446Strhodes if (!full) 466135446Strhodes return; 467135446Strhodes srv = ISC_LIST_NEXT(srv, link); 468135446Strhodes } 469135446Strhodes if (serv_only) 470135446Strhodes return; 471135446Strhodes printf("\nSet options:\n"); 472135446Strhodes printf(" %s\t\t\t%s\t\t%s\n", 473135446Strhodes tcpmode ? "vc" : "novc", 474135446Strhodes short_form ? "nodebug" : "debug", 475135446Strhodes debugging ? "d2" : "nod2"); 476135446Strhodes printf(" %s\t\t%s\n", 477135446Strhodes usesearch ? "search" : "nosearch", 478135446Strhodes recurse ? "recurse" : "norecurse"); 479135446Strhodes printf(" timeout = %d\t\tretry = %d\tport = %d\n", 480135446Strhodes timeout, tries, port); 481135446Strhodes printf(" querytype = %-8s\tclass = %s\n", deftype, defclass); 482135446Strhodes printf(" srchlist = "); 483135446Strhodes for (listent = ISC_LIST_HEAD(search_list); 484135446Strhodes listent != NULL; 485135446Strhodes listent = ISC_LIST_NEXT(listent, link)) { 486135446Strhodes printf("%s", listent->origin); 487135446Strhodes if (ISC_LIST_NEXT(listent, link) != NULL) 488135446Strhodes printf("/"); 489135446Strhodes } 490135446Strhodes printf("\n"); 491135446Strhodes} 492135446Strhodes 493135446Strhodesstatic isc_boolean_t 494135446Strhodestesttype(char *typetext) { 495135446Strhodes isc_result_t result; 496135446Strhodes isc_textregion_t tr; 497135446Strhodes dns_rdatatype_t rdtype; 498135446Strhodes 499135446Strhodes tr.base = typetext; 500135446Strhodes tr.length = strlen(typetext); 501135446Strhodes result = dns_rdatatype_fromtext(&rdtype, &tr); 502135446Strhodes if (result == ISC_R_SUCCESS) 503135446Strhodes return (ISC_TRUE); 504135446Strhodes else { 505135446Strhodes printf("unknown query type: %s\n", typetext); 506135446Strhodes return (ISC_FALSE); 507135446Strhodes } 508135446Strhodes} 509135446Strhodes 510135446Strhodesstatic isc_boolean_t 511135446Strhodestestclass(char *typetext) { 512135446Strhodes isc_result_t result; 513135446Strhodes isc_textregion_t tr; 514135446Strhodes dns_rdataclass_t rdclass; 515135446Strhodes 516135446Strhodes tr.base = typetext; 517135446Strhodes tr.length = strlen(typetext); 518135446Strhodes result = dns_rdataclass_fromtext(&rdclass, &tr); 519135446Strhodes if (result == ISC_R_SUCCESS) 520135446Strhodes return (ISC_TRUE); 521135446Strhodes else { 522135446Strhodes printf("unknown query class: %s\n", typetext); 523135446Strhodes return (ISC_FALSE); 524135446Strhodes } 525135446Strhodes} 526135446Strhodes 527135446Strhodesstatic void 528135446Strhodessafecpy(char *dest, char *src, int size) { 529135446Strhodes strncpy(dest, src, size); 530135446Strhodes dest[size-1] = 0; 531135446Strhodes} 532135446Strhodes 533135446Strhodesstatic isc_result_t 534135446Strhodesparse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max, 535135446Strhodes const char *desc) { 536135446Strhodes isc_uint32_t n; 537135446Strhodes isc_result_t result = isc_parse_uint32(&n, value, 10); 538135446Strhodes if (result == ISC_R_SUCCESS && n > max) 539135446Strhodes result = ISC_R_RANGE; 540135446Strhodes if (result != ISC_R_SUCCESS) { 541135446Strhodes printf("invalid %s '%s': %s\n", desc, 542135446Strhodes value, isc_result_totext(result)); 543135446Strhodes return result; 544135446Strhodes } 545135446Strhodes *uip = n; 546135446Strhodes return (ISC_R_SUCCESS); 547135446Strhodes} 548135446Strhodes 549135446Strhodesstatic void 550135446Strhodesset_port(const char *value) { 551135446Strhodes isc_uint32_t n; 552135446Strhodes isc_result_t result = parse_uint(&n, value, 65535, "port"); 553135446Strhodes if (result == ISC_R_SUCCESS) 554135446Strhodes port = (isc_uint16_t) n; 555135446Strhodes} 556135446Strhodes 557135446Strhodesstatic void 558135446Strhodesset_timeout(const char *value) { 559135446Strhodes isc_uint32_t n; 560135446Strhodes isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout"); 561135446Strhodes if (result == ISC_R_SUCCESS) 562135446Strhodes timeout = n; 563135446Strhodes} 564135446Strhodes 565135446Strhodesstatic void 566135446Strhodesset_tries(const char *value) { 567135446Strhodes isc_uint32_t n; 568135446Strhodes isc_result_t result = parse_uint(&n, value, INT_MAX, "tries"); 569135446Strhodes if (result == ISC_R_SUCCESS) 570135446Strhodes tries = n; 571135446Strhodes} 572135446Strhodes 573135446Strhodesstatic void 574135446Strhodessetoption(char *opt) { 575135446Strhodes if (strncasecmp(opt, "all", 4) == 0) { 576135446Strhodes show_settings(ISC_TRUE, ISC_FALSE); 577135446Strhodes } else if (strncasecmp(opt, "class=", 6) == 0) { 578135446Strhodes if (testclass(&opt[6])) 579135446Strhodes safecpy(defclass, &opt[6], sizeof(defclass)); 580135446Strhodes } else if (strncasecmp(opt, "cl=", 3) == 0) { 581135446Strhodes if (testclass(&opt[3])) 582135446Strhodes safecpy(defclass, &opt[3], sizeof(defclass)); 583135446Strhodes } else if (strncasecmp(opt, "type=", 5) == 0) { 584135446Strhodes if (testtype(&opt[5])) 585135446Strhodes safecpy(deftype, &opt[5], sizeof(deftype)); 586135446Strhodes } else if (strncasecmp(opt, "ty=", 3) == 0) { 587135446Strhodes if (testtype(&opt[3])) 588135446Strhodes safecpy(deftype, &opt[3], sizeof(deftype)); 589135446Strhodes } else if (strncasecmp(opt, "querytype=", 10) == 0) { 590135446Strhodes if (testtype(&opt[10])) 591135446Strhodes safecpy(deftype, &opt[10], sizeof(deftype)); 592135446Strhodes } else if (strncasecmp(opt, "query=", 6) == 0) { 593135446Strhodes if (testtype(&opt[6])) 594135446Strhodes safecpy(deftype, &opt[6], sizeof(deftype)); 595135446Strhodes } else if (strncasecmp(opt, "qu=", 3) == 0) { 596135446Strhodes if (testtype(&opt[3])) 597135446Strhodes safecpy(deftype, &opt[3], sizeof(deftype)); 598135446Strhodes } else if (strncasecmp(opt, "q=", 2) == 0) { 599135446Strhodes if (testtype(&opt[2])) 600135446Strhodes safecpy(deftype, &opt[2], sizeof(deftype)); 601135446Strhodes } else if (strncasecmp(opt, "domain=", 7) == 0) { 602135446Strhodes safecpy(domainopt, &opt[7], sizeof(domainopt)); 603135446Strhodes set_search_domain(domainopt); 604135446Strhodes usesearch = ISC_TRUE; 605135446Strhodes } else if (strncasecmp(opt, "do=", 3) == 0) { 606135446Strhodes safecpy(domainopt, &opt[3], sizeof(domainopt)); 607135446Strhodes set_search_domain(domainopt); 608135446Strhodes usesearch = ISC_TRUE; 609135446Strhodes } else if (strncasecmp(opt, "port=", 5) == 0) { 610135446Strhodes set_port(&opt[5]); 611135446Strhodes } else if (strncasecmp(opt, "po=", 3) == 0) { 612135446Strhodes set_port(&opt[3]); 613135446Strhodes } else if (strncasecmp(opt, "timeout=", 8) == 0) { 614135446Strhodes set_timeout(&opt[8]); 615135446Strhodes } else if (strncasecmp(opt, "t=", 2) == 0) { 616135446Strhodes set_timeout(&opt[2]); 617135446Strhodes } else if (strncasecmp(opt, "rec", 3) == 0) { 618135446Strhodes recurse = ISC_TRUE; 619135446Strhodes } else if (strncasecmp(opt, "norec", 5) == 0) { 620135446Strhodes recurse = ISC_FALSE; 621135446Strhodes } else if (strncasecmp(opt, "retry=", 6) == 0) { 622135446Strhodes set_tries(&opt[6]); 623135446Strhodes } else if (strncasecmp(opt, "ret=", 4) == 0) { 624135446Strhodes set_tries(&opt[4]); 625135446Strhodes } else if (strncasecmp(opt, "def", 3) == 0) { 626135446Strhodes usesearch = ISC_TRUE; 627135446Strhodes } else if (strncasecmp(opt, "nodef", 5) == 0) { 628135446Strhodes usesearch = ISC_FALSE; 629135446Strhodes } else if (strncasecmp(opt, "vc", 3) == 0) { 630135446Strhodes tcpmode = ISC_TRUE; 631135446Strhodes } else if (strncasecmp(opt, "novc", 5) == 0) { 632135446Strhodes tcpmode = ISC_FALSE; 633135446Strhodes } else if (strncasecmp(opt, "deb", 3) == 0) { 634135446Strhodes short_form = ISC_FALSE; 635135446Strhodes } else if (strncasecmp(opt, "nodeb", 5) == 0) { 636135446Strhodes short_form = ISC_TRUE; 637135446Strhodes } else if (strncasecmp(opt, "d2", 2) == 0) { 638135446Strhodes debugging = ISC_TRUE; 639135446Strhodes } else if (strncasecmp(opt, "nod2", 4) == 0) { 640135446Strhodes debugging = ISC_FALSE; 641135446Strhodes } else if (strncasecmp(opt, "search", 3) == 0) { 642135446Strhodes usesearch = ISC_TRUE; 643135446Strhodes } else if (strncasecmp(opt, "nosearch", 5) == 0) { 644135446Strhodes usesearch = ISC_FALSE; 645135446Strhodes } else if (strncasecmp(opt, "sil", 3) == 0) { 646135446Strhodes /* deprecation_msg = ISC_FALSE; */ 647135446Strhodes } else { 648135446Strhodes printf("*** Invalid option: %s\n", opt); 649135446Strhodes } 650135446Strhodes} 651135446Strhodes 652135446Strhodesstatic void 653135446Strhodesaddlookup(char *opt) { 654135446Strhodes dig_lookup_t *lookup; 655135446Strhodes isc_result_t result; 656135446Strhodes isc_textregion_t tr; 657135446Strhodes dns_rdatatype_t rdtype; 658135446Strhodes dns_rdataclass_t rdclass; 659135446Strhodes char store[MXNAME]; 660135446Strhodes 661135446Strhodes debug("addlookup()"); 662135446Strhodes tr.base = deftype; 663135446Strhodes tr.length = strlen(deftype); 664135446Strhodes result = dns_rdatatype_fromtext(&rdtype, &tr); 665135446Strhodes if (result != ISC_R_SUCCESS) { 666135446Strhodes printf("unknown query type: %s\n", deftype); 667135446Strhodes rdclass = dns_rdatatype_a; 668135446Strhodes } 669135446Strhodes tr.base = defclass; 670135446Strhodes tr.length = strlen(defclass); 671135446Strhodes result = dns_rdataclass_fromtext(&rdclass, &tr); 672135446Strhodes if (result != ISC_R_SUCCESS) { 673135446Strhodes printf("unknown query class: %s\n", defclass); 674135446Strhodes rdclass = dns_rdataclass_in; 675135446Strhodes } 676135446Strhodes lookup = make_empty_lookup(); 677135446Strhodes if (get_reverse(store, sizeof(store), opt, lookup->ip6_int, ISC_TRUE) 678135446Strhodes == ISC_R_SUCCESS) { 679135446Strhodes safecpy(lookup->textname, store, sizeof(lookup->textname)); 680135446Strhodes lookup->rdtype = dns_rdatatype_ptr; 681135446Strhodes lookup->rdtypeset = ISC_TRUE; 682135446Strhodes } else { 683135446Strhodes safecpy(lookup->textname, opt, sizeof(lookup->textname)); 684135446Strhodes lookup->rdtype = rdtype; 685135446Strhodes lookup->rdtypeset = ISC_TRUE; 686135446Strhodes } 687135446Strhodes lookup->rdclass = rdclass; 688135446Strhodes lookup->rdclassset = ISC_TRUE; 689135446Strhodes lookup->trace = ISC_FALSE; 690135446Strhodes lookup->trace_root = lookup->trace; 691135446Strhodes lookup->ns_search_only = ISC_FALSE; 692135446Strhodes lookup->identify = identify; 693135446Strhodes lookup->recurse = recurse; 694135446Strhodes lookup->aaonly = aaonly; 695135446Strhodes lookup->retries = tries; 696135446Strhodes lookup->udpsize = 0; 697135446Strhodes lookup->comments = comments; 698135446Strhodes lookup->tcp_mode = tcpmode; 699135446Strhodes lookup->stats = stats; 700135446Strhodes lookup->section_question = section_question; 701135446Strhodes lookup->section_answer = section_answer; 702135446Strhodes lookup->section_authority = section_authority; 703135446Strhodes lookup->section_additional = section_additional; 704135446Strhodes lookup->new_search = ISC_TRUE; 705135446Strhodes ISC_LIST_INIT(lookup->q); 706135446Strhodes ISC_LINK_INIT(lookup, link); 707135446Strhodes ISC_LIST_APPEND(lookup_list, lookup, link); 708135446Strhodes lookup->origin = NULL; 709135446Strhodes ISC_LIST_INIT(lookup->my_server_list); 710135446Strhodes debug("looking up %s", lookup->textname); 711135446Strhodes} 712135446Strhodes 713135446Strhodesstatic void 714135446Strhodesget_next_command(void) { 715135446Strhodes char *buf; 716135446Strhodes char *ptr, *arg; 717135446Strhodes char *input; 718135446Strhodes 719135446Strhodes fflush(stdout); 720135446Strhodes buf = isc_mem_allocate(mctx, COMMSIZE); 721135446Strhodes if (buf == NULL) 722135446Strhodes fatal("memory allocation failure"); 723135446Strhodes fputs("> ", stderr); 724135446Strhodes isc_app_block(); 725135446Strhodes ptr = fgets(buf, COMMSIZE, stdin); 726135446Strhodes isc_app_unblock(); 727135446Strhodes if (ptr == NULL) { 728135446Strhodes in_use = ISC_FALSE; 729135446Strhodes goto cleanup; 730135446Strhodes } 731135446Strhodes input = buf; 732135446Strhodes ptr = next_token(&input, " \t\r\n"); 733135446Strhodes if (ptr == NULL) 734135446Strhodes goto cleanup; 735135446Strhodes arg = next_token(&input, " \t\r\n"); 736135446Strhodes if ((strcasecmp(ptr, "set") == 0) && 737135446Strhodes (arg != NULL)) 738135446Strhodes setoption(arg); 739135446Strhodes else if ((strcasecmp(ptr, "server") == 0) || 740135446Strhodes (strcasecmp(ptr, "lserver") == 0)) { 741143731Sdougb isc_app_block(); 742135446Strhodes set_nameserver(arg); 743143731Sdougb isc_app_unblock(); 744135446Strhodes show_settings(ISC_TRUE, ISC_TRUE); 745135446Strhodes } else if (strcasecmp(ptr, "exit") == 0) { 746135446Strhodes in_use = ISC_FALSE; 747135446Strhodes goto cleanup; 748135446Strhodes } else if (strcasecmp(ptr, "help") == 0 || 749135446Strhodes strcasecmp(ptr, "?") == 0) { 750135446Strhodes printf("The '%s' command is not yet implemented.\n", ptr); 751135446Strhodes goto cleanup; 752135446Strhodes } else if (strcasecmp(ptr, "finger") == 0 || 753135446Strhodes strcasecmp(ptr, "root") == 0 || 754135446Strhodes strcasecmp(ptr, "ls") == 0 || 755135446Strhodes strcasecmp(ptr, "view") == 0) { 756135446Strhodes printf("The '%s' command is not implemented.\n", ptr); 757135446Strhodes goto cleanup; 758135446Strhodes } else 759135446Strhodes addlookup(ptr); 760135446Strhodes cleanup: 761135446Strhodes isc_mem_free(mctx, buf); 762135446Strhodes} 763135446Strhodes 764135446Strhodesstatic void 765135446Strhodesparse_args(int argc, char **argv) { 766135446Strhodes isc_boolean_t have_lookup = ISC_FALSE; 767135446Strhodes 768135446Strhodes usesearch = ISC_TRUE; 769135446Strhodes for (argc--, argv++; argc > 0; argc--, argv++) { 770135446Strhodes debug("main parsing %s", argv[0]); 771135446Strhodes if (argv[0][0] == '-') { 772135446Strhodes if (argv[0][1] != 0) 773135446Strhodes setoption(&argv[0][1]); 774135446Strhodes else 775135446Strhodes have_lookup = ISC_TRUE; 776135446Strhodes } else { 777135446Strhodes if (!have_lookup) { 778135446Strhodes have_lookup = ISC_TRUE; 779135446Strhodes in_use = ISC_TRUE; 780135446Strhodes addlookup(argv[0]); 781135446Strhodes } 782135446Strhodes else 783135446Strhodes set_nameserver(argv[0]); 784135446Strhodes } 785135446Strhodes } 786135446Strhodes} 787135446Strhodes 788135446Strhodesstatic void 789135446Strhodesflush_lookup_list(void) { 790135446Strhodes dig_lookup_t *l, *lp; 791135446Strhodes dig_query_t *q, *qp; 792135446Strhodes dig_server_t *s, *sp; 793135446Strhodes 794135446Strhodes lookup_counter = 0; 795135446Strhodes l = ISC_LIST_HEAD(lookup_list); 796135446Strhodes while (l != NULL) { 797135446Strhodes q = ISC_LIST_HEAD(l->q); 798135446Strhodes while (q != NULL) { 799135446Strhodes if (q->sock != NULL) { 800135446Strhodes isc_socket_cancel(q->sock, NULL, 801135446Strhodes ISC_SOCKCANCEL_ALL); 802135446Strhodes isc_socket_detach(&q->sock); 803135446Strhodes } 804135446Strhodes if (ISC_LINK_LINKED(&q->recvbuf, link)) 805135446Strhodes ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf, 806135446Strhodes link); 807135446Strhodes if (ISC_LINK_LINKED(&q->lengthbuf, link)) 808135446Strhodes ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf, 809135446Strhodes link); 810135446Strhodes isc_buffer_invalidate(&q->recvbuf); 811135446Strhodes isc_buffer_invalidate(&q->lengthbuf); 812135446Strhodes qp = q; 813135446Strhodes q = ISC_LIST_NEXT(q, link); 814135446Strhodes ISC_LIST_DEQUEUE(l->q, qp, link); 815135446Strhodes isc_mem_free(mctx, qp); 816135446Strhodes } 817135446Strhodes s = ISC_LIST_HEAD(l->my_server_list); 818135446Strhodes while (s != NULL) { 819135446Strhodes sp = s; 820135446Strhodes s = ISC_LIST_NEXT(s, link); 821135446Strhodes ISC_LIST_DEQUEUE(l->my_server_list, sp, link); 822135446Strhodes isc_mem_free(mctx, sp); 823135446Strhodes 824135446Strhodes } 825135446Strhodes if (l->sendmsg != NULL) 826135446Strhodes dns_message_destroy(&l->sendmsg); 827135446Strhodes if (l->timer != NULL) 828135446Strhodes isc_timer_detach(&l->timer); 829135446Strhodes lp = l; 830135446Strhodes l = ISC_LIST_NEXT(l, link); 831135446Strhodes ISC_LIST_DEQUEUE(lookup_list, lp, link); 832135446Strhodes isc_mem_free(mctx, lp); 833135446Strhodes } 834135446Strhodes} 835135446Strhodes 836135446Strhodesstatic void 837135446Strhodesgetinput(isc_task_t *task, isc_event_t *event) { 838135446Strhodes UNUSED(task); 839135446Strhodes if (global_event == NULL) 840135446Strhodes global_event = event; 841135446Strhodes while (in_use) { 842135446Strhodes get_next_command(); 843135446Strhodes if (ISC_LIST_HEAD(lookup_list) != NULL) { 844135446Strhodes start_lookup(); 845135446Strhodes return; 846135446Strhodes } 847135446Strhodes } 848135446Strhodes isc_app_shutdown(); 849135446Strhodes} 850135446Strhodes 851135446Strhodesint 852135446Strhodesmain(int argc, char **argv) { 853135446Strhodes isc_result_t result; 854135446Strhodes 855135446Strhodes ISC_LIST_INIT(lookup_list); 856135446Strhodes ISC_LIST_INIT(server_list); 857135446Strhodes ISC_LIST_INIT(search_list); 858135446Strhodes 859135446Strhodes result = isc_app_start(); 860135446Strhodes check_result(result, "isc_app_start"); 861135446Strhodes 862135446Strhodes setup_libs(); 863135446Strhodes progname = argv[0]; 864135446Strhodes 865135446Strhodes parse_args(argc, argv); 866135446Strhodes 867135446Strhodes setup_system(); 868135446Strhodes if (domainopt[0] != '\0') 869135446Strhodes set_search_domain(domainopt); 870135446Strhodes if (in_use) 871135446Strhodes result = isc_app_onrun(mctx, global_task, onrun_callback, 872135446Strhodes NULL); 873135446Strhodes else 874135446Strhodes result = isc_app_onrun(mctx, global_task, getinput, NULL); 875135446Strhodes check_result(result, "isc_app_onrun"); 876135446Strhodes in_use = ISC_TF(!in_use); 877135446Strhodes 878135446Strhodes (void)isc_app_run(); 879135446Strhodes 880135446Strhodes puts(""); 881135446Strhodes debug("done, and starting to shut down"); 882135446Strhodes if (global_event != NULL) 883135446Strhodes isc_event_free(&global_event); 884135446Strhodes cancel_all(); 885135446Strhodes destroy_libs(); 886135446Strhodes isc_app_finish(); 887135446Strhodes 888135446Strhodes return (0); 889135446Strhodes} 890