Browse Source

New upstream version 4.1.7

tags/upstream/4.3.0
Chris Hofstaedtler 2 years ago
parent
commit
6d1b0c0533
38 changed files with 817 additions and 240 deletions
  1. +1
    -1
      .version
  2. +1
    -0
      Makefile.am
  3. +17
    -14
      Makefile.in
  4. +10
    -10
      configure
  5. +1
    -1
      dnsmessage.proto
  6. +3
    -15
      dnsparser.cc
  7. +2
    -3
      dnsparser.hh
  8. +8
    -8
      dnsrecords.cc
  9. +20
    -20
      dnsrecords.hh
  10. +4
    -15
      effective_tld_names.dat
  11. +22
    -7
      lwres.cc
  12. +1
    -1
      mtasker_ucontext.cc
  13. +12
    -12
      nsecrecords.cc
  14. +10
    -1
      opensslsigners.cc
  15. +85
    -11
      packetcache.hh
  16. +1
    -1
      pdns_recursor.1
  17. +28
    -7
      pdns_recursor.cc
  18. +7
    -0
      protobuf.cc
  19. +1
    -0
      protobuf.hh
  20. +1
    -0
      pubsuffix.cc
  21. +41
    -32
      rec-lua-conf.cc
  22. +8
    -1
      rec-lua-conf.hh
  23. +13
    -3
      rec_channel_rec.cc
  24. +1
    -1
      rec_control.1
  25. +43
    -24
      recpacketcache.cc
  26. +17
    -8
      recpacketcache.hh
  27. +1
    -1
      recursor_cache.hh
  28. +4
    -4
      sillyrecords.cc
  29. +23
    -10
      syncres.cc
  30. +2
    -2
      syncres.hh
  31. +6
    -6
      test-dnsrecordcontent.cc
  32. +305
    -0
      test-packetcache_hh.cc
  33. +10
    -9
      test-recpacketcache_cc.cc
  34. +3
    -3
      test-signers.cc
  35. +100
    -6
      test-syncres_cc.cc
  36. +3
    -2
      validate.cc
  37. +1
    -0
      validate.hh
  38. +1
    -1
      ws-recursor.cc

+ 1
- 1
.version View File

@@ -1 +1 @@
4.1.4
4.1.7

+ 1
- 0
Makefile.am View File

@@ -242,6 +242,7 @@ testrunner_SOURCES = \
test-mtasker.cc \
test-nmtree.cc \
test-negcache_cc.cc \
test-packetcache_hh.cc \
test-rcpgenerator_cc.cc \
test-recpacketcache_cc.cc \
test-recursorcache_cc.cc \


+ 17
- 14
Makefile.in View File

@@ -307,13 +307,13 @@ am__testrunner_SOURCES_DIST = arguments.cc base32.cc base64.cc \
test-dnsname_cc.cc test-dnsparser_hh.cc test-dnsrecords_cc.cc \
test-ednsoptions_cc.cc test-iputils_hh.cc test-ixfr_cc.cc \
test-misc_hh.cc test-mtasker.cc test-nmtree.cc \
test-negcache_cc.cc test-rcpgenerator_cc.cc \
test-recpacketcache_cc.cc test-recursorcache_cc.cc \
test-signers.cc test-syncres_cc.cc test-tsig.cc testrunner.cc \
tsigverifier.cc tsigverifier.hh unix_utility.cc validate.cc \
validate.hh validate-recursor.cc validate-recursor.hh \
zoneparser-tng.cc zoneparser-tng.hh botansigners.cc \
sodiumsigners.cc
test-negcache_cc.cc test-packetcache_hh.cc \
test-rcpgenerator_cc.cc test-recpacketcache_cc.cc \
test-recursorcache_cc.cc test-signers.cc test-syncres_cc.cc \
test-tsig.cc testrunner.cc tsigverifier.cc tsigverifier.hh \
unix_utility.cc validate.cc validate.hh validate-recursor.cc \
validate-recursor.hh zoneparser-tng.cc zoneparser-tng.hh \
botansigners.cc sodiumsigners.cc
am_testrunner_OBJECTS = arguments.$(OBJEXT) base32.$(OBJEXT) \
base64.$(OBJEXT) dns.$(OBJEXT) dns_random.$(OBJEXT) \
dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnsparser.$(OBJEXT) \
@@ -335,7 +335,8 @@ am_testrunner_OBJECTS = arguments.$(OBJEXT) base32.$(OBJEXT) \
test-ednsoptions_cc.$(OBJEXT) test-iputils_hh.$(OBJEXT) \
test-ixfr_cc.$(OBJEXT) test-misc_hh.$(OBJEXT) \
test-mtasker.$(OBJEXT) test-nmtree.$(OBJEXT) \
test-negcache_cc.$(OBJEXT) test-rcpgenerator_cc.$(OBJEXT) \
test-negcache_cc.$(OBJEXT) test-packetcache_hh.$(OBJEXT) \
test-rcpgenerator_cc.$(OBJEXT) \
test-recpacketcache_cc.$(OBJEXT) \
test-recursorcache_cc.$(OBJEXT) test-signers.$(OBJEXT) \
test-syncres_cc.$(OBJEXT) test-tsig.$(OBJEXT) \
@@ -992,12 +993,13 @@ testrunner_SOURCES = arguments.cc base32.cc base64.cc base64.hh dns.cc \
test-dnsrecords_cc.cc test-ednsoptions_cc.cc \
test-iputils_hh.cc test-ixfr_cc.cc test-misc_hh.cc \
test-mtasker.cc test-nmtree.cc test-negcache_cc.cc \
test-rcpgenerator_cc.cc test-recpacketcache_cc.cc \
test-recursorcache_cc.cc test-signers.cc test-syncres_cc.cc \
test-tsig.cc testrunner.cc tsigverifier.cc tsigverifier.hh \
unix_utility.cc validate.cc validate.hh validate-recursor.cc \
validate-recursor.hh zoneparser-tng.cc zoneparser-tng.hh \
$(am__append_7) $(am__append_11)
test-packetcache_hh.cc test-rcpgenerator_cc.cc \
test-recpacketcache_cc.cc test-recursorcache_cc.cc \
test-signers.cc test-syncres_cc.cc test-tsig.cc testrunner.cc \
tsigverifier.cc tsigverifier.hh unix_utility.cc validate.cc \
validate.hh validate-recursor.cc validate-recursor.hh \
zoneparser-tng.cc zoneparser-tng.hh $(am__append_7) \
$(am__append_11)
testrunner_LDFLAGS = \
$(AM_LDFLAGS) \
$(BOOST_CONTEXT_LDFLAGS) \
@@ -1291,6 +1293,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-mtasker.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-negcache_cc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-nmtree.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-packetcache_hh.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-rcpgenerator_cc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-recpacketcache_cc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-recursorcache_cc.Po@am__quote@


+ 10
- 10
configure View File

@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for pdns-recursor 4.1.4.
# Generated by GNU Autoconf 2.69 for pdns-recursor 4.1.7.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='pdns-recursor'
PACKAGE_TARNAME='pdns-recursor'
PACKAGE_VERSION='4.1.4'
PACKAGE_STRING='pdns-recursor 4.1.4'
PACKAGE_VERSION='4.1.7'
PACKAGE_STRING='pdns-recursor 4.1.7'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''

