Bug 1416 - qname-minimisation breaks TLSA lookups with CNAMEs
qname-minimisation breaks TLSA lookups with CNAMEs
Status: RESOLVED FIXED
Product: unbound
Classification: Unclassified
Component: server
1.6.4
x86_64 Linux
: P5 normal
Assigned To: unbound team
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2017-08-29 16:38 CEST by Simon Deziel
Modified: 2017-08-30 15:27 CEST (History)
2 users (show)

See Also:


Attachments
verbose log from failed lookup (43.67 KB, application/gzip)
2017-08-30 14:36 CEST, Simon Deziel
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Simon Deziel 2017-08-29 16:38:18 CEST
When using Unbound 1.6.4 with qname-minimisation, TLSA lookups get a SERVFAIL when there is a CNAME to follow (that isn't in the cache already). Here's the TLSA record in question (Google has no problem resolving):

$ dig +short -t tlsa _25._tcp.mx.xelerance.com @8.8.8.8
3.1.1.mx.xelerance.com.
3 1 1 53724982ADD8534750B336E38A7128E122E8EC95EE67F676C7092AD8 38EDC94D


If I try to do the "normal" lookup first, I get a SERVFAIL:

$ dig -t tlsa _25._tcp.mx.xelerance.com @::1

; <<>> DiG 9.10.3-P4-Ubuntu <<>> -t tlsa _25._tcp.mx.xelerance.com @::1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 20209
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;_25._tcp.mx.xelerance.com.	IN	TLSA

;; Query time: 1666 msec
;; SERVER: ::1#53(::1)
;; WHEN: Tue Aug 29 10:29:08 EDT 2017
;; MSG SIZE  rcvd: 54


At this point, I restarted unbound to start fresh and looked up the CNAME first:

$ dig +short -t tlsa 3.1.1.mx.xelerance.com @::1
3 1 1 53724982ADD8534750B336E38A7128E122E8EC95EE67F676C7092AD8 38EDC94D

Then the "normal" lookup works:

$ dig -t tlsa _25._tcp.mx.xelerance.com @::1

; <<>> DiG 9.10.3-P4-Ubuntu <<>> -t tlsa _25._tcp.mx.xelerance.com @::1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62273
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;_25._tcp.mx.xelerance.com.	IN	TLSA

;; ANSWER SECTION:
_25._tcp.mx.xelerance.com. 28652 IN	CNAME	3.1.1.mx.xelerance.com.
3.1.1.mx.xelerance.com.	28652	IN	TLSA	3 1 1 53724982ADD8534750B336E38A7128E122E8EC95EE67F676C7092AD8 38EDC94D

;; Query time: 0 msec
;; SERVER: ::1#53(::1)
;; WHEN: Tue Aug 29 10:31:50 EDT 2017
;; MSG SIZE  rcvd: 121

Disabling qname-minimisation sidesteps the issue but I'd rather have this feature enabled :)
Comment 1 Wouter Wijngaards 2017-08-30 09:09:00 CEST
Hi Simon,

I cannot reproduce this.  I get this:
Host 25._tcp.mx.xelerance.com not found: 3(NXDOMAIN). (secure)

From using unbound-host with dnssec key and looking up -t TLSA for 25._tcp.mx.xelerance.com.

Can you, on a fresh start, set verbosity 5 and upload the attachment of the logs that it creates for you?

Best regards, Wouter
Comment 2 Simon Deziel 2017-08-30 14:35:26 CEST
Hi Wouter,

It seems the leading "_" of the query name was omitted in your test. Anyways, here's my "verbosity: 5" log.

Thanks!
Comment 3 Simon Deziel 2017-08-30 14:36:44 CEST
Created attachment 449 [details]
verbose log from failed lookup
Comment 4 Wouter Wijngaards 2017-08-30 15:15:12 CEST
Hi Simon,

Thank you for the report!  Fixed the minimal truncation for unsigned rrset in the authority section code, it needed to also act in this case.  The code is committed for future release.

Best regards, Wouter

Index: validator/val_utils.c
===================================================================
--- validator/val_utils.c	(revision 4315)
+++ validator/val_utils.c	(working copy)
@@ -932,17 +932,24 @@
 			 * Therefore the message is bogus.
 			 */
 
-			/* check if authority consists of only an NS record
+			/* check if authority has an NS record
 			 * which is bad, and there is an answer section with
 			 * data.  In that case, delete NS and additional to 
 			 * be lenient and make a minimal response */
-			if(rep->an_numrrsets != 0 && rep->ns_numrrsets == 1 &&
+			if(rep->an_numrrsets != 0 &&
 				ntohs(rep->rrsets[i]->rk.type) 
 				== LDNS_RR_TYPE_NS) {
 				verbose(VERB_ALGO, "truncate to minimal");
-				rep->ns_numrrsets = 0;
 				rep->ar_numrrsets = 0;
-				rep->rrset_count = rep->an_numrrsets;
+				rep->rrset_count = rep->an_numrrsets +
+					rep->ns_numrrsets;
+				/* remove this unneeded authority rrset */
+				memmove(rep->rrsets+i, rep->rrsets+i+1, 
+					sizeof(struct ub_packed_rrset_key*)*
+					(rep->rrset_count - i - 1));
+				rep->ns_numrrsets--;
+				rep->rrset_count--;
+				i--;
 				return;
 			}
Comment 5 Simon Deziel 2017-08-30 15:27:12 CEST
Many thanks Wouter!