]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Merge pull request #8418 from pieterlexis/deb-load-keys-from-disk
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 30 Oct 2019 13:09:54 +0000 (14:09 +0100)
committerGitHub <noreply@github.com>
Wed, 30 Oct 2019 13:09:54 +0000 (14:09 +0100)
Deb: Load DNSSEC Keys from disk by default

31 files changed:
.circleci/config.yml
build-scripts/travis.sh
docs/secpoll.zone
modules/geoipbackend/geoipbackend.cc
modules/geoipbackend/geoipbackend.hh
pdns/dnsdist-web.cc
pdns/dnsdist.cc
pdns/dnsdistdist/docs/changelog.rst
pdns/dnsdistdist/docs/conf.py
pdns/dnsdistdist/doh.cc
pdns/doh.hh
pdns/pdns_recursor.cc
pdns/recursordist/Makefile.am
pdns/recursordist/docs/changelog/4.3.rst
pdns/recursordist/docs/settings.rst
pdns/recursordist/test-mtasker.cc
pdns/recursordist/test-recursorcache_cc.cc
pdns/recursordist/test-syncres_cc.cc
pdns/reczones.cc
pdns/syncres.cc
pdns/syncres.hh
pdns/test-packetcache_cc.cc
pdns/zoneparser-tng.cc
regression-tests.api/runtests
regression-tests.auth-py/runtests
regression-tests.dnsdist/runtests
regression-tests.dnsdist/test_Prometheus.py [new file with mode: 0644]
regression-tests.ixfrdist/runtests
regression-tests.recursor-dnssec/recursortests.py
regression-tests.recursor-dnssec/runtests
regression-tests.recursor-dnssec/test_OOOTCP.py

index 089625cbd30980f5e973d124c191db84451f1a70..4b93200431c681e69fa253b10ef7cb6c537287bd 100644 (file)
@@ -474,6 +474,8 @@ commands:
 
 jobs:
   checkout:
+    resource_class: small
+
     docker:
       - image: debian:buster
 
@@ -524,6 +526,8 @@ jobs:
             - pdns-auth
 
   test-auth-regress-odbc-sqlite3:
+    resource_class: small
+
     docker:
       - image: debian:buster
     steps:
@@ -614,6 +618,8 @@ jobs:
           skip: 8bit-txt-unescaped
 
   test-auth-regress-gsqlite3:
+    resource_class: small
+
     docker:
       - image: debian:buster
     steps:
@@ -632,6 +638,8 @@ jobs:
           context: gsqlite3-nsec3-narrow
 
   test-auth-regress-bind:
+    resource_class: small
+
     docker:
       - image: debian:buster
       - image: circleci/mysql:5      # for the hybrid test
@@ -665,6 +673,8 @@ jobs:
           context: bind-hybrid-nsec3
 
   test-auth-regress-gmysql:
+    resource_class: small
+
     docker:
       - image: debian:buster
       - image: circleci/mysql:5
@@ -695,6 +705,8 @@ jobs:
           context: gmysql-nsec3-narrow
 
   test-auth-regress-gpgsql:
+    resource_class: small
+
     docker:
       - image: debian:buster
       - image: circleci/postgres:9
@@ -724,6 +736,8 @@ jobs:
           context: gpgsql-nsec3-narrow
 
   test-auth-regress-ldap:
+    resource_class: small
+
     docker:
       - image: debian:buster
         environment:
@@ -747,6 +761,8 @@ jobs:
           doroot: false
 
   test-auth-regress-tinydns:
+    resource_class: small
+
     docker:
       - image: debian:buster
     steps:
@@ -756,6 +772,8 @@ jobs:
           doroot: false
 
   test-auth-regress-lmdb:
+    resource_class: small
+
     docker:
       - image: debian:buster
     steps:
@@ -773,6 +791,8 @@ jobs:
           context: lmdb-nsec3-narrow
 
   test-auth-algorithms:
+    resource_class: small
+
     docker:
       - image: debian:buster
     steps:
@@ -782,6 +802,8 @@ jobs:
           command: /opt/pdns-auth/bin/pdnsutil test-algorithms
 
   test-auth-api:
+    resource_class: small
+
     docker:
       - image: debian:buster
     steps:
@@ -871,6 +893,8 @@ jobs:
             - pdns-recursor
 
   test-recursor-regression:
+    resource_class: small
+
     docker:
       - image: debian:buster
     steps:
@@ -892,6 +916,8 @@ jobs:
             ./build-scripts/test-recursor
 
   test-recursor-bulk:
+    resource_class: small
+
     docker:
       - image: debian:buster
     steps:
@@ -918,6 +944,8 @@ jobs:
           workdir: ~/project/regression-tests
 
   test-recursor-api:
+    resource_class: small
+
     docker:
       - image: debian:buster
     steps:
@@ -933,6 +961,8 @@ jobs:
             ./runtests recursor
 
   build-auth-docs:
+    resource_class: small
+
     docker:
       - image: debian:buster
     steps:
@@ -941,6 +971,8 @@ jobs:
       - build-auth-docs
 
   deploy-auth-docs:
+    resource_class: small
+
     docker:
       - image: debian:buster
     steps:
@@ -951,6 +983,8 @@ jobs:
       - upload-auth-docs
 
   build-recursor-docs:
+    resource_class: small
+
     docker:
       - image: debian:buster
     steps:
@@ -959,6 +993,8 @@ jobs:
       - build-recursor-docs
 
   deploy-recursor-docs:
+    resource_class: small
+
     docker:
       - image: debian:buster
     steps:
@@ -969,6 +1005,8 @@ jobs:
       - upload-recursor-docs
 
   build-dnsdist-docs:
+    resource_class: small
+
     docker:
       - image: debian:buster
     steps:
@@ -977,6 +1015,8 @@ jobs:
       - build-dnsdist-docs
 
   deploy-dnsdist-docs:
+    resource_class: small
+
     docker:
       - image: debian:buster
     steps:
@@ -1263,6 +1303,8 @@ jobs:
             - dnsdist
 
   test-dnsdist-regression:
+    resource_class: small
+
     docker:
       - image: debian:buster
         environment:
@@ -1276,6 +1318,10 @@ jobs:
             apt-get -qq --no-install-recommends install snmpd
             sed "s/agentxperms 0700 0755 dnsdist/agentxperms 0700 0755/g" regression-tests.dnsdist/snmpd.conf > /etc/snmp/snmpd.conf
             /etc/init.d/snmpd start
+      - run:
+          name: install prometheus tools
+          command: |
+            apt-get -qq --no-install-recommends install prometheus
       - run:
           name: Run dnsdist tests
           workdir: ~/project/regression-tests.dnsdist
@@ -1284,6 +1330,8 @@ jobs:
             ./runtests
 
   test-ixfrdist-regression:
+    resource_class: small
+
     docker:
       - image: debian:buster
         environment:
