From: Remi Gacogne Date: Thu, 21 Oct 2021 15:12:47 +0000 (+0200) Subject: Support DoT, DoH and DNSCrypt transports for protobuf and dnstap X-Git-Tag: rec-4.6.0-beta1~44^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cffd3a17ad7a1a396075dc3123f0ac20cdf02203;p=thirdparty%2Fpdns.git Support DoT, DoH and DNSCrypt transports for protobuf and dnstap --- diff --git a/contrib/ProtobufLogger.py b/contrib/ProtobufLogger.py index 36b361bfda..0370a20ca3 100644 --- a/contrib/ProtobufLogger.py +++ b/contrib/ProtobufLogger.py @@ -204,8 +204,16 @@ class PDNSPBConnHandler(object): if msg.socketProtocol == dnsmessage_pb2.PBDNSMessage.UDP: protostr = 'UDP' - else: + elif msg.socketProtocol == dnsmessage_pb2.PBDNSMessage.TCP: protostr = 'TCP' + elif msg.socketProtocol == dnsmessage_pb2.PBDNSMessage.DOT: + protostr = 'DoT' + elif msg.socketProtocol == dnsmessage_pb2.PBDNSMessage.DOH: + protostr = 'DoH' + elif msg.socketProtocol == dnsmessage_pb2.PBDNSMessage.DNSCryptUDP: + protostr = 'DNSCrypt UDP' + elif msg.socketProtocol == dnsmessage_pb2.PBDNSMessage.DNSCryptTCP: + protostr = 'DNSCrypt TCP' if msg.HasField('fromPort'): fromportstr = ':' + str(msg.fromPort) + ' ' diff --git a/pdns/dnsdist-lua-actions.cc b/pdns/dnsdist-lua-actions.cc index a96b70dcc4..ba132daf83 100644 --- a/pdns/dnsdist-lua-actions.cc +++ b/pdns/dnsdist-lua-actions.cc @@ -1359,10 +1359,10 @@ private: static DnstapMessage::ProtocolType ProtocolToDNSTap(dnsdist::Protocol protocol) { - if (protocol == dnsdist::Protocol::DoUDP || protocol == dnsdist::Protocol::DNSCryptUDP) { + if (protocol == dnsdist::Protocol::DoUDP) { return DnstapMessage::ProtocolType::DoUDP; } - else if (protocol == dnsdist::Protocol::DoTCP || protocol == dnsdist::Protocol::DNSCryptTCP) { + else if (protocol == dnsdist::Protocol::DoTCP) { return DnstapMessage::ProtocolType::DoTCP; } else if (protocol == dnsdist::Protocol::DoT) { @@ -1371,6 +1371,12 @@ static DnstapMessage::ProtocolType ProtocolToDNSTap(dnsdist::Protocol protocol) else if (protocol == dnsdist::Protocol::DoH) { return DnstapMessage::ProtocolType::DoH; } + else if (protocol == dnsdist::Protocol::DNSCryptUDP) { + return DnstapMessage::ProtocolType::DNSCryptUDP; + } + else if (protocol == dnsdist::Protocol::DNSCryptTCP) { + return DnstapMessage::ProtocolType::DNSCryptTCP; + } throw std::runtime_error("Unhandled protocol for dnstap: " + protocol.toPrettyString()); } diff --git a/pdns/dnsdist-protobuf.cc b/pdns/dnsdist-protobuf.cc index 94ebfeb9f5..df8cb3f6b2 100644 --- a/pdns/dnsdist-protobuf.cc +++ b/pdns/dnsdist-protobuf.cc @@ -124,7 +124,26 @@ void DNSDistProtoBufMessage::serialize(std::string& data) const m.setTime(ts.tv_sec, ts.tv_nsec / 1000); } - m.setRequest(d_dq.uniqueId ? *d_dq.uniqueId : getUniqueID(), d_requestor ? *d_requestor : *d_dq.remote, d_responder ? *d_responder : *d_dq.local, d_question ? d_question->d_name : *d_dq.qname, d_question ? d_question->d_type : d_dq.qtype, d_question ? d_question->d_class : d_dq.qclass, d_dq.getHeader()->id, (d_dq.getProtocol() == dnsdist::Protocol::DoH) ? true : d_dq.overTCP(), d_bytes ? *d_bytes : d_dq.getData().size()); + const auto distProto = d_dq.getProtocol(); + pdns::ProtoZero::Message::TransportProtocol protocol = pdns::ProtoZero::Message::TransportProtocol::UDP; + + if (distProto == dnsdist::Protocol::DoTCP) { + protocol = pdns::ProtoZero::Message::TransportProtocol::TCP; + } + else if (distProto == dnsdist::Protocol::DoT) { + protocol = pdns::ProtoZero::Message::TransportProtocol::DoT; + } + else if (distProto == dnsdist::Protocol::DoH) { + protocol = pdns::ProtoZero::Message::TransportProtocol::DoH; + } + else if (distProto == dnsdist::Protocol::DNSCryptUDP) { + protocol = pdns::ProtoZero::Message::TransportProtocol::DNSCryptUDP; + } + else if (distProto == dnsdist::Protocol::DNSCryptTCP) { + protocol = pdns::ProtoZero::Message::TransportProtocol::DNSCryptTCP; + } + + m.setRequest(d_dq.uniqueId ? *d_dq.uniqueId : getUniqueID(), d_requestor ? *d_requestor : *d_dq.remote, d_responder ? *d_responder : *d_dq.local, d_question ? d_question->d_name : *d_dq.qname, d_question ? d_question->d_type : d_dq.qtype, d_question ? d_question->d_class : d_dq.qclass, d_dq.getHeader()->id, protocol, d_bytes ? *d_bytes : d_dq.getData().size()); if (d_serverIdentity) { m.setServerIdentity(*d_serverIdentity); diff --git a/pdns/dnspcap2protobuf.cc b/pdns/dnspcap2protobuf.cc index 60a3311aca..e5ff300d3d 100644 --- a/pdns/dnspcap2protobuf.cc +++ b/pdns/dnspcap2protobuf.cc @@ -126,7 +126,7 @@ try { pbBuffer.clear(); pdns::ProtoZero::Message pbMessage(pbBuffer); pbMessage.setType(dh->qr ? pdns::ProtoZero::Message::MessageType::DNSResponseType : pdns::ProtoZero::Message::MessageType::DNSQueryType); - pbMessage.setRequest(uniqueId, requestor, responder, qname, qtype, qclass, dh->id, false, pr.d_len); + pbMessage.setRequest(uniqueId, requestor, responder, qname, qtype, qclass, dh->id, pdns::ProtoZero::Message::TransportProtocol::UDP, pr.d_len); pbMessage.setTime(pr.d_pheader.ts.tv_sec, pr.d_pheader.ts.tv_usec); if (dh->qr) { diff --git a/pdns/dnstap.hh b/pdns/dnstap.hh index f4c7ee6ad9..798e86762e 100644 --- a/pdns/dnstap.hh +++ b/pdns/dnstap.hh @@ -34,7 +34,7 @@ class DnstapMessage { public: enum class MessageType : uint32_t { auth_query = 1, auth_response = 2, resolver_query = 3, resolver_response = 4, client_query = 5, client_response = 6, forwarder_query = 7, forwarded_response = 8, stub_query = 9, stub_response = 10, tool_query = 11, tool_response = 12 }; - enum class ProtocolType : uint32_t { DoUDP = 1, DoTCP = 2, DoT = 3, DoH = 4 }; + enum class ProtocolType : uint32_t { DoUDP = 1, DoTCP = 2, DoT = 3, DoH = 4, DNSCryptUDP = 5, DNSCryptTCP = 6 }; DnstapMessage(std::string& buffer, MessageType type, const std::string& identity, const ComboAddress* requestor, const ComboAddress* responder, ProtocolType protocol, const char* packet, const size_t len, const struct timespec* queryTime, const struct timespec* responseTime, boost::optional auth=boost::none); diff --git a/pdns/lwres.cc b/pdns/lwres.cc index 177632903c..82486bf783 100644 --- a/pdns/lwres.cc +++ b/pdns/lwres.cc @@ -121,7 +121,7 @@ static void logFstreamResponse(const std::shared_ptr>>& outgoingLoggers, boost::optional initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& ip, const DNSName& domain, int type, uint16_t qid, bool doTCP, size_t bytes, boost::optional& srcmask) +static void logOutgoingQuery(const std::shared_ptr>>& outgoingLoggers, boost::optional 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& srcmask) { if (!outgoingLoggers) { return; @@ -145,7 +145,16 @@ static void logOutgoingQuery(const std::shared_ptr>>& outgoingLoggers, boost::optional initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& ip, const DNSName& domain, int type, uint16_t qid, bool doTCP, boost::optional& srcmask, size_t bytes, int rcode, const std::vector& records, const struct timeval& queryTime, const std::set& exportTypes) +static void logIncomingResponse(const std::shared_ptr>>& outgoingLoggers, boost::optional initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& ip, const DNSName& domain, int type, uint16_t qid, bool doTCP, bool tls, boost::optional& srcmask, size_t bytes, int rcode, const std::vector& records, const struct timeval& queryTime, const std::set& exportTypes) { if (!outgoingLoggers) { return; @@ -193,7 +202,15 @@ static void logIncomingResponse(const std::shared_ptrd_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, vpacket.size(), srcmask); + 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; - bool dnsOverTLS = false; #ifdef HAVE_FSTRM bool fstrmQEnabled = false; bool fstrmREnabled = false; @@ -450,7 +467,7 @@ static LWResult::Result asyncresolve(const ComboAddress& ip, const DNSName& doma if (ret != LWResult::Result::Success) { // includes 'timeout' if (outgoingLoggers) { - logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, srcmask, 0, -1, {}, queryTime, exportTypes); + logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, dnsOverTLS, srcmask, 0, -1, {}, queryTime, exportTypes); } return ret; } @@ -477,7 +494,7 @@ static LWResult::Result asyncresolve(const ComboAddress& ip, const DNSName& doma 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, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes); + 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 @@ -521,7 +538,7 @@ static LWResult::Result asyncresolve(const ComboAddress& ip, const DNSName& doma } if(outgoingLoggers) { - logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes); + 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; @@ -537,7 +554,7 @@ static LWResult::Result asyncresolve(const ComboAddress& ip, const DNSName& doma g_stats.serverParseError++; if(outgoingLoggers) { - logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes); + 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 diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index 39ba53896e..17a56a8cb1 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -1030,7 +1030,7 @@ static void protobufLogQuery(LocalStateHolder& luaconfsLocal, co pdns::ProtoZero::RecMessage m{128, std::string::size_type(policyTags.empty() ? 0 : 64)}; // It's a guess m.setType(pdns::ProtoZero::Message::MessageType::DNSQueryType); - m.setRequest(uniqueId, requestor, local, qname, qtype, qclass, id, tcp, len); + m.setRequest(uniqueId, requestor, local, qname, qtype, qclass, id, tcp ? pdns::ProtoZero::Message::TransportProtocol::TCP : pdns::ProtoZero::Message::TransportProtocol::UDP, len); m.setServerIdentity(SyncRes::s_serverID); m.setEDNSSubnet(ednssubnet, ednssubnet.isIPv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6); m.setRequestorId(requestorId); @@ -1092,7 +1092,7 @@ static void protobufLogResponse(const struct dnsheader* dh, LocalStateHolderid); pbMessage.setTime(); @@ -2331,7 +2331,7 @@ static void startDoResolve(void *p) } pbMessage.setMessageIdentity(dc->d_uuid); pbMessage.setSocketFamily(dc->d_source.sin4.sin_family); - pbMessage.setSocketProtocol(dc->d_tcp); + pbMessage.setSocketProtocol(dc->d_tcp ? pdns::ProtoZero::Message::TransportProtocol::TCP : pdns::ProtoZero::Message::TransportProtocol::UDP); Netmask requestorNM(dc->d_source, dc->d_source.sin4.sin_family == AF_INET ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6); ComboAddress requestor = requestorNM.getMaskedNetwork(); pbMessage.setFrom(requestor); diff --git a/pdns/protozero.cc b/pdns/protozero.cc index 28985f393f..7d13a9cb84 100644 --- a/pdns/protozero.cc +++ b/pdns/protozero.cc @@ -56,11 +56,11 @@ void pdns::ProtoZero::Message::encodeDNSName(protozero::pbf_writer& pbf, std::st // leaving the block will cause the sub writer to compute how much was written based on the new size and update the size accordingly } -void pdns::ProtoZero::Message::setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t id, bool tcp, size_t len) +void pdns::ProtoZero::Message::setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t id, pdns::ProtoZero::Message::TransportProtocol proto, size_t len) { setMessageIdentity(uniqueId); setSocketFamily(requestor.sin4.sin_family); - setSocketProtocol(tcp); + setSocketProtocol(proto); setFrom(requestor); setTo(local); setInBytes(len); diff --git a/pdns/protozero.hh b/pdns/protozero.hh index c8536dc6d6..61d009ac95 100644 --- a/pdns/protozero.hh +++ b/pdns/protozero.hh @@ -41,6 +41,7 @@ namespace pdns { enum class QuestionField : protozero::pbf_tag_type { qName = 1, qType = 2, qClass = 3 }; enum class ResponseField : protozero::pbf_tag_type { rcode = 1, rrs = 2, appliedPolicy = 3, tags = 4, queryTimeSec = 5, queryTimeUsec = 6, appliedPolicyType = 7, appliedPolicyTrigger = 8, appliedPolicyHit = 9, appliedPolicyKind = 10, validationState = 11 }; enum class RRField : protozero::pbf_tag_type { name = 1, type = 2, class_ = 3, ttl = 4, rdata = 5, udr = 6 }; + enum class TransportProtocol : protozero::pbf_tag_type { UDP = 1, TCP = 2, DoT = 3, DoH = 4, DNSCryptUDP = 5, DNSCryptTCP = 6 }; Message(std::string& buffer): d_buffer(buffer), d_message{d_buffer} { @@ -51,7 +52,7 @@ namespace pdns { Message& operator=(const Message&) = delete; Message& operator=(Message&&) = delete; - void setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t id, bool tcp, size_t len); + void setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t id, TransportProtocol proto, size_t len); void setResponse(const DNSName& qname, uint16_t qtype, uint16_t qclass); void setType(MessageType mtype) @@ -74,9 +75,9 @@ namespace pdns { add_enum(d_message, Field::socketFamily, family == AF_INET ? 1 : 2); } - void setSocketProtocol(bool tcp) + void setSocketProtocol(TransportProtocol proto) { - add_enum(d_message, Field::socketProtocol, tcp ? 2 : 1); + add_enum(d_message, Field::socketProtocol, static_cast(proto)); } void setFrom(const ComboAddress& ca)