]> git.ipfire.org Git - thirdparty/pdns.git/blobdiff - pdns/dnsdist.hh
dnsdist: Add TCP management options from rfc7766 section 10
[thirdparty/pdns.git] / pdns / dnsdist.hh
index a91fd16e64e0567209007bcae865fb4f5651703c..eeb2a6d7d3e45ab049507c4a9e28f7e9fb282b59 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * 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 "config.h"
 #include "ext/luawrapper/include/LuaContext.hpp"
@@ -62,6 +83,7 @@ struct DNSDistStats
   stat_t dynBlocked{0};
   stat_t ruleDrop{0};
   stat_t ruleNXDomain{0};
+  stat_t ruleRefused{0};
   stat_t selfAnswered{0};
   stat_t downstreamTimeouts{0};
   stat_t downstreamSendErrors{0};
@@ -75,17 +97,29 @@ struct DNSDistStats
   typedef std::function<uint64_t(const std::string&)> statfunction_t;
   typedef boost::variant<stat_t*, double*, statfunction_t> entry_t;
   std::vector<std::pair<std::string, entry_t>> entries{
-    {"responses", &responses}, {"servfail-responses", &servfailResponses},
-    {"queries", &queries}, {"acl-drops", &aclDrops},
-    {"block-filter", &blockFilter}, {"rule-drop", &ruleDrop},
-    {"rule-nxdomain", &ruleNXDomain}, {"self-answered", &selfAnswered},
-    {"downstream-timeouts", &downstreamTimeouts}, {"downstream-send-errors", &downstreamSendErrors}, 
-    {"trunc-failures", &truncFail}, {"no-policy", &noPolicy},
-    {"latency0-1", &latency0_1}, {"latency1-10", &latency1_10},
-    {"latency10-50", &latency10_50}, {"latency50-100", &latency50_100}, 
-    {"latency100-1000", &latency100_1000}, {"latency-slow", &latencySlow},
-    {"latency-avg100", &latencyAvg100}, {"latency-avg1000", &latencyAvg1000}, 
-    {"latency-avg10000", &latencyAvg10000}, {"latency-avg1000000", &latencyAvg1000000},
+    {"responses", &responses},
+    {"servfail-responses", &servfailResponses},
+    {"queries", &queries},
+    {"acl-drops", &aclDrops},
+    {"block-filter", &blockFilter},
+    {"rule-drop", &ruleDrop},
+    {"rule-nxdomain", &ruleNXDomain},
+    {"rule-refused", &ruleRefused},
+    {"self-answered", &selfAnswered},
+    {"downstream-timeouts", &downstreamTimeouts},
+    {"downstream-send-errors", &downstreamSendErrors}, 
+    {"trunc-failures", &truncFail},
+    {"no-policy", &noPolicy},
+    {"latency0-1", &latency0_1},
+    {"latency1-10", &latency1_10},
+    {"latency10-50", &latency10_50},
+    {"latency50-100", &latency50_100},
+    {"latency100-1000", &latency100_1000},
+    {"latency-slow", &latencySlow},
+    {"latency-avg100", &latencyAvg100},
+    {"latency-avg1000", &latencyAvg1000},
+    {"latency-avg10000", &latencyAvg10000},
+    {"latency-avg1000000", &latencyAvg1000000},
     {"uptime", uptimeOfProcess},
     {"real-memory-usage", getRealMemoryUsage},
     {"noncompliant-queries", &nonCompliantQueries},
@@ -96,7 +130,8 @@ struct DNSDistStats
     {"cache-misses", &cacheMisses},
     {"cpu-user-msec", getCPUTimeUser},
     {"cpu-sys-msec", getCPUTimeSystem},
-    {"fd-usage", getOpenFileDescriptors}, {"dyn-blocked", &dynBlocked}, 
+    {"fd-usage", getOpenFileDescriptors},
+    {"dyn-blocked", &dynBlocked}, 
     {"dyn-block-nmg-size", [](const std::string&) { return g_dynblockNMG.getLocal()->size(); }}
   };
 };
