+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include "utility.hh"
-#include "lwres.hh"
-#include <iostream>
-#include "dnsrecords.hh"
-#include <errno.h>
-#include "misc.hh"
-#include <algorithm>
-#include <sstream>
-#include <cstring>
-#include <string>
-#include <vector>
-#include "dns.hh"
-#include "qtype.hh"
-#include "pdnsexception.hh"
-#include "arguments.hh"
-#include "sstuff.hh"
-#include "syncres.hh"
-#include "dnswriter.hh"
-#include "dnsparser.hh"
-#include "logger.hh"
-#include "dns_random.hh"
-#include <boost/scoped_array.hpp>
-#include <boost/algorithm/string.hpp>
-#include "validate-recursor.hh"
-#include "ednssubnet.hh"
-#include "query-local-address.hh"
-#include "tcpiohandler.hh"
-#include "ednsoptions.hh"
-#include "ednspadding.hh"
-#include "rec-protozero.hh"
-#include "uuid-utils.hh"
-#include "rec-tcpout.hh"
-
-thread_local TCPOutConnectionManager t_tcp_manager;
-std::shared_ptr<Logr::Logger> g_slogout;
-bool g_paddingOutgoing;
-
-void remoteLoggerQueueData(RemoteLoggerInterface& r, const std::string& data)
-{
- auto ret = r.queueData(data);
-
- switch (ret) {
- case RemoteLoggerInterface::Result::Queued:
- break;
- case RemoteLoggerInterface::Result::PipeFull: {
- const auto msg = RemoteLoggerInterface::toErrorString(ret);
- const auto name = r.name();
- SLOG(g_log << Logger::Debug << name << ": " << msg <<std::endl,
- g_slog->withName(name)->info(Logr::Debug, msg));
- break;
- }
- case RemoteLoggerInterface::Result::TooLarge: {
- const auto msg = RemoteLoggerInterface::toErrorString(ret);
- const auto name = r.name();
- SLOG(g_log << Logger::Notice << name << ": " << msg <<endl,
- g_slog->withName(name)->info(Logr::Debug, msg));
- break;
- }
- case RemoteLoggerInterface::Result::OtherError: {
- const auto msg = RemoteLoggerInterface::toErrorString(ret);
- const auto name = r.name();
- SLOG(g_log << Logger::Warning << name << ": " << msg << std::endl,
- g_slog->withName(name)->info(Logr::Warning, msg));
- break;
- }
- }
-}
-
-#ifdef HAVE_FSTRM
-#include "dnstap.hh"
-#include "fstrm_logger.hh"
-
-bool g_syslog;
-
-static bool isEnabledForQueries(const std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& fstreamLoggers)
-{
- if (fstreamLoggers == nullptr) {
- return false;
- }
- for (auto& logger : *fstreamLoggers) {
- if (logger->logQueries()) {
- return true;
- }
- }
- return false;
-}
-
-static void logFstreamQuery(const std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& fstreamLoggers, const struct timeval &queryTime, const ComboAddress& localip, const ComboAddress& ip, DnstapMessage::ProtocolType protocol, boost::optional<const DNSName&> auth, const vector<uint8_t>& packet)
-{
- if (fstreamLoggers == nullptr)
- return;
-
- struct timespec ts;
- TIMEVAL_TO_TIMESPEC(&queryTime, &ts);
- std::string str;
- DnstapMessage message(str, DnstapMessage::MessageType::resolver_query, SyncRes::s_serverID, &localip, &ip, protocol, reinterpret_cast<const char*>(&*packet.begin()), packet.size(), &ts, nullptr, auth);
-
- for (auto& logger : *fstreamLoggers) {
- remoteLoggerQueueData(*logger, str);
- }
-}
-
-static bool isEnabledForResponses(const std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& fstreamLoggers)
-{
- if (fstreamLoggers == nullptr) {
- return false;
- }
- for (auto& logger : *fstreamLoggers) {
- if (logger->logResponses()) {
- return true;
- }
- }
- return false;
-}
-
-static void logFstreamResponse(const std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& fstreamLoggers, const ComboAddress&localip, const ComboAddress& ip, DnstapMessage::ProtocolType protocol, boost::optional<const DNSName&> auth, const PacketBuffer& packet, const struct timeval& queryTime, const struct timeval& replyTime)
-{
- if (fstreamLoggers == nullptr)
- return;
-
- struct timespec ts1, ts2;
- TIMEVAL_TO_TIMESPEC(&queryTime, &ts1);
- TIMEVAL_TO_TIMESPEC(&replyTime, &ts2);
- std::string str;
- DnstapMessage message(str, DnstapMessage::MessageType::resolver_response, SyncRes::s_serverID, &localip, &ip, protocol, reinterpret_cast<const char*>(packet.data()), packet.size(), &ts1, &ts2, auth);
-
- for (auto& logger : *fstreamLoggers) {
- remoteLoggerQueueData(*logger, str);
- }
-}
-
-#endif // HAVE_FSTRM
-
-static void logOutgoingQuery(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, boost::optional<const boost::uuids::uuid&> initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& ip, const DNSName& domain, int type, uint16_t qid, bool doTCP, bool tls, size_t bytes, boost::optional<Netmask>& srcmask)
-{
- if (!outgoingLoggers) {
- return;
- }
-
- bool log = false;
- for (auto& logger : *outgoingLoggers) {
- if (logger->logQueries()) {
- log = true;
- break;
- }
- }
-
- if (!log) {
- return;
- }
-
- static thread_local std::string buffer;
- buffer.clear();
- pdns::ProtoZero::Message m{buffer};
- m.setType(pdns::ProtoZero::Message::MessageType::DNSOutgoingQueryType);
- m.setMessageIdentity(uuid);
- m.setSocketFamily(ip.sin4.sin_family);
- if (!doTCP) {
- m.setSocketProtocol(pdns::ProtoZero::Message::TransportProtocol::UDP);
- }
- else if (!tls) {
- m.setSocketProtocol(pdns::ProtoZero::Message::TransportProtocol::TCP);
- }
- else {
- m.setSocketProtocol(pdns::ProtoZero::Message::TransportProtocol::DoT);
- }
-
- m.setTo(ip);
- m.setInBytes(bytes);
- m.setTime();
- m.setId(qid);
- m.setQuestion(domain, type, QClass::IN);
- m.setToPort(ip.getPort());
- m.setServerIdentity(SyncRes::s_serverID);
-
- if (initialRequestId) {
- m.setInitialRequestID(*initialRequestId);
- }
-
- if (srcmask) {
- m.setEDNSSubnet(*srcmask, 128);
- }
-
- for (auto& logger : *outgoingLoggers) {
- if (logger->logQueries()) {
- remoteLoggerQueueData(*logger, buffer);
- }
- }
-}
-
-static void logIncomingResponse(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, boost::optional<const boost::uuids::uuid&> initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& ip, const DNSName& domain, int type, uint16_t qid, bool doTCP, bool tls, boost::optional<Netmask>& srcmask, size_t bytes, int rcode, const std::vector<DNSRecord>& records, const struct timeval& queryTime, const std::set<uint16_t>& exportTypes)
-{
- if (!outgoingLoggers) {
- return;
- }
-
- bool log = false;
- for (auto& logger : *outgoingLoggers) {
- if (logger->logResponses()) {
- log = true;
- break;
- }
- }
-
- if (!log) {
- return;
- }
-
- static thread_local std::string buffer;
- buffer.clear();
- pdns::ProtoZero::RecMessage m{buffer};
- m.setType(pdns::ProtoZero::Message::MessageType::DNSIncomingResponseType);
- m.setMessageIdentity(uuid);
- m.setSocketFamily(ip.sin4.sin_family);
- if (!doTCP) {
- m.setSocketProtocol(pdns::ProtoZero::Message::TransportProtocol::UDP);
- }
- else if (!tls) {
- m.setSocketProtocol(pdns::ProtoZero::Message::TransportProtocol::TCP);
- }
- else {
- m.setSocketProtocol(pdns::ProtoZero::Message::TransportProtocol::DoT);
- }
- m.setTo(ip);
- m.setInBytes(bytes);
- m.setTime();
- m.setId(qid);
- m.setQuestion(domain, type, QClass::IN);
- m.setToPort(ip.getPort());
- m.setServerIdentity(SyncRes::s_serverID);
-
- if (initialRequestId) {
- m.setInitialRequestID(*initialRequestId);
- }
-
- if (srcmask) {
- m.setEDNSSubnet(*srcmask, 128);
- }
-
- m.startResponse();
- m.setQueryTime(queryTime.tv_sec, queryTime.tv_usec);
- if (rcode == -1) {
- m.setNetworkErrorResponseCode();
- }
- else {
- m.setResponseCode(rcode);
- }
-
- for (const auto& record : records) {
- m.addRR(record, exportTypes, false);
- }
- m.commitResponse();
-
- for (auto& logger : *outgoingLoggers) {
- if (logger->logResponses()) {
- remoteLoggerQueueData(*logger, buffer);
- }
- }
-}
-
-static bool tcpconnect(const struct timeval& now, const ComboAddress& ip, TCPOutConnectionManager::Connection& connection, bool& dnsOverTLS, const std::string& nsName)
-{
- dnsOverTLS = SyncRes::s_dot_to_port_853 && ip.getPort() == 853;
-
- connection = t_tcp_manager.get(ip);
- if (connection.d_handler) {
- return false;
- }
-
- const struct timeval timeout{ g_networkTimeoutMsec / 1000, static_cast<suseconds_t>(g_networkTimeoutMsec) % 1000 * 1000};
- Socket s(ip.sin4.sin_family, SOCK_STREAM);
- s.setNonBlocking();
- setTCPNoDelay(s.getHandle());
- ComboAddress localip = pdns::getQueryLocalAddress(ip.sin4.sin_family, 0);
- s.bind(localip);
-
- std::shared_ptr<TLSCtx> tlsCtx{nullptr};
- if (dnsOverTLS) {
- TLSContextParameters tlsParams;
- tlsParams.d_provider = "openssl";
- tlsParams.d_validateCertificates = false;
- // tlsParams.d_caStore
- tlsCtx = getTLSContext(tlsParams);
- if (tlsCtx == nullptr) {
- SLOG(g_log << Logger::Error << "DoT to " << ip << " requested but not available" << endl,
- g_slogout->info(Logr::Error, "DoT requested but not available", "server", Logging::Loggable(ip)));
- dnsOverTLS = false;
- }
- }
- connection.d_handler = std::make_shared<TCPIOHandler>(nsName, false, s.releaseHandle(), timeout, tlsCtx, now.tv_sec);
- // Returned state ignored
- // This can throw an exception, retry will need to happen at higher level
- connection.d_handler->tryConnect(SyncRes::s_tcp_fast_open_connect, ip);
- return true;
-}
-
-static LWResult::Result tcpsendrecv(const ComboAddress& ip, TCPOutConnectionManager::Connection& connection,
- ComboAddress& localip, const vector<uint8_t>& vpacket, size_t& len, PacketBuffer& buf)
-{
- socklen_t slen = ip.getSocklen();
- uint16_t tlen = htons(vpacket.size());
- const char *lenP = reinterpret_cast<const char*>(&tlen);
-
- len = 0; // in case of error
- localip.sin4.sin_family = ip.sin4.sin_family;
- if (getsockname(connection.d_handler->getDescriptor(), reinterpret_cast<sockaddr*>(&localip), &slen) != 0) {
- return LWResult::Result::PermanentError;
- }
-
- PacketBuffer packet;
- packet.reserve(2 + vpacket.size());
- packet.insert(packet.end(), lenP, lenP + 2);
- packet.insert(packet.end(), vpacket.begin(), vpacket.end());
-
- LWResult::Result ret = asendtcp(packet, connection.d_handler);
- if (ret != LWResult::Result::Success) {
- return ret;
- }
-
- ret = arecvtcp(packet, 2, connection.d_handler, false);
- if (ret != LWResult::Result::Success) {
- return ret;
- }
-
- memcpy(&tlen, packet.data(), sizeof(tlen));
- len = ntohs(tlen); // switch to the 'len' shared with the rest of the calling function
-
- // XXX receive into buf directly?
- packet.resize(len);
- ret = arecvtcp(packet, len, connection.d_handler, false);
- if (ret != LWResult::Result::Success) {
- return ret;
- }
- buf.resize(len);
- memcpy(buf.data(), packet.data(), len);
- return LWResult::Result::Success;
-}
-
-static void addPadding(const DNSPacketWriter& pw, size_t bufsize, DNSPacketWriter::optvect_t& opts)
-{
- const size_t currentSize = pw.getSizeWithOpts(opts);
- if (currentSize < (bufsize - 4)) {
- const size_t remaining = bufsize - (currentSize + 4);
- /* from rfc8647, "4.1. Recommended Strategy: Block-Length Padding":
- Clients SHOULD pad queries to the closest multiple of 128 octets.
- Note we are in the client role here.
- */
- const size_t blockSize = 128;
- const size_t modulo = (currentSize + 4) % blockSize;
- size_t padSize = 0;
- if (modulo > 0) {
- padSize = std::min(blockSize - modulo, remaining);
- }
- opts.emplace_back(EDNSOptionCode::PADDING, makeEDNSPaddingOptString(padSize));
- }
-}
-
-/** lwr is only filled out in case 1 was returned, and even when returning 1 for 'success', lwr might contain DNS errors
- Never throws!
- */
-static LWResult::Result asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, const std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& fstrmLoggers, const std::set<uint16_t>& exportTypes, LWResult *lwr, bool* chained, TCPOutConnectionManager::Connection& connection)
-{
- size_t len;
- size_t bufsize=g_outgoingEDNSBufsize;
- PacketBuffer buf;
- buf.resize(bufsize);
- vector<uint8_t> vpacket;
- // string mapped0x20=dns0x20(domain);
- uint16_t qid = dns_random_uint16();
- DNSPacketWriter pw(vpacket, domain, type);
- bool dnsOverTLS = SyncRes::s_dot_to_port_853 && ip.getPort() == 853;
-
- pw.getHeader()->rd=sendRDQuery;
- pw.getHeader()->id=qid;
- /* RFC 6840 section 5.9:
- * This document further specifies that validating resolvers SHOULD set
- * the CD bit on every upstream query. This is regardless of whether
- * the CD bit was set on the incoming query [...]
- *
- * sendRDQuery is only true if the qname is part of a forward-zone-recurse (or
- * set in the forward-zone-file), so we use this as an indicator for it being
- * an "upstream query". To stay true to "dnssec=off means 3.X behaviour", we
- * only set +CD on forwarded query in any mode other than dnssec=off.
- */
- pw.getHeader()->cd=(sendRDQuery && g_dnssecmode != DNSSECMode::Off);
-
- string ping;
- bool weWantEDNSSubnet=false;
- uint8_t outgoingECSBits = 0;
- ComboAddress outgoingECSAddr;
- if(EDNS0Level > 0) {
- DNSPacketWriter::optvect_t opts;
- if(srcmask) {
- EDNSSubnetOpts eo;
- eo.source = *srcmask;
- outgoingECSBits = srcmask->getBits();
- outgoingECSAddr = srcmask->getNetwork();
- // cout<<"Adding request mask: "<<eo.source.toString()<<endl;
- opts.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(eo));
- weWantEDNSSubnet=true;
- }
-
- if (dnsOverTLS && g_paddingOutgoing) {
- addPadding(pw, bufsize, opts);
- }
-
- pw.addOpt(g_outgoingEDNSBufsize, 0, g_dnssecmode == DNSSECMode::Off ? 0 : EDNSOpts::DNSSECOK, opts);
- pw.commit();
- }
- lwr->d_rcode = 0;
- lwr->d_haveEDNS = false;
- LWResult::Result ret;
-
- DTime dt;
- dt.set();
- *now=dt.getTimeval();
-
- boost::uuids::uuid uuid;
- const struct timeval queryTime = *now;
-
- if (outgoingLoggers) {
- uuid = getUniqueID();
- logOutgoingQuery(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, dnsOverTLS, vpacket.size(), srcmask);
- }
-
- srcmask = boost::none; // this is also our return value, even if EDNS0Level == 0
-
- // We only store the localip if needed for fstrm logging
- ComboAddress localip;
-#ifdef HAVE_FSTRM
- bool fstrmQEnabled = false;
- bool fstrmREnabled = false;
-
- if (isEnabledForQueries(fstrmLoggers)) {
- fstrmQEnabled = true;
- }
- if (isEnabledForResponses(fstrmLoggers)) {
- fstrmREnabled = true;
- }
-#endif
-
- if(!doTCP) {
- int queryfd;
- if (ip.sin4.sin_family==AF_INET6) {
- t_Counters.at(rec::Counter::ipv6queries)++;
- }
-
- ret = asendto((const char*)&*vpacket.begin(), vpacket.size(), 0, ip, qid, domain, type, &queryfd);
-
- if (ret != LWResult::Result::Success) {
- return ret;
- }
-
- if (queryfd == -1) {
- *chained = true;
- }
-
-#ifdef HAVE_FSTRM
- if (!*chained) {
- if (fstrmQEnabled || fstrmREnabled) {
- localip.sin4.sin_family = ip.sin4.sin_family;
- socklen_t slen = ip.getSocklen();
- getsockname(queryfd, reinterpret_cast<sockaddr*>(&localip), &slen);
- }
- if (fstrmQEnabled) {
- logFstreamQuery(fstrmLoggers, queryTime, localip, ip, DnstapMessage::ProtocolType::DoUDP, context ? context->d_auth : boost::none, vpacket);
- }
- }
-#endif /* HAVE_FSTRM */
-
- // sleep until we see an answer to this, interface to mtasker
- ret = arecvfrom(buf, 0, ip, &len, qid, domain, type, queryfd, now);
- }
- else {
- bool isNew;
- do {
- try {
- // If we get a new (not re-used) TCP connection that does not
- // work, we give up. For reused connections, we assume the
- // peer has closed it on error, so we retry. At some point we
- // *will* get a new connection, so this loop is not endless.
- isNew = true; // tcpconnect() might throw for new connections. In that case, we want to break the loop, scanbuild complains here, which is a false positive afaik
- std::string nsName;
- if (context && !context->d_nsName.empty()) {
- nsName = context->d_nsName.toStringNoDot();
- }
- isNew = tcpconnect(*now, ip, connection, dnsOverTLS, nsName);
- ret = tcpsendrecv(ip, connection, localip, vpacket, len, buf);
-#ifdef HAVE_FSTRM
- if (fstrmQEnabled) {
- logFstreamQuery(fstrmLoggers, queryTime, localip, ip, !dnsOverTLS ? DnstapMessage::ProtocolType::DoTCP : DnstapMessage::ProtocolType::DoT, context ? context->d_auth : boost::none, vpacket);
- }
-#endif /* HAVE_FSTRM */
- if (ret == LWResult::Result::Success) {
- break;
- }
- connection.d_handler->close();
- }
- catch (const NetworkError&) {
- ret = LWResult::Result::OSLimitError; // OS limits error
- }
- catch (const runtime_error&) {
- ret = LWResult::Result::OSLimitError; // OS limits error (PermanentError is transport related)
- }
- } while (!isNew);
- }
-
- lwr->d_usec=dt.udiff();
- *now=dt.getTimeval();
-
- if (ret != LWResult::Result::Success) { // includes 'timeout'
- if (outgoingLoggers) {
- logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, dnsOverTLS, srcmask, 0, -1, {}, queryTime, exportTypes);
- }
- return ret;
- }
-
- buf.resize(len);
-
-#ifdef HAVE_FSTRM
- if (fstrmREnabled && (!*chained || doTCP)) {
- DnstapMessage::ProtocolType protocol = doTCP ? DnstapMessage::ProtocolType::DoTCP : DnstapMessage::ProtocolType::DoUDP;
- if (dnsOverTLS) {
- protocol = DnstapMessage::ProtocolType::DoT;
- }
- logFstreamResponse(fstrmLoggers, localip, ip, protocol, context ? context->d_auth : boost::none, buf, queryTime, *now);
- }
-#endif /* HAVE_FSTRM */
-
- lwr->d_records.clear();
- try {
- lwr->d_tcbit=0;
- MOADNSParser mdp(false, reinterpret_cast<const char*>(buf.data()), buf.size());
- lwr->d_aabit=mdp.d_header.aa;
- lwr->d_tcbit=mdp.d_header.tc;
- lwr->d_rcode=mdp.d_header.rcode;
-
- if(mdp.d_header.rcode == RCode::FormErr && mdp.d_qname.empty() && mdp.d_qtype == 0 && mdp.d_qclass == 0) {
- if(outgoingLoggers) {
- logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
- }
- lwr->d_validpacket = true;
- return LWResult::Result::Success; // this is "success", the error is set in lwr->d_rcode
- }
-
- if(domain != mdp.d_qname) {
- if(!mdp.d_qname.empty() && domain.toString().find((char)0) == string::npos /* ugly */) {// embedded nulls are too noisy, plus empty domains are too
- SLOG(g_log<<Logger::Notice<<"Packet purporting to come from remote server "<<ip.toString()<<" contained wrong answer: '" << domain << "' != '" << mdp.d_qname << "'" << endl,
- g_slogout->info(Logr::Notice, "Packet purporting to come from remote server contained wrong answer",
- "server", Logging::Loggable(ip),
- "qname", Logging::Loggable(domain),
- "onwire", Logging::Loggable(mdp.d_qname)));
- }
- // unexpected count has already been done @ pdns_recursor.cc
- goto out;
- }
-
- lwr->d_records.reserve(mdp.d_answers.size());
- for(const auto& a : mdp.d_answers)
- lwr->d_records.push_back(a.first);
-
- EDNSOpts edo;
- if(EDNS0Level > 0 && getEDNSOpts(mdp, &edo)) {
- lwr->d_haveEDNS = true;
-
- if(weWantEDNSSubnet) {
- for(const auto& opt : edo.d_options) {
- if(opt.first==EDNSOptionCode::ECS) {
- EDNSSubnetOpts reso;
- if(getEDNSSubnetOptsFromString(opt.second, &reso)) {
- // cerr<<"EDNS Subnet response: "<<reso.source.toString()<<", scope: "<<reso.scope.toString()<<", family = "<<reso.scope.getNetwork().sin4.sin_family<<endl;
- /* rfc7871 states that 0 "indicate[s] that the answer is suitable for all addresses in FAMILY",
- so we might want to still pass the information along to be able to differentiate between
- IPv4 and IPv6. Still I'm pretty sure it doesn't matter in real life, so let's not duplicate
- entries in our cache. */
- if(reso.scope.getBits()) {
- uint8_t bits = std::min(reso.scope.getBits(), outgoingECSBits);
- outgoingECSAddr.truncate(bits);
- srcmask = Netmask(outgoingECSAddr, bits);
- }
- }
- }
- }
- }
- }
-
- if(outgoingLoggers) {
- logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
- }
-
- lwr->d_validpacket = true;
- return LWResult::Result::Success;
- }
- catch (const std::exception &mde) {
- if (::arg().mustDo("log-common-errors")) {
- SLOG(g_log<<Logger::Notice<<"Unable to parse packet from remote server "<<ip.toString()<<": "<<mde.what()<<endl,
- g_slogout->error(Logr::Notice, mde.what(), "Unable to parse packet from remote server", "server", Logging::Loggable(ip),
- "exception", Logging::Loggable("std::exception")));
- }
-
- lwr->d_rcode = RCode::FormErr;
- lwr->d_validpacket = false;
- t_Counters.at(rec::Counter::serverParseError)++;
-
- if(outgoingLoggers) {
- logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
- }
-
- return LWResult::Result::Success; // success - oddly enough
- }
- catch (...) {
- SLOG(g_log<<Logger::Notice<<"Unknown error parsing packet from remote server"<<endl,
- g_slogout->info(Logr::Notice, "Unknown error parsing packet from remote server", "server", Logging::Loggable(ip)));
- }
-
- t_Counters.at(rec::Counter::serverParseError)++;
-
- out:
- if (!lwr->d_rcode) {
- lwr->d_rcode=RCode::ServFail;
- }
-
- return LWResult::Result::PermanentError;
-}
-
-LWResult::Result asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, const std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& fstrmLoggers, const std::set<uint16_t>& exportTypes, LWResult *lwr, bool* chained)
-{
- TCPOutConnectionManager::Connection connection;
- auto ret = asyncresolve(ip, domain, type, doTCP, sendRDQuery, EDNS0Level, now, srcmask, context, outgoingLoggers, fstrmLoggers, exportTypes, lwr, chained, connection);
-
- if (doTCP) {
- if (connection.d_handler && lwr->d_validpacket) {
- t_tcp_manager.store(*now, ip, std::move(connection));
- }
- }
- return ret;
-}
-