]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add Lua bindings for the current time and query time 12402/head
authorRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 9 Jan 2023 14:14:28 +0000 (15:14 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 10 Jan 2023 16:17:39 +0000 (17:17 +0100)
pdns/dnsdist-console.cc
pdns/dnsdist-idstate.hh
pdns/dnsdist-lua-bindings-dnsquestion.cc
pdns/dnsdist-lua-bindings.cc
pdns/dnsdistdist/docs/reference/config.rst
pdns/dnsdistdist/docs/reference/dq.rst
regression-tests.dnsdist/test_Advanced.py

index 472195d010a6210bf045f6fa595b9c0f798ea603..9cbdbeb1f06ac412a99330cbea8dcddb3e140e88 100644 (file)
@@ -517,6 +517,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
   { "getAction", true, "n", "Returns the Action associated with rule n" },
   { "getBind", true, "n", "returns the listener at index n" },
   { "getBindCount", true, "", "returns the number of listeners all kinds" },
+  { "getCurrentTime", true, "", "returns the current time" },
   { "getDNSCryptBind", true, "n", "return the `DNSCryptContext` object corresponding to the bind `n`" },
   { "getDNSCryptBindCount", true, "", "returns the number of DNSCrypt listeners" },
   { "getDOHFrontend", true, "n", "returns the DOH frontend with index n" },
index 2da6be64726ac7e3ff8b718d86ec7b04bba6420f..1932301ad05201d2b0b63dc95187a628f6160e5d 100644 (file)
@@ -66,13 +66,9 @@ struct StopWatch
     return ret;
   }
 
-  struct timespec getCurrentTime() const
+  struct timespec getStartTime() const
   {
-    struct timespec now;
-    if (gettime(&now, d_needRealTime) < 0) {
-      unixDie("Getting timestamp");
-    }
-    return now;
+    return d_start;
   }
 
   struct timespec d_start
@@ -81,6 +77,15 @@ struct StopWatch
   };
 
 private:
+  struct timespec getCurrentTime() const
+  {
+    struct timespec now;
+    if (gettime(&now, d_needRealTime) < 0) {
+      unixDie("Getting timestamp");
+    }
+    return now;
+  }
+
   bool d_needRealTime;
 };
 
index e53637ef59f6740c02c8fc52a1df02df39f73ca7..5e16d49de9322843dd5275c18b6f6a924578cb29 100644 (file)
@@ -80,6 +80,10 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
     return dq.getProtocol().toPrettyString();
   });
 
