diff --git a/CHANGES b/CHANGES index 0b5a2de328..83680886ff 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +3993. [func] Dig now supports EDNS negotiation by default. + (dig +[no]ednsnegotiation). [RT #37604] + 3992. [func] DiG can now send queries without questions (dig +header-only). [RT #37599] diff --git a/bin/dig/dig.c b/bin/dig/dig.c index 2a00b058d8..725c5203dd 100644 --- a/bin/dig/dig.c +++ b/bin/dig/dig.c @@ -195,6 +195,7 @@ help(void) { " +ednsflags=### (Set EDNS flag bits)\n" " +ednsopt=###[:value] (Send specified EDNS option)\n" " +noednsopt (Clear list of +ednsopt options)\n" +" +[no]ednsnegotiation (Set EDNS version negotiation)\n" " +[no]search (Set whether to use searchlist)\n" " +[no]showsearch (Search with intermediate results)\n" " +[no]defname (Ditto)\n" @@ -981,6 +982,10 @@ plus_option(char *option, isc_boolean_t is_batchfile, "ednsflags"); lookup->ednsflags = num; break; + case 'n': + FULLCHECK("ednsnegotiation"); + lookup->ednsneg = state; + break; case 'o': FULLCHECK("ednsopt"); if (!state) { diff --git a/bin/dig/dig.docbook b/bin/dig/dig.docbook index 24fba64ee2..5a376be820 100644 --- a/bin/dig/dig.docbook +++ b/bin/dig/dig.docbook @@ -590,6 +590,16 @@ + + + + + Enable / disable EDNS version negotiation. By default + EDNS version negotiation is enabled. + + + + diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 7d418804fd..a171358f93 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -832,6 +832,7 @@ make_empty_lookup(void) { #endif looknew->ednsopts = NULL; looknew->ednsoptscnt = 0; + looknew->ednsneg = ISC_TRUE; looknew->dscp = -1; dns_fixedname_init(&looknew->fdomain); ISC_LINK_INIT(looknew, link); @@ -889,6 +890,7 @@ clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) { #endif looknew->ednsopts = lookold->ednsopts; looknew->ednsoptscnt = lookold->ednsoptscnt; + looknew->ednsneg = lookold->ednsneg; #ifdef DIG_SIGCHASE looknew->sigchase = lookold->sigchase; #if DIG_SIGCHASE_TD @@ -3468,6 +3470,10 @@ process_opt(dig_lookup_t *l, dns_message_t *msg) { } #endif +static int +ednsvers(dns_rdataset_t *opt) { + return ((opt->ttl >> 16) & 0xff); +} /*% * Event handler for recv complete. Perform whatever actions are necessary, @@ -3497,6 +3503,7 @@ recv_done(isc_task_t *task, isc_event_t *event) { isc_region_t r; isc_buffer_t *buf = NULL; #endif + int newedns; UNUSED(task); INSIST(!free_now); @@ -3728,6 +3735,25 @@ recv_done(isc_task_t *task, isc_event_t *event) { goto udp_mismatch; } } + if (msg->rcode == dns_rcode_badvers && msg->opt != NULL && + (newedns = ednsvers(msg->opt)) < l->edns && l->ednsneg) { + /* + * Add minimum EDNS version required checks here if needed. + */ + if (l->comments) + printf(";; BADVERS, retrying with EDNS version %u.\n", + newedns); + l->edns = newedns; + n = requeue_lookup(l, ISC_TRUE); + n->origin = query->lookup->origin; + dns_message_destroy(&msg); + isc_event_free(&event); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0 && !l->ignore && !l->tcp_mode) { if (l->comments) diff --git a/bin/dig/include/dig/dig.h b/bin/dig/include/dig/dig.h index 435e8d539c..7c23c74fb9 100644 --- a/bin/dig/include/dig/dig.h +++ b/bin/dig/include/dig/dig.h @@ -136,7 +136,8 @@ struct dig_lookup { sit, #endif nsid, /*% Name Server ID (RFC 5001) */ - header_only; + header_only, + ednsneg; #ifdef DIG_SIGCHASE isc_boolean_t sigchase; #if DIG_SIGCHASE_TD diff --git a/bin/tests/system/ednscompliance/tests.sh b/bin/tests/system/ednscompliance/tests.sh index ab958de00c..310f8211f6 100644 --- a/bin/tests/system/ednscompliance/tests.sh +++ b/bin/tests/system/ednscompliance/tests.sh @@ -48,7 +48,7 @@ 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 +$DIG -p 5300 @10.53.0.1 +norec +edns=100 +noednsneg 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"; } @@ -69,7 +69,7 @@ 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 +$DIG -p 5300 @10.53.0.1 +norec +edns=100 +noednsneg +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"; } @@ -91,7 +91,7 @@ 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 +$DIG -p 5300 @10.53.0.1 +norec +edns=100 +noednsneg +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"; } @@ -100,5 +100,15 @@ if [ $ret != 0 ]; then echo "I:failed $reason"; fi status=`expr $status + $ret` n=`expr $n + 1` +echo "I:DiG's EDNS negotiation ($n)" +ret=0 reason= +$DIG -p 5300 @10.53.0.1 +norec +edns=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 "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 diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index 52480d4e04..c88756e2f7 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -127,6 +127,12 @@ yet-to-be-defined EDNS flags in DNS requests. + + + dig +[no]ednsnegotiation can now be used enable / + disable EDNS version negotiation. + + dig +header-only can now be used to send