No RRSIG for xxxx.is-cf.help.every1dns.net

When I visit https://1.1.1.1/help with DNSSEC enabled on my resolver, it says I’m not using 1.1.1.1. It works perfectly on any website, and I’m clearly using 1.1.1.1, however my resolver notes that there’s no RRSIG for the CNAME at xxxx.is-cf.help.every1dns.net.

Since help.every1dns.net is signed it denies the request as BOGUS. Is this as designed, or is it a bug in the implementation?

I had a search around and I can’t see anyone else querying this. Of course it’s not a big issue, but it still seems like an oversight.

Thanks.

Can you post your debug URL of 1.1.1.1/help?

1 Like

https://1.1.1.1/help#eyJpc0NmIjoiTm8iLCJpc0RvdCI6Ik5vIiwiaXNEb2giOiJObyIsInJlc29sdmVySXAtMS4xLjEuMSI6IlllcyIsInJlc29sdmVySXAtMS4wLjAuMSI6IlllcyIsInJlc29sdmVySXAtMjYwNjo0NzAwOjQ3MDA6OjExMTEiOiJZZXMiLCJyZXNvbHZlcklwLTI2MDY6NDcwMDo0NzAwOjoxMDAxIjoiWWVzIiwiZGF0YWNlbnRlckxvY2F0aW9uIjoiTEhSIiwiaXNXYXJwIjoiTm8iLCJpc3BOYW1lIjoiQ2xvdWRmbGFyZSIsImlzcEFzbiI6IjEzMzM1In0=

Hi! every1dns.net is a signed zone, but help.every1dns.net isn’t, so there’s no RRSIG for the CNAME inside.

Does that mean there’s a bug in the DNSSEC implementation in dnsmasq? I’m not sure how it can determine an unsigned subdomain?

Is there a correct implementation of NSEC on this domain?

Hmmm. Using this tool:

It appears that the NSEC record for help.every1dns.net is returned by 8.8.8.8 and 9.9.9.9 but not 1.1.1.1. perhaps the issue is actually with the Cloudflare DNS itself?

What NSEC record are you looking for? These are the nameservers for the parent zone:

% kdig NS every1dns.net +dnssec
...
every1dns.net.      	86400	IN	NS	amir.ns.cloudflare.com.
every1dns.net.      	86400	IN	NS	rosa.ns.cloudflare.com.
every1dns.net.      	86400	IN	RRSIG	NS 13 2 86400 20220413181203 20220411161203 34505 every1dns.net. AAhHH40GOyE/LG1MuoN4TsNBS3dHk1UmUV6/EDmmFOD1W5zj2rATTT3qMgmVUByhzaysXZSjzP6V5AtOt0srCQ==

You can query them for a DS record to confirm that it doesn’t exist:

% kdig @amir.ns.cloudflare.com. help.every1dns.net DS +dnssec
...
every1dns.net.      	3600	IN	SOA	amir.ns.cloudflare.com. dns.cloudflare.com. 2274099322 10000 2400 604800 3600
help.every1dns.net. 	3600	IN	NSEC	help\000.every1dns.net. NS RRSIG NSEC
help.every1dns.net. 	3600	IN	RRSIG	NSEC 13 3 3600 20220413181246 20220411161246 34505 every1dns.net. 4EqR55iKEydISi0B5c89BuvlLBKqNZFhAwRcXMPn9NU67djx2HHT/2gpv4gEJ5Ou0l/mfflkTE7O3qDq3DuOPw==
every1dns.net.      	3600	IN	RRSIG	SOA 13 2 3600 20220413181246 20220411161246 34505 every1dns.net. uIO9VXckHbcRcTLryuJ5ZTzz4U0elgqOLk34+PeW/b8fEXgYIRIfas6mTfSwBKAH1O3WAArMqsqNQ5auvqnRgg==

The NSEC record here tells you that the name exists in the zone, but only has types NS RRSIG and NSEC, not DS.

When a delegation doesn’t have a signature, the zone underneath is not signed.

Here’s the summary:

bf15d04f-a509-4104-88eb-fbafadaa7459.is-dot.help.every1dns.net fails due to no RRSIG

bf15d04f-a509-4104-88eb-fbafadaa7459.is-cf.help.every1dns.net fails due to no 15d04f-a509-4104-88eb-fbafadaa7459.map.help.every1dns.net resolves as a CNAME but INSECURE

bf15d04f-a509-4104-88eb-fbafadaa7459.is-doh.help.every1dns.net resolves as NXDOMAIN INSECURE

