]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: Backport 14346 to rec-4.9.x: fix TCP case for cached policy tags 14352/head
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Tue, 18 Jun 2024 09:50:55 +0000 (11:50 +0200)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Tue, 18 Jun 2024 09:50:55 +0000 (11:50 +0200)
Cherry picked from
6a3943374904b39769d8c6fcb3923b6456814d19 and 9bddb82fd4166c83b055f037f775f33471403704

Backport of #14351

pdns/recursordist/rec-main.hh
pdns/recursordist/rec-tcp.cc
regression-tests.recursor-dnssec/test_Protobuf.py

index 5031fe8045188024b9b58b333ba5d0c1e7a33c3e..a809bd70a92f5ba2a6941e90aeacba5dd0c38567 100644 (file)
@@ -125,7 +125,7 @@ struct DNSComboWriter
   };
   std::string d_query;
   std::unordered_set<std::string> d_policyTags;
-  const std::unordered_set<std::string> d_gettagPolicyTags;
+  std::unordered_set<std::string> d_gettagPolicyTags;
   std::string d_routingTag;
   std::vector<DNSRecord> d_records;
 
index aa2c2426953e1e0aa6cb2be5abbd3f6d6ffd6b7e..5efdbb18aa037ec40bfc08c2166c0483b91d3fe2 100644 (file)
@@ -415,16 +415,23 @@ static void handleRunningTCPQuestion(int fileDesc, FDMultiplexer::funcparam_t& v
           if (t_pdl) {
             try {
               if (t_pdl->d_gettag_ffi) {
-                RecursorLua4::FFIParams params(qname, qtype, comboWriter->d_destination, comboWriter->d_source, comboWriter->d_ednssubnet.source, comboWriter->d_data, comboWriter->d_policyTags, comboWriter->d_records, ednsOptions, comboWriter->d_proxyProtocolValues, requestorId, deviceId, deviceName, comboWriter->d_routingTag, comboWriter->d_rcode, comboWriter->d_ttlCap, comboWriter->d_variable, true, logQuery, comboWriter->d_logResponse, comboWriter->d_followCNAMERecords, comboWriter->d_extendedErrorCode, comboWriter->d_extendedErrorExtra, comboWriter->d_responsePaddingDisabled, comboWriter->d_meta);
+                RecursorLua4::FFIParams params(qname, qtype, comboWriter->d_destination, comboWriter->d_source, comboWriter->d_ednssubnet.source, comboWriter->d_data, comboWriter->d_gettagPolicyTags, comboWriter->d_records, ednsOptions, comboWriter->d_proxyProtocolValues, requestorId, deviceId, deviceName, comboWriter->d_routingTag, comboWriter->d_rcode, comboWriter->d_ttlCap, comboWriter->d_variable, true, logQuery, comboWriter->d_logResponse, comboWriter->d_followCNAMERecords, comboWriter->d_extendedErrorCode, comboWriter->d_extendedErrorExtra, comboWriter->d_responsePaddingDisabled, comboWriter->d_meta);
                 comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTagFFI);
                 comboWriter->d_tag = t_pdl->gettag_ffi(params);
                 comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTagFFI, comboWriter->d_tag, false);
               }
               else if (t_pdl->d_gettag) {
                 comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTag);
-                comboWriter->d_tag = t_pdl->gettag(comboWriter->d_source, comboWriter->d_ednssubnet.source, comboWriter->d_destination, qname, qtype, &comboWriter->d_policyTags, comboWriter->d_data, ednsOptions, true, requestorId, deviceId, deviceName, comboWriter->d_routingTag, comboWriter->d_proxyProtocolValues);
+                comboWriter->d_tag = t_pdl->gettag(comboWriter->d_source, comboWriter->d_ednssubnet.source, comboWriter->d_destination, qname, qtype, &comboWriter->d_gettagPolicyTags, comboWriter->d_data, ednsOptions, true, requestorId, deviceId, deviceName, comboWriter->d_routingTag, comboWriter->d_proxyProtocolValues);
                 comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTag, comboWriter->d_tag, false);
               }
