]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Support DoT, DoH and DNSCrypt transports for protobuf and dnstap
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 21 Oct 2021 15:12:47 +0000 (17:12 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 21 Oct 2021 15:20:35 +0000 (17:20 +0200)
contrib/ProtobufLogger.py
pdns/dnsdist-lua-actions.cc
pdns/dnsdist-protobuf.cc
pdns/dnspcap2protobuf.cc
pdns/dnstap.hh
pdns/lwres.cc
pdns/pdns_recursor.cc
pdns/protozero.cc
pdns/protozero.hh

index 36b361bfdae45aedf3771349e026222a81584d20..0370a20ca36fdb2b9de344efd58096cdc97cb720 100644 (file)
@@ -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) + ' '
index a96b70dcc444e26ff032b9bb788ebf7cf3a5b5b7..ba132daf83ece58978fba86b39af88a791faa3c6 100644 (file)
@@ -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());
 }
 
index 94ebfeb9f5babd74433a1ddf3af02de4399dcd38..df8cb3f6b20d5b6b91aaed3432c27f6d47f3173b 100644 (file)
@@ -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);
index 60a3311aca5c703125f20ffe2c6e1b10c6bbbe02..e5ff300d3d0f3374cca1c1f90eb53101be7cb250 100644 (file)
@@ -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) {
index f4c7ee6ad959ae6e161c8673eba75a4980fd1089..798e86762eb5c8d168ba2673347c636ae410d2b7 100644 (file)
@@ -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<const DNSName&> auth=boost::none);
 
index 177632903cd2abda0b77013780810404a892e15d..82486bf78351a7906ff467090ec23dc0b2f7af82 100644 (file)
@@ -121,7 +121,7 @@ static void logFstreamResponse(const std::shared_ptr<std::vector<std::unique_ptr
 
 #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, size_t bytes, boost::optional<Netmask>& srcmask)
+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;
@@ -145,7 +145,16 @@ static void logOutgoingQuery(const std::shared_ptr<std::vector<std::unique_ptr<R
   m.setType(pdns::ProtoZero::Message::MessageType::DNSOutgoingQueryType);
   m.setMessageIdentity(uuid);
   m.setSocketFamily(ip.sin4.sin_family);
-  m.setSocketProtocol(doTCP);
+  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();
@@ -169,7 +178,7 @@ static void logOutgoingQuery(const std::shared_ptr<std::vector<std::unique_ptr<R
   }
 }
 
-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, boost::optional<Netmask>& srcmask, size_t bytes, int rcode, const std::vector<DNSRecord>& records, const struct timeval& queryTime, const std::set<uint16_t>& exportTypes)
+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;
@@ -193,7 +202,15 @@ static void logIncomingResponse(const std::shared_ptr<std::vector<std::unique_pt
   m.setType(pdns::ProtoZero::Message::MessageType::DNSIncomingResponseType);
   m.setMessageIdentity(uuid);
   m.setSocketFamily(ip.sin4.sin_family);
-  m.setSocketProtocol(doTCP);
+  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();
@@ -361,17 +378,17 @@ static LWResult::Result asyncresolve(const ComboAddress& ip, const DNSName& doma
 
   boost::uuids::uuid uuid;
   const struct timeval queryTime = *now;
+  bool dnsOverTLS = SyncRes::s_dot_to_port_853 && ip.getPort() == 853;
 
   if (outgoingLoggers) {
     uuid = getUniqueID();
-    logOutgoingQuery(outgoingLoggers, context ? context->d_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
index 39ba53896eb8c1483a1ece0be65d952e20bfcd1d..17a56a8cb1f55934d101fa94cdafbb1fcacb8b66 100644 (file)
@@ -1030,7 +1030,7 @@ static void protobufLogQuery(LocalStateHolder<LuaConfigItems>& 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, LocalStateHolder<Lua
   pbMessage.setMessageIdentity(uniqueId);
   pbMessage.setFrom(requestor);
   pbMessage.setTo(destination);
-  pbMessage.setSocketProtocol(tcp);
+  pbMessage.setSocketProtocol(tcp ? pdns::ProtoZero::Message::TransportProtocol::TCP : pdns::ProtoZero::Message::TransportProtocol::UDP);
   pbMessage.setId(dh->id);
 
   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);
index 28985f393fc1dc66dd6331c249c5741828a3fc4f..7d13a9cb8411d898aade694a75b3dbdbc646fdff 100644 (file)
@@ -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);
index c8536dc6d6e9d91a11b8b1e6d34292448c1ffd06..61d009ac951bea5ee5d4671739a1bbd3b1389369 100644 (file)
@@ -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<int32_t>(proto));
       }
 
       void setFrom(const ComboAddress& ca)