This is all with dnsmasq through a DNS-over-TLS proxy, hence expecting the is-dot one to resolve and the NXDOMAIN for the is-doh is expected.

Not sure why the map.help is fine, but the is-dot.help is not??

I wonder if the answer lies in this comment from the dnsmasq source:

1799           F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
1800           but that's because there's no NS record either, ie this isn't the start
1801           of a zone. We only prove that the DNS tree below a node is unsigned when
1802           we prove that we're at a zone cut AND there's no DS record. ```

More investigation required I think...

It seems to me that dnsmasq doesn’t find the correct authority for these records, and thinks it’s every1dns.net. This is generally tricky for recursives/revalidators.

Ah ha! I’ve found the problem. Turns out that dnsmasq has a logic issue in that when it tries to validate the is-cf.help.every1dns.net it tries to look up the DS for help.every1dns.net and correctly identifies it as being its own zone. However it then does the CNAME lookup for target.every1dns.net and gets confused and tries to look up its DS record, even though it’s already been returned its RRSIG.

I’m not entirely sure of the solution yet, but it seems that all the Cloudflare services are doing their thing just right.

For those interested, here’s the fix for dnsmasq:

diff --git a/src/dnssec.c b/src/dnssec.c
index 9965eea..8339a56 100644
--- a/src/dnssec.c
+++ b/src/dnssec.c
@@ -2001,8 +2001,15 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
 		  if (check_unsigned && i < ntohs(header->ancount))
 		    {
 		      rc = zone_status(name, class1, keyname, now);
-		      if (STAT_ISEQUAL(rc, STAT_SECURE))
-			rc = STAT_BOGUS | DNSSEC_FAIL_NOSIG;
+		      if (STAT_ISEQUAL(rc, STAT_INSECURE))
+		      {
+		        /* This is BOGUS, unless it's a CNAME because that can be in
+		           another zone and is validated separately */
+		        if (type1 == T_CNAME)
+		          rc = STAT_INSECURE;
+		        else
+		          rc = STAT_BOGUS | DNSSEC_FAIL_NOSIG;
+		      }
 		      
 		      if (class)
 			*class = class1; /* Class for NEED_DS or NEED_KEY */
1 Like

Turns out my previous patch was actually incorrect. Having re-visited the problem this evening and re-validated my assumptions, what was actually happening was the SECURE target.every1dns.net response was making it think that the INSECURE help.every1dns.net was actually spoofing. I’ve modified my previous patch to detect and allow this case.

diff --git a/src/dnssec.c b/src/dnssec.c
index 9965eea..ceb6250 100644
--- a/src/dnssec.c
+++ b/src/dnssec.c
@@ -2004,6 +2004,9 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
 		      if (STAT_ISEQUAL(rc, STAT_SECURE))
 			rc = STAT_BOGUS | DNSSEC_FAIL_NOSIG;
 		      
+		      if (STAT_ISEQUAL(rc, STAT_INSECURE) && type1 == T_CNAME)
+		        check_unsigned = 0;
+
 		      if (class)
 			*class = class1; /* Class for NEED_DS or NEED_KEY */
 		    }
1 Like

So it turns out my initial assessment of this problem was incorrect…

The issue is actually that the Cloudflare DNS server replies to the query for xxx.is-cf.every1dns.net with the following response:

xxx.is-cf.help.every1dns.net. 0 IN CNAME target.every1dns.net.
target.every1dns.net. 300 IN A 104.17.198.37
target.every1dns.net. 300 IN A 104.17.199.37

Note that there are no RRSIG responses in the above. However, if you query for target.every1dns.net then the following is returned:

|target.every1dns.net.|300|IN|A|104.17.198.37|
|target.every1dns.net.|300|IN|A|104.17.199.37|
|target.every1dns.net.|300|IN|RRSIG|A 13 3 300 20220422230710 20220420210710 34505 every1dns.net. 8+U9GXJEj2e65zKcf/oO2PiX98Jxn/c76zHd4qFZWug00gYJ8aqTNJb0 Ctl7ebVOQ6X4EfW3x9lPCfLbDJTB4w==|

Note the addition of the RRSIG in the response. This is what is causing the issues.

2 Likes

Thanks! Let me try to figure out what’s wrong with that.

1 Like

There should be an RRSIG on the A records now, looks like the DO bit wasn’t set on some of these generated test records.

Yup, working now! Thanks.

1 Like

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.