18.3.2. DNS

DNS transaction details are exposed to Lua scripts with the suricata.dns library, for example:

local dns = require("suricata.dns")

18.3.2.1. Setup

If your purpose is to create a logging script, initialize the buffer as:

function init (args)
   local needs = {}
   needs["protocol"] = "dns"
   return needs
end

If you are going to use the script for rule matching, choose one of the available DNS buffers listed in Lua Scripting for Detection and follow the pattern:

For use in rule matching, the rule must hook into a DNS transaction state. Available states are request_complete and response_complete. For example:

alert dns:request_complete any any -> any any (...

Then to initialize the script:

function init (args)
   return {}
end

18.3.2.1.1. Transaction

DNS is transaction based, and the current transaction must be obtained before use:

local tx, err = dns.get_tx()
if tx == err then
    print(err)
end

All other functions are methods on the transaction table.

18.3.2.1.2. Transaction Methods

18.3.2.2. answers()

Get the answers response section as a table of tables.

Example:

local tx = dns.get_tx()
local answers = tx:answers()
if answers ~= nil then
    for n, t in pairs(answers) do
        rrname = t["rrname"]
        rrtype = t["type"]
        ttl = t["ttl"]

        print ("ANSWER: " .. ts .. " " .. rrname .. " [**] " .. rrtype .. " [**] " ..
               ttl .. " [**] " .. srcip .. ":" .. sp .. " -> " ..
               dstip .. ":" .. dp)
    end
end

18.3.2.3. authorities()

Get the authorities response section as a table of tables.

Example:

local tx = dns.get_tx()
local authorities = tx:authorities();
if authorities ~= nil then
    for n, t in pairs(authorities) do
        rrname = t["rrname"]
        rrtype = t["type"]
        ttl = t["ttl"]
         print ("AUTHORITY: " .. ts .. " " .. rrname .. " [**] " .. rrtype .. " [**] " ..
               ttl .. " [**] " .. srcip .. ":" .. sp .. " -> " ..
               dstip .. ":" .. dp)
    end
end

18.3.2.4. queries()

Get the queries request or response section as a table of tables.

Example:

local tx = dns.get_tx()
local queries = tx:queries();
if queries ~= nil then
    for n, t in pairs(queries) do
        rrname = t["rrname"]
        rrtype = t["type"]

        print ("QUERY: " .. ts .. " " .. rrname .. " [**] " .. rrtype .. " [**] " ..
               "TODO" .. " [**] " .. srcip .. ":" .. sp .. " -> " ..
               dstip .. ":" .. dp)
    end
end

18.3.2.5. rcode()

Get the rcode value as an integer.

Example:

local tx = dns.get_tx()
local rcode = tx:rcode()
print (rcode)

18.3.2.6. rcode_string()

Get the rcode value as a string.

Example:

local tx = dns.get_tx()
local rcode_string = tx:rcode_string();
print (rcode_string)

18.3.2.7. recursion_desired()

Return the value of the recursion desired (RD) flag as a boolean.

Example:

local tx = dns.get_tx()
if tx:recursion_desired() == true then
    print ("RECURSION DESIRED")
end

18.3.2.8. rrname()

Return the resource name from the first query object.

Example:

local tx = dns.get_tx()
local rrname = tx:rrname()
print(rrname)

18.3.2.9. txid()

Return the DNS transaction ID found in the DNS message.

Example:

local tx = dns.get_tx()
local txid = tx:txid()
print(txid)