Skip to content
This repository has been archived by the owner on Jul 11, 2023. It is now read-only.

fix(client) resolve FQDNs ending in dots #122

Merged
merged 1 commit into from
Mar 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions spec/client_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,73 @@ describe("[DNS client]", function()

end)

describe("FQDN without type", function()
it("works with a 'search' option", function()
assert(client.init({
resolvConf = {
"nameserver 8.8.8.8",
"search one.com two.com",
"options ndots:1",
}
}))
local list = {}
for qname, qtype in client._search_iter("host.", nil) do
table.insert(list, tostring(qname)..":"..tostring(qtype))
end
assert.same({
'host.:33',
'host.:1',
'host.:28',
'host.:5',
}, list)
end)

it("works with a 'domain' option", function()
assert(client.init({
resolvConf = {
"nameserver 8.8.8.8",
"domain local.domain.com",
"options ndots:1",
}
}))
local list = {}
for qname, qtype in client._search_iter("host.", nil) do
table.insert(list, tostring(qname)..":"..tostring(qtype))
end
assert.same({
'host.:33',
'host.:1',
'host.:28',
'host.:5',
}, list)
end)

it("handles last successful type", function()
assert(client.init({
resolvConf = {
"nameserver 8.8.8.8",
"search one.com two.com",
"options ndots:1",
}
}))
local lrucache = client.getcache()
-- insert a last successful type
local hostname = "host."
lrucache:set(hostname, client.TYPE_CNAME)
local list = {}
for qname, qtype in client._search_iter(hostname, nil) do
table.insert(list, tostring(qname)..":"..tostring(qtype))
end
assert.same({
'host.:5',
'host.:33',
'host.:1',
'host.:28',
}, list)
end)

end)

