]> granicus.if.org Git - pdns/commitdiff
rec: Export a protobuf incoming response message for timeouts
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 28 Jun 2019 14:47:25 +0000 (16:47 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 28 Jun 2019 14:47:25 +0000 (16:47 +0200)
pdns/dnsmessage.proto
pdns/lwres.cc
pdns/protobuf.cc
pdns/protobuf.hh
regression-tests.recursor-dnssec/test_Protobuf.py

index a460b51f3cd09ca2f404252dcdad0f0a7ccf06e2..8a0fe0082869f3ee8cf452b9bc167bf0b9faa871 100644 (file)
@@ -72,7 +72,7 @@ message PBDNSMessage {
       optional bytes rdata = 5;
       optional bool  udr = 6;                   // True if this is the first time this RR has been seen for this question
     }
-    optional uint32 rcode = 1;
+    optional uint32 rcode = 1;                  // DNS Response code, or 65536 for a network error including a timeout
     repeated DNSRR rrs = 2;
     optional string appliedPolicy = 3;          // Filtering policy (RPZ or Lua) applied
     repeated string tags = 4;                   // Additional tags
index a1fb7400aab623dd3613df25c79afe6b4c22b312..87745d15fe95e7126652796377fb93ec2a2aa83c 100644 (file)
@@ -197,7 +197,12 @@ static void logIncomingResponse(const std::shared_ptr<std::vector<std::unique_pt
   }
 
   message->setQueryTime(queryTime.tv_sec, queryTime.tv_usec);
-  message->setResponseCode(rcode);
+  if (rcode == -1) {
+    message->setNetworkErrorResponseCode();
+  }
+  else {
+    message->setResponseCode(rcode);
+  }
   message->addRRs(records, exportTypes);
 
 //  cerr <<message.toDebugString()<<endl;
@@ -351,8 +356,14 @@ int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool d
   lwr->d_usec=dt.udiff();
   *now=dt.getTimeval();
 
-  if(ret <= 0) // includes 'timeout'
+  if(ret <= 0) { // includes 'timeout'
+#ifdef HAVE_PROTOBUF
+      if (outgoingLoggers) {
+        logIncomingResponse(outgoingLoggers, pbMessage, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, srcmask, 0, -1, {}, queryTime, exportTypes);
+      }
+#endif
     return ret;
+  }
 
   buf.resize(len);
 
index fd491ac669f629cb407f3bd3d73c71aac75b0510..7e51225c816de690de674fd5c56cc8c1e2f12479 100644 (file)
@@ -62,6 +62,17 @@ void DNSProtoBufMessage::setResponseCode(uint8_t rcode)
 #endif /* HAVE_PROTOBUF */
 }
 
