From: Dmitry Alenichev Date: Tue, 22 Jan 2019 17:43:39 +0000 (+0300) Subject: respond with RCODE=BADVERS on EDNS version >0 (rfc6891) X-Git-Tag: auth-4.2.0-beta1~9^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5e98ccfa1e74517ce718a6e1d5964392397afd37;p=thirdparty%2Fpdns.git respond with RCODE=BADVERS on EDNS version >0 (rfc6891) --- diff --git a/pdns/dnsdist-ecs.cc b/pdns/dnsdist-ecs.cc index dbb6cad589..cfd8f084c0 100644 --- a/pdns/dnsdist-ecs.cc +++ b/pdns/dnsdist-ecs.cc @@ -244,12 +244,12 @@ void generateECSOption(const ComboAddress& source, string& res, uint16_t ECSPref generateEDNSOption(EDNSOptionCode::ECS, payload, res); } -void generateOptRR(const std::string& optRData, string& res, uint16_t udpPayloadSize, bool dnssecOK) +void generateOptRR(const std::string& optRData, string& res, uint16_t udpPayloadSize, uint16_t ednsrcode, bool dnssecOK) { const uint8_t name = 0; dnsrecordheader dh; EDNS0Record edns0; - edns0.extRCode = 0; + edns0.extRCode = ednsrcode; edns0.version = 0; edns0.extFlags = dnssecOK ? htons(EDNS_HEADER_FLAG_DO) : 0; @@ -358,7 +358,7 @@ static bool addEDNSWithECS(char* const packet, size_t const packetSize, uint16_t /* we need to add a EDNS0 RR with one EDNS0 ECS option, fixing the AR count */ string EDNSRR; struct dnsheader* dh = reinterpret_cast(packet); - generateOptRR(newECSOption, EDNSRR, g_EdnsUDPPayloadSize, false); + generateOptRR(newECSOption, EDNSRR, g_EdnsUDPPayloadSize, 0, false); /* does it fit in the existing buffer? */ if (packetSize - *len <= EDNSRR.size()) { @@ -626,14 +626,14 @@ int rewriteResponseWithoutEDNSOption(const std::string& initialPacket, const uin return 0; } -bool addEDNS(dnsheader* dh, uint16_t& len, const size_t size, bool dnssecOK, uint16_t payloadSize) +bool addEDNS(dnsheader* dh, uint16_t& len, const size_t size, bool dnssecOK, uint16_t payloadSize, uint16_t ednsrcode) { if (dh->arcount != 0) { return false; } std::string optRecord; - generateOptRR(std::string(), optRecord, payloadSize, dnssecOK); + generateOptRR(std::string(), optRecord, payloadSize, ednsrcode, dnssecOK); if (optRecord.size() >= size || (size - optRecord.size()) < len) { return false; @@ -679,7 +679,7 @@ bool addEDNSToQueryTurnedResponse(DNSQuestion& dq) if (g_addEDNSToSelfGeneratedResponses) { /* now we need to add a new OPT record */ - return addEDNS(dq.dh, dq.len, dq.size, dnssecOK, g_PayloadSizeSelfGenAnswers); + return addEDNS(dq.dh, dq.len, dq.size, dnssecOK, g_PayloadSizeSelfGenAnswers, dq.ednsRCode); } /* otherwise we are just fine */ @@ -741,3 +741,45 @@ bool queryHasEDNS(const DNSQuestion& dq) return false; } + +int getEDNSVersion(const DNSQuestion& dq) +try +{ + if (ntohs(dq.dh->qdcount) != 1 || dq.dh->ancount != 0 || ntohs(dq.dh->arcount) != 1 || dq.dh->nscount != 0) { + return 0; + } + + if (dq.len <= sizeof(dnsheader)) { + return 0; + } + + size_t pos = sizeof(dnsheader) + dq.consumed + DNS_TYPE_SIZE + DNS_CLASS_SIZE; + + if (dq.len <= (pos + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE)) { + return 0; + } + + const char* packet = reinterpret_cast(dq.dh); + + if (packet[pos] != 0) { + /* not root, so not a valid OPT record */ + return 0; + } + + pos++; + + uint16_t qtype = (reinterpret_cast(packet)[pos])*256 + reinterpret_cast(packet)[pos+1]; + pos += DNS_TYPE_SIZE; + pos += DNS_CLASS_SIZE; + + if (qtype != QType::OPT || (pos + EDNS_EXTENDED_RCODE_SIZE + 1) >= dq.len) { + return 0; + } + + const uint8_t* z = reinterpret_cast(packet) + pos + EDNS_EXTENDED_RCODE_SIZE; + return 0x100 * (*z) + *(z+1); +} +catch(...) +{ + return 0; +} diff --git a/pdns/dnsdist-ecs.hh b/pdns/dnsdist-ecs.hh index dd0a782931..48c298b864 100644 --- a/pdns/dnsdist-ecs.hh +++ b/pdns/dnsdist-ecs.hh @@ -26,13 +26,13 @@ extern uint16_t g_PayloadSizeSelfGenAnswers; int rewriteResponseWithoutEDNS(const std::string& initialPacket, vector& newContent); int locateEDNSOptRR(const std::string& packet, uint16_t * optStart, size_t * optLen, bool * last); -void generateOptRR(const std::string& optRData, string& res, uint16_t udpPayloadSize, bool dnssecOK); +void generateOptRR(const std::string& optRData, string& res, uint16_t udpPayloadSize, uint16_t ednsrcode, bool dnssecOK); void generateECSOption(const ComboAddress& source, string& res, uint16_t ECSPrefixLength); int removeEDNSOptionFromOPT(char* optStart, size_t* optLen, const uint16_t optionCodeToRemove); int rewriteResponseWithoutEDNSOption(const std::string& initialPacket, const uint16_t optionCodeToSkip, vector& newContent); int getEDNSOptionsStart(const char* packet, const size_t offset, const size_t len, uint16_t* optRDPosition, size_t * remaining); bool isEDNSOptionInOpt(const std::string& packet, const size_t optStart, const size_t optLen, const uint16_t optionCodeToFind, size_t* optContentStart = nullptr, uint16_t* optContentLen = nullptr); -bool addEDNS(dnsheader* dh, uint16_t& len, const size_t size, bool dnssecOK, uint16_t payloadSize); +bool addEDNS(dnsheader* dh, uint16_t& len, const size_t size, bool dnssecOK, uint16_t payloadSize, uint16_t ednsrcode); bool addEDNSToQueryTurnedResponse(DNSQuestion& dq); bool handleEDNSClientSubnet(DNSQuestion& dq, bool* ednsAdded, bool* ecsAdded, bool preserveTrailingData); @@ -42,3 +42,4 @@ bool parseEDNSOptions(DNSQuestion& dq); int getEDNSZ(const DNSQuestion& dq); bool queryHasEDNS(const DNSQuestion& dq); +int getEDNSVersion(const DNSQuestion& dq); diff --git a/pdns/dnsdist-lua-actions.cc b/pdns/dnsdist-lua-actions.cc index 43fa9aa3c1..db70a8d4af 100644 --- a/pdns/dnsdist-lua-actions.cc +++ b/pdns/dnsdist-lua-actions.cc @@ -462,7 +462,7 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, string* ruleresult) c dq->dh->ancount = htons(dq->dh->ancount); if (hadEDNS) { - addEDNS(dq->dh, dq->len, dq->size, dnssecOK, g_PayloadSizeSelfGenAnswers); + addEDNS(dq->dh, dq->len, dq->size, dnssecOK, g_PayloadSizeSelfGenAnswers, 0); } return Action::HeaderModify; @@ -486,7 +486,7 @@ public: generateEDNSOption(d_code, mac, optRData); string res; - generateOptRR(optRData, res, g_EdnsUDPPayloadSize, false); + generateOptRR(optRData, res, g_EdnsUDPPayloadSize, 0, false); if ((dq->size - dq->len) < res.length()) return Action::None; diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index 3e0607e658..70a5ddb8ba 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -160,7 +160,7 @@ try dh->ancount = dh->arcount = dh->nscount = 0; if (hadEDNS) { - addEDNS(dh, *len, responseSize, z & EDNS_HEADER_FLAG_DO, payloadSize); + addEDNS(dh, *len, responseSize, z & EDNS_HEADER_FLAG_DO, payloadSize, 0); } } catch(...) @@ -1403,6 +1403,12 @@ static void processUDPQuery(ClientState& cs, LocalHolders& holders, const struct return; } + if (queryHasEDNS(dq) && getEDNSVersion(dq) > 0) { + dq.dh->qr = true; + dq.dh->rcode = (16 & 0xF); + dq.ednsRCode = ((16 & 0xFFF0)>>4); // set rcode to BADVERS + } + if(dq.dh->qr) { // something turned it into a response fixUpQueryTurnedResponse(dq, origFlags); diff --git a/pdns/dnsdist.hh b/pdns/dnsdist.hh index 8b36320f6c..c61ff4a2de 100644 --- a/pdns/dnsdist.hh +++ b/pdns/dnsdist.hh @@ -79,6 +79,7 @@ struct DNSQuestion unsigned int consumed{0}; uint16_t len; uint16_t ecsPrefixLength; + uint16_t ednsRCode; // WARNING: this is really 12 bits boost::optional tempFailureTTL; const bool tcp; const struct timespec* queryTime;