Skip to content
Snippets Groups Projects
Commit 5c14ca9d authored by Marek Vavruša's avatar Marek Vavruša
Browse files

modules/dns64: introduced module

parent aea3484c
Branches
Tags
No related merge requests found
......@@ -19,3 +19,4 @@ Knot DNS Resolver modules
.. include:: ../modules/ketcd/README.rst
.. include:: ../modules/cachectl/README.rst
.. include:: ../modules/tinyweb/README.rst
.. include:: ../modules/dns64/README.rst
......@@ -72,9 +72,10 @@ static inline long time_diff(struct timeval *begin, struct timeval *end) {
return res.tv_sec * 1000 + res.tv_usec / 1000;
}
/** @internal Array types */
/** @cond Array types */
struct kr_context;
typedef array_t(knot_rrset_t *) rr_array_t;
/* @endcond */
/** @internal Next RDATA shortcut. */
#define kr_rdataset_next(rd) (rd + knot_rdata_array_size(knot_rdata_rdlen(rd)))
......
.. _mod-dns64:
DNS64
-----
The module for :rfc:`6147` DNS64 AAAA-from-A record synthesis, it is used to enable client-server communication between an IPv6-only client and an IPv4-only server. See the well written `introduction`_ in the PowerDNS documentation.
.. tip:: The A record sub-requests will be DNSSEC secured, but the synthetic AAAA records can't be. Make sure the last mile between stub and resolver is secure to avoid spoofing.
Example configuration
^^^^^^^^^^^^^^^^^^^^^
.. code-block:: lua
-- Load the module with a NAT64 address
modules = { dns64 = 'fe80::21b:77ff:0:0' }
-- Reconfigure later
dns64.config('fe80::21b:aabb:0:0')
.. _RPZ: https://dnsrpz.info/
.. _introduction: https://doc.powerdns.com/md/recursor/dns64
\ No newline at end of file
-- Module interface
local ffi = require('ffi')
local bit = require('bit')
local mod = {}
local MARK_DNS64 = bit.lshift(1, 31)
-- Config
function mod.config (confstr)
if confstr == nil then return end
mod.proxy = kres.str2ip(confstr)
if mod.proxy == nil then error('[dns64] "'..confstr..'" is not a valid address') end
end
-- Layers
mod.layer = {
consume = function (state, req, pkt)
pkt = kres.pkt_t(pkt)
req = kres.request_t(req)
qry = req:current()
-- Observe only authoritative answers
if mod.proxy == nil or bit.band(qry.flags, kres.query.RESOLVED) == 0 then
return state
end
-- Synthetic AAAA from marked A responses
local answer = pkt:section(kres.section.ANSWER)
if bit.band(qry.flags, MARK_DNS64) ~= 0 then -- Marked request
for i = 1, #answer do
local rr = answer[i]
-- Synthesise address
local rdata = ffi.new('char [16]')
ffi.copy(rdata, mod.proxy)
ffi.copy(rdata + 12, rr.rdata, 4)
rdata = ffi.string(rdata, 16)
-- Write to answer
req.answer:put(rr.owner, rr.ttl, rr.class, kres.type.AAAA, rdata)
end
return state
end
-- Observe AAAA NODATA responses
local is_nodata = (pkt:rcode() == kres.rcode.NOERROR) and (#answer == 0)
if pkt:qtype() == kres.type.AAAA and is_nodata and pkt:qname() == qry:name() then
local next = req:push(pkt:qname(), kres.type.A, kres.class.IN, 0, qry)
next.flags = bit.band(qry.flags, kres.query.DNSSEC_WANT) + kres.query.AWAIT_CUT + MARK_DNS64
end
return state
end
}
return mod
dns64_SOURCES := dns64.lua
$(call make_lua_module,dns64)
......@@ -18,7 +18,8 @@ modules_TARGETS += ketcd \
graphite \
policy \
view \
predict
predict \
dns64
endif
# List of Golang modules
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment