-@ 86400 IN SOA pdns-public-ns1.powerdns.com. pieter\.lexis.powerdns.com. 2019040201 10800 3600 604800 10800
+@ 86400 IN SOA pdns-public-ns1.powerdns.com. pieter\.lexis.powerdns.com. 2019041201 10800 3600 604800 10800
@ 3600 IN NS pdns-public-ns1.powerdns.com.
@ 3600 IN NS pdns-public-ns2.powerdns.com.
; Auth
; dnsdist
dnsdist-1.3.3.security-status 60 IN TXT "1 OK"
+dnsdist-1.4.0-alpha1.security-status 60 IN TXT "1 OK"
vector<string> parts;
stringtok(parts, ips, " \t;,");
for(const auto& ip : parts)
- masters.push_back(ComboAddress(ip));
+ masters.push_back(ComboAddress(ip, 53));
return genChangeDomain(domain, [&masters](DomainInfo& di) {
di.masters = masters;
d_GetAllDomainMetadataQuery_stmt->nextRow(row);
ASSERT_ROW_COLUMNS("get-all-domain-metadata-query", row, 2);
- if (!isDnssecDomainMetadata(row[0]))
+ if (d_dnssecQueries || !isDnssecDomainMetadata(row[0]))
meta[row[0]].push_back(row[1]);
}
return string(buf);
}
-void DNSCryptContext::addNewCertificate(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, bool active)
+void DNSCryptContext::addNewCertificate(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, bool active, bool reload)
{
WriteLock w(&d_lock);
for (auto pair : certs) {
if (pair->cert.getSerial() == newCert.getSerial()) {
- throw std::runtime_error("Error adding a new certificate: we already have a certificate with the same serial");
+ if (reload) {
+ /* on reload we just assume that this is the same certificate */
+ return;
+ }
+ else {
+ throw std::runtime_error("Error adding a new certificate: we already have a certificate with the same serial");
+ }
}
}
certs.push_back(pair);
}
-void DNSCryptContext::loadNewCertificate(const std::string& certFile, const std::string& keyFile, bool active)
+void DNSCryptContext::loadNewCertificate(const std::string& certFile, const std::string& keyFile, bool active, bool reload)
{
DNSCryptCert newCert;
DNSCryptPrivateKey newPrivateKey;
loadCertFromFile(certFile, newCert);
newPrivateKey.loadFromFile(keyFile);
- addNewCertificate(newCert, newPrivateKey, active);
+ addNewCertificate(newCert, newPrivateKey, active, reload);
+ certificatePath = certFile;
+ keyPath = keyFile;
+}
+
+void DNSCryptContext::reloadCertificate()
+{
+ loadNewCertificate(certificatePath, keyPath, true, true);
}
void DNSCryptContext::markActive(uint32_t serial)
DNSCryptContext(const std::string& pName, const std::string& certFile, const std::string& keyFile);
DNSCryptContext(const std::string& pName, const DNSCryptCert& certificate, const DNSCryptPrivateKey& pKey);
- void loadNewCertificate(const std::string& certFile, const std::string& keyFile, bool active=true);
- void addNewCertificate(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, bool active=true);
+ void reloadCertificate();
+ void loadNewCertificate(const std::string& certFile, const std::string& keyFile, bool active=true, bool reload=false);
+ void addNewCertificate(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, bool active=true, bool reload=false);
void markActive(uint32_t serial);
void markInactive(uint32_t serial);
void removeInactiveCertificate(uint32_t serial);
pthread_rwlock_t d_lock;
std::vector<std::shared_ptr<DNSCryptCertificatePair>> certs;
DNSName providerName;
+ std::string certificatePath;
+ std::string keyPath;
};
bool generateDNSCryptCertificate(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, DNSCryptExchangeVersion version, DNSCryptCert& certOut, DNSCryptPrivateKey& keyOut);
{ "RCodeRule", true, "rcode", "matches responses with the specified rcode" },
{ "RegexRule", true, "regex", "matches the query name against the supplied regex" },
{ "registerDynBPFFilter", true, "DynBPFFilter", "register this dynamic BPF filter into the web interface so that its counters are displayed" },
+ { "reloadAllCertificates", true, "", "reload all DNSCrypt and TLS certificates, along with their associated keys" },
{ "RemoteLogAction", true, "RemoteLogger [, alterFunction [, serverID]]", "send the content of this query to a remote logger via Protocol Buffer. `alterFunction` is a callback, receiving a DNSQuestion and a DNSDistProtoBufMessage, that can be used to modify the Protocol Buffer content, for example for anonymization purposes. `serverID` is the server identifier." },
{ "RemoteLogResponseAction", true, "RemoteLogger [,alterFunction [,includeCNAME [, serverID]]]", "send the content of this response to a remote logger via Protocol Buffer. `alterFunction` is the same callback than the one in `RemoteLogAction` and `includeCNAME` indicates whether CNAME records inside the response should be parsed and exported. The default is to only exports A and AAAA records. `serverID` is the server identifier." },
{ "rmCacheHitResponseRule", true, "id", "remove cache hit response rule in position 'id', or whose uuid matches if 'id' is an UUID string" },
class DnstapLogAction : public DNSAction, public boost::noncopyable
{
public:
- DnstapLogAction(const std::string& identity, std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(const DNSQuestion&, DnstapMessage*)> > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(alterFunc)
+ DnstapLogAction(const std::string& identity, std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(alterFunc)
{
}
DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
if (d_alterFunc) {
std::lock_guard<std::mutex> lock(g_luamutex);
- (*d_alterFunc)(*dq, &message);
+ (*d_alterFunc)(dq, &message);
}
}
std::string data;
private:
std::string d_identity;
std::shared_ptr<RemoteLoggerInterface> d_logger;
- boost::optional<std::function<void(const DNSQuestion&, DnstapMessage*)> > d_alterFunc;
+ boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > d_alterFunc;
};
class RemoteLogAction : public DNSAction, public boost::noncopyable
{
public:
- RemoteLogAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(const DNSQuestion&, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID, const std::string& ipEncryptKey): d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID), d_ipEncryptKey(ipEncryptKey)
+ RemoteLogAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID, const std::string& ipEncryptKey): d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID), d_ipEncryptKey(ipEncryptKey)
{
}
DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
if (d_alterFunc) {
std::lock_guard<std::mutex> lock(g_luamutex);
- (*d_alterFunc)(*dq, &message);
+ (*d_alterFunc)(dq, &message);
}
std::string data;
}
private:
std::shared_ptr<RemoteLoggerInterface> d_logger;
- boost::optional<std::function<void(const DNSQuestion&, DNSDistProtoBufMessage*)> > d_alterFunc;
+ boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > d_alterFunc;
std::string d_serverID;
std::string d_ipEncryptKey;
};
class DnstapLogResponseAction : public DNSResponseAction, public boost::noncopyable
{
public:
- DnstapLogResponseAction(const std::string& identity, std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(const DNSResponse&, DnstapMessage*)> > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(alterFunc)
+ DnstapLogResponseAction(const std::string& identity, std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(alterFunc)
{
}
DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
{
if (d_alterFunc) {
std::lock_guard<std::mutex> lock(g_luamutex);
- (*d_alterFunc)(*dr, &message);
+ (*d_alterFunc)(dr, &message);
}
}
std::string data;
private:
std::string d_identity;
std::shared_ptr<RemoteLoggerInterface> d_logger;
- boost::optional<std::function<void(const DNSResponse&, DnstapMessage*)> > d_alterFunc;
+ boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > d_alterFunc;
};
class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopyable
{
public:
- RemoteLogResponseAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(const DNSResponse&, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID, const std::string& ipEncryptKey, bool includeCNAME): d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID), d_ipEncryptKey(ipEncryptKey), d_includeCNAME(includeCNAME)
+ RemoteLogResponseAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID, const std::string& ipEncryptKey, bool includeCNAME): d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID), d_ipEncryptKey(ipEncryptKey), d_includeCNAME(includeCNAME)
{
}
DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
if (d_alterFunc) {
std::lock_guard<std::mutex> lock(g_luamutex);
- (*d_alterFunc)(*dr, &message);
+ (*d_alterFunc)(dr, &message);
}
std::string data;
}
private:
std::shared_ptr<RemoteLoggerInterface> d_logger;
- boost::optional<std::function<void(const DNSResponse&, DNSDistProtoBufMessage*)> > d_alterFunc;
+ boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > d_alterFunc;
std::string d_serverID;
std::string d_ipEncryptKey;
bool d_includeCNAME;
return std::shared_ptr<DNSResponseAction>(new LuaResponseAction(func));
});
- g_lua.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSQuestion&, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<std::unordered_map<std::string, std::string>> vars) {
+ g_lua.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<std::unordered_map<std::string, std::string>> vars) {
// avoids potentially-evaluated-expression warning with clang.
RemoteLoggerInterface& rl = *logger.get();
if (typeid(rl) != typeid(RemoteLogger)) {
#endif
});
- g_lua.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSResponse&, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<bool> includeCNAME, boost::optional<std::unordered_map<std::string, std::string>> vars) {
+ g_lua.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<bool> includeCNAME, boost::optional<std::unordered_map<std::string, std::string>> vars) {
// avoids potentially-evaluated-expression warning with clang.
RemoteLoggerInterface& rl = *logger.get();
if (typeid(rl) != typeid(RemoteLogger)) {
#endif
});
- g_lua.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSQuestion&, DnstapMessage*)> > alterFunc) {
+ g_lua.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > alterFunc) {
#ifdef HAVE_PROTOBUF
return std::shared_ptr<DNSAction>(new DnstapLogAction(identity, logger, alterFunc));
#else
#endif
});
- g_lua.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSResponse&, DnstapMessage*)> > alterFunc) {
+ g_lua.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > alterFunc) {
#ifdef HAVE_PROTOBUF
return std::shared_ptr<DNSResponseAction>(new DnstapLogResponseAction(identity, logger, alterFunc));
#else
{"KEYTAG", EDNSOptionCode::KEYTAG }
});
- vector<pair<string, int> > rcodes = {{"NOERROR", RCode::NoError },
- {"FORMERR", RCode::FormErr },
- {"SERVFAIL", RCode::ServFail },
- {"NXDOMAIN", RCode::NXDomain },
- {"NOTIMP", RCode::NotImp },
- {"REFUSED", RCode::Refused },
- {"YXDOMAIN", RCode::YXDomain },
- {"YXRRSET", RCode::YXRRSet },
- {"NXRRSET", RCode::NXRRSet },
- {"NOTAUTH", RCode::NotAuth },
- {"NOTZONE", RCode::NotZone },
- {"BADVERS", ERCode::BADVERS },
- {"BADSIG", ERCode::BADSIG },
- {"BADKEY", ERCode::BADKEY },
- {"BADTIME", ERCode::BADTIME },
- {"BADMODE", ERCode::BADMODE },
- {"BADNAME", ERCode::BADNAME },
- {"BADALG", ERCode::BADALG },
- {"BADTRUNC", ERCode::BADTRUNC },
- {"BADCOOKIE",ERCode::BADCOOKIE },
- };
+ g_lua.writeVariable("DNSRCode", std::unordered_map<string, int>{
+ {"NOERROR", RCode::NoError },
+ {"FORMERR", RCode::FormErr },
+ {"SERVFAIL", RCode::ServFail },
+ {"NXDOMAIN", RCode::NXDomain },
+ {"NOTIMP", RCode::NotImp },
+ {"REFUSED", RCode::Refused },
+ {"YXDOMAIN", RCode::YXDomain },
+ {"YXRRSET", RCode::YXRRSet },
+ {"NXRRSET", RCode::NXRRSet },
+ {"NOTAUTH", RCode::NotAuth },
+ {"NOTZONE", RCode::NotZone },
+ {"BADVERS", ERCode::BADVERS },
+ {"BADSIG", ERCode::BADSIG },
+ {"BADKEY", ERCode::BADKEY },
+ {"BADTIME", ERCode::BADTIME },
+ {"BADMODE", ERCode::BADMODE },
+ {"BADNAME", ERCode::BADNAME },
+ {"BADALG", ERCode::BADALG },
+ {"BADTRUNC", ERCode::BADTRUNC },
+ {"BADCOOKIE",ERCode::BADCOOKIE }
+ });
+
vector<pair<string, int> > dd;
for(const auto& n : QType::names)
dd.push_back({n.first, n.second});
- for(const auto& n : rcodes)
- dd.push_back({n.first, n.second});
- g_lua.writeVariable("dnsdist", dd);
+ g_lua.writeVariable("DNSQType", dd);
+
+ g_lua.executeCode(R"LUA(
+ local tables = {
+ DNSQType = DNSQType,
+ DNSRCode = DNSRCode
+ }
+ local function index (table, key)
+ for tname,t in pairs(tables)
+ do
+ local val = t[key]
+ if val then
+ warnlog(string.format("access to dnsdist.%s is deprecated, please use %s.%s", key, tname, key))
+ return val
+ end
+ end
+ end
+
+ dnsdist = {}
+ setmetatable(dnsdist, { __index = index })
+ )LUA"
+ );
#ifdef HAVE_DNSCRYPT
g_lua.writeVariable("DNSCryptExchangeVersion", std::unordered_map<string,int>{
try {
ComboAddress loc(addr, 53);
- g_locals.clear();
- g_locals.push_back(std::make_tuple(loc, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus)); /// only works pre-startup, so no sync necessary
+ for (auto it = g_frontends.begin(); it != g_frontends.end(); ) {
+ /* TLS and DNSCrypt frontends are separate */
+ if ((*it)->tlsFrontend == nullptr && (*it)->dnscryptCtx == nullptr) {
+ it = g_frontends.erase(it);
+ }
+ else {
+ ++it;
+ }
+ }
+
+ // only works pre-startup, so no sync necessary
+ g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus)));
+ if (doTCP) {
+ g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus)));
+ }
}
- catch(std::exception& e) {
+ catch(const std::exception& e) {
g_outputBuffer="Error: "+string(e.what())+"\n";
}
});
try {
ComboAddress loc(addr, 53);
- g_locals.push_back(std::make_tuple(loc, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus)); /// only works pre-startup, so no sync necessary
+ // only works pre-startup, so no sync necessary
+ g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus)));
+ if (doTCP) {
+ g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus)));
+ }
}
catch(std::exception& e) {
g_outputBuffer="Error: "+string(e.what())+"\n";
try {
auto ctx = std::make_shared<DNSCryptContext>(providerName, certFile, keyFile);
- g_dnsCryptLocals.push_back(std::make_tuple(ComboAddress(addr, 443), ctx, reusePort, tcpFastOpenQueueSize, interface, cpus));
+
+ /* UDP */
+ auto cs = std::unique_ptr<ClientState>(new ClientState(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus));
+ cs->dnscryptCtx = ctx;
+ g_dnsCryptLocals.push_back(ctx);
+ g_frontends.push_back(std::move(cs));
+
+ /* TCP */
+ cs = std::unique_ptr<ClientState>(new ClientState(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus));
+ cs->dnscryptCtx = ctx;
+ g_frontends.push_back(std::move(cs));
}
catch(std::exception& e) {
errlog(e.what());
ret << (fmt % "#" % "Address" % "Provider Name") << endl;
size_t idx = 0;
- for (const auto& local : g_dnsCryptLocals) {
- const std::shared_ptr<DNSCryptContext> ctx = std::get<1>(local);
- ret<< (fmt % idx % std::get<0>(local).toStringWithPort() % ctx->getProviderName()) << endl;
+ for (const auto& frontend : g_frontends) {
+ const std::shared_ptr<DNSCryptContext> ctx = frontend->dnscryptCtx;
+ ret<< (fmt % idx % frontend->local.toStringWithPort() % ctx->getProviderName()) << endl;
idx++;
}
#ifdef HAVE_DNSCRYPT
std::shared_ptr<DNSCryptContext> ret = nullptr;
if (idx < g_dnsCryptLocals.size()) {
- ret = std::get<1>(g_dnsCryptLocals.at(idx));
+ ret = g_dnsCryptLocals.at(idx);
}
return ret;
#else
setLuaNoSideEffect();
ClientState* ret = nullptr;
if(num < g_frontends.size()) {
- ret=g_frontends[num];
+ ret=g_frontends[num].get();
}
return ret;
});
g_servFailOnNoPolicy = servfail;
});
+ g_lua.writeFunction("setRoundRobinFailOnNoServer", [](bool fail) {
+ setLuaSideEffect();
+ g_roundrobinFailOnNoServer = fail;
+ });
+
g_lua.writeFunction("setRingBuffersSize", [](size_t capacity, boost::optional<size_t> numberOfShards) {
setLuaSideEffect();
if (g_configurationDone) {
return;
}
+ bool doTCP = true;
+ bool reusePort = false;
+ int tcpFastOpenQueueSize = 0;
+ std::string interface;
+ std::set<int> cpus;
+ (void) doTCP;
+
if (vars) {
bool doTCP = true;
- parseLocalBindVars(vars, doTCP, frontend->d_reusePort, frontend->d_tcpFastOpenQueueSize, frontend->d_interface, frontend->d_cpus);
+ parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus);
if (vars->count("provider")) {
frontend->d_provider = boost::get<const string>((*vars)["provider"]);
try {
frontend->d_addr = ComboAddress(addr, 853);
vinfolog("Loading TLS provider %s", frontend->d_provider);
- g_tlslocals.push_back(frontend); /// only works pre-startup, so no sync necessary
+ // only works pre-startup, so no sync necessary
+ auto cs = std::unique_ptr<ClientState>(new ClientState(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus));
+ cs->tlsFrontend = frontend;
+ g_tlslocals.push_back(cs->tlsFrontend);
+ g_frontends.push_back(std::move(cs));
}
catch(const std::exception& e) {
g_outputBuffer="Error: "+string(e.what())+"\n";
#endif
});
- g_lua.writeFunction("setAllowEmptyResponse", [](bool allow) { g_allowEmptyResponse=allow; });
+ g_lua.writeFunction("reloadAllCertificates", []() {
+ for (auto& frontend : g_frontends) {
+ if (!frontend) {
+ continue;
+ }
+ try {
+#ifdef HAVE_DNSCRYPT
+ if (frontend->dnscryptCtx) {
+ frontend->dnscryptCtx->reloadCertificate();
+ }
+#endif /* HAVE_DNSCRYPT */
+#ifdef HAVE_DNS_OVER_TLS
+ if (frontend->tlsFrontend) {
+ frontend->tlsFrontend->setupTLS();
+ }
+#endif /* HAVE_DNS_OVER_TLS */
+ }
+ catch(const std::exception& e) {
+ errlog("Error reloading certificates for frontend %s: %s", frontend->local.toStringWithPort(), e.what());
+ }
+ }
+ });
+
+ g_lua.writeFunction("setAllowEmptyResponse", [](bool allow) { g_allowEmptyResponse=allow; });
}
vector<std::function<void(void)>> setupLua(bool client, const std::string& config)
ConnectionInfo(ClientState* cs_): cs(cs_), fd(-1)
{
}
- ConnectionInfo(ConnectionInfo&& rhs)
+ ConnectionInfo(ConnectionInfo&& rhs): remote(rhs.remote), cs(rhs.cs), fd(rhs.fd)
{
- remote = rhs.remote;
- cs = rhs.cs;
rhs.cs = nullptr;
- fd = rhs.fd;
rhs.fd = -1;
}
acl+=s;
}
string localaddresses;
- for(const auto& loc : g_locals) {
- if(!localaddresses.empty()) localaddresses += ", ";
- localaddresses += std::get<0>(loc).toStringWithPort();
+ for(const auto& front : g_frontends) {
+ if (front->tcp) {
+ continue;
+ }
+ if (!localaddresses.empty()) {
+ localaddresses += ", ";
+ }
+ localaddresses += front->local.toStringWithPort();
}
Json my_json = Json::object {
GlobalStateHolder<NetmaskGroup> g_ACL;
string g_outputBuffer;
-vector<std::tuple<ComboAddress, bool, bool, int, string, std::set<int>>> g_locals;
std::vector<std::shared_ptr<TLSFrontend>> g_tlslocals;
-std::vector<std::tuple<ComboAddress,std::shared_ptr<DNSCryptContext>,bool, int, string, std::set<int> >> g_dnsCryptLocals;
+std::vector<std::shared_ptr<DNSCryptContext>> g_dnsCryptLocals;
#ifdef HAVE_EBPF
shared_ptr<BPFFilter> g_defaultBPFFilter;
std::vector<std::shared_ptr<DynBPFFilter> > g_dynBPFFilters;
#endif /* HAVE_EBPF */
-vector<ClientState *> g_frontends;
+std::vector<std::unique_ptr<ClientState>> g_frontends;
GlobalStateHolder<pools_t> g_pools;
size_t g_udpVectorSize{1};
bool g_truncateTC{false};
bool g_fixupCase{false};
bool g_preserveTrailingData{false};
+bool g_roundrobinFailOnNoServer{false};
static void truncateTC(char* packet, uint16_t* len, size_t responseSize, unsigned int consumed)
try
}
const auto *res=&poss;
- if(poss.empty())
+ if(poss.empty() && !g_roundrobinFailOnNoServer)
res = &servers;
if(res->empty())
bool countQuery{true};
if(g_qcount.filter) {
std::lock_guard<std::mutex> lock(g_luamutex);
- std::tie (countQuery, qname) = g_qcount.filter(dq);
+ std::tie (countQuery, qname) = g_qcount.filter(&dq);
}
if(countQuery) {
}
}
+static void setUpLocalBind(std::unique_ptr<ClientState>& cs)
+{
+ /* skip some warnings if there is an identical UDP context */
+ bool warn = cs->tcp == false || cs->tlsFrontend != nullptr;
+ int& fd = cs->tcp == false ? cs->udpFD : cs->tcpFD;
+ (void) warn;
+
+ fd = SSocket(cs->local.sin4.sin_family, cs->tcp == false ? SOCK_DGRAM : SOCK_STREAM, 0);
+
+ if (cs->tcp) {
+ SSetsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 1);
+#ifdef TCP_DEFER_ACCEPT
+ SSetsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, 1);
+#endif
+ if (cs->fastOpenQueueSize > 0) {
+#ifdef TCP_FASTOPEN
+ SSetsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, cs->fastOpenQueueSize);
+#else
+ if (warn) {
+ warnlog("TCP Fast Open has been configured on local address '%s' but is not supported", cs->local.toStringWithPort());
+ }
+#endif
+ }
+ }
+
+ if(cs->local.sin4.sin_family == AF_INET6) {
+ SSetsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, 1);
+ }
+
+ bindAny(cs->local.sin4.sin_family, fd);
+
+ if(!cs->tcp && IsAnyAddress(cs->local)) {
+ int one=1;
+ setsockopt(fd, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
+#ifdef IPV6_RECVPKTINFO
+ setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
+#endif
+ }
+
+ if (cs->reuseport) {
+#ifdef SO_REUSEPORT
+ SSetsockopt(fd, SOL_SOCKET, SO_REUSEPORT, 1);
+#else
+ if (warn) {
+ /* no need to warn again if configured but support is not available, we already did for UDP */
+ warnlog("SO_REUSEPORT has been configured on local address '%s' but is not supported", cs->local.toStringWithPort());
+ }
+#endif
+ }
+
+ const std::string& itf = cs->interface;
+ if (!itf.empty()) {
+#ifdef SO_BINDTODEVICE
+ int res = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, itf.c_str(), itf.length());
+ if (res != 0) {
+ warnlog("Error setting up the interface on local address '%s': %s", cs->local.toStringWithPort(), strerror(errno));
+ }
+#else
+ if (warn) {
+ warnlog("An interface has been configured on local address '%s' but SO_BINDTODEVICE is not supported", cs->local.toStringWithPort());
+ }
+#endif
+ }
+
+#ifdef HAVE_EBPF
+ if (g_defaultBPFFilter) {
+ cs->attachFilter(g_defaultBPFFilter);
+ vinfolog("Attaching default BPF Filter to %s frontend %s", (!cs->tcp ? "UDP" : "TCP"), cs->local.toStringWithPort());
+ }
+#endif /* HAVE_EBPF */
+
+ if (cs->tlsFrontend != nullptr) {
+ if (!cs->tlsFrontend->setupTLS()) {
+ errlog("Error while setting up TLS on local address '%s', exiting", cs->local.toStringWithPort());
+ _exit(EXIT_FAILURE);
+ }
+ }
+
+ SBind(fd, cs->local);
+
+ if (cs->tcp) {
+ SListen(cs->tcpFD, 64);
+ if (cs->tlsFrontend != nullptr) {
+ warnlog("Listening on %s for TLS", cs->local.toStringWithPort());
+ }
+ else if (cs->dnscryptCtx != nullptr) {
+ warnlog("Listening on %s for DNSCrypt", cs->local.toStringWithPort());
+ }
+ else {
+ warnlog("Listening on %s", cs->local.toStringWithPort());
+ }
+ }
+
+ cs->ready = true;
+}
+
struct
{
vector<string> locals;
}
}
- if(g_cmdLine.locals.size()) {
- g_locals.clear();
- for(auto loc : g_cmdLine.locals)
- g_locals.push_back(std::make_tuple(ComboAddress(loc, 53), true, false, 0, "", std::set<int>()));
- }
-
- if(g_locals.empty())
- g_locals.push_back(std::make_tuple(ComboAddress("127.0.0.1", 53), true, false, 0, "", std::set<int>()));
-
- g_configurationDone = true;
-
- vector<ClientState*> toLaunch;
- for(const auto& local : g_locals) {
- ClientState* cs = new ClientState;
- cs->local= std::get<0>(local);
- cs->udpFD = SSocket(cs->local.sin4.sin_family, SOCK_DGRAM, 0);
- if(cs->local.sin4.sin_family == AF_INET6) {
- SSetsockopt(cs->udpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1);
- }
- //if(g_vm.count("bind-non-local"))
- bindAny(cs->local.sin4.sin_family, cs->udpFD);
-
- // if (!setSocketTimestamps(cs->udpFD))
- // g_log<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
-
-
- if(IsAnyAddress(cs->local)) {
- int one=1;
- setsockopt(cs->udpFD, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
-#ifdef IPV6_RECVPKTINFO
- setsockopt(cs->udpFD, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
-#endif
- }
-
- if (std::get<2>(local)) {
-#ifdef SO_REUSEPORT
- SSetsockopt(cs->udpFD, SOL_SOCKET, SO_REUSEPORT, 1);
-#else
- warnlog("SO_REUSEPORT has been configured on local address '%s' but is not supported", std::get<0>(local).toStringWithPort());
-#endif
- }
-
- const std::string& itf = std::get<4>(local);
- if (!itf.empty()) {
-#ifdef SO_BINDTODEVICE
- int res = setsockopt(cs->udpFD, SOL_SOCKET, SO_BINDTODEVICE, itf.c_str(), itf.length());
- if (res != 0) {
- warnlog("Error setting up the interface on local address '%s': %s", std::get<0>(local).toStringWithPort(), strerror(errno));
+ if (!g_cmdLine.locals.empty()) {
+ for (auto it = g_frontends.begin(); it != g_frontends.end(); ) {
+ /* TLS and DNSCrypt frontends are separate */
+ if ((*it)->tlsFrontend == nullptr && (*it)->dnscryptCtx == nullptr) {
+ it = g_frontends.erase(it);
}
-#else
- warnlog("An interface has been configured on local address '%s' but SO_BINDTODEVICE is not supported", std::get<0>(local).toStringWithPort());
-#endif
- }
-
-#ifdef HAVE_EBPF
- if (g_defaultBPFFilter) {
- cs->attachFilter(g_defaultBPFFilter);
- vinfolog("Attaching default BPF Filter to UDP frontend %s", cs->local.toStringWithPort());
- }
-#endif /* HAVE_EBPF */
-
- cs->cpus = std::get<5>(local);
-
- SBind(cs->udpFD, cs->local);
- toLaunch.push_back(cs);
- g_frontends.push_back(cs);
- udpBindsCount++;
- }
-
- for(const auto& local : g_locals) {
- if(!std::get<1>(local)) { // no TCP/IP
- warnlog("Not providing TCP/IP service on local address '%s'", std::get<0>(local).toStringWithPort());
- continue;
- }
- ClientState* cs = new ClientState;
- cs->local= std::get<0>(local);
-
- cs->tcpFD = SSocket(cs->local.sin4.sin_family, SOCK_STREAM, 0);
-
- SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEADDR, 1);
-#ifdef TCP_DEFER_ACCEPT
- SSetsockopt(cs->tcpFD, IPPROTO_TCP, TCP_DEFER_ACCEPT, 1);
-#endif
- if (std::get<3>(local) > 0) {
-#ifdef TCP_FASTOPEN
- SSetsockopt(cs->tcpFD, IPPROTO_TCP, TCP_FASTOPEN, std::get<3>(local));
-#else
- warnlog("TCP Fast Open has been configured on local address '%s' but is not supported", std::get<0>(local).toStringWithPort());
-#endif
- }
- if(cs->local.sin4.sin_family == AF_INET6) {
- SSetsockopt(cs->tcpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1);
- }
-#ifdef SO_REUSEPORT
- /* no need to warn again if configured but support is not available, we already did for UDP */
- if (std::get<2>(local)) {
- SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEPORT, 1);
- }
-#endif
-
- const std::string& itf = std::get<4>(local);
- if (!itf.empty()) {
-#ifdef SO_BINDTODEVICE
- int res = setsockopt(cs->tcpFD, SOL_SOCKET, SO_BINDTODEVICE, itf.c_str(), itf.length());
- if (res != 0) {
- warnlog("Error setting up the interface on local address '%s': %s", std::get<0>(local).toStringWithPort(), strerror(errno));
+ else {
+ ++it;
}
-#else
- warnlog("An interface has been configured on local address '%s' but SO_BINDTODEVICE is not supported", std::get<0>(local).toStringWithPort());
-#endif
}
-#ifdef HAVE_EBPF
- if (g_defaultBPFFilter) {
- cs->attachFilter(g_defaultBPFFilter);
- vinfolog("Attaching default BPF Filter to TCP frontend %s", cs->local.toStringWithPort());
+ for(const auto& loc : g_cmdLine.locals) {
+ /* UDP */
+ g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress(loc, 53), false, false, 0, "", {})));
+ /* TCP */
+ g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress(loc, 53), true, false, 0, "", {})));
}
-#endif /* HAVE_EBPF */
-
- // if(g_vm.count("bind-non-local"))
- bindAny(cs->local.sin4.sin_family, cs->tcpFD);
- SBind(cs->tcpFD, cs->local);
- SListen(cs->tcpFD, 64);
- warnlog("Listening on %s", cs->local.toStringWithPort());
-
- toLaunch.push_back(cs);
- g_frontends.push_back(cs);
- tcpBindsCount++;
}
- for(auto& dcLocal : g_dnsCryptLocals) {
- ClientState* cs = new ClientState;
- cs->local = std::get<0>(dcLocal);
- cs->dnscryptCtx = std::get<1>(dcLocal);
- cs->udpFD = SSocket(cs->local.sin4.sin_family, SOCK_DGRAM, 0);
- if(cs->local.sin4.sin_family == AF_INET6) {
- SSetsockopt(cs->udpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1);
- }
- bindAny(cs->local.sin4.sin_family, cs->udpFD);
- if(IsAnyAddress(cs->local)) {
- int one=1;
- setsockopt(cs->udpFD, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
-#ifdef IPV6_RECVPKTINFO
- setsockopt(cs->udpFD, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
-#endif
- }
- if (std::get<2>(dcLocal)) {
-#ifdef SO_REUSEPORT
- SSetsockopt(cs->udpFD, SOL_SOCKET, SO_REUSEPORT, 1);
-#else
- warnlog("SO_REUSEPORT has been configured on local address '%s' but is not supported", std::get<0>(dcLocal).toStringWithPort());
-#endif
- }
-
- const std::string& itf = std::get<4>(dcLocal);
- if (!itf.empty()) {
-#ifdef SO_BINDTODEVICE
- int res = setsockopt(cs->udpFD, SOL_SOCKET, SO_BINDTODEVICE, itf.c_str(), itf.length());
- if (res != 0) {
- warnlog("Error setting up the interface on local address '%s': %s", std::get<0>(dcLocal).toStringWithPort(), strerror(errno));
- }
-#else
- warnlog("An interface has been configured on local address '%s' but SO_BINDTODEVICE is not supported", std::get<0>(dcLocal).toStringWithPort());
-#endif
- }
-
-#ifdef HAVE_EBPF
- if (g_defaultBPFFilter) {
- cs->attachFilter(g_defaultBPFFilter);
- vinfolog("Attaching default BPF Filter to UDP DNSCrypt frontend %s", cs->local.toStringWithPort());
- }
-#endif /* HAVE_EBPF */
- SBind(cs->udpFD, cs->local);
- toLaunch.push_back(cs);
- g_frontends.push_back(cs);
- udpBindsCount++;
-
- cs = new ClientState;
- cs->local = std::get<0>(dcLocal);
- cs->dnscryptCtx = std::get<1>(dcLocal);
- cs->tcpFD = SSocket(cs->local.sin4.sin_family, SOCK_STREAM, 0);
- SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEADDR, 1);
-#ifdef TCP_DEFER_ACCEPT
- SSetsockopt(cs->tcpFD, IPPROTO_TCP, TCP_DEFER_ACCEPT, 1);
-#endif
- if (std::get<3>(dcLocal) > 0) {
-#ifdef TCP_FASTOPEN
- SSetsockopt(cs->tcpFD, IPPROTO_TCP, TCP_FASTOPEN, std::get<3>(dcLocal));
-#else
- warnlog("TCP Fast Open has been configured on local address '%s' but is not supported", std::get<0>(dcLocal).toStringWithPort());
-#endif
- }
-
-#ifdef SO_REUSEPORT
- /* no need to warn again if configured but support is not available, we already did for UDP */
- if (std::get<2>(dcLocal)) {
- SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEPORT, 1);
- }
-#endif
-
- if (!itf.empty()) {
-#ifdef SO_BINDTODEVICE
- int res = setsockopt(cs->tcpFD, SOL_SOCKET, SO_BINDTODEVICE, itf.c_str(), itf.length());
- if (res != 0) {
- warnlog("Error setting up the interface on local address '%s': %s", std::get<0>(dcLocal).toStringWithPort(), strerror(errno));
- }
-#else
- warnlog("An interface has been configured on local address '%s' but SO_BINDTODEVICE is not supported", std::get<0>(dcLocal).toStringWithPort());
-#endif
- }
-
- if(cs->local.sin4.sin_family == AF_INET6) {
- SSetsockopt(cs->tcpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1);
- }
-#ifdef HAVE_EBPF
- if (g_defaultBPFFilter) {
- cs->attachFilter(g_defaultBPFFilter);
- vinfolog("Attaching default BPF Filter to TCP DNSCrypt frontend %s", cs->local.toStringWithPort());
- }
-#endif /* HAVE_EBPF */
-
- cs->cpus = std::get<5>(dcLocal);
-
- bindAny(cs->local.sin4.sin_family, cs->tcpFD);
- SBind(cs->tcpFD, cs->local);
- SListen(cs->tcpFD, 64);
- warnlog("Listening on %s", cs->local.toStringWithPort());
- toLaunch.push_back(cs);
- g_frontends.push_back(cs);
- tcpBindsCount++;
+ if (g_frontends.empty()) {
+ /* UDP */
+ g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress("127.0.0.1", 53), false, false, 0, "", {})));
+ /* TCP */
+ g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress("127.0.0.1", 53), true, false, 0, "", {})));
}
- for(auto& frontend : g_tlslocals) {
- ClientState* cs = new ClientState;
- cs->local = frontend->d_addr;
- cs->tcpFD = SSocket(cs->local.sin4.sin_family, SOCK_STREAM, 0);
- SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEADDR, 1);
-#ifdef TCP_DEFER_ACCEPT
- SSetsockopt(cs->tcpFD, IPPROTO_TCP, TCP_DEFER_ACCEPT, 1);
-#endif
- if (frontend->d_tcpFastOpenQueueSize > 0) {
-#ifdef TCP_FASTOPEN
- SSetsockopt(cs->tcpFD, IPPROTO_TCP, TCP_FASTOPEN, frontend->d_tcpFastOpenQueueSize);
-#else
- warnlog("TCP Fast Open has been configured on local address '%s' but is not supported", cs->local.toStringWithPort());
-#endif
- }
- if (frontend->d_reusePort) {
-#ifdef SO_REUSEPORT
- SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEPORT, 1);
-#else
- warnlog("SO_REUSEPORT has been configured on local address '%s' but is not supported", cs->local.toStringWithPort());
-#endif
- }
- if(cs->local.sin4.sin_family == AF_INET6) {
- SSetsockopt(cs->tcpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1);
- }
-
- if (!frontend->d_interface.empty()) {
-#ifdef SO_BINDTODEVICE
- int res = setsockopt(cs->tcpFD, SOL_SOCKET, SO_BINDTODEVICE, frontend->d_interface.c_str(), frontend->d_interface.length());
- if (res != 0) {
- warnlog("Error setting up the interface on local address '%s': %s", cs->local.toStringWithPort(), strerror(errno));
- }
-#else
- warnlog("An interface has been configured on local address '%s' but SO_BINDTODEVICE is not supported", cs->local.toStringWithPort());
-#endif
- }
+ g_configurationDone = true;
- cs->cpus = frontend->d_cpus;
+ for(auto& frontend : g_frontends) {
+ setUpLocalBind(frontend);
- bindAny(cs->local.sin4.sin_family, cs->tcpFD);
- if (frontend->setupTLS()) {
- cs->tlsFrontend = frontend;
- SBind(cs->tcpFD, cs->local);
- SListen(cs->tcpFD, 64);
- warnlog("Listening on %s for TLS", cs->local.toStringWithPort());
- toLaunch.push_back(cs);
- g_frontends.push_back(cs);
- tcpBindsCount++;
+ if (frontend->tcp == false) {
+ ++udpBindsCount;
}
else {
- errlog("Error while setting up TLS on local address '%s', exiting", cs->local.toStringWithPort());
- delete cs;
- _exit(EXIT_FAILURE);
+ ++tcpBindsCount;
}
}
}
}
- for(auto& cs : toLaunch) {
+ for(auto& cs : g_frontends) {
if (cs->udpFD >= 0) {
- thread t1(udpClientThread, cs);
+ thread t1(udpClientThread, cs.get());
if (!cs->cpus.empty()) {
mapThreadToCPUList(t1.native_handle(), cs->cpus);
}
t1.detach();
}
else if (cs->tcpFD >= 0) {
- thread t1(tcpAcceptorThread, cs);
+ thread t1(tcpAcceptorThread, cs.get());
if (!cs->cpus.empty()) {
mapThreadToCPUList(t1.native_handle(), cs->cpus);
}
const uint16_t* flags = getFlagsFromDNSHeader(dh);
origFlags = *flags;
}
+ DNSQuestion(const DNSQuestion&) = delete;
+ DNSQuestion& operator=(const DNSQuestion&) = delete;
+ DNSQuestion(DNSQuestion&&) = default;
#ifdef HAVE_PROTOBUF
boost::optional<boost::uuids::uuid> uniqueId;
{
DNSResponse(const DNSName* name, uint16_t type, uint16_t class_, unsigned int consumed, const ComboAddress* lc, const ComboAddress* rem, struct dnsheader* header, size_t bufferSize, uint16_t responseLen, bool isTcp, const struct timespec* queryTime_):
DNSQuestion(name, type, class_, consumed, lc, rem, header, bufferSize, responseLen, isTcp, queryTime_) { }
+ DNSResponse(const DNSResponse&) = delete;
+ DNSResponse& operator=(const DNSResponse&) = delete;
+ DNSResponse(DNSResponse&&) = default;
};
/* so what could you do:
};
typedef std::unordered_map<string, unsigned int> QueryCountRecords;
-typedef std::function<std::tuple<bool, string>(DNSQuestion dq)> QueryCountFilter;
+typedef std::function<std::tuple<bool, string>(const DNSQuestion* dq)> QueryCountFilter;
struct QueryCount {
QueryCount()
{
struct ClientState
{
+ ClientState(const ComboAddress& local_, bool isTCP, bool doReusePort, int fastOpenQueue, const std::string& itfName, const std::set<int>& cpus_): cpus(cpus_), local(local_), interface(itfName), fastOpenQueueSize(fastOpenQueue), tcp(isTCP), reuseport(doReusePort)
+ {
+ }
+
std::set<int> cpus;
ComboAddress local;
std::shared_ptr<DNSCryptContext> dnscryptCtx{nullptr};
- shared_ptr<TLSFrontend> tlsFrontend;
+ std::shared_ptr<TLSFrontend> tlsFrontend{nullptr};
+ std::string interface;
std::atomic<uint64_t> queries{0};
std::atomic<uint64_t> tcpDiedReadingQuery{0};
std::atomic<uint64_t> tcpDiedSendingResponse{0};
std::atomic<double> tcpAvgConnectionDuration{0.0};
int udpFD{-1};
int tcpFD{-1};
+ int fastOpenQueueSize{0};
bool muted{false};
+ bool tcp;
+ bool reuseport;
+ bool ready{false};
int getSocket() const
{
extern std::vector<std::tuple<ComboAddress, bool, bool, int, std::string, std::set<int>>> g_locals; // not changed at runtime (we hope XXX)
extern std::vector<shared_ptr<TLSFrontend>> g_tlslocals;
-extern vector<ClientState*> g_frontends;
+extern std::vector<std::unique_ptr<ClientState>> g_frontends;
extern bool g_truncateTC;
extern bool g_fixupCase;
extern int g_tcpRecvTimeout;
extern size_t g_udpVectorSize;
extern bool g_preserveTrailingData;
extern bool g_allowEmptyResponse;
+extern bool g_roundrobinFailOnNoServer;
#ifdef HAVE_EBPF
extern shared_ptr<BPFFilter> g_defaultBPFFilter;
bool checkQueryHeaders(const struct dnsheader* dh);
-extern std::vector<std::tuple<ComboAddress, std::shared_ptr<DNSCryptContext>, bool, int, std::string, std::set<int> > > g_dnsCryptLocals;
+extern std::vector<std::shared_ptr<DNSCryptContext>> g_dnsCryptLocals;
int handleDNSCryptQuery(char* packet, uint16_t len, std::shared_ptr<DNSCryptQuery> query, uint16_t* decryptedQueryLen, bool tcp, time_t now, std::vector<uint8_t>& response);
boost::optional<std::vector<uint8_t>> checkDNSCryptQuery(const ClientState& cs, const char* query, uint16_t& len, std::shared_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp);
The first issue can be solved by routing SOA, AXFR and IXFR requests explicitly to the master::
newServer({address="192.168.1.2", name="master", pool={"master", "otherpool"}})
- addAction(OrRule({QTypeRule(dnsdist.SOA), QTypeRule(dnsdist.AXFR), QTypeRule(dnsdist.IXFR)}), PoolAction("master"))
+ addAction(OrRule({QTypeRule(DNSQType.SOA), QTypeRule(DNSQType.AXFR), QTypeRule(DNSQType.IXFR)}), PoolAction("master"))
The second one might require allowing AXFR/IXFR from the :program:`dnsdist` source address
and moving the source address check to :program:`dnsdist`'s side::
- addAction(AndRule({OrRule({QTypeRule(dnsdist.AXFR), QTypeRule(dnsdist.IXFR)}), NotRule(makeRule("192.168.1.0/24"))}), RCodeAction(dnsdist.REFUSED))
+ addAction(AndRule({OrRule({QTypeRule(DNSQType.AXFR), QTypeRule(DNSQTypeIXFR)}), NotRule(makeRule("192.168.1.0/24"))}), RCodeAction(DNSRCode.REFUSED))
+
+.. versionchanged:: 1.4.0
+ Before 1.4.0, the QTypes were in the ``dnsdist`` namespace. Use ``dnsdist.AXFR`` and ``dnsdist.IXFR`` in these versions.
+ Before 1.4.0, the RCodes were in the ``dnsdist`` namespace. Use ``dnsdist.REFUSED`` in these versions.
When :program:`dnsdist` is deployed in front of slaves, however, an issue might arise with NOTIFY
queries, because the slave will receive a notification coming from the :program:`dnsdist` address,
address on the slave side (for example with PowerDNS's `trusted-notification-proxy`) and move the address
check to :program:`dnsdist`'s side::
- addAction(AndRule({OpcodeRule(DNSOpcode.Notify), NotRule(makeRule("192.168.1.0/24"))}), RCodeAction(dnsdist.REFUSED))
+ addAction(AndRule({OpcodeRule(DNSOpcode.Notify), NotRule(makeRule("192.168.1.0/24"))}), RCodeAction(DNSRCode.REFUSED))
+.. versionchanged:: 1.4.0
+ Before 1.4.0, the RCodes were in the ``dnsdist`` namespace. Use ``dnsdist.REFUSED`` in these versions.
\ No newline at end of file
Changelog
=========
+.. changelog::
+ :version: 1.4.0-alpha1
+ :released: 12th of April 2019
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7167
+
+ Fix compiler warning about returning garbage (Adam Majer)
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7168
+
+ Fix warnings, mostly unused parameters, reported by -wextra
+
+ .. change::
+ :tags: New Features
+ :pullreq: 6959
+ :tickets: 6941, 2362
+
+ Add namespace and instance variable to carbon key (Gibheer)
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7191
+
+ Add optional uuid column to showServers()
+
+ .. change::
+ :tags: New Features
+ :pullreq: 7087
+
+ Allow NoRecurse for use in dynamic blocks or Lua rules (phonedph1)
+
+ .. change::
+ :tags: New Features
+ :pullreq: 7197
+ :tickets: 7194
+
+ Expose secpoll status
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7026
+
+ Configure --enable-pdns-option --with-third-party-module (Josh Soref)
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 7256
+
+ Protect GnuTLS tickets key rotation with a read-write lock
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 7267
+
+ Check that ``SO_ATTACH_BPF`` is defined before enabling eBPF
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7138
+
+ Drop remaining capabilities after startup
+
+ .. change::
+ :tags: New Features
+ :pullreq: 7323
+ :tickets: 7236
+
+ Add an optional 'checkTimeout' parameter to 'newServer()'
+
+ .. change::
+ :tags: New Features
+ :pullreq: 7322
+ :tickets: 7237
+
+ Add a 'rise' parameter to 'newServer()'
+
+ .. change::
+ :tags: New Features
+ :pullreq: 7310
+ :tickets: 7239
+
+ Add a 'keepStaleData' option to the packet cache
+
+ .. change::
+ :tags: New Features
+ :pullreq: 6967
+ :tickets: 6846, 6897
+
+ Expose trailing data (Richard Gibson)
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 6634
+
+ More sandboxing using systemd's features
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 7426
+
+ Fix off-by-one in mvRule counting
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7428
+
+ Reduce systemcall usage in Protobuf logging
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7433
+
+ Resync YaHTTP code to cmouse/yahttp@11be77a1fc4032 (Chris Hofstaedtler)
+
+ .. change::
+ :tags: New Features
+ :pullreq: 7142
+
+ Add option to set interval between health checks (1848)
+
+ .. change::
+ :tags: New Features
+ :pullreq: 7406
+
+ Add EDNS unknown version handling (Dmitry Alenichev)
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7431
+
+ Pass empty response (Dmitry Alenichev)
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7502
+
+ Change the way getRealMemusage() works on linux (using statm)
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 7520
+
+ Don't convert nsec to usec if we need nsec
+
+ .. change::
+ :tags: New Features
+ :pullreq: 7537
+
+ DNSNameSet and QNameSetRule (Andrey)
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 7594
+
+ Fix setRules()
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 7560
+
+ Handle EAGAIN in the GnuTLS DNS over TLS provider
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 7586
+ :tickets: 7461
+
+ Gracefully handle a null latency in the webserver's js
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7585
+ :tickets: 7534
+
+ Prevent 0-ttl cache hits
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7343
+ :tickets: 7139
+
+ Add addDynBlockSMT() support to dynBlockRulesGroup
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7578
+
+ Add frontend response statistics (Matti Hiljanen)
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 7652
+
+ EDNSOptionView improvements
+
+ .. change::
+ :tags: New Features
+ :pullreq: 7481
+ :tickets: 6242
+
+ Add support for encrypting ip addresses #gdpr
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7670
+
+ Remove addLuaAction and addLuaResponseAction
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7559
+ :tickets: 7526, 4814
+
+ Refactoring of the TCP stack
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 7674
+ :tickets: 7481
+
+ Honor libcrypto include path
+
+ .. change::
+ :tags: New Features
+ :pullreq: 7677
+ :tickets: 5653
+
+ Add 'setSyslogFacility()'
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7692
+ :tickets: 7556
+
+ Prevent a conflict with BADSIG being clobbered
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7689
+
+ Switch to the new 'newPacketCache()' syntax for 1.4.0
+
+ .. change::
+ :tags: New Features
+ :pullreq: 7676
+
+ Add 'reloadAllCertificates()'
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7678
+
+ Move constants to proper namespace
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 7694
+
+ Unify the management of DNS/DNSCrypt/DoT frontends
+
.. changelog::
:version: 1.3.3
:released: 8th of November 2018
It is enabled per-pool, but the same cache can be shared between several pools.
The first step is to define a cache with :func:`newPacketCache`, then to assign that cache to the chosen pool, the default one being represented by the empty string::
- pc = newPacketCache(10000, 86400, 0, 60, 60, false)
+ pc = newPacketCache(10000, {maxTTL=86400, minTTL=0, temporaryFailureTTL=60, staleTTL=60, dontAge=false})
getPool(""):setCache(pc)
+ The first parameter (10000) is the maximum number of entries stored in the cache, and is the only one required. All the other parameters are optional and in seconds, except the last one which is a boolean.
Specific entries can also be removed using the :meth:`PacketCache:expungeByName` method::
- getPool("poolname"):getCache():expungeByName(newDNSName("powerdns.com"), dnsdist.A)
+ getPool("poolname"):getCache():expungeByName(newDNSName("powerdns.com"), DNSQType.A)
+
+.. versionchanged:: 1.4.0
+ Before 1.4.0, the QTypes were in the ``dnsdist`` namespace. Use ``dnsdist.A`` in these versions.
Finally, the :meth:`PacketCache:expunge` method will remove all entries until at most n entries remain in the cache::
~~~~~~~~~~~~~~
The last available policy is ``roundrobin``, which indiscriminately sends each query to the next server that is up.
+If all servers are down, the policy will still select one server by default. Setting :func:`setRoundRobinFailOnNoServer` to ``true`` will change this behavior.
Lua server policies
-------------------
If set, return a ServFail when no servers are available, instead of the default behaviour of dropping the query.
- :param bool value:
+ :param bool value: whether to return a servfail instead of dropping the query
.. function:: setPoolServerPolicy(policy, pool)
:param string function: name of the function
:param string pool: Name of the pool
+.. function:: setRoundRobinFailOnNoServer(value)
+
+ .. versionadded:: 1.4.0
+
+ By default the roundrobin load-balancing policy will still try to select a backend even if all backends are currently down. Setting this to true will make the policy fail and return that no server is available instead.
+
+ :param bool value: whether to fail when all servers are down
+
.. function:: showPoolServerPolicy(pool)
Print server selection policy for ``pool``.
:param str path: The directory to load configuration files from. Each file must end in ``.conf``.
+.. function:: reloadAllCertificates()
+
+ .. versionadded:: 1.4.0
+
+ Reload all DNSCrypt and TLS certificates, along with their associated keys.
+
.. function:: setSyslogFacility(facility)
.. versionadded:: 1.4.0
:param int n: Number of entries to keep
- .. method:: PacketCache:expungeByName(name [, qtype=dnsdist.ANY[, suffixMatch=false]])
+ .. method:: PacketCache:expungeByName(name [, qtype=DNSQType.ANY[, suffixMatch=false]])
.. versionchanged:: 1.2.0
``suffixMatch`` parameter added.
Remove entries matching ``name`` and type from the cache.
:param DNSName name: The name to expunge
- :param int qtype: The type to expunge
+ :param int qtype: The type to expunge, can be a pre-defined :ref:`DNSQType`
:param bool suffixMatch: When set to true, remove al entries under ``name``
.. method:: PacketCache:getStats()
OPCode
------
+These constants represent the `OpCode <https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-5>`__ of a query.
+
- ``DNSOpcode.Query``
- ``DNSOpcode.IQuery``
- ``DNSOpcode.Status``
DNSClass
------
+These constants represent the `CLASS <https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-2>`__ of a DNS record.
+
- ``DNSClass.IN``
- ``DNSClass.CHAOS``
- ``DNSClass.NONE``
RCode
-----
-- ``dnsdist.NOERROR``
-- ``dnsdist.FORMERR``
-- ``dnsdist.SERVFAIL``
-- ``dnsdist.NXDOMAIN``
-- ``dnsdist.NOTIMP``
-- ``dnsdist.REFUSED``
-- ``dnsdist.YXDOMAIN``
-- ``dnsdist.YXRRSET``
-- ``dnsdist.NXRRSET``
-- ``dnsdist.NOTAUTH``
-- ``dnsdist.NOTZONE``
-- ``dnsdist.BADVERS``
-- ``dnsdist.BADSIG``
-- ``dnsdist.BADKEY``
-- ``dnsdist.BADTIME``
-- ``dnsdist.BADMODE``
-- ``dnsdist.BADNAME``
-- ``dnsdist.BADALG``
-- ``dnsdist.BADTRUNC``
-- ``dnsdist.BADCOOKIE``
-
-RCodes below and including ``BADVERS`` are extended RCodes that can only be matched using :func:`ERCodeRule`.
-
-Reference: https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6
-
+These constants represent the different `RCODEs <https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6>`__ for DNS messages.
+
+.. versionchanged:: 1.4.0
+ The prefix is changed from ``dnsdist`` to ``DNSRCode``.
+
+- ``DNSRCode.NOERROR``
+- ``DNSRCode.FORMERR``
+- ``DNSRCode.SERVFAIL``
+- ``DNSRCode.NXDOMAIN``
+- ``DNSRCode.NOTIMP``
+- ``DNSRCode.REFUSED``
+- ``DNSRCode.YXDOMAIN``
+- ``DNSRCode.YXRRSET``
+- ``DNSRCode.NXRRSET``
+- ``DNSRCode.NOTAUTH``
+- ``DNSRCode.NOTZONE``
+
+RCodes below are extended RCodes that can only be matched using :func:`ERCodeRule`.
+
+- ``DNSRCode.BADVERS``
+- ``DNSRCode.BADSIG``
+- ``DNSRCode.BADKEY``
+- ``DNSRCode.BADTIME``
+- ``DNSRCode.BADMODE``
+- ``DNSRCode.BADNAME``
+- ``DNSRCode.BADALG``
+- ``DNSRCode.BADTRUNC``
+- ``DNSRCode.BADCOOKIE``
.. _EDNSOptionCode:
.. _DNSSection:
-DNS Section
------------
+DNS Packet Sections
+-------------------
+
+These constants represent the section in the DNS Packet.
- ``DNSSection.Question``
- ``DNSSection.Answer``
* ``DNSAction.Truncate``: truncate the response
* ``DNSAction.NoRecurse``: set rd=0 on the query
+.. _DNSQType:
+
+DNSQType
+--------
+
+.. versionchanged:: 1.3.0
+ The prefix is changed from ``dnsdist.`` to ``DNSQType``.
+
+All named `QTypes <https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4>`__ are available as constants, prefixed with ``DNSQType.``, e.g.:
+
+ * ``DNSQType.AAAA``
+ * ``DNSQType.AXFR``
+ * ``DNSQType.A``
+ * ``DNSQType.NS``
+ * ``DNSQType.SOA``
+ * etc.
.. _DNSResponseAction:
.. attribute:: DNSQuestion.qtype
QType (as an unsigned integer) of this question.
- Can be compared against ``dnsdist.A``, ``dnsdist.AAAA`` etc.
+ Can be compared against the pre-defined :ref:`constants <DNSQType>` like ``DNSQType.A``, DNSQType.AAAA``.
.. attribute:: DNSQuestion.remoteaddr
- ``section`` is the section in the packet and can be compared to :ref:`DNSSection`
- ``qclass`` is the QClass of the record. Can be compared to :ref:`DNSQClass`
- - ``qtype`` is the QType of the record. Can be e.g. compared to ``dnsdist.A``, ``dnsdist.AAAA`` and the like.
+ - ``qtype`` is the QType of the record. Can be e.g. compared to ``DNSQType.A``, ``DNSQType.AAAA`` :ref:`constants <DNSQType>` and the like.
- ``ttl`` is the current TTL
This function must return an integer with the new TTL.
Set the TC-bit (truncate) on ANY queries received over UDP, forcing a retry over TCP.
This function is deprecated as of 1.2.0 and will be removed in 1.3.0. This is equivalent to doing::
- addAction(AndRule({QTypeRule(dnsdist.ANY), TCPRule(false)}), TCAction())
+ addAction(AndRule({QTypeRule(DNSQType.ANY), TCPRule(false)}), TCAction())
+
+ .. versionchanged:: 1.4.0
+ Before 1.4.0, the QTypes were in the ``dnsdist`` namespace. Use ``dnsdist.ANY`` in these versions.
.. function:: addDelay(DNSrule, delay)
Matches if there is at least ``minCount`` and at most ``maxCount`` records of type ``type`` in the section ``section``.
``section`` can be specified as an integer or as a ref:`DNSSection`.
- ``qtype`` may be specified as an integer or as one of the built-in QTypes, for instance ``dnsdist.A`` or ``dnsdist.TXT``.
+ ``qtype`` may be specified as an integer or as one of the :ref:`built-in QTypes <DNSQType>`, for instance ``DNSQType.A`` or ``DNSQType.TXT``.
:param int section: The section to match on
:param int qtype: The QTYPE to match on
:func:`addLuaAction` and :func:`addLuaResponseAction` have been removed. Instead, use :func:`addAction` with a :func:`LuaAction`, or :func:`addResponseAction` with a :func:`LuaResponseAction`.
+:func:`newPacketCache` now takes an optional table as its second argument, instead of several optional parameters.
+
+Lua's constants for DNS response codes and QTypes have been moved from the 'dnsdist' prefix to, respectively, the 'DNSQType' and 'DNSRCode' prefix.
+
+To improve security, all ambient capabilities are now dropped after the startup phase, which might prevent launching the webserver on a privileged port at run-time, or impact some custom Lua code. In addition, systemd's sandboxing features are now determined at compile-time, resulting in more restrictions on recent distributions. See pull requests 7138 and 6634 for more information.
+
+If you are compiling dnsdist, note that several ./configure options have been renamed to provide a more consistent experience. Features that depend on an external component have been prefixed with '--with-' while internal features use '--enable-'. This lead to the following changes:
+
+- ``--enable-fstrm`` to ``--enable-dnstap``
+- ``--enable-gnutls`` to ``--with-gnutls``
+- ``--enable-libsodium`` to ``--with-libsodium``
+- ``--enable-libssl`` to ``--with-libssl``
+- ``--enable-re2`` to ``--with-re2``
+
1.3.2 to 1.3.3
--------------
rc = gnutls_priority_init(&d_priorityCache, fe.d_ciphers.empty() ? "NORMAL" : fe.d_ciphers.c_str(), nullptr);
if (rc != GNUTLS_E_SUCCESS) {
- warnlog("Error setting up TLS cipher preferences to %s (%s), skipping.", fe.d_ciphers.c_str(), gnutls_strerror(rc));
+ throw std::runtime_error("Error setting up TLS cipher preferences to '" + fe.d_ciphers + "' (" + gnutls_strerror(rc) + ") on " + fe.d_addr.toStringWithPort());
}
pthread_rwlock_init(&d_lock, nullptr);
char host[1024];
int retval = 0;
if(sin4.sin_family && !(retval = getnameinfo((struct sockaddr*) this, getSocklen(), host, sizeof(host),0, 0, NI_NUMERICHOST)))
- return host;
+ return string(host);
else
return "invalid "+string(gai_strerror(retval));
}
// YYYY-mm-dd HH:MM:SS TZOFF
strftime(buffer, sizeof(buffer), "%F %T %z", tm);
buffer[sizeof(buffer)-1] = '\0';
- return buffer;
+ return string(buffer);
}
uint16_t getShort(const unsigned char *p)
if(gethostname(tmp, MAXHOSTNAMELEN))
return "UNKNOWN";
- return tmp;
+ return string(tmp);
}
string itoa(int i)
(val >> 16)&0xff,
(val >> 8)&0xff,
(val )&0xff);
- return tmp;
+ return string(tmp);
}
```sh
brew install boost lua pkg-config ragel openssl
-./configure --with-modules="" --with-lua PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig
+./configure --with-lua PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig
make -j4
```
uint8_t sourceBytes = ((sourceMask - 1) >> 3) + 1;
BOOST_REQUIRE_EQUAL(ecsOptionStr.size(), (ecsHeaderSize + sourceBytes));
/* family */
- BOOST_REQUIRE_EQUAL(ntohs(*(reinterpret_cast<const uint16_t*>(&ecsOptionStr.at(0)))), source.isIPv4() ? 1 : 2);
+ uint16_t u;
+ memcpy(&u, ecsOptionStr.c_str(), sizeof(u));
+ BOOST_REQUIRE_EQUAL(ntohs(u), source.isIPv4() ? 1 : 2);
/* source mask */
BOOST_REQUIRE_EQUAL(static_cast<uint8_t>(ecsOptionStr.at(2)), sourceMask);
BOOST_REQUIRE_EQUAL(static_cast<uint8_t>(ecsOptionStr.at(3)), scopeMask);
return res;
}
- std::set<int> d_cpus;
std::vector<std::pair<std::string, std::string>> d_certKeyPairs;
ComboAddress d_addr;
std::string d_ciphers;
std::string d_provider;
- std::string d_interface;
std::string d_ticketKeyFile;
size_t d_maxStoredSessions{20480};
time_t d_ticketsKeyRotationDelay{43200};
- int d_tcpFastOpenQueueSize{0};
uint8_t d_numberOfTicketsKeys{5};
- bool d_reusePort{false};
bool d_enableTickets{true};
private:
{
dnsheader* dh = reinterpret_cast<dnsheader*>(query.data());
- DNSQuestion dq(&qname, qtype, qclass, qname.wirelength(), &lc, &rem, dh, query.size(), len, false, &realTime);
- return dq;
+ return DNSQuestion(&qname, qtype, qclass, qname.wirelength(), &lc, &rem, dh, query.size(), len, false, &realTime);
}
static DNSQuestion turnIntoResponse(const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& lc, const ComboAddress& rem, const struct timespec& queryRealTime, vector<uint8_t>& query, bool resizeBuffer=true)
set -x
fi
+rm -f ca.key ca.pem ca.srl server.csr server.key server.pem server.chain
+rm -rf configs/*
+
# Generate a new CA
openssl req -new -x509 -days 1 -extensions v3_ca -keyout ca.key -out ca.pem -nodes -config configCA.conf
# Generate a new server certificate request
# Sign the server cert
openssl x509 -req -days 1 -CA ca.pem -CAkey ca.key -CAcreateserial -in server.csr -out server.pem
# Generate a chain
-cat server.pem ca.pem >> server.chain
+cat server.pem ca.pem > server.chain
if ! nosetests --with-xunit $@; then
for log in configs/*.log; do
-addAction(AllRule(), RCodeAction(dnsdist.REFUSED))
+addAction(AllRule(), RCodeAction(DNSRCode.REFUSED))
class TestAdvancedAndNot(DNSDistTest):
_config_template = """
- addAction(AndRule({NotRule(QTypeRule("A")), TCPRule(false)}), RCodeAction(dnsdist.NOTIMP))
+ addAction(AndRule({NotRule(QTypeRule("A")), TCPRule(false)}), RCodeAction(DNSRCode.NOTIMP))
newServer{address="127.0.0.1:%s"}
"""
def testAOverUDPReturnsNotImplementedCanary(self):
class TestAdvancedOr(DNSDistTest):
_config_template = """
- addAction(OrRule({QTypeRule("A"), TCPRule(false)}), RCodeAction(dnsdist.NOTIMP))
+ addAction(OrRule({QTypeRule("A"), TCPRule(false)}), RCodeAction(DNSRCode.NOTIMP))
newServer{address="127.0.0.1:%s"}
"""
def testAAAAOverUDPReturnsNotImplemented(self):
_config_template = """
addAction("qpsnone.advanced.tests.powerdns.com", QPSAction(100))
- addAction(AllRule(), RCodeAction(dnsdist.REFUSED))
+ addAction(AllRule(), RCodeAction(DNSRCode.REFUSED))
newServer{address="127.0.0.1:%s"}
"""
_config_template = """
allowed = newNMG()
allowed:addMask("192.0.2.1/32")
- addAction(NotRule(NetmaskGroupRule(allowed)), RCodeAction(dnsdist.REFUSED))
+ addAction(NotRule(NetmaskGroupRule(allowed)), RCodeAction(DNSRCode.REFUSED))
newServer{address="127.0.0.1:%s"}
"""
_config_params = ['_dnsDistPort', '_testServerPort']
_config_template = """
- addAction(DSTPortRule(%d), RCodeAction(dnsdist.REFUSED))
+ addAction(DSTPortRule(%d), RCodeAction(DNSRCode.REFUSED))
newServer{address="127.0.0.1:%s"}
"""
class TestAdvancedLabelsCountRule(DNSDistTest):
_config_template = """
- addAction(QNameLabelsCountRule(5,6), RCodeAction(dnsdist.REFUSED))
+ addAction(QNameLabelsCountRule(5,6), RCodeAction(DNSRCode.REFUSED))
newServer{address="127.0.0.1:%s"}
"""
class TestAdvancedWireLengthRule(DNSDistTest):
_config_template = """
- addAction(QNameWireLengthRule(54,56), RCodeAction(dnsdist.REFUSED))
+ addAction(QNameWireLengthRule(54,56), RCodeAction(DNSRCode.REFUSED))
newServer{address="127.0.0.1:%s"}
"""
class TestAdvancedRD(DNSDistTest):
_config_template = """
- addAction(RDRule(), RCodeAction(dnsdist.REFUSED))
+ addAction(RDRule(), RCodeAction(DNSRCode.REFUSED))
newServer{address="127.0.0.1:%s"}
"""
_config_template = """
newServer{address="127.0.0.1:%s"}
- addAction(EDNSVersionRule(0), ERCodeAction(dnsdist.BADVERS))
+ addAction(EDNSVersionRule(0), ERCodeAction(DNSRCode.BADVERS))
"""
def testDropped(self):
_config_template = """
newServer{address="127.0.0.1:%s"}
truncateTC(true)
- addAction(AndRule{QTypeRule(dnsdist.ANY), TCPRule(false)}, TCAction())
- addAction(RegexRule("evil[0-9]{4,}\\\\.regex\\\\.tests\\\\.powerdns\\\\.com$"), RCodeAction(dnsdist.REFUSED))
+ addAction(AndRule{QTypeRule(DNSQType.ANY), TCPRule(false)}, TCAction())
+ addAction(RegexRule("evil[0-9]{4,}\\\\.regex\\\\.tests\\\\.powerdns\\\\.com$"), RCodeAction(DNSRCode.REFUSED))
mySMN = newSuffixMatchNode()
mySMN:add(newDNSName("nameAndQtype.tests.powerdns.com."))
- addAction(AndRule{SuffixMatchNodeRule(mySMN), QTypeRule("TXT")}, RCodeAction(dnsdist.NOTIMP))
+ addAction(AndRule{SuffixMatchNodeRule(mySMN), QTypeRule("TXT")}, RCodeAction(DNSRCode.NOTIMP))
addAction(makeRule("drop.test.powerdns.com."), DropAction())
- addAction(AndRule({QTypeRule(dnsdist.A),QNameRule("ds9a.nl")}), SpoofAction("1.2.3.4"))
- addAction(newDNSName("dnsname.addaction.powerdns.com."), RCodeAction(dnsdist.REFUSED))
- addAction({newDNSName("dnsname-table1.addaction.powerdns.com."), newDNSName("dnsname-table2.addaction.powerdns.com.")}, RCodeAction(dnsdist.REFUSED))
+ addAction(AndRule({QTypeRule(DNSQType.A),QNameRule("ds9a.nl")}), SpoofAction("1.2.3.4"))
+ addAction(newDNSName("dnsname.addaction.powerdns.com."), RCodeAction(DNSRCode.REFUSED))
+ addAction({newDNSName("dnsname-table1.addaction.powerdns.com."), newDNSName("dnsname-table2.addaction.powerdns.com.")}, RCodeAction(DNSRCode.REFUSED))
"""
def testDropped(self):
self.assertEquals(receivedResponse, response2)
# remove cached entries from name A
- self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"" + name + "\"), dnsdist.A)")
+ self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"" + name + "\"), DNSQType.A)")
# Miss for name A
(receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
self.assertEquals(receivedResponse, response2)
# remove cached entries from name
- self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"suffix.cache.tests.powerdns.com.\"), dnsdist.ANY, true)")
+ self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"suffix.cache.tests.powerdns.com.\"), DNSQType.ANY, true)")
# Miss for name
(receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
self.assertEquals(receivedResponse, response2)
# remove cached entries from name A
- self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"suffixtype.cache.tests.powerdns.com.\"), dnsdist.A, true)")
+ self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"suffixtype.cache.tests.powerdns.com.\"), DNSQType.A, true)")
# Miss for name A
(receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
configTemplate = """
newServer{address="127.0.0.1:53"}
truncateTC(true)
- addAction(AndRule{QTypeRule(dnsdist.ANY), TCPRule(false)}, TCAction())
- addAction(RegexRule("evil[0-9]{4,}\\\\.regex\\\\.tests\\\\.powerdns\\\\.com$"), RCodeAction(dnsdist.REFUSED))
+ addAction(AndRule{QTypeRule(DNSQType.ANY), TCPRule(false)}, TCAction())
+ addAction(RegexRule("evil[0-9]{4,}\\\\.regex\\\\.tests\\\\.powerdns\\\\.com$"), RCodeAction(DNSRCode.REFUSED))
mySMN = newSuffixMatchNode()
mySMN:add(newDNSName("nameAndQtype.tests.powerdns.com."))
- addAction(AndRule{SuffixMatchNodeRule(mySMN), QTypeRule("TXT")}, RCodeAction(dnsdist.NOTIMP))
+ addAction(AndRule{SuffixMatchNodeRule(mySMN), QTypeRule("TXT")}, RCodeAction(DNSRCode.NOTIMP))
addAction(makeRule("drop.test.powerdns.com."), DropAction())
"""
function luaFunc(dq)
dq.dh:setQR(true)
- dq.dh:setRCode(dnsdist.NXDOMAIN)
+ dq.dh:setRCode(DNSRCode.NXDOMAIN)
return DNSAction.None, ""
end
_config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
_config_template = """
local dbr = dynBlockRulesGroup()
- dbr:setRCodeRate(dnsdist.SERVFAIL, %d, %d, "Exceeded query rate", %d)
+ dbr:setRCodeRate(DNSRCode.SERVFAIL, %d, %d, "Exceeded query rate", %d)
function maintenance()
dbr:apply()
"""
_config_template = """
- addAction("rcode.edns-self.tests.powerdns.com.", RCodeAction(dnsdist.REFUSED))
+ addAction("rcode.edns-self.tests.powerdns.com.", RCodeAction(DNSRCode.REFUSED))
addAction("tc.edns-self.tests.powerdns.com.", TCAction())
function luarule(dq)
_config_template = """
setAddEDNSToSelfGeneratedResponses(false)
- addAction("rcode.edns-self-disabled.tests.powerdns.com.", RCodeAction(dnsdist.REFUSED))
+ addAction("rcode.edns-self-disabled.tests.powerdns.com.", RCodeAction(DNSRCode.REFUSED))
addAction("tc.edns-self-disabled.tests.powerdns.com.", TCAction())
function luarule(dq)
function myHealthCheckFunction(qname, qtype, qclass, dh)
dh:setCD(true)
- return newDNSName('powerdns.com.'), dnsdist.AAAA, qclass
+ return newDNSName('powerdns.com.'), DNSQType.AAAA, qclass
end
srv = newServer{address="127.0.0.1:%d", checkName='powerdns.org.', checkFunction=myHealthCheckFunction}
protobuf:setTagArray(tablePB) -- store table in protobuf
protobuf:setTag("Query,123") -- add another tag entry in protobuf
- protobuf:setResponseCode(dnsdist.NXDOMAIN) -- set protobuf response code to be NXDOMAIN
+ protobuf:setResponseCode(DNSRCode.NXDOMAIN) -- set protobuf response code to be NXDOMAIN
local strReqName = dq.qname:toString() -- get request dns name
"""
name = 'query.protobuf-ipcipher.tests.powerdns.com.'
- target = 'target.protobuf-ipcipher.tests.powerdns.com.'
+ target = b'target.protobuf-ipcipher.tests.powerdns.com.'
query = dns.message.make_query(name, 'A', 'IN')
response = dns.message.make_response(query)
class TestRecordsCountOnlyOneAR(DNSDistTest):
_config_template = """
- addAction(NotRule(RecordsCountRule(DNSSection.Additional, 1, 1)), RCodeAction(dnsdist.REFUSED))
+ addAction(NotRule(RecordsCountRule(DNSSection.Additional, 1, 1)), RCodeAction(DNSRCode.REFUSED))
newServer{address="127.0.0.1:%s"}
"""
_config_template = """
addAction(RecordsCountRule(DNSSection.Answer, 2, 3), AllowAction())
- addAction(AllRule(), RCodeAction(dnsdist.REFUSED))
+ addAction(AllRule(), RCodeAction(DNSRCode.REFUSED))
newServer{address="127.0.0.1:%s"}
"""
_config_template = """
addAction(RecordsCountRule(DNSSection.Authority, 0, 0), AllowAction())
- addAction(AllRule(), RCodeAction(dnsdist.REFUSED))
+ addAction(AllRule(), RCodeAction(DNSRCode.REFUSED))
newServer{address="127.0.0.1:%s"}
"""
class TestRecordsCountNoOPTInAR(DNSDistTest):
_config_template = """
- addAction(NotRule(RecordsTypeCountRule(DNSSection.Additional, dnsdist.OPT, 0, 0)), RCodeAction(dnsdist.REFUSED))
+ addAction(NotRule(RecordsTypeCountRule(DNSSection.Additional, DNSQType.OPT, 0, 0)), RCodeAction(DNSRCode.REFUSED))
newServer{address="127.0.0.1:%s"}
"""
_config_template = """
newServer{address="127.0.0.1:%s"}
- addResponseAction(RCodeRule(dnsdist.NXDOMAIN), DelayResponseAction(1000))
+ addResponseAction(RCodeRule(DNSRCode.NXDOMAIN), DelayResponseAction(1000))
"""
def testNXDelayed(self):
_config_template = """
newServer{address="127.0.0.1:%s"}
- addResponseAction(ERCodeRule(dnsdist.BADVERS), DelayResponseAction(1000))
+ addResponseAction(ERCodeRule(DNSRCode.BADVERS), DelayResponseAction(1000))
"""
def testBADVERSDelayed(self):
return DNSResponseAction.Drop
end
addResponseAction("drop.responses.tests.powerdns.com.", LuaResponseAction(customDrop))
- addResponseAction(RCodeRule(dnsdist.NXDOMAIN), LuaResponseAction(customDelay))
+ addResponseAction(RCodeRule(DNSRCode.NXDOMAIN), LuaResponseAction(customDelay))
"""
def testResponseActionDelayed(self):
self.assertEquals(total, numberOfQueries * 2)
+class TestRoutingRoundRobinLBAllDown(DNSDistTest):
+
+ _testServer2Port = 5351
+ _config_params = ['_testServerPort', '_testServer2Port']
+ _config_template = """
+ setServerPolicy(roundrobin)
+ setRoundRobinFailOnNoServer(true)
+ s1 = newServer{address="127.0.0.1:%s"}
+ s1:setDown()
+ s2 = newServer{address="127.0.0.1:%s"}
+ s2:setDown()
+ """
+
+ def testRRWithAllDown(self):
+ """
+ Routing: Round Robin with all servers down
+ """
+ numberOfQueries = 10
+ name = 'alldown.rr.routing.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'A', 'IN')
+ response = dns.message.make_response(query)
+ rrset = dns.rrset.from_text(name,
+ 60,
+ dns.rdataclass.IN,
+ dns.rdatatype.A,
+ '192.0.2.1')
+ response.answer.append(rrset)
+
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ (_, receivedResponse) = sender(query, response=None, useQueue=False)
+ self.assertEquals(receivedResponse, None)
+
class TestRoutingOrder(DNSDistTest):
_testServer2Port = 5351
pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
getPool(""):setCache(pc)
addAction("largernumberofconnections.tcpka.tests.powerdns.com.", SkipCacheAction())
- addAction("refused.tcpka.tests.powerdns.com.", RCodeAction(dnsdist.REFUSED))
+ addAction("refused.tcpka.tests.powerdns.com.", RCodeAction(DNSRCode.REFUSED))
addAction("dropped.tcpka.tests.powerdns.com.", DropAction())
addResponseAction("dropped-response.tcpka.tests.powerdns.com.", DropResponseAction())
-- create the pool named "nosuchpool"
setKey("%s")
controlSocket("127.0.0.1:%s")
newServer{address="127.0.0.1:%d"}
- addAction(QTypeRule(dnsdist.A), TeeAction("127.0.0.1:%d", true))
- addAction(QTypeRule(dnsdist.AAAA), TeeAction("127.0.0.1:%d", false))
+ addAction(QTypeRule(DNSQType.A), TeeAction("127.0.0.1:%d", true))
+ addAction(QTypeRule(DNSQType.AAAA), TeeAction("127.0.0.1:%d", false))
"""
_config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_teeServerPort', '_teeServerPort']
@classmethod