Skip to content

Commit

Permalink
fix(client) resolve FQDNs ending in dots (#122)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tieske authored Mar 10, 2021
1 parent 6b34b59 commit 7107570
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 2 deletions.
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

0 comments on commit 7107570

Please sign in to comment.