+  luaCtx.registerFunction<timespec(DNSQuestion::*)()const>("getQueryTime", [](const DNSQuestion& dq) {
+    return dq.ids.queryRealTime.getStartTime();
+  });
+
   luaCtx.registerFunction<void(DNSQuestion::*)(std::string)>("sendTrap", [](const DNSQuestion& dq, boost::optional<std::string> reason) {
 #ifdef HAVE_NET_SNMP
       if (g_snmpAgent && g_snmpTrapsEnabled) {
@@ -253,6 +257,10 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
     return dr.getProtocol().toPrettyString();
   });
 
+  luaCtx.registerFunction<timespec(DNSResponse::*)()const>("getQueryTime", [](const DNSResponse& dr) {
+    return dr.ids.queryRealTime.getStartTime();
+  });
+
   luaCtx.registerFunction<void(DNSResponse::*)(std::string)>("sendTrap", [](const DNSResponse& dr, boost::optional<std::string> reason) {
 #ifdef HAVE_NET_SNMP
       if (g_snmpAgent && g_snmpTrapsEnabled) {
index ced2f8a3d71c7de9149ffe1e744d70710695b207..63c9be3ae2716eff887b315f81d2f60ab7ca0f1f 100644 (file)
@@ -768,4 +768,12 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
   luaCtx.writeFunction("getMACAddress", [](const std::string& ip) {
     return getMACAddress(ComboAddress(ip));
   });
+
+  luaCtx.writeFunction("getCurrentTime", []() -> timespec {
+    timespec now;
+    if (gettime(&now, true) < 0) {
+      unixDie("Getting timestamp");
+    }
+    return now;
+  });
 }
index cf6cd011b0ca4d9d25da6c5ec9e89e221d0b200b..65ca67cedd1e23bf93dd209e58e80ff641e8cb75 100644 (file)
@@ -1743,6 +1743,14 @@ These values can be set at configuration time via:
 Other functions
 ---------------
 
+.. function:: getCurrentTime -> timespec
+
+  .. versionadded:: 1.8.0
+
+  Return the current time, in whole seconds and nanoseconds since epoch.
+
+  :returns: A timespec object, see :ref:`timespec`
+
 .. function:: getResolvers(path)
 
   .. versionadded:: 1.8.0
@@ -1980,6 +1988,8 @@ LuaRingEntry
 
     The timestamp of this entry, as a :ref:`timespec`.
 
+.. _timespec:
+
 timespec
 ~~~~~~~~
 
index db344e8fbf80cbc71bbbc1228b91ba76921ca01d..8bd47cc03f2f7491e43193284a593a2f76992ca4 100644 (file)
@@ -173,6 +173,14 @@ This state can be modified from the various hooks.
 
     :returns: A table whose keys are types and values are binary-safe strings
 
+  .. method:: DNSQuestion:getQueryTime -> timespec
+
+    .. versionadded:: 1.8.0
+
+    Return the time at which the current query has been received, in whole seconds and nanoseconds since epoch, as a :ref:`timespec` object.
+
+    :returns: A :ref:`timespec` object
+
   .. method:: DNSQuestion:getServerNameIndication() -> string
 
     .. versionadded:: 1.4.0
index f79d24901e250cbdb45572e65526022a036f213e..b5409f1a0eb63860d54c0a141d112b46edd51129 100644 (file)
@@ -517,3 +517,75 @@ class TestCustomMetrics(DNSDistTest):
             sender = getattr(self, method)
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, response)
+
+class TestDNSQuestionTime(DNSDistTest):
+    _config_template = """
+    local queryTime = nil
+
+    function luaquery(dq)
+      if queryTime then
+        errlog('Error, the time variable is already set')
+        return DNSAction.Drop
+      end
+      queryTime = dq:getQueryTime()
+      local currentTime = getCurrentTime()
+      if queryTime.tv_sec > currentTime.tv_sec then
+        errlog('Error, query time is higher than current time')
+        return DNSAction.Drop
+      end
+      if queryTime.tv_sec == currentTime.tv_sec and queryTime.tv_nsec > currentTime.tv_nsec then
+        errlog('Error, query time NS is higher than current time')
+        return DNSAction.Drop
+      end
+      return DNSAction.None
+    end
+
+    function luaresponse(dr)
+      if queryTime == nil then
+        errlog('Error, the time variable is NOT set')
+        return DNSAction.Drop
+      end
+      local currentTime        = getCurrentTime()
+      local queryTimeFromResponse = dr:getQueryTime()
+      if queryTime.tv_sec ~= queryTimeFromResponse.tv_sec or queryTime.tv_nsec ~= queryTimeFromResponse.tv_nsec then
+        errlog('Error, the query time in the response does NOT match the one from the query')
+        return DNSAction.Drop
+      end
+      if queryTime.tv_sec > currentTime.tv_sec then
+        errlog('Error, query time is higher than current time')
+        return DNSAction.Drop
+      end
+      if queryTime.tv_sec == currentTime.tv_sec and queryTime.tv_nsec > currentTime.tv_nsec then
+        errlog('Error, query time (NS) is higher than current time')
+        return DNSAction.Drop
+      end
+
+      queryTime = nil
+      return DNSAction.None
+    end
+
+    addAction(AllRule(), LuaAction(luaquery))
+    addResponseAction(AllRule(), LuaResponseAction(luaresponse))
+    newServer{address="127.0.0.1:%s"}
+    """
+
+    def testQueryTime(self):
+        """
+        Advanced: Test query time
+        """
+        name = 'query.time.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    60,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '4.3.2.1')
+        response.answer.append(rrset)
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (receivedQuery, receivedResponse) = sender(query, response)
+            receivedQuery.id = query.id
+            self.assertEqual(receivedQuery, query)
+            self.assertEqual(receivedResponse, response)