return d_haveednssubnet;
}
+bool DNSPacket::hasEDNS()
+{
+ return d_haveednssection;
+}
+
Netmask DNSPacket::getRealRemote() const
{
if(d_haveednssubnet)
bool couldBeCached(); //!< returns 0 if this query should bypass the packet cache
bool hasEDNSSubnet();
+ bool hasEDNS();
//////// DATA !
ComboAddress d_remote;
}
uint16_t maxReplyLen = p->d_tcp ? 0xffff : p->getMaxReplyLen();
- haveSomething=getEntryLocked(p->qdomain, p->qtype, PacketCache::PACKETCACHE, value, -1, packetMeritsRecursion, maxReplyLen, p->d_dnssecOk);
+ haveSomething=getEntryLocked(p->qdomain, p->qtype, PacketCache::PACKETCACHE, value, -1, packetMeritsRecursion, maxReplyLen, p->d_dnssecOk, p->hasEDNS());
}
if(haveSomething) {
(*d_statnumhit)++;
if(maxttl<ourttl)
ourttl=maxttl;
insert(q->qdomain, q->qtype, PacketCache::PACKETCACHE, r->getString(), ourttl, -1, packetMeritsRecursion,
- maxReplyLen, q->d_dnssecOk);
+ maxReplyLen, q->d_dnssecOk, q->hasEDNS());
}
// universal key appears to be: qname, qtype, kind (packet, query cache), optionally zoneid, meritsRecursion
void PacketCache::insert(const string &qname, const QType& qtype, CacheEntryType cet, const string& value, unsigned int ttl, int zoneID,
- bool meritsRecursion, unsigned int maxReplyLen, bool dnssecOk)
+ bool meritsRecursion, unsigned int maxReplyLen, bool dnssecOk, bool EDNS)
{
if(!((++d_ops) % 300000)) {
cleanup();
if(!ttl)
return;
- //cerr<<"Inserting qname '"<<qname<<"', cet: "<<(int)cet<<", value: '"<< (cet ? value : "PACKET") <<"', qtype: "<<qtype.getName()<<", ttl: "<<ttl<<", maxreplylen: "<<maxReplyLen<<endl;
+ //cerr<<"Inserting qname '"<<qname<<"', cet: "<<(int)cet<<", qtype: "<<qtype.getName()<<", ttl: "<<ttl<<", maxreplylen: "<<maxReplyLen<<", hasEDNS: "<<EDNS<<endl;
CacheEntry val;
val.ttd=time(0)+ttl;
val.qname=qname;
val.maxReplyLen = maxReplyLen;
val.dnssecOk = dnssecOk;
val.zoneID = zoneID;
+ val.hasEDNS = EDNS;
TryWriteLock l(&d_mut);
if(l.gotIt()) {
}
// called from ueberbackend
bool PacketCache::getEntry(const string &qname, const QType& qtype, CacheEntryType cet, string& value, int zoneID, bool meritsRecursion,
- unsigned int maxReplyLen, bool dnssecOk)
+ unsigned int maxReplyLen, bool dnssecOk, bool hasEDNS)
{
if(d_ttl<0)
getTTLS();
return false;
}
- return getEntryLocked(qname, qtype, cet, value, zoneID, meritsRecursion, maxReplyLen, dnssecOk);
+ return getEntryLocked(qname, qtype, cet, value, zoneID, meritsRecursion, maxReplyLen, dnssecOk, hasEDNS);
}
bool PacketCache::getEntryLocked(const string &qname, const QType& qtype, CacheEntryType cet, string& value, int zoneID, bool meritsRecursion,
- unsigned int maxReplyLen, bool dnssecOK)
+ unsigned int maxReplyLen, bool dnssecOK, bool hasEDNS)
{
uint16_t qt = qtype.getCode();
//cerr<<"Lookup for maxReplyLen: "<<maxReplyLen<<endl;
- cmap_t::const_iterator i=d_map.find(tie(qname, qt, cet, zoneID, meritsRecursion, maxReplyLen, dnssecOK));
+ cmap_t::const_iterator i=d_map.find(tie(qname, qt, cet, zoneID, meritsRecursion, maxReplyLen, dnssecOK, hasEDNS));
time_t now=time(0);
bool ret=(i!=d_map.end() && i->ttd > now);
if(ret)
void insert(DNSPacket *q, DNSPacket *r, unsigned int maxttl=UINT_MAX); //!< We copy the contents of *p into our cache. Do not needlessly call this to insert questions already in the cache as it wastes resources
void insert(const string &qname, const QType& qtype, CacheEntryType cet, const string& value, unsigned int ttl, int zoneID=-1, bool meritsRecursion=false,
- unsigned int maxReplyLen=512, bool dnssecOk=false);
+ unsigned int maxReplyLen=512, bool dnssecOk=false, bool EDNS=false);
int get(DNSPacket *p, DNSPacket *q); //!< We return a dynamically allocated copy out of our cache. You need to delete it. You also need to spoof in the right ID with the DNSPacket.spoofID() method.
bool getEntry(const string &content, const QType& qtype, CacheEntryType cet, string& entry, int zoneID=-1,
- bool meritsRecursion=false, unsigned int maxReplyLen=512, bool dnssecOk=false);
+ bool meritsRecursion=false, unsigned int maxReplyLen=512, bool dnssecOk=false, bool hasEDNS=false);
int size(); //!< number of entries in the cache
void cleanup(); //!< force the cache to preen itself from expired packets
map<char,int> getCounts();
private:
bool getEntryLocked(const string &content, const QType& qtype, CacheEntryType cet, string& entry, int zoneID=-1,
- bool meritsRecursion=false, unsigned int maxReplyLen=512, bool dnssecOk=false);
+ bool meritsRecursion=false, unsigned int maxReplyLen=512, bool dnssecOk=false, bool hasEDNS=false);
struct CacheEntry
{
- CacheEntry() { qtype = ctype = 0; zoneID = -1; meritsRecursion=false; dnssecOk=false;}
+ CacheEntry() { qtype = ctype = 0; zoneID = -1; meritsRecursion=false; dnssecOk=false; hasEDNS=false;}
string qname;
uint16_t qtype;
bool meritsRecursion;
unsigned int maxReplyLen;
bool dnssecOk;
+ bool hasEDNS;
string value;
};
member<CacheEntry,int, &CacheEntry::zoneID>,
member<CacheEntry,bool, &CacheEntry::meritsRecursion>,
member<CacheEntry,unsigned int, &CacheEntry::maxReplyLen>,
- member<CacheEntry,bool, &CacheEntry::dnssecOk>
+ member<CacheEntry,bool, &CacheEntry::dnssecOk>,
+ member<CacheEntry,bool, &CacheEntry::hasEDNS>
>,
composite_key_compare<CIBackwardsStringCompare, std::less<uint16_t>, std::less<uint16_t>, std::less<int>, std::less<bool>,
- std::less<unsigned int>, std::less<bool> >
+ std::less<unsigned int>, std::less<bool>, std::less<bool> >
>,
sequenced<>
>
--- /dev/null
+#!/bin/bash -ex
+
+bindwait ()
+{
+ configname=$1
+ domcount=1
+ while sleep 1
+ do
+ done=$( (../pdns/pdns_control --config-name=$configname --socket-dir=. --no-config bind-domain-status || true) | grep -c 'parsed into memory' || true )
+ if [ $done = $domcount ]
+ then
+ return
+ fi
+ done
+}
+
+port=5501
+rm -f pdns*.pid
+
+../pdns/pdns_server --daemon=no --local-port=$port --socket-dir=./ \
+ --no-shuffle --launch=bind --bind-config=edns-packet-cache/named.conf \
+ --fancy-records --send-root-referral \
+ --cache-ttl=60 --no-config &
+bindwait
+
+# prime cache without EDNS
+../pdns/sdig 127.0.0.1 5501 minimal.com SOA | LC_ALL=C sort
+# expect EDNS in identical query with EDNS
+SDIGBUFSIZE=512 ../pdns/sdig 127.0.0.1 5501 minimal.com SOA | LC_ALL=C sort
+
+# prime cache with EDNS
+SDIGBUFSIZE=512 ../pdns/sdig 127.0.0.1 5501 minimal.com NS | LC_ALL=C sort
+# expect no EDNS in identical query without EDNS
+../pdns/sdig 127.0.0.1 5501 minimal.com NS | LC_ALL=C sort
+
+kill $(cat pdns*.pid)
+rm pdns*.pid
--- /dev/null
+The authoritative packet cache does not check whether a cached packet and the
+response is it being matched again, have the same EDNS status (present vs.
+not-present).
+
+Because it does take max reply length into account, the impact of this is
+limited - non-EDNS clients would only get EDNS replies from the cache if the
+EDNS bufsize happened to be 512.
--- /dev/null
+0 minimal.com. IN SOA 120 ns1.example.com. ahu.example.com. 2000081501 28800 7200 604800 86400
+Rcode: 0, RD: 0, QR: 1, TC: 0, AA: 1, opcode: 0
+Reply to question for qname='minimal.com.', qtype=SOA
+0 minimal.com. IN SOA 120 ns1.example.com. ahu.example.com. 2000081501 28800 7200 604800 86400
+2 . IN OPT 0
+Rcode: 0, RD: 0, QR: 1, TC: 0, AA: 1, opcode: 0
+Reply to question for qname='minimal.com.', qtype=SOA
+0 minimal.com. IN NS 120 ns1.example.com.
+0 minimal.com. IN NS 120 ns2.example.com.
+2 . IN OPT 0
+Rcode: 0, RD: 0, QR: 1, TC: 0, AA: 1, opcode: 0
+Reply to question for qname='minimal.com.', qtype=NS
+0 minimal.com. IN NS 120 ns1.example.com.
+0 minimal.com. IN NS 120 ns2.example.com.
+Rcode: 0, RD: 0, QR: 1, TC: 0, AA: 1, opcode: 0
+Reply to question for qname='minimal.com.', qtype=NS
--- /dev/null
+options {
+ directory "../regression-tests/";
+ recursion no;
+ listen-on port 5300 {
+ 127.0.0.1;
+ };
+ version "Meow!Meow!";
+ minimal-responses yes;
+};
+
+zone "minimal.com"{
+ type master;
+ file "./minimal.com";
+};