]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: add DNSAction::Action::SpoofPacket so that spoofing can be done within a... 11051/head
authorCharles-Henri Bruyand <charles-henri.bruyand@open-xchange.com>
Fri, 3 Dec 2021 11:13:38 +0000 (12:13 +0100)
committerCharles-Henri Bruyand <charles-henri.bruyand@open-xchange.com>
Fri, 3 Dec 2021 11:15:43 +0000 (12:15 +0100)
- fix small (and bigger) nits reported by rgacogne, thanks.
- update regression tests with better boundaries on queries beeing spoofed

pdns/dnsdist-lua-actions.cc
pdns/dnsdist-lua-vars.cc
pdns/dnsdist.cc
pdns/dnsdist.hh
pdns/dnsdistdist/docs/reference/constants.rst
pdns/dnsdistdist/docs/rules-actions.rst
regression-tests.dnsdist/test_Spoofing.py

index efaca54fddb3ad3a9c11c0a05013ecce12ea7d5f..fe2f2efebb3fce788d66ba99a9e3f2eaef464de6 100644 (file)
@@ -784,7 +784,7 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresu
 
   if (d_raw.size() >= sizeof(dnsheader)) {
     auto id = dq->getHeader()->id;
-    dq->getMutableData() = std::move(d_raw);
+    dq->getMutableData() = d_raw;
     dq->getHeader()->id = id;
     return Action::HeaderModify;
   }
index 82c4a8e4820ab55ff835bbd109f83069a3efc6ab..ed5cf1e5d737b2788e7ed2319cf96e1b0e08d9dc 100644 (file)
@@ -32,6 +32,7 @@ void setupLuaVars(LuaContext& luaCtx)
       {"Nxdomain", (int)DNSAction::Action::Nxdomain},
       {"Refused", (int)DNSAction::Action::Refused},
       {"Spoof", (int)DNSAction::Action::Spoof},
+      {"SpoofPacket", (int)DNSAction::Action::SpoofPacket},
       {"SpoofRaw", (int)DNSAction::Action::SpoofRaw},
       {"Allow", (int)DNSAction::Action::Allow},
       {"HeaderModify", (int)DNSAction::Action::HeaderModify},
index 4a18e7e7ad0b1129e0a48c0e1e6b6c106632b844..33f7835170ff8edfd05fb7eff8004dd75c228cb0 100644 (file)
@@ -768,6 +768,14 @@ static void spoofResponseFromString(DNSQuestion& dq, const string& spoofContent,
   }
 }
 
