]> git.ipfire.org Git - thirdparty/pdns.git/blobdiff - pdns/dnsdist-web.cc
Merge pull request #9229 from rgacogne/dnsdist-webserver-allow-from
[thirdparty/pdns.git] / pdns / dnsdist-web.cc
index a089a9f6c3f17359998627d0b63a3cd5df031c28..5a738ca0ac5af60a616b91e14943e25deca45f8e 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-#include "dnsdist.hh"
-#include "dnsdist-healthchecks.hh"
-#include "dnsdist-prometheus.hh"
 
-#include "sstuff.hh"
-#include "ext/json11/json11.hpp"
-#include "ext/incbin/incbin.h"
-#include "dolog.hh"
-#include <thread>
-#include "threadname.hh"
+#include <boost/format.hpp>
 #include <sstream>
-#include <yahttp/yahttp.hpp>
-#include "namespaces.hh"
 #include <sys/time.h>
 #include <sys/resource.h>
+#include <thread>
+
 #include "ext/incbin/incbin.h"
-#include "htmlfiles.h"
+#include "ext/json11/json11.hpp"
+#include <yahttp/yahttp.hpp>
+
 #include "base64.hh"
+#include "dnsdist.hh"
+#include "dnsdist-healthchecks.hh"
+#include "dnsdist-prometheus.hh"
+#include "dnsdist-web.hh"
+#include "dolog.hh"
 #include "gettime.hh"
-#include  <boost/format.hpp>
+#include "htmlfiles.h"
+#include "threadname.hh"
+#include "sstuff.hh"
 
 bool g_apiReadWrite{false};
 WebserverConfig g_webserverConfig;
@@ -88,6 +89,8 @@ const std::map<std::string, MetricDefinition> MetricDefinitionStorage::metrics{
   { "dyn-blocked",            MetricDefinition(PrometheusMetricType::counter, "Number of queries dropped because of a dynamic block")},
   { "dyn-block-nmg-size",     MetricDefinition(PrometheusMetricType::gauge,   "Number of dynamic blocks entries") },
   { "security-status",        MetricDefinition(PrometheusMetricType::gauge,   "Security status of this software. 0=unknown, 1=OK, 2=upgrade recommended, 3=upgrade mandatory") },
+  { "doh-query-pipe-full",    MetricDefinition(PrometheusMetricType::counter, "Number of DoH queries dropped because the internal pipe used to distribute queries was full") },
+  { "doh-response-pipe-full", MetricDefinition(PrometheusMetricType::counter, "Number of DoH responses dropped because the internal pipe used to distribute responses was full") },
   { "udp-in-errors",          MetricDefinition(PrometheusMetricType::counter, "From /proc/net/snmp InErrors") },
   { "udp-noport-errors",      MetricDefinition(PrometheusMetricType::counter, "From /proc/net/snmp NoPorts") },
   { "udp-recvbuf-errors",     MetricDefinition(PrometheusMetricType::counter, "From /proc/net/snmp RcvbufErrors") },
@@ -221,6 +224,12 @@ static bool isMethodAllowed(const YaHTTP::Request& req)
   return false;
 }
 
+static bool isClientAllowedByACL(const ComboAddress& remote)
+{
+  std::lock_guard<std::mutex> lock(g_webserverConfig.lock);
+  return g_webserverConfig.acl.match(remote);
+}
+
 static void handleCORS(const YaHTTP::Request& req, YaHTTP::Response& resp)
 {
   const auto origin = req.headers.find("Origin");
@@ -395,15 +404,15 @@ static void connectionThread(int sock, ComboAddress remote)
         struct timespec now;
         gettime(&now);
         for(const auto& e: *nmg) {
-          if(now < e->second.until ) {
+          if(now < e.second.until ) {
             Json::object thing{
-              {"reason", e->second.reason},
-              {"seconds", (double)(e->second.until.tv_sec - now.tv_sec)},
-              {"blocks", (double)e->second.blocks},
-              {"action", DNSAction::typeToString(e->second.action != DNSAction::Action::None ? e->second.action : g_dynBlockAction) },
-              {"warning", e->second.warning }
+              {"reason", e.second.reason},
+              {"seconds", (double)(e.second.until.tv_sec - now.tv_sec)},
+              {"blocks", (double)e.second.blocks},
+              {"action", DNSAction::typeToString(e.second.action != DNSAction::Action::None ? e.second.action : g_dynBlockAction) },
+              {"warning", e.second.warning }
             };
-            obj.insert({e->first.toString(), thing});
+            obj.insert({e.first.toString(), thing});
           }
         }
 
@@ -500,7 +509,7 @@ static void connectionThread(int sock, ComboAddress remote)
         }
 
         // Latency histogram buckets
-        output << "# HELP dnsdist_latency Histogram of responses by latency\n";
+        output << "# HELP dnsdist_latency Histogram of responses by latency (in milliseconds)\n";
         output << "# TYPE dnsdist_latency histogram\n";
         uint64_t latency_amounts = g_stats.latency0_1;
         output << "dnsdist_latency_bucket{le=\"1\"} " << latency_amounts << "\n";
@@ -558,7 +567,7 @@ static void connectionThread(int sock, ComboAddress remote)
         for (const auto& state : *states) {
           string serverName;
 
-          if (state->name.empty())
+          if (state->getName().empty())
               serverName = state->remote.toStringWithPort();
           else
               serverName = state->getName();
@@ -821,7 +830,7 @@ static void connectionThread(int sock, ComboAddress remote)
 
        Json::object server{
          {"id", num++},
-         {"name", a->name},
+         {"name", a->getName()},
           {"address", a->remote.toStringWithPort()},
           {"state", status},
           {"qps", (double)a->queryLoad},
@@ -1226,6 +1235,17 @@ void setWebserverPassword(const std::string& password)
   g_webserverConfig.password = password;
 }
 
+void setWebserverACL(const std::string& acl)
+{
+  NetmaskGroup newACL;
+  newACL.toMasks(acl);
+
+  {
+    std::lock_guard<std::mutex> lock(g_webserverConfig.lock);
+    g_webserverConfig.acl = std::move(newACL);
+  }
+}
+
 void setWebserverCustomHeaders(const boost::optional<std::map<std::string, std::string> > customHeaders)
 {
   std::lock_guard<std::mutex> lock(g_webserverConfig.lock);
@@ -1237,15 +1257,21 @@ void dnsdistWebserverThread(int sock, const ComboAddress& local)
 {
   setThreadName("dnsdist/webserv");
   warnlog("Webserver launched on %s", local.toStringWithPort());
+
   for(;;) {
     try {
       ComboAddress remote(local);
       int fd = SAccept(sock, remote);
-      vinfolog("Got connection from %s", remote.toStringWithPort());
+      if (!isClientAllowedByACL(remote)) {
+        vinfolog("Connection to webserver from client %s is not allowed, closing", remote.toStringWithPort());
+        close(fd);
+        continue;
+      }
+      vinfolog("Got a connection to the webserver from %s", remote.toStringWithPort());
       std::thread t(connectionThread, fd, remote);
       t.detach();
     }
-    catch(std::exception& e) {
+    catch (const std::exception& e) {
       errlog("Had an error accepting new webserver connection: %s", e.what());
     }
   }