]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
also copy metas to responses + unit tests
authorCharles-Henri Bruyand <charles-henri.bruyand@open-xchange.com>
Fri, 18 Jun 2021 09:30:54 +0000 (11:30 +0200)
committerCharles-Henri Bruyand <charles-henri.bruyand@open-xchange.com>
Wed, 30 Jun 2021 15:47:59 +0000 (17:47 +0200)
pdns/lua-recursor4.hh
pdns/pdns_recursor.cc
regression-tests.recursor-dnssec/test_Protobuf.py

index 1536b303b81793b81b44254f9a0cde39c788b821..a1ff21e89d860e5feae1e98ee220970ef6077cc6 100644 (file)
@@ -63,6 +63,11 @@ public:
   RecursorLua4();
   ~RecursorLua4(); // this is so unique_ptr works with an incomplete type
 
+  struct MetaValue
+  {
+    std::unordered_set<std::string> stringVal;
+    std::unordered_set<int64_t> intVal;
+  };
   struct DNSQuestion
   {
     DNSQuestion(const ComboAddress& rem, const ComboAddress& loc, const DNSName& query, uint16_t type, bool tcp, bool& variable_, bool& wantsRPZ_, bool& logResponse_, bool& addPaddingToResponse_) :
@@ -93,6 +98,7 @@ public:
     bool& logResponse;
     bool& addPaddingToResponse;
     unsigned int tag{0};
+    std::map<std::string, MetaValue> meta;
 
     void addAnswer(uint16_t type, const std::string& content, boost::optional<int> ttl, boost::optional<string> name);
     void addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional<int> ttl, boost::optional<string> name);
@@ -136,11 +142,6 @@ public:
     std::unordered_set<std::string>* policyTags{nullptr};
     std::unordered_map<std::string, bool>* discardedPolicies{nullptr};
   };
