Skip to content

Commit

Permalink
Merge pull request #7165 from rgacogne/dnsdist-fix-trailing-bis
Browse files Browse the repository at this point in the history
dnsdist: Add 1.3.3 ChangeLog, update the secpoll zone
  • Loading branch information
rgacogne committed Nov 8, 2018
2 parents 8cbd287 + fe66026 commit 27dd1e3
Show file tree
Hide file tree
Showing 24 changed files with 731 additions and 112 deletions.
5 changes: 4 additions & 1 deletion docs/secpoll.zone
@@ -1,4 +1,4 @@
@ 86400 IN SOA pdns-public-ns1.powerdns.com. pieter\.lexis.powerdns.com. 2018110701 10800 3600 604800 10800
@ 86400 IN SOA pdns-public-ns1.powerdns.com. pieter\.lexis.powerdns.com. 2018110801 10800 3600 604800 10800
@ 3600 IN NS pdns-public-ns1.powerdns.com.
@ 3600 IN NS pdns-public-ns2.powerdns.com.
; Auth
Expand Down Expand Up @@ -275,3 +275,6 @@ recursor-4.0.0_beta1-1pdns.xenial.ubuntu.security-status 60 IN TXT "3 Upgrade no
recursor-4.0.0_alpha2-1pdns.jessie.raspbian.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/3/security/powerdns-advisory-2016-02/ and https://doc.powerdns.com/3/security/powerdns-advisory-2016-04/"
recursor-4.0.0_alpha3-1pdns.jessie.raspbian.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/3/security/powerdns-advisory-2016-02/ and https://doc.powerdns.com/3/security/powerdns-advisory-2016-04/"
recursor-4.0.0_beta1-1pdns.jessie.raspbian.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/3/security/powerdns-advisory-2016-02/ and https://doc.powerdns.com/3/security/powerdns-advisory-2016-04/"

; dnsdist
dnsdist-1.3.3.security-status 60 IN TXT "1 OK"
13 changes: 7 additions & 6 deletions pdns/dnsdist-cache.cc
Expand Up @@ -78,9 +78,9 @@ bool DNSDistPacketCache::getClientSubnet(const char* packet, unsigned int consum
return false;
}

