1135446Strhodes/* 2262706Serwin * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2000-2003 Internet Software Consortium. 4135446Strhodes * 5174187Sdougb * Permission to use, copy, modify, and/or 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 18254897Serwin/* $Id: nslookup.c,v 1.130 2011/12/16 23:01:16 each Exp $ */ 19135446Strhodes 20135446Strhodes#include <config.h> 21135446Strhodes 22135446Strhodes#include <stdlib.h> 23254897Serwin#include <unistd.h> 24135446Strhodes 25135446Strhodes#include <isc/app.h> 26135446Strhodes#include <isc/buffer.h> 27135446Strhodes#include <isc/commandline.h> 28135446Strhodes#include <isc/event.h> 29135446Strhodes#include <isc/parseint.h> 30193149Sdougb#include <isc/print.h> 31135446Strhodes#include <isc/string.h> 32135446Strhodes#include <isc/timer.h> 33135446Strhodes#include <isc/util.h> 34135446Strhodes#include <isc/task.h> 35135446Strhodes#include <isc/netaddr.h> 36135446Strhodes 37135446Strhodes#include <dns/message.h> 38135446Strhodes#include <dns/name.h> 39135446Strhodes#include <dns/fixedname.h> 40135446Strhodes#include <dns/rdata.h> 41135446Strhodes#include <dns/rdataclass.h> 42135446Strhodes#include <dns/rdataset.h> 43135446Strhodes#include <dns/rdatastruct.h> 44135446Strhodes#include <dns/rdatatype.h> 45135446Strhodes#include <dns/byaddr.h> 46135446Strhodes 47135446Strhodes#include <dig/dig.h> 48135446Strhodes 49254897Serwin#if defined(HAVE_READLINE) 50254897Serwin#include <readline/readline.h> 51254897Serwin#include <readline/history.h> 52254897Serwin#endif 53254897Serwin 54135446Strhodesstatic isc_boolean_t short_form = ISC_TRUE, 55135446Strhodes tcpmode = ISC_FALSE, 56135446Strhodes identify = ISC_FALSE, stats = ISC_TRUE, 57135446Strhodes comments = ISC_TRUE, section_question = ISC_TRUE, 58135446Strhodes section_answer = ISC_TRUE, section_authority = ISC_TRUE, 59135446Strhodes section_additional = ISC_TRUE, recurse = ISC_TRUE, 60170222Sdougb aaonly = ISC_FALSE, nofail = ISC_TRUE; 61170222Sdougb 62254897Serwinstatic isc_boolean_t interactive; 63254897Serwin 64135446Strhodesstatic isc_boolean_t in_use = ISC_FALSE; 65135446Strhodesstatic char defclass[MXRD] = "IN"; 66135446Strhodesstatic char deftype[MXRD] = "A"; 67135446Strhodesstatic isc_event_t *global_event = NULL; 68245163Serwinstatic int query_error = 1, print_error = 0; 69135446Strhodes 70135446Strhodesstatic char domainopt[DNS_NAME_MAXTEXT]; 71135446Strhodes 72135446Strhodesstatic const char *rcodetext[] = { 73135446Strhodes "NOERROR", 74135446Strhodes "FORMERR", 75135446Strhodes "SERVFAIL", 76135446Strhodes "NXDOMAIN", 77135446Strhodes "NOTIMP", 78135446Strhodes "REFUSED", 79135446Strhodes "YXDOMAIN", 80135446Strhodes "YXRRSET", 81135446Strhodes "NXRRSET", 82135446Strhodes "NOTAUTH", 83135446Strhodes "NOTZONE", 84135446Strhodes "RESERVED11", 85135446Strhodes "RESERVED12", 86135446Strhodes "RESERVED13", 87135446Strhodes "RESERVED14", 88135446Strhodes "RESERVED15", 89135446Strhodes "BADVERS" 90135446Strhodes}; 91135446Strhodes 92135446Strhodesstatic const char *rtypetext[] = { 93135446Strhodes "rtype_0 = ", /* 0 */ 94135446Strhodes "internet address = ", /* 1 */ 95135446Strhodes "nameserver = ", /* 2 */ 96135446Strhodes "md = ", /* 3 */ 97135446Strhodes "mf = ", /* 4 */ 98135446Strhodes "canonical name = ", /* 5 */ 99135446Strhodes "soa = ", /* 6 */ 100135446Strhodes "mb = ", /* 7 */ 101135446Strhodes "mg = ", /* 8 */ 102135446Strhodes "mr = ", /* 9 */ 103135446Strhodes "rtype_10 = ", /* 10 */ 104135446Strhodes "protocol = ", /* 11 */ 105135446Strhodes "name = ", /* 12 */ 106135446Strhodes "hinfo = ", /* 13 */ 107135446Strhodes "minfo = ", /* 14 */ 108135446Strhodes "mail exchanger = ", /* 15 */ 109135446Strhodes "text = ", /* 16 */ 110135446Strhodes "rp = ", /* 17 */ 111135446Strhodes "afsdb = ", /* 18 */ 112135446Strhodes "x25 address = ", /* 19 */ 113135446Strhodes "isdn address = ", /* 20 */ 114135446Strhodes "rt = ", /* 21 */ 115135446Strhodes "nsap = ", /* 22 */ 116135446Strhodes "nsap_ptr = ", /* 23 */ 117135446Strhodes "signature = ", /* 24 */ 118135446Strhodes "key = ", /* 25 */ 119135446Strhodes "px = ", /* 26 */ 120135446Strhodes "gpos = ", /* 27 */ 121135446Strhodes "has AAAA address ", /* 28 */ 122135446Strhodes "loc = ", /* 29 */ 123135446Strhodes "next = ", /* 30 */ 124135446Strhodes "rtype_31 = ", /* 31 */ 125135446Strhodes "rtype_32 = ", /* 32 */ 126135446Strhodes "service = ", /* 33 */ 127135446Strhodes "rtype_34 = ", /* 34 */ 128135446Strhodes "naptr = ", /* 35 */ 129135446Strhodes "kx = ", /* 36 */ 130135446Strhodes "cert = ", /* 37 */ 131135446Strhodes "v6 address = ", /* 38 */ 132135446Strhodes "dname = ", /* 39 */ 133135446Strhodes "rtype_40 = ", /* 40 */ 134135446Strhodes "optional = " /* 41 */ 135135446Strhodes}; 136135446Strhodes 137135446Strhodes#define N_KNOWN_RRTYPES (sizeof(rtypetext) / sizeof(rtypetext[0])) 138135446Strhodes 139135446Strhodesstatic void flush_lookup_list(void); 140135446Strhodesstatic void getinput(isc_task_t *task, isc_event_t *event); 141135446Strhodes 142193149Sdougbstatic char * 143193149Sdougbrcode_totext(dns_rcode_t rcode) 144193149Sdougb{ 145193149Sdougb static char buf[sizeof("?65535")]; 146193149Sdougb union { 147193149Sdougb const char *consttext; 148193149Sdougb char *deconsttext; 149193149Sdougb } totext; 150193149Sdougb 151193149Sdougb if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) { 152193149Sdougb snprintf(buf, sizeof(buf), "?%u", rcode); 153193149Sdougb totext.deconsttext = buf; 154193149Sdougb } else 155193149Sdougb totext.consttext = rcodetext[rcode]; 156193149Sdougb return totext.deconsttext; 157193149Sdougb} 158193149Sdougb 159135446Strhodesvoid 160135446Strhodesdighost_shutdown(void) { 161135446Strhodes isc_event_t *event = global_event; 162135446Strhodes 163135446Strhodes flush_lookup_list(); 164135446Strhodes debug("dighost_shutdown()"); 165135446Strhodes 166135446Strhodes if (!in_use) { 167135446Strhodes isc_app_shutdown(); 168135446Strhodes return; 169135446Strhodes } 170135446Strhodes 171135446Strhodes isc_task_send(global_task, &event); 172135446Strhodes} 173135446Strhodes 174135446Strhodesstatic void 175135446Strhodesprintsoa(dns_rdata_t *rdata) { 176135446Strhodes dns_rdata_soa_t soa; 177135446Strhodes isc_result_t result; 178135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 179135446Strhodes 180135446Strhodes result = dns_rdata_tostruct(rdata, &soa, NULL); 181135446Strhodes check_result(result, "dns_rdata_tostruct"); 182135446Strhodes 183135446Strhodes dns_name_format(&soa.origin, namebuf, sizeof(namebuf)); 184135446Strhodes printf("\torigin = %s\n", namebuf); 185135446Strhodes dns_name_format(&soa.contact, namebuf, sizeof(namebuf)); 186135446Strhodes printf("\tmail addr = %s\n", namebuf); 187135446Strhodes printf("\tserial = %u\n", soa.serial); 188135446Strhodes printf("\trefresh = %u\n", soa.refresh); 189135446Strhodes printf("\tretry = %u\n", soa.retry); 190135446Strhodes printf("\texpire = %u\n", soa.expire); 191135446Strhodes printf("\tminimum = %u\n", soa.minimum); 192135446Strhodes dns_rdata_freestruct(&soa); 193135446Strhodes} 194135446Strhodes 195135446Strhodesstatic void 196135446Strhodesprinta(dns_rdata_t *rdata) { 197135446Strhodes isc_result_t result; 198135446Strhodes char text[sizeof("255.255.255.255")]; 199135446Strhodes isc_buffer_t b; 200135446Strhodes 201135446Strhodes isc_buffer_init(&b, text, sizeof(text)); 202135446Strhodes result = dns_rdata_totext(rdata, NULL, &b); 203135446Strhodes check_result(result, "dns_rdata_totext"); 204135446Strhodes printf("Address: %.*s\n", (int)isc_buffer_usedlength(&b), 205135446Strhodes (char *)isc_buffer_base(&b)); 206135446Strhodes} 207135446Strhodes#ifdef DIG_SIGCHASE 208135446Strhodes/* Just for compatibility : not use in host program */ 209135446Strhodesisc_result_t 210135446Strhodesprintrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset, 211135446Strhodes isc_buffer_t *target) 212135446Strhodes{ 213135446Strhodes UNUSED(owner_name); 214135446Strhodes UNUSED(rdataset); 215135446Strhodes UNUSED(target); 216135446Strhodes return(ISC_FALSE); 217135446Strhodes} 218135446Strhodes#endif 219135446Strhodesstatic void 220135446Strhodesprintrdata(dns_rdata_t *rdata) { 221135446Strhodes isc_result_t result; 222135446Strhodes isc_buffer_t *b = NULL; 223135446Strhodes unsigned int size = 1024; 224135446Strhodes isc_boolean_t done = ISC_FALSE; 225135446Strhodes 226135446Strhodes if (rdata->type < N_KNOWN_RRTYPES) 227135446Strhodes printf("%s", rtypetext[rdata->type]); 228135446Strhodes else 229135446Strhodes printf("rdata_%d = ", rdata->type); 230135446Strhodes 231135446Strhodes while (!done) { 232135446Strhodes result = isc_buffer_allocate(mctx, &b, size); 233135446Strhodes if (result != ISC_R_SUCCESS) 234135446Strhodes check_result(result, "isc_buffer_allocate"); 235135446Strhodes result = dns_rdata_totext(rdata, NULL, b); 236135446Strhodes if (result == ISC_R_SUCCESS) { 237135446Strhodes printf("%.*s\n", (int)isc_buffer_usedlength(b), 238135446Strhodes (char *)isc_buffer_base(b)); 239135446Strhodes done = ISC_TRUE; 240135446Strhodes } else if (result != ISC_R_NOSPACE) 241135446Strhodes check_result(result, "dns_rdata_totext"); 242135446Strhodes isc_buffer_free(&b); 243135446Strhodes size *= 2; 244135446Strhodes } 245135446Strhodes} 246135446Strhodes 247135446Strhodesstatic isc_result_t 248135446Strhodesprintsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, 249135446Strhodes dns_section_t section) { 250135446Strhodes isc_result_t result, loopresult; 251135446Strhodes dns_name_t *name; 252135446Strhodes dns_rdataset_t *rdataset = NULL; 253135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 254135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 255135446Strhodes 256135446Strhodes UNUSED(query); 257135446Strhodes UNUSED(headers); 258135446Strhodes 259135446Strhodes debug("printsection()"); 260135446Strhodes 261135446Strhodes result = dns_message_firstname(msg, section); 262135446Strhodes if (result == ISC_R_NOMORE) 263135446Strhodes return (ISC_R_SUCCESS); 264135446Strhodes else if (result != ISC_R_SUCCESS) 265135446Strhodes return (result); 266135446Strhodes for (;;) { 267135446Strhodes name = NULL; 268135446Strhodes dns_message_currentname(msg, section, 269135446Strhodes &name); 270135446Strhodes for (rdataset = ISC_LIST_HEAD(name->list); 271135446Strhodes rdataset != NULL; 272135446Strhodes rdataset = ISC_LIST_NEXT(rdataset, link)) { 273135446Strhodes loopresult = dns_rdataset_first(rdataset); 274135446Strhodes while (loopresult == ISC_R_SUCCESS) { 275135446Strhodes dns_rdataset_current(rdataset, &rdata); 276135446Strhodes switch (rdata.type) { 277135446Strhodes case dns_rdatatype_a: 278135446Strhodes if (section != DNS_SECTION_ANSWER) 279135446Strhodes goto def_short_section; 280135446Strhodes dns_name_format(name, namebuf, 281135446Strhodes sizeof(namebuf)); 282135446Strhodes printf("Name:\t%s\n", namebuf); 283135446Strhodes printa(&rdata); 284135446Strhodes break; 285135446Strhodes case dns_rdatatype_soa: 286135446Strhodes dns_name_format(name, namebuf, 287135446Strhodes sizeof(namebuf)); 288135446Strhodes printf("%s\n", namebuf); 289135446Strhodes printsoa(&rdata); 290135446Strhodes break; 291135446Strhodes default: 292135446Strhodes def_short_section: 293135446Strhodes dns_name_format(name, namebuf, 294135446Strhodes sizeof(namebuf)); 295135446Strhodes printf("%s\t", namebuf); 296135446Strhodes printrdata(&rdata); 297135446Strhodes break; 298135446Strhodes } 299135446Strhodes dns_rdata_reset(&rdata); 300135446Strhodes loopresult = dns_rdataset_next(rdataset); 301135446Strhodes } 302135446Strhodes } 303135446Strhodes result = dns_message_nextname(msg, section); 304135446Strhodes if (result == ISC_R_NOMORE) 305135446Strhodes break; 306135446Strhodes else if (result != ISC_R_SUCCESS) { 307135446Strhodes return (result); 308135446Strhodes } 309135446Strhodes } 310135446Strhodes return (ISC_R_SUCCESS); 311135446Strhodes} 312135446Strhodes 313135446Strhodesstatic isc_result_t 314135446Strhodesdetailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, 315135446Strhodes dns_section_t section) { 316135446Strhodes isc_result_t result, loopresult; 317135446Strhodes dns_name_t *name; 318135446Strhodes dns_rdataset_t *rdataset = NULL; 319135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 320135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 321135446Strhodes 322135446Strhodes UNUSED(query); 323135446Strhodes 324135446Strhodes debug("detailsection()"); 325135446Strhodes 326135446Strhodes if (headers) { 327135446Strhodes switch (section) { 328135446Strhodes case DNS_SECTION_QUESTION: 329135446Strhodes puts(" QUESTIONS:"); 330135446Strhodes break; 331135446Strhodes case DNS_SECTION_ANSWER: 332135446Strhodes puts(" ANSWERS:"); 333135446Strhodes break; 334135446Strhodes case DNS_SECTION_AUTHORITY: 335135446Strhodes puts(" AUTHORITY RECORDS:"); 336135446Strhodes break; 337135446Strhodes case DNS_SECTION_ADDITIONAL: 338135446Strhodes puts(" ADDITIONAL RECORDS:"); 339135446Strhodes break; 340135446Strhodes } 341135446Strhodes } 342135446Strhodes 343135446Strhodes result = dns_message_firstname(msg, section); 344135446Strhodes if (result == ISC_R_NOMORE) 345135446Strhodes return (ISC_R_SUCCESS); 346135446Strhodes else if (result != ISC_R_SUCCESS) 347135446Strhodes return (result); 348135446Strhodes for (;;) { 349135446Strhodes name = NULL; 350135446Strhodes dns_message_currentname(msg, section, 351135446Strhodes &name); 352135446Strhodes for (rdataset = ISC_LIST_HEAD(name->list); 353135446Strhodes rdataset != NULL; 354135446Strhodes rdataset = ISC_LIST_NEXT(rdataset, link)) { 355135446Strhodes if (section == DNS_SECTION_QUESTION) { 356135446Strhodes dns_name_format(name, namebuf, 357135446Strhodes sizeof(namebuf)); 358135446Strhodes printf("\t%s, ", namebuf); 359135446Strhodes dns_rdatatype_format(rdataset->type, 360135446Strhodes namebuf, 361135446Strhodes sizeof(namebuf)); 362135446Strhodes printf("type = %s, ", namebuf); 363135446Strhodes dns_rdataclass_format(rdataset->rdclass, 364135446Strhodes namebuf, 365135446Strhodes sizeof(namebuf)); 366135446Strhodes printf("class = %s\n", namebuf); 367135446Strhodes } 368135446Strhodes loopresult = dns_rdataset_first(rdataset); 369135446Strhodes while (loopresult == ISC_R_SUCCESS) { 370135446Strhodes dns_rdataset_current(rdataset, &rdata); 371135446Strhodes 372135446Strhodes dns_name_format(name, namebuf, 373135446Strhodes sizeof(namebuf)); 374135446Strhodes printf(" -> %s\n", namebuf); 375135446Strhodes 376135446Strhodes switch (rdata.type) { 377135446Strhodes case dns_rdatatype_soa: 378135446Strhodes printsoa(&rdata); 379135446Strhodes break; 380135446Strhodes default: 381135446Strhodes printf("\t"); 382135446Strhodes printrdata(&rdata); 383135446Strhodes } 384135446Strhodes dns_rdata_reset(&rdata); 385204619Sdougb printf("\tttl = %u\n", rdataset->ttl); 386135446Strhodes loopresult = dns_rdataset_next(rdataset); 387135446Strhodes } 388135446Strhodes } 389135446Strhodes result = dns_message_nextname(msg, section); 390135446Strhodes if (result == ISC_R_NOMORE) 391135446Strhodes break; 392135446Strhodes else if (result != ISC_R_SUCCESS) { 393135446Strhodes return (result); 394135446Strhodes } 395135446Strhodes } 396135446Strhodes return (ISC_R_SUCCESS); 397135446Strhodes} 398135446Strhodes 399135446Strhodesvoid 400135446Strhodesreceived(int bytes, isc_sockaddr_t *from, dig_query_t *query) 401135446Strhodes{ 402135446Strhodes UNUSED(bytes); 403135446Strhodes UNUSED(from); 404135446Strhodes UNUSED(query); 405135446Strhodes} 406135446Strhodes 407135446Strhodesvoid 408135446Strhodestrying(char *frm, dig_lookup_t *lookup) { 409135446Strhodes UNUSED(frm); 410135446Strhodes UNUSED(lookup); 411135446Strhodes 412135446Strhodes} 413135446Strhodes 414135446Strhodesisc_result_t 415135446Strhodesprintmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { 416193149Sdougb char servtext[ISC_SOCKADDR_FORMATSIZE]; 417135446Strhodes 418245163Serwin /* I've we've gotten this far, we've reached a server. */ 419245163Serwin query_error = 0; 420245163Serwin 421135446Strhodes debug("printmessage()"); 422135446Strhodes 423135446Strhodes isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext)); 424143731Sdougb printf("Server:\t\t%s\n", query->userarg); 425135446Strhodes printf("Address:\t%s\n", servtext); 426193149Sdougb 427135446Strhodes puts(""); 428135446Strhodes 429135446Strhodes if (!short_form) { 430135446Strhodes isc_boolean_t headers = ISC_TRUE; 431135446Strhodes puts("------------"); 432135446Strhodes /* detailheader(query, msg);*/ 433135446Strhodes detailsection(query, msg, headers, DNS_SECTION_QUESTION); 434135446Strhodes detailsection(query, msg, headers, DNS_SECTION_ANSWER); 435135446Strhodes detailsection(query, msg, headers, DNS_SECTION_AUTHORITY); 436135446Strhodes detailsection(query, msg, headers, DNS_SECTION_ADDITIONAL); 437135446Strhodes puts("------------"); 438135446Strhodes } 439135446Strhodes 440135446Strhodes if (msg->rcode != 0) { 441135446Strhodes char nametext[DNS_NAME_FORMATSIZE]; 442135446Strhodes dns_name_format(query->lookup->name, 443135446Strhodes nametext, sizeof(nametext)); 444174187Sdougb printf("** server can't find %s: %s\n", 445262706Serwin nametext, rcode_totext(msg->rcode)); 446135446Strhodes debug("returning with rcode == 0"); 447245163Serwin 448245163Serwin /* the lookup failed */ 449245163Serwin print_error |= 1; 450135446Strhodes return (ISC_R_SUCCESS); 451135446Strhodes } 452135446Strhodes 453135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) 454135446Strhodes puts("Non-authoritative answer:"); 455135446Strhodes if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) 456135446Strhodes printsection(query, msg, headers, DNS_SECTION_ANSWER); 457135446Strhodes else 458135446Strhodes printf("*** Can't find %s: No answer\n", 459135446Strhodes query->lookup->textname); 460135446Strhodes 461135446Strhodes if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) && 462135446Strhodes (query->lookup->rdtype != dns_rdatatype_a)) { 463135446Strhodes puts("\nAuthoritative answers can be found from:"); 464135446Strhodes printsection(query, msg, headers, 465135446Strhodes DNS_SECTION_AUTHORITY); 466135446Strhodes printsection(query, msg, headers, 467135446Strhodes DNS_SECTION_ADDITIONAL); 468135446Strhodes } 469135446Strhodes return (ISC_R_SUCCESS); 470135446Strhodes} 471135446Strhodes 472135446Strhodesstatic void 473135446Strhodesshow_settings(isc_boolean_t full, isc_boolean_t serv_only) { 474135446Strhodes dig_server_t *srv; 475135446Strhodes isc_sockaddr_t sockaddr; 476135446Strhodes dig_searchlist_t *listent; 477193149Sdougb isc_result_t result; 478135446Strhodes 479135446Strhodes srv = ISC_LIST_HEAD(server_list); 480135446Strhodes 481135446Strhodes while (srv != NULL) { 482135446Strhodes char sockstr[ISC_SOCKADDR_FORMATSIZE]; 483135446Strhodes 484193149Sdougb result = get_address(srv->servername, port, &sockaddr); 485193149Sdougb check_result(result, "get_address"); 486193149Sdougb 487135446Strhodes isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr)); 488135446Strhodes printf("Default server: %s\nAddress: %s\n", 489143731Sdougb srv->userarg, sockstr); 490135446Strhodes if (!full) 491135446Strhodes return; 492135446Strhodes srv = ISC_LIST_NEXT(srv, link); 493135446Strhodes } 494135446Strhodes if (serv_only) 495135446Strhodes return; 496135446Strhodes printf("\nSet options:\n"); 497135446Strhodes printf(" %s\t\t\t%s\t\t%s\n", 498135446Strhodes tcpmode ? "vc" : "novc", 499135446Strhodes short_form ? "nodebug" : "debug", 500135446Strhodes debugging ? "d2" : "nod2"); 501135446Strhodes printf(" %s\t\t%s\n", 502135446Strhodes usesearch ? "search" : "nosearch", 503135446Strhodes recurse ? "recurse" : "norecurse"); 504262706Serwin printf(" timeout = %d\t\tretry = %d\tport = %d\tndots = %d\n", 505262706Serwin timeout, tries, port, ndots); 506135446Strhodes printf(" querytype = %-8s\tclass = %s\n", deftype, defclass); 507135446Strhodes printf(" srchlist = "); 508135446Strhodes for (listent = ISC_LIST_HEAD(search_list); 509135446Strhodes listent != NULL; 510135446Strhodes listent = ISC_LIST_NEXT(listent, link)) { 511135446Strhodes printf("%s", listent->origin); 512135446Strhodes if (ISC_LIST_NEXT(listent, link) != NULL) 513135446Strhodes printf("/"); 514135446Strhodes } 515135446Strhodes printf("\n"); 516135446Strhodes} 517135446Strhodes 518135446Strhodesstatic isc_boolean_t 519135446Strhodestesttype(char *typetext) { 520135446Strhodes isc_result_t result; 521135446Strhodes isc_textregion_t tr; 522135446Strhodes dns_rdatatype_t rdtype; 523135446Strhodes 524135446Strhodes tr.base = typetext; 525135446Strhodes tr.length = strlen(typetext); 526135446Strhodes result = dns_rdatatype_fromtext(&rdtype, &tr); 527135446Strhodes if (result == ISC_R_SUCCESS) 528135446Strhodes return (ISC_TRUE); 529135446Strhodes else { 530135446Strhodes printf("unknown query type: %s\n", typetext); 531135446Strhodes return (ISC_FALSE); 532135446Strhodes } 533135446Strhodes} 534135446Strhodes 535135446Strhodesstatic isc_boolean_t 536135446Strhodestestclass(char *typetext) { 537135446Strhodes isc_result_t result; 538135446Strhodes isc_textregion_t tr; 539135446Strhodes dns_rdataclass_t rdclass; 540135446Strhodes 541135446Strhodes tr.base = typetext; 542135446Strhodes tr.length = strlen(typetext); 543135446Strhodes result = dns_rdataclass_fromtext(&rdclass, &tr); 544193149Sdougb if (result == ISC_R_SUCCESS) 545135446Strhodes return (ISC_TRUE); 546135446Strhodes else { 547135446Strhodes printf("unknown query class: %s\n", typetext); 548135446Strhodes return (ISC_FALSE); 549135446Strhodes } 550135446Strhodes} 551135446Strhodes 552135446Strhodesstatic void 553135446Strhodesset_port(const char *value) { 554135446Strhodes isc_uint32_t n; 555135446Strhodes isc_result_t result = parse_uint(&n, value, 65535, "port"); 556135446Strhodes if (result == ISC_R_SUCCESS) 557135446Strhodes port = (isc_uint16_t) n; 558135446Strhodes} 559135446Strhodes 560135446Strhodesstatic void 561135446Strhodesset_timeout(const char *value) { 562135446Strhodes isc_uint32_t n; 563135446Strhodes isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout"); 564135446Strhodes if (result == ISC_R_SUCCESS) 565135446Strhodes timeout = n; 566135446Strhodes} 567135446Strhodes 568135446Strhodesstatic void 569135446Strhodesset_tries(const char *value) { 570135446Strhodes isc_uint32_t n; 571135446Strhodes isc_result_t result = parse_uint(&n, value, INT_MAX, "tries"); 572135446Strhodes if (result == ISC_R_SUCCESS) 573135446Strhodes tries = n; 574135446Strhodes} 575135446Strhodes 576135446Strhodesstatic void 577262706Serwinset_ndots(const char *value) { 578262706Serwin isc_uint32_t n; 579262706Serwin isc_result_t result = parse_uint(&n, value, 128, "ndots"); 580262706Serwin if (result == ISC_R_SUCCESS) 581262706Serwin ndots = n; 582262706Serwin} 583262706Serwin 584262706Serwinstatic void 585135446Strhodessetoption(char *opt) { 586135446Strhodes if (strncasecmp(opt, "all", 4) == 0) { 587135446Strhodes show_settings(ISC_TRUE, ISC_FALSE); 588135446Strhodes } else if (strncasecmp(opt, "class=", 6) == 0) { 589135446Strhodes if (testclass(&opt[6])) 590225361Sdougb strlcpy(defclass, &opt[6], sizeof(defclass)); 591135446Strhodes } else if (strncasecmp(opt, "cl=", 3) == 0) { 592135446Strhodes if (testclass(&opt[3])) 593225361Sdougb strlcpy(defclass, &opt[3], sizeof(defclass)); 594135446Strhodes } else if (strncasecmp(opt, "type=", 5) == 0) { 595135446Strhodes if (testtype(&opt[5])) 596225361Sdougb strlcpy(deftype, &opt[5], sizeof(deftype)); 597135446Strhodes } else if (strncasecmp(opt, "ty=", 3) == 0) { 598135446Strhodes if (testtype(&opt[3])) 599225361Sdougb strlcpy(deftype, &opt[3], sizeof(deftype)); 600135446Strhodes } else if (strncasecmp(opt, "querytype=", 10) == 0) { 601135446Strhodes if (testtype(&opt[10])) 602225361Sdougb strlcpy(deftype, &opt[10], sizeof(deftype)); 603135446Strhodes } else if (strncasecmp(opt, "query=", 6) == 0) { 604135446Strhodes if (testtype(&opt[6])) 605225361Sdougb strlcpy(deftype, &opt[6], sizeof(deftype)); 606135446Strhodes } else if (strncasecmp(opt, "qu=", 3) == 0) { 607135446Strhodes if (testtype(&opt[3])) 608225361Sdougb strlcpy(deftype, &opt[3], sizeof(deftype)); 609135446Strhodes } else if (strncasecmp(opt, "q=", 2) == 0) { 610135446Strhodes if (testtype(&opt[2])) 611225361Sdougb strlcpy(deftype, &opt[2], sizeof(deftype)); 612135446Strhodes } else if (strncasecmp(opt, "domain=", 7) == 0) { 613225361Sdougb strlcpy(domainopt, &opt[7], sizeof(domainopt)); 614135446Strhodes set_search_domain(domainopt); 615135446Strhodes usesearch = ISC_TRUE; 616135446Strhodes } else if (strncasecmp(opt, "do=", 3) == 0) { 617225361Sdougb strlcpy(domainopt, &opt[3], sizeof(domainopt)); 618135446Strhodes set_search_domain(domainopt); 619135446Strhodes usesearch = ISC_TRUE; 620135446Strhodes } else if (strncasecmp(opt, "port=", 5) == 0) { 621135446Strhodes set_port(&opt[5]); 622135446Strhodes } else if (strncasecmp(opt, "po=", 3) == 0) { 623135446Strhodes set_port(&opt[3]); 624135446Strhodes } else if (strncasecmp(opt, "timeout=", 8) == 0) { 625135446Strhodes set_timeout(&opt[8]); 626135446Strhodes } else if (strncasecmp(opt, "t=", 2) == 0) { 627135446Strhodes set_timeout(&opt[2]); 628193149Sdougb } else if (strncasecmp(opt, "rec", 3) == 0) { 629135446Strhodes recurse = ISC_TRUE; 630135446Strhodes } else if (strncasecmp(opt, "norec", 5) == 0) { 631135446Strhodes recurse = ISC_FALSE; 632135446Strhodes } else if (strncasecmp(opt, "retry=", 6) == 0) { 633135446Strhodes set_tries(&opt[6]); 634135446Strhodes } else if (strncasecmp(opt, "ret=", 4) == 0) { 635135446Strhodes set_tries(&opt[4]); 636193149Sdougb } else if (strncasecmp(opt, "def", 3) == 0) { 637135446Strhodes usesearch = ISC_TRUE; 638135446Strhodes } else if (strncasecmp(opt, "nodef", 5) == 0) { 639135446Strhodes usesearch = ISC_FALSE; 640193149Sdougb } else if (strncasecmp(opt, "vc", 3) == 0) { 641135446Strhodes tcpmode = ISC_TRUE; 642135446Strhodes } else if (strncasecmp(opt, "novc", 5) == 0) { 643135446Strhodes tcpmode = ISC_FALSE; 644193149Sdougb } else if (strncasecmp(opt, "deb", 3) == 0) { 645135446Strhodes short_form = ISC_FALSE; 646170222Sdougb showsearch = ISC_TRUE; 647135446Strhodes } else if (strncasecmp(opt, "nodeb", 5) == 0) { 648135446Strhodes short_form = ISC_TRUE; 649170222Sdougb showsearch = ISC_FALSE; 650193149Sdougb } else if (strncasecmp(opt, "d2", 2) == 0) { 651135446Strhodes debugging = ISC_TRUE; 652135446Strhodes } else if (strncasecmp(opt, "nod2", 4) == 0) { 653135446Strhodes debugging = ISC_FALSE; 654135446Strhodes } else if (strncasecmp(opt, "search", 3) == 0) { 655135446Strhodes usesearch = ISC_TRUE; 656135446Strhodes } else if (strncasecmp(opt, "nosearch", 5) == 0) { 657135446Strhodes usesearch = ISC_FALSE; 658135446Strhodes } else if (strncasecmp(opt, "sil", 3) == 0) { 659135446Strhodes /* deprecation_msg = ISC_FALSE; */ 660170222Sdougb } else if (strncasecmp(opt, "fail", 3) == 0) { 661170222Sdougb nofail=ISC_FALSE; 662170222Sdougb } else if (strncasecmp(opt, "nofail", 3) == 0) { 663170222Sdougb nofail=ISC_TRUE; 664262706Serwin } else if (strncasecmp(opt, "ndots=", 6) == 0) { 665262706Serwin set_ndots(&opt[6]); 666135446Strhodes } else { 667193149Sdougb printf("*** Invalid option: %s\n", opt); 668135446Strhodes } 669135446Strhodes} 670135446Strhodes 671135446Strhodesstatic void 672135446Strhodesaddlookup(char *opt) { 673135446Strhodes dig_lookup_t *lookup; 674135446Strhodes isc_result_t result; 675135446Strhodes isc_textregion_t tr; 676135446Strhodes dns_rdatatype_t rdtype; 677135446Strhodes dns_rdataclass_t rdclass; 678135446Strhodes char store[MXNAME]; 679135446Strhodes 680135446Strhodes debug("addlookup()"); 681135446Strhodes tr.base = deftype; 682135446Strhodes tr.length = strlen(deftype); 683135446Strhodes result = dns_rdatatype_fromtext(&rdtype, &tr); 684135446Strhodes if (result != ISC_R_SUCCESS) { 685135446Strhodes printf("unknown query type: %s\n", deftype); 686135446Strhodes rdclass = dns_rdatatype_a; 687135446Strhodes } 688135446Strhodes tr.base = defclass; 689135446Strhodes tr.length = strlen(defclass); 690135446Strhodes result = dns_rdataclass_fromtext(&rdclass, &tr); 691135446Strhodes if (result != ISC_R_SUCCESS) { 692135446Strhodes printf("unknown query class: %s\n", defclass); 693135446Strhodes rdclass = dns_rdataclass_in; 694135446Strhodes } 695135446Strhodes lookup = make_empty_lookup(); 696135446Strhodes if (get_reverse(store, sizeof(store), opt, lookup->ip6_int, ISC_TRUE) 697135446Strhodes == ISC_R_SUCCESS) { 698225361Sdougb strlcpy(lookup->textname, store, sizeof(lookup->textname)); 699135446Strhodes lookup->rdtype = dns_rdatatype_ptr; 700135446Strhodes lookup->rdtypeset = ISC_TRUE; 701135446Strhodes } else { 702225361Sdougb strlcpy(lookup->textname, opt, sizeof(lookup->textname)); 703135446Strhodes lookup->rdtype = rdtype; 704135446Strhodes lookup->rdtypeset = ISC_TRUE; 705135446Strhodes } 706135446Strhodes lookup->rdclass = rdclass; 707135446Strhodes lookup->rdclassset = ISC_TRUE; 708135446Strhodes lookup->trace = ISC_FALSE; 709135446Strhodes lookup->trace_root = lookup->trace; 710135446Strhodes lookup->ns_search_only = ISC_FALSE; 711135446Strhodes lookup->identify = identify; 712135446Strhodes lookup->recurse = recurse; 713135446Strhodes lookup->aaonly = aaonly; 714135446Strhodes lookup->retries = tries; 715135446Strhodes lookup->udpsize = 0; 716135446Strhodes lookup->comments = comments; 717135446Strhodes lookup->tcp_mode = tcpmode; 718135446Strhodes lookup->stats = stats; 719135446Strhodes lookup->section_question = section_question; 720135446Strhodes lookup->section_answer = section_answer; 721135446Strhodes lookup->section_authority = section_authority; 722135446Strhodes lookup->section_additional = section_additional; 723135446Strhodes lookup->new_search = ISC_TRUE; 724170222Sdougb if (nofail) 725170222Sdougb lookup->servfail_stops = ISC_FALSE; 726135446Strhodes ISC_LIST_INIT(lookup->q); 727135446Strhodes ISC_LINK_INIT(lookup, link); 728135446Strhodes ISC_LIST_APPEND(lookup_list, lookup, link); 729135446Strhodes lookup->origin = NULL; 730135446Strhodes ISC_LIST_INIT(lookup->my_server_list); 731135446Strhodes debug("looking up %s", lookup->textname); 732135446Strhodes} 733135446Strhodes 734135446Strhodesstatic void 735254897Serwindo_next_command(char *input) { 736135446Strhodes char *ptr, *arg; 737135446Strhodes 738135446Strhodes ptr = next_token(&input, " \t\r\n"); 739135446Strhodes if (ptr == NULL) 740254897Serwin return; 741135446Strhodes arg = next_token(&input, " \t\r\n"); 742135446Strhodes if ((strcasecmp(ptr, "set") == 0) && 743135446Strhodes (arg != NULL)) 744135446Strhodes setoption(arg); 745135446Strhodes else if ((strcasecmp(ptr, "server") == 0) || 746135446Strhodes (strcasecmp(ptr, "lserver") == 0)) { 747143731Sdougb isc_app_block(); 748135446Strhodes set_nameserver(arg); 749170222Sdougb check_ra = ISC_FALSE; 750143731Sdougb isc_app_unblock(); 751135446Strhodes show_settings(ISC_TRUE, ISC_TRUE); 752135446Strhodes } else if (strcasecmp(ptr, "exit") == 0) { 753135446Strhodes in_use = ISC_FALSE; 754135446Strhodes } else if (strcasecmp(ptr, "help") == 0 || 755135446Strhodes strcasecmp(ptr, "?") == 0) { 756135446Strhodes printf("The '%s' command is not yet implemented.\n", ptr); 757135446Strhodes } else if (strcasecmp(ptr, "finger") == 0 || 758135446Strhodes strcasecmp(ptr, "root") == 0 || 759135446Strhodes strcasecmp(ptr, "ls") == 0 || 760135446Strhodes strcasecmp(ptr, "view") == 0) { 761135446Strhodes printf("The '%s' command is not implemented.\n", ptr); 762135446Strhodes } else 763135446Strhodes addlookup(ptr); 764254897Serwin} 765254897Serwin 766254897Serwinstatic void 767254897Serwinget_next_command(void) { 768254897Serwin char *buf; 769254897Serwin char *ptr; 770254897Serwin 771254897Serwin fflush(stdout); 772254897Serwin buf = isc_mem_allocate(mctx, COMMSIZE); 773254897Serwin if (buf == NULL) 774254897Serwin fatal("memory allocation failure"); 775254897Serwin isc_app_block(); 776254897Serwin if (interactive) { 777254897Serwin#ifdef HAVE_READLINE 778254897Serwin ptr = readline("> "); 779262706Serwin if (ptr != NULL) 780262706Serwin add_history(ptr); 781254897Serwin#else 782254897Serwin fputs("> ", stderr); 783254897Serwin fflush(stderr); 784254897Serwin ptr = fgets(buf, COMMSIZE, stdin); 785254897Serwin#endif 786254897Serwin } else 787254897Serwin ptr = fgets(buf, COMMSIZE, stdin); 788254897Serwin isc_app_unblock(); 789254897Serwin if (ptr == NULL) { 790254897Serwin in_use = ISC_FALSE; 791254897Serwin } else 792254897Serwin do_next_command(ptr); 793254897Serwin#ifdef HAVE_READLINE 794254897Serwin if (interactive) 795254897Serwin free(ptr); 796254897Serwin#endif 797135446Strhodes isc_mem_free(mctx, buf); 798135446Strhodes} 799135446Strhodes 800135446Strhodesstatic void 801135446Strhodesparse_args(int argc, char **argv) { 802135446Strhodes isc_boolean_t have_lookup = ISC_FALSE; 803135446Strhodes 804135446Strhodes usesearch = ISC_TRUE; 805135446Strhodes for (argc--, argv++; argc > 0; argc--, argv++) { 806135446Strhodes debug("main parsing %s", argv[0]); 807135446Strhodes if (argv[0][0] == '-') { 808135446Strhodes if (argv[0][1] != 0) 809135446Strhodes setoption(&argv[0][1]); 810135446Strhodes else 811135446Strhodes have_lookup = ISC_TRUE; 812135446Strhodes } else { 813135446Strhodes if (!have_lookup) { 814135446Strhodes have_lookup = ISC_TRUE; 815135446Strhodes in_use = ISC_TRUE; 816135446Strhodes addlookup(argv[0]); 817170222Sdougb } else { 818170222Sdougb set_nameserver(argv[0]); 819170222Sdougb check_ra = ISC_FALSE; 820135446Strhodes } 821135446Strhodes } 822135446Strhodes } 823135446Strhodes} 824135446Strhodes 825135446Strhodesstatic void 826135446Strhodesflush_lookup_list(void) { 827135446Strhodes dig_lookup_t *l, *lp; 828135446Strhodes dig_query_t *q, *qp; 829135446Strhodes dig_server_t *s, *sp; 830135446Strhodes 831135446Strhodes lookup_counter = 0; 832135446Strhodes l = ISC_LIST_HEAD(lookup_list); 833135446Strhodes while (l != NULL) { 834135446Strhodes q = ISC_LIST_HEAD(l->q); 835135446Strhodes while (q != NULL) { 836135446Strhodes if (q->sock != NULL) { 837135446Strhodes isc_socket_cancel(q->sock, NULL, 838135446Strhodes ISC_SOCKCANCEL_ALL); 839135446Strhodes isc_socket_detach(&q->sock); 840135446Strhodes } 841135446Strhodes if (ISC_LINK_LINKED(&q->recvbuf, link)) 842135446Strhodes ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf, 843135446Strhodes link); 844135446Strhodes if (ISC_LINK_LINKED(&q->lengthbuf, link)) 845135446Strhodes ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf, 846135446Strhodes link); 847135446Strhodes isc_buffer_invalidate(&q->recvbuf); 848135446Strhodes isc_buffer_invalidate(&q->lengthbuf); 849135446Strhodes qp = q; 850135446Strhodes q = ISC_LIST_NEXT(q, link); 851135446Strhodes ISC_LIST_DEQUEUE(l->q, qp, link); 852135446Strhodes isc_mem_free(mctx, qp); 853135446Strhodes } 854135446Strhodes s = ISC_LIST_HEAD(l->my_server_list); 855135446Strhodes while (s != NULL) { 856135446Strhodes sp = s; 857135446Strhodes s = ISC_LIST_NEXT(s, link); 858135446Strhodes ISC_LIST_DEQUEUE(l->my_server_list, sp, link); 859135446Strhodes isc_mem_free(mctx, sp); 860135446Strhodes 861135446Strhodes } 862135446Strhodes if (l->sendmsg != NULL) 863135446Strhodes dns_message_destroy(&l->sendmsg); 864135446Strhodes if (l->timer != NULL) 865135446Strhodes isc_timer_detach(&l->timer); 866135446Strhodes lp = l; 867135446Strhodes l = ISC_LIST_NEXT(l, link); 868135446Strhodes ISC_LIST_DEQUEUE(lookup_list, lp, link); 869135446Strhodes isc_mem_free(mctx, lp); 870135446Strhodes } 871135446Strhodes} 872135446Strhodes 873135446Strhodesstatic void 874135446Strhodesgetinput(isc_task_t *task, isc_event_t *event) { 875135446Strhodes UNUSED(task); 876135446Strhodes if (global_event == NULL) 877135446Strhodes global_event = event; 878135446Strhodes while (in_use) { 879135446Strhodes get_next_command(); 880135446Strhodes if (ISC_LIST_HEAD(lookup_list) != NULL) { 881135446Strhodes start_lookup(); 882135446Strhodes return; 883135446Strhodes } 884135446Strhodes } 885135446Strhodes isc_app_shutdown(); 886135446Strhodes} 887135446Strhodes 888135446Strhodesint 889135446Strhodesmain(int argc, char **argv) { 890135446Strhodes isc_result_t result; 891135446Strhodes 892254897Serwin interactive = ISC_TF(isatty(0)); 893254897Serwin 894135446Strhodes ISC_LIST_INIT(lookup_list); 895135446Strhodes ISC_LIST_INIT(server_list); 896135446Strhodes ISC_LIST_INIT(search_list); 897135446Strhodes 898170222Sdougb check_ra = ISC_TRUE; 899170222Sdougb 900135446Strhodes result = isc_app_start(); 901135446Strhodes check_result(result, "isc_app_start"); 902135446Strhodes 903135446Strhodes setup_libs(); 904135446Strhodes progname = argv[0]; 905135446Strhodes 906135446Strhodes parse_args(argc, argv); 907135446Strhodes 908135446Strhodes setup_system(); 909135446Strhodes if (domainopt[0] != '\0') 910135446Strhodes set_search_domain(domainopt); 911135446Strhodes if (in_use) 912135446Strhodes result = isc_app_onrun(mctx, global_task, onrun_callback, 913135446Strhodes NULL); 914135446Strhodes else 915135446Strhodes result = isc_app_onrun(mctx, global_task, getinput, NULL); 916135446Strhodes check_result(result, "isc_app_onrun"); 917135446Strhodes in_use = ISC_TF(!in_use); 918135446Strhodes 919135446Strhodes (void)isc_app_run(); 920135446Strhodes 921135446Strhodes puts(""); 922135446Strhodes debug("done, and starting to shut down"); 923135446Strhodes if (global_event != NULL) 924135446Strhodes isc_event_free(&global_event); 925135446Strhodes cancel_all(); 926135446Strhodes destroy_libs(); 927135446Strhodes isc_app_finish(); 928135446Strhodes 929245163Serwin return (query_error | print_error); 930135446Strhodes} 931