15185a700Sflorian /*
25185a700Sflorian * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
35185a700Sflorian *
45185a700Sflorian * Permission to use, copy, modify, and/or distribute this software for any
55185a700Sflorian * purpose with or without fee is hereby granted, provided that the above
65185a700Sflorian * copyright notice and this permission notice appear in all copies.
75185a700Sflorian *
85185a700Sflorian * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
95185a700Sflorian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
105185a700Sflorian * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
115185a700Sflorian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
125185a700Sflorian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
135185a700Sflorian * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
145185a700Sflorian * PERFORMANCE OF THIS SOFTWARE.
155185a700Sflorian */
165185a700Sflorian
175185a700Sflorian /*! \file */
18*e9ec1762Sflorian #include <sys/types.h>
195185a700Sflorian
205185a700Sflorian #include <err.h>
215185a700Sflorian #include <limits.h>
225185a700Sflorian #include <locale.h>
235185a700Sflorian #include <stdlib.h>
245185a700Sflorian #include <string.h>
255185a700Sflorian #include <unistd.h>
264465bcfbSjsg #include <time.h>
274465bcfbSjsg #include <stdint.h>
285185a700Sflorian
295185a700Sflorian #include <isc/app.h>
305185a700Sflorian #include <isc/util.h>
315185a700Sflorian
325185a700Sflorian #include <dns/fixedname.h>
335185a700Sflorian #include <dns/message.h>
345185a700Sflorian #include <dns/name.h>
355185a700Sflorian #include <dns/rdata.h>
365185a700Sflorian #include <dns/rdataclass.h>
375185a700Sflorian #include <dns/rdataset.h>
385185a700Sflorian #include <dns/rdatatype.h>
395185a700Sflorian
405185a700Sflorian #include "dig.h"
415185a700Sflorian
421fb015a8Sflorian static int short_form = 1, listed_server = 0;
431fb015a8Sflorian static int default_lookups = 1;
445185a700Sflorian static int seen_error = -1;
451fb015a8Sflorian static int list_addresses = 1;
465185a700Sflorian static dns_rdatatype_t list_type = dns_rdatatype_a;
471fb015a8Sflorian static int printed_server = 0;
481fb015a8Sflorian static int ipv4only = 0, ipv6only = 0;
495185a700Sflorian
505185a700Sflorian static const char *opcodetext[] = {
515185a700Sflorian "QUERY",
525185a700Sflorian "IQUERY",
535185a700Sflorian "STATUS",
545185a700Sflorian "RESERVED3",
555185a700Sflorian "NOTIFY",
565185a700Sflorian "UPDATE",
575185a700Sflorian "RESERVED6",
585185a700Sflorian "RESERVED7",
595185a700Sflorian "RESERVED8",
605185a700Sflorian "RESERVED9",
615185a700Sflorian "RESERVED10",
625185a700Sflorian "RESERVED11",
635185a700Sflorian "RESERVED12",
645185a700Sflorian "RESERVED13",
655185a700Sflorian "RESERVED14",
665185a700Sflorian "RESERVED15"
675185a700Sflorian };
685185a700Sflorian
695185a700Sflorian static const char *rcodetext[] = {
705185a700Sflorian "NOERROR",
715185a700Sflorian "FORMERR",
725185a700Sflorian "SERVFAIL",
735185a700Sflorian "NXDOMAIN",
745185a700Sflorian "NOTIMP",
755185a700Sflorian "REFUSED",
765185a700Sflorian "YXDOMAIN",
775185a700Sflorian "YXRRSET",
785185a700Sflorian "NXRRSET",
795185a700Sflorian "NOTAUTH",
805185a700Sflorian "NOTZONE",
815185a700Sflorian "RESERVED11",
825185a700Sflorian "RESERVED12",
835185a700Sflorian "RESERVED13",
845185a700Sflorian "RESERVED14",
855185a700Sflorian "RESERVED15",
865185a700Sflorian "BADVERS"
875185a700Sflorian };
885185a700Sflorian
895185a700Sflorian struct rtype {
905185a700Sflorian unsigned int type;
915185a700Sflorian const char *text;
925185a700Sflorian };
935185a700Sflorian
945185a700Sflorian static struct rtype rtypes[] = {
955185a700Sflorian { 1, "has address" },
965185a700Sflorian { 2, "name server" },
975185a700Sflorian { 5, "is an alias for" },
985185a700Sflorian { 11, "has well known services" },
995185a700Sflorian { 12, "domain name pointer" },
1005185a700Sflorian { 13, "host information" },
1015185a700Sflorian { 15, "mail is handled by" },
1025185a700Sflorian { 16, "descriptive text" },
1035185a700Sflorian { 19, "x25 address" },
1045185a700Sflorian { 20, "ISDN address" },
1055185a700Sflorian { 24, "has signature" },
1065185a700Sflorian { 25, "has key" },
1075185a700Sflorian { 28, "has IPv6 address" },
1085185a700Sflorian { 29, "location" },
1095185a700Sflorian { 0, NULL }
1105185a700Sflorian };
1115185a700Sflorian
1125185a700Sflorian static char *
rcode_totext(dns_rcode_t rcode)1135185a700Sflorian rcode_totext(dns_rcode_t rcode)
1145185a700Sflorian {
1155185a700Sflorian static char buf[sizeof("?65535")];
1165185a700Sflorian union {
1175185a700Sflorian const char *consttext;
1185185a700Sflorian char *deconsttext;
1195185a700Sflorian } totext;
1205185a700Sflorian
1215185a700Sflorian if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
1225185a700Sflorian snprintf(buf, sizeof(buf), "?%u", rcode);
1235185a700Sflorian totext.deconsttext = buf;
1245185a700Sflorian } else
1255185a700Sflorian totext.consttext = rcodetext[rcode];
1265185a700Sflorian return totext.deconsttext;
1275185a700Sflorian }
1285185a700Sflorian
1295185a700Sflorian static __dead void
1305185a700Sflorian show_usage(void);
1315185a700Sflorian
1325185a700Sflorian static void
show_usage(void)1335185a700Sflorian show_usage(void) {
1345185a700Sflorian fputs(
1355185a700Sflorian "usage: host [-46aCdilrsTVvw] [-c class] [-m flag] [-N ndots] [-R number]\n"
1365185a700Sflorian " [-t type] [-W wait] name [server]\n", stderr);
1375185a700Sflorian exit(1);
1385185a700Sflorian }
1395185a700Sflorian
1405185a700Sflorian static void
host_shutdown(void)1415185a700Sflorian host_shutdown(void) {
1425185a700Sflorian (void) isc_app_shutdown();
1435185a700Sflorian }
1445185a700Sflorian
1455185a700Sflorian static void
received(unsigned int bytes,struct sockaddr_storage * from,dig_query_t * query)146b1a294b5Sflorian received(unsigned int bytes, struct sockaddr_storage *from, dig_query_t *query) {
1477238a213Sflorian struct timespec now;
1485185a700Sflorian
1495185a700Sflorian if (!short_form) {
1505185a700Sflorian char fromtext[ISC_SOCKADDR_FORMATSIZE];
1515185a700Sflorian isc_sockaddr_format(from, fromtext, sizeof(fromtext));
152b53d8310Sflorian clock_gettime(CLOCK_MONOTONIC, &now);
153427f8978Sflorian printf("Received %u bytes from %s in %lld ms\n",
154427f8978Sflorian bytes, fromtext, uelapsed(&now, &query->time_sent)/1000);
1555185a700Sflorian }
1565185a700Sflorian }
1575185a700Sflorian
1585185a700Sflorian static void
trying(char * frm,dig_lookup_t * lookup)1595185a700Sflorian trying(char *frm, dig_lookup_t *lookup) {
1605185a700Sflorian UNUSED(lookup);
1615185a700Sflorian
1625185a700Sflorian if (!short_form)
1635185a700Sflorian printf("Trying \"%s\"\n", frm);
1645185a700Sflorian }
1655185a700Sflorian
1665185a700Sflorian static void
say_message(dns_name_t * name,const char * msg,dns_rdata_t * rdata,dig_query_t * query)1675185a700Sflorian say_message(dns_name_t *name, const char *msg, dns_rdata_t *rdata,
1685185a700Sflorian dig_query_t *query)
1695185a700Sflorian {
1705185a700Sflorian isc_buffer_t *b = NULL;
1715185a700Sflorian char namestr[DNS_NAME_FORMATSIZE];
1725185a700Sflorian isc_region_t r;
1735185a700Sflorian isc_result_t result;
1745185a700Sflorian unsigned int bufsize = BUFSIZ;
1755185a700Sflorian
1765185a700Sflorian dns_name_format(name, namestr, sizeof(namestr));
1775185a700Sflorian retry:
1785185a700Sflorian result = isc_buffer_allocate(&b, bufsize);
1795185a700Sflorian check_result(result, "isc_buffer_allocate");
1805185a700Sflorian result = dns_rdata_totext(rdata, NULL, b);
1815185a700Sflorian if (result == ISC_R_NOSPACE) {
1825185a700Sflorian isc_buffer_free(&b);
1835185a700Sflorian bufsize *= 2;
1845185a700Sflorian goto retry;
1855185a700Sflorian }
1865185a700Sflorian check_result(result, "dns_rdata_totext");
1875185a700Sflorian isc_buffer_usedregion(b, &r);
1885185a700Sflorian if (query->lookup->identify_previous_line) {
1895185a700Sflorian printf("Nameserver %s:\n\t",
1905185a700Sflorian query->servname);
1915185a700Sflorian }
1925185a700Sflorian printf("%s %s %.*s", namestr,
1935185a700Sflorian msg, (int)r.length, (char *)r.base);
1945185a700Sflorian if (query->lookup->identify) {
1955185a700Sflorian printf(" on server %s", query->servname);
1965185a700Sflorian }
1975185a700Sflorian printf("\n");
1985185a700Sflorian isc_buffer_free(&b);
1995185a700Sflorian }
2005185a700Sflorian static isc_result_t
printsection(dns_message_t * msg,dns_section_t sectionid,const char * section_name,int headers,dig_query_t * query)2015185a700Sflorian printsection(dns_message_t *msg, dns_section_t sectionid,
2021fb015a8Sflorian const char *section_name, int headers,
2035185a700Sflorian dig_query_t *query)
2045185a700Sflorian {
2055185a700Sflorian dns_name_t *name, *print_name;
2065185a700Sflorian dns_rdataset_t *rdataset;
2075185a700Sflorian dns_rdata_t rdata = DNS_RDATA_INIT;
2085185a700Sflorian isc_buffer_t target;
2095185a700Sflorian isc_result_t result, loopresult;
2105185a700Sflorian isc_region_t r;
2115185a700Sflorian dns_name_t empty_name;
2125185a700Sflorian char tbuf[4096];
2131fb015a8Sflorian int first;
2141fb015a8Sflorian int no_rdata;
2155185a700Sflorian
2165185a700Sflorian if (sectionid == DNS_SECTION_QUESTION)
2171fb015a8Sflorian no_rdata = 1;
2185185a700Sflorian else
2191fb015a8Sflorian no_rdata = 0;
2205185a700Sflorian
2215185a700Sflorian if (headers)
2225185a700Sflorian printf(";; %s SECTION:\n", section_name);
2235185a700Sflorian
2245185a700Sflorian dns_name_init(&empty_name, NULL);
2255185a700Sflorian
2265185a700Sflorian result = dns_message_firstname(msg, sectionid);
2275185a700Sflorian if (result == ISC_R_NOMORE)
2285185a700Sflorian return (ISC_R_SUCCESS);
2295185a700Sflorian else if (result != ISC_R_SUCCESS)
2305185a700Sflorian return (result);
2315185a700Sflorian
2325185a700Sflorian for (;;) {
2335185a700Sflorian name = NULL;
2345185a700Sflorian dns_message_currentname(msg, sectionid, &name);
2355185a700Sflorian
2365185a700Sflorian isc_buffer_init(&target, tbuf, sizeof(tbuf));
2371fb015a8Sflorian first = 1;
2385185a700Sflorian print_name = name;
2395185a700Sflorian
2405185a700Sflorian for (rdataset = ISC_LIST_HEAD(name->list);
2415185a700Sflorian rdataset != NULL;
2425185a700Sflorian rdataset = ISC_LIST_NEXT(rdataset, link)) {
2435185a700Sflorian if (query->lookup->rdtype == dns_rdatatype_axfr &&
2445185a700Sflorian !((!list_addresses &&
2455185a700Sflorian (list_type == dns_rdatatype_any ||
2465185a700Sflorian rdataset->type == list_type)) ||
2475185a700Sflorian (list_addresses &&
2485185a700Sflorian (rdataset->type == dns_rdatatype_a ||
2495185a700Sflorian rdataset->type == dns_rdatatype_aaaa ||
2505185a700Sflorian rdataset->type == dns_rdatatype_ns ||
2515185a700Sflorian rdataset->type == dns_rdatatype_ptr))))
2525185a700Sflorian continue;
2535185a700Sflorian if (!short_form) {
2545185a700Sflorian result = dns_rdataset_totext(rdataset,
2555185a700Sflorian print_name,
2561fb015a8Sflorian 0,
2575185a700Sflorian no_rdata,
2585185a700Sflorian &target);
2595185a700Sflorian if (result != ISC_R_SUCCESS)
2605185a700Sflorian return (result);
2615185a700Sflorian UNUSED(first); /* Shut up compiler. */
2625185a700Sflorian } else {
2635185a700Sflorian loopresult = dns_rdataset_first(rdataset);
2645185a700Sflorian while (loopresult == ISC_R_SUCCESS) {
2655185a700Sflorian struct rtype *t;
2665185a700Sflorian const char *rtt;
2675185a700Sflorian char typebuf[DNS_RDATATYPE_FORMATSIZE];
2685185a700Sflorian char typebuf2[DNS_RDATATYPE_FORMATSIZE
2695185a700Sflorian + 20];
2705185a700Sflorian dns_rdataset_current(rdataset, &rdata);
2715185a700Sflorian
2725185a700Sflorian for (t = rtypes; t->text != NULL; t++) {
2735185a700Sflorian if (t->type == rdata.type) {
2745185a700Sflorian rtt = t->text;
2755185a700Sflorian goto found;
2765185a700Sflorian }
2775185a700Sflorian }
2785185a700Sflorian
2795185a700Sflorian dns_rdatatype_format(rdata.type,
2805185a700Sflorian typebuf,
2815185a700Sflorian sizeof(typebuf));
2825185a700Sflorian snprintf(typebuf2, sizeof(typebuf2),
2835185a700Sflorian "has %s record", typebuf);
2845185a700Sflorian rtt = typebuf2;
2855185a700Sflorian found:
2865185a700Sflorian say_message(print_name, rtt,
2875185a700Sflorian &rdata, query);
2885185a700Sflorian dns_rdata_reset(&rdata);
2895185a700Sflorian loopresult =
2905185a700Sflorian dns_rdataset_next(rdataset);
2915185a700Sflorian }
2925185a700Sflorian }
2935185a700Sflorian }
2945185a700Sflorian if (!short_form) {
2955185a700Sflorian isc_buffer_usedregion(&target, &r);
2965185a700Sflorian if (no_rdata)
2975185a700Sflorian printf(";%.*s", (int)r.length,
2985185a700Sflorian (char *)r.base);
2995185a700Sflorian else
3005185a700Sflorian printf("%.*s", (int)r.length, (char *)r.base);
3015185a700Sflorian }
3025185a700Sflorian
3035185a700Sflorian result = dns_message_nextname(msg, sectionid);
3045185a700Sflorian if (result == ISC_R_NOMORE)
3055185a700Sflorian break;
3065185a700Sflorian else if (result != ISC_R_SUCCESS)
3075185a700Sflorian return (result);
3085185a700Sflorian }
3095185a700Sflorian
3105185a700Sflorian return (ISC_R_SUCCESS);
3115185a700Sflorian }
3125185a700Sflorian
3135185a700Sflorian static isc_result_t
printrdata(dns_message_t * msg,dns_rdataset_t * rdataset,dns_name_t * owner,const char * set_name,int headers)3145185a700Sflorian printrdata(dns_message_t *msg, dns_rdataset_t *rdataset, dns_name_t *owner,
3151fb015a8Sflorian const char *set_name, int headers)
3165185a700Sflorian {
3175185a700Sflorian isc_buffer_t target;
3185185a700Sflorian isc_result_t result;
3195185a700Sflorian isc_region_t r;
3205185a700Sflorian char tbuf[4096];
3215185a700Sflorian
3225185a700Sflorian UNUSED(msg);
3235185a700Sflorian if (headers)
3245185a700Sflorian printf(";; %s SECTION:\n", set_name);
3255185a700Sflorian
3265185a700Sflorian isc_buffer_init(&target, tbuf, sizeof(tbuf));
3275185a700Sflorian
3281fb015a8Sflorian result = dns_rdataset_totext(rdataset, owner, 0, 0,
3295185a700Sflorian &target);
3305185a700Sflorian if (result != ISC_R_SUCCESS)
3315185a700Sflorian return (result);
3325185a700Sflorian isc_buffer_usedregion(&target, &r);
3335185a700Sflorian printf("%.*s", (int)r.length, (char *)r.base);
3345185a700Sflorian
3355185a700Sflorian return (ISC_R_SUCCESS);
3365185a700Sflorian }
3375185a700Sflorian
3385185a700Sflorian static void
chase_cnamechain(dns_message_t * msg,dns_name_t * qname)3395185a700Sflorian chase_cnamechain(dns_message_t *msg, dns_name_t *qname) {
3405185a700Sflorian isc_result_t result;
3415185a700Sflorian dns_rdataset_t *rdataset;
3425185a700Sflorian dns_rdata_cname_t cname;
3435185a700Sflorian dns_rdata_t rdata = DNS_RDATA_INIT;
3445185a700Sflorian unsigned int i = msg->counts[DNS_SECTION_ANSWER];
3455185a700Sflorian
3465185a700Sflorian while (i-- > 0) {
3475185a700Sflorian rdataset = NULL;
3485185a700Sflorian result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname,
3495185a700Sflorian dns_rdatatype_cname, 0, NULL,
3505185a700Sflorian &rdataset);
3515185a700Sflorian if (result != ISC_R_SUCCESS)
3525185a700Sflorian return;
3535185a700Sflorian result = dns_rdataset_first(rdataset);
3545185a700Sflorian check_result(result, "dns_rdataset_first");
3555185a700Sflorian dns_rdata_reset(&rdata);
3565185a700Sflorian dns_rdataset_current(rdataset, &rdata);
357ee21177aSflorian result = dns_rdata_tostruct_cname(&rdata, &cname);
358ee21177aSflorian check_result(result, "dns_rdata_tostruct_cname");
3595185a700Sflorian dns_name_copy(&cname.cname, qname, NULL);
360a0b66ce4Sflorian dns_rdata_freestruct_cname(&cname);
3615185a700Sflorian }
3625185a700Sflorian }
3635185a700Sflorian
3645185a700Sflorian static isc_result_t
printmessage(dig_query_t * query,dns_message_t * msg,int headers)3651fb015a8Sflorian printmessage(dig_query_t *query, dns_message_t *msg, int headers) {
3661fb015a8Sflorian int did_flag = 0;
3675185a700Sflorian dns_rdataset_t *opt, *tsig = NULL;
3685185a700Sflorian dns_name_t *tsigname;
3695185a700Sflorian isc_result_t result = ISC_R_SUCCESS;
3705185a700Sflorian int force_error;
3715185a700Sflorian
3725185a700Sflorian UNUSED(headers);
3735185a700Sflorian
3745185a700Sflorian /*
3755185a700Sflorian * We get called multiple times.
3765185a700Sflorian * Preserve any existing error status.
3775185a700Sflorian */
3785185a700Sflorian force_error = (seen_error == 1) ? 1 : 0;
3795185a700Sflorian seen_error = 1;
3805185a700Sflorian if (listed_server && !printed_server) {
3815185a700Sflorian char sockstr[ISC_SOCKADDR_FORMATSIZE];
3825185a700Sflorian
3835185a700Sflorian printf("Using domain server:\n");
3845185a700Sflorian printf("Name: %s\n", query->userarg);
3855185a700Sflorian isc_sockaddr_format(&query->sockaddr, sockstr,
3865185a700Sflorian sizeof(sockstr));
3875185a700Sflorian printf("Address: %s\n", sockstr);
3885185a700Sflorian printf("Aliases: \n\n");
3891fb015a8Sflorian printed_server = 1;
3905185a700Sflorian }
3915185a700Sflorian
3925185a700Sflorian if (msg->rcode != 0) {
3935185a700Sflorian char namestr[DNS_NAME_FORMATSIZE];
3945185a700Sflorian dns_name_format(query->lookup->name, namestr, sizeof(namestr));
3955185a700Sflorian
3965185a700Sflorian if (query->lookup->identify_previous_line)
3975185a700Sflorian printf("Nameserver %s:\n\t%s not found: %d(%s)\n",
3985185a700Sflorian query->servname,
3995185a700Sflorian (msg->rcode != dns_rcode_nxdomain) ? namestr :
4005185a700Sflorian query->lookup->textname, msg->rcode,
4015185a700Sflorian rcode_totext(msg->rcode));
4025185a700Sflorian else
4035185a700Sflorian printf("Host %s not found: %d(%s)\n",
4045185a700Sflorian (msg->rcode != dns_rcode_nxdomain) ? namestr :
4055185a700Sflorian query->lookup->textname, msg->rcode,
4065185a700Sflorian rcode_totext(msg->rcode));
4075185a700Sflorian return (ISC_R_SUCCESS);
4085185a700Sflorian }
4095185a700Sflorian
4105185a700Sflorian if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) {
4115185a700Sflorian char namestr[DNS_NAME_FORMATSIZE];
4125185a700Sflorian dig_lookup_t *lookup;
4135185a700Sflorian dns_fixedname_t fixed;
4145185a700Sflorian dns_name_t *name;
4155185a700Sflorian
4165185a700Sflorian /* Add AAAA and MX lookups. */
4175185a700Sflorian dns_fixedname_init(&fixed);
4185185a700Sflorian name = dns_fixedname_name(&fixed);
4195185a700Sflorian dns_name_copy(query->lookup->name, name, NULL);
4205185a700Sflorian chase_cnamechain(msg, name);
4215185a700Sflorian dns_name_format(name, namestr, sizeof(namestr));
4221fb015a8Sflorian lookup = clone_lookup(query->lookup, 0);
4235185a700Sflorian if (lookup != NULL) {
4245185a700Sflorian strlcpy(lookup->textname, namestr,
4255185a700Sflorian sizeof(lookup->textname));
4265185a700Sflorian lookup->rdtype = dns_rdatatype_aaaa;
4271fb015a8Sflorian lookup->rdtypeset = 1;
4285185a700Sflorian lookup->origin = NULL;
4295185a700Sflorian lookup->retries = tries;
4305185a700Sflorian ISC_LIST_APPEND(lookup_list, lookup, link);
4315185a700Sflorian }
4321fb015a8Sflorian lookup = clone_lookup(query->lookup, 0);
4335185a700Sflorian if (lookup != NULL) {
4345185a700Sflorian strlcpy(lookup->textname, namestr,
4355185a700Sflorian sizeof(lookup->textname));
4365185a700Sflorian lookup->rdtype = dns_rdatatype_mx;
4371fb015a8Sflorian lookup->rdtypeset = 1;
4385185a700Sflorian lookup->origin = NULL;
4395185a700Sflorian lookup->retries = tries;
4405185a700Sflorian ISC_LIST_APPEND(lookup_list, lookup, link);
4415185a700Sflorian }
4425185a700Sflorian }
4435185a700Sflorian
4445185a700Sflorian if (!short_form) {
4455185a700Sflorian printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n",
4465185a700Sflorian opcodetext[msg->opcode], rcode_totext(msg->rcode),
4475185a700Sflorian msg->id);
4485185a700Sflorian printf(";; flags: ");
4495185a700Sflorian if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
4505185a700Sflorian printf("qr");
4511fb015a8Sflorian did_flag = 1;
4525185a700Sflorian }
4535185a700Sflorian if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
4545185a700Sflorian printf("%saa", did_flag ? " " : "");
4551fb015a8Sflorian did_flag = 1;
4565185a700Sflorian }
4575185a700Sflorian if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
4585185a700Sflorian printf("%stc", did_flag ? " " : "");
4591fb015a8Sflorian did_flag = 1;
4605185a700Sflorian }
4615185a700Sflorian if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
4625185a700Sflorian printf("%srd", did_flag ? " " : "");
4631fb015a8Sflorian did_flag = 1;
4645185a700Sflorian }
4655185a700Sflorian if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
4665185a700Sflorian printf("%sra", did_flag ? " " : "");
4671fb015a8Sflorian did_flag = 1;
4685185a700Sflorian }
4695185a700Sflorian if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
4705185a700Sflorian printf("%sad", did_flag ? " " : "");
4711fb015a8Sflorian did_flag = 1;
4725185a700Sflorian }
4735185a700Sflorian if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
4745185a700Sflorian printf("%scd", did_flag ? " " : "");
4751fb015a8Sflorian did_flag = 1;
4765185a700Sflorian POST(did_flag);
4775185a700Sflorian }
4785185a700Sflorian printf("; QUERY: %u, ANSWER: %u, "
4795185a700Sflorian "AUTHORITY: %u, ADDITIONAL: %u\n",
4805185a700Sflorian msg->counts[DNS_SECTION_QUESTION],
4815185a700Sflorian msg->counts[DNS_SECTION_ANSWER],
4825185a700Sflorian msg->counts[DNS_SECTION_AUTHORITY],
4835185a700Sflorian msg->counts[DNS_SECTION_ADDITIONAL]);
4845185a700Sflorian opt = dns_message_getopt(msg);
4855185a700Sflorian if (opt != NULL)
4865185a700Sflorian printf(";; EDNS: version: %u, udp=%u\n",
4875185a700Sflorian (unsigned int)((opt->ttl & 0x00ff0000) >> 16),
4885185a700Sflorian (unsigned int)opt->rdclass);
4895185a700Sflorian tsigname = NULL;
4905185a700Sflorian tsig = dns_message_gettsig(msg, &tsigname);
4915185a700Sflorian if (tsig != NULL)
4925185a700Sflorian printf(";; PSEUDOSECTIONS: TSIG\n");
4935185a700Sflorian }
4945185a700Sflorian if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) &&
4955185a700Sflorian !short_form) {
4965185a700Sflorian printf("\n");
4975185a700Sflorian result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION",
4981fb015a8Sflorian 1, query);
4995185a700Sflorian if (result != ISC_R_SUCCESS)
5005185a700Sflorian return (result);
5015185a700Sflorian }
5025185a700Sflorian if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
5035185a700Sflorian if (!short_form)
5045185a700Sflorian printf("\n");
5055185a700Sflorian result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER",
5061fb015a8Sflorian !short_form, query);
5075185a700Sflorian if (result != ISC_R_SUCCESS)
5085185a700Sflorian return (result);
5095185a700Sflorian }
5105185a700Sflorian
5115185a700Sflorian if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) &&
5125185a700Sflorian !short_form) {
5135185a700Sflorian printf("\n");
5145185a700Sflorian result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY",
5151fb015a8Sflorian 1, query);
5165185a700Sflorian if (result != ISC_R_SUCCESS)
5175185a700Sflorian return (result);
5185185a700Sflorian }
5195185a700Sflorian if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) &&
5205185a700Sflorian !short_form) {
5215185a700Sflorian printf("\n");
5225185a700Sflorian result = printsection(msg, DNS_SECTION_ADDITIONAL,
5231fb015a8Sflorian "ADDITIONAL", 1, query);
5245185a700Sflorian if (result != ISC_R_SUCCESS)
5255185a700Sflorian return (result);
5265185a700Sflorian }
5275185a700Sflorian if ((tsig != NULL) && !short_form) {
5285185a700Sflorian printf("\n");
5295185a700Sflorian result = printrdata(msg, tsig, tsigname,
5301fb015a8Sflorian "PSEUDOSECTION TSIG", 1);
5315185a700Sflorian if (result != ISC_R_SUCCESS)
5325185a700Sflorian return (result);
5335185a700Sflorian }
5345185a700Sflorian if (!short_form)
5355185a700Sflorian printf("\n");
5365185a700Sflorian
5375185a700Sflorian if (short_form && !default_lookups &&
5385185a700Sflorian ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
5395185a700Sflorian char namestr[DNS_NAME_FORMATSIZE];
5405185a700Sflorian char typestr[DNS_RDATATYPE_FORMATSIZE];
5415185a700Sflorian dns_name_format(query->lookup->name, namestr, sizeof(namestr));
5425185a700Sflorian dns_rdatatype_format(query->lookup->rdtype, typestr,
5435185a700Sflorian sizeof(typestr));
5445185a700Sflorian printf("%s has no %s record\n", namestr, typestr);
5455185a700Sflorian }
5465185a700Sflorian seen_error = force_error;
5475185a700Sflorian return (result);
5485185a700Sflorian }
5495185a700Sflorian
5505185a700Sflorian static const char * optstring = "46ac:dilnrst:vVwCDN:R:TW:";
5515185a700Sflorian
5525185a700Sflorian /*% version */
5535185a700Sflorian static void
version(void)5545185a700Sflorian version(void) {
5555185a700Sflorian fputs("host " VERSION "\n", stderr);
5565185a700Sflorian }
5575185a700Sflorian
5585185a700Sflorian static void
pre_parse_args(int argc,char ** argv)5595185a700Sflorian pre_parse_args(int argc, char **argv) {
5605185a700Sflorian int c;
5615185a700Sflorian
5625185a700Sflorian while ((c = getopt(argc, argv, optstring)) != -1) {
5635185a700Sflorian switch (c) {
5645185a700Sflorian case '4':
5655185a700Sflorian if (ipv6only)
5665185a700Sflorian fatal("only one of -4 and -6 allowed");
5671fb015a8Sflorian ipv4only = 1;
5685185a700Sflorian break;
5695185a700Sflorian case '6':
5705185a700Sflorian if (ipv4only)
5715185a700Sflorian fatal("only one of -4 and -6 allowed");
5721fb015a8Sflorian ipv6only = 1;
5735185a700Sflorian break;
5745185a700Sflorian case 'a': break;
5755185a700Sflorian case 'c': break;
5765185a700Sflorian case 'd': break;
5775185a700Sflorian case 'i': break;
5785185a700Sflorian case 'l': break;
5795185a700Sflorian case 'n': break;
5805185a700Sflorian case 'r': break;
5815185a700Sflorian case 's': break;
5825185a700Sflorian case 't': break;
5835185a700Sflorian case 'v': break;
5845185a700Sflorian case 'V':
5855185a700Sflorian version();
5865185a700Sflorian exit(0);
5875185a700Sflorian break;
5885185a700Sflorian case 'w': break;
5895185a700Sflorian case 'C': break;
5905185a700Sflorian case 'D':
5915185a700Sflorian if (debugging)
5921fb015a8Sflorian debugtiming = 1;
5931fb015a8Sflorian debugging = 1;
5945185a700Sflorian break;
5955185a700Sflorian case 'N': break;
5965185a700Sflorian case 'R': break;
5975185a700Sflorian case 'T': break;
5985185a700Sflorian case 'W': break;
5995185a700Sflorian default:
6005185a700Sflorian show_usage();
6015185a700Sflorian }
6025185a700Sflorian }
6035185a700Sflorian optind = 1;
6045185a700Sflorian optreset = 1;
6055185a700Sflorian }
6065185a700Sflorian
6075185a700Sflorian static void
parse_args(int argc,char ** argv)6085185a700Sflorian parse_args(int argc, char **argv) {
6095185a700Sflorian char hostname[MXNAME];
6105185a700Sflorian dig_lookup_t *lookup;
6115185a700Sflorian int c;
6125185a700Sflorian char store[MXNAME];
6135185a700Sflorian isc_textregion_t tr;
6145185a700Sflorian isc_result_t result = ISC_R_SUCCESS;
6155185a700Sflorian dns_rdatatype_t rdtype;
6165185a700Sflorian dns_rdataclass_t rdclass;
6175185a700Sflorian uint32_t serial = 0;
6185185a700Sflorian const char *errstr;
6195185a700Sflorian
6205185a700Sflorian lookup = make_empty_lookup();
6215185a700Sflorian
6221fb015a8Sflorian lookup->servfail_stops = 0;
6231fb015a8Sflorian lookup->comments = 0;
6245185a700Sflorian
6255185a700Sflorian while ((c = getopt(argc, argv, optstring)) != -1) {
6265185a700Sflorian switch (c) {
6275185a700Sflorian case 'l':
6281fb015a8Sflorian lookup->tcp_mode = 1;
6295185a700Sflorian lookup->rdtype = dns_rdatatype_axfr;
6301fb015a8Sflorian lookup->rdtypeset = 1;
6315185a700Sflorian fatalexit = 3;
6325185a700Sflorian break;
6335185a700Sflorian case 'v':
6345185a700Sflorian case 'd':
6351fb015a8Sflorian short_form = 0;
6365185a700Sflorian break;
6375185a700Sflorian case 'r':
6381fb015a8Sflorian lookup->recurse = 0;
6395185a700Sflorian break;
6405185a700Sflorian case 't':
6415185a700Sflorian if (strncasecmp(optarg, "ixfr=", 5) == 0) {
6425185a700Sflorian rdtype = dns_rdatatype_ixfr;
6435185a700Sflorian /* XXXMPA add error checking */
6445185a700Sflorian serial = strtoul(optarg + 5,
6455185a700Sflorian NULL, 10);
6465185a700Sflorian result = ISC_R_SUCCESS;
6475185a700Sflorian } else {
6485185a700Sflorian tr.base = optarg;
6495185a700Sflorian tr.length = strlen(optarg);
6505185a700Sflorian result = dns_rdatatype_fromtext(&rdtype,
6515185a700Sflorian (isc_textregion_t *)&tr);
6525185a700Sflorian }
6535185a700Sflorian
6545185a700Sflorian if (result != ISC_R_SUCCESS) {
6555185a700Sflorian fatalexit = 2;
6565185a700Sflorian fatal("invalid type: %s\n", optarg);
6575185a700Sflorian }
6585185a700Sflorian if (!lookup->rdtypeset ||
6595185a700Sflorian lookup->rdtype != dns_rdatatype_axfr)
6605185a700Sflorian lookup->rdtype = rdtype;
6611fb015a8Sflorian lookup->rdtypeset = 1;
6625185a700Sflorian if (rdtype == dns_rdatatype_axfr) {
6635185a700Sflorian /* -l -t any -v */
6645185a700Sflorian list_type = dns_rdatatype_any;
6651fb015a8Sflorian short_form = 0;
6661fb015a8Sflorian lookup->tcp_mode = 1;
6675185a700Sflorian } else if (rdtype == dns_rdatatype_ixfr) {
6685185a700Sflorian lookup->ixfr_serial = serial;
6691fb015a8Sflorian lookup->tcp_mode = 1;
6705185a700Sflorian list_type = rdtype;
6715185a700Sflorian } else
6725185a700Sflorian list_type = rdtype;
6731fb015a8Sflorian list_addresses = 0;
6741fb015a8Sflorian default_lookups = 0;
6755185a700Sflorian break;
6765185a700Sflorian case 'c':
6775185a700Sflorian tr.base = optarg;
6785185a700Sflorian tr.length = strlen(optarg);
6795185a700Sflorian result = dns_rdataclass_fromtext(&rdclass,
6805185a700Sflorian (isc_textregion_t *)&tr);
6815185a700Sflorian
6825185a700Sflorian if (result != ISC_R_SUCCESS) {
6835185a700Sflorian fatalexit = 2;
6845185a700Sflorian fatal("invalid class: %s\n", optarg);
6855185a700Sflorian } else {
6865185a700Sflorian lookup->rdclass = rdclass;
6871fb015a8Sflorian lookup->rdclassset = 1;
6885185a700Sflorian }
6891fb015a8Sflorian default_lookups = 0;
6905185a700Sflorian break;
6915185a700Sflorian case 'a':
6925185a700Sflorian if (!lookup->rdtypeset ||
6935185a700Sflorian lookup->rdtype != dns_rdatatype_axfr)
6945185a700Sflorian lookup->rdtype = dns_rdatatype_any;
6955185a700Sflorian list_type = dns_rdatatype_any;
6961fb015a8Sflorian list_addresses = 0;
6971fb015a8Sflorian lookup->rdtypeset = 1;
6981fb015a8Sflorian short_form = 0;
6991fb015a8Sflorian default_lookups = 0;
7005185a700Sflorian break;
7015185a700Sflorian case 'i':
7021fb015a8Sflorian lookup->ip6_int = 1;
7035185a700Sflorian break;
7045185a700Sflorian case 'n':
7055185a700Sflorian /* deprecated */
7065185a700Sflorian break;
7075185a700Sflorian case 'm':
7085185a700Sflorian /* Handled by pre_parse_args(). */
7095185a700Sflorian break;
7105185a700Sflorian case 'w':
7115185a700Sflorian /*
7125185a700Sflorian * The timer routines are coded such that
7135185a700Sflorian * timeout==MAXINT doesn't enable the timer
7145185a700Sflorian */
7155185a700Sflorian timeout = INT_MAX;
7165185a700Sflorian break;
7175185a700Sflorian case 'W':
7185185a700Sflorian timeout = strtonum(optarg, 0, INT_MAX, &errstr);
7195185a700Sflorian if (errstr != NULL)
7205185a700Sflorian errx(1, "timeout is %s: %s", errstr, optarg);
7215185a700Sflorian if (timeout < 1)
7225185a700Sflorian timeout = 1;
7235185a700Sflorian break;
7245185a700Sflorian case 'R':
7255185a700Sflorian tries = strtonum(optarg, INT_MIN, INT_MAX - 1, &errstr);
7265185a700Sflorian if (errstr != NULL)
7275185a700Sflorian errx(1, "retries is %s: %s", errstr, optarg);
7285185a700Sflorian tries++;
7295185a700Sflorian if (tries < 2)
7305185a700Sflorian tries = 2;
7315185a700Sflorian break;
7325185a700Sflorian case 'T':
7331fb015a8Sflorian lookup->tcp_mode = 1;
7345185a700Sflorian break;
7355185a700Sflorian case 'C':
7365185a700Sflorian debug("showing all SOAs");
7375185a700Sflorian lookup->rdtype = dns_rdatatype_ns;
7381fb015a8Sflorian lookup->rdtypeset = 1;
7395185a700Sflorian lookup->rdclass = dns_rdataclass_in;
7401fb015a8Sflorian lookup->rdclassset = 1;
7411fb015a8Sflorian lookup->ns_search_only = 1;
7421fb015a8Sflorian lookup->trace_root = 1;
7431fb015a8Sflorian lookup->identify_previous_line = 1;
7441fb015a8Sflorian default_lookups = 0;
7455185a700Sflorian break;
7465185a700Sflorian case 'N':
7475185a700Sflorian debug("setting NDOTS to %s", optarg);
7485185a700Sflorian ndots = strtonum(optarg, 0, INT_MAX, &errstr);
7495185a700Sflorian if (errstr != NULL)
7505185a700Sflorian errx(1, "ndots is %s: %s", errstr, optarg);
7515185a700Sflorian break;
7525185a700Sflorian case 'D':
7535185a700Sflorian /* Handled by pre_parse_args(). */
7545185a700Sflorian break;
7555185a700Sflorian case '4':
7565185a700Sflorian /* Handled by pre_parse_args(). */
7575185a700Sflorian break;
7585185a700Sflorian case '6':
7595185a700Sflorian /* Handled by pre_parse_args(). */
7605185a700Sflorian break;
7615185a700Sflorian case 's':
7621fb015a8Sflorian lookup->servfail_stops = 1;
7635185a700Sflorian break;
7645185a700Sflorian default:
7655185a700Sflorian show_usage();
7665185a700Sflorian }
7675185a700Sflorian }
7685185a700Sflorian
7695185a700Sflorian lookup->retries = tries;
7705185a700Sflorian
7715185a700Sflorian argc -= optind;
7725185a700Sflorian argv += optind;
7735185a700Sflorian
7745185a700Sflorian if (argc == 0)
7755185a700Sflorian show_usage();
7765185a700Sflorian
777f5ba66e4Sflorian strlcpy(hostname, argv[0], sizeof(hostname));
7785185a700Sflorian
779f5ba66e4Sflorian if (argc >= 2) {
780aebd9aa6Sderaadt isc_result_t res;
781aebd9aa6Sderaadt
782aebd9aa6Sderaadt if ((res = set_nameserver(argv[1])))
783aebd9aa6Sderaadt fatal("couldn't get address for '%s': %s",
784aebd9aa6Sderaadt argv[1], isc_result_totext(res));
7855185a700Sflorian debug("server is %s", *argv + 1);
7861fb015a8Sflorian listed_server = 1;
7875185a700Sflorian } else
7881fb015a8Sflorian check_ra = 1;
7895185a700Sflorian
7901fb015a8Sflorian lookup->pending = 0;
7915185a700Sflorian if (get_reverse(store, sizeof(store), hostname,
7921fb015a8Sflorian lookup->ip6_int, 1) == ISC_R_SUCCESS) {
7935185a700Sflorian strlcpy(lookup->textname, store, sizeof(lookup->textname));
7945185a700Sflorian lookup->rdtype = dns_rdatatype_ptr;
7951fb015a8Sflorian lookup->rdtypeset = 1;
7961fb015a8Sflorian default_lookups = 0;
7975185a700Sflorian } else {
7985185a700Sflorian strlcpy(lookup->textname, hostname, sizeof(lookup->textname));
7991fb015a8Sflorian usesearch = 1;
8005185a700Sflorian }
8011fb015a8Sflorian lookup->new_search = 1;
8025185a700Sflorian ISC_LIST_APPEND(lookup_list, lookup, link);
8035185a700Sflorian }
8045185a700Sflorian
8055185a700Sflorian int
host_main(int argc,char ** argv)8065185a700Sflorian host_main(int argc, char **argv) {
8075185a700Sflorian isc_result_t result;
8085185a700Sflorian
8095185a700Sflorian tries = 2;
8105185a700Sflorian
8115185a700Sflorian ISC_LIST_INIT(lookup_list);
8125185a700Sflorian ISC_LIST_INIT(server_list);
813927deb69Sflorian ISC_LIST_INIT(root_hints_server_list);
8145185a700Sflorian ISC_LIST_INIT(search_list);
8155185a700Sflorian
8165185a700Sflorian fatalexit = 1;
8175185a700Sflorian
8185185a700Sflorian /* setup dighost callbacks */
8195185a700Sflorian dighost_printmessage = printmessage;
8205185a700Sflorian dighost_received = received;
8215185a700Sflorian dighost_trying = trying;
8225185a700Sflorian dighost_shutdown = host_shutdown;
8235185a700Sflorian
8245185a700Sflorian debug("main()");
8255185a700Sflorian progname = argv[0];
8265185a700Sflorian pre_parse_args(argc, argv);
8275185a700Sflorian result = isc_app_start();
8285185a700Sflorian check_result(result, "isc_app_start");
8295185a700Sflorian
8305185a700Sflorian if (pledge("stdio rpath inet dns", NULL) == -1) {
8315185a700Sflorian perror("pledge");
8325185a700Sflorian exit(1);
8335185a700Sflorian }
8345185a700Sflorian
8355185a700Sflorian setup_libs();
8365185a700Sflorian
8375185a700Sflorian if (pledge("stdio inet dns", NULL) == -1) {
8385185a700Sflorian perror("pledge");
8395185a700Sflorian exit(1);
8405185a700Sflorian }
8415185a700Sflorian
8425185a700Sflorian parse_args(argc, argv);
8435185a700Sflorian setup_system(ipv4only, ipv6only);
8445185a700Sflorian result = isc_app_onrun(global_task, onrun_callback, NULL);
8455185a700Sflorian check_result(result, "isc_app_onrun");
8465185a700Sflorian isc_app_run();
8475185a700Sflorian cancel_all();
8485185a700Sflorian destroy_libs();
8495185a700Sflorian return ((seen_error == 0) ? 0 : 1);
8505185a700Sflorian }
851