Fast and intuitive FFI API¶
While Defender provides a lot of new features, there are still cases where it makes sense to write Lua code to tailor DNSdist to specific needs. The Lua FFI provided by DNSdist is designed to offer the maximum possible performance, and therefore looks a lot like the C++ API that it is a thin wrapper over. This comes with very rough edges, and can be challenging to use. Defender wraps the FFI API to provide the ability to extend DNSdist without having the feeling to write C code.
Helpers¶
ComboAddress API¶
The ComboAddress API mimicks the ComboAddress class available in the regular, non-FFI interface.
newCAWithHints(version, address, port) -> FFIComboAddressWrapper¶
This method returns a FFIComboAddressWrapper object from a string.
Parameters:
version- integer: The IP version of the address,4for IPv4 and6for IPv6address- string: The address, for example192.0.2.1port- integer: The port
FFIComboAddressWrapper class¶
The FFIComboAddressWrapper object mimicks the ComboAddress object available in the regular, non-FFI interface, and supports the following methods:
FFIComboAddressWrapper:getPort() -> integer¶
Returns the port as an integer.
FFIComboAddressWrapper:isIPv4() -> boolean¶
Returns true if the address is an IPv4 one, false otherwise.
FFIComboAddressWrapper:isIPv6() -> boolean¶
Returns true if the address is an IPv6 one, false otherwise.
FFIComboAddressWrapper:toString() -> string¶
Returns the address as a string, without the port.
FFIComboAddressWrapper:toStringWithPort() -> string¶
Returns the address as a string, including the port.
DNSName API¶
The DNSName API mimicks the DNSName class available in the regular, non-FFI interface.
newDNSName(raw) -> FFIDNSNameWrapper¶
This method returns a FFIDNSNameWrapper object from a Lua string containing a DNS name in wire format:
local dnsdistFFI = require 'dnsdist/ffi'
local name = dnsdistFFI.newDNSName('\007dnsdist\003org\000')
print(name:toString())
FFIDNSNameWrapper class¶
The FFIDNSNameWrapper object mimicks a DNSName object available in the regular, non-FFI interface, and supports the following methods:
FFIDNSNameWrapper:toString() -> string¶
Returns the DNS name in human-readable form as a string, including the trailing dot.
FFIDNSNameWrapper:wirelength() -> integer¶
Returns the length in bytes of the DNSName as it would be on the wire.
DNSQuestion API¶
The DNSQuestion API wraps the dnsdist_ffi_dnsquestion_t object to provide a compatility layer with the DNSQuestion object from the regular, non-FFI
interface, making it easier to write code using the FFI interface and to reuse existing code.
DNSQuestion¶
newDNSQuestion(dnsdist_ffi_dnsquestion_t) -> FFIDNSQuestionWrapper¶
This method returns a FFIDNSNameWrapper object from a Lua string containing a DNS name in wire format:
local dnsdistFFI = require 'dnsdist/ffi'
local dq = dnsdistFFI.newDNSQuestion(dqffi)
print(dq.remoteaddr:toStringWithPort())
FFIDNSQuestionWrapper class¶
The FFIDNSQuestionWrapper object provides a compatility layer with the DNSQuestion object from the regular, non-FFI interface. It provides the following methods and fields:
FFIDNSQuestionWrapperFunctions:getProtocol() -> string¶
Return the protocol this query was received over, in human-readable format ("Do53 UDP", "Do53 TCP", "DNSCrypt UDP", "DNSCrypt TCP", "DNS over TLS", "DNS over HTTPS").
FFIDNSQuestionWrapperFunctions.len¶
The size, in bytes, of the received query.
FFIDNSQuestionWrapperFunctions.localaddr¶
The FFIComboAddressWrapper of the local bind this question was received on.
FFIDNSQuestionWrapperFunctions.opcode¶
The opcode, as an integer, of the received query.
FFIDNSQuestionWrapperFunctions.qclass¶
The requested class, as an integer, of the received query.
FFIDNSQuestionWrapperFunctions.qname¶
The requested name, as a FFIDNSNameWrapper, of the received query.
FFIDNSQuestionWrapperFunctions.qtype¶
The requested type, as an integer, of the received query.
FFIDNSQuestionWrapperFunctions.rcode¶
The rcode, as an integer, of the received query.
FFIDNSQuestionWrapperFunctions.remoteaddr¶
The FFIComboAddressWrapper of the remote client.
FFIDNSQuestionWrapperFunctions.size¶
The total size, in bytes, of the buffer holding the query payload.
FFIDNSQuestionWrapperFunctions.tcp¶
Whether the query was received over UDP (false) or TCP (true). See FFIDNSQuestionWrapperFunctions:getProtocol() for the exact protocol.
StatNode API¶
The StatNode API is useful when extending the existing capabilities of
the pseudo random subdomain detection and mitigation features by
passinng a custom Lua function to DNSdist's
DynBlockRulesGroup:setSuffixMatchRuleFFI(). The custom Lua function is
then invoked for every node of the DNS tree built by the algorithm
described in Pseudo Random Subdomain attack protection,
getting a dnsdist_ffi_stat_node object containing
information about the node and the traffic it received during the last
time window.
FFIStatNodeWrapper¶
newStatNode(statNodeFFI) -> FFIStatNodeWrapper¶
This method returns a FFIStatNodeWrapper object from a dnsdist_ffi_stat_node one:
:::
local dnsdistFFI = require 'dnsdist/ffi'
local node = dnsdistFFI.newStatNode(statNodeFFI)
if node:getChildrenCount() < minChildren then
return false
end
local qps = node:getChildrenQueriesCount() / window
if qps < minQPS then
return false
end
end
FFIStatNodeWrapper class¶
The FFIStatNodeWrapper object wraps a dnsdist_ffi_stat_node FFI object and supports the following methods:
FFIStatNodeWrapper:getBytes() -> integer¶
Returns the amount of bytes for all responses received by this node.
FFIStatNodeWrapper:getChildrenBytes() -> integer¶
Returns the amount of bytes for all responses received by the children of this node.
FFIStatNodeWrapper:getChildrenCount() -> integer (#FFIStatNodeWrapper.getChildrenCount)¶
Returns the number of children of this node.
FFIStatNodeWrapper:getChildrenHitsCount() -> integer¶
Returns the amount of cache hits for the children of this node.
FFIStatNodeWrapper:getChildrenQueriesCount() -> integer¶
Returns the number of queries the children of this node have received.
FFIStatNodeWrapper:getChildrenNOERRORCount() -> integer¶
Returns the number of NoError responses the children of this node have received.
FFIStatNodeWrapper:getChildrenNXDOMAINCount() -> integer¶
Returns the number of NXDOMAIN responses the children of this node have received.
FFIStatNodeWrapper:getChildrenSERVFAILCount() -> integer¶
Returns the number of SERVFAIL responses the children of this node have received.
FFIStatNodeWrapper:getFullName() -> integer¶
Returns a Lua string containing the DNS name of the current node.
FFIStatNodeWrapper:getHitsCount() -> integer¶
Returns the amount of cache hits for this node.
FFIStatNodeWrapper:getDropsCount() -> integer¶
Returns the number of queries for this node that did not get an answer from the backend in time.
FFIStatNodeWrapper:getLabelsCount() -> integer¶
Returns the number of labels in the DNS name of the current node.
FFIStatNodeWrapper:getNOERRORCount() -> integer¶
Returns the number of NoError responses this node has received.
FFIStatNodeWrapper:getNXDOMAINCount() -> integer¶
Returns the number of NXDOMAIN responses this node has received.
FFIStatNodeWrapper:getQueriesCount() -> integer¶
Returns the number of queries this node has received.
FFIStatNodeWrapper:getQueriesPerChildRatio() -> integer¶
Returns the average number of queries per child received by the children of this node.
FFIStatNodeWrapper:getSERVFAILCount() -> integer¶
Returns the number of SERVFAIL responses this node has received.
Metrics¶
The FFI interface provides a faster way to interact with metrics.
declareMetric(name, type, description[, prometheusName]) -> boolean¶
Identical to DNSdist's declareMetric.
incMetric(name[, value])¶
Increment the value of an existing metric by:
- 1 if
valueis unset valueotherwise
decMetric(name)¶
Decrement the value of an existing metric by 1.
getMetric(name, isCounter) -> float¶
Return the value of an existing metric. isCounter should be set to true if the metric is a counter, and false if it is a gauge.
setMetric(name, value)¶
Set an existing metric to the specified value.