+void DNSProtoBufMessage::setNetworkErrorResponseCode()
+{
+#ifdef HAVE_PROTOBUF
+  PBDNSMessage_DNSResponse* response = d_message.mutable_response();
+  if (response) {
+    /* special code meaning 'network error', like a timeout */
+    response->set_rcode(65536);
+  }
+#endif /* HAVE_PROTOBUF */
+}
+
 void DNSProtoBufMessage::setTime(time_t sec, uint32_t usec)
 {
 #ifdef HAVE_PROTOBUF
index f87dd5f08cc6a57b10f128a7946573363b40c4a1..c3277cc83a7f91531f3143257c4c80fdb297b23e 100644 (file)
@@ -62,6 +62,7 @@ public:
   void updateTime();
   void setQueryTime(time_t sec, uint32_t usec);
   void setResponseCode(uint8_t rcode);
+  void setNetworkErrorResponseCode();
   void addRRsFromPacket(const char* packet, const size_t len, bool includeCNAME=false);
   void serialize(std::string& data) const;
   void setRequestor(const std::string& requestor);
index 7d9f36ee2479afe0390828220a4006e19b22be62..14497a53c5458ac4ecb0b9742ac1e502a57de535 100644 (file)
@@ -143,7 +143,7 @@ class TestRecursorProtobuf(RecursorTest):
             self.assertEquals(len(msg.originalRequestorSubnet), 4)
             self.assertEquals(socket.inet_ntop(socket.AF_INET, msg.originalRequestorSubnet), '127.0.0.1')
 
-    def checkOutgoingProtobufBase(self, msg, protocol, query, initiator):
+    def checkOutgoingProtobufBase(self, msg, protocol, query, initiator, length=None):
         self.assertTrue(msg)
         self.assertTrue(msg.HasField('timeSec'))
         self.assertTrue(msg.HasField('socketFamily'))
@@ -155,8 +155,11 @@ class TestRecursorProtobuf(RecursorTest):
         self.assertTrue(msg.HasField('id'))
         self.assertNotEquals(msg.id, query.id)
         self.assertTrue(msg.HasField('inBytes'))
-        # compare inBytes with length of query/response
-        self.assertEquals(msg.inBytes, len(query.to_wire()))
+        if length is not None:
+          self.assertEquals(msg.inBytes, length)
+        else:
+          # compare inBytes with length of query/response
+          self.assertEquals(msg.inBytes, len(query.to_wire()))
 
     def checkProtobufQuery(self, msg, protocol, query, qclass, qtype, qname, initiator='127.0.0.1'):
         self.assertEquals(msg.type, dnsmessage_pb2.PBDNSMessage.DNSQueryType)
@@ -203,9 +206,9 @@ class TestRecursorProtobuf(RecursorTest):
         for tag in msg.response.tags:
             self.assertTrue(tag in tags)
 
-    def checkProtobufOutgoingQuery(self, msg, protocol, query, qclass, qtype, qname, initiator='127.0.0.1'):
+    def checkProtobufOutgoingQuery(self, msg, protocol, query, qclass, qtype, qname, initiator='127.0.0.1', length=None):
         self.assertEquals(msg.type, dnsmessage_pb2.PBDNSMessage.DNSOutgoingQueryType)
-        self.checkOutgoingProtobufBase(msg, protocol, query, initiator)
+        self.checkOutgoingProtobufBase(msg, protocol, query, initiator, length=length)
         self.assertTrue(msg.HasField('to'))
         self.assertTrue(msg.HasField('question'))
         self.assertTrue(msg.question.HasField('qClass'))
@@ -215,12 +218,17 @@ class TestRecursorProtobuf(RecursorTest):
         self.assertTrue(msg.question.HasField('qName'))
         self.assertEquals(msg.question.qName, qname)
 
-    def checkProtobufIncomingResponse(self, msg, protocol, response, initiator='127.0.0.1'):
+    def checkProtobufIncomingResponse(self, msg, protocol, response, initiator='127.0.0.1', length=None):
         self.assertEquals(msg.type, dnsmessage_pb2.PBDNSMessage.DNSIncomingResponseType)
-        self.checkOutgoingProtobufBase(msg, protocol, response, initiator)
+        self.checkOutgoingProtobufBase(msg, protocol, response, initiator, length=length)
         self.assertTrue(msg.HasField('response'))
+        self.assertTrue(msg.response.HasField('rcode'))
         self.assertTrue(msg.response.HasField('queryTimeSec'))
 
+    def checkProtobufIncomingNetworkErrorResponse(self, msg, protocol, response, initiator='127.0.0.1'):
+        self.checkProtobufIncomingResponse(msg, protocol, response, initiator, length=0)
+        self.assertEquals(msg.response.rcode, 65536)
+
     @classmethod
     def setUpClass(cls):
 
@@ -350,9 +358,9 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         # check the protobuf messages corresponding to the UDP query and answer
         msg = self.getFirstProtobufMessage()
         self.checkProtobufOutgoingQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
-#        # then the response
-#        msg = self.getFirstProtobufMessage()
-#        self.checkProtobufIncomingResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res)
+        # then the response
+        msg = self.getFirstProtobufMessage()
+        self.checkProtobufIncomingNetworkErrorResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res)
         self.checkNoRemainingMessage()
 
 class OutgoingProtobufNoQueriesTest(TestRecursorProtobuf):
@@ -376,11 +384,9 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         query.flags |= dns.flags.RD
         res = self.sendUDPQuery(query)
 
-#        # check the response
-#        msg = self.getFirstProtobufMessage()
-#        self.checkProtobufIncomingResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res)
-        # let's wait a bit for a potential message to arrive
-        time.sleep(2)
+        # check the response
+        msg = self.getFirstProtobufMessage()
+        self.checkProtobufIncomingNetworkErrorResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res)
         self.checkNoRemainingMessage()
 
 class ProtobufMasksTest(TestRecursorProtobuf):