BADCOOKIE = 23,
}
+-- This corresponds to `enum kr_rank`, it's not possible to do this without introspection unfortunately
+local const_rank = {
+ INITIAL = 0,
+ OMIT = 1,
+ TRY = 2,
+ INDET = 4,
+ BOGUS = 5,
+ MISMATCH = 6,
+ MISSING = 7,
+ INSECURE = 8,
+ AUTH = 16,
+ SECURE = 32
+}
+
+-- Create inverse table
+local const_rank_tostring = {}
+for k, v in pairs(const_rank) do
+ const_rank_tostring[v] = k
+end
+
-- Metatype for RR types to allow anonymous types
setmetatable(const_type, {
__index = function (t, k)
ffi.metatype( knot_rrset_t, {
-- beware: `owner` and `rdata` are typed as a plain lua strings
-- and not the real types they represent.
+ __tostring = function(rr) return rr:txt_dump() end,
__index = {
owner = function(rr) return ffi.string(rr._owner, knot.knot_dname_size(rr._owner)) end,
ttl = function(rr) return tonumber(knot.knot_rrset_ttl(rr)) end,
},
})
+-- C array iterator
+local function c_array_iter(t, i)
+ i = i + 1
+ if i >= t.len then return end
+ return i, t.at[i][0]
+end
+
+-- Metatype for ranked record array
+local ranked_rr_array_t = ffi.typeof('ranked_rr_array_t')
+ffi.metatype(ranked_rr_array_t, {
+ __len = function(self)
+ return tonumber(self.len)
+ end,
+ __ipairs = function (self)
+ return c_array_iter, self, -1
+ end,
+ __index = {
+ get = function (self, i)
+ if i < 0 or i > self.len then return nil end
+ return self.at[i][0]
+ end,
+ }
+})
+
-- Pretty print for domain name
local function dname2str(dname)
return ffi.string(ffi.gc(C.knot_dname_to_str(nil, dname, 0), C.free))
type = const_type,
section = const_section,
rcode = const_rcode,
+ rank = const_rank,
+ rank_tostring = const_rank_tostring,
-- Create a struct kr_qflags from a single flag name or a list of names.
mk_qflags = function (names)
local ffi = require('ffi')
+local bit = require('bit')
local condition = require('cqueues.condition')
+-- Buffer selected record information to a table
+local function add_selected_records(dst, records)
+ for _, rec in ipairs(records) do
+ local rank = rec.rank
+ -- Separate the referral chain verified flag
+ local verified = bit.band(rec.rank, kres.rank.AUTH)
+ if verified then
+ rank = bit.band(rank, bit.bnot(kres.rank.AUTH))
+ end
+ local rank_name = kres.rank_tostring[rank] or tostring(rank)
+ -- Write out each individual RR
+ for rr in tostring(rec.rr):gmatch('[^\n]+\n?') do
+ local row = string.format('cached: %s, rank: %s, record: %s',
+ rec.cached, rank_name:lower(), rr)
+ table.insert(dst, row)
+ end
+ end
+end
+
+local function format_selected_records(header, records)
+ if #records == 0 then return '' end
+ return string.format('%s\n%s\n', header, string.rep('-', #header))
+ .. table.concat(records, '') .. '\n'
+end
+
-- Trace execution of DNS queries
local function serve_trace(h, _)
local path = h:get(':path')
local done = false
-- Resolve query and buffer logs into table
+ local answers, authority = {}, {}
resolve {
name = qname,
type = qtype,
req = kres.request_t(req)
req.trace_log = buffer_log_cb
end,
- finish = function ()
+ finish = function (_, req)
+ req = kres.request_t(req)
+ add_selected_records(answers, req.answ_selected)
+ add_selected_records(authority, req.auth_selected)
cond:signal()
done = true
end
end
buffer_log_cb:free()
- -- Return buffered data
+ -- Build the result
local result = table.concat(buffer, '') .. '\n'
+ .. format_selected_records('Used records from answer:', answers)
+ .. format_selected_records('Used records from authority:', authority)
+ -- Return buffered data
if not done then
return 504, result
end