ComboAddress d_remote, d_local;
#ifdef HAVE_PROTOBUF
boost::uuids::uuid d_uuid;
- Netmask d_ednssubnet;
#endif
+ EDNSSubnetOpts d_ednssubnet;
+ bool d_ecsFound{false};
+ bool d_ecsParsed{false};
bool d_tcp;
int d_socket;
int d_tag{0};
maxanswersize = min(edo.d_packetsize, g_udpTruncationThreshold);
dc->d_ednsOpts = edo.d_options;
haveEDNS=true;
+
+ if (g_useIncomingECS && !dc->d_ecsParsed) {
+ for (const auto& o : edo.d_options) {
+ if (o.first == EDNSOptionCode::ECS) {
+ dc->d_ecsFound = getEDNSSubnetOptsFromString(o.second, &dc->d_ednssubnet);
+ break;
+ }
+ }
+ }
}
+ /* perhaps there was no EDNS or no ECS but by now we looked */
+ dc->d_ecsParsed = true;
vector<DNSRecord> ret;
vector<uint8_t> packet;
Netmask requestorNM(dc->d_remote, dc->d_remote.sin4.sin_family == AF_INET ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
const ComboAddress& requestor = requestorNM.getMaskedNetwork();
pbMessage.update(dc->d_uuid, &requestor, &dc->d_local, dc->d_tcp, dc->d_mdp.d_header.id);
- pbMessage.setEDNSSubnet(dc->d_ednssubnet, dc->d_ednssubnet.isIpv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
+ pbMessage.setEDNSSubnet(dc->d_ednssubnet.source, dc->d_ednssubnet.source.isIpv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
pbMessage.setQuestion(dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass);
}
#endif /* HAVE_PROTOBUF */
#ifdef HAVE_PROTOBUF
sr.d_initialRequestId = dc->d_uuid;
#endif
+ if (g_useIncomingECS) {
+ sr.d_incomingECSFound = dc->d_ecsFound;
+ if (dc->d_ecsFound) {
+ sr.d_incomingECS = dc->d_ednssubnet;
+ }
+ }
bool tracedQuery=false; // we could consider letting Lua know about this too
bool variableAnswer = false;
if(!g_quiet || tracedQuery) {
L<<Logger::Warning<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] " << (dc->d_tcp ? "TCP " : "") << "question for '"<<dc->d_mdp.d_qname<<"|"
<<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)<<"' from "<<dc->getRemote();
-#ifdef HAVE_PROTOBUF
- if(!dc->d_ednssubnet.empty()) {
- L<<" (ecs "<<dc->d_ednssubnet.toString()<<")";
+ if(!dc->d_ednssubnet.source.empty()) {
+ L<<" (ecs "<<dc->d_ednssubnet.source.toString()<<")";
}
-#endif
L<<endl;
}
}
}
-static void getQNameAndSubnet(const std::string& question, DNSName* dnsname, uint16_t* qtype, uint16_t* qclass, Netmask* ednssubnet)
+static bool getQNameAndSubnet(const std::string& question, DNSName* dnsname, uint16_t* qtype, uint16_t* qclass, EDNSSubnetOpts* ednssubnet)
{
+ bool found = false;
const struct dnsheader* dh = (struct dnsheader*)question.c_str();
size_t questionLen = question.length();
unsigned int consumed=0;
if (res == 0 && ecsLen > 4) {
EDNSSubnetOpts eso;
if(getEDNSSubnetOptsFromString(ecsStart + 4, ecsLen - 4, &eso)) {
- *ednssubnet=eso.source;
+ *ednssubnet=eso;
+ found = true;
}
}
}
}
+ return found;
}
void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var)
socklen_t len = dest.getSocklen();
getsockname(conn->getFD(), (sockaddr*)&dest, &len); // if this fails, we're ok with it
dc->setLocal(dest);
- Netmask ednssubnet;
DNSName qname;
uint16_t qtype=0;
uint16_t qclass=0;
if(needECS || (t_pdl->get() && (*t_pdl)->d_gettag)) {
try {
- getQNameAndSubnet(std::string(conn->data, conn->qlen), &qname, &qtype, &qclass, &ednssubnet);
+ dc->d_ecsParsed = true;
+ dc->d_ecsFound = getQNameAndSubnet(std::string(conn->data, conn->qlen), &qname, &qtype, &qclass, &dc->d_ednssubnet);
if(t_pdl->get() && (*t_pdl)->d_gettag) {
try {
- dc->d_tag = (*t_pdl)->gettag(conn->d_remote, ednssubnet, dest, qname, qtype, &dc->d_policyTags, dc->d_data);
+ dc->d_tag = (*t_pdl)->gettag(conn->d_remote, dc->d_ednssubnet.source, dest, qname, qtype, &dc->d_policyTags, dc->d_data);
}
catch(std::exception& e) {
if(g_logCommonErrors)
if(luaconfsLocal->protobufServer) {
try {
const struct dnsheader* dh = (const struct dnsheader*) conn->data;
- dc->d_ednssubnet = ednssubnet;
if (!luaconfsLocal->protobufTaggedOnly) {
- protobufLogQuery(luaconfsLocal->protobufServer, luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, dc->d_uuid, conn->d_remote, dest, ednssubnet, true, dh->id, conn->qlen, qname, qtype, qclass, dc->d_policyTags);
+ protobufLogQuery(luaconfsLocal->protobufServer, luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, dc->d_uuid, conn->d_remote, dest, dc->d_ednssubnet.source, true, dh->id, conn->qlen, qname, qtype, qclass, dc->d_policyTags);
}
}
catch(std::exception& e) {
uniqueId = (*t_uuidGenerator)();
}
#endif
- Netmask ednssubnet;
+ EDNSSubnetOpts ednssubnet;
+ bool ecsFound = false;
+ bool ecsParsed = false;
try {
DNSName qname;
uint16_t qtype=0;
if(needECS || (t_pdl->get() && (*t_pdl)->d_gettag)) {
try {
- getQNameAndSubnet(question, &qname, &qtype, &qclass, &ednssubnet);
+ ecsParsed = true;
+ ecsFound = getQNameAndSubnet(question, &qname, &qtype, &qclass, &ednssubnet);
if(t_pdl->get() && (*t_pdl)->d_gettag) {
try {
- ctag=(*t_pdl)->gettag(fromaddr, ednssubnet, destaddr, qname, qtype, &policyTags, data);
+ ctag=(*t_pdl)->gettag(fromaddr, ednssubnet.source, destaddr, qname, qtype, &policyTags, data);
}
catch(std::exception& e) {
if(g_logCommonErrors)
#ifdef HAVE_PROTOBUF
if(luaconfsLocal->protobufServer) {
if (!luaconfsLocal->protobufTaggedOnly || !policyTags.empty()) {
- protobufLogQuery(luaconfsLocal->protobufServer, luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, uniqueId, fromaddr, destaddr, ednssubnet, false, dh->id, question.size(), qname, qtype, qclass, policyTags);
+ protobufLogQuery(luaconfsLocal->protobufServer, luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, uniqueId, fromaddr, destaddr, ednssubnet.source, false, dh->id, question.size(), qname, qtype, qclass, policyTags);
}
}
#endif /* HAVE_PROTOBUF */
Netmask requestorNM(fromaddr, fromaddr.sin4.sin_family == AF_INET ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
const ComboAddress& requestor = requestorNM.getMaskedNetwork();
pbMessage.update(uniqueId, &requestor, &destaddr, false, dh->id);
- pbMessage.setEDNSSubnet(ednssubnet, ednssubnet.isIpv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
+ pbMessage.setEDNSSubnet(ednssubnet.source, ednssubnet.source.isIpv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
pbMessage.setQueryTime(g_now.tv_sec, g_now.tv_usec);
protobufLogResponse(luaconfsLocal->protobufServer, pbMessage);
}
dc->d_tcp=false;
dc->d_policyTags = policyTags;
dc->d_data = data;
+ dc->d_ecsFound = ecsFound;
+ dc->d_ecsParsed = ecsParsed;
+ dc->d_ednssubnet = ednssubnet;
#ifdef HAVE_PROTOBUF
if (luaconfsLocal->protobufServer || luaconfsLocal->outgoingProtobufServer) {
dc->d_uuid = uniqueId;
}
- dc->d_ednssubnet = ednssubnet;
#endif
MT->makeThread(startDoResolve, (void*) dc); // deletes dc
makeTCPServerSockets();
parseEDNSSubnetWhitelist(::arg()["edns-subnet-whitelist"]);
+ g_useIncomingECS = ::arg().mustDo("use-incoming-edns-subnet");
int forks;
for(forks = 0; forks < ::arg().asNum("processes") - 1; ++forks) {
::arg().set("ecs-ipv4-bits", "Number of bits of IPv4 address to pass for EDNS Client Subnet")="24";
::arg().set("ecs-ipv6-bits", "Number of bits of IPv6 address to pass for EDNS Client Subnet")="56";
::arg().set("edns-subnet-whitelist", "List of netmasks and domains that we should enable EDNS subnet for")="";
+ ::arg().setSwitch( "use-incoming-edns-subnet", "Pass along received EDNS Client Subnet information")="";
::arg().setSwitch( "pdns-distributes-queries", "If PowerDNS itself should distribute queries over threads")="yes";
::arg().setSwitch( "root-nx-trust", "If set, believe that an NXDOMAIN from the root means the TLD does not exist")="yes";
::arg().setSwitch( "any-to-tcp","Answer ANY queries with tc=1, shunting to TCP" )="no";