Skip to content

Commit c37abc2

Browse files
Tieskeagentzh
authored andcommitted
bugfix: fixed issues with retrans not being honoured upon connection failures.
feature: improved error reporting, making it more precise, and returning errors of previous tries. Signed-off-by: Yichun Zhang (agentzh) <agentzh@gmail.com>
1 parent f16e046 commit c37abc2

File tree

3 files changed

+142
-36
lines changed

3 files changed

+142
-36
lines changed

README.markdown

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,10 @@ server {
8585
return
8686
end
8787
88-
local answers, err = r:query("www.google.com")
88+
local answers, err, tries = r:query("www.google.com", nil, {})
8989
if not answers then
9090
ngx.say("failed to query the DNS server: ", err)
91+
ngx.say("retry historie:\n ", table.concat(tries, "\n "))
9192
return
9293
end
9394
@@ -138,7 +139,7 @@ It accepts a `opts` table argument. The following options are supported:
138139

139140
query
140141
-----
141-
`syntax: answers, err = r:query(name, options?)`
142+
`syntax: answers, err, tries? = r:query(name, options?, tries?)`
142143

143144
Performs a DNS standard query to the nameservers specified by the `new` method,
144145
and returns all the answer records in an array-like Lua table. In case of errors, it will
@@ -201,6 +202,10 @@ This method also takes an optional `options` argument table, which takes the fol
201202

202203
When set to a true value, the `answers` return value includes the `Additional` section of the DNS response. Default to `false`.
203204

205+
The optional parameter `tries` can be provided as an empty table, and will be
206+
returned as a third result. The table will be an array with the error message
207+
for each (if any) failed try.
208+
204209
When data truncation happens, the resolver will automatically retry using the TCP transport mode
205210
to query the current nameserver. All TCP connections are short lived.
206211

lib/resty/dns/resolver.lua

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ function _M.tcp_query(self, qname, opts)
830830
end
831831

832832

833-
function _M.query(self, qname, opts)
833+
function _M.query(self, qname, opts, tries)
834834
local socks = self.socks
835835
if not socks then
836836
return nil, "not initialized"
@@ -847,55 +847,60 @@ function _M.query(self, qname, opts)
847847
-- print("query: ", cjson.encode(concat(query, "")))
848848

849849
local retrans = self.retrans
850+
if tries then
851+
tries[1] = nil
852+
end
850853

851854
-- print("retrans: ", retrans)
852855

853856
for i = 1, retrans do
854857
local sock = pick_sock(self, socks)
855858

856-
local ok, err = sock:send(query)
859+
local ok
860+
ok, err = sock:send(query)
857861
if not ok then
858862
local server = _get_cur_server(self)
859-
return nil, "failed to send request to UDP server "
863+
err = "failed to send request to UDP server "
860864
.. concat(server, ":") .. ": " .. err
861-
end
862-
863-
local buf, err
864865

865-
for j = 1, 128 do
866-
buf, err = sock:receive(4096)
867-
868-
if err then
869-
break
870-
end
866+
else
867+
local buf
868+
869+
for _ = 1, 128 do
870+
buf, err = sock:receive(4096)
871+
if err then
872+
local server = _get_cur_server(self)
873+
err = "failed to receive reply from UDP server "
874+
.. concat(server, ":") .. ": " .. err
875+
break
876+
end
871877

872-
if buf then
873-
local answers
874-
answers, err = parse_response(buf, id, opts)
875-
if not answers then
878+
if buf then
879+
local answers
880+
answers, err = parse_response(buf, id, opts)
876881
if err == "truncated" then
877-
return _tcp_query(self, query, id, opts)
882+
answers, err = _tcp_query(self, query, id, opts)
878883
end
879884

880-
if err ~= "id mismatch" then
881-
return nil, err
885+
if err and err ~= "id mismatch" then
886+
break
882887
end
883888

884-
-- retry receiving when err == "id mismatch"
885-
else
886-
return answers
889+
if answers then
890+
return answers, nil, tries
891+
end
887892
end
893+
-- only here in case of an "id mismatch"
888894
end
889895
end
890896

891-
if err ~= "timeout" or i == retrans then
892-
local server = _get_cur_server(self)
893-
return nil, "failed to receive reply from UDP server "
894-
.. concat(server, ":") .. ": " .. err
897+
if tries then
898+
tries[i] = err
899+
tries[i + 1] = nil -- ensure termination for user supplied table
895900
end
896901
end
897902

898-
-- impossible to reach here
903+
return nil, err, tries
899904
end
900905

901906

t/mock.t

Lines changed: 103 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ records: []
130130
local resolver = require "resty.dns.resolver"
131131
132132
local r, err = resolver:new{
133-
nameservers = { {"127.0.0.1", 1953} }
133+
nameservers = { {"127.0.0.1", 1953} },
134+
retrans = 1,
134135
}
135136
if not r then
136137
ngx.say("failed to instantiate resolver: ", err)
@@ -166,7 +167,8 @@ connect() failed
166167
local resolver = require "resty.dns.resolver"
167168
168169
local r, err = resolver:new{
169-
nameservers = { {"127.0.0.1", 1953} }
170+
nameservers = { {"127.0.0.1", 1953} },
171+
retrans = 1,
170172
}
171173
if not r then
172174
ngx.say("failed to instantiate resolver: ", err)
@@ -297,7 +299,8 @@ records: [{"class":1,"cname":"blah.google.com","name":"www.google.com","section"
297299
local resolver = require "resty.dns.resolver"
298300
299301
local r, err = resolver:new{
300-
nameservers = { {"127.0.0.1", 1953} }
302+
nameservers = { {"127.0.0.1", 1953} },
303+
retrans = 1,
301304
}
302305
if not r then
303306
ngx.say("failed to instantiate resolver: ", err)
@@ -343,7 +346,8 @@ failed to query: bad cname record length: 17 ~= 3
343346
local resolver = require "resty.dns.resolver"
344347
345348
local r, err = resolver:new{
346-
nameservers = { {"127.0.0.1", 1953} }
349+
nameservers = { {"127.0.0.1", 1953} },
350+
retrans = 1,
347351
}
348352
if not r then
349353
ngx.say("failed to instantiate resolver: ", err)
@@ -387,7 +391,8 @@ failed to query: bad A record value length: 1
387391
local resolver = require "resty.dns.resolver"
388392
389393
local r, err = resolver:new{
390-
nameservers = { {"127.0.0.1", 1953} }
394+
nameservers = { {"127.0.0.1", 1953} },
395+
retrans = 1,
391396
}
392397
if not r then
393398
ngx.say("failed to instantiate resolver: ", err)
@@ -878,7 +883,7 @@ records: {"errcode":6,"errstr":"unknown"}
878883
879884
local r, err = resolver:new{
880885
nameservers = { {"127.0.0.1", 1953} },
881-
retrans = 3,
886+
retrans = 1,
882887
}
883888
if not r then
884889
ngx.say("failed to instantiate resolver: ", err)
@@ -924,7 +929,7 @@ connect() failed
924929
925930
local r, err = resolver:new{
926931
nameservers = { {"127.0.0.1", 1953} },
927-
retrans = 3,
932+
retrans = 1,
928933
}
929934
if not r then
930935
ngx.say("failed to instantiate resolver: ", err)
@@ -1787,3 +1792,94 @@ GET /t
17871792
records: [{"class":1,"expire":1800,"minimum":60,"mname":"ns3.google.com","name":"google.com","refresh":900,"retry":900,"rname":"dns-admin.google.com","section":1,"serial":175802026,"ttl":0,"type":6},{"address":"127.0.0.1","class":1,"name":"ns3.google.com","section":3,"ttl":0,"type":1}]
17881793
--- no_error_log
17891794
[error]
1795+
1796+
1797+
1798+
=== TEST 36: retry on connection failures
1799+
--- http_config eval: $::HttpConfig
1800+
--- config
1801+
location /t {
1802+
content_by_lua_block {
1803+
local resolver = require "resty.dns.resolver"
1804+
1805+
local r, err = resolver:new{
1806+
nameservers = { {"127.0.0.1", 20000} }, -- note: bad port
1807+
retrans = 3,
1808+
}
1809+
if not r then
1810+
ngx.say("failed to instantiate resolver: ", err)
1811+
return
1812+
end
1813+
1814+
r._id = 125
1815+
1816+
local ans, err, lst = r:query("www.google.com", { qtype = r.TYPE_A }, {})
1817+
if not ans then
1818+
ngx.say("failed to query: ", err, " ", (lst[#lst] == err))
1819+
for i, err in ipairs(lst) do
1820+
ngx.say(i, ": ", err)
1821+
end
1822+
return
1823+
end
1824+
-- should not reach here
1825+
}
1826+
}
1827+
--- request
1828+
GET /t
1829+
--- udp_query eval
1830+
"\x{00}}\x{01}\x{00}\x{00}\x{01}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{03}www\x{06}google\x{03}com\x{00}\x{00}\x{01}\x{00}\x{01}"
1831+
--- response_body
1832+
failed to query: failed to receive reply from UDP server 127.0.0.1:20000: connection refused true
1833+
1: failed to receive reply from UDP server 127.0.0.1:20000: connection refused
1834+
2: failed to receive reply from UDP server 127.0.0.1:20000: connection refused
1835+
3: failed to receive reply from UDP server 127.0.0.1:20000: connection refused
1836+
--- error_log
1837+
Connection refused
1838+
1839+
1840+
1841+
=== TEST 37: retry on connection failures, multiple servers
1842+
--- http_config eval: $::HttpConfig
1843+
--- config
1844+
location /t {
1845+
content_by_lua_block {
1846+
local resolver = require "resty.dns.resolver"
1847+
1848+
local r, err = resolver:new{
1849+
nameservers = { -- note: using bad ports
1850+
{"127.0.0.1", 20000},
1851+
{"127.0.0.1", 20001},
1852+
{"127.0.0.1", 20002},
1853+
},
1854+
retrans = 3,
1855+
}
1856+
if not r then
1857+
ngx.say("failed to instantiate resolver: ", err)
1858+
return
1859+
end
1860+
1861+
r._id = 125
1862+
1863+
local ans, err, lst = r:query("www.google.com", { qtype = r.TYPE_A }, {})
1864+
if not ans then
1865+
ngx.say("failed to query:")
1866+
table.sort(lst)
1867+
for i, err in ipairs(lst) do
1868+
ngx.say(i, ": ", err)
1869+
end
1870+
return
1871+
end
1872+
-- should not reach here
1873+
}
1874+
}
1875+
--- request
1876+
GET /t
1877+
--- udp_query eval
1878+
"\x{00}}\x{01}\x{00}\x{00}\x{01}\x{00}\x{00}\x{00}\x{00}\x{00}\x{00}\x{03}www\x{06}google\x{03}com\x{00}\x{00}\x{01}\x{00}\x{01}"
1879+
--- response_body
1880+
failed to query:
1881+
1: failed to receive reply from UDP server 127.0.0.1:20000: connection refused
1882+
2: failed to receive reply from UDP server 127.0.0.1:20001: connection refused
1883+
3: failed to receive reply from UDP server 127.0.0.1:20002: connection refused
1884+
--- error_log
1885+
Connection refused

0 commit comments

Comments
 (0)