From 2aa2c0aa69afec5520ebebb5ef08c91ecc68653c Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Wed, 27 Feb 2019 12:06:53 +0100 Subject: [PATCH] dnsdist: Add a function to extract an EDNS0Record from a DNS packet --- pdns/dnsdist-ecs.cc | 38 ++++++++++++++++++----- pdns/dnsdist-ecs.hh | 4 +++ pdns/dnsdist.cc | 4 +-- pdns/dnsdistdist/dnsdist-rules.hh | 51 +++---------------------------- pdns/test-dnsdist_cc.cc | 3 +- 5 files changed, 43 insertions(+), 57 deletions(-) diff --git a/pdns/dnsdist-ecs.cc b/pdns/dnsdist-ecs.cc index 56422e48a..9390a55df 100644 --- a/pdns/dnsdist-ecs.cc +++ b/pdns/dnsdist-ecs.cc @@ -464,9 +464,7 @@ static int removeEDNSOptionFromOptions(unsigned char* optionsStart, const uint16 int removeEDNSOptionFromOPT(char* optStart, size_t* optLen, const uint16_t optionCodeToRemove) { - /* we need at least: - root label (1), type (2), class (2), ttl (4) + rdlen (2)*/ - if (*optLen < 11) { + if (*optLen < optRecordMinimumSize) { return EINVAL; } const unsigned char* end = (const unsigned char*) optStart + *optLen; @@ -490,15 +488,13 @@ int removeEDNSOptionFromOPT(char* optStart, size_t* optLen, const uint16_t optio bool isEDNSOptionInOpt(const std::string& packet, const size_t optStart, const size_t optLen, const uint16_t optionCodeToFind, size_t* optContentStart, uint16_t* optContentLen) { - /* we need at least: - root label (1), type (2), class (2), ttl (4) + rdlen (2)*/ - if (optLen < 11) { + if (optLen < optRecordMinimumSize) { return false; } size_t p = optStart + 9; uint16_t rdLen = (0x100*packet.at(p) + packet.at(p+1)); p += sizeof(rdLen); - if (rdLen > (optLen - 11)) { + if (rdLen > (optLen - optRecordMinimumSize)) { return false; } @@ -741,3 +737,31 @@ bool queryHasEDNS(const DNSQuestion& dq) return false; } + +bool getEDNS0Record(const DNSQuestion& dq, EDNS0Record& edns0) +{ + uint16_t optStart; + size_t optLen = 0; + bool last = false; + const char * packet = reinterpret_cast(dq.dh); + std::string packetStr(packet, dq.len); + int res = locateEDNSOptRR(packetStr, &optStart, &optLen, &last); + if (res != 0) { + // no EDNS OPT RR + return false; + } + + if (optLen < optRecordMinimumSize) { + return false; + } + + if (optStart < dq.len && packetStr.at(optStart) != 0) { + // OPT RR Name != '.' + return false; + } + + static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t) AKA RR TTL size"); + // copy out 4-byte "ttl" (really the EDNS0 record), after root label (1) + type (2) + class (2). + memcpy(&edns0, packet + optStart + 5, sizeof edns0); + return true; +} diff --git a/pdns/dnsdist-ecs.hh b/pdns/dnsdist-ecs.hh index 7c3739f44..767575723 100644 --- a/pdns/dnsdist-ecs.hh +++ b/pdns/dnsdist-ecs.hh @@ -21,6 +21,9 @@ */ #pragma once +// root label (1), type (2), class (2), ttl (4) + rdlen (2) +static const size_t optRecordMinimumSize = 11; + extern size_t g_EdnsUDPPayloadSize; extern uint16_t g_PayloadSizeSelfGenAnswers; @@ -42,3 +45,4 @@ bool parseEDNSOptions(DNSQuestion& dq); int getEDNSZ(const DNSQuestion& dq); bool queryHasEDNS(const DNSQuestion& dq); +bool getEDNS0Record(const DNSQuestion& dq, EDNS0Record& edns0); diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index 07f587e92..1e02ceb85 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -156,7 +156,7 @@ try hadEDNS = getEDNSUDPPayloadSizeAndZ(packet, *len, &payloadSize, &z); } - *len=(uint16_t) (sizeof(dnsheader)+consumed+DNS_TYPE_SIZE+DNS_CLASS_SIZE); + *len=static_cast(sizeof(dnsheader)+consumed+DNS_TYPE_SIZE+DNS_CLASS_SIZE); struct dnsheader* dh = reinterpret_cast(packet); dh->ancount = dh->arcount = dh->nscount = 0; @@ -537,7 +537,7 @@ try { char * response = packet; size_t responseSize = sizeof(packet); - if (got < static_cast(sizeof(dnsheader))) + if (got < 0 || static_cast(got) < sizeof(dnsheader)) continue; uint16_t responseLen = static_cast(got); diff --git a/pdns/dnsdistdist/dnsdist-rules.hh b/pdns/dnsdistdist/dnsdist-rules.hh index 7361a4808..bbc4ff205 100644 --- a/pdns/dnsdistdist/dnsdist-rules.hh +++ b/pdns/dnsdistdist/dnsdist-rules.hh @@ -863,30 +863,10 @@ public: return false; } - uint16_t optStart; - size_t optLen = 0; - bool last = false; - const char * packet = reinterpret_cast(dq->dh); - std::string packetStr(packet, dq->len); - int res = locateEDNSOptRR(packetStr, &optStart, &optLen, &last); - if (res != 0) { - // no EDNS OPT RR - return d_extrcode == 0; - } - - // root label (1), type (2), class (2), ttl (4) + rdlen (2) - if (optLen < 11) { - return false; - } - - if (optStart < dq->len && packet[optStart] != 0) { - // OPT RR Name != '.' + EDNS0Record edns0; + if (!getEDNS0Record(*dq, edns0)) { return false; } - EDNS0Record edns0; - static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t) AKA RR TTL size"); - // copy out 4-byte "ttl" (really the EDNS0 record), after root label (1) + type (2) + class (2). - memcpy(&edns0, packet + optStart + 5, sizeof edns0); return d_extrcode == edns0.extRCode; } @@ -907,30 +887,10 @@ public: } bool matches(const DNSQuestion* dq) const override { - uint16_t optStart; - size_t optLen = 0; - bool last = false; - const char * packet = reinterpret_cast(dq->dh); - std::string packetStr(packet, dq->len); - int res = locateEDNSOptRR(packetStr, &optStart, &optLen, &last); - if (res != 0) { - // no EDNS OPT RR - return false; - } - - // root label (1), type (2), class (2), ttl (4) + rdlen (2) - if (optLen < 11) { - return false; - } - - if (optStart < dq->len && packetStr.at(optStart) != 0) { - // OPT RR Name != '.' + EDNS0Record edns0; + if (!getEDNS0Record(*dq, edns0)) { return false; } - EDNS0Record edns0; - static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t) AKA RR TTL size"); - // copy out 4-byte "ttl" (really the EDNS0 record), after root label (1) + type (2) + class (2). - memcpy(&edns0, packet + optStart + 5, sizeof edns0); return d_version < edns0.version; } @@ -961,8 +921,7 @@ public: return false; } - // root label (1), type (2), class (2), ttl (4) + rdlen (2) - if (optLen < 11) { + if (optLen < optRecordMinimumSize) { return false; } diff --git a/pdns/test-dnsdist_cc.cc b/pdns/test-dnsdist_cc.cc index 872592ead..f34968e74 100644 --- a/pdns/test-dnsdist_cc.cc +++ b/pdns/test-dnsdist_cc.cc @@ -1433,8 +1433,7 @@ BOOST_AUTO_TEST_CASE(test_isEDNSOptionInOpt) { return false; } - // root label (1), type (2), class (2), ttl (4) + rdlen (2) - if (optLen < 11) { + if (optLen < optRecordMinimumSize) { return false; } -- 2.40.0