Bug 4103 - Unbound appears to be picky about auth-zone: zon-file format
Unbound appears to be picky about auth-zone: zon-file format
Status: RESOLVED FIXED
Product: unbound
Classification: Unclassified
Component: server
1.7.2
All All
: P5 enhancement
Assigned To: unbound team
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2018-06-14 05:17 CEST by Eric Luehrsen
Modified: 2018-06-18 17:53 CEST (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Eric Luehrsen 2018-06-14 05:17:36 CEST
Testing the auth-zone: clause finds a nice example using ICANN root zone-files. However, https://www.internic.net/domains/in-addr.arpa.zone has a slight glitch. It appears the SOA end markers meet in the middle. It is as if it was wrapped on itself. Unbound rejects this zone-file because the first RR is not SOA. zone-files are really flat data and all the data seems to be there. 

A robustness opportunity exists in auth-zone: when Unbound downloads from an URL source. It could be more forgiving of trivial blemishes. If AXFR "master:" options are given, then it may be faster to just use them. If "url:" is the only option, then maybe parse and fix it pass may be in order. If "fallback-back: no" and "url:" are the only option, then a fix it pass could save the day. 

This later option could be a secure deployment method for a large organization. AXFR is disabled, period. Internal zones are served "auth-zone:"  by "url:" only and "fall-back:" recursion is forbidden. Unbound (intranet) forwards all global queries to another Unbound (internet) sitting in a DMZ. A minor format mistake like "in-addr.arpa.zone" applied to "it-ops.example.com.zone" could cause a lot of grief. Because the old zone-file (now damaged) might be needed to boot strap the "auth-zone:" search for the "url:", it might be a long day for IT.

Error:

Wed Jun 13 22:19:20 2018 daemon.err unbound: [3924:0] error: parse failure: first record in downloaded zonefile not of type SOA
Wed Jun 13 22:19:20 2018 daemon.err unbound: [3924:0] error: http download www.internic.net/domain/in-addr.arpa.zone does not contain a zonefile, but got 'in-addr.arpa. 3600 IN DNSKEY 256 3 8 ...key.hash...'

CONF:

auth-zone:
  name: "."
  master: "lax.xfr.dns.icann.org"
  master: "iad.xfr.dns.icann.org"
  url: "http://www.internic.net/domain/root.zone"
  fallback-enabled: yes
  for-downstream: no
  for-upstream: yes
  zonefile: "root.zone"

auth-zone:
  name: "arpa"
  master: "lax.xfr.dns.icann.org"
  master: "iad.xfr.dns.icann.org"
  url: "http://www.internic.net/domain/arpa.zone"
  fallback-enabled: yes
  for-downstream: no
  for-upstream: yes
  zonefile: "arpa.zone"

auth-zone:
  name: "in-addr.arpa"
  master: "lax.xfr.dns.icann.org"
  master: "iad.xfr.dns.icann.org"
  url: "http://www.internic.net/domain/in-addr.arpa.zone"
  fallback-enabled: yes
  for-downstream: no
  for-upstream: yes
  zonefile: "in-addr.arpa.zone"

auth-zone:
  name: "ip6.arpa"
  master: "lax.xfr.dns.icann.org"
  master: "iad.xfr.dns.icann.org"
  url: "http://www.internic.net/domain/ip6.arpa.zone"
  fallback-enabled: yes
  for-downstream: no
  for-upstream: yes
  zonefile: "ip6.arpa.zone"
Comment 1 Wouter Wijngaards 2018-06-14 09:00:08 CEST
Hi Eric,

I honestly thought the zonefile format had to start with a SOA record.  But it seems I have to get compatible.  I'll see if I can just parse the first record, without checking that that is a SOA record.

Right now, the url options are preferred over the master options.  It'll try that first.  Then the masters.

Thanks for the report.

Best regards, Wouter
Comment 2 Wouter Wijngaards 2018-06-14 09:07:58 CEST
Hi Eric,

Here is a fix.  It checks that the first RR in the file parses correctly.  But does not insist that this is the SOA RR of that zone.

Best regards, Wouter

Patch:

Index: services/authzone.c
===================================================================
--- services/authzone.c	(revision 4728)
+++ services/authzone.c	(working copy)
@@ -4164,8 +4164,8 @@
 	return 0;
 }
 