index c9ffa50cb61113f32edcef8d2280ccacf5001d4e..0b64ee5e76245da0e900daa33ac14f9c858288e9 100755 (executable)
@@ -639,7 +639,7 @@ test_recursor() {
 
 test_dnsdist(){
   run "cd regression-tests.dnsdist"
-  run "DNSDISTBIN=$HOME/dnsdist/bin/dnsdist ./runtests -v --ignore-files='(?:^\.|^_,|^setup\.py$|^test_DOH\.py$|^test_OCSP\.py$|^test_TLSSessionResumption\.py$)'"
+  run "DNSDISTBIN=$HOME/dnsdist/bin/dnsdist ./runtests -v --ignore-files='(?:^\.|^_,|^setup\.py$|^test_DOH\.py$|^test_OCSP\.py$|^test_Prometheus\.py$|^test_TLSSessionResumption\.py$)'"
   run "rm -f ./DNSCryptResolver.cert ./DNSCryptResolver.key"
   run "cd .."
 }
index 8d93ceeeefcc1f7d20dd87d468340b00294dd616..bfce792eb54f68ca65c79aec15d45954bbd91ef8 100644 (file)
@@ -1,4 +1,4 @@
-@       86400   IN  SOA pdns-public-ns1.powerdns.com. pieter\.lexis.powerdns.com. 2019093001 10800 3600 604800 10800
+@       86400   IN  SOA pdns-public-ns1.powerdns.com. pieter\.lexis.powerdns.com. 2019103001 10800 3600 604800 10800
 @       3600    IN  NS  pdns-public-ns1.powerdns.com.
 @       3600    IN  NS  pdns-public-ns2.powerdns.com.
 
@@ -199,6 +199,8 @@ recursor-4.2.0-rc1.security-status                      60 IN TXT "2 Unsupported
 recursor-4.2.0-rc2.security-status                      60 IN TXT "2 Unsupported pre-release (no known vulnerabilities)"
 recursor-4.2.0.security-status                          60 IN TXT "1 OK"
 recursor-4.3.0-alpha1.security-status                   60 IN TXT "1 OK"
+recursor-4.3.0-alpha2.security-status                   60 IN TXT "1 OK"
+recursor-4.3.0-alpha3.security-status                   60 IN TXT "1 OK"
 
 ; Recursor Debian
 recursor-3.6.2-2.debian.security-status                 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/3/security/powerdns-advisory-2015-01/ and https://doc.powerdns.com/3/security/powerdns-advisory-2016-02/"
@@ -323,3 +325,5 @@ dnsdist-1.4.0-beta1.security-status                        60 IN TXT "1 OK"
 dnsdist-1.4.0-rc1.security-status                          60 IN TXT "1 OK"
 dnsdist-1.4.0-rc2.security-status                          60 IN TXT "1 OK"
 dnsdist-1.4.0-rc3.security-status                          60 IN TXT "1 OK"
+dnsdist-1.4.0-rc4.security-status                          60 IN TXT "1 OK"
+dnsdist-1.4.0-rc5.security-status                          60 IN TXT "1 OK"
index 682501e605751d09c72b5eaaf86e282c004ab2ef..b56d16f5d9279827e9b013beecef1d4632dd4de0 100644 (file)
@@ -89,7 +89,7 @@ GeoIPBackend::GeoIPBackend(const string& suffix) {
 static vector<std::unique_ptr<GeoIPInterface> > s_geoip_files;
 
 string getGeoForLua(const std::string& ip, int qaint);
-static string queryGeoIP(const string &ip, bool v6, GeoIPInterface::GeoIPQueryAttribute attribute, GeoIPNetmask& gl);
+static string queryGeoIP(const Netmask& addr, GeoIPInterface::GeoIPQueryAttribute attribute, GeoIPNetmask& gl);
 
 void GeoIPBackend::initialize() {
   YAML::Node config;
@@ -311,7 +311,7 @@ GeoIPBackend::~GeoIPBackend() {
   }
 }
 
-bool GeoIPBackend::lookup_static(const GeoIPDomain &dom, const DNSName &search, const QType &qtype, const DNSName& qdomain, const std::string &ip, GeoIPNetmask &gl, bool v6) {
+bool GeoIPBackend::lookup_static(const GeoIPDomain &dom, const DNSName &search, const QType &qtype, const DNSName& qdomain, const Netmask& addr, GeoIPNetmask &gl) {
   const auto& i = dom.records.find(search);
   map<uint16_t,int> cumul_probabilities;
   int probability_rnd = 1+(dns_random(1000)); // setting probability=0 means it never is used
@@ -321,13 +321,13 @@ bool GeoIPBackend::lookup_static(const GeoIPDomain &dom, const DNSName &search,
       if (qtype != QType::ANY && rr.qtype != qtype) continue;
 
       if (rr.has_weight) {
-        gl.netmask = (v6?128:32);
+        gl.netmask = (addr.isIpv6()?128:32);
         int comp = cumul_probabilities[rr.qtype.getCode()];
         cumul_probabilities[rr.qtype.getCode()] += rr.weight;
         if (rr.weight == 0 || probability_rnd < comp || probability_rnd > (comp + rr.weight))
           continue;
       }
-      const string& content = format2str(rr.content, ip, v6, gl);
+      const string& content = format2str(rr.content, addr, gl);
       if (rr.qtype != QType::ENT && rr.qtype != QType::TXT && content.empty()) continue;
       d_result.push_back(rr);
       d_result.back().content = content;
@@ -367,21 +367,18 @@ void GeoIPBackend::lookup(const QType &qtype, const DNSName& qdomain, int zoneId
     if (!found) return; // not found
   }
 
-  string ip = "0.0.0.0";
-  bool v6 = false;
-  if (pkt_p != NULL) {
-    ip = pkt_p->getRealRemote().toStringNoMask();
-    v6 = pkt_p->getRealRemote().isIpv6();
-  }
+  Netmask addr{"0.0.0.0/0"};
+  if (pkt_p != NULL)
+    addr = Netmask(pkt_p->getRealRemote());
 
   gl.netmask = 0;
 
-  (void)this->lookup_static(*dom, qdomain, qtype, qdomain, ip, gl, v6);
+  (void)this->lookup_static(*dom, qdomain, qtype, qdomain, addr, gl);
 
   const auto& target = (*dom).services.find(qdomain);
   if (target == (*dom).services.end()) return; // no hit
 
-  const NetmaskTree<vector<string> >::node_type* node = target->second.masks.lookup(ComboAddress(ip));
+  const NetmaskTree<vector<string> >::node_type* node = target->second.masks.lookup(addr);
   if (node == NULL) return; // no hit, again.
 
   DNSName sformat;
@@ -391,14 +388,14 @@ void GeoIPBackend::lookup(const QType &qtype, const DNSName& qdomain, int zoneId
     GeoIPNetmask tmp_gl;
     tmp_gl.netmask = 0;
     // get netmask from geoip backend
-    if (queryGeoIP(ip, v6, GeoIPInterface::Name, tmp_gl) == "unknown") {
-      if (v6)
+    if (queryGeoIP(addr, GeoIPInterface::Name, tmp_gl) == "unknown") {
+      if (addr.isIpv6())
         gl.netmask = target->second.netmask6;
       else
         gl.netmask = target->second.netmask4;
     }
   } else {
-    if (v6)
+    if (addr.isIpv6())
       gl.netmask = target->second.netmask6;
     else
       gl.netmask = target->second.netmask4;
@@ -406,10 +403,10 @@ void GeoIPBackend::lookup(const QType &qtype, const DNSName& qdomain, int zoneId
 
   // note that this means the array format won't work with indirect
   for(auto it = node->second.begin(); it != node->second.end(); it++) {
-    sformat = DNSName(format2str(*it, ip, v6, gl));
+    sformat = DNSName(format2str(*it, addr, gl));
 
     // see if the record can be found
-    if (this->lookup_static((*dom), sformat, qtype, qdomain, ip, gl, v6))
+    if (this->lookup_static((*dom), sformat, qtype, qdomain, addr, gl))
       return;
   }
 
@@ -445,46 +442,47 @@ bool GeoIPBackend::get(DNSResourceRecord &r) {
   return true;
 }
 
-static string queryGeoIP(const string &ip, bool v6, GeoIPInterface::GeoIPQueryAttribute attribute, GeoIPNetmask& gl) {
+static string queryGeoIP(const Netmask& addr, GeoIPInterface::GeoIPQueryAttribute attribute, GeoIPNetmask& gl) {
   string ret = "unknown";
 
   for(auto const& gi: s_geoip_files) {
     string val;
+    const string ip = addr.toStringNoMask();
     bool found = false;
 
     switch(attribute) {
     case GeoIPInterface::ASn:
-      if (v6) found = gi->queryASnumV6(val, gl, ip);
+      if (addr.isIpv6()) found = gi->queryASnumV6(val, gl, ip);
       else found =gi->queryASnum(val, gl, ip);
       break;
     case GeoIPInterface::Name:
-      if (v6) found = gi->queryNameV6(val, gl, ip);
+      if (addr.isIpv6()) found = gi->queryNameV6(val, gl, ip);
       else found = gi->queryName(val, gl, ip);
       break;
     case GeoIPInterface::Continent:
-      if (v6) found = gi->queryContinentV6(val, gl, ip);
+      if (addr.isIpv6()) found = gi->queryContinentV6(val, gl, ip);
       else found = gi->queryContinent(val, gl, ip);
       break;
     case GeoIPInterface::Region:
-      if (v6) found = gi->queryRegionV6(val, gl, ip);
+      if (addr.isIpv6()) found = gi->queryRegionV6(val, gl, ip);
       else found = gi->queryRegion(val, gl, ip);
       break;
     case GeoIPInterface::Country:
-      if (v6) found = gi->queryCountryV6(val, gl, ip);
+      if (addr.isIpv6()) found = gi->queryCountryV6(val, gl, ip);
       else found = gi->queryCountry(val, gl, ip);
       break;
     case GeoIPInterface::Country2:
-      if (v6) found = gi->queryCountry2V6(val, gl, ip);
+      if (addr.isIpv6()) found = gi->queryCountry2V6(val, gl, ip);
       else found = gi->queryCountry2(val, gl, ip);
       break;
     case GeoIPInterface::City:
-      if (v6) found = gi->queryCityV6(val, gl, ip);
+      if (addr.isIpv6()) found = gi->queryCityV6(val, gl, ip);
       else found = gi->queryCity(val, gl, ip);
       break;
     case GeoIPInterface::Location:
       double lat=0, lon=0;
       boost::optional<int> alt, prec;
-      if (v6) found = gi->queryLocationV6(gl, ip, lat, lon, alt, prec);
+      if (addr.isIpv6()) found = gi->queryLocationV6(gl, ip, lat, lon, alt, prec);
       else found = gi->queryLocation(gl, ip, lat, lon, alt, prec);
       val = std::to_string(lat)+" "+std::to_string(lon);
       break;
@@ -496,7 +494,7 @@ static string queryGeoIP(const string &ip, bool v6, GeoIPInterface::GeoIPQueryAt
     break;
   }
 
-  if (ret == "unknown") gl.netmask = (v6?128:32); // prevent caching
+  if (ret == "unknown") gl.netmask = (addr.isIpv6()?128:32); // prevent caching
   return ret;
 }
 
@@ -504,8 +502,9 @@ string getGeoForLua(const std::string& ip, int qaint)
 {
   GeoIPInterface::GeoIPQueryAttribute qa((GeoIPInterface::GeoIPQueryAttribute)qaint);
   try {
+    const Netmask addr{ip};
     GeoIPNetmask gl;
-    string res=queryGeoIP(ip, false, qa, gl);
+    string res=queryGeoIP(addr, qa, gl);
     //    cout<<"Result for "<<ip<<" lookup: "<<res<<endl;
     if(qa==GeoIPInterface::ASn && boost::starts_with(res, "as"))
       return res.substr(2);
@@ -520,21 +519,21 @@ string getGeoForLua(const std::string& ip, int qaint)
   return "";
 }
 
-bool queryGeoLocation(const string &ip, bool v6, GeoIPNetmask& gl, double& lat, double& lon,
+bool queryGeoLocation(const Netmask& addr, GeoIPNetmask& gl, double& lat, double& lon,
                       boost::optional<int>& alt, boost::optional<int>& prec)
 {
   for(auto const& gi: s_geoip_files) {
     string val;
-    if (v6) {
-      if (gi->queryLocationV6(gl, ip, lat, lon, alt, prec))
+    if (addr.isIpv6()) {
+      if (gi->queryLocationV6(gl, addr.toStringNoMask(), lat, lon, alt, prec))
         return true;
-     } else if (gi->queryLocation(gl, ip, lat, lon, alt, prec))
+     } else if (gi->queryLocation(gl, addr.toStringNoMask(), lat, lon, alt, prec))
         return true;
   }
   return false;
 }
 
-string GeoIPBackend::format2str(string sformat, const string& ip, bool v6, GeoIPNetmask& gl) {
+string GeoIPBackend::format2str(string sformat, const Netmask& addr, GeoIPNetmask& gl) {
   string::size_type cur,last;
   boost::optional<int> alt, prec;
   double lat, lon;
@@ -549,26 +548,26 @@ string GeoIPBackend::format2str(string sformat, const string& ip, bool v6, GeoIP
     int nrep=3;
     tmp_gl.netmask = 0;
     if (!sformat.compare(cur,3,"%cn")) {
-      rep = queryGeoIP(ip, v6, GeoIPInterface::Continent, tmp_gl);
+      rep = queryGeoIP(addr, GeoIPInterface::Continent, tmp_gl);
     } else if (!sformat.compare(cur,3,"%co")) {
-      rep = queryGeoIP(ip, v6, GeoIPInterface::Country, tmp_gl);
+      rep = queryGeoIP(addr, GeoIPInterface::Country, tmp_gl);
     } else if (!sformat.compare(cur,3,"%cc")) {
-      rep = queryGeoIP(ip, v6, GeoIPInterface::Country2, tmp_gl);
+      rep = queryGeoIP(addr, GeoIPInterface::Country2, tmp_gl);
     } else if (!sformat.compare(cur,3,"%af")) {
-      rep = (v6?"v6":"v4");
+      rep = (addr.isIpv6()?"v6":"v4");
     } else if (!sformat.compare(cur,3,"%as")) {
-      rep = queryGeoIP(ip, v6, GeoIPInterface::ASn, tmp_gl);
+      rep = queryGeoIP(addr, GeoIPInterface::ASn, tmp_gl);
     } else if (!sformat.compare(cur,3,"%re")) {
-      rep = queryGeoIP(ip, v6, GeoIPInterface::Region, tmp_gl);
+      rep = queryGeoIP(addr, GeoIPInterface::Region, tmp_gl);
     } else if (!sformat.compare(cur,3,"%na")) {
-      rep = queryGeoIP(ip, v6, GeoIPInterface::Name, tmp_gl);
+      rep = queryGeoIP(addr, GeoIPInterface::Name, tmp_gl);
     } else if (!sformat.compare(cur,3,"%ci")) {
-      rep = queryGeoIP(ip, v6, GeoIPInterface::City, tmp_gl);
+      rep = queryGeoIP(addr, GeoIPInterface::City, tmp_gl);
     } else if (!sformat.compare(cur,4,"%loc")) {
       char ns, ew;
       int d1, d2, m1, m2;
       double s1, s2;
-      if (!queryGeoLocation(ip, v6, gl, lat, lon, alt, prec)) {
+      if (!queryGeoLocation(addr, gl, lat, lon, alt, prec)) {
         rep = "";
       } else {
         ns = (lat>0) ? 'N' : 'S';
@@ -593,14 +592,14 @@ string GeoIPBackend::format2str(string sformat, const string& ip, bool v6, GeoIP
       }
       nrep = 4;
     } else if (!sformat.compare(cur,4,"%lat")) {
-      if (!queryGeoLocation(ip, v6, gl, lat, lon, alt, prec)) {
+      if (!queryGeoLocation(addr, gl, lat, lon, alt, prec)) {
         rep = "";
       } else {
         rep = str(boost::format("%lf") % lat);
       }
       nrep = 4;
     } else if (!sformat.compare(cur,4,"%lon")) {
-      if (!queryGeoLocation(ip, v6, gl, lat, lon, alt, prec)) {
+      if (!queryGeoLocation(addr, gl, lat, lon, alt, prec)) {
         rep = "";
       } else {
         rep = str(boost::format("%lf") % lon);
@@ -608,44 +607,44 @@ string GeoIPBackend::format2str(string sformat, const string& ip, bool v6, GeoIP
       nrep = 4;
     } else if (!sformat.compare(cur,3,"%hh")) {
       rep = boost::str(boost::format("%02d") % gtm.tm_hour);
-      tmp_gl.netmask = (v6?128:32);
+      tmp_gl.netmask = (addr.isIpv6()?128:32);
     } else if (!sformat.compare(cur,3,"%yy")) {
       rep = boost::str(boost::format("%02d") % (gtm.tm_year + 1900));
-      tmp_gl.netmask = (v6?128:32);
+      tmp_gl.netmask = (addr.isIpv6()?128:32);
     } else if (!sformat.compare(cur,3,"%dd")) {
       rep = boost::str(boost::format("%02d") % (gtm.tm_yday + 1));
-      tmp_gl.netmask = (v6?128:32);
+      tmp_gl.netmask = (addr.isIpv6()?128:32);
     } else if (!sformat.compare(cur,4,"%wds")) {
       nrep=4;
       rep = GeoIP_WEEKDAYS[gtm.tm_wday];
-      tmp_gl.netmask = (v6?128:32);
+      tmp_gl.netmask = (addr.isIpv6()?128:32);
     } else if (!sformat.compare(cur,4,"%mos")) {
       nrep=4;
       rep = GeoIP_MONTHS[gtm.tm_mon];
-      tmp_gl.netmask = (v6?128:32);
+      tmp_gl.netmask = (addr.isIpv6()?128:32);
     } else if (!sformat.compare(cur,3,"%wd")) {
       rep = boost::str(boost::format("%02d") % (gtm.tm_wday + 1));
-      tmp_gl.netmask = (v6?128:32);
+      tmp_gl.netmask = (addr.isIpv6()?128:32);
     } else if (!sformat.compare(cur,3,"%mo")) {
       rep = boost::str(boost::format("%02d") % (gtm.tm_mon + 1));
-      tmp_gl.netmask = (v6?128:32);
+      tmp_gl.netmask = (addr.isIpv6()?128:32);
     } else if (!sformat.compare(cur,4,"%ip6")) {
       nrep = 4;
-      if (v6)
-        rep = ip;
+      if (addr.isIpv6())
+        rep = addr.toStringNoMask();
       else
         rep = "";
-      tmp_gl.netmask = (v6?128:32);
+      tmp_gl.netmask = (addr.isIpv6()?128:32);
     } else if (!sformat.compare(cur,4,"%ip4")) {
       nrep = 4;
-      if (!v6)
-        rep = ip;
+      if (!addr.isIpv6())
+        rep = addr.toStringNoMask();
       else
         rep = "";
-      tmp_gl.netmask = (v6?128:32);
+      tmp_gl.netmask = (addr.isIpv6()?128:32);
     } else if (!sformat.compare(cur,3,"%ip")) {
-      rep = ip;
-      tmp_gl.netmask = (v6?128:32);
+      rep = addr.toStringNoMask();
+      tmp_gl.netmask = (addr.isIpv6()?128:32);
     } else if (!sformat.compare(cur,2,"%%")) {
       last = cur + 2; continue;
     } else {
index 9d8f00af9964df3cd672aa4e71c21f19b3850916..c947478bf972ef107836983912c680a338e352bb 100644 (file)
@@ -70,10 +70,10 @@ private:
   static pthread_rwlock_t s_state_lock;
 
   void initialize();
-  string format2str(string format, const string& ip, bool v6, GeoIPNetmask& gl);
+  string format2str(string format, const Netmask &addr, GeoIPNetmask& gl);
   bool d_dnssec;
   bool hasDNSSECkey(const DNSName& name);
-  bool lookup_static(const GeoIPDomain &dom, const DNSName &search, const QType &qtype, const DNSName& qdomain, const std::string &ip, GeoIPNetmask& gl, bool v6);
+  bool lookup_static(const GeoIPDomain &dom, const DNSName &search, const QType &qtype, const DNSName& qdomain, const Netmask &addr, GeoIPNetmask& gl);
   vector<DNSResourceRecord> d_result;
   vector<GeoIPInterface> d_files;
 };
index 0ed3f66f831eab94b6d210f929bab80c21a3e5a2..07613f131c516b9ee81378c885d38bcf2ec2cdfe 100644 (file)
@@ -656,7 +656,7 @@ static void connectionThread(int sock, ComboAddress remote)
             threadNumber = dupPair.first->second;
             ++(dupPair.first->second);
           }
-          const std::string addrlabel = boost::str(boost::format("address=\"%1%\",thread=\"%2%\"") % frontName % threadNumber);
+          const std::string addrlabel = boost::str(boost::format("frontend=\"%1%\",thread=\"%2%\"") % frontName % threadNumber);
           const std::string label = "{" + addrlabel + "} ";
 
           output << frontsbase << "http_connects" << label << doh->d_httpconnects << "\n";
index 955743971cd4d9b38c84959f418b53d252883280..d9a149df5370f82d0d350be560a6f23229b32466 100644 (file)
@@ -616,8 +616,10 @@ try {
             du->response = std::string(response, responseLen);
             if (send(du->rsock, &du, sizeof(du), 0) != sizeof(du)) {
               /* at this point we have the only remaining pointer on this
-                 DOHUnit object since we did set ids->du to nullptr earlier */
-              delete du;
+                 DOHUnit object since we did set ids->du to nullptr earlier,
+                 except if we got the response before the pointer could be
+                 released by the frontend */
+              du->release();
             }
 #endif /* HAVE_DNS_OVER_HTTPS */
             du = nullptr;
index b84d1d8a535a6c034fc6b533a0d35d6e9ae67611..d3297b5f2094028a8af4cacbf04cd38f7deb9147 100644 (file)
@@ -1,6 +1,162 @@
 Changelog
 =========
 
+.. changelog::
+  :version: 1.4.0-rc5
+  :released: 30th of October 2019
+
+  .. change::
+    :tags: Improvements, DNS over HTTPS, Metrics
+    :pullreq: 8465
+
+    Rename the 'address' label to 'frontend' for DoH metrics
+
+  .. change::
+    :tags: Bug Fixes, DNS over HTTPS
+    :pullreq: 8471
+
+    Increment the DOHUnit ref count when it's set in the IDState
+
+.. changelog::
+  :version: 1.4.0-rc4
+  :released: 25th of October 2019
+
+  .. change::
+    :tags: New Features, DNS over HTTPS, DNS over TLS
+    :pullreq: 8442
+
+    Add support dumping TLS keys via keyLogFile
+
+  .. change::
+    :tags: Improvements, DNS over HTTPS
+    :pullreq: 8416
+
+    Implement reference counting for the DOHUnit object
+
+  .. change::
+    :tags: Improvements, DNS over HTTPS, DNS over TLS, Metrics
+    :pullreq: 8447
+
+    Add metrics about TLS handshake failures for DoH and DoT
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 8411
+    :tickets: 8390
+
+    Add more options to LogAction (non-verbose mode, timestamps)
+
+  .. change::
+    :tags: Improvements, DNS over HTTPS, DNS over TLS
+    :pullreq: 8383
+
+    Merge the setup of TLS contexts in DoH and DoT
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 8408
+
+    Fix the caching of large entries
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 8415
+
+    Fix formatting in showTCPStats()
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 8413
+    :tickets: 8412
+
+    Work around cmsg_space somehow not being a constexpr on macOS
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 8372
+
+    Use SO_BINDTODEVICE when available for newServer's source interface
+
+  .. change::
+    :tags: Bug Fixes, Metrics
+    :pullreq: 8409
+
+    Add missing prometheus descriptions for cache-related metrics
+
+  .. change::
+    :tags: Improvements, DNS over HTTPS, DNS over TLS, Metrics
+    :pullreq: 8406
+
+    Add metrics about unknown/inactive TLS ticket keys
+
+  .. change::
+    :tags: Improvements, DNS over TLS, Metrics
+    :pullreq: 8387
+
+    Add metrics about TLS versions with DNS over TLS
+
+  .. change::
+    :tags: Improvements, DNS over HTTPS, Metrics
+    :pullreq: 8395
+
+    Count the number of concurrent connections for DoH as well
+
+  .. change::
+    :tags: Bug Fixes, DNS over HTTPS
+    :pullreq: 8388
+
+    Clear the DoH session ticket encryption key in the ctor
+
+  .. change::
+    :tags: Improvements, DNS over HTTPS, DNS over TLS
+    :pullreq: 8382
+
+    Add a 'preferServerCiphers' option for DoH and DoT
+
+  .. change::
+    :tags: Bug Fixes, Metrics
+    :pullreq: 8381
+
+    Add a prometheus 'thread' label to distinguish identical frontends
+
+  .. change::
+    :tags: Bug Fixes, Metrics
+    :pullreq: 8378
+
+    Fix a typo in the prometheus description of 'senderrors'
+
+  .. change::
+    :tags: Bug Fixes, Metrics
+    :pullreq: 8368
+
+    More prometheus fixes
+
+  .. change::
+    :tags: Improvements, DNS over HTTPS
+    :pullreq: 8365
+    :tickets: 8353
+
+    Lowercase custom DoH header names
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 8364
+    :tickets: 8362
+
+    Check the address supplied to 'webserver' in check-config
+
+  .. change::
+    :tags: Improvements, DNS over HTTPS, Metrics
+    :pullreq: 8361
+
+    Refactor DoH prometheus metrics again
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 8359
+
+    Fix the creation order of rules when inserted via setRules()
+
 .. changelog::
   :version: 1.4.0-rc3
   :released: 30th of September 2019
index 87c8c969c19ca946fb9fa0f282be66ec8801293c..c6c6142041a0781a17e172b5f0fbea751a881ad5 100644 (file)
@@ -85,7 +85,7 @@ changelog_render_pullreq = "https://github.com/PowerDNS/pdns/pull/%s"
 changelog_render_changeset = "https://github.com/PowerDNS/pdns/commit/%s"
 
 changelog_sections = ['New Features', 'Improvements', 'Bug Fixes', 'Removals']
-changelog_inner_tag_sort = ['Security', 'DNS over HTTPS', 'DNS over TLS', 'DNSCrypt', 'Protobuf', 'Performance', 'Webserver']
+changelog_inner_tag_sort = ['Security', 'DNS over HTTPS', 'DNS over TLS', 'DNSCrypt', 'Protobuf', 'Performance', 'Webserver', 'Metrics']
 
 changelog_render_tags = False
 
index bff3ef6a10f51f554593ab5978db88a95cd08fce..9b29e650b810bc5179e35964bbfa475ea1cdc483 100644 (file)
@@ -75,8 +75,7 @@ public:
 
   void release()
   {
-    --d_refcnt;
-    if (d_refcnt == 0) {
+    if (--d_refcnt == 0) {
       SSL_CTX_free(d_h2o_accept_ctx.ssl_ctx);
       d_h2o_accept_ctx.ssl_ctx = nullptr;
       delete this;
@@ -349,11 +348,11 @@ static void handleResponse(DOHFrontend& df, st_h2o_req_t* req, uint16_t statusCo
    this function calls 'return -1' to drop a query without sending it
    caller should make sure HTTPS thread hears of that
 */
-
 static int processDOHQuery(DOHUnit* du)
 {
   uint16_t queryId = 0;
   ComboAddress remote;
+  bool duRefCountIncremented = false;
   try {
     if(!du->req) {
       // we got closed meanwhile. XXX small race condition here
@@ -466,6 +465,9 @@ static int processDOHQuery(DOHUnit* du)
     }
 
     ids->origFD = 0;
+    /* increase the ref count since we are about to store the pointer */
+    du->get();
+    duRefCountIncremented = true;
     ids->du = du;
 
     ids->cs = &cs;
@@ -491,18 +493,17 @@ static int processDOHQuery(DOHUnit* du)
 
     int fd = pickBackendSocketForSending(ss);
     try {
-      /* increase the ref count since we are about to send the pointer */
-         du->get();
       /* you can't touch du after this line, because it might already have been freed */
       ssize_t ret = udpClientSendRequestToBackend(ss, fd, query, dq.len);
 
       if(ret < 0) {
-        du->release();
         /* we are about to handle the error, make sure that
            this pointer is not accessed when the state is cleaned,
            but first check that it still belongs to us */
         if (ids->tryMarkUnused(generation)) {
           ids->du = nullptr;
+          du->release();
+          duRefCountIncremented = false;
           --ss->outstanding;
         }
         ++ss->sendErrors;
@@ -512,7 +513,9 @@ static int processDOHQuery(DOHUnit* du)
       }
     }
     catch (const std::exception& e) {
-      du->release();
+      if (duRefCountIncremented) {
+        du->release();
+      }
       throw;
     }
 
@@ -527,6 +530,7 @@ static int processDOHQuery(DOHUnit* du)
   return 0;
 }
 
+/* called when a HTTP response is about to be sent */
 static void on_response_ready_cb(struct st_h2o_filter_t *self, h2o_req_t *req, h2o_ostream_t **slot)
 {
   if (req == nullptr) {
@@ -599,6 +603,8 @@ static void on_generator_dispose(void *_self)
   }
 }
 
+/* We allocate a DOHUnit and send it to dnsdistclient() function in the doh client thread
+   via a pipe */
 static void doh_dispatch_query(DOHServerConfig* dsc, h2o_handler_t* self, h2o_req_t* req, std::string&& query, const ComboAddress& local, const ComboAddress& remote)
 {
   try {
@@ -633,8 +639,9 @@ static void doh_dispatch_query(DOHServerConfig* dsc, h2o_handler_t* self, h2o_re
 }
 
 /*
-   For GET, the base64url-encoded payload is in the 'dns' parameter, which might be the first parameter, or not.
-   For POST, the payload is the payload.
+  A query has been parsed by h2o.
+  For GET, the base64url-encoded payload is in the 'dns' parameter, which might be the first parameter, or not.
+  For POST, the payload is the payload.
  */
 static int doh_handler(h2o_handler_t *self, h2o_req_t *req)
 try
@@ -884,7 +891,10 @@ void DOHUnit::setHTTPResponse(uint16_t statusCode, const std::string& body_, con
   contentType = contentType_;
 }
 
-void dnsdistclient(int qsock, int rsock)
+/* query has been parsed by h2o, which called doh_handler() in the main DoH thread.
+   In order not to blockfor long, doh_handler() called doh_dispatch_query() which allocated
+   a DOHUnit object and passed it to us */
+static void dnsdistclient(int qsock, int rsock)
 {
   setThreadName("dnsdist/doh-cli");
 
@@ -936,7 +946,13 @@ void dnsdistclient(int qsock, int rsock)
   }
 }
 
-// called if h2o finds that dnsdist gave us an answer
+/* called if h2o finds that dnsdist gave us an answer by writing into
+   the dohresponsepair[0] side of the pipe so from:
+   - handleDOHTimeout() when we did not get a response fast enough (called
+     either from the health check thread (active) or from the frontend ones (reused))
+   - dnsdistclient (error 500 because processDOHQuery() returned a negative value)
+   - processDOHQuery (self-answered queries)
+   */
 static void on_dnsdist(h2o_socket_t *listener, const char *err)
 {
   DOHUnit *du = nullptr;
@@ -964,6 +980,7 @@ static void on_dnsdist(h2o_socket_t *listener, const char *err)
   du->release();
 }
 
+/* called when a TCP connection has been accepted, the TLS session has not been established */
 static void on_accept(h2o_socket_t *listener, const char *err)
 {
   DOHServerConfig* dsc = reinterpret_cast<DOHServerConfig*>(listener->data);
index 53cfbcd206630491bd74c43212e4c55cce68781d..ba0499f7e048ef08b12b47ef33a1db04481c31d2 100644 (file)
@@ -151,8 +151,7 @@ struct DOHUnit
 
   void release()
   {
-    --d_refcnt;
-    if (d_refcnt == 0) {
+    if (--d_refcnt == 0) {
       delete this;
     }
   }
index 3666525f9b87ff96e25484c1b070d31a28c54131..d7c3716d2a88c1ccfcbd78e7d77bfd0cc8a909ba 100644 (file)
@@ -2914,8 +2914,10 @@ static void houseKeeping(void *)
 
     if(now.tv_sec - last_rootupdate > 7200) {
       int res = SyncRes::getRootNS(g_now, nullptr);
-      if (!res)
+      if (!res) {
         last_rootupdate=now.tv_sec;
+        primeRootNSZones(g_dnssecmode != DNSSECMode::Off);
+      }
     }
 
     if(isHandlerThread()) {
index 65022d5aa740840b4068842bfb15d4930befdcdd..565bd70d3b15b6c29615731b468574c2aef08820 100644 (file)
@@ -35,6 +35,8 @@ BUILT_SOURCES=htmlfiles.h \
 CLEANFILES = htmlfiles.h \
        dnsmessage.pb.cc \
        dnsmessage.pb.h \
+       dnstap.pb.cc \
+       dnstap.pb.h \
        recursor.conf-dist
 
 htmlfiles.h: html/*
index aca1a5804e1adee9f80c539a4f238a48b7ac07b7..168c2fad3e69d757f5c64c7f14e30c2ed0dcca33 100644 (file)
@@ -1,6 +1,113 @@
 Changelogs for 4.3.x
 ====================
 
+.. changelog::
+  :version: 4.3.0-alpha3
+  :released: 29th of October 2019
+
+  .. change::
+    :tags: Bug fixes
+    :pullreq: 8470
+
+    Prime NS records of root-servers.net parent (.net)
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 8463
+
+    Update CentOS 6 init script (None)
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 8451
+
+    Basic validation of $GENERATE parameters
+
+  .. change::
+    :tags: Bug fixes
+    :pullreq: 8433
+
+    Dns64: stop hiding PTR indirection
+
+  .. change::
+    :tags: New features
+    :pullreq: 8391
+    :tickets: 8358
+
+    Allow multiple simultaneous incoming TCP queries over a connection
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 8344
+
+    Add signal handling for SIGTERM and SIGINT in pdns_recursor, if we are PID1 (Frank Louwers)
+
+  .. change::
+    :tags: New Features
+    :pullreq: 8367
+
+    Implement RFC 8020 "NXDOMAIN: There Really Is Nothing Underneath"
+
+  .. change::
+    :tags: New features
+    :pullreq: 8400
+
+    Add CentOS 8 as builder target
+
+  .. change::
+    :tags: Bug fixes
+    :pullreq: 8371
+
+    Fix chmod paths in rules files
+
+  .. change::
+    :tags: New features
+    :pullreq: 8366
+
+    Build Newly Observed Domain (NOD) support by default.
+
+  .. change::
+    :tags: Bug fixes
+    :pullreq: 8360
+    :tickets: 8352
+
+    Rec: chmod/own recursor.conf for the systemd case
+    
+  .. change::
+    :tags: Bug fixes
+    :pullreq: 8340
+    :tickets: 8338
+
+    Fix #8338: Issue with "zz" abbreviation for IPv6 RPZ triggers
+
+  .. change::
+    :tags: Bug fixes
+    :pullreq: 8317
+
+    Retry getrandom() on EINTR
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 8287
+
+    Docs: Add small description for pipe backend about distributor-threads (Donatas Abraitis)
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 8290
+
+    Improve commandline error reporting for non-opts
+
+  .. change::
+    :tags: New features
+    :pullreq: 7758
+
+    Recursor webhandler for prometheus metrics (Greg Cockroft)
+
+.. changelog::
+  :version: 4.3.0-alpha2
+  :released: Never released
+
 .. changelog::
   :version: 4.3.0-alpha1
   :released: 5th of September 2019
@@ -170,7 +277,7 @@ Changelogs for 4.3.x
     :pullreq: 7967
     :tickets: 7949
 
-    Silence unused lambda warning (retry) (None)
+    Silence unused lambda warning (retry) (fwSmit)
 
   .. change::
     :tags: New Features
index d8321659fd8fcca4bc266b1776eb951fc0345dc3..d9b65d35bf0ec7d8eabff18afb0b01bfef4325fc 100644 (file)
@@ -864,7 +864,7 @@ Maximum number of seconds to cache an item in the DNS cache, no matter what the
 .. _setting max-concurrent-requests-per-tcp-connection:
 
 ``max-concurrent-requests-per-tcp-connection``
-------------------------------------------
+----------------------------------------------
 -  Integer
 -  Default: 10
 
index e022a19f7b96787271c00bc09599a8d8628a73f1..7e33160c1936f04809458e82ee2640c606831002 100644 (file)
@@ -5,7 +5,6 @@
 #include "config.h"
 #endif
 #include <boost/test/unit_test.hpp>
-#include <boost/test/floating_point_comparison.hpp>
 #include "mtasker.hh"
 
 BOOST_AUTO_TEST_SUITE(mtasker_cc)
index 85a60d003ac14800a941417828c65d3cf0e6de50..8accd90d6453bfc74c40237c1677c6c25bab6d99 100644 (file)
@@ -5,7 +5,6 @@
 #include "config.h"
 #endif
 #include <boost/test/unit_test.hpp>
-#include <boost/test/floating_point_comparison.hpp>
 
 #include "iputils.hh"
 #include "recursor_cache.hh"
index d74197807893aa7786b9670a4ad591cf0451bac9..46ee34258a2b22b22220c3fbad3330d2e3b2da1a 100644 (file)
@@ -27,6 +27,10 @@ int getMTaskerTID()
   return 0;
 }
 
+void primeRootNSZones(bool)
+{
+}
+
 bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret) const
 {
   return false;
index 45bcb814a2445f830545af3336b7c426fdeeaf96..505a18402edda79e9591881954ce3b882c019e95 100644 (file)
 extern int g_argc;
 extern char** g_argv;
 
+static thread_local set<DNSName> t_rootNSZones;
+
+static void insertIntoRootNSZones(const DNSName &name) {
+  // do not insert dot, wiping dot's NS records from the cache in primeRootNSZones()
+  // will cause infinite recursion
+  if (!name.isRoot()) {
+    t_rootNSZones.insert(name);
+  }
+}
+
 void primeHints(void)
 {
   // prime root cache
   const vState validationState = Insecure;
   vector<DNSRecord> nsset;
+  t_rootNSZones.clear();
   if(!t_RC)
     t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
 
@@ -54,6 +65,7 @@ void primeHints(void)
       templ[sizeof(templ)-1] = '\0';
       *templ=c;
       aaaarr.d_name=arr.d_name=DNSName(templ);
+      insertIntoRootNSZones(arr.d_name.getLastLabel());
       nsrr.d_content=std::make_shared<NSRecordContent>(DNSName(templ));
       arr.d_content=std::make_shared<ARecordContent>(ComboAddress(rootIps4[c-'a']));
       vector<DNSRecord> aset;
@@ -88,12 +100,39 @@ void primeHints(void)
         rr.content=toLower(rr.content);
         nsset.push_back(DNSRecord(rr));
       }
+      insertIntoRootNSZones(rr.qname.getLastLabel());
     }
   }
   t_RC->doWipeCache(g_rootdnsname, false, QType::NS);
   t_RC->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false, boost::none, validationState); // and stuff in the cache
 }
 
+
+// Do not only put the root hints into the cache, but also make sure
+// the NS records of the top level domains of the names of the root
+// servers are in the cache. We need these to correctly determine the
+// security status of that specific domain (normally
+// root-servers.net). This is caused by the accident that the root
+// servers are authoritative for root-servers.net, and some
+// implementations reply not with a delegation on a root-servers.net
+// DS query, but with a NODATA response (the domain is unsigned).
+void primeRootNSZones(bool dnssecmode)
+{
+  struct timeval now;
+  gettimeofday(&now, 0);
+  SyncRes sr(now);
+
+  if (dnssecmode) {
+    sr.setDoDNSSEC(true);
+    sr.setDNSSECValidationRequested(true);
+  }
+  for (const auto & qname: t_rootNSZones) {
+    t_RC->doWipeCache(qname, false, QType::NS);
+    vector<DNSRecord> ret;
+    sr.beginResolve(qname, QType(QType::NS), QClass::IN, ret);
+  }
+}
+
 static void makeNameToIPZone(std::shared_ptr<SyncRes::domainmap_t> newMap, const DNSName& hostname, const string& ip)
 {
   SyncRes::AuthDomain ad;
@@ -479,4 +518,3 @@ std::shared_ptr<SyncRes::domainmap_t> parseAuthAndForwards()
   }
   return newMap;
 }
-
index 8419150aa19db196c39338812c4502bcc923166d..ae18dd8abe64dd0f32424f4eddc2e297db6098f7 100644 (file)
@@ -1025,6 +1025,7 @@ void SyncRes::getBestNSFromCache(const DNSName &qname, const QType& qtype, vecto
     if(subdomain.isRoot() && !brokeloop) {
       // We lost the root NS records
       primeHints();
+      primeRootNSZones(g_dnssecmode != DNSSECMode::Off);
       LOG(prefix<<qname<<": reprimed the root"<<endl);
       /* let's prevent an infinite loop */
       if (!d_updatingRootNS) {
index d1e87f6a2534cf2311f955eb90a54f90a046aeca..f72a2cdb50dba960bf882866d47a9c1ab9e4802b 100644 (file)
@@ -1073,6 +1073,7 @@ uint64_t* pleaseWipePacketCache(const DNSName& canon, bool subtree);
 uint64_t* pleaseWipeAndCountNegCache(const DNSName& canon, bool subtree=false);
 void doCarbonDump(void*);
 void primeHints(void);
+void primeRootNSZones(bool);
 
 extern __thread struct timeval g_now;
 
index fc277f50cf68bdc66173be28a5543712ec1a771a..1655abe42a67b3fdef1c90890864464e4219c700 100644 (file)
@@ -5,7 +5,6 @@
 #include "config.h"
 #endif
 #include <boost/test/unit_test.hpp>
-#include <boost/test/floating_point_comparison.hpp>
 #include "iputils.hh"
 #include "nameserver.hh"
 #include "statbag.hh"
index 5c4ed00db28b040201a14df8b16403084136289b..9772e36ada35b6afbe40b217da0c229b5c3b1e2d 100644 (file)
@@ -326,7 +326,7 @@ bool ZoneParserTNG::get(DNSResourceRecord& rr, std::string* comment)
       sscanf(range.c_str(),"%u-%u/%u", &d_templatecounter, &d_templatestop, &d_templatestep);
       if (d_templatestep < 1 ||
           d_templatestop < d_templatecounter) {
-        throw exception("Illegal $GENERATE parameters");
+        throw exception("Invalid $GENERATE parameters");
       }
       d_templateline=d_line;
       parts.pop_front();
index 6574536d177b000c5580df65957f9f308383c0cc..56e5bf77b3bf763858e4a1dc29ad539256e6ed2a 100755 (executable)
@@ -15,7 +15,7 @@ if [ ! -d .venv ]; then
 fi
 . .venv/bin/activate
 python -V
-pip install -r requirements.txt
+pip install -r requirements.txt | cat
 
 if [ -z "${SDIG}" ]; then
   export SDIG=$(type -P sdig)
index 68797ebddc965805db0ee05be24f36d2e00f4c6e..6c30ba8c6634b2fe3d102732ef0dd1405d76a4aa 100755 (executable)
@@ -9,7 +9,7 @@ fi
 
 . .venv/bin/activate
 python -V
-pip install -q -r requirements.txt
+pip install -q -r requirements.txt | cat
 
 mkdir -p configs
 
index eb2fc9b4c174382c0e9f5b4aa13884df6abdaa7d..93543922c581364a9d7c3f3d8fccbccb771c30b7 100755 (executable)
@@ -29,7 +29,7 @@ then
     export CPPFLAGS=-I/usr/local/opt/openssl/include
   fi
 fi
-pip install -r requirements.txt
+pip install -r requirements.txt | cat
 
 protoc -I=../pdns/ --python_out=. ../pdns/dnsmessage.proto
 protoc -I=../pdns/ --python_out=. ../pdns/dnstap.proto
diff --git a/regression-tests.dnsdist/test_Prometheus.py b/regression-tests.dnsdist/test_Prometheus.py
new file mode 100644 (file)
index 0000000..02b0159
--- /dev/null
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+import requests
+import subprocess
+from dnsdisttests import DNSDistTest
+
+class TestPrometheus(DNSDistTest):
+
+    _webTimeout = 2.0
+    _webServerPort = 8083
+    _webServerBasicAuthPassword = 'secret'
+    _webServerAPIKey = 'apisecret'
+    _config_params = ['_testServerPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
+    _config_template = """
+    newServer{address="127.0.0.1:%s"}
+    webserver("127.0.0.1:%s", "%s", "%s")
+    """
+
+    def checkPrometheusContentBasic(self, content):
+        for line in content.splitlines():
+            if line.startswith('# HELP'):
+                tokens = line.split(' ')
+                self.assertGreaterEqual(len(tokens), 4)
+            elif line.startswith('# TYPE'):
+                tokens = line.split(' ')
+                self.assertEquals(len(tokens), 4)
+                self.assertIn(tokens[3], ['counter', 'gauge', 'histogram'])
+            elif not line.startswith('#'):
+                tokens = line.split(' ')
+                self.assertEquals(len(tokens), 2)
+                if not line.startswith('dnsdist_'):
+                    raise AssertionError('Expecting prometheus metric to be prefixed by \'dnsdist_\', got: "%s"' % (line))
+
+    def checkPrometheusContentPromtool(self, content):
+        output = None
+        try:
+            testcmd = ['promtool', 'check', 'metrics']
+            process = subprocess.Popen(testcmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
+            output = process.communicate(input=content)
+        except subprocess.CalledProcessError as exc:
+            raise AssertionError('%s failed (%d): %s' % (testcmd, process.returncode, process.output))
+
+        # commented out because promtool returns 3 because of the "_total" suffix warnings
+        #if process.returncode != 0:
+        #  raise AssertionError('%s failed (%d): %s' % (testcmd, process.returncode, output))
+
+        for line in output[0].splitlines():
+            if line.endswith(b"should have \"_total\" suffix"):
+                continue
+            raise AssertionError('%s returned an unexpected output. Faulty line is "%s", complete content is "%s"' % (testcmd, line, output))
+
+    def testMetrics(self):
+        """
+        Prometheus: Retrieve metrics
+        """
+        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/metrics'
+        r = requests.get(url, auth=('whatever', self._webServerBasicAuthPassword), timeout=self._webTimeout)
+        self.assertTrue(r)
+        self.assertEquals(r.status_code, 200)
+        self.checkPrometheusContentBasic(r.text)
+        self.checkPrometheusContentPromtool(r.content)
index 5a560a05d046512ea160ba0fdd71dcd4208c35a2..0bbf43915dd8432ba9392ab5acddeeb81b789de6 100755 (executable)
@@ -16,7 +16,7 @@ if [ ! -d .venv ]; then
 fi
 . .venv/bin/activate
 python -V
-pip install -r requirements.txt
+pip install -r requirements.txt | cat
 
 if [ -z "${IXFRDISTBIN}" ]; then
   IXFRDISTBIN=$(ls ../pdns/ixfrdist)
index 1b2f018aa4c485f2646b725696768861d5e293e1..9406f11eac7fc17a6cd795e75d76941afe19a0a9 100644 (file)
@@ -70,14 +70,14 @@ example.                 3600 IN NS   ns2.example.
 example.                 3600 IN DS   53174 13 1 50c9e913818767c236c06c2d8272723cb78cbf26
 
 ns1.example.             3600 IN A    {prefix}.10
-ns2.example.             3600 IN A    {prefix}.11
+ns2.example.             3600 IN A    {prefix}.18
         """,
         'example': """
 example.                 3600 IN SOA  {soa}
 example.                 3600 IN NS   ns1.example.
 example.                 3600 IN NS   ns2.example.
 ns1.example.             3600 IN A    {prefix}.10
-ns2.example.             3600 IN A    {prefix}.11
+ns2.example.             3600 IN A    {prefix}.18
 
 secure.example.          3600 IN NS   ns.secure.example.
 secure.example.          3600 IN DS   64723 13 1 53eb985040d3a89bacf29dbddb55a65834706f33
@@ -119,8 +119,11 @@ sort.example.                      3600 IN MX    25 mx
 
 delay1.example.                     3600 IN NS   ns1.delay1.example.
 ns1.delay1.example.                 3600 IN A    {prefix}.16
+delay1.example.                     3600 IN DS 42043 13 2 7319fa605cf117f36e3de070157577ebb9a05a1d1f963d80eda55b5d6e793eb2
+
 delay2.example.                     3600 IN NS   ns1.delay2.example.
 ns1.delay2.example.                 3600 IN A    {prefix}.17
+delay2.example.                     3600 IN DS 42043 13 2 60a047b87740c8564c21d5fd34626c10a77a6c41e3b34564230119c2f13937b8
         """,
         'secure.example': """
 secure.example.          3600 IN SOA  {soa}
@@ -310,6 +313,18 @@ PrivateKey: kvoV/g4IO/tefSro+FLJ5UC7H3BUf0IUtZQSUOfQGyA=
 Private-key-format: v1.2
 Algorithm: 13 (ECDSAP256SHA256)
 PrivateKey: Ep9uo6+wwjb4MaOmqq7LHav2FLrjotVOeZg8JT1Qk04=
+""",
+
+        'delay1.example': """
+Private-key-format: v1.2
+Algorithm: 13 (ECDSAP256SHA256)
+PrivateKey: Ep9uo6+wwjb4MaOmqq7LHav2FLrjotVOeZg8JT1Qk04=
+""",
+
+        'delay2.example': """
+Private-key-format: v1.2
+Algorithm: 13 (ECDSAP256SHA256)
+PrivateKey: Ep9uo6+wwjb4MaOmqq7LHav2FLrjotVOeZg8JT1Qk04=
 """
     }
 
@@ -323,8 +338,9 @@ PrivateKey: Ep9uo6+wwjb4MaOmqq7LHav2FLrjotVOeZg8JT1Qk04=
               'zones': ['secure.example', 'islandofsecurity.example']},
         '10': {'threads': 1,
                'zones': ['example']},
-        '11': {'threads': 1,
-               'zones': ['example']},
+
+        # 11 is used by CircleCI provided resolver
+
         '12': {'threads': 1,
                'zones': ['bogus.example', 'undelegated.secure.example', 'undelegated.insecure.example']},
         '13': {'threads': 1,
@@ -336,7 +352,9 @@ PrivateKey: Ep9uo6+wwjb4MaOmqq7LHav2FLrjotVOeZg8JT1Qk04=
         '16': {'threads': 2,
                'zones': ['delay1.example']},
         '17': {'threads': 2,
-               'zones': ['delay2.example']}
+               'zones': ['delay2.example']},
+        '18': {'threads': 1,
+               'zones': ['example']}
     }
 
     _auth_cmd = ['authbind',
index 4f1a674a3cea9cb6211e35e3eb8a3df7f665db4f..b21a776e66fd773d153d5111756ab49fc97b5f12 100755 (executable)
@@ -7,8 +7,8 @@ if [ ! -d .venv ]; then
 fi
 . .venv/bin/activate
 python -V
-pip install -U pip
-pip install -r requirements.txt
+pip install -U pip | cat
+pip install -r requirements.txt | cat
 
 protoc -I=../pdns/ --python_out=. ../pdns/dnsmessage.proto
 protoc -I=../pdns/ --python_out=. ../pdns/dnstap.proto
index a68d208e7e50375b5154c95894c868e4ea2aa554..9c18017011a0475182288e56e5ae7cc060ba255c 100644 (file)
@@ -6,7 +6,7 @@ from recursortests import RecursorTest
 class testOOOTCP(RecursorTest):
     _confdir = 'OOOTCP'
 
-    _config_template = """dnssec=off
+    _config_template = """dnssec=validate
 """
 
     @classmethod
@@ -18,7 +18,7 @@ class testOOOTCP(RecursorTest):
         queries = []
         for zone in ['5.delay1.example.', '0.delay2.example.']:
             expected[zone] = dns.rrset.from_text(zone, 0, dns.rdataclass.IN, 'TXT', 'a')
-            query = dns.message.make_query(zone, 'TXT', want_dnssec=False)
+            query = dns.message.make_query(zone, 'TXT', want_dnssec=True)
             query.flags |= dns.flags.AD
             queries.append(query)
 
@@ -32,16 +32,16 @@ class testOOOTCP(RecursorTest):
             print(ress[i].answer[0].to_text())
             print('exp')
             print(exp.to_text())
-            #self.assertMessageIsAuthenticated(ress[i])
+            self.assertMessageIsAuthenticated(ress[i])
             self.assertRRsetInAnswer(ress[i], exp)
-            #self.assertMatchingRRSIGInAnswer(ress[i], exp)
+            self.assertMatchingRRSIGInAnswer(ress[i], exp)
             i = i + 1
 
-    def XXXOOOTimeout(self):
+    def testOOOTimeout(self):
         expected = {}
         queries = []
         for zone in ['25.delay1.example.', '1.delay2.example.']:
-            query = dns.message.make_query(zone, 'TXT', want_dnssec=False)
+            query = dns.message.make_query(zone, 'TXT', want_dnssec=True)
             query.flags |= dns.flags.AD
             queries.append(query)
 
@@ -50,8 +50,10 @@ class testOOOTCP(RecursorTest):
         self.assertEqual(len(ress), 2)
         exp = dns.rrset.from_text('1.delay2.example.', 0, dns.rdataclass.IN, 'TXT', 'a')
         self.assertRRsetInAnswer(ress[0], exp)
+        self.assertMatchingRRSIGInAnswer(ress[0], exp)
         self.assertRcodeEqual(ress[1], dns.rcode.SERVFAIL)
 
         # Let the auth timeout happen to not disturb other tests
+        # this can happen if the auth is single-threaded
         time.sleep(1)