From c6fcaf44b4143b1045182a6ab70dacf67fa9b596 Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Mon, 7 Mar 2016 11:41:26 +0100 Subject: [PATCH] rec: Handle more than EDNS option in our packet cache hashing We now skip an ECS option regardless of whether there are others EDNS options before or after the ECS one, keeping the others untouched. --- pdns/recpacketcache.cc | 65 +++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/pdns/recpacketcache.cc b/pdns/recpacketcache.cc index bd03e2a53..2e91c431b 100644 --- a/pdns/recpacketcache.cc +++ b/pdns/recpacketcache.cc @@ -63,29 +63,54 @@ uint32_t RecursorPacketCache::canHashPacket(const std::string& origPacket) const char l = dns_tolower(*p); // label lengths can safely be lower cased ret=burtle((const unsigned char*)&l, 1, ret); } // XXX the embedded 0 in the qname will break the subnet stripping - - // this code will only function properly with *1* EDNS option + struct dnsheader* dh = (struct dnsheader*)origPacket.c_str(); - if(ntohs(dh->arcount)==1 && p+12 < end) { - const unsigned char *q = (const unsigned char*) p; - q+=5; - unsigned int optlen=(0x100*q[9] + q[10]); - /* - cout<<"Option length: "<< optlen < p) { - /* - cout<<"Had "<<(end-p)<<" bytes left to hash, removing "<arcount)==1 && (p+16) < end) { + /* skip the final empty label (1), the qtype (2), qclass (2) */ + /* root label (1), type (2), class (2) and ttl (4) */ + const unsigned char *q = (const unsigned char*) p + 14; + uint16_t optRRLen = (0x100*q[0] + q[1]); + q += 2; + if ((q + optRRLen) <= (const unsigned char*) end) { + const unsigned char* optRRend = q + optRRLen; + while((q + 4) <= optRRend) { + const unsigned char* optionBegin = q; + uint16_t optionCode = 0x100*q[0] + q[1]; + //cout << "OPT RR Option Code is " << optionCode << endl; + q += 2; + uint16_t optionLen = 0x100*q[0] + q[1]; + //cout << "OPT RR Option Length is " << optionLen << endl; + q += 2; + if ((q + optionLen) > (const unsigned char*) end) { + break; + } + if (optionCode == 8) { + //cout << "Skipping OPT RR Option Client Subnet:" << endl; + //cout << makeHexDump(string((const char*)optionBegin, (const char*) q + optionLen)) << endl; + skipBegin = (const char*) optionBegin; + skipEnd = (const char*) q + optionLen; + break; + } + q += optionLen; + } } } - // cout<<"Hashing: "< p) { + //cout << "Hashing from " << (p-origPacket.c_str()) << " for " << skipBegin-p << "bytes, end is at "<< end-origPacket.c_str() << endl; + ret = burtle((const unsigned char*)p, skipBegin-p, ret); + } + if (skipEnd < end) { + //cout << "Hashing from " << (skipEnd-origPacket.c_str()) << " for " << end-skipEnd << "bytes, end is at " << end-origPacket.c_str() << endl; + ret = burtle((const unsigned char*) skipEnd, end-skipEnd, ret); + } + return ret; } bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, -- 2.40.0