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