bool DNSDistPacketCache::cachedValueMatches(const CacheValue& cachedValue, uint16_t queryFlags, const DNSName& qname, uint16_t qtype, uint16_t qclass, bool tcp, const boost::optional<Netmask>& subnet) const
bool DNSDistPacketCache::cachedValueMatches(const CacheValue& cachedValue, uint16_t queryFlags, const DNSName& qname, uint16_t qtype, uint16_t qclass, bool tcp, bool dnssecOK, const boost::optional<Netmask>& subnet) const
{
if (cachedValue.queryFlags != queryFlags || cachedValue.tcp != tcp || cachedValue.qtype != qtype || cachedValue.qclass != qclass || cachedValue.qname != qname) {
if (cachedValue.queryFlags != queryFlags || cachedValue.dnssecOK != dnssecOK || cachedValue.tcp != tcp || cachedValue.qtype != qtype || cachedValue.qclass != qclass || cachedValue.qname != qname) {
return false;
}

Expand Down Expand Up @@ -113,7 +113,7 @@ void DNSDistPacketCache::insertLocked(CacheShard& shard, uint32_t key, CacheValu
CacheValue& value = it->second;
bool wasExpired = value.validity <= newValue.added;

if (!wasExpired && !cachedValueMatches(value, newValue.queryFlags, newValue.qname, newValue.qtype, newValue.qclass, newValue.tcp, newValue.subnet)) {
if (!wasExpired && !cachedValueMatches(value, newValue.queryFlags, newValue.qname, newValue.qtype, newValue.qclass, newValue.tcp, newValue.dnssecOK, newValue.subnet)) {
d_insertCollisions++;
return;
}
Expand All @@ -126,7 +126,7 @@ void DNSDistPacketCache::insertLocked(CacheShard& shard, uint32_t key, CacheValu
value = newValue;
}

void DNSDistPacketCache::insert(uint32_t key, const boost::optional<Netmask>& subnet, uint16_t queryFlags, const DNSName& qname, uint16_t qtype, uint16_t qclass, const char* response, uint16_t responseLen, bool tcp, uint8_t rcode, boost::optional<uint32_t> tempFailureTTL)
void DNSDistPacketCache::insert(uint32_t key, const boost::optional<Netmask>& subnet, uint16_t queryFlags, bool dnssecOK, const DNSName& qname, uint16_t qtype, uint16_t qclass, const char* response, uint16_t responseLen, bool tcp, uint8_t rcode, boost::optional<uint32_t> tempFailureTTL)
{
if (responseLen < sizeof(dnsheader)) {
return;
Expand Down Expand Up @@ -179,6 +179,7 @@ void DNSDistPacketCache::insert(uint32_t key, const boost::optional<Netmask>& su
newValue.validity = newValidity;
newValue.added = now;
newValue.tcp = tcp;
newValue.dnssecOK = dnssecOK;
newValue.value = std::string(response, responseLen);
newValue.subnet = subnet;

Expand All @@ -200,7 +201,7 @@ void DNSDistPacketCache::insert(uint32_t key, const boost::optional<Netmask>& su
}
}

bool DNSDistPacketCache::get(const DNSQuestion& dq, uint16_t consumed, uint16_t queryId, char* response, uint16_t* responseLen, uint32_t* keyOut, boost::optional<Netmask>& subnet, uint32_t allowExpired, bool skipAging)
bool DNSDistPacketCache::get(const DNSQuestion& dq, uint16_t consumed, uint16_t queryId, char* response, uint16_t* responseLen, uint32_t* keyOut, boost::optional<Netmask>& subnet, bool dnssecOK, uint32_t allowExpired, bool skipAging)
{
std::string dnsQName(dq.qname->toDNSString());
uint32_t key = getKey(dnsQName, consumed, reinterpret_cast<const unsigned char*>(dq.dh), dq.len, dq.tcp);
Expand Down Expand Up @@ -247,7 +248,7 @@ bool DNSDistPacketCache::get(const DNSQuestion& dq, uint16_t consumed, uint16_t
}

/* check for collision */
if (!cachedValueMatches(value, *(getFlagsFromDNSHeader(dq.dh)), *dq.qname, dq.qtype, dq.qclass, dq.tcp, subnet)) {
if (!cachedValueMatches(value, *(getFlagsFromDNSHeader(dq.dh)), *dq.qname, dq.qtype, dq.qclass, dq.tcp, dnssecOK, subnet)) {
d_lookupCollisions++;
return false;
}
Expand Down
7 changes: 4 additions & 3 deletions pdns/dnsdist-cache.hh
Expand Up @@ -33,8 +33,8 @@ public:
DNSDistPacketCache(size_t maxEntries, uint32_t maxTTL=86400, uint32_t minTTL=0, uint32_t tempFailureTTL=60, uint32_t maxNegativeTTL=3600, uint32_t staleTTL=60, bool dontAge=false, uint32_t shards=1, bool deferrableInsertLock=true, bool parseECS=false);
~DNSDistPacketCache();

void insert(uint32_t key, const boost::optional<Netmask>& subnet, uint16_t queryFlags, const DNSName& qname, uint16_t qtype, uint16_t qclass, const char* response, uint16_t responseLen, bool tcp, uint8_t rcode, boost::optional<uint32_t> tempFailureTTL);
bool get(const DNSQuestion& dq, uint16_t consumed, uint16_t queryId, char* response, uint16_t* responseLen, uint32_t* keyOut, boost::optional<Netmask>& subnetOut, uint32_t allowExpired=0, bool skipAging=false);
void insert(uint32_t key, const boost::optional<Netmask>& subnet, uint16_t queryFlags, bool dnssecOK, const DNSName& qname, uint16_t qtype, uint16_t qclass, const char* response, uint16_t responseLen, bool tcp, uint8_t rcode, boost::optional<uint32_t> tempFailureTTL);
bool get(const DNSQuestion& dq, uint16_t consumed, uint16_t queryId, char* response, uint16_t* responseLen, uint32_t* keyOut, boost::optional<Netmask>& subnetOut, bool dnssecOK, uint32_t allowExpired=0, bool skipAging=false);
void purgeExpired(size_t upTo=0);
void expunge(size_t upTo=0);
void expungeByName(const DNSName& name, uint16_t qtype=QType::ANY, bool suffixMatch=false);
Expand Down Expand Up @@ -70,6 +70,7 @@ private:
time_t validity{0};
uint16_t len{0};
bool tcp{false};
bool dnssecOK{false};
};

class CacheShard
Expand All @@ -95,7 +96,7 @@ private:
};

static bool getClientSubnet(const char* packet, unsigned int consumed, uint16_t len, boost::optional<Netmask>& subnet);
bool cachedValueMatches(const CacheValue& cachedValue, uint16_t queryFlags, const DNSName& qname, uint16_t qtype, uint16_t qclass, bool tcp, const boost::optional<Netmask>& subnet) const;
bool cachedValueMatches(const CacheValue& cachedValue, uint16_t queryFlags, const DNSName& qname, uint16_t qtype, uint16_t qclass, bool tcp, bool dnssecOK, const boost::optional<Netmask>& subnet) const;
uint32_t getShardIndex(uint32_t key) const;
void insertLocked(CacheShard& shard, uint32_t key, CacheValue& newValue);

Expand Down
1 change: 1 addition & 0 deletions pdns/dnsdist-console.cc
Expand Up @@ -430,6 +430,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
{ "setPayloadSizeOnSelfGeneratedAnswers", true, "payloadSize", "set the UDP payload size advertised via EDNS on self-generated responses" },
{ "setPoolServerPolicy", true, "policy, pool", "set the server selection policy for this pool to that policy" },
{ "setPoolServerPolicy", true, "name, func, pool", "set the server selection policy for this pool to one named 'name' and provided by 'function'" },
{ "setPreserveTrailingData", true, "bool", "set whether trailing data should be preserved while adding ECS or XPF records to incoming queries" },
{ "setQueryCount", true, "bool", "set whether queries should be counted" },
{ "setQueryCountFilter", true, "func", "filter queries that would be counted, where `func` is a function with parameter `dq` which decides whether a query should and how it should be counted" },
{ "setRingBuffersLockRetries", true, "n", "set the number of attempts to get a non-blocking lock to a ringbuffer shard before blocking" },
Expand Down
26 changes: 18 additions & 8 deletions pdns/dnsdist-ecs.cc
Expand Up @@ -353,7 +353,7 @@ static bool addECSToExistingOPT(char* const packet, size_t const packetSize, uin
return true;
}

static bool addEDNSWithECS(char* const packet, size_t const packetSize, uint16_t* const len, const string& newECSOption, bool* const ednsAdded)
static bool addEDNSWithECS(char* const packet, size_t const packetSize, uint16_t* const len, const string& newECSOption, bool* const ednsAdded, bool preserveTrailingData)
{
/* we need to add a EDNS0 RR with one EDNS0 ECS option, fixing the AR count */
string EDNSRR;
Expand All @@ -365,17 +365,27 @@ static bool addEDNSWithECS(char* const packet, size_t const packetSize, uint16_t
return false;
}

uint32_t realPacketLen = getDNSPacketLength(packet, *len);
if (realPacketLen < *len && preserveTrailingData) {
size_t toMove = *len - realPacketLen;
memmove(packet + realPacketLen + EDNSRR.size(), packet + realPacketLen, toMove);
*len += EDNSRR.size();
}
else {
*len = realPacketLen + EDNSRR.size();
}

uint16_t arcount = ntohs(dh->arcount);
arcount++;
dh->arcount = htons(arcount);
*ednsAdded = true;

memcpy(packet + *len, EDNSRR.c_str(), EDNSRR.size());
*len += EDNSRR.size();
memcpy(packet + realPacketLen, EDNSRR.c_str(), EDNSRR.size());

return true;
}

bool handleEDNSClientSubnet(char* const packet, const size_t packetSize, const unsigned int consumed, uint16_t* const len, bool* const ednsAdded, bool* const ecsAdded, bool overrideExisting, const string& newECSOption)
bool handleEDNSClientSubnet(char* const packet, const size_t packetSize, const unsigned int consumed, uint16_t* const len, bool* const ednsAdded, bool* const ecsAdded, bool overrideExisting, const string& newECSOption, bool preserveTrailingData)
{
assert(packet != nullptr);
assert(len != nullptr);
Expand All @@ -388,7 +398,7 @@ bool handleEDNSClientSubnet(char* const packet, const size_t packetSize, const u
int res = getEDNSOptionsStart(packet, consumed, *len, &optRDPosition, &remaining);

if (res != 0) {
return addEDNSWithECS(packet, packetSize, len, newECSOption, ednsAdded);
return addEDNSWithECS(packet, packetSize, len, newECSOption, ednsAdded, preserveTrailingData);
}

unsigned char* optRDLen = reinterpret_cast<unsigned char*>(packet) + optRDPosition;
Expand All @@ -412,14 +422,14 @@ bool handleEDNSClientSubnet(char* const packet, const size_t packetSize, const u
return true;
}

bool handleEDNSClientSubnet(DNSQuestion& dq, bool* ednsAdded, bool* ecsAdded)
bool handleEDNSClientSubnet(DNSQuestion& dq, bool* ednsAdded, bool* ecsAdded, bool preserveTrailingData)
{
assert(dq.remote != nullptr);
string newECSOption;
generateECSOption(dq.ecsSet ? dq.ecs.getNetwork() : *dq.remote, newECSOption, dq.ecsSet ? dq.ecs.getBits() : dq.ecsPrefixLength);
generateECSOption(dq.ecsSet ? dq.ecs.getNetwork() : *dq.remote, newECSOption, dq.ecsSet ? dq.ecs.getBits() : dq.ecsPrefixLength);
char* packet = reinterpret_cast<char*>(dq.dh);

return handleEDNSClientSubnet(packet, dq.size, dq.consumed, &dq.len, ednsAdded, ecsAdded, dq.ecsOverride, newECSOption);
return handleEDNSClientSubnet(packet, dq.size, dq.consumed, &dq.len, ednsAdded, ecsAdded, dq.ecsOverride, newECSOption, preserveTrailingData);
}

static int removeEDNSOptionFromOptions(unsigned char* optionsStart, const uint16_t optionsLen, const uint16_t optionCodeToRemove, uint16_t* newOptionsLen)
Expand Down
4 changes: 2 additions & 2 deletions pdns/dnsdist-ecs.hh
Expand Up @@ -35,8 +35,8 @@ bool isEDNSOptionInOpt(const std::string& packet, const size_t optStart, const s
bool addEDNS(dnsheader* dh, uint16_t& len, const size_t size, bool dnssecOK, uint16_t payloadSize);
bool addEDNSToQueryTurnedResponse(DNSQuestion& dq);

bool handleEDNSClientSubnet(DNSQuestion& dq, bool* ednsAdded, bool* ecsAdded);
bool handleEDNSClientSubnet(char* const packet, const size_t packetSize, const unsigned int consumed, uint16_t* const len, bool* const ednsAdded, bool* const ecsAdded, bool overrideExisting, const string& newECSOption);
bool handleEDNSClientSubnet(DNSQuestion& dq, bool* ednsAdded, bool* ecsAdded, bool preserveTrailingData);
bool handleEDNSClientSubnet(char* const packet, const size_t packetSize, const unsigned int consumed, uint16_t* const len, bool* const ednsAdded, bool* const ecsAdded, bool overrideExisting, const string& newECSOption, bool preserveTrailingData);

bool parseEDNSOptions(DNSQuestion& dq);

Expand Down
2 changes: 1 addition & 1 deletion pdns/dnsdist-lua-actions.cc
Expand Up @@ -176,7 +176,7 @@ DNSAction::Action TeeAction::operator()(DNSQuestion* dq, string* ruleresult) con
string newECSOption;
generateECSOption(dq->ecsSet ? dq->ecs.getNetwork() : *dq->remote, newECSOption, dq->ecsSet ? dq->ecs.getBits() : dq->ecsPrefixLength);

if (!handleEDNSClientSubnet(const_cast<char*>(query.c_str()), query.capacity(), dq->qname->wirelength(), &len, &ednsAdded, &ecsAdded, dq->ecsOverride, newECSOption)) {
if (!handleEDNSClientSubnet(const_cast<char*>(query.c_str()), query.capacity(), dq->qname->wirelength(), &len, &ednsAdded, &ecsAdded, dq->ecsOverride, newECSOption, g_preserveTrailingData)) {
return DNSAction::Action::None;
}

Expand Down
2 changes: 2 additions & 0 deletions pdns/dnsdist-lua.cc
Expand Up @@ -913,6 +913,8 @@ void setupLuaConfig(bool client)

g_lua.writeFunction("setECSOverride", [](bool override) { g_ECSOverride=override; });

g_lua.writeFunction("setPreserveTrailingData", [](bool preserve) { g_preserveTrailingData = preserve; });

g_lua.writeFunction("showDynBlocks", []() {
setLuaNoSideEffect();
auto slow = g_dynblockNMG.getCopy();
Expand Down
11 changes: 7 additions & 4 deletions pdns/dnsdist-tcp.cc
Expand Up @@ -22,6 +22,7 @@
#include "dnsdist.hh"
#include "dnsdist-ecs.hh"
#include "dnsdist-rings.hh"
#include "dnsdist-xpf.hh"

#include "dnsparser.hh"
#include "ednsoptions.hh"
Expand Down Expand Up @@ -433,19 +434,21 @@ void* tcpClientThread(int pipefd)
}

if (dq.useECS && ((ds && ds->useECS) || (!ds && serverPool->getECS()))) {
if (!handleEDNSClientSubnet(dq, &(ednsAdded), &(ecsAdded))) {
if (!handleEDNSClientSubnet(dq, &(ednsAdded), &(ecsAdded), g_preserveTrailingData)) {
vinfolog("Dropping query from %s because we couldn't insert the ECS value", ci.remote.toStringWithPort());
goto drop;
}
}

uint32_t cacheKey = 0;
boost::optional<Netmask> subnet;
bool dnssecOK = false;
if (packetCache && !dq.skipCache) {
char cachedResponse[4096];
uint16_t cachedResponseSize = sizeof cachedResponse;
uint32_t allowExpired = ds ? 0 : g_staleCacheEntriesTTL;
if (packetCache->get(dq, (uint16_t) consumed, dq.dh->id, cachedResponse, &cachedResponseSize, &cacheKey, subnet, allowExpired)) {
dnssecOK = (getEDNSZ(dq) & EDNS_HEADER_FLAG_DO);
if (packetCache->get(dq, (uint16_t) consumed, dq.dh->id, cachedResponse, &cachedResponseSize, &cacheKey, subnet, dnssecOK, allowExpired)) {
DNSResponse dr(dq.qname, dq.qtype, dq.qclass, dq.consumed, dq.local, dq.remote, (dnsheader*) cachedResponse, sizeof cachedResponse, cachedResponseSize, true, &queryRealTime);
#ifdef HAVE_PROTOBUF
dr.uniqueId = dq.uniqueId;
Expand Down Expand Up @@ -501,7 +504,7 @@ void* tcpClientThread(int pipefd)
}

if (dq.addXPF && ds->xpfRRCode != 0) {
addXPF(dq, ds->xpfRRCode);
addXPF(dq, ds->xpfRRCode, g_preserveTrailingData);
}

int dsock = -1;
Expand Down Expand Up @@ -629,7 +632,7 @@ void* tcpClientThread(int pipefd)
}

if (packetCache && !dq.skipCache) {
packetCache->insert(cacheKey, subnet, origFlags, qname, qtype, qclass, response, responseLen, true, dh->rcode, dq.tempFailureTTL);
packetCache->insert(cacheKey, subnet, origFlags, dnssecOK, qname, qtype, qclass, response, responseLen, true, dh->rcode, dq.tempFailureTTL);
}

#ifdef HAVE_DNSCRYPT
Expand Down
67 changes: 67 additions & 0 deletions pdns/dnsdist-xpf.cc
@@ -0,0 +1,67 @@
/*
* This file is part of PowerDNS or dnsdist.
* Copyright -- PowerDNS.COM B.V. and its contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* In addition, for the avoidance of any doubt, permission is granted to
* link this program with OpenSSL and to (re)distribute the binaries
* produced as the result of such linking.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "dnsdist-xpf.hh"

#include "dnsparser.hh"
#include "xpf.hh"

bool addXPF(DNSQuestion& dq, uint16_t optionCode, bool preserveTrailingData)
{
std::string payload = generateXPFPayload(dq.tcp, *dq.remote, *dq.local);
uint8_t root = '\0';
dnsrecordheader drh;
drh.d_type = htons(optionCode);
drh.d_class = htons(QClass::IN);
drh.d_ttl = 0;
drh.d_clen = htons(payload.size());
size_t recordHeaderLen = sizeof(root) + sizeof(drh);

size_t available = dq.size - dq.len;

if ((payload.size() + recordHeaderLen) > available) {
return false;
}

size_t xpfSize = sizeof(root) + sizeof(drh) + payload.size();
uint32_t realPacketLen = getDNSPacketLength(reinterpret_cast<const char*>(dq.dh), dq.len);
if (realPacketLen < dq.len && preserveTrailingData) {
size_t toMove = dq.len - realPacketLen;
memmove(reinterpret_cast<char*>(dq.dh) + realPacketLen + xpfSize, reinterpret_cast<const char*>(dq.dh) + realPacketLen, toMove);
dq.len += xpfSize;
}
else {
dq.len = realPacketLen + xpfSize;
}

size_t pos = realPacketLen;
memcpy(reinterpret_cast<char*>(dq.dh) + pos, &root, sizeof(root));
pos += sizeof(root);
memcpy(reinterpret_cast<char*>(dq.dh) + pos, &drh, sizeof(drh));
pos += sizeof(drh);
memcpy(reinterpret_cast<char*>(dq.dh) + pos, payload.data(), payload.size());
pos += payload.size();

dq.dh->arcount = htons(ntohs(dq.dh->arcount) + 1);

return true;
}
27 changes: 27 additions & 0 deletions pdns/dnsdist-xpf.hh
@@ -0,0 +1,27 @@
/*
* 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 "dnsdist.hh"

bool addXPF(DNSQuestion& dq, uint16_t optionCode, bool preserveTrailingData);

0 comments on commit 27dd1e3

Please sign in to comment.