-  struct MetaValue
-  {
-    std::unordered_set<std::string> stringVal;
-    std::unordered_set<int64_t> intVal;
-  };
 
   struct FFIParams
   {
index 4c499f13737175450da5481da7b24af37f2143c4..542a9754f3db5b9bd9ab6956b3fe8a38bd3e1ac3 100644 (file)
@@ -1750,6 +1750,7 @@ static void startDoResolve(void *p)
     dq.proxyProtocolValues = &dc->d_proxyProtocolValues;
     dq.extendedErrorCode = &dc->d_extendedErrorCode;
     dq.extendedErrorExtra = &dc->d_extendedErrorExtra;
+    dq.meta = dc->d_meta;
 
     if(ednsExtRCode != 0) {
       goto sendit;
@@ -1894,6 +1895,7 @@ static void startDoResolve(void *p)
       dq.validationState = sr.getValidationState();
       appliedPolicy = sr.d_appliedPolicy;
       dc->d_policyTags = std::move(sr.d_policyTags);
+
       if (appliedPolicy.d_type != DNSFilterEngine::PolicyType::None && appliedPolicy.d_zoneData && appliedPolicy.d_zoneData->d_extendedErrorCode) {
         dc->d_extendedErrorCode = *appliedPolicy.d_zoneData->d_extendedErrorCode;
         dc->d_extendedErrorExtra = appliedPolicy.d_zoneData->d_extendedErrorExtra;
@@ -2251,6 +2253,10 @@ static void startDoResolve(void *p)
       pbMessage.setDeviceName(dq.deviceName);
       pbMessage.setFromPort(dc->d_source.getPort());
       pbMessage.setToPort(dc->d_destination.getPort());
+
+      for (const auto& m : dq.meta) {
+        pbMessage.setMeta(m.first, m.second.stringVal, m.second.intVal);
+      }
 #ifdef NOD_ENABLED
       if (g_nodEnabled) {
         if (nod) {
@@ -2535,6 +2541,7 @@ static bool checkForCacheHit(bool qnameParsed, unsigned int tag, const string& d
     g_stats.ourtime(0);
 #endif
   }
+
   return cacheHit;
 }
 
@@ -3148,6 +3155,7 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
   dc->d_extendedErrorCode = extendedErrorCode;
   dc->d_extendedErrorExtra = std::move(extendedErrorExtra);
   dc->d_responsePaddingDisabled = responsePaddingDisabled;
+  dc->d_meta = std::move(meta);
 
   MT->makeThread(startDoResolve, (void*) dc.release()); // deletes dc
   return 0;
index c0dec8fe09127ccc04bb69666104ca8430731bc4..9a6e54fd662c1c5e231ae1b5e4db8c28dfa40ee3 100644 (file)
@@ -228,6 +228,20 @@ class TestRecursorProtobuf(RecursorTest):
         for tag in msg.response.tags:
             self.assertTrue(tag in tags)
 
+    def checkProtobufMetas(self, msg, metas):
+        print(metas)
+        print('---')
+        print(msg.meta)
+        self.assertEqual(len(msg.meta), len(metas))
+        for m in msg.meta:
+            self.assertTrue(m.HasField('key'))
+            self.assertTrue(m.HasField('value'))
+            self.assertTrue(m.key in metas)
+            for i in m.value.intVal :
+              self.assertTrue(i in metas[m.key]['intVal'])
+            for s in m.value.stringVal :
+              self.assertTrue(s in metas[m.key]['stringVal'])
+
     def checkProtobufOutgoingQuery(self, msg, protocol, query, qclass, qtype, qname, initiator='127.0.0.1', length=None):
         self.assertEqual(msg.type, dnsmessage_pb2.PBDNSMessage.DNSOutgoingQueryType)
         self.checkOutgoingProtobufBase(msg, protocol, query, initiator, length=length)
@@ -279,6 +293,7 @@ class TestRecursorProtobuf(RecursorTest):
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 tagged 3600 IN A 192.0.2.84
+meta 3600 IN A 192.0.2.85
 query-selected 3600 IN A 192.0.2.84
 answer-selected 3600 IN A 192.0.2.84
 types 3600 IN A 192.0.2.84
@@ -991,3 +1006,61 @@ sub.test 3600 IN A 192.0.2.42
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
         self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.42')
         self.checkNoRemainingMessage()
+
+
+class ProtobufMetaFFITest(TestRecursorProtobuf):
+    """
+    This test makes sure that we can correctly add extra meta fields (FFI version).
+    """
+    _confdir = 'ProtobufMetaFFITest'
+    _config_template = """
+auth-zones=example=configs/%s/example.zone""" % _confdir
+    _lua_config_file = """
+    protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=true, logResponses=true } )
+    """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
+    _lua_dns_script_file = """
+    local ffi = require("ffi")
+
+    ffi.cdef[[
+      typedef struct pdns_ffi_param pdns_ffi_param_t;
+
+      const char* pdns_ffi_param_get_qname(pdns_ffi_param_t* ref);
+      void pdns_ffi_param_add_meta_single_string_kv(pdns_ffi_param_t *ref, const char* key, const char* val);
+      void pdns_ffi_param_add_meta_single_int64_kv(pdns_ffi_param_t *ref, const char* key, int64_t val);
+    ]]
+
+    function gettag_ffi(obj)
+      qname = ffi.string(ffi.C.pdns_ffi_param_get_qname(obj))
+      if qname == 'meta.example' then
+        ffi.C.pdns_ffi_param_add_meta_single_string_kv(obj, "meta-str", "keyword")
+        ffi.C.pdns_ffi_param_add_meta_single_int64_kv(obj, "meta-int", 42)
+        ffi.C.pdns_ffi_param_add_meta_single_string_kv(obj, "meta-str", "content")
+        ffi.C.pdns_ffi_param_add_meta_single_int64_kv(obj, "meta-int", 21)
+      end
+      return 0
+    end
+    """
+    def testMeta(self):
+        name = 'meta.example.'
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.85')
+        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        query.flags |= dns.flags.CD
+        res = self.sendUDPQuery(query)
+        self.assertRRsetInAnswer(res, expected)
+
+        # check the protobuf messages corresponding to the UDP query and answer
+        msg = self.getFirstProtobufMessage()
+        self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
+        self.checkProtobufMetas(msg, {'meta-str': { "stringVal" : ["content", "keyword"]}, 'meta-int': {"intVal" : [21, 42]}})
+
+        # then the response
+        msg = self.getFirstProtobufMessage()
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res)
+        self.assertEqual(len(msg.response.rrs), 1)
+        rr = msg.response.rrs[0]
+        # we have max-cache-ttl set to 15
+        self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.85')
+        self.checkProtobufMetas(msg, {'meta-str': { "stringVal" : ["content", "keyword"]}, 'meta-int': {"intVal" : [21, 42]}})
+
+        self.checkNoRemainingMessage()