]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
auth+rec secpoll: Combine secpoll result parsing code
authorPieter Lexis <pieter.lexis@powerdns.com>
Mon, 24 Jun 2019 11:42:14 +0000 (13:42 +0200)
committerPieter Lexis <pieter.lexis@powerdns.com>
Mon, 24 Jun 2019 11:42:14 +0000 (13:42 +0200)
pdns/Makefile.am
pdns/recursordist/Makefile.am
pdns/recursordist/secpoll.cc [new symlink]
pdns/recursordist/secpoll.hh [new symlink]
pdns/secpoll-auth.cc
pdns/secpoll-recursor.cc
pdns/secpoll.cc [new file with mode: 0644]
pdns/secpoll.hh [new file with mode: 0644]
pdns/stubresolver.cc
pdns/stubresolver.hh

index b29a58686c839ad1cb2612c118c713253933cb83..4f71e11908463761c38db28e64f309078e3b02bd 100644 (file)
@@ -207,6 +207,7 @@ pdns_server_SOURCES = \
        resolver.cc resolver.hh \
        responsestats.cc responsestats.hh responsestats-auth.cc \
        rfc2136handler.cc \
+       secpoll.cc secpoll.hh \
        secpoll-auth.cc secpoll-auth.hh \
        serialtweaker.cc \
        sha.hh \
index 12d93f680fd8040b3b8f54757be5ebd3a7d334ca..65a8e5b3d0b06be3bdebb749f0e3d1327ba155dc 100644 (file)
@@ -161,8 +161,8 @@ pdns_recursor_SOURCES = \
        root-addresses.hh \
        root-dnssec.hh \
        rpzloader.cc rpzloader.hh \
-       secpoll-recursor.cc \
-       secpoll-recursor.hh \
+       secpoll-recursor.cc secpoll-recursor.hh \
+       secpoll.cc secpoll.hh \
        sholder.hh \
        sillyrecords.cc \
        snmp-agent.hh snmp-agent.cc \
diff --git a/pdns/recursordist/secpoll.cc b/pdns/recursordist/secpoll.cc
new file mode 120000 (symlink)
index 0000000..997c393
--- /dev/null
@@ -0,0 +1 @@
+../secpoll.cc
\ No newline at end of file
diff --git a/pdns/recursordist/secpoll.hh b/pdns/recursordist/secpoll.hh
new file mode 120000 (symlink)
index 0000000..a1beadc
--- /dev/null
@@ -0,0 +1 @@
+../secpoll.hh
\ No newline at end of file
index a4d60561f532607b61236a17afd88733ab47e504..65ab81d3521f93594413bec4e62a88ed194842f0 100644 (file)
@@ -15,6 +15,7 @@
 #include "namespaces.hh"
 #include "statbag.hh"
 #include "stubresolver.hh"
+#include "secpoll.hh"
 #include "dnsrecords.hh"
 #include <stdint.h>
 #ifndef PACKAGEVERSION
@@ -35,8 +36,9 @@ void doSecPoll(bool first)
 
   struct timeval now;
   gettimeofday(&now, 0);
+  string pkgv(PACKAGEVERSION);
 
-  string version = "auth-" + string(PACKAGEVERSION);
+  string version = "auth-" + pkgv;
   string query = version.substr(0, 63) +".security-status."+::arg()["security-poll-suffix"];
 
   if(*query.rbegin()!='.')
@@ -47,33 +49,27 @@ void doSecPoll(bool first)
 
   int security_status = std::stoi(S.getValueStr("security-status"));
 
-  vector<DNSZoneRecord> ret;
-  int res=stubDoResolve(DNSName(query), QType::TXT, ret);
+  vector<DNSRecord> ret;
+  int res = stubDoResolve(DNSName(query), QType::TXT, ret);
 
