local bit = require('bit')
local ffi = require('ffi')
+local todname = kres.str2dname -- not available during module load otherwise
+
-- Counter of unique rules
local nextid = 0
local function getruleid()
end
end
+local function mkauth_soa(answer, dname, mname)
+ if mname == nil then
+ mname = dname
+ end
+ return answer:put(dname, 900, answer:qclass(), kres.type.SOA,
+ mname .. '\6nobody\7invalid\0\0\0\0\0\0\0\14\16\0\0\3\132\0\9\58\128\0\0\3\132')
+end
+
+local dname_localhost = todname('localhost.')
+
+-- Rule for localhost. zone; see RFC6303, sec. 3
local function localhost(state, req)
local qry = req:current()
local answer = req.answer
ffi.C.kr_pkt_make_auth_header(answer)
+
+ local is_exact = ffi.C.knot_dname_is_equal(qry.sname, dname_localhost)
+ if not is_exact then
+ answer:rcode(kres.rcode.NXDOMAIN)
+ answer:begin(kres.section.AUTHORITY)
+ mkauth_soa(answer, dname_localhost)
+ return kres.DONE
+ end
+
+ answer:rcode(kres.rcode.NOERROR)
+ answer:begin(kres.section.ANSWER)
if qry.stype == kres.type.AAAA then
- answer:begin(kres.section.ANSWER)
- answer:put(qry.sname, 900, answer:qclass(), kres.type.AAAA, '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1')
+ answer:put(dname_localhost, 900, answer:qclass(), kres.type.AAAA,
+ '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1')
elseif qry.stype == kres.type.A then
- answer:begin(kres.section.ANSWER)
- answer:put(qry.sname, 900, answer:qclass(), kres.type.A, '\127\0\0\1')
+ answer:put(dname_localhost, 900, answer:qclass(), kres.type.A, '\127\0\0\1')
+ elseif qry.stype == kres.type.SOA then
+ mkauth_soa(answer, dname_localhost)
+ elseif qry.stype == kres.type.NS then
+ answer:put(dname_localhost, 900, answer:qclass(), kres.type.NS,
+ dname_localhost)
else
- answer:rcode(kres.rcode.NOERROR)
answer:begin(kres.section.AUTHORITY)
- answer:put('\7blocked', 900, answer:qclass(), kres.type.SOA,
- '\7blocked\0\0\0\0\0\0\0\0\14\16\0\0\3\132\0\9\58\128\0\0\3\132')
+ mkauth_soa(answer, dname_localhost)
end
return kres.DONE
end
+local dname_rev4_localhost = todname('1.0.0.127.in-addr.arpa');
+local dname_rev4_localhost_apex = todname('127.in-addr.arpa');
+
+-- Rule for reverse localhost.
+-- Answer with locally served minimal 127.in-addr.arpa domain, only having
+-- a PTR record in 1.0.0.127.in-addr.arpa, and with 1.0...0.ip6.arpa. zone.
+-- TODO: much of this would better be left to the hints module (or coordinated).
local function localhost_reversed(state, req)
local qry = req:current()
local answer = req.answer
+
+ -- classify qry.sname:
+ local is_exact -- exact dname for localhost
+ local is_apex -- apex of a locally-served localhost zone
+ local is_nonterm -- empty non-terminal name
+ if ffi.C.knot_dname_is_sub(qry.sname, todname('ip6.arpa.')) then
+ -- exact ::1 query (relying on the calling rule)
+ is_exact = true
+ is_apex = true
+ else
+ -- within 127.in-addr.arpa.
+ local labels = ffi.C.knot_dname_labels(qry.sname, nil)
+ if labels == 3 then
+ is_exact = false
+ is_apex = true
+ elseif labels == 4+2 and ffi.C.knot_dname_is_equal(
+ qry.sname, dname_rev4_localhost) then
+ is_exact = true
+ else
+ is_exact = false
+ is_apex = false
+ is_nonterm = ffi.C.knot_dname_is_sub(dname_rev4_localhost, qry.sname)
+ end
+ end
+
ffi.C.kr_pkt_make_auth_header(answer)
- if qry.stype == kres.type.PTR then
- answer:begin(kres.section.ANSWER)
- answer:put(qry.sname, 900, answer:qclass(), kres.type.PTR, todname('localhost'))
+ answer:rcode(kres.rcode.NOERROR)
+ answer:begin(kres.section.ANSWER)
+ if is_exact and qry.stype == kres.type.PTR then
+ answer:put(qry.sname, 900, answer:qclass(), kres.type.PTR, dname_localhost)
+ elseif is_apex and qry.stype == kres.type.SOA then
+ mkauth_soa(answer, dname_rev4_localhost_apex, dname_localhost)
+ elseif is_apex and qry.stype == kres.type.NS then
+ answer:put(dname_rev4_localhost_apex, 900, answer:qclass(), kres.type.NS,
+ dname_localhost)
else
- answer:rcode(kres.rcode.NOERROR)
+ if not is_nonterm then
+ answer:rcode(kres.rcode.NXDOMAIN)
+ end
answer:begin(kres.section.AUTHORITY)
- answer:put('\7blocked', 900, answer:qclass(), kres.type.SOA,
- '\7blocked\0\0\0\0\0\0\0\0\14\16\0\0\3\132\0\9\58\128\0\0\3\132')
+ mkauth_soa(answer, dname_rev4_localhost_apex, dname_localhost)
end
return kres.DONE
end
ffi.C.kr_pkt_make_auth_header(answer)
answer:rcode(kres.rcode.NXDOMAIN)
answer:begin(kres.section.AUTHORITY)
- answer:put('\7blocked', 900, answer:qclass(), kres.type.SOA,
- '\7blocked\0\0\0\0\0\0\0\0\14\16\0\0\3\132\0\9\58\128\0\0\3\132')
+ mkauth_soa(answer, '\7blocked\0')
return kres.DONE
elseif action == policy.DROP then
return kres.FAIL
'127.100.in-addr.arpa.',
-- RFC6303
+ -- localhost_reversed handles ::1
'0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.',
'd.f.ip6.arpa.',
'8.e.f.ip6.arpa.',
count=0
},
{
- cb=policy.suffix(localhost, {todname('localhost.')}),
+ cb=policy.suffix(localhost, {dname_localhost}),
count=0
},
{
- cb=policy.suffix_common(localhost_reversed, {
+ cb=policy.suffix_common(localhost_reversed, {
todname('127.in-addr.arpa.'),
todname('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.')},
todname('arpa.')),