From: Pieter Lexis Date: Tue, 20 Feb 2018 23:43:38 +0000 (+0100) Subject: rec: Add EDNS OPT record to packet when the client sent one X-Git-Tag: dnsdist-1.3.1~50^2~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f1db0de279271451c8911e8f75e82866d630d598;p=thirdparty%2Fpdns.git rec: Add EDNS OPT record to packet when the client sent one Also, Ensure we reply with BADVERS when the EDNS version is not 0. --- diff --git a/pdns/dnswriter.cc b/pdns/dnswriter.cc index 916a23b995..d788217e8c 100644 --- a/pdns/dnswriter.cc +++ b/pdns/dnswriter.cc @@ -100,10 +100,20 @@ void DNSPacketWriter::addOpt(uint16_t udpsize, int extRCode, int Z, const vector EDNS0Record stuff; - stuff.extRCode=extRCode; stuff.version=version; stuff.Z=htons(Z); + /* RFC 6891 section 4 on the Extended RCode wire format + * EXTENDED-RCODE + * Forms the upper 8 bits of extended 12-bit RCODE (together with the + * 4 bits defined in [RFC1035]. Note that EXTENDED-RCODE value 0 + * indicates that an unextended RCODE is in use (values 0 through 15). + */ + stuff.extRCode = extRCode>>4; + if (extRCode != 0) { // As this trumps the existing RCODE + getHeader()->rcode = extRCode; + } + static_assert(sizeof(EDNS0Record) == sizeof(ttl), "sizeof(EDNS0Record) must match sizeof(ttl)"); memcpy(&ttl, &stuff, sizeof(stuff)); diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index 5947c775a1..181183087f 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -871,9 +871,16 @@ static void startDoResolve(void *p) uint16_t maxanswersize = dc->d_tcp ? 65535 : min(static_cast(512), g_udpTruncationThreshold); EDNSOpts edo; std::vector > ednsOpts; + bool variableAnswer = false; bool haveEDNS=false; - bool wantsNSID = false; + DNSPacketWriter::optvect_t returnedEdnsOptions; // Here we stuff all the options for the return packet + uint8_t ednsExtRCode = 0; if(getEDNSOpts(dc->d_mdp, &edo)) { + haveEDNS=true; + if (edo.d_version != 0) { + ednsExtRCode = ERCode::BADVERS; + } + if(!dc->d_tcp) { /* rfc6891 6.2.3: "Values lower than 512 MUST be treated as equal to 512." @@ -887,7 +894,13 @@ static void startDoResolve(void *p) if (o.first == EDNSOptionCode::ECS && g_useIncomingECS && !dc->d_ecsParsed) { dc->d_ecsFound = getEDNSSubnetOptsFromString(o.second, &dc->d_ednssubnet); } else if (o.first == EDNSOptionCode::NSID) { - wantsNSID = true; + const static string mode_server_id = ::arg()["server-id"]; + if(mode_server_id != "disabled" && !mode_server_id.empty()) { + returnedEdnsOptions.push_back(make_pair(EDNSOptionCode::NSID, mode_server_id)); + variableAnswer = true; // Can't packetcache an answer with NSID + // Option Code and Option Length are both 2 + maxanswersize -= 2 + 2 + mode_server_id.size(); + } } } } @@ -955,7 +968,7 @@ static void startDoResolve(void *p) sr.setQuerySource(dc->d_remote, g_useIncomingECS && !dc->d_ednssubnet.source.empty() ? boost::optional(dc->d_ednssubnet) : boost::none); bool tracedQuery=false; // we could consider letting Lua know about this too - bool variableAnswer = dc->d_variable; + variableAnswer = dc->d_variable || variableAnswer; bool shouldNotValidate = false; /* preresolve expects res (dq.rcode) to be set to RCode::NoError by default */ @@ -1295,19 +1308,7 @@ static void startDoResolve(void *p) OPT record. This MUST also occur when a truncated response (using the DNS header's TC bit) is returned." */ - DNSPacketWriter::optvect_t opts; - if(wantsNSID) { - const static string mode_server_id = ::arg()["server-id"]; - if(mode_server_id != "disabled" && !mode_server_id.empty()) { - opts.push_back(make_pair(EDNSOptionCode::NSID, mode_server_id)); - variableAnswer = true; // Can't packetcache an answer with NSID - } - } - pw.addOpt(g_udpTruncationThreshold, 0, DNSSECOK ? EDNSOpts::DNSSECOK : 0, opts); - if (pw.size() > maxanswersize) { - pw.rollback(); - pw.addOpt(g_udpTruncationThreshold, 0, DNSSECOK ? EDNSOpts::DNSSECOK : 0, opts); - } + pw.addOpt(g_udpTruncationThreshold, ednsExtRCode, DNSSECOK ? EDNSOpts::DNSSECOK : 0, returnedEdnsOptions); pw.commit(); }