pdns-recursor-4.0.0~alpha2 (Ubuntu/Xenial) 4.0.0~alpha2-2osso1 "EDNS/FORMERR fix"

Build instructions:

    $ apt-get source pdns-recursor
    $ patch -p0 < pdns-recursor_4.0.0~alpha2-2--osso1.patch
    $ cd pdns-recursor-4.0.0~alpha2
    $ DEB_BUILD_OPTIONS="parallel=15" dpkg-buildpackage -us -uc -sa

Related URLs:

    http://postfix.1071664.n5.nabble.com/EDNS-DANE-trouble-with-Microsoft-mail-protection-outlook-com-td87331.html
    https://bugs.launchpad.net/ubuntu/+source/pdns-recursor/+bug/1646538
    https://github.com/PowerDNS/pdns/commit/9d534f2a12defc44d2a79291bf34b82e5ee28121

Fixes:

    dig A umcg-nl.mail.protection.outlook.com. @localhost. +edns +dnssec

    # Should return two A records.
    # Without this patch, returns SERVFAIL because the NS for that domain
    # returns FORMERR on the EDNS query.
    
--- pdns-recursor-4.0.0~alpha2/debian/changelog	2016-03-28 14:15:41.000000000 +0200
+++ pdns-recursor-4.0.0~alpha2/debian/changelog	2016-12-01 16:24:26.008412557 +0100
@@ -1,3 +1,10 @@
+pdns-recursor (4.0.0~alpha2-2osso1) unstable; urgency=medium
+
+  * Add 9d534f2a12defc44d2a79291bf34b82e5ee28121 DNSSEC fix against
+    FORMERR served as SERVFAIL.
+
+ -- Walter Doekes <wjdoekes+powerdns@osso.nl>  Thu, 01 Dec 2016 16:24:22 +0100
+
 pdns-recursor (4.0.0~alpha2-2) unstable; urgency=medium
 
   * Apply patch from upstream to fix build without
--- pdns-recursor-4.0.0~alpha2/debian/patches/series	2016-03-28 14:15:41.000000000 +0200
+++ pdns-recursor-4.0.0~alpha2/debian/patches/series	2016-12-01 16:12:52.402666579 +0100
@@ -1,2 +1,3 @@
 disable-dnssec
 e512f4f99403601638a08f738a55d9854caa8680.patch
+9d534f2a12defc44d2a79291bf34b82e5ee28121.patch
--- pdns-recursor-4.0.0~alpha2/debian/patches/9d534f2a12defc44d2a79291bf34b82e5ee28121.patch	1970-01-01 01:00:00.000000000 +0100
+++ pdns-recursor-4.0.0~alpha2/debian/patches/9d534f2a12defc44d2a79291bf34b82e5ee28121.patch	2016-12-01 16:24:03.568356177 +0100
@@ -0,0 +1,85 @@
+Fixes this problem:
+http://postfix.1071664.n5.nabble.com/EDNS-DANE-trouble-with-Microsoft-mail-protection-outlook-com-td87331.html#a87353
+
+This query returns FORMERR, which should result in a second query, not
+in a SERVFAIL response by pdns_recursor.
+
+    dig A umcg-nl.mail.protection.outlook.com. @localhost. +edns +dnssec
+
+commit 9d534f2a12defc44d2a79291bf34b82e5ee28121
+Author: bert hubert <bert.hubert@netherlabs.nl>
+Date:   Thu May 19 11:41:25 2016 +0200
+
+    with this commit, we turn off DNSSEC queries iff you respond with NotImp or FormErr. Also includes comment block with rationale.
+
+--- a/syncres.cc
++++ b/syncres.cc
+@@ -291,6 +291,27 @@ void SyncRes::doEDNSDumpAndClose(int fd)
+   fclose(fp);
+ }
+ 
++/* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
++   to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
++   so that if there are RRSIGs for a name, we'll have them.
++
++   However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
++   * No answer
++   * FormErr
++   * Nonsense answer
++
++   The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
++   Another cause of "No answer" may simply be a network condition.
++   Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
++
++   Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts. 
++   A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
++   clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens 
++   elsewhere. It may not have happened yet. 
++
++   For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
++*/
++
+ int SyncRes::asyncresolveWrapper(const ComboAddress& ip, bool ednsMANDATORY, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, boost::optional<Netmask>& srcmask, LWResult* res)
+ {
+   /* what is your QUEST?
+@@ -300,7 +321,7 @@ int SyncRes::asyncresolveWrapper(const ComboAddress& ip, bool ednsMANDATORY, con
+      0) UNKNOWN Unknown state 
+      1) EDNS: Honors EDNS0
+      2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
+-     3) NOEDNS: Generates FORMERR on EDNS queries
++     3) NOEDNS: Generates FORMERR/NOTIMP on EDNS queries
+ 
+      Everybody starts out assumed to be '0'.
+      If '0', send out EDNS0
+@@ -331,23 +352,19 @@ int SyncRes::asyncresolveWrapper(const ComboAddress& ip, bool ednsMANDATORY, con
+   for(int tries = 0; tries < 3; ++tries) {
+     //    cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
+     
+-    if(ednsMANDATORY || mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSOK || mode==EDNSStatus::EDNSIGNORANT)
+-      EDNSLevel = 1;
+-    else if(mode==EDNSStatus::NOEDNS) {
++    if(mode==EDNSStatus::NOEDNS) {
+       g_stats.noEdnsOutQueries++;
+-      EDNSLevel = 0;
++      EDNSLevel = 0; // level != mode
+     }
++    else if(ednsMANDATORY || mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSOK || mode==EDNSStatus::EDNSIGNORANT)
++      EDNSLevel = 1;
+     
+     ret=asyncresolve(ip, domain, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, res);
++    if(ret < 0) {
++      return ret; // transport error, nothing to learn here
++    }
+ 
+-    if(ret == 0 || ret < 0) {
+-//      cerr<< (ret < 0 ? "Transport error" : "Timeout")<<" for query to "<<ip.toString()<<" for '"<<domain.toString()<<"' (ret = "<<ret<<", mode = "<<(int)mode<<")"<<endl;
+-      // timeout = downgrade to EDNS
+-      if(ret==0 && mode != EDNSStatus::NOEDNS) {
+-        //	cerr<<"\tDowngrading to NOEDNS"<<endl;
+-	mode = EDNSStatus::NOEDNS;
+-	continue;
+-      }
++    if(ret == 0) { // timeout, not doing anything with it now
+       return ret;
+     }
+     else if(mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSOK || mode == EDNSStatus::EDNSIGNORANT ) {
