diff options
Diffstat (limited to 'net/resolvers')
-rw-r--r-- | net/resolvers/basic.lua | 88 | ||||
-rw-r--r-- | net/resolvers/manual.lua | 1 | ||||
-rw-r--r-- | net/resolvers/service.lua | 47 |
3 files changed, 115 insertions, 21 deletions
diff --git a/net/resolvers/basic.lua b/net/resolvers/basic.lua index 867ccf60..305bce76 100644 --- a/net/resolvers/basic.lua +++ b/net/resolvers/basic.lua @@ -2,10 +2,13 @@ local adns = require "net.adns"; local inet_pton = require "util.net".pton; local inet_ntop = require "util.net".ntop; local idna_to_ascii = require "util.encodings".idna.to_ascii; +local unpack = table.unpack or unpack; -- luacheck: ignore 113 local methods = {}; local resolver_mt = { __index = methods }; +-- FIXME RFC 6724 + -- Find the next target to connect to, and -- pass it to cb() function methods:next(cb) @@ -20,39 +23,96 @@ function methods:next(cb) end if not self.hostname then - -- FIXME report IDNA error + self.last_error = "hostname failed IDNA"; cb(nil); return; end + local secure = true; + local tlsa = {}; local targets = {}; - local n = 2; + local n = 3; local function ready() n = n - 1; if n > 0 then return; end self.targets = targets; + if self.extra and self.extra.use_dane then + if secure and tlsa[1] then + self.extra.tlsa = tlsa; + self.extra.dane_hostname = self.hostname; + else + self.extra.tlsa = nil; + self.extra.dane_hostname = nil; + end + end self:next(cb); end -- Resolve DNS to target list local dns_resolver = adns.resolver(); - dns_resolver:lookup(function (answer) - if answer then - for _, record in ipairs(answer) do - table.insert(targets, { self.conn_type.."4", record.a, self.port, self.extra }); + + if not self.extra or self.extra.use_ipv4 ~= false then + dns_resolver:lookup(function (answer, err) + if answer then + secure = secure and answer.secure; + for _, record in ipairs(answer) do + table.insert(targets, { self.conn_type.."4", record.a, self.port, self.extra }); + end + if answer.bogus then + self.last_error = "Validation error in A lookup"; + elseif answer.status then + self.last_error = answer.status .. " in A lookup"; + end + else + self.last_error = err; end - end + ready(); + end, self.hostname, "A", "IN"); + else + ready(); + end + + if not self.extra or self.extra.use_ipv6 ~= false then + dns_resolver:lookup(function (answer, err) + if answer then + secure = secure and answer.secure; + for _, record in ipairs(answer) do + table.insert(targets, { self.conn_type.."6", record.aaaa, self.port, self.extra }); + end + if answer.bogus then + self.last_error = "Validation error in AAAA lookup"; + elseif answer.status then + self.last_error = answer.status .. " in AAAA lookup"; + end + else + self.last_error = err; + end + ready(); + end, self.hostname, "AAAA", "IN"); + else ready(); - end, self.hostname, "A", "IN"); + end - dns_resolver:lookup(function (answer) - if answer then - for _, record in ipairs(answer) do - table.insert(targets, { self.conn_type.."6", record.aaaa, self.port, self.extra }); + if self.extra and self.extra.use_dane == true then + dns_resolver:lookup(function (answer, err) + if answer then + secure = secure and answer.secure; + for _, record in ipairs(answer) do + table.insert(tlsa, record.tlsa); + end + if answer.bogus then + self.last_error = "Validation error in TLSA lookup"; + elseif answer.status then + self.last_error = answer.status .. " in TLSA lookup"; + end + else + self.last_error = err; end - end + ready(); + end, ("_%d._tcp.%s"):format(self.port, self.hostname), "TLSA", "IN"); + else ready(); - end, self.hostname, "AAAA", "IN"); + end end local function new(hostname, port, conn_type, extra) diff --git a/net/resolvers/manual.lua b/net/resolvers/manual.lua index c0d4e5d5..dbc40256 100644 --- a/net/resolvers/manual.lua +++ b/net/resolvers/manual.lua @@ -1,5 +1,6 @@ local methods = {}; local resolver_mt = { __index = methods }; +local unpack = table.unpack or unpack; -- luacheck: ignore 113 -- Find the next target to connect to, and -- pass it to cb() diff --git a/net/resolvers/service.lua b/net/resolvers/service.lua index 34f14cba..3810cac8 100644 --- a/net/resolvers/service.lua +++ b/net/resolvers/service.lua @@ -1,6 +1,8 @@ local adns = require "net.adns"; local basic = require "net.resolvers.basic"; +local inet_pton = require "util.net".pton; local idna_to_ascii = require "util.encodings".idna.to_ascii; +local unpack = table.unpack or unpack; -- luacheck: ignore 113 local methods = {}; local resolver_mt = { __index = methods }; @@ -9,14 +11,20 @@ local resolver_mt = { __index = methods }; -- pass it to cb() function methods:next(cb) if self.targets then - if #self.targets == 0 then - cb(nil); - return; + if not self.resolver then + if #self.targets == 0 then + cb(nil); + return; + end + local next_target = table.remove(self.targets, 1); + self.resolver = basic.new(unpack(next_target, 1, 4)); end - local next_target = table.remove(self.targets, 1); - self.resolver = basic.new(unpack(next_target, 1, 4)); self.resolver:next(function (...) + if self.resolver then + self.last_error = self.resolver.last_error; + end if ... == nil then + self.resolver = nil; self:next(cb); else cb(...); @@ -26,7 +34,7 @@ function methods:next(cb) end if not self.hostname then - -- FIXME report IDNA error + self.last_error = "hostname failed IDNA"; cb(nil); return; end @@ -39,17 +47,32 @@ function methods:next(cb) -- Resolve DNS to target list local dns_resolver = adns.resolver(); - dns_resolver:lookup(function (answer) + dns_resolver:lookup(function (answer, err) + if not answer and not err then + -- net.adns returns nil if there are zero records or nxdomain + answer = {}; + end if answer then + if self.extra and not answer.secure then + self.extra.use_dane = false; + elseif answer.bogus then + self.last_error = "Validation error in SRV lookup"; + ready(); + return; + end + if #answer == 0 then if self.extra and self.extra.default_port then table.insert(targets, { self.hostname, self.extra.default_port, self.conn_type, self.extra }); + else + self.last_error = "zero SRV records found"; end ready(); return; end if #answer == 1 and answer[1].srv.target == "." then -- No service here + self.last_error = "service explicitly unavailable"; ready(); return; end @@ -58,12 +81,22 @@ function methods:next(cb) for _, record in ipairs(answer) do table.insert(targets, { record.srv.target, record.srv.port, self.conn_type, self.extra }); end + else + self.last_error = err; end ready(); end, "_" .. self.service .. "._" .. self.conn_type .. "." .. self.hostname, "SRV", "IN"); end local function new(hostname, service, conn_type, extra) + local is_ip = inet_pton(hostname); + if not is_ip and hostname:sub(1,1) == '[' then + is_ip = inet_pton(hostname:sub(2,-2)); + end + if is_ip and extra and extra.default_port then + return basic.new(hostname, extra.default_port, conn_type, extra); + end + return setmetatable({ hostname = idna_to_ascii(hostname); service = service; |