diff --git a/README.md b/README.md index 186ff728c27e..ddb069641a16 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,11 @@ History Versioning is strictly based on [Semantic Versioning](https://semver.org/) +### 2.2.0 (xx-Sep-2018) unreleased... + +- Added: a new option `validTtl` that, if set, will forcefully override the + `ttl` value of any valid answer received. [Issue 48](https://github.com/Kong/lua-resty-dns-client/issues/48). + ### 2.1.0 (21-May-2018) Fixes - Fix: the round robin scheme for the balanceer starts at a randomized position diff --git a/spec/client_spec.lua b/spec/client_spec.lua index c04326e39abc..25262142d886 100644 --- a/spec/client_spec.lua +++ b/spec/client_spec.lua @@ -1144,6 +1144,44 @@ describe("DNS client", function() end) + it("verifies validTtl", function() + local validTtl = 0.1 + local emptyTtl = 0.1 + local staleTtl = 0.1 + local qname = "konghq.com" + assert(client.init({ + emptyTtl = emptyTtl, + staleTtl = staleTtl, + validTtl = validTtl, + resolvConf = { + -- resolv.conf without `search` and `domain` options + "nameserver 8.8.8.8", + }, + })) + + -- mock query function to return a default record + query_func = function(self, original_query_func, name, options) + return { + { + type = client.TYPE_A, + address = "5.6.7.8", + class = 1, + name = qname, + ttl = 10, -- should be overridden by the validTtl setting + }, + } + end + + -- do a query + local res1, _, _ = client.resolve( + qname, + { qtype = client.TYPE_A } + ) + + assert.equal(validTtl, res1[1].ttl) + assert.is_near(validTtl, res1.expire - gettime(), 0.1) + end) + it("verifies ttl and caching of empty responses and name errors", function() --empty/error responses should be cached for a configurable time local emptyTtl = 0.1 diff --git a/src/resty/dns/client.lua b/src/resty/dns/client.lua index 1f5d7d053fcb..806e75d0334b 100644 --- a/src/resty/dns/client.lua +++ b/src/resty/dns/client.lua @@ -53,6 +53,7 @@ local defined_hosts -- hash table to lookup names originating from the ho local emptyTtl -- ttl (in seconds) for empty and 'name error' (3) errors local badTtl -- ttl (in seconds) for a other dns error results local staleTtl -- ttl (in seconds) to serve stale data (while new lookup is in progress) +local validTtl -- ttl (in seconds) to use to override ttl of any valid answer local cacheSize -- size of the lru cache local noSynchronisation local orderValids = {"LAST", "SRV", "A", "AAAA", "CNAME"} -- default order to query @@ -161,11 +162,16 @@ local cacheinsert = function(entry, qname, qtype) -- an actual, non-empty, record key = (qtype or e1.type) .. ":" .. (qname or e1.name) - ttl = math.huge + ttl = validTtl or math.huge for i = 1, #entry do local record = entry[i] - -- determine minimum ttl of all answer records - ttl = math_min(ttl, record.ttl) + if validTtl then + -- force configured ttl + record.ttl = validTtl + else + -- determine minimum ttl of all answer records + ttl = math_min(ttl, record.ttl) + end -- update IPv6 address format to include square brackets if record.type == _M.TYPE_AAAA then record.address = utils.parseHostname(record.address) @@ -402,6 +408,9 @@ local poolMaxRetry -- -- Cache ttl for other error responses -- local badTtl = 1.0 -- in seconds (can have fractions) -- +-- -- Overriding ttl for valid queries, if given +-- local validTtl = nil -- in seconds (can have fractions) +-- -- -- `ndots`, same as the `resolv.conf` option, if not given it is taken from -- -- `resolv.conf` or otherwise set to 1 -- local ndots = 1 @@ -422,6 +431,7 @@ local poolMaxRetry -- badTtl = badTtl, -- emptyTtl = emptTtl, -- staleTtl = staleTtl, +-- validTtl = validTtl, -- enable_ipv6 = enable_ipv6, -- }) -- ) @@ -430,8 +440,13 @@ _M.init = function(options) log(DEBUG, PREFIX, "(re)configuring dns client") local resolv, hosts, err options = options or {} + staleTtl = options.staleTtl or 4 log(DEBUG, PREFIX, "staleTtl = ", staleTtl) + + validTtl = options.validTtl + log(DEBUG, PREFIX, "validTtl = ", tostring(validTtl)) + cacheSize = options.cacheSize or 10000 -- default set here to be able to reset the cache noSynchronisation = options.noSynchronisation log(DEBUG, PREFIX, "noSynchronisation = ", tostring(noSynchronisation))