From: Remi Gacogne Date: Mon, 9 Jan 2023 14:14:28 +0000 (+0100) Subject: dnsdist: Add Lua bindings for the current time and query time X-Git-Tag: dnsdist-1.8.0-rc1~126^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F12402%2Fhead;p=thirdparty%2Fpdns.git dnsdist: Add Lua bindings for the current time and query time --- diff --git a/pdns/dnsdist-console.cc b/pdns/dnsdist-console.cc index 472195d010..9cbdbeb1f0 100644 --- a/pdns/dnsdist-console.cc +++ b/pdns/dnsdist-console.cc @@ -517,6 +517,7 @@ const std::vector 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" }, diff --git a/pdns/dnsdist-idstate.hh b/pdns/dnsdist-idstate.hh index 2da6be6472..1932301ad0 100644 --- a/pdns/dnsdist-idstate.hh +++ b/pdns/dnsdist-idstate.hh @@ -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; }; diff --git a/pdns/dnsdist-lua-bindings-dnsquestion.cc b/pdns/dnsdist-lua-bindings-dnsquestion.cc index e53637ef59..5e16d49de9 100644 --- a/pdns/dnsdist-lua-bindings-dnsquestion.cc +++ b/pdns/dnsdist-lua-bindings-dnsquestion.cc @@ -80,6 +80,10 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx) return dq.getProtocol().toPrettyString(); }); + luaCtx.registerFunction("getQueryTime", [](const DNSQuestion& dq) { + return dq.ids.queryRealTime.getStartTime(); + }); + luaCtx.registerFunction("sendTrap", [](const DNSQuestion& dq, boost::optional reason) { #ifdef HAVE_NET_SNMP if (g_snmpAgent && g_snmpTrapsEnabled) { @@ -253,6 +257,10 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx) return dr.getProtocol().toPrettyString(); }); + luaCtx.registerFunction("getQueryTime", [](const DNSResponse& dr) { + return dr.ids.queryRealTime.getStartTime(); + }); + luaCtx.registerFunction("sendTrap", [](const DNSResponse& dr, boost::optional reason) { #ifdef HAVE_NET_SNMP if (g_snmpAgent && g_snmpTrapsEnabled) { diff --git a/pdns/dnsdist-lua-bindings.cc b/pdns/dnsdist-lua-bindings.cc index ced2f8a3d7..63c9be3ae2 100644 --- a/pdns/dnsdist-lua-bindings.cc +++ b/pdns/dnsdist-lua-bindings.cc @@ -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; + }); } diff --git a/pdns/dnsdistdist/docs/reference/config.rst b/pdns/dnsdistdist/docs/reference/config.rst index cf6cd011b0..65ca67cedd 100644 --- a/pdns/dnsdistdist/docs/reference/config.rst +++ b/pdns/dnsdistdist/docs/reference/config.rst @@ -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 ~~~~~~~~ diff --git a/pdns/dnsdistdist/docs/reference/dq.rst b/pdns/dnsdistdist/docs/reference/dq.rst index db344e8fbf..8bd47cc03f 100644 --- a/pdns/dnsdistdist/docs/reference/dq.rst +++ b/pdns/dnsdistdist/docs/reference/dq.rst @@ -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 diff --git a/regression-tests.dnsdist/test_Advanced.py b/regression-tests.dnsdist/test_Advanced.py index f79d24901e..b5409f1a0e 100644 --- a/regression-tests.dnsdist/test_Advanced.py +++ b/regression-tests.dnsdist/test_Advanced.py @@ -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)