net/resolvers/service.lua
author Kim Alvefur <zash@zash.se>
Sun, 24 Nov 2019 04:43:14 +0100
changeset 10444 1ee87b4979c2
parent 10405 1ef1f6c43c5b
child 10488 b13a31cea7d9
permissions -rw-r--r--
net.resolvers.service: Pass IP literals directly to basic resolver IP literals will not work with SRV records anyways. Fixes s2s with IP literals.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     1
local adns = require "net.adns";
9391
a5d11627ce5d net.resolvers.service: net.connect resolver that uses SRV records
Kim Alvefur <zash@zash.se>
parents: 8778
diff changeset
     2
local basic = require "net.resolvers.basic";
10444
1ee87b4979c2 net.resolvers.service: Pass IP literals directly to basic resolver
Kim Alvefur <zash@zash.se>
parents: 10405
diff changeset
     3
local inet_pton = require "util.net".pton;
10388
94c9c574cd8a net.resolvers: Apply IDNA conversion to ascii for DNS lookups (fixes #1426)
Kim Alvefur <zash@zash.se>
parents: 9400
diff changeset
     4
local idna_to_ascii = require "util.encodings".idna.to_ascii;
9695
e11e076f0eb8 various: Don't rely on _G.unpack existing
Kim Alvefur <zash@zash.se>
parents: 9400
diff changeset
     5
local unpack = table.unpack or unpack; -- luacheck: ignore 113
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     6
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     7
local methods = {};
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     8
local resolver_mt = { __index = methods };
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     9
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    10
-- Find the next target to connect to, and
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    11
-- pass it to cb()
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    12
function methods:next(cb)
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    13
	if self.targets then
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    14
		if #self.targets == 0 then
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    15
			cb(nil);
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    16
			return;
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    17
		end
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    18
		local next_target = table.remove(self.targets, 1);
9391
a5d11627ce5d net.resolvers.service: net.connect resolver that uses SRV records
Kim Alvefur <zash@zash.se>
parents: 8778
diff changeset
    19
		self.resolver = basic.new(unpack(next_target, 1, 4));
a5d11627ce5d net.resolvers.service: net.connect resolver that uses SRV records
Kim Alvefur <zash@zash.se>
parents: 8778
diff changeset
    20
		self.resolver:next(function (...)
a5d11627ce5d net.resolvers.service: net.connect resolver that uses SRV records
Kim Alvefur <zash@zash.se>
parents: 8778
diff changeset
    21
			if ... == nil then
a5d11627ce5d net.resolvers.service: net.connect resolver that uses SRV records
Kim Alvefur <zash@zash.se>
parents: 8778
diff changeset
    22
				self:next(cb);
a5d11627ce5d net.resolvers.service: net.connect resolver that uses SRV records
Kim Alvefur <zash@zash.se>
parents: 8778
diff changeset
    23
			else
a5d11627ce5d net.resolvers.service: net.connect resolver that uses SRV records
Kim Alvefur <zash@zash.se>
parents: 8778
diff changeset
    24
				cb(...);
a5d11627ce5d net.resolvers.service: net.connect resolver that uses SRV records
Kim Alvefur <zash@zash.se>
parents: 8778
diff changeset
    25
			end
a5d11627ce5d net.resolvers.service: net.connect resolver that uses SRV records
Kim Alvefur <zash@zash.se>
parents: 8778
diff changeset
    26
		end);
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    27
		return;
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    28
	end
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    29
10389
62a7042e0771 net.resolvers: Abort on hostnames not passing IDNA validation
Kim Alvefur <zash@zash.se>
parents: 10388
diff changeset
    30
	if not self.hostname then
62a7042e0771 net.resolvers: Abort on hostnames not passing IDNA validation
Kim Alvefur <zash@zash.se>
parents: 10388
diff changeset
    31
		-- FIXME report IDNA error
62a7042e0771 net.resolvers: Abort on hostnames not passing IDNA validation
Kim Alvefur <zash@zash.se>
parents: 10388
diff changeset
    32
		cb(nil);
10404
4c2d789a106b net.resolvers: Fix traceback from hostname failing IDNA
Kim Alvefur <zash@zash.se>
parents: 10389
diff changeset
    33
		return;
10389
62a7042e0771 net.resolvers: Abort on hostnames not passing IDNA validation
Kim Alvefur <zash@zash.se>
parents: 10388
diff changeset
    34
	end
62a7042e0771 net.resolvers: Abort on hostnames not passing IDNA validation
Kim Alvefur <zash@zash.se>
parents: 10388
diff changeset
    35
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    36
	local targets = {};
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    37
	local function ready()
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    38
		self.targets = targets;
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    39
		self:next(cb);
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    40
	end
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    41
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    42
	-- Resolve DNS to target list
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    43
	local dns_resolver = adns.resolver();
10125
33f287519bf6 net.resolvers.service: Fix DNS fallback
Kim Alvefur <zash@zash.se>
parents: 9695
diff changeset
    44
	dns_resolver:lookup(function (answer, err)
33f287519bf6 net.resolvers.service: Fix DNS fallback
Kim Alvefur <zash@zash.se>
parents: 9695
diff changeset
    45
		if not answer and not err then
33f287519bf6 net.resolvers.service: Fix DNS fallback
Kim Alvefur <zash@zash.se>
parents: 9695
diff changeset
    46
			-- net.adns returns nil if there are zero records or nxdomain
33f287519bf6 net.resolvers.service: Fix DNS fallback
Kim Alvefur <zash@zash.se>
parents: 9695
diff changeset
    47
			answer = {};
33f287519bf6 net.resolvers.service: Fix DNS fallback
Kim Alvefur <zash@zash.se>
parents: 9695
diff changeset
    48
		end
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    49
		if answer then
9396
e2733f504d9e net.resolvers.service: Early return on empty result set
Kim Alvefur <zash@zash.se>
parents: 9395
diff changeset
    50
			if #answer == 0 then
9397
bcd94cc355d3 net.resolvers.service: Add support for fallback to bare domain and default port
Kim Alvefur <zash@zash.se>
parents: 9396
diff changeset
    51
				if self.extra and self.extra.default_port then
9398
794eda565c69 net.resolvers.service: Rename internal variable since net.connect uses it for __tostring
Kim Alvefur <zash@zash.se>
parents: 9397
diff changeset
    52
					table.insert(targets, { self.hostname, self.extra.default_port, self.conn_type, self.extra });
9397
bcd94cc355d3 net.resolvers.service: Add support for fallback to bare domain and default port
Kim Alvefur <zash@zash.se>
parents: 9396
diff changeset
    53
				end
9396
e2733f504d9e net.resolvers.service: Early return on empty result set
Kim Alvefur <zash@zash.se>
parents: 9395
diff changeset
    54
				ready();
e2733f504d9e net.resolvers.service: Early return on empty result set
Kim Alvefur <zash@zash.se>
parents: 9395
diff changeset
    55
				return;
e2733f504d9e net.resolvers.service: Early return on empty result set
Kim Alvefur <zash@zash.se>
parents: 9395
diff changeset
    56
			end
e2733f504d9e net.resolvers.service: Early return on empty result set
Kim Alvefur <zash@zash.se>
parents: 9395
diff changeset
    57
9395
f2d71e4284b7 net.resolvers.service: Understand when service is explicitly unavailable
Kim Alvefur <zash@zash.se>
parents: 9391
diff changeset
    58
			if #answer == 1 and answer[1].srv.target == "." then -- No service here
f2d71e4284b7 net.resolvers.service: Understand when service is explicitly unavailable
Kim Alvefur <zash@zash.se>
parents: 9391
diff changeset
    59
				ready();
f2d71e4284b7 net.resolvers.service: Understand when service is explicitly unavailable
Kim Alvefur <zash@zash.se>
parents: 9391
diff changeset
    60
				return;
f2d71e4284b7 net.resolvers.service: Understand when service is explicitly unavailable
Kim Alvefur <zash@zash.se>
parents: 9391
diff changeset
    61
			end
f2d71e4284b7 net.resolvers.service: Understand when service is explicitly unavailable
Kim Alvefur <zash@zash.se>
parents: 9391
diff changeset
    62
9400
e09ddd061ec4 net.resolvers.service: Sort SRV records in correct direction
Kim Alvefur <zash@zash.se>
parents: 9399
diff changeset
    63
			table.sort(answer, function (a, b) return a.srv.priority < b.srv.priority end);
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    64
			for _, record in ipairs(answer) do
9391
a5d11627ce5d net.resolvers.service: net.connect resolver that uses SRV records
Kim Alvefur <zash@zash.se>
parents: 8778
diff changeset
    65
				table.insert(targets, { record.srv.target, record.srv.port, self.conn_type, self.extra });
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    66
			end
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    67
		end
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    68
		ready();
9398
794eda565c69 net.resolvers.service: Rename internal variable since net.connect uses it for __tostring
Kim Alvefur <zash@zash.se>
parents: 9397
diff changeset
    69
	end, "_" .. self.service .. "._" .. self.conn_type .. "." .. self.hostname, "SRV", "IN");
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    70
end
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    71
9398
794eda565c69 net.resolvers.service: Rename internal variable since net.connect uses it for __tostring
Kim Alvefur <zash@zash.se>
parents: 9397
diff changeset
    72
local function new(hostname, service, conn_type, extra)
10444
1ee87b4979c2 net.resolvers.service: Pass IP literals directly to basic resolver
Kim Alvefur <zash@zash.se>
parents: 10405
diff changeset
    73
	local is_ip = inet_pton(hostname);
1ee87b4979c2 net.resolvers.service: Pass IP literals directly to basic resolver
Kim Alvefur <zash@zash.se>
parents: 10405
diff changeset
    74
	if not is_ip and hostname:sub(1,1) == '[' then
1ee87b4979c2 net.resolvers.service: Pass IP literals directly to basic resolver
Kim Alvefur <zash@zash.se>
parents: 10405
diff changeset
    75
		is_ip = inet_pton(hostname:sub(2,-2));
1ee87b4979c2 net.resolvers.service: Pass IP literals directly to basic resolver
Kim Alvefur <zash@zash.se>
parents: 10405
diff changeset
    76
	end
1ee87b4979c2 net.resolvers.service: Pass IP literals directly to basic resolver
Kim Alvefur <zash@zash.se>
parents: 10405
diff changeset
    77
	if is_ip and extra and extra.default_port then
1ee87b4979c2 net.resolvers.service: Pass IP literals directly to basic resolver
Kim Alvefur <zash@zash.se>
parents: 10405
diff changeset
    78
		return basic.new(hostname, extra.default_port, conn_type, extra);
1ee87b4979c2 net.resolvers.service: Pass IP literals directly to basic resolver
Kim Alvefur <zash@zash.se>
parents: 10405
diff changeset
    79
	end
1ee87b4979c2 net.resolvers.service: Pass IP literals directly to basic resolver
Kim Alvefur <zash@zash.se>
parents: 10405
diff changeset
    80
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    81
	return setmetatable({
10388
94c9c574cd8a net.resolvers: Apply IDNA conversion to ascii for DNS lookups (fixes #1426)
Kim Alvefur <zash@zash.se>
parents: 9400
diff changeset
    82
		hostname = idna_to_ascii(hostname);
9391
a5d11627ce5d net.resolvers.service: net.connect resolver that uses SRV records
Kim Alvefur <zash@zash.se>
parents: 8778
diff changeset
    83
		service = service;
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    84
		conn_type = conn_type or "tcp";
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    85
		extra = extra;
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    86
	}, resolver_mt);
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    87
end
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    88
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    89
return {
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    90
	new = new;
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    91
};