+static void spoofPacketFromString(DNSQuestion& dq, const string& spoofContent)
+{
+  string result;
+
+  SpoofAction sa(spoofContent.c_str(), spoofContent.size());
+  sa(&dq, &result);
+}
+
 bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dq, std::string& ruleresult, bool& drop)
 {
   switch(action) {
@@ -801,6 +809,10 @@ bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dq, std::s
     spoofResponseFromString(dq, ruleresult, false);
     return true;
     break;
+  case DNSAction::Action::SpoofPacket:
+    spoofPacketFromString(dq, ruleresult);
+    return true;
+    break;
   case DNSAction::Action::SpoofRaw:
     spoofResponseFromString(dq, ruleresult, true);
     return true;
index 6ee0b3382861f43e02a6a04eca3489f7bfdb4d7e..865f6dec26c905307ed77262beadae963bbe6e3d 100644 (file)
@@ -204,7 +204,7 @@ struct DNSResponse : DNSQuestion
 class DNSAction
 {
 public:
-  enum class Action : uint8_t { Drop, Nxdomain, Refused, Spoof, Allow, HeaderModify, Pool, Delay, Truncate, ServFail, None, NoOp, NoRecurse, SpoofRaw };
+  enum class Action : uint8_t { Drop, Nxdomain, Refused, Spoof, Allow, HeaderModify, Pool, Delay, Truncate, ServFail, None, NoOp, NoRecurse, SpoofRaw, SpoofPacket };
   static std::string typeToString(const Action& action)
   {
     switch(action) {
@@ -216,6 +216,8 @@ public:
       return "Send Refused";
     case Action::Spoof:
       return "Spoof an answer";
+    case Action::SpoofPacket:
+      return "Spoof a raw answer from bytes";
     case Action::SpoofRaw:
       return "Spoof an answer from raw bytes";
     case Action::Allow:
index d81c2d44f7f970670a0a438ca40a6b53d24a9848..c391741b2668d0b9ed26b31661cd437ee774c285 100755 (executable)
@@ -108,6 +108,9 @@ DNSAction
 .. versionchanged:: 1.5.0
   ``DNSAction.SpoofRaw`` has been added.
 
+.. versionchanged:: 1.8.0
+  ``DNSAction.SpoofPacket`` has been added.
+
 These constants represent an Action that can be returned from :func:`LuaAction` functions.
 
  * ``DNSAction.Allow``: let the query pass, skipping other rules
@@ -121,6 +124,7 @@ These constants represent an Action that can be returned from :func:`LuaAction`
  * ``DNSAction.Refused``: return a response with a Refused rcode
  * ``DNSAction.ServFail``: return a response with a ServFail rcode
  * ``DNSAction.Spoof``: spoof the response using the supplied IPv4 (A), IPv6 (AAAA) or string (CNAME) value. TTL will be 60 seconds.
+ * ``DNSAction.SpoofPacket``: spoof the response using the supplied raw packet
  * ``DNSAction.SpoofRaw``: spoof the response using the supplied raw value as record data (see also :meth:`DNSQuestion:spoof` and :func:`dnsdist_ffi_dnsquestion_spoof_raw` to spoof multiple values)
  * ``DNSAction.Truncate``: truncate the response
  * ``DNSAction.NoRecurse``: set rd=0 on the query
index 07374e36131916d79d12e1c31ad14d6292038d2b..16dcdd188b1d80a806dea2d802ee63a64d0e7b08 100644 (file)
@@ -1561,7 +1561,7 @@ The following actions exist.
   Spoof a raw self-generated answer
 
   :param string rawPacket: The raw wire-ready DNS answer
-  :param int len: The len of the packet
+  :param int len: The length of the packet
 
 .. function:: TagAction(name, value)
 
index 5ae66249b7efe5d15b0e7c9a93960c8d2c67de87..ab46b536fda247013a56ac24b646f969b84cb8b8 100644 (file)
@@ -917,46 +917,59 @@ class TestSpoofingLuaWithStatistics(DNSDistTest):
 class TestSpoofingLuaSpoofPacket(DNSDistTest):
 
     _config_template = """
-    local ffi = require("ffi")
 
     function spoofpacket(dq)
-        -- REFUSED answer
-        local rawResponse="\\000\\000\\129\\133\\000\\001\\000\\000\\000\\000\\000\\000\\014lua\\045raw\\045packet\\012ffi\\045spoofing\\005tests\\008powerdns\\003com\\000\\000\\001\\000\\001"
+        if dq.qtype == DNSQType.A then
+             return DNSAction.SpoofPacket, "\\000\\000\\129\\133\\000\\001\\000\\000\\000\\000\\000\\000\\014lua\\045raw\\045packet\\008spoofing\\005tests\\008powerdns\\003com\\000\\000\\001\\000\\001"
+        end
+        return DNSAction.None, ""
+    end
+
+    addAction("lua-raw-packet.spoofing.tests.powerdns.com.", LuaAction(spoofpacket))
+    local rawResponse="\\000\\000\\129\\133\\000\\001\\000\\000\\000\\000\\000\\000\\019rule\\045lua\\045raw\\045packet\\008spoofing\\005tests\\008powerdns\\003com\\000\\000\\001\\000\\001"
+    addAction(AndRule{QTypeRule(DNSQType.A), makeRule("rule-lua-raw-packet.spoofing.tests.powerdns.com.")}, SpoofPacketAction(rawResponse, string.len(rawResponse)))
+
+    local ffi = require("ffi")
+
+    function spoofpacketffi(dq)
         local qtype = ffi.C.dnsdist_ffi_dnsquestion_get_qtype(dq)
-        ffi.C.dnsdist_ffi_dnsquestion_spoof_packet(dq, rawResponse, string.len(rawResponse))
-        return DNSAction.HeaderModify
+        if qtype == DNSQType.A then
+            -- REFUSED answer
+            local refusedResponse="\\000\\000\\129\\133\\000\\001\\000\\000\\000\\000\\000\\000\\014lua\\045raw\\045packet\\012ffi\\045spoofing\\005tests\\008powerdns\\003com\\000\\000\\001\\000\\001"
+
+            ffi.C.dnsdist_ffi_dnsquestion_spoof_packet(dq, refusedResponse, string.len(refusedResponse))
+            return DNSAction.HeaderModify
+        end
+        return DNSAction.None, ""
     end
 
-    addAction("lua-raw-packet.ffi-spoofing.tests.powerdns.com.", LuaFFIAction(spoofpacket))
-    local otherResponse="\\000\\000\\129\\133\\000\\001\\000\\000\\000\\000\\000\\000\\014lua\\045raw\\045packet\\008spoofing\\005tests\\008powerdns\\003com\\000\\000\\001\\000\\001"
-    addAction("lua-raw-packet.spoofing.tests.powerdns.com.", SpoofPacketAction(otherResponse, string.len(otherResponse)))
+    addAction("lua-raw-packet.ffi-spoofing.tests.powerdns.com.", LuaFFIAction(spoofpacketffi))
     newServer{address="127.0.0.1:%s"}
     """
     _verboseMode = True
 
-    def testLuaFFISpoofPacket(self):
+    def testLuaSpoofPacket(self):
         """
         Spoofing via Lua FFI: Spoof raw response via Lua FFI
         """
-        name = 'lua-raw-packet.ffi-spoofing.tests.powerdns.com.'
+        for name in ('lua-raw-packet.spoofing.tests.powerdns.com.', 'rule-lua-raw-packet.spoofing.tests.powerdns.com.'):
 
-        #
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedResponse = dns.message.make_response(query)
-        expectedResponse.flags |= dns.flags.RA
-        expectedResponse.set_rcode(dns.rcode.REFUSED)
+            query = dns.message.make_query(name, 'A', 'IN')
+            expectedResponse = dns.message.make_response(query)
+            expectedResponse.flags |= dns.flags.RA
+            expectedResponse.set_rcode(dns.rcode.REFUSED)
 
-        for method in ("sendUDPQuery", "sendTCPQuery"):
-            sender = getattr(self, method)
-            (_, receivedResponse) = sender(query, response=None, useQueue=False)
-            self.assertTrue(receivedResponse)
-            self.assertEqual(expectedResponse, receivedResponse)
+            for method in ("sendUDPQuery", "sendTCPQuery"):
+                sender = getattr(self, method)
+                (_, receivedResponse) = sender(query, response=None, useQueue=False)
+                self.assertTrue(receivedResponse)
+                self.assertEqual(expectedResponse, receivedResponse)
 
-    def testLuaSpoofPacket(self):
+    def testLuaFFISpoofPacket(self):
         """
-        Spoofing via Lua : Spoof raw response via Lua
+        Spoofing via Lua FFI: Spoof raw response via Lua FFI
         """
-        name = 'lua-raw-packet.spoofing.tests.powerdns.com.'
+        name = 'lua-raw-packet.ffi-spoofing.tests.powerdns.com.'
 
         #
         query = dns.message.make_query(name, 'A', 'IN')