Maintained by: NLnet Labs

message is bogus, non secure rrset with Unbound as local caching resolver

Olav Morken
Wed Mar 2 12:39:30 CET 2016


Hi,

sorry for the rather longwinded email. In the interest of saving some 
time, here is a short summary:

We get the error "message is bogus, non secure rrset" from Unbound in 
some cases when resolving a wildcard CNAME record. The cause appears to 
be an upstream BIND resolver that in some cases returns an authority 
section containing NS-records but no RRSIG-record for those records.

A longer version of the questions are at the end, but in short:

* Is this a bug in Unbound (it should handle those types of responses) 
  or in BIND (it should not generate those kind of responses).
* Could (and should?) Unbound be extended to deal with this type of 
  responses (no matter whether they are legal or not)?


Now the longwinded version:

We have an Unbound server running as a local caching resolver on a 
server. This instance is configured to forward requests to two 
resolvers, one running Unbound and one running BIND.

Both Unbound servers are running 1.4.22 from Debian Jessie. The BIND 
server is running version 9.9.8P2.

This error occurs frequently when doing lookups for a domain 
"pingapi.paas.uninett.no". This is handled by a wildcard CNAME 
pointing at "paas-lb.uninett.no". Since this is a wildcard CNAME, is 
must be authenticated with a NSEC3-record in the authority section.

As far as we can tell, the problem occurs because the BIND server is 
occasionally returning responses with NS-records in the 
authority-section that does not include the RRSIG records. 


There are actually two errors from Unbound due to this:

The first is when doing a request for the "pingapi.paas.uninett.no". 
In that case, the response from the resolver running BIND looks 
something like this:

  ;; ANSWER SECTION:
  pingapi.paas.uninett.no. 85 IN CNAME paas-lb.uninett.no.
  pingapi.paas.uninett.no. 85 IN RRSIG CNAME [...]
  paas-lb.uninett.no. 158 IN A 158.38.213.52
  paas-lb.uninett.no. 158 IN RRSIG A [...]
  
  ;; AUTHORITY SECTION:
  st5rjlutdrm3le5lla3r11bu3qu2qk06.uninett.no. 85 IN NSEC3 [...]
  st5rjlutdrm3le5lla3r11bu3qu2qk06.uninett.no. 85 IN RRSIG NSEC3 [...]
  uninett.no. 3408 IN NS server.nordu.net.
  uninett.no. 3408 IN NS benoni.uit.no.
  uninett.no. 3408 IN NS nac.no.
  uninett.no. 3408 IN NS ns.uninett.no.
  uninett.no. 3408 IN NS nn.uninett.no.

Note that the signature for the NSEC3-record is present, but no 
signature for the NS-records. At that point, Unbound rejects the 
response, and tries a different server:

  info: validator operate: query pingapi.paas.uninett.no. A IN
  debug: CNAME response was wildcard expansion and did not prove original data did not exist
  info: validate(cname): sec_status_bogus
  debug: iterator[module 1] operate: extstate:module_finished event:module_event_pass
  info: resolving pingapi.paas.uninett.no. A IN

Once the query hits the resolver running Unbound, it succeeds, and the 
local resolver moves on to resolving the "paas-lb.uninett.no" domain. 
At that point, it may query the resolver running BIND, and will get a 
response looking like:

  ;; ANSWER SECTION:
  paas-lb.uninett.no.	299	IN	A	158.38.213.52
  paas-lb.uninett.no.	299	IN	RRSIG	A [...]
  
  ;; AUTHORITY SECTION:
  uninett.no.		1118	IN	NS	ns.uninett.no.
  uninett.no.		1118	IN	NS	server.nordu.net.
  uninett.no.		1118	IN	NS	nac.no.
  uninett.no.		1118	IN	NS	nn.uninett.no.
  uninett.no.		1118	IN	NS	benoni.uit.no.

Now I am a bit unclear about what happens, but as far as I can tell, 
Unbound sort-of accepts this response, since the authority-section 
isn't necessary to validate the answer. However, it then fails with 
the error from the subject line:

  [...]
  info: reply from <.> 158.38.212.107#53
  info: query response was CNAME
  info: resolving pingapi.paas.uninett.no. A IN
  info: processQueryTargets: pingapi.paas.uninett.no. A IN
  info: sending query: paas-lb.uninett.no. A IN
  debug: sending to target: <.> 2001:700:0:ff00::1#53
  debug: cache memory msg=89289 rrset=121419 infra=3788 val=77277
  debug: iterator[module 1] operate: extstate:module_wait_reply event:module_event_reply
  info: iterator operate: query pingapi.paas.uninett.no. A IN
  info: iterator operate: chased to paas-lb.uninett.no. A IN
  info: response for pingapi.paas.uninett.no. A IN
  info: reply from <.> 2001:700:0:ff00::1#53
  info: query response was ANSWER
  info: finishing processing for pingapi.paas.uninett.no. A IN
  debug: validator[module 0] operate: extstate:module_restart_next event:module_event_moddone
  info: validator operate: query pingapi.paas.uninett.no. A IN
  info: validator operate: chased to . TYPE0 CLASS0
  info: validate(cname): sec_status_secure
  info: validate(positive): sec_status_secure
  info: message is bogus, non secure rrset uninett.no. NS IN

My guess is that it somehow tries to combine the response it got from 
the server running BIND, which contains an authority-section with NS 
records but no RRSIG, and the response it got from Unbound, containing 
the NSEC3-record and its RRSIG record.

At that point, Unbound has a response containing three items in its 
authority-section:

* The NSEC3-record for the wildcard CNAME
* The RRSIG-record for the NSEC3-record
* The NS-records, without any RRSIG-record

I see that Unbound has some code for dealing with the case where the 
authority-section contains NS-records without RRSIG records, but that 
code does handle this case.


The questions I have are:

* Is this a bug in BIND or in Unbound, or something else? I am not 
  clear on what recursive resolvers supposed to do with RRSIG-records 
  in the authority section. The DNSSEC specification is very clear on 
  what authorative servers should do (i.e. always include them; if not 
  possible to include them also drop the record they sign). I have 
  however not been able to determine what the behavior should be when 
  the server is a recursive resolver.

* Could the code in Unbound be extended to deal with this case as well? 
  As mentioned, I see that code was added to deal with the case where 
  there are only unsigned NS-records in the authority-section. Could 
  that code be made generic, so that it will always strip unsigned 
  NS-records, even when there are other records present?

Best regards,
Olav Morken
UNINETT