dnsparser.cc \
dnsrecords.cc \
dnswriter.cc \
+ ednsoptions.cc ednsoptions.hh \
+ ednssubnet.cc ednssubnet.hh \
iputils.cc \
logger.cc \
misc.cc \
dnsrecords.cc \
dnssecinfra.cc \
dnswriter.cc dnswriter.hh \
+ ednsoptions.cc ednsoptions.hh \
+ ednssubnet.cc ednssubnet.hh \
gss_context.cc gss_context.hh \
iputils.cc \
ixfr.cc ixfr.hh \
}
d_dedup.insert(hash);
}
-
d_rrs.push_back(std::move(rr));
}
try {
uint8_t maxScopeMask=0;
for(pos=d_rrs.begin(); pos < d_rrs.end(); ++pos) {
- // cerr<<"during wrapup, content=["<<pos->content<<"]"<<endl;
maxScopeMask = max(maxScopeMask, pos->scopeMask);
-
+
pw.startRecord(pos->dr.d_name, pos->dr.d_type, pos->dr.d_ttl, pos->dr.d_class, pos->dr.d_place);
pos->dr.getContent()->toPacket(pw);
if(pw.size() + optsize > (d_tcp ? 65535 : getMaxReplyLen())) {
if(d_haveednssubnet) {
EDNSSubnetOpts eso = d_eso;
+ // use the scopeMask from the resolver, if it is greater - issue #5469
+ maxScopeMask = max(maxScopeMask, eso.scope.getBits());
eso.scope = Netmask(eso.source.getNetwork(), maxScopeMask);
string opt = makeEDNSSubnetOptsString(eso);
*/
d_ednsRawPacketSizeLimit=edo.d_packetsize;
d_maxreplylen=std::min(std::max(static_cast<uint16_t>(512), edo.d_packetsize), s_udpTruncationThreshold);
-// cerr<<edo.d_extFlags<<endl;
- if(edo.d_extFlags & EDNSOpts::DNSSECOK)
+ if((edo.d_extFlags & EDNSOpts::DNSSECOK) != 0) {
d_dnssecOk=true;
+ }
for(const auto & option : edo.d_options) {
if(option.first == EDNSOptionCode::NSID) {
static bool s_doEDNSSubnetProcessing;
static bool s_doEDNSCookieProcessing;
static string s_EDNSCookieKey;
+ EDNSSubnetOpts d_eso;
#ifdef ENABLE_GSS_TSIG
void cleanupGSS(int rcode);
vector<DNSZoneRecord> d_rrs; // 8
std::unordered_set<size_t> d_dedup;
string d_rawpacket; // this is where everything lives 8
- EDNSSubnetOpts d_eso;
EDNSCookiesOpt d_eco;
int d_maxreplylen{0};
#include "stubresolver.hh"
#include "arguments.hh"
#include "threadname.hh"
+#include "ednsoptions.hh"
+#include "ednssubnet.hh"
extern StatBag S;
//! look up qname target with r->qtype, plonk it in the answer section of 'r' with name aname
bool DNSProxy::completePacket(std::unique_ptr<DNSPacket>& r, const DNSName& target,const DNSName& aname, const uint8_t scopeMask)
{
+ string ECSOptionStr;
+
+ if (r->hasEDNSSubnet())
+ {
+ DLOG(g_log<<"dnsproxy::completePacket: Parsed edns source: "<<r->d_eso.source.toString()<<", scope: "<<r->d_eso.scope.toString()<<", family = "<<r->d_eso.scope.getNetwork().sin4.sin_family<<endl);
+ ECSOptionStr = makeEDNSSubnetOptsString(r->d_eso);
+ DLOG(g_log<<"from dnsproxy::completePacket: Creating ECS option string "<<makeHexDump(ECSOptionStr)<<endl);
+ }
+
if(r->d_tcp) {
vector<DNSZoneRecord> ips;
int ret1 = 0, ret2 = 0;
-
+ // rip out edns info here, pass it to the stubDoResolve
if(r->qtype == QType::A || r->qtype == QType::ANY)
- ret1 = stubDoResolve(target, QType::A, ips);
+ ret1 = stubDoResolve(target, QType::A, ips, r->hasEDNSSubnet() ? &r->d_eso : nullptr);
if(r->qtype == QType::AAAA || r->qtype == QType::ANY)
- ret2 = stubDoResolve(target, QType::AAAA, ips);
+ ret2 = stubDoResolve(target, QType::AAAA, ips, r->hasEDNSSubnet() ? &r->d_eso : nullptr);
if(ret1 != RCode::NoError || ret2 != RCode::NoError) {
g_log<<Logger::Error<<"Error resolving for "<<aname<<" ALIAS "<<target<<" over UDP, original query came in over TCP";
DNSPacketWriter pw(packet, target, qtype);
pw.getHeader()->rd=true;
pw.getHeader()->id=id ^ d_xor;
+ // Add EDNS Subnet if the client sent one - issue #5469
+ if (!ECSOptionStr.empty()) {
+ DLOG(g_log<<"from dnsproxy::completePacket: adding ECS option string to packet options "<<makeHexDump(ECSOptionStr)<<endl);
+ DNSPacketWriter::optvect_t opts;
+ opts.emplace_back(EDNSOptionCode::ECS, ECSOptionStr);
+ pw.addOpt(512, 0, 0, opts);
+ pw.commit();
+ }
if(send(d_sock,&packet[0], packet.size() , 0)<0) { // zoom
g_log<<Logger::Error<<"Unable to send a packet to our recursing backend: "<<stringerror()<<endl;
d.id=i->second.id;
memcpy(buffer,&d,sizeof(d)); // commit spoofed id
- DNSPacket p(false),q(false);
+ DNSPacket p(false);
p.parse(buffer,(size_t)len);
- q.parse(buffer,(size_t)len);
if(p.qtype.getCode() != i->second.qtype || p.qdomain != i->second.qname) {
g_log<<Logger::Error<<"Discarding packet from recursor backend with id "<<(d.id^d_xor)<<
memset(&msgh, 0, sizeof(struct msghdr));
string reply; // needs to be alive at time of sendmsg!
MOADNSParser mdp(false, p.getString());
- // cerr<<"Got completion, "<<mdp.d_answers.size()<<" answers, rcode: "<<mdp.d_header.rcode<<endl;
+ if (p.d_eso.scope.isValid()){
+ // update the EDNS options with info from the resolver - issue #5469
+ i->second.complete->d_eso = p.d_eso;
+ DLOG(g_log<<"from dnsproxy::mainLoop: updated EDNS options from resolver EDNS source: "<<i->second.complete->d_eso.source.toString()<<" EDNS scope: "<<i->second.complete->d_eso.scope.toString()<<endl);
+ }
+
if (mdp.d_header.rcode == RCode::NoError) {
- for (auto& answer : mdp.d_answers) {
- // cerr<<"comp: "<<(int)j->first.d_place-1<<" "<<j->first.d_label<<" " << DNSRecordContent::NumberToType(j->first.d_type)<<" "<<j->first.d_content->getZoneRepresentation()<<endl;
+ for(const auto & answer : mdp.d_answers) {
if(answer.first.d_place == DNSResourceRecord::ANSWER || (answer.first.d_place == DNSResourceRecord::AUTHORITY && answer.first.d_type == QType::SOA)) {
if(answer.first.d_type == i->second.qtype || (i->second.qtype == QType::ANY && (answer.first.d_type == QType::A || answer.first.d_type == QType::AAAA))) {
}
}
}
+
i->second.complete->setRcode(mdp.d_header.rcode);
} else {
g_log<<Logger::Error<<"Error resolving for "<<i->second.aname<<" ALIAS "<<i->second.qname<<" over UDP, "<<QType(i->second.qtype).toString()<<"-record query returned "<<RCode::to_s(mdp.d_header.rcode)<<", returning SERVFAIL"<<endl;
}
else
return false;
- //cerr<<"Source address: "<<address.toString()<<", mask: "<<(int)esow.sourceMask<<endl;
eso->source = Netmask(address, esow.sourceMask);
/* 'address' has more bits set (potentially) than scopeMask. This leads to odd looking netmasks that promise
more precision than they have. For this reason we truncate the address to scopeMask bits */
return ret;
}
+ bool isValid() const
+ {
+ char host[1024];
+ int retval = 0;
+ if(sin4.sin_family && !(retval = getnameinfo(reinterpret_cast<const struct sockaddr*>(this), getSocklen(), host, sizeof(host),0, 0, NI_NUMERICHOST)))
+ return true;
+ else
+ return false;
+ }
+
string toString() const
{
char host[1024];
return (ip & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr));
}
+ bool isValid()
+ {
+ return d_network.isValid();
+ }
+
string toString() const
{
return d_network.toStringNoInterface()+"/"+std::to_string((unsigned int)d_bits);
#include "namespaces.hh"
#include "statbag.hh"
#include "stubresolver.hh"
+#include "ednsoptions.hh"
+#include "ednssubnet.hh"
#define LOCAL_RESOLV_CONF_PATH "/etc/resolv.conf"
// don't stat() for local resolv.conf more than once every INTERVAL secs.
}
// s_resolversForStub contains the ComboAddresses that are used to resolve the
-int stubDoResolve(const DNSName& qname, uint16_t qtype, vector<DNSZoneRecord>& ret)
+int stubDoResolve(const DNSName& qname, uint16_t qtype, vector<DNSZoneRecord>& ret, EDNSSubnetOpts* d_eso)
{
// ensure resolver gets always configured
if (!s_stubResolvConfigured) {
DNSPacketWriter pw(packet, qname, qtype);
pw.getHeader()->id=dns_random_uint16();
pw.getHeader()->rd=1;
+
+ if(d_eso != nullptr)
+ {
+ // pass along EDNS subnet from client if given - issue #5469
+ string origECSOptionStr = makeEDNSSubnetOptsString(*d_eso);
+ DNSPacketWriter::optvect_t opts;
+ opts.emplace_back(EDNSOptionCode::ECS, origECSOptionStr);
+ pw.addOpt(512, 0, 0, opts);
+ pw.commit();
+ }
string queryNameType = qname.toString() + "|" + QType(qtype).toString();
string msg ="Doing stub resolving for '" + queryNameType + "', using resolvers: ";
return RCode::ServFail;
}
-int stubDoResolve(const DNSName& qname, uint16_t qtype, vector<DNSRecord>& ret) {
+int stubDoResolve(const DNSName& qname, uint16_t qtype, vector<DNSRecord>& ret, EDNSSubnetOpts* d_eso) {
vector<DNSZoneRecord> ret2;
- int res = stubDoResolve(qname, qtype, ret2);
+ int res = stubDoResolve(qname, qtype, ret2, d_eso);
for (const auto &r : ret2) {
ret.push_back(r.dr);
}
#pragma once
#include "namespaces.hh"
#include "dnsparser.hh"
+#include "ednssubnet.hh"
void stubParseResolveConf();
bool resolversDefined();
-int stubDoResolve(const DNSName& qname, uint16_t qtype, vector<DNSZoneRecord>& ret);
-int stubDoResolve(const DNSName& qname, uint16_t qtype, vector<DNSRecord>& ret);
+int stubDoResolve(const DNSName& qname, uint16_t qtype, vector<DNSZoneRecord>& ret, EDNSSubnetOpts* d_eso = nullptr);
+int stubDoResolve(const DNSName& qname, uint16_t qtype, vector<DNSRecord>& ret, EDNSSubnetOpts* d_eso = nullptr);