-/** check syntax of chunklist zonefile, parse SOA RR, return false on
- * failure and return a string in the scratch buffer (SOA RR string)
+/** check syntax of chunklist zonefile, parse first RR, return false on
+ * failure and return a string in the scratch buffer (first RR string)
  * on failure. */
 static int
 http_zonefile_syntax_check(struct auth_xfer* xfr, sldns_buffer* buf)
@@ -4193,26 +4193,11 @@
 		pstate.origin_len?pstate.origin:NULL, pstate.origin_len,
 		pstate.prev_rr_len?pstate.prev_rr:NULL, pstate.prev_rr_len);
 	if(e != 0) {
-		log_err("parse failure on SOA RR[%d]: %s",
+		log_err("parse failure on first RR[%d]: %s",
 			LDNS_WIREPARSE_OFFSET(e),
 			sldns_get_errorstr_parse(LDNS_WIREPARSE_ERROR(e)));
 		return 0;
 	}
-	/* check that name is correct */
-	if(query_dname_compare(rr, xfr->name) != 0) {
-		char nm[255+1], zname[255+1];
-		dname_str(rr, nm);
-		dname_str(xfr->name, zname);
-		log_err("parse failure for %s, SOA RR for %s found instead",
-			zname, nm);
-		return 0;
-	}
-	/* check that type is SOA */
-	if(sldns_wirerr_get_type(rr, rr_len, dname_len) != LDNS_RR_TYPE_SOA) {
-		log_err("parse failure: first record in downloaded zonefile "
-			"not of type SOA");
-		return 0;
-	}
 	/* check that class is correct */
 	if(sldns_wirerr_get_class(rr, rr_len, dname_len) != xfr->dclass) {
 		log_err("parse failure: first record in downloaded zonefile "
Comment 3 Eric Luehrsen 2018-06-16 06:54:19 CEST
Considering the patch, it seems that now it doesn't require any SOA. I struggle to follow the code to guarantee the zone is rejected in some later checks. This could have unintended consequences. 

I didn't mean to say that Unbound's previous behavior was wrong. If AXFR and URL are used together or fallback is enabled, then it is fair to reject anything but a perfect zone-file. However if URL is the only method, then maybe a more permissive  method should be used to prevent killing DNS. I would expect a zone-file to start and end in SOA as clear markers, but like ICANN example given, trivial blemishes might exist which are acceptable.

Side note while reviewing authzone.c more closely, it looks like one NS is not required to load a zone. If the zone lacks SOA and NS, then it is broken authoritative zone. Regardless of URL or AXFR, I would have expected a validation of minimum one each. If URL only, then Unbound is masquerading , but the NS should still be present in the zone-file as downloaded.
Comment 4 Eric Luehrsen 2018-06-16 07:01:19 CEST
Hi Wouter -
Thanks for acting on this so quickly. I am concerned the patch may introduce unintended consequences. Sorry to reopen the ticket. Please forgive the annoyance.
- Eric
Comment 5 Wouter Wijngaards 2018-06-18 09:35:54 CEST
Hi Eric,

Yes zones should have a SOA and NS.  But if they don't I don't see the issue with loading them, and attempting to use it.  I checked the behaviour of NSD (our authority DNS server) and it also allows the SOA to appear later in the file.

If a SOA record is not present, the authzone in Unbound would respond to all NXDOMAINs with SERVFAIL, because the negative denial SOA record cannot be added.  So I don't really see a problem with the lenience introduced.  Although checking for the presence of a SOA record afterward could, perhaps, be useful.  The only action at that point is dropping zone contents completely, so accepting as now is better.

The AXFR format does have to start with SOA markers at start and end.  And Unbound checks, and continues to check that.  But the zonefile format is allowed more, and does not have to start and end in SOA records.

Best regards, Wouter
Comment 6 Eric Luehrsen 2018-06-18 17:53:37 CEST
Hi Wouter -
That closes my concerns about balance of robustness and error proofing. It all seems good based on existing design (NSD).
Thsnks.
- Eric