@@ -1445,7 +1445,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures pdns-recursor 4.1.4 to adapt to many kinds of systems.
\`configure' configures pdns-recursor 4.1.7 to adapt to many kinds of systems.

Usage: $0 [OPTION]... [VAR=VALUE]...

@@ -1515,7 +1515,7 @@ fi

if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of pdns-recursor 4.1.4:";;
short | recursive ) echo "Configuration of pdns-recursor 4.1.7:";;
esac
cat <<\_ACEOF

@@ -1677,7 +1677,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
pdns-recursor configure 4.1.4
pdns-recursor configure 4.1.7
generated by GNU Autoconf 2.69

Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2270,7 +2270,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.

It was created by pdns-recursor $as_me 4.1.4, which was
It was created by pdns-recursor $as_me 4.1.7, which was
generated by GNU Autoconf 2.69. Invocation command line was

$ $0 $@
@@ -3133,7 +3133,7 @@ fi

# Define the identity of the package.
PACKAGE='pdns-recursor'
VERSION='4.1.4'
VERSION='4.1.7'


cat >>confdefs.h <<_ACEOF
@@ -21846,7 +21846,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by pdns-recursor $as_me 4.1.4, which was
This file was extended by pdns-recursor $as_me 4.1.7, which was
generated by GNU Autoconf 2.69. Invocation command line was

CONFIG_FILES = $CONFIG_FILES
@@ -21912,7 +21912,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
pdns-recursor config.status 4.1.4
pdns-recursor config.status 4.1.7
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"



+ 1
- 1
dnsmessage.proto View File

@@ -46,7 +46,7 @@ message PBDNSMessage {
}
required Type type = 1;
optional bytes messageId = 2; // UUID, shared by the query and the response
optional bytes serverIdentity = 3; // UUID of the server emitting the protobuf message
optional bytes serverIdentity = 3; // ID of the server emitting the protobuf message
optional SocketFamily socketFamily = 4;
optional SocketProtocol socketProtocol = 5;
optional bytes from = 6; // DNS requestor (client)


+ 3
- 15
dnsparser.cc View File

@@ -131,7 +131,7 @@ std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(const DNSRecord &
return std::make_shared<UnknownRecordContent>(dr, pr);
}

return std::shared_ptr<DNSRecordContent>(i->second(dr, pr));
return i->second(dr, pr);
}

std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(uint16_t qtype, uint16_t qclass,
@@ -142,21 +142,9 @@ std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(uint16_t qtype, u
return std::make_shared<UnknownRecordContent>(content);
}

return std::shared_ptr<DNSRecordContent>(i->second(content));
return i->second(content);
}

std::unique_ptr<DNSRecordContent> DNSRecordContent::makeunique(uint16_t qtype, uint16_t qclass,
const string& content)
{
zmakermap_t::const_iterator i=getZmakermap().find(make_pair(qclass, qtype));
if(i==getZmakermap().end()) {
return std::unique_ptr<DNSRecordContent>(new UnknownRecordContent(content));
}

return std::unique_ptr<DNSRecordContent>(i->second(content));
}


std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t oc) {
// For opcode UPDATE and where the DNSRecord is an answer record, we don't care about content, because this is
// not used within the prerequisite section of RFC2136, so - we can simply use unknownrecordcontent.
@@ -171,7 +159,7 @@ std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(const DNSRecord &
return std::make_shared<UnknownRecordContent>(dr, pr);
}

return std::shared_ptr<DNSRecordContent>(i->second(dr, pr));
return i->second(dr, pr);
}




+ 2
- 3
dnsparser.hh View File

@@ -169,7 +169,6 @@ public:
static std::shared_ptr<DNSRecordContent> mastermake(const DNSRecord &dr, PacketReader& pr);
static std::shared_ptr<DNSRecordContent> mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t opcode);
static std::shared_ptr<DNSRecordContent> mastermake(uint16_t qtype, uint16_t qclass, const string& zone);
static std::unique_ptr<DNSRecordContent> makeunique(uint16_t qtype, uint16_t qclass, const string& content);

virtual std::string getZoneRepresentation(bool noDot=false) const = 0;
virtual ~DNSRecordContent() {}
@@ -201,8 +200,8 @@ public:

void doRecordCheck(const struct DNSRecord&){}

typedef DNSRecordContent* makerfunc_t(const struct DNSRecord& dr, PacketReader& pr);
typedef DNSRecordContent* zmakerfunc_t(const string& str);
typedef std::shared_ptr<DNSRecordContent> makerfunc_t(const struct DNSRecord& dr, PacketReader& pr);
typedef std::shared_ptr<DNSRecordContent> zmakerfunc_t(const string& str);

static void regist(uint16_t cl, uint16_t ty, makerfunc_t* f, zmakerfunc_t* z, const char* name)
{


+ 8
- 8
dnsrecords.cc View File

@@ -385,19 +385,19 @@ void EUI48RecordContent::report(void)
{
regist(1, QType::EUI48, &make, &make, "EUI48");
}
DNSRecordContent* EUI48RecordContent::make(const DNSRecord &dr, PacketReader& pr)
std::shared_ptr<DNSRecordContent> EUI48RecordContent::make(const DNSRecord &dr, PacketReader& pr)
{
if(dr.d_clen!=6)
throw MOADNSException("Wrong size for EUI48 record");

EUI48RecordContent* ret=new EUI48RecordContent();
auto ret=std::make_shared<EUI48RecordContent>();
pr.copyRecord((uint8_t*) &ret->d_eui48, 6);
return ret;
}
DNSRecordContent* EUI48RecordContent::make(const string& zone)
std::shared_ptr<DNSRecordContent> EUI48RecordContent::make(const string& zone)
{
// try to parse
EUI48RecordContent *ret=new EUI48RecordContent();
auto ret=std::make_shared<EUI48RecordContent>();
// format is 6 hex bytes and dashes
if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
ret->d_eui48, ret->d_eui48+1, ret->d_eui48+2,
@@ -428,19 +428,19 @@ void EUI64RecordContent::report(void)
{
regist(1, QType::EUI64, &make, &make, "EUI64");
}
DNSRecordContent* EUI64RecordContent::make(const DNSRecord &dr, PacketReader& pr)
std::shared_ptr<DNSRecordContent> EUI64RecordContent::make(const DNSRecord &dr, PacketReader& pr)
{
if(dr.d_clen!=8)
throw MOADNSException("Wrong size for EUI64 record");

EUI64RecordContent* ret=new EUI64RecordContent();
auto ret=std::make_shared<EUI64RecordContent>();
pr.copyRecord((uint8_t*) &ret->d_eui64, 8);
return ret;
}
DNSRecordContent* EUI64RecordContent::make(const string& zone)
std::shared_ptr<DNSRecordContent> EUI64RecordContent::make(const string& zone)
{
// try to parse
EUI64RecordContent *ret=new EUI64RecordContent();
auto ret=std::make_shared<EUI64RecordContent>();
// format is 8 hex bytes and dashes
if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
ret->d_eui64, ret->d_eui64+1, ret->d_eui64+2,


+ 20
- 20
dnsrecords.hh View File

@@ -33,8 +33,8 @@
RNAME##RecordContent(const string& zoneData); \
static void report(void); \
static void unreport(void); \
static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); \
static DNSRecordContent* make(const string& zonedata); \
static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr); \
static std::shared_ptr<DNSRecordContent> make(const string& zonedata); \
string getZoneRepresentation(bool noDot=false) const override; \
void toPacket(DNSPacketWriter& pw) override; \
uint16_t getType() const override { return QType::RNAME; } \
@@ -511,8 +511,8 @@ public:
{}
NSECRecordContent(const string& content, const string& zone=""); //FIXME400: DNSName& zone?

static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr);
static DNSRecordContent* make(const string& content);
static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr);
static std::shared_ptr<DNSRecordContent> make(const string& content);
string getZoneRepresentation(bool noDot=false) const override;
void toPacket(DNSPacketWriter& pw) override;
uint16_t getType() const override
@@ -532,8 +532,8 @@ public:
{}
NSEC3RecordContent(const string& content, const string& zone=""); //FIXME400: DNSName& zone?

static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr);
static DNSRecordContent* make(const string& content);
static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr);
static std::shared_ptr<DNSRecordContent> make(const string& content);
string getZoneRepresentation(bool noDot=false) const override;
void toPacket(DNSPacketWriter& pw) override;

@@ -561,8 +561,8 @@ public:
{}
NSEC3PARAMRecordContent(const string& content, const string& zone=""); // FIXME400: DNSName& zone?

static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr);
static DNSRecordContent* make(const string& content);
static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr);
static std::shared_ptr<DNSRecordContent> make(const string& content);
string getZoneRepresentation(bool noDot=false) const override;
void toPacket(DNSPacketWriter& pw) override;

@@ -586,8 +586,8 @@ public:
{}
LOCRecordContent(const string& content, const string& zone="");

static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr);
static DNSRecordContent* make(const string& content);
static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr);
static std::shared_ptr<DNSRecordContent> make(const string& content);
string getZoneRepresentation(bool noDot=false) const override;
void toPacket(DNSPacketWriter& pw) override;

@@ -610,8 +610,8 @@ public:
{}
WKSRecordContent(const string& content, const string& zone=""); // FIXME400: DNSName& zone?

static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr);
static DNSRecordContent* make(const string& content);
static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr);
static std::shared_ptr<DNSRecordContent> make(const string& content);
string getZoneRepresentation(bool noDot=false) const override;
void toPacket(DNSPacketWriter& pw) override;

@@ -625,8 +625,8 @@ class EUI48RecordContent : public DNSRecordContent
public:
EUI48RecordContent() {};
static void report(void);
static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr);
static DNSRecordContent* make(const string& zone); // FIXME400: DNSName& zone?
static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr);
static std::shared_ptr<DNSRecordContent> make(const string& zone); // FIXME400: DNSName& zone?
string getZoneRepresentation(bool noDot=false) const override;
void toPacket(DNSPacketWriter& pw) override;
uint16_t getType() const override { return QType::EUI48; }
@@ -640,8 +640,8 @@ class EUI64RecordContent : public DNSRecordContent
public:
EUI64RecordContent() {};
static void report(void);
static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr);
static DNSRecordContent* make(const string& zone); // FIXME400: DNSName& zone?
static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr);
static std::shared_ptr<DNSRecordContent> make(const string& zone); // FIXME400: DNSName& zone?
string getZoneRepresentation(bool noDot=false) const override;
void toPacket(DNSPacketWriter& pw) override;
uint16_t getType() const override { return QType::EUI64; }
@@ -688,9 +688,9 @@ class CAARecordContent : public DNSRecordContent {
};

#define boilerplate(RNAME, RTYPE) \
RNAME##RecordContent::DNSRecordContent* RNAME##RecordContent::make(const DNSRecord& dr, PacketReader& pr) \
std::shared_ptr<RNAME##RecordContent::DNSRecordContent> RNAME##RecordContent::make(const DNSRecord& dr, PacketReader& pr) \
{ \
return new RNAME##RecordContent(dr, pr); \
return std::make_shared<RNAME##RecordContent>(dr, pr); \
} \
\
RNAME##RecordContent::RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr) \
@@ -699,9 +699,9 @@ RNAME##RecordContent::RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr
xfrPacket(pr); \
} \
\
RNAME##RecordContent::DNSRecordContent* RNAME##RecordContent::make(const string& zonedata) \
std::shared_ptr<RNAME##RecordContent::DNSRecordContent> RNAME##RecordContent::make(const string& zonedata) \
{ \
return new RNAME##RecordContent(zonedata); \
return std::make_shared<RNAME##RecordContent>(zonedata); \
} \
\
void RNAME##RecordContent::toPacket(DNSPacketWriter& pw) \


+ 4
- 15
effective_tld_names.dat View File

@@ -8344,9 +8344,6 @@ golf
// goo : 2014-12-18 NTT Resonant Inc.
goo

// goodhands : 2015-07-31 Allstate Fire and Casualty Insurance Company
goodhands

// goodyear : 2015-07-02 The Goodyear Tire & Rubber Company
goodyear

@@ -8647,9 +8644,6 @@ jewelry
// jio : 2015-04-02 Reliance Industries Limited
jio

// jlc : 2014-12-04 Richemont DNS Inc.
jlc

// jll : 2015-04-02 Jones Lang LaSalle Incorporated
jll

@@ -9292,9 +9286,6 @@ page
// panasonic : 2015-07-30 Panasonic Corporation
panasonic

// panerai : 2014-11-07 Richemont DNS Inc.
panerai

// paris : 2014-01-30 City of Paris
paris

@@ -9997,9 +9988,6 @@ tech
// technology : 2013-09-13 Binky Moon, LLC
technology

// telecity : 2015-02-19 TelecityGroup International Limited
telecity

// telefonica : 2014-10-16 Telefónica S.A.
telefonica

@@ -10207,9 +10195,6 @@ visa
// vision : 2013-12-05 Binky Moon, LLC
vision

// vista : 2014-09-18 Vistaprint Limited
vista

// vistaprint : 2014-09-18 Vistaprint Limited
vistaprint

@@ -10827,6 +10812,10 @@ s3-website.us-east-2.amazonaws.com
t3l3p0rt.net
tele.amune.org

// Apigee : https://apigee.com/
// Submitted by Apigee Security Team <security@apigee.com>
apigee.io

// Aptible : https://www.aptible.com/
// Submitted by Thomas Orozco <thomas@aptible.com>
on-aptible.com


+ 22
- 7
lwres.cc View File

@@ -50,16 +50,22 @@

#ifdef HAVE_PROTOBUF

static void logOutgoingQuery(std::shared_ptr<RemoteLogger> outgoingLogger, boost::optional<const boost::uuids::uuid&> initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& ip, const DNSName& domain, int type, uint16_t qid, bool doTCP, size_t bytes)
static void logOutgoingQuery(std::shared_ptr<RemoteLogger> outgoingLogger, boost::optional<const boost::uuids::uuid&> initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& ip, const DNSName& domain, int type, uint16_t qid, bool doTCP, size_t bytes, boost::optional<Netmask>& srcmask)
{
if(!outgoingLogger)
return;

RecProtoBufMessage message(DNSProtoBufMessage::OutgoingQuery, uuid, nullptr, &ip, domain, type, QClass::IN, qid, doTCP, bytes);
message.setServerIdentity(SyncRes::s_serverID);

if (initialRequestId) {
message.setInitialRequestID(*initialRequestId);
}

if (srcmask) {
message.setEDNSSubnet(*srcmask);
}

// cerr <<message.toDebugString()<<endl;
std::string str;
message.serialize(str);
@@ -72,6 +78,7 @@ static void logIncomingResponse(std::shared_ptr<RemoteLogger> outgoingLogger, bo
return;

RecProtoBufMessage message(DNSProtoBufMessage::IncomingResponse, uuid, nullptr, &ip, domain, type, QClass::IN, qid, doTCP, bytes);
message.setServerIdentity(SyncRes::s_serverID);
if (initialRequestId) {
message.setInitialRequestID(*initialRequestId);
}
@@ -116,20 +123,23 @@ int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool d

string ping;
bool weWantEDNSSubnet=false;
uint8_t outgoingECSBits = 0;
ComboAddress outgoingECSAddr;
if(EDNS0Level > 0) {
DNSPacketWriter::optvect_t opts;
if(srcmask) {
EDNSSubnetOpts eo;
eo.source = *srcmask;
outgoingECSBits = srcmask->getBits();
outgoingECSAddr = srcmask->getNetwork();
// cout<<"Adding request mask: "<<eo.source.toString()<<endl;
opts.push_back(make_pair(8, makeEDNSSubnetOptsString(eo)));
opts.push_back(make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(eo)));
weWantEDNSSubnet=true;
}

pw.addOpt(g_outgoingEDNSBufsize, 0, g_dnssecmode == DNSSECMode::Off ? 0 : EDNSOpts::DNSSECOK, opts);
pw.commit();
}
srcmask = boost::none; // this is also our return value, even if EDNS0Level == 0
lwr->d_rcode = 0;
lwr->d_haveEDNS = false;
int ret;
@@ -144,10 +154,12 @@ int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool d

if (outgoingLogger) {
uuid = (*t_uuidGenerator)();
logOutgoingQuery(outgoingLogger, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, vpacket.size());
logOutgoingQuery(outgoingLogger, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, vpacket.size(), srcmask);
}
#endif

srcmask = boost::none; // this is also our return value, even if EDNS0Level == 0

errno=0;
if(!doTCP) {
int queryfd;
@@ -255,7 +267,7 @@ int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool d

if(weWantEDNSSubnet) {
for(const auto& opt : edo.d_options) {
if(opt.first==8) {
if(opt.first==EDNSOptionCode::ECS) {
EDNSSubnetOpts reso;
if(getEDNSSubnetOptsFromString(opt.second, &reso)) {
// cerr<<"EDNS Subnet response: "<<reso.source.toString()<<", scope: "<<reso.scope.toString()<<", family = "<<reso.scope.getNetwork().sin4.sin_family<<endl;
@@ -263,8 +275,11 @@ int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool d
so we might want to still pass the information along to be able to differentiate between
IPv4 and IPv6. Still I'm pretty sure it doesn't matter in real life, so let's not duplicate
entries in our cache. */
if(reso.scope.getBits())
srcmask = reso.scope;
if(reso.scope.getBits()) {
uint8_t bits = std::min(reso.scope.getBits(), outgoingECSBits);
outgoingECSAddr.truncate(bits);
srcmask = Netmask(outgoingECSAddr, bits);
}
}
}
}


+ 1
- 1
mtasker_ucontext.cc View File

@@ -134,7 +134,7 @@ pdns_makecontext
}
mcp->uc_link = next;
mcp->uc_stack.ss_sp = ctx.uc_stack.data();
mcp->uc_stack.ss_size = ctx.uc_stack.size();
mcp->uc_stack.ss_size = ctx.uc_stack.size()-1;
mcp->uc_stack.ss_flags = 0;

auto ctxarg = splitPointer (&ctx);


+ 12
- 12
nsecrecords.cc View File

@@ -29,9 +29,9 @@ void NSECRecordContent::report(void)
regist(1, 47, &make, &make, "NSEC");
}

DNSRecordContent* NSECRecordContent::make(const string& content)
std::shared_ptr<DNSRecordContent> NSECRecordContent::make(const string& content)
{
return new NSECRecordContent(content);
return std::make_shared<NSECRecordContent>(content);
}

NSECRecordContent::NSECRecordContent(const string& content, const string& zone)
@@ -81,9 +81,9 @@ void NSECRecordContent::toPacket(DNSPacketWriter& pw)
pw.xfrBlob(tmp);
}

NSECRecordContent::DNSRecordContent* NSECRecordContent::make(const DNSRecord &dr, PacketReader& pr)
std::shared_ptr<NSECRecordContent::DNSRecordContent> NSECRecordContent::make(const DNSRecord &dr, PacketReader& pr)
{
NSECRecordContent* ret=new NSECRecordContent();
auto ret=std::make_shared<NSECRecordContent>();
pr.xfrName(ret->d_next);
string bitmap;
pr.xfrBlob(bitmap);
@@ -136,9 +136,9 @@ void NSEC3RecordContent::report(void)
regist(1, 50, &make, &make, "NSEC3");
}

DNSRecordContent* NSEC3RecordContent::make(const string& content)
std::shared_ptr<DNSRecordContent> NSEC3RecordContent::make(const string& content)
{
return new NSEC3RecordContent(content);
return std::make_shared<NSEC3RecordContent>(content);
}

NSEC3RecordContent::NSEC3RecordContent(const string& content, const string& zone)
@@ -203,9 +203,9 @@ void NSEC3RecordContent::toPacket(DNSPacketWriter& pw)
}
}

NSEC3RecordContent::DNSRecordContent* NSEC3RecordContent::make(const DNSRecord &dr, PacketReader& pr)
std::shared_ptr<NSEC3RecordContent::DNSRecordContent> NSEC3RecordContent::make(const DNSRecord &dr, PacketReader& pr)
{
NSEC3RecordContent* ret=new NSEC3RecordContent();
auto ret=std::make_shared<NSEC3RecordContent>();
pr.xfr8BitInt(ret->d_algorithm);
pr.xfr8BitInt(ret->d_flags);
pr.xfr16BitInt(ret->d_iterations);
@@ -272,9 +272,9 @@ void NSEC3PARAMRecordContent::report(void)
regist(254, 51, &make, &make, "NSEC3PARAM");
}

DNSRecordContent* NSEC3PARAMRecordContent::make(const string& content)
std::shared_ptr<DNSRecordContent> NSEC3PARAMRecordContent::make(const string& content)
{
return new NSEC3PARAMRecordContent(content);
return std::make_shared<NSEC3PARAMRecordContent>(content);
}

NSEC3PARAMRecordContent::NSEC3PARAMRecordContent(const string& content, const string& zone)
@@ -296,9 +296,9 @@ void NSEC3PARAMRecordContent::toPacket(DNSPacketWriter& pw)
pw.xfrBlob(d_salt);
}

NSEC3PARAMRecordContent::DNSRecordContent* NSEC3PARAMRecordContent::make(const DNSRecord &dr, PacketReader& pr)
std::shared_ptr<NSEC3PARAMRecordContent::DNSRecordContent> NSEC3PARAMRecordContent::make(const DNSRecord &dr, PacketReader& pr)
{
NSEC3PARAMRecordContent* ret=new NSEC3PARAMRecordContent();
auto ret=std::make_shared<NSEC3PARAMRecordContent>();
pr.xfr8BitInt(ret->d_algorithm);
pr.xfr8BitInt(ret->d_flags);
pr.xfr16BitInt(ret->d_iterations);


+ 10
- 1
opensslsigners.cc View File

@@ -76,6 +76,8 @@ void openssl_thread_cleanup()
OPENSSL_free(openssllocks);
}

#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL
/* those symbols are defined in LibreSSL 2.7.0+ */
/* compat helpers. These DO NOT do any of the checking that the libssl 1.1 functions do. */
static inline void RSA_get0_key(const RSA* rsakey, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d) {
*n = rsakey->n;
@@ -143,6 +145,8 @@ static inline int ECDSA_SIG_set0(ECDSA_SIG* signature, BIGNUM* pr, BIGNUM* ps) {
}
#endif /* HAVE_LIBCRYPTO_ECDSA */

#endif /* !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL */

#else
void openssl_thread_setup() {}
void openssl_thread_cleanup() {}
@@ -597,14 +601,19 @@ public:
d_ecgroup = EC_GROUP_new_by_curve_name(NID_secp384r1);
d_len = 48;
} else {
EC_KEY_free(d_eckey);
throw runtime_error(getName()+" unknown algorithm "+std::to_string(d_algorithm));
}

if (d_ecgroup == NULL) {
EC_KEY_free(d_eckey);
throw runtime_error(getName()+" allocation of group structure failed");
}

ret = EC_KEY_set_group(d_eckey,d_ecgroup);
ret = EC_KEY_set_group(d_eckey, d_ecgroup);
if (ret != 1) {
EC_KEY_free(d_eckey);
EC_GROUP_free(d_ecgroup);
throw runtime_error(getName()+" setting key group failed");
}



+ 85
- 11
packetcache.hh View File

@@ -28,13 +28,13 @@

class PacketCache : public boost::noncopyable
{
protected:
static uint32_t canHashPacket(const std::string& packet, bool skipECS=true)
public:
static uint32_t canHashPacket(const std::string& packet, uint16_t* ecsBegin, uint16_t* ecsEnd)
{
uint32_t ret = 0;
ret=burtle((const unsigned char*)packet.c_str() + 2, 10, ret); // rest of dnsheader, skip id
ret = burtle(reinterpret_cast<const unsigned char*>(packet.c_str()) + 2, sizeof(dnsheader) - 2, ret); // rest of dnsheader, skip id
size_t packetSize = packet.size();
size_t pos = 12;
size_t pos = sizeof(dnsheader);
const char* end = packet.c_str() + packetSize;
const char* p = packet.c_str() + pos;

@@ -43,36 +43,110 @@ protected:
ret=burtle(&l, 1, ret);
} // XXX the embedded 0 in the qname will break the subnet stripping

struct dnsheader* dh = (struct dnsheader*)packet.c_str();
const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.c_str());
const char* skipBegin = p;
const char* skipEnd = p;
if (ecsBegin != nullptr && ecsEnd != nullptr) {
*ecsBegin = 0;
*ecsEnd = 0;
}
/* we need at least 1 (final empty label) + 2 (QTYPE) + 2 (QCLASS)
+ OPT root label (1), type (2), class (2) and ttl (4)
+ the OPT RR rdlen (2)
= 16
*/
if(skipECS && ntohs(dh->arcount)==1 && (pos+16) < packetSize) {
if(ntohs(dh->arcount)==1 && (pos+16) < packetSize) {
char* optionBegin = nullptr;
size_t optionLen = 0;
/* skip the final empty label (1), the qtype (2), qclass (2) */
/* root label (1), type (2), class (2) and ttl (4) */
int res = getEDNSOption((char*) p + 14, end - (p + 14), EDNSOptionCode::ECS, &optionBegin, &optionLen);
int res = getEDNSOption(const_cast<char*>(reinterpret_cast<const char*>(p)) + 14, end - (p + 14), EDNSOptionCode::ECS, &optionBegin, &optionLen);
if (res == 0) {
skipBegin = optionBegin;
skipEnd = optionBegin + optionLen;
if (ecsBegin != nullptr && ecsEnd != nullptr) {
*ecsBegin = optionBegin - packet.c_str();
*ecsEnd = *ecsBegin + optionLen;
}
}
}
if (skipBegin > p) {
// cerr << "Hashing from " << (p-packet.c_str()) << " for " << skipBegin-p << "bytes, end is at "<< end-packet.c_str() << endl;
ret = burtle((const unsigned char*)p, skipBegin-p, ret);
ret = burtle(reinterpret_cast<const unsigned char*>(p), skipBegin-p, ret);
}
if (skipEnd < end) {
// cerr << "Hashing from " << (skipEnd-packet.c_str()) << " for " << end-skipEnd << "bytes, end is at " << end-packet.c_str() << endl;
ret = burtle((const unsigned char*) skipEnd, end-skipEnd, ret);
ret = burtle(reinterpret_cast<const unsigned char*>(skipEnd), end-skipEnd, ret);
}

return ret;
}

static uint32_t canHashPacket(const std::string& packet)
{
uint32_t ret = 0;
ret = burtle(reinterpret_cast<const unsigned char*>(packet.c_str()) + 2, sizeof(dnsheader) - 2, ret); // rest of dnsheader, skip id
size_t packetSize = packet.size();
size_t pos = sizeof(dnsheader);
const char* end = packet.c_str() + packetSize;
const char* p = packet.c_str() + pos;

for(; p < end && *p; ++p) { // XXX if you embed a 0 in your qname we'll stop lowercasing there
const unsigned char l = dns_tolower(*p); // label lengths can safely be lower cased
ret=burtle(&l, 1, ret);
} // XXX the embedded 0 in the qname will break the subnet stripping

if (p < end) {
ret = burtle(reinterpret_cast<const unsigned char*>(p), end-p, ret);
}

return ret;
}

static bool queryHeaderMatches(const std::string& cachedQuery, const std::string& query)
{
if (cachedQuery.size() != query.size()) {
return false;
}

return (cachedQuery.compare(/* skip the ID */ 2, sizeof(dnsheader) - 2, query, 2, sizeof(dnsheader) - 2) == 0);
}

static bool queryMatches(const std::string& cachedQuery, const std::string& query, const DNSName& qname)
{
if (!queryHeaderMatches(cachedQuery, query)) {
return false;
}

size_t pos = sizeof(dnsheader) + qname.wirelength();

return (cachedQuery.compare(pos, cachedQuery.size() - pos, query, pos, query.size() - pos) == 0);
}

static bool queryMatches(const std::string& cachedQuery, const std::string& query, const DNSName& qname, uint16_t ecsBegin, uint16_t ecsEnd)
{
if (!queryHeaderMatches(cachedQuery, query)) {
return false;
}

size_t pos = sizeof(dnsheader) + qname.wirelength();

if (ecsBegin != 0 && ecsBegin >= pos && ecsEnd > ecsBegin) {
if (cachedQuery.compare(pos, ecsBegin - pos, query, pos, ecsBegin - pos) != 0) {
return false;
}

if (cachedQuery.compare(ecsEnd, cachedQuery.size() - ecsEnd, query, ecsEnd, query.size() - ecsEnd) != 0) {
return false;
}
}
else {
if (cachedQuery.compare(pos, cachedQuery.size() - pos, query, pos, query.size() - pos) != 0) {
return false;
}
}

return true;
}

};

#endif /* PACKETCACHE_HH */

+ 1
- 1
pdns_recursor.1 View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "PDNS_RECURSOR" "1" "Aug 31, 2018" "4.1" "PowerDNS Recursor"
.TH "PDNS_RECURSOR" "1" "Nov 09, 2018" "4.1" "PowerDNS Recursor"
.SH NAME
pdns_recursor \- The PowerDNS Recursor binary
.


+ 28
- 7
pdns_recursor.cc View File

@@ -219,6 +219,7 @@ struct DNSComboWriter {
string d_requestorId;
string d_deviceId;
#endif
std::string d_query;
EDNSSubnetOpts d_ednssubnet;
bool d_ecsFound{false};
bool d_ecsParsed{false};
@@ -226,12 +227,13 @@ struct DNSComboWriter {
int d_socket;
unsigned int d_tag{0};
uint32_t d_qhash{0};
string d_query;
shared_ptr<TCPConnection> d_tcpConnection;
vector<pair<uint16_t, string> > d_ednsOpts;
std::vector<std::string> d_policyTags;
LuaContext::LuaObject d_data;
uint32_t d_ttlCap{std::numeric_limits<uint32_t>::max()};
uint16_t d_ecsBegin{0};
uint16_t d_ecsEnd{0};
bool d_variable{false};
};

@@ -666,6 +668,7 @@ static void protobufLogQuery(const std::shared_ptr<RemoteLogger>& logger, uint8_
Netmask requestorNM(remote, remote.sin4.sin_family == AF_INET ? maskV4 : maskV6);
const ComboAddress& requestor = requestorNM.getMaskedNetwork();
RecProtoBufMessage message(DNSProtoBufMessage::Query, uniqueId, &requestor, &local, qname, qtype, qclass, id, tcp, len);
message.setServerIdentity(SyncRes::s_serverID);
message.setEDNSSubnet(ednssubnet, ednssubnet.isIpv4() ? maskV4 : maskV6);
message.setRequestorId(requestorId);
message.setDeviceId(deviceId);
@@ -777,6 +780,7 @@ static void startDoResolve(void *p)
if (luaconfsLocal->protobufServer) {
Netmask requestorNM(dc->d_remote, dc->d_remote.sin4.sin_family == AF_INET ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
const ComboAddress& requestor = requestorNM.getMaskedNetwork();
pbMessage.setServerIdentity(SyncRes::s_serverID);
pbMessage.update(dc->d_uuid, &requestor, &dc->d_local, dc->d_tcp, dc->d_mdp.d_header.id);
pbMessage.setEDNSSubnet(dc->d_ednssubnet.source, dc->d_ednssubnet.source.isIpv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
pbMessage.setQuestion(dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass);
@@ -1208,11 +1212,13 @@ static void startDoResolve(void *p)
L<<Logger::Warning<<"Sending UDP reply to client "<<dc->d_remote.toStringWithPort()<<" failed with: "<<strerror(errno)<<endl;

if(!SyncRes::s_nopacketcache && !variableAnswer && !sr.wasVariable() ) {
t_packetCache->insertResponsePacket(dc->d_tag, dc->d_qhash, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass,
t_packetCache->insertResponsePacket(dc->d_tag, dc->d_qhash, dc->d_query, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass,
string((const char*)&*packet.begin(), packet.size()),
g_now.tv_sec,
pw.getHeader()->rcode == RCode::ServFail ? SyncRes::s_packetcacheservfailttl :
min(minTTL,SyncRes::s_packetcachettl),
dc->d_ecsBegin,
dc->d_ecsEnd,
&pbMessage);
}
// else cerr<<"Not putting in packet cache: "<<sr.wasVariable()<<endl;
@@ -1344,6 +1350,7 @@ static void startDoResolve(void *p)
}
catch(...) {
L<<Logger::Error<<"Any other exception in a resolver context "<< makeLoginfo(dc) <<endl;
delete dc;
}

g_stats.maxMThreadStackUsage = max(MT->getMaxStackUsage(), g_stats.maxMThreadStackUsage);
@@ -1664,6 +1671,8 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
EDNSSubnetOpts ednssubnet;
bool ecsFound = false;
bool ecsParsed = false;
uint16_t ecsBegin = 0;
uint16_t ecsEnd = 0;
uint32_t ttlCap = std::numeric_limits<uint32_t>::max();
bool variable = false;
try {
@@ -1716,6 +1725,7 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
bool cacheHit = false;
RecProtoBufMessage pbMessage(DNSProtoBufMessage::DNSProtoBufMessageType::Response);
#ifdef HAVE_PROTOBUF
pbMessage.setServerIdentity(SyncRes::s_serverID);
if(luaconfsLocal->protobufServer) {
if (!luaconfsLocal->protobufTaggedOnly || !policyTags.empty()) {
protobufLogQuery(luaconfsLocal->protobufServer, luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, uniqueId, fromaddr, destaddr, ednssubnet.source, false, dh->id, question.size(), qname, qtype, qclass, policyTags, requestorId, deviceId);
@@ -1727,10 +1737,10 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
but it means that the hash would not be computed. If some script decides at a later time to mark back the answer
as cacheable we would cache it with a wrong tag, so better safe than sorry. */
if (qnameParsed) {
cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, qtype, qclass, g_now.tv_sec, &response, &age, &qhash, &pbMessage));
cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, qtype, qclass, g_now.tv_sec, &response, &age, &qhash, &ecsBegin, &ecsEnd, &pbMessage));
}
else {
cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, g_now.tv_sec, &response, &age, &qhash, &pbMessage));
cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, &qtype, &qclass, g_now.tv_sec, &response, &age, &qhash, &ecsBegin, &ecsEnd, &pbMessage));
}

if (cacheHit) {
@@ -1808,6 +1818,8 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
dc->d_data = data;
dc->d_ecsFound = ecsFound;
dc->d_ecsParsed = ecsParsed;
dc->d_ecsBegin = ecsBegin;
dc->d_ecsEnd = ecsEnd;
dc->d_ednssubnet = ednssubnet;
dc->d_ttlCap = ttlCap;
dc->d_variable = variable;
@@ -2955,14 +2967,21 @@ static int serviceMain(int argc, char*argv[])
exit(1);
}

g_signatureInceptionSkew = ::arg().asNum("signature-inception-skew");
if (g_signatureInceptionSkew < 0) {
L<<Logger::Error<<"A negative value for 'signature-inception-skew' is not allowed"<<endl;
exit(1);
}

g_dnssecLogBogus = ::arg().mustDo("dnssec-log-bogus");
g_maxNSEC3Iterations = ::arg().asNum("nsec3-max-iterations");

g_maxCacheEntries = ::arg().asNum("max-cache-entries");
g_maxPacketCacheEntries = ::arg().asNum("max-packetcache-entries");

luaConfigDelayedThreads delayedLuaThreads;
try {
loadRecursorLuaConfig(::arg()["lua-config-file"], ::arg().mustDo("daemon"));
loadRecursorLuaConfig(::arg()["lua-config-file"], delayedLuaThreads);
}
catch (PDNSException &e) {
L<<Logger::Error<<"Cannot load Lua configuration: "<<e.reason<<endl;
@@ -3126,7 +3145,6 @@ static int serviceMain(int argc, char*argv[])
L<<Logger::Warning<<"Calling daemonize, going to background"<<endl;
L.toConsole(Logger::Critical);
daemonize();
loadRecursorLuaConfig(::arg()["lua-config-file"], false);
}
signal(SIGUSR1,usr1Handler);
signal(SIGUSR2,usr2Handler);
@@ -3179,6 +3197,8 @@ static int serviceMain(int argc, char*argv[])

Utility::dropUserPrivs(newuid);

startLuaConfigDelayedThreads(delayedLuaThreads);

makeThreadPipes();

g_tcpTimeout=::arg().asNum("client-tcp-timeout");
@@ -3413,6 +3433,7 @@ int main(int argc, char **argv)
::arg().set("trace","if we should output heaps of logging. set to 'fail' to only log failing domains")="off";
::arg().set("dnssec", "DNSSEC mode: off/process-no-validate (default)/process/log-fail/validate")="process-no-validate";
::arg().set("dnssec-log-bogus", "Log DNSSEC bogus validations")="no";
::arg().set("signature-inception-skew", "Allow the signture inception to be off by this number of seconds")="0";
::arg().set("daemon","Operate as a daemon")="no";
::arg().setSwitch("write-pid","Write a PID file")="yes";
::arg().set("loglevel","Amount of logging. Higher is more. Do not set below 3")="6";


+ 7
- 0
protobuf.cc View File

@@ -243,6 +243,13 @@ void DNSProtoBufMessage::setDeviceId(const std::string& deviceId)
#endif /* HAVE_PROTOBUF */
}

void DNSProtoBufMessage::setServerIdentity(const std::string& serverId)
{
#ifdef HAVE_PROTOBUF
d_message.set_serveridentity(serverId);
#endif /* HAVE_PROTOBUF */
}

void DNSProtoBufMessage::setResponder(const std::string& responder)
{
#ifdef HAVE_PROTOBUF


+ 1
- 0
protobuf.hh View File

@@ -70,6 +70,7 @@ public:
void setResponder(const ComboAddress& responder);
void setRequestorId(const std::string& requestorId);
void setDeviceId(const std::string& deviceId);
void setServerIdentity(const std::string& serverId);
std::string toDebugString() const;
void addTag(const std::string& strValue);
void addRR(const DNSName& qame, uint16_t utype, uint16_t uClass, uint32_t uTTl, const std::string& strBlob);


+ 1
- 0
pubsuffix.cc View File

@@ -5566,6 +5566,7 @@ const char* g_pubsuffix[]={
"s3-website.us-east-2.amazonaws.com",
"t3l3p0rt.net",
"tele.amune.org",
"apigee.io",
"on-aptible.com",
"user.party.eus",
"pimienta.org",


+ 41
- 32
rec-lua-conf.cc View File

@@ -35,7 +35,7 @@ LuaConfigItems::LuaConfigItems()
{
DNSName root("."); // don't use g_rootdnsname here, it might not exist yet
for (const auto &dsRecord : rootDSs) {
auto ds=unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(dsRecord)));
auto ds=std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(dsRecord));
dsAnchors[root].insert(*ds);
}
}
@@ -81,7 +81,7 @@ static void parseRPZParameters(const std::unordered_map<string,boost::variant<ui
}
}

void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
void loadRecursorLuaConfig(const std::string& fname, luaConfigDelayedThreads& delayedThreads)
{
LuaConfigItems lci;

@@ -92,10 +92,23 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
if(!ifs)
throw PDNSException("Cannot open file '"+fname+"': "+strerror(errno));

std::vector<std::tuple<ComboAddress, boost::optional<DNSFilterEngine::Policy>, uint32_t, size_t, TSIGTriplet, size_t, ComboAddress, uint16_t> > rpzMasterThreads;

auto luaconfsLocal = g_luaconfs.getLocal();

// pdnslog here is compatible with pdnslog in lua-base4.cc.
Lua.writeFunction("pdnslog", [](const std::string& msg, boost::optional<int> loglevel) { L << (Logger::Urgency)loglevel.get_value_or(Logger::Warning) << msg<<endl; });
std::unordered_map<string, std::unordered_map<string, int>> pdns_table;
pdns_table["loglevels"] = std::unordered_map<string, int>{
{"Alert", LOG_ALERT},
{"Critical", LOG_CRIT},
{"Debug", LOG_DEBUG},
{"Emergency", LOG_EMERG},
{"Info", LOG_INFO},
{"Notice", LOG_NOTICE},
{"Warning", LOG_WARNING},
{"Error", LOG_ERR}
};
Lua.writeVariable("pdns", pdns_table);

Lua.writeFunction("clearSortlist", [&lci]() { lci.sortlist.clear(); });
/* we can get: "1.2.3.4"
@@ -138,7 +151,7 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
}
});

Lua.writeFunction("rpzMaster", [&lci, &rpzMasterThreads, checkOnly](const string& master_, const string& zoneName, const boost::optional<std::unordered_map<string,boost::variant<uint32_t, string>>>& options) {
Lua.writeFunction("rpzMaster", [&lci, &delayedThreads](const string& master_, const string& zoneName, const boost::optional<std::unordered_map<string,boost::variant<uint32_t, string>>>& options) {

boost::optional<DNSFilterEngine::Policy> defpol;
std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
@@ -198,7 +211,7 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
exit(1); // FIXME proper exit code?
}

rpzMasterThreads.push_back(std::make_tuple(master, defpol, maxTTL, zoneIdx, tt, maxReceivedXFRMBytes, localAddress, axfrTimeout));
delayedThreads.rpzMasterThreads.push_back(std::make_tuple(master, defpol, maxTTL, zoneIdx, tt, maxReceivedXFRMBytes, localAddress, axfrTimeout));
});

typedef vector<pair<int,boost::variant<string, vector<pair<int, string> > > > > argvec_t;
@@ -236,7 +249,7 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
Lua.writeFunction("addDS", [&lci](const std::string& who, const std::string& what) {
warnIfDNSSECDisabled("Warning: adding Trust Anchor for DNSSEC (addDS), but dnssec is set to 'off'!");
DNSName zone(who);
auto ds = unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(what)));
auto ds=std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(what));
lci.dsAnchors[zone].insert(*ds);
});

@@ -265,13 +278,11 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
});

#if HAVE_PROTOBUF
Lua.writeFunction("protobufServer", [&lci, checkOnly](const string& server_, const boost::optional<uint16_t> timeout, const boost::optional<uint64_t> maxQueuedEntries, const boost::optional<uint8_t> reconnectWaitTime, const boost::optional<uint8_t> maskV4, boost::optional<uint8_t> maskV6, boost::optional<bool> asyncConnect, boost::optional<bool> taggedOnly) {
Lua.writeFunction("protobufServer", [&lci](const string& server_, const boost::optional<uint16_t> timeout, const boost::optional<uint64_t> maxQueuedEntries, const boost::optional<uint8_t> reconnectWaitTime, const boost::optional<uint8_t> maskV4, boost::optional<uint8_t> maskV6, boost::optional<bool> asyncConnect, boost::optional<bool> taggedOnly) {
try {
ComboAddress server(server_);
if (!lci.protobufServer) {
if (!checkOnly) {
lci.protobufServer = std::make_shared<RemoteLogger>(server, timeout ? *timeout : 2, maxQueuedEntries ? *maxQueuedEntries : 100, reconnectWaitTime ? *reconnectWaitTime : 1, asyncConnect ? *asyncConnect : false);
}
lci.protobufServer = std::make_shared<RemoteLogger>(server, timeout ? *timeout : 2, maxQueuedEntries ? *maxQueuedEntries : 100, reconnectWaitTime ? *reconnectWaitTime : 1, asyncConnect ? *asyncConnect : false);

if (maskV4) {
lci.protobufMaskV4 = *maskV4;
@@ -295,13 +306,11 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
}
});

Lua.writeFunction("outgoingProtobufServer", [&lci, checkOnly](const string& server_, const boost::optional<uint16_t> timeout, const boost::optional<uint64_t> maxQueuedEntries, const boost::optional<uint8_t> reconnectWaitTime, boost::optional<bool> asyncConnect) {
Lua.writeFunction("outgoingProtobufServer", [&lci](const string& server_, const boost::optional<uint16_t> timeout, const boost::optional<uint64_t> maxQueuedEntries, const boost::optional<uint8_t> reconnectWaitTime, boost::optional<bool> asyncConnect) {
try {
ComboAddress server(server_);
if (!lci.outgoingProtobufServer) {
if (!checkOnly) {
lci.outgoingProtobufServer = std::make_shared<RemoteLogger>(server, timeout ? *timeout : 2, maxQueuedEntries ? *maxQueuedEntries : 100, reconnectWaitTime ? *reconnectWaitTime : 1, asyncConnect ? *asyncConnect : false);
}
lci.outgoingProtobufServer = std::make_shared<RemoteLogger>(server, timeout ? *timeout : 2, maxQueuedEntries ? *maxQueuedEntries : 100, reconnectWaitTime ? *reconnectWaitTime : 1, asyncConnect ? *asyncConnect : false);
}
else {
theL()<<Logger::Error<<"Only one protobuf server can be configured, we already have "<<lci.protobufServer->toString()<<endl;
@@ -319,23 +328,6 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
try {
Lua.executeCode(ifs);
g_luaconfs.setState(lci);

if (!checkOnly) {
for (const auto& rpzMaster : rpzMasterThreads) {
try {
std::thread t(RPZIXFRTracker, std::get<0>(rpzMaster), std::get<1>(rpzMaster), std::get<2>(rpzMaster), std::get<3>(rpzMaster), std::get<4>(rpzMaster), std::get<5>(rpzMaster) * 1024 * 1024, std::get<6>(rpzMaster), std::get<7>(rpzMaster));
t.detach();
}
catch(const std::exception& e) {
L<<Logger::Error<<"Problem starting RPZIXFRTracker thread: "<<e.what()<<endl;
exit(1); // FIXME proper exit code?
}
catch(const PDNSException& e) {
L<<Logger::Error<<"Problem starting RPZIXFRTracker thread: "<<e.reason<<endl;
exit(1); // FIXME proper exit code?
}
}
}
}
catch(const LuaContext::ExecutionErrorException& e) {
theL()<<Logger::Error<<"Unable to load Lua script from '"+fname+"': ";
@@ -359,3 +351,20 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)

}

void startLuaConfigDelayedThreads(const luaConfigDelayedThreads& delayedThreads)
{
for (const auto& rpzMaster : delayedThreads.rpzMasterThreads) {
try {
std::thread t(RPZIXFRTracker, std::get<0>(rpzMaster), std::get<1>(rpzMaster), std::get<2>(rpzMaster), std::get<3>(rpzMaster), std::get<4>(rpzMaster), std::get<5>(rpzMaster) * 1024 * 1024, std::get<6>(rpzMaster), std::get<7>(rpzMaster));
t.detach();
}
catch(const std::exception& e) {
L<<Logger::Error<<"Problem starting RPZIXFRTracker thread: "<<e.what()<<endl;
exit(1); // FIXME proper exit code?
}
catch(const PDNSException& e) {
L<<Logger::Error<<"Problem starting RPZIXFRTracker thread: "<<e.reason<<endl;
exit(1); // FIXME proper exit code?
}
}
}

+ 8
- 1
rec-lua-conf.hh View File

@@ -42,5 +42,12 @@ public:
};

extern GlobalStateHolder<LuaConfigItems> g_luaconfs;
void loadRecursorLuaConfig(const std::string& fname, bool checkOnly);

struct luaConfigDelayedThreads
{
std::vector<std::tuple<ComboAddress, boost::optional<DNSFilterEngine::Policy>, uint32_t, size_t, TSIGTriplet, size_t, ComboAddress, uint16_t> > rpzMasterThreads;
};

void loadRecursorLuaConfig(const std::string& fname, luaConfigDelayedThreads& delayedThreads);
void startLuaConfigDelayedThreads(const luaConfigDelayedThreads& delayedThreads);


+ 13
- 3
rec_channel_rec.cc View File

@@ -435,7 +435,9 @@ string doAddNTA(T begin, T end)
g_luaconfs.modify([who, why](LuaConfigItems& lci) {
lci.negAnchors[who] = why;
});
broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, who, true));
broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, who, true));
broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, who, true));
return "Added Negative Trust Anchor for " + who.toLogString() + " with reason '" + why + "'\n";
}

@@ -481,7 +483,9 @@ string doClearNTA(T begin, T end)
g_luaconfs.modify([entry](LuaConfigItems& lci) {
lci.negAnchors.erase(entry);
});
broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, entry, true));
broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, entry, true));
broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, entry, true));
if (!first) {
first = false;
removed += ",";
@@ -533,10 +537,12 @@ string doAddTA(T begin, T end)
try {
L<<Logger::Warning<<"Adding Trust Anchor for "<<who<<" with data '"<<what<<"', requested via control channel";
g_luaconfs.modify([who, what](LuaConfigItems& lci) {
auto ds = unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(what)));
auto ds=std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(what));
lci.dsAnchors[who].insert(*ds);
});
broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, who, true));
broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, who, true));
broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, who, true));
L<<Logger::Warning<<endl;
return "Added Trust Anchor for " + who.toStringRootDot() + " with data " + what + "\n";
}
@@ -580,7 +586,9 @@ string doClearTA(T begin, T end)
g_luaconfs.modify([entry](LuaConfigItems& lci) {
lci.dsAnchors.erase(entry);
});
broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, entry, true));
broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, entry, true));
broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, entry, true));
if (!first) {
first = false;
removed += ",";
@@ -1186,7 +1194,7 @@ string doGenericTopQueries(pleasequeryfunc_t func, boost::function<DNSName(const
int limit=0, accounted=0;
if(total) {
for(rcounts_t::const_iterator i=rcounts.begin(); i != rcounts.end() && limit < 20; ++i, ++limit) {
ret<< fmt % (-100.0*i->first/total) % (i->second.first.toString()+"|"+DNSRecordContent::NumberToType(i->second.second));
ret<< fmt % (-100.0*i->first/total) % (i->second.first.toLogString()+"|"+DNSRecordContent::NumberToType(i->second.second));
accounted+= -i->first;
}
ret<< '\n' << fmt % (100.0*(total-accounted)/total) % "rest";
@@ -1304,7 +1312,9 @@ string RecursorControlParser::getAnswer(const string& question, RecursorControlP
::arg().set("lua-config-file") = *begin;

try {
loadRecursorLuaConfig(::arg()["lua-config-file"], false);
luaConfigDelayedThreads delayedLuaThreads;
loadRecursorLuaConfig(::arg()["lua-config-file"], delayedLuaThreads);
startLuaConfigDelayedThreads(delayedLuaThreads);
L<<Logger::Warning<<"Reloaded Lua configuration file '"<<::arg()["lua-config-file"]<<"', requested via control channel"<<endl;
return "Reloaded Lua configuration file '"+::arg()["lua-config-file"]+"'\n";
}


+ 1
- 1
rec_control.1 View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "REC_CONTROL" "1" "Aug 31, 2018" "4.1" "PowerDNS Recursor"
.TH "REC_CONTROL" "1" "Nov 09, 2018" "4.1" "PowerDNS Recursor"
.SH NAME
rec_control \- Command line tool to control a running Recursor
.


+ 43
- 24
recpacketcache.cc View File

@@ -43,19 +43,29 @@ int RecursorPacketCache::doWipePacketCache(const DNSName& name, uint16_t qtype,
return count;
}

static bool qrMatch(const DNSName& qname, uint16_t qtype, uint16_t qclass, const DNSName& rname, uint16_t rtype, uint16_t rclass)
bool RecursorPacketCache::qrMatch(const packetCache_t::index<HashTag>::type::iterator& iter, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t ecsBegin, uint16_t ecsEnd)
{
// this ignores checking on the EDNS subnet flags!
return qname==rname && rtype == qtype && rclass == qclass;
if (qname != iter->d_name || iter->d_type != qtype || iter->d_class != qclass) {
return false;
}

if (iter->d_ecsBegin != ecsBegin || iter->d_ecsEnd != ecsEnd) {
return false;
}

return queryMatches(iter->d_query, queryPacket, qname, ecsBegin, ecsEnd);
}

bool RecursorPacketCache::checkResponseMatches(std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage)
bool RecursorPacketCache::checkResponseMatches(std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage, uint16_t ecsBegin, uint16_t ecsEnd)
{
for(auto iter = range.first ; iter != range.second ; ++ iter) {
for(auto iter = range.first ; iter != range.second ; ++iter) {
// the possibility is VERY real that we get hits that are not right - birthday paradox
if(!qrMatch(qname, qtype, qclass, iter->d_name, iter->d_type, iter->d_class))
if (!qrMatch(iter, queryPacket, qname, qtype, qclass, ecsBegin, ecsEnd)) {
continue;
if(now < iter->d_ttd) { // it is right, it is fresh!
}

if (now < iter->d_ttd) { // it is right, it is fresh!
*age = static_cast<uint32_t>(now - iter->d_creation);
*responsePacket = iter->d_packet;
responsePacket->replace(0, 2, queryPacket.c_str(), 2);
@@ -93,19 +103,25 @@ bool RecursorPacketCache::checkResponseMatches(std::pair<packetCache_t::index<Ha
bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now,
std::string* responsePacket, uint32_t* age, uint32_t* qhash)
{
return getResponsePacket(tag, queryPacket, now, responsePacket, age, qhash, nullptr);
DNSName qname;
uint16_t qtype, qclass;
uint16_t ecsBegin;
uint16_t ecsEnd;
return getResponsePacket(tag, queryPacket, qname, &qtype, &qclass, now, responsePacket, age, qhash, &ecsBegin, &ecsEnd, nullptr);
}

bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now,
std::string* responsePacket, uint32_t* age, uint32_t* qhash)
{
return getResponsePacket(tag, queryPacket, qname, qtype, qclass, now, responsePacket, age, qhash, nullptr);
uint16_t ecsBegin;
uint16_t ecsEnd;
return getResponsePacket(tag, queryPacket, qname, qtype, qclass, now, responsePacket, age, qhash, &ecsBegin, &ecsEnd, nullptr);
}

bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now,
std::string* responsePacket, uint32_t* age, uint32_t* qhash, RecProtoBufMessage* protobufMessage)
std::string* responsePacket, uint32_t* age, uint32_t* qhash, uint16_t* ecsBegin, uint16_t* ecsEnd, RecProtoBufMessage* protobufMessage)
{
*qhash = canHashPacket(queryPacket, true);
*qhash = canHashPacket(queryPacket, ecsBegin, ecsEnd);
const auto& idx = d_packetCache.get<HashTag>();
auto range = idx.equal_range(tie(tag,*qhash));

@@ -114,13 +130,13 @@ bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string&
return false;
}

return checkResponseMatches(range, queryPacket, qname, qtype, qclass, now, responsePacket, age, protobufMessage);
return checkResponseMatches(range, queryPacket, qname, qtype, qclass, now, responsePacket, age, protobufMessage, *ecsBegin, *ecsEnd);
}

bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now,
std::string* responsePacket, uint32_t* age, uint32_t* qhash, RecProtoBufMessage* protobufMessage)
bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, DNSName& qname, uint16_t* qtype, uint16_t* qclass, time_t now,
std::string* responsePacket, uint32_t* age, uint32_t* qhash, uint16_t* ecsBegin, uint16_t* ecsEnd, RecProtoBufMessage* protobufMessage)
{
*qhash = canHashPacket(queryPacket, true);
*qhash = canHashPacket(queryPacket, ecsBegin, ecsEnd);
const auto& idx = d_packetCache.get<HashTag>();
auto range = idx.equal_range(tie(tag,*qhash));

@@ -129,30 +145,33 @@ bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string&
return false;
}

uint16_t qtype, qclass;
DNSName qname(queryPacket.c_str(), queryPacket.length(), sizeof(dnsheader), false, &qtype, &qclass, 0);
qname = DNSName(queryPacket.c_str(), queryPacket.length(), sizeof(dnsheader), false, qtype, qclass, 0);

return checkResponseMatches(range, queryPacket, qname, qtype, qclass, now, responsePacket, age, protobufMessage);
return checkResponseMatches(range, queryPacket, qname, *qtype, *qclass, now, responsePacket, age, protobufMessage, *ecsBegin, *ecsEnd);
}


void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl)
void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, const std::string& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl, uint16_t ecsBegin, uint16_t ecsEnd)
{
insertResponsePacket(tag, qhash, qname, qtype, qclass, responsePacket, now, ttl, nullptr);
insertResponsePacket(tag, qhash, query, qname, qtype, qclass, responsePacket, now, ttl, ecsBegin, ecsEnd, nullptr);
}

void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl, const RecProtoBufMessage* protobufMessage)
void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, const std::string& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl, uint16_t ecsBegin, uint16_t ecsEnd, const RecProtoBufMessage* protobufMessage)
{
auto& idx = d_packetCache.get<HashTag>();
auto range = idx.equal_range(tie(tag,qhash));
auto iter = range.first;

for( ; iter != range.second ; ++iter) {
if(iter->d_type != qtype || iter->d_class != qclass || iter->d_name != qname)
if (iter->d_type != qtype || iter->d_class != qclass || iter->d_name != qname) {
continue;
}

moveCacheItemToBack(d_packetCache, iter);
iter->d_packet = responsePacket;
iter->d_query = query;
iter->d_ecsBegin = ecsBegin;
iter->d_ecsEnd = ecsEnd;
iter->d_ttd = now + ttl;
iter->d_creation = now;
#ifdef HAVE_PROTOBUF
@@ -165,10 +184,10 @@ void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash,
}
if(iter == range.second) { // nothing to refresh
struct Entry e;
e.d_packet = responsePacket;
e.d_name = qname;
struct Entry e(qname, responsePacket, query);
e.d_qhash = qhash;
e.d_ecsBegin = ecsBegin;
e.d_ecsEnd = ecsEnd;
e.d_type = qtype;
e.d_class = qclass;
e.d_ttd = now+ttl;


+ 17
- 8
recpacketcache.hh View File

@@ -57,9 +57,10 @@ public:
bool getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash);
bool getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash, RecProtoBufMessage* protobufMessage);
bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash);
bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash, RecProtoBufMessage* protobufMessage);
void insertResponsePacket(unsigned int tag, uint32_t qhash, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl);
void insertResponsePacket(unsigned int tag, uint32_t qhash, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl, const RecProtoBufMessage* protobufMessage);
bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash, uint16_t* ecsBegin, uint16_t* ecsEnd, RecProtoBufMessage* protobufMessage);
bool getResponsePacket(unsigned int tag, const std::string& queryPacket, DNSName& qname, uint16_t* qtype, uint16_t* qclass, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash, uint16_t* ecsBegin, uint16_t* ecsEnd, RecProtoBufMessage* protobufMessage);
void insertResponsePacket(unsigned int tag, uint32_t qhash, const std::string& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl, uint16_t ecsBegin, uint16_t ecsEnd);
void insertResponsePacket(unsigned int tag, uint32_t qhash, const std::string& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string& responsePacket, time_t now, uint32_t ttl, uint16_t ecsBegin, uint16_t ecsEnd, const RecProtoBufMessage* protobufMessage);
void doPruneTo(unsigned int maxSize=250000);
uint64_t doDump(int fd);
int doWipePacketCache(const DNSName& name, uint16_t qtype=0xffff, bool subtree=false);
@@ -74,17 +75,24 @@ private:
struct NameTag {};
struct Entry
{
mutable time_t d_ttd;
mutable time_t d_creation; // so we can 'age' our packets
Entry(const DNSName& qname, const std::string& packet, const std::string& query): d_name(qname), d_packet(packet), d_query(query)
{
}

DNSName d_name;
uint16_t d_type;
uint16_t d_class;
mutable std::string d_packet; // "I know what I am doing"
mutable std::string d_query;
#ifdef HAVE_PROTOBUF
mutable RecProtoBufMessage d_protobufMessage;
#endif
mutable time_t d_ttd;
mutable time_t d_creation; // so we can 'age' our packets
uint32_t d_qhash;
uint32_t d_tag;
uint16_t d_type;
uint16_t d_class;
mutable uint16_t d_ecsBegin;
mutable uint16_t d_ecsEnd;
inline bool operator<(const struct Entry& rhs) const;
time_t getTTD() const
@@ -104,7 +112,8 @@ private:
packetCache_t d_packetCache;

bool checkResponseMatches(std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage);
static bool qrMatch(const packetCache_t::index<HashTag>::type::iterator& iter, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t ecsBegin, uint16_t ecsEnd);
bool checkResponseMatches(std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage, uint16_t ecsBegin, uint16_t ecsEnd);

public:
void preRemoval(const Entry& entry)


+ 1
- 1
recursor_cache.hh View File

@@ -108,7 +108,7 @@ private:
class ECSIndexEntry
{
public:
ECSIndexEntry(const DNSName& qname, uint16_t qtype): d_qname(qname), d_qtype(qtype)
ECSIndexEntry(const DNSName& qname, uint16_t qtype): d_nmt(true), d_qname(qname), d_qtype(qtype)
{
}



+ 4
- 4
sillyrecords.cc View File

@@ -159,9 +159,9 @@ void LOCRecordContent::report(void)
regist(254, QType::LOC, &make, &make, "LOC");
}

DNSRecordContent* LOCRecordContent::make(const string& content)
std::shared_ptr<DNSRecordContent> LOCRecordContent::make(const string& content)
{
return new LOCRecordContent(content);
return std::make_shared<LOCRecordContent>(content);
}


@@ -177,9 +177,9 @@ void LOCRecordContent::toPacket(DNSPacketWriter& pw)
pw.xfr32BitInt(d_altitude);
}

LOCRecordContent::DNSRecordContent* LOCRecordContent::make(const DNSRecord &dr, PacketReader& pr)
std::shared_ptr<LOCRecordContent::DNSRecordContent> LOCRecordContent::make(const DNSRecord &dr, PacketReader& pr)
{
LOCRecordContent* ret=new LOCRecordContent();
auto ret=std::make_shared<LOCRecordContent>();
pr.xfr8BitInt(ret->d_version);
pr.xfr8BitInt(ret->d_size);
pr.xfr8BitInt(ret->d_horizpre);


+ 23
- 10
syncres.cc View File

@@ -127,8 +127,11 @@ int SyncRes::beginResolve(const DNSName &qname, const QType &qtype, uint16_t qcl
return 0; // so do check before updating counters (we do now)
}

if( (qtype.getCode() == QType::AXFR) || (qtype.getCode() == QType::IXFR) || (qtype.getCode() == QType::RRSIG) || (qtype.getCode() == QType::NSEC3))
auto qtypeCode = qtype.getCode();
/* rfc6895 section 3.1 */
if ((qtypeCode >= 128 && qtypeCode <= 254) || qtypeCode == QType::RRSIG || qtypeCode == QType::NSEC3 || qtypeCode == QType::OPT || qtypeCode == 65535) {
return -1;
}

if(qclass==QClass::ANY)
qclass=QClass::IN;
@@ -476,7 +479,12 @@ int SyncRes::asyncresolveWrapper(const ComboAddress& ip, bool ednsMANDATORY, con
return ret;
}
else if(mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSOK || mode == EDNSStatus::EDNSIGNORANT ) {
if(res->d_rcode == RCode::FormErr || res->d_rcode == RCode::NotImp) {
/* So, you might be tempted to treat the presence of EDNS in a response as meaning that the
server does understand EDNS, and thus prevent a downgrade to no EDNS.
It turns out that you can't because there are a lot of crappy servers out there,
so you have to treat a FormErr as 'I have no idea what this EDNS thing is' no matter what.
*/
if(res->d_rcode == RCode::FormErr || res->d_rcode == RCode::NotImp) {
// cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
mode = EDNSStatus::NOEDNS;
continue;
@@ -570,21 +578,25 @@ int SyncRes::doResolve(const DNSName &qname, const QType &qtype, vector<DNSRecor
DNSName authname(qname);
bool wasForwardedOrAuthZone = false;
bool wasAuthZone = false;
bool wasForwardRecurse = false;
domainmap_t::const_iterator iter = getBestAuthZone(&authname);
if(iter != t_sstorage.domainmap->end()) {
const auto& domain = iter->second;
wasForwardedOrAuthZone = true;
const vector<ComboAddress>& servers = iter->second.d_servers;
if(servers.empty()) {
if (domain.isAuth()) {
wasAuthZone = true;
} else if (domain.shouldRecurse()) {
wasForwardRecurse = true;
}
}

if(!d_skipCNAMECheck && doCNAMECacheCheck(qname, qtype, ret, depth, res, state, wasAuthZone)) { // will reroute us if needed
if(!d_skipCNAMECheck && doCNAMECacheCheck(qname, qtype, ret, depth, res, state, wasAuthZone, wasForwardRecurse)) { // will reroute us if needed
d_wasOutOfBand = wasAuthZone;
return res;
}

if(doCacheCheck(qname, authname, wasForwardedOrAuthZone, wasAuthZone, qtype, ret, depth, res, state)) {
if(doCacheCheck(qname, authname, wasForwardedOrAuthZone, wasAuthZone, wasForwardRecurse, qtype, ret, depth, res, state)) {
// we done
d_wasOutOfBand = wasAuthZone;
return res;
@@ -880,7 +892,7 @@ DNSName SyncRes::getBestNSNamesFromCache(const DNSName &qname, const QType& qtyp
return subdomain;
}

bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>& ret, unsigned int depth, int &res, vState& state, bool wasAuthZone)
bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>& ret, unsigned int depth, int &res, vState& state, bool wasAuthZone, bool wasForwardRecurse)
{
string prefix;
if(doLog()) {
@@ -899,7 +911,8 @@ bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector
vector<std::shared_ptr<RRSIGRecordContent>> signatures;
vector<std::shared_ptr<DNSRecord>> authorityRecs;
bool wasAuth;
if(t_RC->get(d_now.tv_sec, qname, QType(QType::CNAME), d_requireAuthData, &cset, d_incomingECSFound ? d_incomingECSNetwork : d_requestor, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) {
/* we don't require auth data for forward-recurse lookups */
if(t_RC->get(d_now.tv_sec, qname, QType(QType::CNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_incomingECSFound ? d_incomingECSNetwork : d_requestor, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) {

for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) {
if (j->d_class != QClass::IN) {
@@ -1074,7 +1087,7 @@ void SyncRes::computeNegCacheValidationStatus(NegCache::NegCacheEntry& ne, const
}
}

bool SyncRes::doCacheCheck(const DNSName &qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state)
bool SyncRes::doCacheCheck(const DNSName &qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, bool wasForwardRecurse, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state)
{
bool giveNegative=false;

@@ -1152,7 +1165,7 @@ bool SyncRes::doCacheCheck(const DNSName &qname, const DNSName& authname, bool w
vector<std::shared_ptr<DNSRecord>> authorityRecs;
uint32_t ttl=0;
bool wasCachedAuth;
if(t_RC->get(d_now.tv_sec, sqname, sqt, d_requireAuthData, &cset, d_incomingECSFound ? d_incomingECSNetwork : d_requestor, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &cachedState, &wasCachedAuth) > 0) {
if(t_RC->get(d_now.tv_sec, sqname, sqt, !wasForwardRecurse && d_requireAuthData, &cset, d_incomingECSFound ? d_incomingECSNetwork : d_requestor, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &cachedState, &wasCachedAuth) > 0) {

LOG(prefix<<sqname<<": Found cache hit for "<<sqt.getName()<<": ");



+ 2
- 2
syncres.hh View File

@@ -736,8 +736,8 @@ private:
bool doOOBResolve(const AuthDomain& domain, const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, int& res);
bool doOOBResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res);
domainmap_t::const_iterator getBestAuthZone(DNSName* qname) const;
bool doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state, bool wasAuthZone);
bool doCacheCheck(const DNSName &qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state);
bool doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state, bool wasAuthZone, bool wasForwardRecurse);
bool doCacheCheck(const DNSName &qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, bool wasForwardRecurse, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state);
void getBestNSFromCache(const DNSName &qname, const QType &qtype, vector<DNSRecord>&bestns, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>& beenthere);
DNSName getBestNSNamesFromCache(const DNSName &qname, const QType &qtype, NsSet& nsset, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>&beenthere);



+ 6
- 6
test-dnsrecordcontent.cc View File

@@ -21,12 +21,12 @@ BOOST_AUTO_TEST_CASE(test_equality) {
BOOST_CHECK(aaaa == aaaa1);


auto rec1=DNSRecordContent::makeunique(QType::A, 1, "192.168.0.1");
auto rec2=DNSRecordContent::makeunique(QType::A, 1, "192.168.222.222");
auto rec3=DNSRecordContent::makeunique(QType::AAAA, 1, "::1");
auto recMX=DNSRecordContent::makeunique(QType::MX, 1, "25 smtp.powerdns.com");
auto recMX2=DNSRecordContent::makeunique(QType::MX, 1, "26 smtp.powerdns.com");
auto recMX3=DNSRecordContent::makeunique(QType::MX, 1, "26 SMTP.powerdns.com");
auto rec1=DNSRecordContent::mastermake(QType::A, 1, "192.168.0.1");
auto rec2=DNSRecordContent::mastermake(QType::A, 1, "192.168.222.222");
auto rec3=DNSRecordContent::mastermake(QType::AAAA, 1, "::1");
auto recMX=DNSRecordContent::mastermake(QType::MX, 1, "25 smtp.powerdns.com");
auto recMX2=DNSRecordContent::mastermake(QType::MX, 1, "26 smtp.powerdns.com");
auto recMX3=DNSRecordContent::mastermake(QType::MX, 1, "26 SMTP.powerdns.com");
BOOST_CHECK(!(*rec1==*rec2));
BOOST_CHECK(*rec1==*rec1);
BOOST_CHECK(*rec3==*rec3);


+ 305
- 0
test-packetcache_hh.cc View File

@@ -0,0 +1,305 @@
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_NO_MAIN

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <boost/test/unit_test.hpp>

#include "dnswriter.hh"
#include "dnsrecords.hh"
#include "ednscookies.hh"
#include "ednssubnet.hh"
#include "packetcache.hh"

BOOST_AUTO_TEST_SUITE(packetcache_hh)

BOOST_AUTO_TEST_CASE(test_PacketCacheAuthCollision) {

/* auth version (ECS is not processed, we just hash the whole query except for the ID, while lowercasing the qname) */
const DNSName qname("www.powerdns.com.");
uint16_t qtype = QType::AAAA;
EDNSSubnetOpts opt;
DNSPacketWriter::optvect_t ednsOptions;

{
/* same query, different IDs */
vector<uint8_t> packet;
DNSPacketWriter pw1(packet, qname, qtype);
pw1.getHeader()->rd = true;
pw1.getHeader()->qr = false;
pw1.getHeader()->id = 0x42;
string spacket1((const char*)&packet[0], packet.size());
auto hash1 = PacketCache::canHashPacket(spacket1);

packet.clear();
DNSPacketWriter pw2(packet, qname, qtype);
pw2.getHeader()->rd = true;
pw2.getHeader()->qr = false;
pw2.getHeader()->id = 0x84;
string spacket2((const char*)&packet[0], packet.size());
auto hash2 = PacketCache::canHashPacket(spacket2);

BOOST_CHECK_EQUAL(hash1, hash2);
BOOST_CHECK(PacketCache::queryMatches(spacket1, spacket2, qname));
}

{
/* same query, different IDs, different ECS, still hashes to the same value */
vector<uint8_t> packet;
DNSPacketWriter pw1(packet, qname, qtype);
pw1.getHeader()->rd = true;
pw1.getHeader()->qr = false;
pw1.getHeader()->id = 0x42;
opt.source = Netmask("10.0.18.199/32");
ednsOptions.clear();
ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
pw1.addOpt(512, 0, 0, ednsOptions);
pw1.commit();

string spacket1((const char*)&packet[0], packet.size());
auto hash1 = PacketCache::canHashPacket(spacket1);

packet.clear();
DNSPacketWriter pw2(packet, qname, qtype);
pw2.getHeader()->rd = true;
pw2.getHeader()->qr = false;
pw2.getHeader()->id = 0x84;
opt.source = Netmask("10.0.131.66/32");
ednsOptions.clear();
ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
pw2.addOpt(512, 0, 0, ednsOptions);
pw2.commit();

string spacket2((const char*)&packet[0], packet.size());
auto hash2 = PacketCache::canHashPacket(spacket2);

BOOST_CHECK_EQUAL(hash1, hash2);
/* the hash is the same but we should _not_ match */
BOOST_CHECK(!PacketCache::queryMatches(spacket1, spacket2, qname));
}

{
/* same query but one has DNSSECOK, not the other, different IDs, different ECS, still hashes to the same value */
vector<uint8_t> packet;
DNSPacketWriter pw1(packet, qname, qtype);
pw1.getHeader()->rd = true;
pw1.getHeader()->qr = false;
pw1.getHeader()->id = 0x42;
opt.source = Netmask("47.8.0.0/32");
ednsOptions.clear();
ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
pw1.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions);
pw1.commit();

string spacket1((const char*)&packet[0], packet.size());
auto hash1 = PacketCache::canHashPacket(spacket1);

packet.clear();
DNSPacketWriter pw2(packet, qname, qtype);
pw2.getHeader()->rd = true;
pw2.getHeader()->qr = false;
pw2.getHeader()->id = 0x84;
opt.source = Netmask("18.43.1.0/32");
ednsOptions.clear();
ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
/* no EDNSOpts::DNSSECOK !! */
pw2.addOpt(512, 0, 0, ednsOptions);
pw2.commit();

string spacket2((const char*)&packet[0], packet.size());
auto hash2 = PacketCache::canHashPacket(spacket2);

BOOST_CHECK_EQUAL(hash1, hash2);
/* the hash is the same but we should _not_ match */
BOOST_CHECK(!PacketCache::queryMatches(spacket1, spacket2, qname));
}

{
/* same query but different cookies, still hashes to the same value */
vector<uint8_t> packet;
DNSPacketWriter pw1(packet, qname, qtype);
pw1.getHeader()->rd = true;
pw1.getHeader()->qr = false;
pw1.getHeader()->id = 0x42;
opt.source = Netmask("192.0.2.1/32");
ednsOptions.clear();
ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
EDNSCookiesOpt cookiesOpt;
cookiesOpt.client = string("deadbeef");
cookiesOpt.server = string("deadbeef");
cookiesOpt.server[4] = -42;
cookiesOpt.server[5] = -6;
cookiesOpt.server[6] = 1;
cookiesOpt.server[7] = 0;
ednsOptions.push_back(std::make_pair(EDNSOptionCode::COOKIE, makeEDNSCookiesOptString(cookiesOpt)));
pw1.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions);
pw1.commit();

string spacket1((const char*)&packet[0], packet.size());
auto hash1 = PacketCache::canHashPacket(spacket1);

packet.clear();
DNSPacketWriter pw2(packet, qname, qtype);
pw2.getHeader()->rd = true;
pw2.getHeader()->qr = false;
pw2.getHeader()->id = 0x84;
opt.source = Netmask("192.0.2.1/32");
ednsOptions.clear();
ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
cookiesOpt.client = string("deadbeef");
cookiesOpt.server = string("deadbeef");
cookiesOpt.server[4] = 29;
cookiesOpt.server[5] = -79;
cookiesOpt.server[6] = 1;
cookiesOpt.server[7] = 0;
ednsOptions.push_back(std::make_pair(EDNSOptionCode::COOKIE, makeEDNSCookiesOptString(cookiesOpt)));
pw2.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions);
pw2.commit();

string spacket2((const char*)&packet[0], packet.size());
auto hash2 = PacketCache::canHashPacket(spacket2);

BOOST_CHECK_EQUAL(hash1, hash2);
/* the hash is the same but we should _not_ match */
BOOST_CHECK(!PacketCache::queryMatches(spacket1, spacket2, qname));
}
}

BOOST_AUTO_TEST_CASE(test_PacketCacheRecCollision) {

/* rec version (ECS is processed, we hash the whole query except for the ID and the ECS value, while lowercasing the qname) */
const DNSName qname("www.powerdns.com.");
uint16_t qtype = QType::AAAA;
EDNSSubnetOpts opt;
DNSPacketWriter::optvect_t ednsOptions;
uint16_t ecsBegin;
uint16_t ecsEnd;

{
/* same query, different IDs */
vector<uint8_t> packet;
DNSPacketWriter pw1(packet, qname, qtype);
pw1.getHeader()->rd = true;
pw1.getHeader()->qr = false;
pw1.getHeader()->id = 0x42;
string spacket1((const char*)&packet[0], packet.size());
auto hash1 = PacketCache::canHashPacket(spacket1, &ecsBegin, &ecsEnd);
/* no ECS */
BOOST_CHECK_EQUAL(ecsBegin, 0);
BOOST_CHECK_EQUAL(ecsEnd, 0);

packet.clear();
DNSPacketWriter pw2(packet, qname, qtype);
pw2.getHeader()->rd = true;
pw2.getHeader()->qr = false;
pw2.getHeader()->id = 0x84;
string spacket2((const char*)&packet[0], packet.size());
auto hash2 = PacketCache::canHashPacket(spacket2, &ecsBegin, &ecsEnd);
/* no ECS */
BOOST_CHECK_EQUAL(ecsBegin, 0);
BOOST_CHECK_EQUAL(ecsEnd, 0);