-  if (res != 0) { // not NOERROR
-    if(security_status == 1) // it was ok, now it is unknown
-      S.set("security-status", 0);
-
-    string pkgv(PACKAGEVERSION);
-    if (std::count(pkgv.begin(), pkgv.end(), '.') > 2) {
-      g_log<<Logger::Warning<<"Not validating response for security status update, this is a non-release version."<<endl;
-      return;
-    }
-    g_log<<Logger::Warning<<"Could not retrieve security status update for '" + PACKAGEVERSION + "' on '"+ query + "', RCODE = "<< RCode::to_s(res)<<endl;
+  if (res == RCode::NXDomain && !isReleaseVersion(pkgv)) {
+    g_log<<Logger::Warning<<"Not validating response for security status update, this is a non-release version"<<endl;
     return;
   }
 
-  if (ret.empty()) { // empty NOERROR... wat?
-    if(security_status == 1) // it was ok, now it is unknown
-      S.set("security-status", 0);
-    g_log<<Logger::Warning<<"Could not retrieve security status update for '" + PACKAGEVERSION + "' on '"+ query + "', had empty answer, RCODE = "<< RCode::to_s(res)<<endl;
+  string security_message;
+
+  try {
+    processSecPoll(res, ret, security_status, security_message);
+  } catch(const PDNSException &pe) {
+    S.set("security-status", security_status);
+    g_log<<Logger::Warning<<"Could not retrieve security status update for '" + pkgv + "' on '"+ query + "': "<<pe.reason<<endl;
     return;
   }
 
-  string content=getRR<TXTRecordContent>(ret.begin()->dr)->d_text;
-  pair<string, string> split = splitField(unquotify(content), ' ');
-  security_status = std::stoi(split.first);
-  g_security_message = split.second;
+
+  S.set("security-status", security_status);
+  g_security_message = security_message;
 
   if(security_status == 1 && first) {
     g_log<<Logger::Warning << "Polled security status of version "<<PACKAGEVERSION<<" at startup, no known issues reported: " <<g_security_message<<endl;
@@ -84,6 +80,4 @@ void doSecPoll(bool first)
   if(security_status == 3) {
     g_log<<Logger::Error<<"PowerDNS Security Update Mandatory: "<<g_security_message<<endl;
   }
-
-  S.set("security-status", security_status);
 }
index 79717a75c65254d714594257b1f73b875b4d20c8..2e53ec0d474c846f902c669aad3f540cc9d069aa 100644 (file)
@@ -7,6 +7,7 @@
 #include "arguments.hh"
 #include "version.hh"
 #include "validate-recursor.hh"
+#include "secpoll.hh"
 
 #include <stdint.h>
 #ifndef PACKAGEVERSION 
@@ -36,7 +37,7 @@ void doSecPoll(time_t* last_secpoll)
   }
 
   vector<DNSRecord> ret;
-  
+
   string version = "recursor-" +pkgv;
   string qstring(version.substr(0, 63)+ ".security-status."+::arg()["security-poll-suffix"]);
 
@@ -48,7 +49,7 @@ void doSecPoll(time_t* last_secpoll)
 
   vState state = Indeterminate;
   DNSName query(qstring);
-  int res=sr.beginResolve(query, QType(QType::TXT), 1, ret);
+  int res = sr.beginResolve(query, QType(QType::TXT), 1, ret);
 
   if (g_dnssecmode != DNSSECMode::Off && res) {
     state = sr.getValidationState();
@@ -61,44 +62,33 @@ void doSecPoll(time_t* last_secpoll)
     return;
   }
 
-  if (res != 0) { // Not NOERROR
-    if(g_security_status == 1) // it was ok, now it is unknown
-      g_security_status = 0;
-
-    if (std::count(pkgv.begin(), pkgv.end(), '.') > 2) {
-      g_log<<Logger::Warning<<"Ignoring response for security status update, this is a non-release version."<<endl;
-      return;
-    }
-    g_log<<Logger::Warning<<"Could not retrieve security status update for '" +pkgv+ "' on '"<<query<<"', RCODE = "<< RCode::to_s(res)<<endl;
+  if (res == RCode::NXDomain && !isReleaseVersion(pkgv)) {
+    g_log<<Logger::Warning<<"Not validating response for security status update, this is a non-release version"<<endl;
     return;
   }
 
-  if (ret.empty()) { // Empty NOERROR
-    if(g_security_status == 1) // it was ok, now it is unknown
-      g_security_status = 0;
-    g_log<<Logger::Warning<<"Could not retrieve security status update for '" +pkgv+ "' on '"<<query<<"', had empty answer, RCODE = "<< RCode::to_s(res)<<endl;
+  string security_message;
+  int security_status = g_security_status;
+
+  try {
+    processSecPoll(res, ret, security_status, security_message);
+  } catch(const PDNSException &pe) {
+    g_security_status = security_status;
+    g_log<<Logger::Warning<<"Could not retrieve security status update for '" << pkgv << "' on '"<< query << "': "<<pe.reason<<endl;
     return;
   }
 
-  string content;
-  for(const auto&r : ret) {
-    if(r.d_type == QType::TXT)
-      content = r.d_content->getZoneRepresentation();
-  }
+  g_security_message = security_message;
 
-  if(!content.empty() && content[0]=='"' && content[content.size()-1]=='"') {
-    content=content.substr(1, content.length()-2);
+  if(g_security_status != 1 && security_status == 1) {
+    g_log<<Logger::Warning << "Polled security status of version "<<pkgv<<", no known issues reported: " <<g_security_message<<endl;
   }
-
-  pair<string, string> split = splitField(content, ' ');
-
-  g_security_status = std::stoi(split.first);
-  g_security_message = split.second;
-
-  if(g_security_status == 2) {
+  if(security_status == 2) {
     g_log<<Logger::Error<<"PowerDNS Security Update Recommended: "<<g_security_message<<endl;
   }
-  else if(g_security_status == 3) {
+  if(security_status == 3) {
     g_log<<Logger::Error<<"PowerDNS Security Update Mandatory: "<<g_security_message<<endl;
   }
+
+  g_security_status = security_status;
 }
diff --git a/pdns/secpoll.cc b/pdns/secpoll.cc
new file mode 100644 (file)
index 0000000..e919623
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <string>
+#include <vector>
+#include "dnsrecords.hh"
+#include "pdnsexception.hh"
+#include "misc.hh"
+
+bool isReleaseVersion(const std::string &version) {
+  return std::count(version.begin(), version.end(), '.') == 2;
+}
+
+void processSecPoll(const int res, const std::vector<DNSRecord> &ret, int &secPollStatus, std::string &secPollMessage) {
+  secPollMessage.clear();
+  if (res != 0) { // not NOERROR
+    if(secPollStatus == 1) // it was ok, now it is unknown
+      secPollStatus = 0;
+    throw PDNSException("RCODE was not NOERROR but " + RCode::to_s(res));
+  }
+
+  if (ret.empty()) { // empty NOERROR... wat?
+    if(secPollStatus == 1) // it was ok, now it is unknown
+      secPollStatus = 0;
+    throw PDNSException("Had empty answer on NOERROR RCODE");
+  }
+
+  DNSRecord record;
+  for (auto const &r: ret) {
+    if (r.d_type == QType::TXT && r.d_place == DNSResourceRecord::Place::ANSWER) {
+      record = r;
+      break;
+    }
+  }
+
+  if (record.d_name.empty()) {
+    throw PDNSException("No TXT record found in response");
+  }
+
+  auto recordContent = getRR<TXTRecordContent>(record);
+  if (recordContent == nullptr) {
+    throw PDNSException("Could not parse TXT record content");
+  }
+  string content = recordContent->d_text;
+
+  pair<string, string> split = splitField(unquotify(content), ' ');
+
+  try {
+    secPollStatus = std::stoi(split.first);
+  } catch (const std::exception &e) {
+    throw PDNSException(std::string("Could not parse status number: ") + e.what());
+  }
+  secPollMessage = split.second;
+}
diff --git a/pdns/secpoll.hh b/pdns/secpoll.hh
new file mode 100644 (file)
index 0000000..141bb83
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include <string>
+#include <vector>
+#include "dnsrecords.hh"
+
+/* Parses the result of a security poll, will throw a PDNSException when it could not be parsed, secPollStatus is
+ * set correctly regardless whether or not an exception was thrown.
+ *
+ * res: DNS Rcode result from the secpoll
+ * ret: Records returned during secpoll
+ * secPollStatus: The actual secpoll status, pass the current status in here and it is changed to the new status
+ * secPollMessage: Will be cleared and filled with the message from the secpoll message
+ */
+void processSecPoll(const int res, const std::vector<DNSRecord> &ret, int &secPollStatus, std::string &secPollMessage);
+bool isReleaseVersion(const std::string &version);
index 3068842bfa84b8a61d87ac92facbed27e799869b..8f593f9f22d557127011e3b299d9182b200f3169 100644 (file)
@@ -169,3 +169,12 @@ int stubDoResolve(const DNSName& qname, uint16_t qtype, vector<DNSZoneRecord>& r
   }
   return RCode::ServFail;
 }
+
+int stubDoResolve(const DNSName& qname, uint16_t qtype, vector<DNSRecord>& ret) {
+  vector<DNSZoneRecord> ret2;
+  int res = stubDoResolve(qname, qtype, ret2);
+  for (const auto &r : ret2) {
+    ret.push_back(r.dr);
+  }
+  return res;
+}
index bcbec421da07e5a572486257f7da5a9cdf8caa08..1cb94c8d4246438cd3e786833605605800e1a775 100644 (file)
@@ -26,3 +26,4 @@
 void stubParseResolveConf();
 bool resolversDefined();
 int stubDoResolve(const DNSName& qname, uint16_t qtype, vector<DNSZoneRecord>& ret);
+int stubDoResolve(const DNSName& qname, uint16_t qtype, vector<DNSRecord>& ret);