@@ -234,6 +269,7 @@ struct IDState
   bool ednsAdded{false};
   bool ecsAdded{false};
   bool skipCache{false};
+  bool destHarvested{false}; // if true, origDest holds the original dest addr, otherwise the listening addr
 };
 
 struct Rings {
@@ -274,6 +310,21 @@ struct Rings {
 
 extern Rings g_rings;
 
+typedef std::unordered_map<string, unsigned int> QueryCountRecords;
+typedef std::function<std::tuple<bool, string>(DNSQuestion dq)> QueryCountFilter;
+struct QueryCount {
+  QueryCount()
+  {
+    pthread_rwlock_init(&queryLock, 0);
+  }
+  QueryCountRecords records;
+  QueryCountFilter filter;
+  pthread_rwlock_t queryLock;
+  bool enabled{false};
+};
+
+extern QueryCount g_qcount;
+
 struct ClientState
 {
   ComboAddress local;
@@ -283,27 +334,69 @@ struct ClientState
   std::atomic<uint64_t> queries{0};
   int udpFD{-1};
   int tcpFD{-1};
+
+  int getSocket() const
+  {
+    return udpFD != -1 ? udpFD : tcpFD;
+  }
+
+#ifdef HAVE_EBPF
+  shared_ptr<BPFFilter> d_filter;
+
+  void detachFilter()
+  {
+    if (d_filter) {
+      d_filter->removeSocket(getSocket());
+      d_filter = nullptr;
+    }
+  }
+
+  void attachFilter(shared_ptr<BPFFilter> bpf)
+  {
+    detachFilter();
+
+    bpf->addSocket(getSocket());
+    d_filter = bpf;
+  }
+#endif /* HAVE_EBPF */
 };
 
 class TCPClientCollection {
   std::vector<int> d_tcpclientthreads;
+  std::atomic<uint64_t> d_numthreads{0};
   std::atomic<uint64_t> d_pos{0};
-public:
-  std::atomic<uint64_t> d_queued{0}, d_numthreads{0};
+  std::atomic<uint64_t> d_queued{0};
   uint64_t d_maxthreads{0};
+  std::mutex d_mutex;
+public:
 
   TCPClientCollection(size_t maxThreads)
   {
     d_maxthreads = maxThreads;
     d_tcpclientthreads.reserve(maxThreads);
   }
-
   int getThread()
   {
     uint64_t pos = d_pos++;
     ++d_queued;
     return d_tcpclientthreads[pos % d_numthreads];
   }
+  bool hasReachedMaxThreads() const
+  {
+    return d_numthreads >= d_maxthreads;
+  }
+  uint64_t getThreadsCount() const
+  {
+    return d_numthreads;
+  }
+  uint64_t getQueuedCount() const
+  {
+    return d_queued;
+  }
+  void decrementQueuedCount()
+  {
+    --d_queued;
+  }
   void addTCPClientThread();
 };
 
@@ -355,6 +448,7 @@ struct DownstreamState
   bool mustResolve{false};
   bool upStatus{false};
   bool useECS{false};
+  bool setCD{false};
   bool isUp() const
   {
     if(availability == Availability::Down)
@@ -382,9 +476,13 @@ struct DownstreamState
 };
 using servers_t =vector<std::shared_ptr<DownstreamState>>;
 
+extern uint16_t g_ECSSourcePrefixV4;
+extern uint16_t g_ECSSourcePrefixV6;
+extern bool g_ECSOverride;
+
 struct DNSQuestion
 {
-  DNSQuestion(const DNSName* name, uint16_t type, uint16_t class_, const ComboAddress* lc, const ComboAddress* rem, struct dnsheader* header, size_t bufferSize, uint16_t queryLen, bool isTcp): qname(name), qtype(type), qclass(class_), local(lc), remote(rem), dh(header), size(bufferSize), len(queryLen), tcp(isTcp) { }
+  DNSQuestion(const DNSName* name, uint16_t type, uint16_t class_, const ComboAddress* lc, const ComboAddress* rem, struct dnsheader* header, size_t bufferSize, uint16_t queryLen, bool isTcp): qname(name), qtype(type), qclass(class_), local(lc), remote(rem), dh(header), size(bufferSize), len(queryLen), ecsPrefixLength(rem->sin4.sin_family == AF_INET ? g_ECSSourcePrefixV4 : g_ECSSourcePrefixV6), tcp(isTcp), ecsOverride(g_ECSOverride) { }
 
 #ifdef HAVE_PROTOBUF
   boost::uuids::uuid uniqueId;
@@ -397,8 +495,11 @@ struct DNSQuestion
   struct dnsheader* dh;
   size_t size;
   uint16_t len;
+  uint16_t ecsPrefixLength;
   const bool tcp;
   bool skipCache{false};
+  bool ecsOverride;
+  bool useECS{true};    
 };
 
 struct DNSResponse : DNSQuestion
@@ -436,7 +537,7 @@ public:
 class DNSAction
 {
 public:
-  enum class Action { Drop, Nxdomain, Spoof, Allow, HeaderModify, Pool, Delay, None};
+  enum class Action { Drop, Nxdomain, Refused, Spoof, Allow, HeaderModify, Pool, Delay, None};
   virtual Action operator()(DNSQuestion*, string* ruleresult) const =0;
   virtual string toString() const = 0;
   virtual std::unordered_map<string, double> getStats() const 
@@ -448,7 +549,7 @@ public:
 class DNSResponseAction
 {
 public:
-  enum class Action { None };
+  enum class Action { Allow, Delay, Drop, HeaderModify, None };
   virtual Action operator()(DNSResponse*, string* ruleresult) const =0;
   virtual string toString() const = 0;
 };
@@ -485,101 +586,8 @@ enum ednsHeaderFlags {
   EDNS_HEADER_FLAG_DO = 32768
 };
 
-/* Quest in life: serve as a rapid block list. If you add a DNSName to a root SuffixMatchNode, 
-   anything part of that domain will return 'true' in check */
-template<typename T>
-struct SuffixMatchTree
-{
-  SuffixMatchTree(const std::string& name_="", bool endNode_=false) : name(name_), endNode(endNode_)
-  {}
-
-  SuffixMatchTree(const SuffixMatchTree& rhs)
-  {
-    name = rhs.name;
-    d_human = rhs.d_human;
-    children = rhs.children;
-    endNode = rhs.endNode;
-    d_value = rhs.d_value;
-  }
-  std::string name;
-  std::string d_human;
-  mutable std::set<SuffixMatchTree> children;
-  mutable bool endNode;
-  mutable T d_value;
-  bool operator<(const SuffixMatchTree& rhs) const
-  {
-    return strcasecmp(name.c_str(), rhs.name.c_str()) < 0;
-  }
-  typedef SuffixMatchTree value_type;
-
-  template<typename V>
-  void visit(const V& v) const {
-    for(const auto& c : children) 
-      c.visit(v);
-    if(endNode)
-      v(*this);
-  }
-
-  void add(const DNSName& name, const T& t) 
-  {
-    add(name.getRawLabels(), t);
-  }
-
-  void add(std::vector<std::string> labels, const T& value) const
-  {
-    if(labels.empty()) { // this allows insertion of the root
-      endNode=true;
-      d_value=value;
-    }
-    else if(labels.size()==1) {
-      SuffixMatchTree newChild(*labels.begin(), true);
-      newChild.d_value=value;
-      children.insert(newChild);
-    }
-    else {
-      SuffixMatchTree newnode(*labels.rbegin(), false);
-      auto res=children.insert(newnode);
-      if(!res.second) {
-        children.erase(newnode);
-        res=children.insert(newnode);
-      }
-      labels.pop_back();
-      res.first->add(labels, value);
-    }
-  }
-
-  T* lookup(const DNSName& name)  const
-  {
-    if(children.empty()) { // speed up empty set
-      if(endNode)
-        return &d_value;
-      return 0;
-    }
-    return lookup(name.getRawLabels());
-  }
-
-  T* lookup(std::vector<std::string> labels) const
-  {
-    if(labels.empty()) { // optimization
-      if(endNode)
-        return &d_value;
-      return 0;
-    }
-
-    SuffixMatchTree smn(*labels.rbegin());
-    auto child = children.find(smn);
-    if(child == children.end()) {
-      if(endNode)
-        return &d_value;
-      return 0;
-    }
-    labels.pop_back();
-    return child->lookup(labels);
-  }
-  
-};
-
 extern GlobalStateHolder<SuffixMatchTree<DynBlock>> g_dynblockSMT;
+extern DNSAction::Action g_dynBlockAction;
 
 extern GlobalStateHolder<vector<CarbonConfig> > g_carbon;
 extern GlobalStateHolder<ServerPolicy> g_policy;
@@ -598,16 +606,21 @@ extern bool g_truncateTC;
 extern bool g_fixupCase;
 extern int g_tcpRecvTimeout;
 extern int g_tcpSendTimeout;
+extern int g_udpTimeout;
 extern uint16_t g_maxOutstanding;
 extern std::atomic<bool> g_configurationDone;
 extern uint64_t g_maxTCPClientThreads;
 extern uint64_t g_maxTCPQueuedConnections;
+extern size_t g_maxTCPQueriesPerConn;
+extern size_t g_maxTCPConnectionDuration;
+extern size_t g_maxTCPConnectionsPerClient;
 extern std::atomic<uint16_t> g_cacheCleaningDelay;
-extern uint16_t g_ECSSourcePrefixV4;
-extern uint16_t g_ECSSourcePrefixV6;
-extern bool g_ECSOverride;
+extern std::atomic<uint16_t> g_cacheCleaningPercentage;
 extern bool g_verboseHealthChecks;
 extern uint32_t g_staleCacheEntriesTTL;
+extern bool g_apiReadWrite;
+extern std::string g_apiConfigDirectory;
+extern bool g_servFailOnNoPolicy;
 
 struct ConsoleKeyword {
   std::string name;
@@ -629,6 +642,7 @@ extern const std::vector<ConsoleKeyword> g_consoleKeywords;
 
 #ifdef HAVE_EBPF
 extern shared_ptr<BPFFilter> g_defaultBPFFilter;
+extern std::vector<std::shared_ptr<DynBPFFilter> > g_dynBPFFilters;
 #endif /* HAVE_EBPF */
 
 struct dnsheader;
@@ -668,7 +682,7 @@ void resetLuaSideEffect(); // reset to indeterminate state
 bool responseContentMatches(const char* response, const uint16_t responseLen, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote);
 bool processQuery(LocalStateHolder<NetmaskTree<DynBlock> >& localDynBlockNMG,
                   LocalStateHolder<SuffixMatchTree<DynBlock> >& localDynBlockSMT, LocalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSAction> > > >& localRulactions, blockfilter_t blockFilter, DNSQuestion& dq, string& poolname, int* delayMsec, const struct timespec& now);
-bool processResponse(LocalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSResponseAction> > > >& localRespRulactions, DNSResponse& dr);
+bool processResponse(LocalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSResponseAction> > > >& localRespRulactions, DNSResponse& dr, int* delayMsec);
 bool fixUpResponse(char** response, uint16_t* responseLen, size_t* responseSize, const DNSName& qname, uint16_t origFlags, bool ednsAdded, bool ecsAdded, std::vector<uint8_t>& rewrittenResponse, uint16_t addRoom);
 void restoreFlags(struct dnsheader* dh, uint16_t origFlags);