+              // Copy d_gettagPolicyTags to d_policyTags, so other Lua hooks see them and can add their
+              // own. Before storing into the packetcache, the tags in d_gettagPolicyTags will be
+              // cleared by addPolicyTagsToPBMessageIfNeeded() so they do *not* end up in the PC. When an
+              // Protobuf message is constructed, one part comes from the PC (including the tags
+              // set by non-gettag hooks), and the tags in d_gettagPolicyTags will be added by the code
+              // constructing the PB message.
+              comboWriter->d_policyTags = comboWriter->d_gettagPolicyTags;
             }
             catch (const std::exception& e) {
               if (g_logCommonErrors) {
index 347c918832a30ba0e6510fb0b9c57aa9c1c14c61..0f4e5fed092575d40be344f0c226e53eb7b32b09 100644 (file)
@@ -302,6 +302,7 @@ class TestRecursorProtobuf(RecursorTest):
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 tagged 3600 IN A 192.0.2.84
+taggedtcp 3600 IN A 192.0.2.87
 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
@@ -981,25 +982,8 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         self.checkProtobufTags(msg, tags)
         self.checkNoRemainingMessage()
 
-class ProtobufTagCacheTest(TestRecursorProtobuf):
-    """
-    This test makes sure that we correctly cache tags (actually not cache them)
-    """
-
-    _confdir = 'ProtobufTagCache'
-    _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=false, logResponses=true } )
-    """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
-    _lua_dns_script_file = """
-    function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp)
-      if qname:equal('tagged.example.') then
-        return 0, { '' .. math.random() }
-      end
-      return 0
-    end
-    """
+class ProtobufTagCacheBase(TestRecursorProtobuf):
+    __test__ = False
 
     def testTagged(self):
         name = 'tagged.example.'
@@ -1036,6 +1020,95 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         ts2 = msg.response.tags[0]
         self.assertNotEqual(ts1, ts2)
 
+    def testTaggedTCP(self):
+        name = 'taggedtcp.example.'
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.87')
+        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        query.flags |= dns.flags.CD
+        res = self.sendTCPQuery(query)
+        self.assertRRsetInAnswer(res, expected)
+
+        msg = self.getFirstProtobufMessage()
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, 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.87')
+        self.checkNoRemainingMessage()
+        print(msg.response)
+        self.assertEqual(len(msg.response.tags), 1)
+        ts1 = msg.response.tags[0]
+
+        # Again to check PC case
+        res = self.sendTCPQuery(query)
+        self.assertRRsetInAnswer(res, expected)
+
+        msg = self.getFirstProtobufMessage()
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, res)
+        print(msg.response)
+        self.assertEqual(len(msg.response.rrs), 1)
+        rr = msg.response.rrs[0]
+        # time may have passed, so do not check TTL
+        self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15, checkTTL=False)
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.87')
+        self.checkNoRemainingMessage()
+        self.assertEqual(len(msg.response.tags), 1)
+        ts2 = msg.response.tags[0]
+        self.assertNotEqual(ts1, ts2)
+
+class ProtobufTagCacheTest(ProtobufTagCacheBase):
+    """
+    This test makes sure that we correctly cache tags (actually not cache them)
+    """
+
+    __test__ = True
+    _confdir = 'ProtobufTagCache'
+    _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=false, logResponses=true } )
+    """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
+    _lua_dns_script_file = """
+    function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp)
+      if qname:equal('tagged.example.') or qname:equal('taggedtcp.example.') then
+        return 0, { '' .. math.random() }
+      end
+      return 0
+    end
+    """
+
+class ProtobufTagCacheFFITest(ProtobufTagCacheBase):
+    """
+    This test makes sure that we correctly cache tags (actually not cache them) for the FFI case
+    """
+
+    __test__ = True
+    _confdir = 'ProtobufTagCacheFFI'
+    _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=false, 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_policytag(pdns_ffi_param_t* ref, const char* name);
+    ]]
+
+    function gettag_ffi(obj)
+      qname = ffi.string(ffi.C.pdns_ffi_param_get_qname(obj))
+      if qname == 'tagged.example' or qname == 'taggedtcp.example' then
+        ffi.C.pdns_ffi_param_add_policytag(obj, '' .. math.random())
+      end
+      return 0
+    end
+    """
+
 class ProtobufSelectedFromLuaTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export queries and responses but only if they have been selected from Lua.