diff --git a/CHANGES b/CHANGES index a104487997..44203bfaa8 100644 --- a/CHANGES +++ b/CHANGES @@ -161,6 +161,9 @@ during operation. If the read failed, named could segfault. [RT #38559] +3951. [func] Add the ability to set yet-to-be-defined EDNS flags + to dig (+ednsflags=#). [RT #37142] + 3937. [func] Added some debug logging to better indicate the conditions causing SERVFAILs when resolving. [RT #35538] diff --git a/bin/dig/dig.c b/bin/dig/dig.c index e6bba27b24..75f6b8da6e 100644 --- a/bin/dig/dig.c +++ b/bin/dig/dig.c @@ -194,6 +194,7 @@ help(void) { " +ndots=### (Set NDOTS value)\n" " +subnet=addr (Set edns-client-subnet option)\n" " +[no]edns[=###] (Set EDNS version) [0]\n" +" +ednsflags=### (Set EDNS flag bits)\n" " +ednsopt=###[:value] (Send specified EDNS option)\n" " +noednsopt (Clear list of +ednsopt options)\n" " +[no]search (Set whether to use searchlist)\n" @@ -947,6 +948,25 @@ plus_option(char *option, isc_boolean_t is_batchfile, "edns"); lookup->edns = num; break; + case 'f': + FULLCHECK("ednsflags"); + if (!state) { + lookup->ednsflags = 0; + break; + } + if (value == NULL) { + lookup->ednsflags = 0; + break; + } + result = parse_xint(&num, + value, + 0xffff, + "ednsflags"); + if (result != ISC_R_SUCCESS) + fatal("Couldn't parse " + "ednsflags"); + lookup->ednsflags = num; + break; case 'o': FULLCHECK("ednsopt"); if (!state) { diff --git a/bin/dig/dig.docbook b/bin/dig/dig.docbook index 9e0e7879cc..db844161f8 100644 --- a/bin/dig/dig.docbook +++ b/bin/dig/dig.docbook @@ -646,6 +646,18 @@ + + + + + Set the must-be-zero EDNS flags bits (Z bits) to the + specified value. Decimal, hex and octal encodings are + accepted. Setting a named flag (e.g. DO) will silently be + ignored. By default, no Z bits are set. + + + + diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 27b01a84d8..f1a82c7228 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -788,6 +788,7 @@ make_empty_lookup(void) { looknew->servfail_stops = ISC_TRUE; looknew->besteffort = ISC_TRUE; looknew->dnssec = ISC_FALSE; + looknew->ednsflags = 0; looknew->opcode = dns_opcode_query; looknew->expire = ISC_FALSE; looknew->nsid = ISC_FALSE; @@ -882,6 +883,7 @@ clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) { looknew->servfail_stops = lookold->servfail_stops; looknew->besteffort = lookold->besteffort; looknew->dnssec = lookold->dnssec; + looknew->ednsflags = lookold->ednsflags; looknew->opcode = lookold->opcode; looknew->expire = lookold->expire; looknew->nsid = lookold->nsid; @@ -1020,11 +1022,11 @@ setup_text_key(void) { isc_buffer_free(&namebuf); } -isc_result_t -parse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max, - const char *desc) { +static isc_result_t +parse_uint_helper(isc_uint32_t *uip, const char *value, isc_uint32_t max, + const char *desc, int base) { isc_uint32_t n; - isc_result_t result = isc_parse_uint32(&n, value, 10); + isc_result_t result = isc_parse_uint32(&n, value, base); if (result == ISC_R_SUCCESS && n > max) result = ISC_R_RANGE; if (result != ISC_R_SUCCESS) { @@ -1036,6 +1038,18 @@ parse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max, return (ISC_R_SUCCESS); } +isc_result_t +parse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max, + const char *desc) { + return (parse_uint_helper(uip, value, max, desc, 10)); +} + +isc_result_t +parse_xint(isc_uint32_t *uip, const char *value, isc_uint32_t max, + const char *desc) { + return (parse_uint_helper(uip, value, max, desc, 0)); +} + static isc_uint32_t parse_bits(char *arg, const char *desc, isc_uint32_t max) { isc_result_t result; @@ -1544,15 +1558,12 @@ save_opt(dig_lookup_t *lookup, char *code, char *value) { */ static void add_opt(dns_message_t *msg, isc_uint16_t udpsize, isc_uint16_t edns, - isc_boolean_t dnssec, dns_ednsopt_t *opts, size_t count) + unsigned int flags, dns_ednsopt_t *opts, size_t count) { dns_rdataset_t *rdataset = NULL; isc_result_t result; - unsigned int flags = 0; debug("add_opt()"); - if (dnssec) - flags |= DNS_MESSAGEEXTFLAG_DO; result = dns_message_buildopt(msg, &rdataset, edns, udpsize, flags, opts, count); check_result(result, "dns_message_buildopt"); @@ -2442,6 +2453,7 @@ setup_lookup(dig_lookup_t *lookup) { lookup->edns > -1 || lookup->ecs_addr != NULL) { dns_ednsopt_t opts[EDNSOPTS + DNS_EDNSOPTIONS]; + unsigned int flags; int i = 0; if (lookup->udpsize == 0) @@ -2531,8 +2543,12 @@ setup_lookup(dig_lookup_t *lookup) { i += lookup->ednsoptscnt; } + flags = lookup->ednsflags; + flags &= ~DNS_MESSAGEEXTFLAG_DO; + if (lookup->dnssec) + flags |= DNS_MESSAGEEXTFLAG_DO; add_opt(lookup->sendmsg, lookup->udpsize, - lookup->edns, lookup->dnssec, opts, i); + lookup->edns, flags, opts, i); } result = dns_message_rendersection(lookup->sendmsg, diff --git a/bin/dig/include/dig/dig.h b/bin/dig/include/dig/dig.h index 237eb915b6..b0aa3210a2 100644 --- a/bin/dig/include/dig/dig.h +++ b/bin/dig/include/dig/dig.h @@ -193,6 +193,7 @@ isc_boolean_t sigchase; #endif dns_ednsopt_t *ednsopts; unsigned int ednsoptscnt; + unsigned int ednsflags; dns_opcode_t opcode; }; @@ -347,6 +348,10 @@ isc_result_t parse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max, const char *desc); +isc_result_t +parse_xint(isc_uint32_t *uip, const char *value, isc_uint32_t max, + const char *desc); + isc_result_t parse_netprefix(isc_sockaddr_t **sap, const char *value); diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in index 8ad4746e71..440c795f40 100644 --- a/bin/tests/system/conf.sh.in +++ b/bin/tests/system/conf.sh.in @@ -67,14 +67,15 @@ RANDFILE=$TOP/bin/tests/system/random.data SUBDIRS="acl additional allow_query addzone autosign builtin cacheclean case checkconf @CHECKDS@ checknames checkzone @COVERAGE@ database delv dlv dlvauto dlz dlzexternal - dlzredir dname dns64 dnssec dsdigest dscp ecdsa emptyzones - filter-aaaa formerr forward geoip glue gost ixfr inline - legacy limits logfileconfig lwresd masterfile masterformat - metadata notify nslookup nsupdate pending @PKCS11_TEST@ - reclimit redirect resolver rndc rpz rpzrecurse rrl rrchecker - rrsetorder rsabigexponent sit smartsign sortlist spf staticstub - statistics stub tkey tsig tsiggss unknown upforwd verify - views wildcard xfer xferquota zero zonechecks" + dlzredir dname dns64 dnssec dsdigest dscp ecdsa ednscompliance + emptyzones filter-aaaa formerr forward geoip glue gost + ixfr inline legacy limits logfileconfig lwresd masterfile + masterformat metadata notify nslookup nsupdate pending + @PKCS11_TEST@ reclimit redirect resolver rndc rpz rpzrecurse + rrl rrchecker rrsetorder rsabigexponent sit smartsign + sortlist spf staticstub statistics stub tkey tsig tsiggss + unknown upforwd verify views wildcard xfer xferquota zero + zonechecks" # Use the CONFIG_SHELL detected by configure for tests SHELL=@SHELL@ diff --git a/bin/tests/system/ednscompliance/clean.sh b/bin/tests/system/ednscompliance/clean.sh new file mode 100644 index 0000000000..3c5f50f025 --- /dev/null +++ b/bin/tests/system/ednscompliance/clean.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# +# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. + +rm -f dig.out* diff --git a/bin/tests/system/ednscompliance/ns1/named.conf b/bin/tests/system/ednscompliance/ns1/named.conf new file mode 100644 index 0000000000..869e95e3f4 --- /dev/null +++ b/bin/tests/system/ednscompliance/ns1/named.conf @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +controls { /* empty */ }; + +options { + query-source address 10.53.0.1; + notify-source 10.53.0.1; + transfer-source 10.53.0.1; + port 5300; + pid-file "named.pid"; + listen-on { 10.53.0.1; }; + listen-on-v6 { none; }; + recursion no; +}; + +zone "." { + type master; + file "root.db"; +}; + diff --git a/bin/tests/system/ednscompliance/ns1/root.db b/bin/tests/system/ednscompliance/ns1/root.db new file mode 100644 index 0000000000..a44acf16ec --- /dev/null +++ b/bin/tests/system/ednscompliance/ns1/root.db @@ -0,0 +1,24 @@ +; Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") +; +; Permission to use, copy, modify, and/or distribute this software for any +; purpose with or without fee is hereby granted, provided that the above +; copyright notice and this permission notice appear in all copies. +; +; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +; PERFORMANCE OF THIS SOFTWARE. + +$TTL 300 +. IN SOA marka.isc.org. a.root.servers.nil. ( + 2010 ; serial + 600 ; refresh + 600 ; retry + 1200 ; expire + 600 ; minimum + ) +. NS a.root-servers.nil. +a.root-servers.nil. A 10.53.0.6 diff --git a/bin/tests/system/ednscompliance/tests.sh b/bin/tests/system/ednscompliance/tests.sh new file mode 100644 index 0000000000..ab958de00c --- /dev/null +++ b/bin/tests/system/ednscompliance/tests.sh @@ -0,0 +1,104 @@ +#!/bin/sh +# +# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. + +SYSTEMTESTTOP=.. +. $SYSTEMTESTTOP/conf.sh + +status=0 +n=0 +zone=. + +n=`expr $n + 1` +echo "I:check +edns=100 sets version 100 ($n)" +ret=0 reason= +$DIG -p 5300 @10.53.0.1 +qr +norec +edns=100 soa $zone > dig.out$n +grep "EDNS: version: 100," dig.out$n > /dev/null || { ret=1; reason="version"; } +if [ $ret != 0 ]; then echo "I:failed $reason"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +ret=0 reason= +echo "I:check +ednsopt=100 adds option 100 ($n)" +$DIG -p 5300 @10.53.0.1 +qr +norec +ednsopt=100 soa $zone > dig.out$n +grep "; OPT=100" dig.out$n > /dev/null || { ret=1; reason="option"; } +if [ $ret != 0 ]; then echo "I:failed $reason"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo "I:check +ednsflags=0x80 sets flags to 0080 ($n)" +ret=0 reason= +$DIG -p 5300 @10.53.0.1 +qr +norec +ednsflags=0x80 soa $zone > dig.out$n +grep "MBZ: 0080" dig.out$n > /dev/null || { ret=1; reason="flags"; } +if [ $ret != 0 ]; then echo "I:failed $reason"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo "I:Unknown EDNS version ($n)" +ret=0 reason= +$DIG -p 5300 @10.53.0.1 +norec +edns=100 soa $zone > dig.out$n +grep "status: BADVERS," dig.out$n > /dev/null || { ret=1; reason="status"; } +grep "EDNS: version: 0," dig.out$n > /dev/null || { ret=1; reason="version"; } +grep "IN.SOA." dig.out$n > /dev/null && { ret=1; reaons="soa"; } +if [ $ret != 0 ]; then echo "I:failed $reason"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo "I:Unknown EDNS option ($n)" +ret=0 reason= +$DIG -p 5300 @10.53.0.1 +norec +ednsopt=100 soa $zone > dig.out$n +grep "status: NOERROR," dig.out$n > /dev/null || { ret=1; reason="status"; } +grep "EDNS: version: 0," dig.out$n > /dev/null || { ret=1; reason="version"; } +grep "; OPT=100" dig.out$n > /dev/null && { ret=1; reason="option"; } +grep "IN.SOA." dig.out$n > /dev/null || { ret=1; reason="nosoa"; } +if [ $ret != 0 ]; then echo "I:failed $reason"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo "I:Unknown EDNS version + option ($n)" +ret=0 reason= +$DIG -p 5300 @10.53.0.1 +norec +edns=100 +ednsopt=100 soa $zone > dig.out$n +grep "status: BADVERS," dig.out$n > /dev/null || { ret=1; reason="status"; } +grep "EDNS: version: 0," dig.out$n > /dev/null || { ret=1; reason="version"; } +grep "; OPT=100" dig.out$n > /dev/null && { ret=1; reason="option"; } +grep "IN.SOA." dig.out$n > /dev/null && { ret=1; reason="soa"; } +if [ $ret != 0 ]; then echo "I:failed: $reason"; fi +status=`expr $status + $ret` +n=`expr $n + 1` + +echo "I:Unknown EDNS flag ($n)" +ret=0 reason= +$DIG -p 5300 @10.53.0.1 +norec +ednsflags=0x80 soa $zone > dig.out$n +grep "status: NOERROR," dig.out$n > /dev/null || { ret=1; reason="status"; } +grep "EDNS: version: 0," dig.out$n > /dev/null || { ret=1; reason="version"; } +grep "EDNS:.*MBZ" dig.out$n > /dev/null > /dev/null && { ret=1; reason="mbz"; } +grep ".IN.SOA." dig.out$n > /dev/null || { ret=1; reason="nosoa"; } +if [ $ret != 0 ]; then echo "I:failed $reason"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo "I:Unknown EDNS version + flag ($n)" +ret=0 reason= +$DIG -p 5300 @10.53.0.1 +norec +edns=100 +ednsflags=0x80 soa $zone > dig.out$n +grep "status: BADVERS," dig.out$n > /dev/null || { ret=1; reason="status"; } +grep "EDNS: version: 0," dig.out$n > /dev/null || { ret=1; reason="version"; } +grep "EDNS:.*MBZ" dig.out$n > /dev/null > /dev/null && { ret=1; reason="mbz"; } +grep "IN.SOA." dig.out$n > /dev/null && { ret=1; reason="soa"; } +if [ $ret != 0 ]; then echo "I:failed $reason"; fi +status=`expr $status + $ret` +n=`expr $n + 1` + +echo "I:exit status: $status" +exit $status