describe("with type", function()
it("works with a 'search' option", function()
assert(client.init({
Expand Down Expand Up @@ -329,6 +396,65 @@ describe("[DNS client]", function()

end)

describe("FQDN with type", function()
it("works with a 'search' option", function()
assert(client.init({
resolvConf = {
"nameserver 8.8.8.8",
"search one.com two.com",
"options ndots:1",
}
}))
local list = {}
-- search using IPv6 type
for qname, qtype in client._search_iter("host.", client.TYPE_AAAA) do
table.insert(list, tostring(qname)..":"..tostring(qtype))
end
assert.same({
'host.:28',
}, list)
end)

it("works with a 'domain' option", function()
assert(client.init({
resolvConf = {
"nameserver 8.8.8.8",
"domain local.domain.com",
"options ndots:1",
}
}))
local list = {}
-- search using IPv6 type
for qname, qtype in client._search_iter("host.", client.TYPE_AAAA) do
table.insert(list, tostring(qname)..":"..tostring(qtype))
end
assert.same({
'host.:28',
}, list)
end)

it("ignores last successful type", function()
assert(client.init({
resolvConf = {
"nameserver 8.8.8.8",
"search one.com two.com",
"options ndots:1",
}
}))
-- insert a last successful type
client.getcache()["host"] = client.TYPE_CNAME
local list = {}
-- search using IPv6 type
for qname, qtype in client._search_iter("host.", client.TYPE_AAAA) do
table.insert(list, tostring(qname)..":"..tostring(qtype))
end
assert.same({
'host.:28',
}, list)
end)

end)

it("honours 'ndots'", function()
assert(client.init({
resolvConf = {
Expand Down Expand Up @@ -430,6 +556,18 @@ describe("[DNS client]", function()
assert.are.equal(#answers, 1)
end)

it("fetching a CNAME record FQDN", function()
assert(client.init())

local host = "smtp.thijsschreijer.nl"
local typ = client.TYPE_CNAME

local answers = assert(client.resolve(host .. ".", { qtype = typ }))
assert.are.equal(host, answers[1].name)
assert.are.equal(typ, answers[1].type)
assert.are.equal(#answers, 1)
end)

it("expire and touch times", function()
assert(client.init())

Expand Down Expand Up @@ -500,6 +638,20 @@ describe("[DNS client]", function()
assert.are.equal(typ, answers[2].type)
end)

it("fetching multiple A records FQDN", function()
assert(client.init())

local host = "atest.thijsschreijer.nl"
local typ = client.TYPE_A

local answers = assert(client.resolve(host .. ".", { qtype = typ }))
assert.are.equal(#answers, 2)
assert.are.equal(host, answers[1].name)
assert.are.equal(typ, answers[1].type)
assert.are.equal(host, answers[2].name)
assert.are.equal(typ, answers[2].type)
end)

it("fetching A record redirected through 2 CNAME records (un-typed)", function()
assert(client.init())
local lrucache = client.getcache()
Expand Down
13 changes: 13 additions & 0 deletions spec/utils_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,11 @@ options ndots:2
assert.are.same("ipv6", dnsutils.hostnameType("2345::6789"))
assert.are.same("ipv6", dnsutils.hostnameType("0001:0001:0001:0001:0001:0001:0001:0001"))
end)
it("checks valid FQDN address types", function()
assert.are.same("name", dnsutils.hostnameType("konghq."))
assert.are.same("name", dnsutils.hostnameType("konghq.com."))
assert.are.same("name", dnsutils.hostnameType("www.konghq.com."))
end)
end)

describe("parseHostname", function()
Expand All @@ -368,6 +373,14 @@ options ndots:2
assert.are.same({"somename456.domain.local789", nil, "name"}, {dnsutils.parseHostname("somename456.domain.local789")})
assert.are.same({"somename456.domain.local789", 123, "name"}, {dnsutils.parseHostname("somename456.domain.local789:123")})
end)
it("parses valid FQDN address types", function()
assert.are.same({"somename.", nil, "name"}, {dnsutils.parseHostname("somename.")})
assert.are.same({"somename.", 123, "name"}, {dnsutils.parseHostname("somename.:123")})
assert.are.same({"somename456.", nil, "name"}, {dnsutils.parseHostname("somename456.")})
assert.are.same({"somename456.", 123, "name"}, {dnsutils.parseHostname("somename456.:123")})
assert.are.same({"somename456.domain.local789.", nil, "name"}, {dnsutils.parseHostname("somename456.domain.local789.")})
assert.are.same({"somename456.domain.local789.", 123, "name"}, {dnsutils.parseHostname("somename456.domain.local789.:123")})
end)
end)

end)
21 changes: 19 additions & 2 deletions src/resty/dns/client.lua
Original file line number Diff line number Diff line change
Expand Up @@ -626,13 +626,23 @@ local function parseAnswer(qname, qtype, answers, try_list)
-- eg. A, AAAA, SRV records may be accompanied by CNAME records
-- store them all, leaving only the requested type in so we can return that set
local others = {}

-- remove last '.' from FQDNs as the answer does not contain it
local check_qname do
if qname:sub(-1, -1) == "." then
check_qname = qname:sub(1, -2) -- FQDN, drop the last dot
else
check_qname = qname
end
end

for i = #answers, 1, -1 do -- we're deleting entries, so reverse the traversal
local answer = answers[i]

-- normalize casing
answer.name = string_lower(answer.name)

if (answer.type ~= qtype) or (answer.name ~= qname) then
if (answer.type ~= qtype) or (answer.name ~= check_qname) then
local key = answer.type..":"..answer.name
try_status(try_list, key .. " removed")
local lst = others[key]
Expand Down Expand Up @@ -987,7 +997,14 @@ local function search_iter(qname, qtype)
type_end = #type_list

local i_type = type_start
local search = config.search
local search do
if qname:sub(-1, -1) == "." then
-- this is a FQDN, so no searches
search = {}
else
search = config.search
end
end
local i_search, search_start, search_end
local type_done = {}
local type_current
Expand Down