From 4b6fa7a772ad9b0a6375bced51d58841e76c385b Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Tue, 10 Jan 2023 14:53:29 +0100 Subject: [PATCH] dnsdist: Add documentation for suspending/resuming objects --- .../docs/advanced/asynchronous-processing.rst | 52 ++++++++++++ pdns/dnsdistdist/docs/advanced/index.rst | 1 + pdns/dnsdistdist/docs/imgs/AsyncQuery.png | Bin 0 -> 51326 bytes pdns/dnsdistdist/docs/reference/dnsparser.rst | 5 ++ pdns/dnsdistdist/docs/reference/dq.rst | 79 ++++++++++++++++++ 5 files changed, 137 insertions(+) create mode 100644 pdns/dnsdistdist/docs/advanced/asynchronous-processing.rst create mode 100644 pdns/dnsdistdist/docs/imgs/AsyncQuery.png diff --git a/pdns/dnsdistdist/docs/advanced/asynchronous-processing.rst b/pdns/dnsdistdist/docs/advanced/asynchronous-processing.rst new file mode 100644 index 0000000000..404e0170d1 --- /dev/null +++ b/pdns/dnsdistdist/docs/advanced/asynchronous-processing.rst @@ -0,0 +1,52 @@ +Asynchronous processing +======================= + +Since 1.8.0, dnsdist has the ability to process queries and responses in an asynchronous way, suspending them to continue processing other queries and responses, while we are waiting for an external event to occur. + +This is done by calling the :meth:`DNSQuestion:suspend` method on a query or a response to pause it, then later the :func:`getAsynchronousObject` to retrieve it before resuming via :meth:`AsynchronousObject:resume`. + +A timeout must be supplied when pausing a query or a response, to prevent paused objects from piling up, consuming memory. When the timeout expires, the suspended object is automatically retrieved and resumes its processing where it was left. + +.. figure:: ../imgs/AsyncQuery.png + :align: center + :alt: Asynchronous processing of queries and responses + +The following code shows a very simple example that forwards queries and responses to an external component over a unix network socket, and resumes them when it gets an answer from the external component. + +.. code-block:: lua + + local asyncID = 0 + local asyncResponderEndpoint = newNetworkEndpoint('/path/to/unix/network/socket/remote/endpoint') + local listener = newNetworkListener() + listener:addUnixListeningEndpoint('/path/to/unix/network/socket/local/endpoint', 0, gotAsyncResponse) + listener:start() + + function gotAsyncResponse(endpointID, message, from) + local queryID = tonumber(message) + local asyncObject = getAsynchronousObject(asyncID, queryID) + local dq = asyncObject:getDQ() + dq:setTag(filteringTagName, filteringTagValue) + asyncObject:resume() + end + + function passQueryToAsyncFilter(dq) + local timeout = 500 -- 500 ms + local buffer = dq:getContent() + local id = dq.dh:getID() + dq:suspend(asyncID, id, timeout) + asyncResponderEndpoint:send(buffer) + return DNSAction.Allow + end + + function passResponseToAsyncFilter(dr) + local timeout = 500 -- 500 ms + local buffer = dr:getContent() + local id = dr.dh:getID() + dr:suspend(asyncID, id, timeout) + asyncResponderEndpoint:send(buffer) + return DNSResponseAction.Allow + end + + addAction(AllRule(), LuaAction(passQueryToAsyncFilter)) + addCacheHitResponseAction(AllRule(), LuaResponseAction(passResponseToAsyncFilter)) + addResponseAction(AllRule(), LuaResponseAction(passResponseToAsyncFilter)) diff --git a/pdns/dnsdistdist/docs/advanced/index.rst b/pdns/dnsdistdist/docs/advanced/index.rst index a028a9292f..e390db09eb 100644 --- a/pdns/dnsdistdist/docs/advanced/index.rst +++ b/pdns/dnsdistdist/docs/advanced/index.rst @@ -21,3 +21,4 @@ These chapters contain information on the advanced features of dnsdist ocsp-stapling tls-sessions-management internal-design + asynchronous-processing diff --git a/pdns/dnsdistdist/docs/imgs/AsyncQuery.png b/pdns/dnsdistdist/docs/imgs/AsyncQuery.png new file mode 100644 index 0000000000000000000000000000000000000000..b9c5ab121cf591bdd9791fde863b46a495323665 GIT binary patch literal 51326 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 literal 0 Hc-jL100001 diff --git a/pdns/dnsdistdist/docs/reference/dnsparser.rst b/pdns/dnsdistdist/docs/reference/dnsparser.rst index 1b07bf672d..5661b7edc2 100644 --- a/pdns/dnsdistdist/docs/reference/dnsparser.rst +++ b/pdns/dnsdistdist/docs/reference/dnsparser.rst @@ -42,6 +42,11 @@ and then to create a :class:`DNSPacketOverlay` object: :param str packet: The DNS payload +.. _DNSPacketOverlay: + +DNSPacketOverlay +---------------- + .. class:: DNSPacketOverlay .. versionadded:: 1.8.0 diff --git a/pdns/dnsdistdist/docs/reference/dq.rst b/pdns/dnsdistdist/docs/reference/dq.rst index 8bd47cc03f..4f4afa4fe3 100644 --- a/pdns/dnsdistdist/docs/reference/dq.rst +++ b/pdns/dnsdistdist/docs/reference/dq.rst @@ -217,6 +217,14 @@ This state can be modified from the various hooks. :param string reason: An optional string describing the reason why this trap was sent + .. method:: DNSQuestion:setContent(data) + + .. versionadded:: 1.8.0 + + Replace the DNS payload of the query with the supplied data, and adjusts the ID in the DNS header to the existing query. + + :param string data: The raw DNS payload + .. method:: DNSQuestion:setEDNSOption(code, data) .. versionadded:: 1.8.0 @@ -303,6 +311,18 @@ This state can be modified from the various hooks. :param string raw: The raw string to be spoofed, e.g. `"\\192\\000\\002\\001"`. :param table raws: The raw strings to be spoofed, e.g. `{ "\\192\\000\\002\\001", "\\192\\000\\002\\002" }`. + .. method:: DNSQuestion:suspend(asyncID, queryID, timeoutMS) -> bool + + .. versionadded:: 1.8.0 + + Suspend the processing for the current query, making it asynchronous. The query is then placed into memory, in a map called the Asynchronous Holder, until it is either resumed or the supplied timeout kicks in. The object is stored under a key composed of the tuple (`asyncID`, `queryID`) which is needed to retrieve it later, which can be done via :func:`getAsynchronousObject`. + Note that the DNSQuestion object should NOT be accessed after successfully calling this method. + Returns true on success and false on failure, indicating that the query has not been suspended and the normal processing will continue. + + :param int asyncID: A numeric identifier used to identify the suspended query for later retrieval + :param int queryID: A numeric identifier used to identify the suspended query for later retrieval. This ID does not have to match the query ID present in the initial DNS header. A given (asyncID, queryID) tuple should be unique at a given time. + :param int timeoutMS: The maximum duration this query will be kept in the asynchronous holder before being automatically resumed, in milliseconds. + .. _DNSResponse: DNSResponse object @@ -371,6 +391,12 @@ DNSHeader (``dh``) object Get checking disabled flag. + .. method:: DNSHeader:getID() -> int + + .. versionadded:: 1.8.0 + + Get the ID. + .. method:: DNSHeader:getRA() -> bool Get recursion available flag. @@ -438,3 +464,56 @@ EDNSOptionView object .. method:: EDNSOptionView:getValues() Return a table of NULL-safe strings values for this EDNS option. + +.. _AsynchronousObject: + +AsynchronousObject object +========================= + +.. class:: AsynchronousObject + + .. versionadded:: 1.8.0 + + This object holds a representation of a DNS query or response that has been suspended. + + .. method:: AsynchronousObject:drop() -> bool + + Drop that object immediately, without resuming it. + Returns true on success, false on failure. + + .. method:: AsynchronousObject:getDQ() -> DNSQuestion + + Return a DNSQuestion object for the suspended object. + + .. method:: AsynchronousObject:getDR() -> DNSResponse + + Return a DNSResponse object for the suspended object. + + .. method:: AsynchronousObject:resume() -> bool + + Resume the processing of the suspended object. + For a question, it means first checking whether it was turned into a response, + and sending the response out it it was. Otherwise do a cache-lookup, select a + backend and send the query to the backend. + For a response, it means inserting into the cache if needed and sending the + response to the backend. + Note that the AsynchronousObject object should NOT be accessed after successfully calling this method. + Returns true on success, false on failure. + + .. method:: AsynchronousObject:setRCode(rcode, clearRecords) -> bool + + Set the response code in the DNS header of the current object to the supplied value, + optionally removing all records from the existing payload, if any. + Returns true on success, false on failure. + + :param int code: The response code to set + :param bool clearRecords: Whether to clear all records from the existing payload, if any + +.. function:: getAsynchronousObject(asyncID, queryID) -> AsynchronousObject + + .. versionadded:: 1.8.0 + + Retrieves an asynchronous object stored into the Asynchronous holder. + + :param int asyncID: A numeric identifier used to identify the query when it was suspended + :param int queryID: A numeric identifier used to identify the query when it was suspended -- 2.47.2