122 lines
3.2 KiB
Lua
122 lines
3.2 KiB
Lua
-- SPDX-License-Identifier: GPL-3.0-or-later
|
|
-- Module interface
|
|
|
|
local ffi = require('ffi')
|
|
local basexx = require('basexx')
|
|
local C = ffi.C
|
|
|
|
-- Export module interface
|
|
local M = {}
|
|
M.layer = {}
|
|
local base32 = {}
|
|
local str = {}
|
|
local AF_INET = 2
|
|
local AF_INET6 = 10
|
|
local INET_ADDRSTRLEN = 16
|
|
local INET6_ADDRSTRLEN = 46
|
|
|
|
ffi.cdef[[
|
|
/*
|
|
* Data structures
|
|
*/
|
|
typedef int socklen_t;
|
|
struct sockaddr_storage{
|
|
unsigned short int ss_family;
|
|
unsigned long int __ss_align;
|
|
char __ss_padding[128 - (2 *sizeof(unsigned long int))];
|
|
};
|
|
struct in_addr{
|
|
unsigned char s_addr[4];
|
|
};
|
|
struct in6_addr{
|
|
unsigned char s6_addr[16];
|
|
};
|
|
struct sockaddr_in{
|
|
short sin_family;
|
|
unsigned short sin_port;
|
|
struct in_addr sin_addr;
|
|
char sin_zero[8];
|
|
} __attribute__ ((__packed__));
|
|
struct sockaddr_in6{
|
|
unsigned short sin6_family;
|
|
unsigned short sin6_port;
|
|
unsigned int sin6_flowinfo;
|
|
struct in6_addr sin6_addr;
|
|
unsigned int sin6_scope_id;
|
|
};
|
|
typedef unsigned short sa_family_t;
|
|
struct sockaddr_un {
|
|
sa_family_t sun_family;
|
|
char sun_path[108];
|
|
};
|
|
const char *inet_ntop(
|
|
int af,
|
|
const void *cp,
|
|
char *buf,
|
|
socklen_t len);
|
|
]]
|
|
|
|
function base32.pad(b32)
|
|
local m = #b32 % 8
|
|
if m ~= 0 then
|
|
b32 = b32 .. string.rep("=", 8 - m)
|
|
end
|
|
return b32
|
|
end
|
|
|
|
function str.starts(String,Start)
|
|
return string.sub(String,1,string.len(Start))==Start
|
|
end
|
|
|
|
-- Handle DoT signalling NS domains.
|
|
function M.layer.consume(state, _, pkt)
|
|
-- Only successful answers
|
|
if state == kres.FAIL then return state end
|
|
-- log_debug(ffi.C.LOG_GRP_DOTAUTH, "%s", pkt:tostring())
|
|
local authority = pkt:section(kres.section.AUTHORITY)
|
|
local additional = pkt:section(kres.section.ADDITIONAL)
|
|
for _, rr in ipairs(authority) do
|
|
--log_debug(ffi.C.LOG_GRP_DOTAUTH, "%d %s", rr.type, kres.dname2str(rr.rdata))
|
|
if rr.type == kres.type.NS then
|
|
local name = kres.dname2str(rr.rdata):upper()
|
|
-- log_debug(ffi.C.LOG_GRP_DOTAUTH, "NS %d", name:len())
|
|
if name:len() > 56 and str.starts(name, "DOT-") then
|
|
local k = basexx.to_base64(
|
|
basexx.from_base32(
|
|
base32.pad(string.sub(name, 5, string.find(name, '[.]') - 1))
|
|
)
|
|
)
|
|
for _, rr_add in ipairs(additional) do
|
|
if rr_add.type == kres.type.A or rr_add.type == kres.type.AAAA then
|
|
local name_add = kres.dname2str(rr_add.owner):upper()
|
|
if name == name_add then
|
|
local addrbuf
|
|
if rr_add.type == kres.type.A then
|
|
local ns_addr = ffi.new("struct sockaddr_in")
|
|
ns_addr.sin_family = AF_INET
|
|
|
|
ns_addr.sin_addr.s_addr = rr_add.rdata
|
|
addrbuf = ffi.new("char[?]", INET_ADDRSTRLEN)
|
|
C.inet_ntop(AF_INET, ns_addr.sin_addr, addrbuf, INET_ADDRSTRLEN)
|
|
else
|
|
local ns_addr = ffi.new("struct sockaddr_in6")
|
|
ns_addr.sin6_family = AF_INET6
|
|
|
|
ns_addr.sin6_addr.s6_addr = rr_add.rdata
|
|
addrbuf = ffi.new("char[?]", INET6_ADDRSTRLEN)
|
|
C.inet_ntop(AF_INET6, ns_addr.sin6_addr, addrbuf, INET6_ADDRSTRLEN)
|
|
end
|
|
net.tls_client(ffi.string(addrbuf).."@853", {k})
|
|
log_info(ffi.C.LOG_GRP_DOTAUTH, "Adding %s IP %s %s", name_add, ffi.string(addrbuf).."@853", k)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return state
|
|
|
|
end
|
|
|
|
return M
|