diff --git a/CHANGES b/CHANGES index 3bca3eed4a..401c08601b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +4420. [func] nslookup now looks for AAAA as well as A by default. + [RT #40420] + 4419. [bug] Don't cause undefined result if the label of an entry in catalog zone is changed. [RT #42708] diff --git a/bin/dig/nslookup.c b/bin/dig/nslookup.c index 6a9955edd8..f00ab4558e 100644 --- a/bin/dig/nslookup.c +++ b/bin/dig/nslookup.c @@ -46,7 +46,8 @@ static isc_boolean_t short_form = ISC_TRUE, comments = ISC_TRUE, section_question = ISC_TRUE, section_answer = ISC_TRUE, section_authority = ISC_TRUE, section_additional = ISC_TRUE, recurse = ISC_TRUE, - aaonly = ISC_FALSE, nofail = ISC_TRUE; + aaonly = ISC_FALSE, nofail = ISC_TRUE, + default_lookups = ISC_TRUE, a_noanswer = ISC_FALSE; static isc_boolean_t interactive; @@ -182,9 +183,9 @@ printsoa(dns_rdata_t *rdata) { } static void -printa(dns_rdata_t *rdata) { +printaddr(dns_rdata_t *rdata) { isc_result_t result; - char text[sizeof("255.255.255.255")]; + char text[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; isc_buffer_t b; isc_buffer_init(&b, text, sizeof(text)); @@ -193,6 +194,7 @@ printa(dns_rdata_t *rdata) { printf("Address: %.*s\n", (int)isc_buffer_usedlength(&b), (char *)isc_buffer_base(&b)); } + #ifdef DIG_SIGCHASE /* Just for compatibility : not use in host program */ isc_result_t @@ -264,12 +266,13 @@ printsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers, dns_rdataset_current(rdataset, &rdata); switch (rdata.type) { case dns_rdatatype_a: + case dns_rdatatype_aaaa: if (section != DNS_SECTION_ANSWER) goto def_short_section; dns_name_format(name, namebuf, sizeof(namebuf)); printf("Name:\t%s\n", namebuf); - printa(&rdata); + printaddr(&rdata); break; case dns_rdatatype_soa: dns_name_format(name, namebuf, @@ -400,6 +403,31 @@ trying(char *frm, dig_lookup_t *lookup) { } +static void +chase_cnamechain(dns_message_t *msg, dns_name_t *qname) { + isc_result_t result; + dns_rdataset_t *rdataset; + dns_rdata_cname_t cname; + dns_rdata_t rdata = DNS_RDATA_INIT; + unsigned int i = msg->counts[DNS_SECTION_ANSWER]; + + while (i-- > 0) { + rdataset = NULL; + result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname, + dns_rdatatype_cname, 0, NULL, &rdataset); + if (result != ISC_R_SUCCESS) + return; + result = dns_rdataset_first(rdataset); + check_result(result, "dns_rdataset_first"); + dns_rdata_reset(&rdata); + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &cname, NULL); + check_result(result, "dns_rdata_tostruct"); + dns_name_copy(&cname.cname, qname, NULL); + dns_rdata_freestruct(&cname); + } +} + isc_result_t printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { char servtext[ISC_SOCKADDR_FORMATSIZE]; @@ -409,11 +437,13 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { debug("printmessage()"); - isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext)); - printf("Server:\t\t%s\n", query->userarg); - printf("Address:\t%s\n", servtext); + if(!default_lookups || query->lookup->rdtype == dns_rdatatype_a) { + isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext)); + printf("Server:\t\t%s\n", query->userarg); + printf("Address:\t%s\n", servtext); - puts(""); + puts(""); + } if (!short_form) { puts("------------"); @@ -438,16 +468,50 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { return (ISC_R_SUCCESS); } - if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) + if ( default_lookups && query->lookup->rdtype == dns_rdatatype_a) { + char namestr[DNS_NAME_FORMATSIZE]; + dig_lookup_t *lookup; + dns_fixedname_t fixed; + dns_name_t *name; + + /* Add AAAA lookup. */ + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + dns_name_copy(query->lookup->name, name, NULL); + chase_cnamechain(msg, name); + dns_name_format(name, namestr, sizeof(namestr)); + lookup = clone_lookup(query->lookup, ISC_FALSE); + if (lookup != NULL) { + strncpy(lookup->textname, namestr, + sizeof(lookup->textname)); + lookup->textname[sizeof(lookup->textname)-1] = 0; + lookup->rdtype = dns_rdatatype_aaaa; + lookup->rdtypeset = ISC_TRUE; + lookup->origin = NULL; + lookup->retries = tries; + ISC_LIST_APPEND(lookup_list, lookup, link); + } + } + + if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0 && + ( !default_lookups || query->lookup->rdtype == dns_rdatatype_a) ) puts("Non-authoritative answer:"); if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) printsection(query, msg, headers, DNS_SECTION_ANSWER); - else - printf("*** Can't find %s: No answer\n", - query->lookup->textname); + else { + if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) + a_noanswer = ISC_TRUE; + + else if (!default_lookups || + (query->lookup->rdtype == dns_rdatatype_aaaa && + a_noanswer ) ) + printf("*** Can't find %s: No answer\n", + query->lookup->textname); + } if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) && - (query->lookup->rdtype != dns_rdatatype_a)) { + (query->lookup->rdtype != dns_rdatatype_a) && + (query->lookup->rdtype != dns_rdatatype_aaaa) ) { puts("\nAuthoritative answers can be found from:"); printsection(query, msg, headers, DNS_SECTION_AUTHORITY); @@ -585,23 +649,35 @@ setoption(char *opt) { if (testclass(&opt[3])) strlcpy(defclass, &opt[3], sizeof(defclass)); } else if (strncasecmp(opt, "type=", 5) == 0) { - if (testtype(&opt[5])) + if (testtype(&opt[5])) { strlcpy(deftype, &opt[5], sizeof(deftype)); + default_lookups = ISC_FALSE; + } } else if (strncasecmp(opt, "ty=", 3) == 0) { - if (testtype(&opt[3])) + if (testtype(&opt[3])) { strlcpy(deftype, &opt[3], sizeof(deftype)); + default_lookups = ISC_FALSE; + } } else if (strncasecmp(opt, "querytype=", 10) == 0) { - if (testtype(&opt[10])) + if (testtype(&opt[10])) { strlcpy(deftype, &opt[10], sizeof(deftype)); + default_lookups = ISC_FALSE; + } } else if (strncasecmp(opt, "query=", 6) == 0) { - if (testtype(&opt[6])) + if (testtype(&opt[6])) { strlcpy(deftype, &opt[6], sizeof(deftype)); + default_lookups = ISC_FALSE; + } } else if (strncasecmp(opt, "qu=", 3) == 0) { - if (testtype(&opt[3])) + if (testtype(&opt[3])) { strlcpy(deftype, &opt[3], sizeof(deftype)); + default_lookups = ISC_FALSE; + } } else if (strncasecmp(opt, "q=", 2) == 0) { - if (testtype(&opt[2])) + if (testtype(&opt[2])) { strlcpy(deftype, &opt[2], sizeof(deftype)); + default_lookups = ISC_FALSE; + } } else if (strncasecmp(opt, "domain=", 7) == 0) { strlcpy(domainopt, &opt[7], sizeof(domainopt)); set_search_domain(domainopt); @@ -671,6 +747,9 @@ addlookup(char *opt) { char store[MXNAME]; debug("addlookup()"); + + a_noanswer = ISC_FALSE; + tr.base = deftype; tr.length = strlen(deftype); result = dns_rdatatype_fromtext(&rdtype, &tr); diff --git a/bin/tests/system/nslookup/ns1/named.conf b/bin/tests/system/nslookup/ns1/named.conf index aa02c89a44..ddf4dabedc 100644 --- a/bin/tests/system/nslookup/ns1/named.conf +++ b/bin/tests/system/nslookup/ns1/named.conf @@ -23,3 +23,8 @@ zone "example" { type master; file "example.db"; }; + +zone "example.net" { + type master; + file "example.net.db"; +}; diff --git a/bin/tests/system/nslookup/tests.sh b/bin/tests/system/nslookup/tests.sh index 1b612ff357..f088dd8db2 100644 --- a/bin/tests/system/nslookup/tests.sh +++ b/bin/tests/system/nslookup/tests.sh @@ -23,5 +23,85 @@ grep "origin = ns1.example" nslookup.out${n} > /dev/null || ret=1 if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` +n=`expr $n + 1` +echo "Check A only lookup" +ret=0 +$NSLOOKUP -port=5300 a-only.example.net 10.53.0.1 > nslookup.out${n} || ret=1 +lines=`grep "Server:" nslookup.out${n} | wc -l` +test $lines = 1 || ret=1 +lines=`grep a-only.example.net nslookup.out${n} | wc -l` +test $lines = 1 || ret=1 +grep "1.2.3.4" nslookup.out${n} > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo "Check AAAA only lookup" +ret=0 +$NSLOOKUP -port=5300 aaaa-only.example.net 10.53.0.1 > nslookup.out${n} || ret=1 +lines=`grep "Server:" nslookup.out${n} | wc -l` +test $lines = 1 || ret=1 +lines=`grep aaaa-only.example.net nslookup.out${n} | wc -l` +test $lines = 1 || ret=1 +grep "2001::ffff" nslookup.out${n} > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo "Check dual A + AAAA lookup" +ret=0 +$NSLOOKUP -port=5300 dual.example.net 10.53.0.1 > nslookup.out${n} || ret=1 +lines=`grep "Server:" nslookup.out${n} | wc -l` +test $lines = 1 || ret=1 +lines=`grep dual.example.net nslookup.out${n} | wc -l` +test $lines = 2 || ret=1 +grep "1.2.3.4" nslookup.out${n} > /dev/null || ret=1 +grep "2001::ffff" nslookup.out${n} > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo "Check CNAME to A only lookup" +ret=0 +$NSLOOKUP -port=5300 cname-a-only.example.net 10.53.0.1 > nslookup.out${n} || ret=1 +lines=`grep "Server:" nslookup.out${n} | wc -l` +test $lines = 1 || ret=1 +lines=`grep "canonical name" nslookup.out${n} | wc -l` +test $lines = 1 || ret=1 +lines=`grep a-only.example.net nslookup.out${n} | grep -v "canonical name" | wc -l` +test $lines = 1 || ret=1 +grep "1.2.3.4" nslookup.out${n} > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo "Check CNAME to AAAA only lookup" +ret=0 +$NSLOOKUP -port=5300 cname-aaaa-only.example.net 10.53.0.1 > nslookup.out${n} || ret=1 +lines=`grep "Server:" nslookup.out${n} | wc -l` +test $lines = 1 || ret=1 +lines=`grep "canonical name" nslookup.out${n} | wc -l` +test $lines = 1 || ret=1 +lines=`grep aaaa-only.example.net nslookup.out${n} | grep -v "canonical name" |wc -l` +test $lines = 1 || ret=1 +grep "2001::ffff" nslookup.out${n} > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo "Check CNAME to dual A + AAAA lookup" +ret=0 +$NSLOOKUP -port=5300 cname-dual.example.net 10.53.0.1 > nslookup.out${n} || ret=1 +lines=`grep "Server:" nslookup.out${n} | wc -l` +test $lines = 1 || ret=1 +lines=`grep "canonical name" nslookup.out${n} | wc -l` +test $lines = 1 || ret=1 +lines=`grep dual.example.net nslookup.out${n} | grep -v "canonical name" | wc -l` +test $lines = 2 || ret=1 +grep "1.2.3.4" nslookup.out${n} > /dev/null || ret=1 +grep "2001::ffff" nslookup.out${n} > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + echo "I:exit status: $status" [ $status -eq 0 ] || exit 1