From 3796a6b47ad060cadc3a5b01599efcfe2834da0e Mon Sep 17 00:00:00 2001 From: Aapo Talvensaari Date: Mon, 26 Feb 2024 19:20:23 +0200 Subject: [PATCH] fix(dns): resolv.conf options timeout: 0 is ignored ### Summary The `options timeout: 0` has a specific meaning in `resolv.conf`. It means that the request will be sent to all nameservers without waiting and whoever answers first, will be accepted. In Kong the `options timeout: 0` cause actually all the DNS queries themselves to timeout. This is bad as some platforms tend to follow `options timeout: 0` as a good practice when having more than one resolver. Kong should in future support parallel thread based resolving from multiple resolvers, but first we need to get this fix to stop it causing issues. Signed-off-by: Aapo Talvensaari --- .../kong/fix-dns-resolv-timeout-zero.yml | 3 +++ kong/resty/dns/client.lua | 12 ++++++++++-- t/03-dns-client/00-sanity.t | 19 ++++++++++++++++++- 3 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 changelog/unreleased/kong/fix-dns-resolv-timeout-zero.yml diff --git a/changelog/unreleased/kong/fix-dns-resolv-timeout-zero.yml b/changelog/unreleased/kong/fix-dns-resolv-timeout-zero.yml new file mode 100644 index 000000000000..8afed868f164 --- /dev/null +++ b/changelog/unreleased/kong/fix-dns-resolv-timeout-zero.yml @@ -0,0 +1,3 @@ +message: "**DNS Client**: ignore a non-positive values on resolv.conf for options timeout, and use a default value of 2 seconds instead." +type: bugfix +scope: Core diff --git a/kong/resty/dns/client.lua b/kong/resty/dns/client.lua index fcc92a4217d7..8c611031f199 100644 --- a/kong/resty/dns/client.lua +++ b/kong/resty/dns/client.lua @@ -32,6 +32,7 @@ local log = ngx.log local ERR = ngx.ERR local WARN = ngx.WARN local ALERT = ngx.ALERT +local NOTICE = ngx.NOTICE local DEBUG = ngx.DEBUG --[[ DEBUG = ngx.WARN @@ -54,6 +55,8 @@ local req_dyn_hook_run_hooks = req_dyn_hook.run_hooks local DOT = string_byte(".") local COLON = string_byte(":") +local DEFAULT_TIMEOUT = 2000 -- 2000 is openresty default + local EMPTY = setmetatable({}, {__newindex = function() error("The 'EMPTY' table is read-only") end}) @@ -621,10 +624,15 @@ _M.init = function(options) if resolv.options.timeout then options.timeout = resolv.options.timeout * 1000 else - options.timeout = 2000 -- 2000 is openresty default + options.timeout = DEFAULT_TIMEOUT end end - log(DEBUG, PREFIX, "timeout = ", options.timeout, " ms") + if options.timeout > 0 then + log(DEBUG, PREFIX, "timeout = ", options.timeout, " ms") + else + log(NOTICE, PREFIX, "timeout = ", DEFAULT_TIMEOUT, " ms (a non-positive timeout of ", options.timeout, " configured - using default timeout)") + options.timeout = DEFAULT_TIMEOUT + end -- setup the search order options.ndots = options.ndots or resolv.options.ndots or 1 diff --git a/t/03-dns-client/00-sanity.t b/t/03-dns-client/00-sanity.t index 0c365c576efd..2856ea84b08a 100644 --- a/t/03-dns-client/00-sanity.t +++ b/t/03-dns-client/00-sanity.t @@ -2,7 +2,7 @@ use strict; use warnings FATAL => 'all'; use Test::Nginx::Socket::Lua; -plan tests => 2; +plan tests => 5; run_tests(); @@ -25,3 +25,20 @@ GET /t --- response_body 127.0.0.1 --- no_error_log + + + +=== TEST 2: load lua-resty-dns-client +--- config + location = /t { + access_by_lua_block { + local client = require("kong.resty.dns.client") + assert(client.init({ timeout = 0 })) + ngx.exit(200) + } + } +--- request +GET /t +--- error_log +[notice] +timeout = 2000 ms (a non-positive timeout of 0 configured - using default timeout)