+/*
+ * 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"
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};
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},
{"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(); }}
};
};
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 {
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;
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();
};
bool mustResolve{false};
bool upStatus{false};
bool useECS{false};
+ bool setCD{false};
bool isUp() const
{
if(availability == Availability::Down)
};
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;
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
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
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;
};
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;
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;
#ifdef HAVE_EBPF
extern shared_ptr<BPFFilter> g_defaultBPFFilter;
+extern std::vector<std::shared_ptr<DynBPFFilter> > g_dynBPFFilters;
#endif /* HAVE_EBPF */
struct dnsheader;
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);