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