File 3681-kernel-Add-new-option-servfail_retry_timeout.patch of Package erlang
From 4441e664e84c45030d67e27ab3f56bd35bcec541 Mon Sep 17 00:00:00 2001
From: Micael Karlberg <bmk@erlang.org>
Date: Mon, 26 Oct 2020 14:58:02 +0100
Subject: [PATCH 1/6] [kernel] Add new option 'servfail_retry_timeout'
As of version NNN of the DNS server, there is a servfail cache
which has the servfail-ttl default value of 1 sec.
This means if the agent is "to eager" after a servfail, it will
just get the cache'd value (that is, no dns lookup is attempted).
To avoid the situation, a new config option has been added;
servfail_retry_timeout (with default 1500 = 1.5 sec), which
defines the timeout after each failed query, before attempting
a new query.
OTP-16956
---
lib/kernel/src/inet_db.erl | 133 +++++++++++++++++++++++++++---------
lib/kernel/src/inet_res.erl | 12 +++-
lib/kernel/src/inet_res.hrl | 46 +++++++++----
3 files changed, 146 insertions(+), 45 deletions(-)
diff --git a/lib/kernel/src/inet_db.erl b/lib/kernel/src/inet_db.erl
index 814c3f4276..ff5bdd8f26 100644
--- a/lib/kernel/src/inet_db.erl
+++ b/lib/kernel/src/inet_db.erl
@@ -44,7 +44,8 @@
del_socks_methods/1, del_socks_methods/0,
add_socks_noproxy/1, del_socks_noproxy/1]).
-export([set_cache_size/1, set_cache_refresh/1]).
--export([set_timeout/1, set_retry/1, set_inet6/1, set_usevc/1]).
+-export([set_timeout/1, set_retry/1, set_servfail_retry_timeout/1,
+ set_inet6/1, set_usevc/1]).
-export([set_edns/1, set_udp_payload_size/1]).
-export([set_resolv_conf/1, set_hosts_file/1, get_hosts_file/0]).
-export([tcp_module/0, set_tcp_module/1]).
@@ -221,6 +222,9 @@ set_timeout(Time) -> res_option(timeout, Time).
set_retry(N) -> res_option(retry, N).
+set_servfail_retry_timeout(Time) when is_integer(Time) andalso (Time >= 0) ->
+ res_option(servfail_retry_timeout, Time).
+
set_inet6(Bool) -> res_option(inet6, Bool).
set_usevc(Bool) -> res_option(usevc, Bool).
@@ -313,42 +317,104 @@ valid_lookup() -> [dns, file, yp, nis, nisplus, native].
%% Reconstruct an inetrc structure from inet_db
get_rc() ->
get_rc([hosts, domain, nameservers, search, alt_nameservers,
- timeout, retry, inet6, usevc,
+ timeout, retry, servfail_retry_timeout, inet6, usevc,
edns, udp_payload_size, resolv_conf, hosts_file,
socks5_server, socks5_port, socks5_methods, socks5_noproxy,
udp, sctp, tcp, host, cache_size, cache_refresh, lookup], []).
get_rc([K | Ks], Ls) ->
case K of
- hosts -> get_rc_hosts(Ks, Ls, inet_hosts_byaddr);
- domain -> get_rc(domain, res_domain, "", Ks, Ls);
- nameservers -> get_rc_ns(db_get(res_ns),nameservers,Ks,Ls);
- alt_nameservers -> get_rc_ns(db_get(res_alt_ns),alt_nameservers,Ks,Ls);
- search -> get_rc(search, res_search, [], Ks, Ls);
- timeout -> get_rc(timeout,res_timeout,?RES_TIMEOUT, Ks,Ls);
- retry -> get_rc(retry, res_retry, ?RES_RETRY, Ks, Ls);
- inet6 -> get_rc(inet6, res_inet6, false, Ks, Ls);
- usevc -> get_rc(usevc, res_usevc, false, Ks, Ls);
- edns -> get_rc(edns, res_edns, false, Ks, Ls);
- udp_payload_size -> get_rc(udp_payload_size, res_udp_payload_size,
- ?DNS_UDP_PAYLOAD_SIZE, Ks, Ls);
- resolv_conf -> get_rc(resolv_conf, res_resolv_conf, undefined, Ks, Ls);
- hosts_file -> get_rc(hosts_file, res_hosts_file, undefined, Ks, Ls);
- tcp -> get_rc(tcp, tcp_module, ?DEFAULT_TCP_MODULE, Ks, Ls);
- udp -> get_rc(udp, udp_module, ?DEFAULT_UDP_MODULE, Ks, Ls);
- sctp -> get_rc(sctp, sctp_module, ?DEFAULT_SCTP_MODULE, Ks, Ls);
- lookup -> get_rc(lookup, res_lookup, [native,file], Ks, Ls);
- cache_size -> get_rc(cache_size, cache_size, ?CACHE_LIMIT, Ks, Ls);
- cache_refresh ->
- get_rc(cache_refresh, cache_refresh_interval,?CACHE_REFRESH,Ks,Ls);
- socks5_server -> get_rc(socks5_server, socks5_server, "", Ks, Ls);
- socks5_port -> get_rc(socks5_port,socks5_port,?IPPORT_SOCKS,Ks,Ls);
- socks5_methods -> get_rc(socks5_methods,socks5_methods,[none],Ks,Ls);
- socks5_noproxy ->
- case db_get(socks5_noproxy) of
- [] -> get_rc(Ks, Ls);
- NoProxy -> get_rc_noproxy(NoProxy, Ks, Ls)
- end;
+ hosts -> get_rc_hosts(Ks, Ls, inet_hosts_byaddr);
+ domain -> get_rc(domain,
+ res_domain,
+ "",
+ Ks, Ls);
+ nameservers -> get_rc_ns(db_get(res_ns),
+ nameservers,
+ Ks, Ls);
+ alt_nameservers -> get_rc_ns(db_get(res_alt_ns),
+ alt_nameservers,
+ Ks, Ls);
+ search -> get_rc(search,
+ res_search,
+ [],
+ Ks, Ls);
+ timeout -> get_rc(timeout,
+ res_timeout,
+ ?RES_TIMEOUT,
+ Ks, Ls);
+ retry -> get_rc(retry,
+ res_retry,
+ ?RES_RETRY,
+ Ks, Ls);
+ servfail_retry_timeout -> get_rc(servfail_retry_timeout,
+ res_servfail_retry_timeout,
+ ?RES_SERVFAIL_RETRY_TO,
+ Ks, Ls);
+ inet6 -> get_rc(inet6,
+ res_inet6,
+ false,
+ Ks, Ls);
+ usevc -> get_rc(usevc,
+ res_usevc,
+ false,
+ Ks, Ls);
+ edns -> get_rc(edns,
+ res_edns,
+ false,
+ Ks, Ls);
+ udp_payload_size -> get_rc(udp_payload_size,
+ res_udp_payload_size,
+ ?DNS_UDP_PAYLOAD_SIZE,
+ Ks, Ls);
+ resolv_conf -> get_rc(resolv_conf,
+ res_resolv_conf,
+ undefined,
+ Ks, Ls);
+ hosts_file -> get_rc(hosts_file,
+ res_hosts_file,
+ undefined,
+ Ks, Ls);
+ tcp -> get_rc(tcp,
+ tcp_module,
+ ?DEFAULT_TCP_MODULE,
+ Ks, Ls);
+ udp -> get_rc(udp,
+ udp_module,
+ ?DEFAULT_UDP_MODULE,
+ Ks, Ls);
+ sctp -> get_rc(sctp,
+ sctp_module,
+ ?DEFAULT_SCTP_MODULE,
+ Ks, Ls);
+ lookup -> get_rc(lookup,
+ res_lookup,
+ [native, file],
+ Ks, Ls);
+ cache_size -> get_rc(cache_size,
+ cache_size,
+ ?CACHE_LIMIT,
+ Ks, Ls);
+ cache_refresh -> get_rc(cache_refresh,
+ cache_refresh_interval,
+ ?CACHE_REFRESH,
+ Ks, Ls);
+ socks5_server -> get_rc(socks5_server,
+ socks5_server,
+ "",
+ Ks, Ls);
+ socks5_port -> get_rc(socks5_port,
+ socks5_port,
+ ?IPPORT_SOCKS,
+ Ks, Ls);
+ socks5_methods -> get_rc(socks5_methods,
+ socks5_methods,
+ [none],
+ Ks, Ls);
+ socks5_noproxy -> case db_get(socks5_noproxy) of
+ [] -> get_rc(Ks, Ls);
+ NoProxy -> get_rc_noproxy(NoProxy, Ks, Ls)
+ end;
_ ->
get_rc(Ks, Ls)
end;
@@ -415,6 +481,7 @@ res_optname(lookup) -> res_lookup;
res_optname(recurse) -> res_recurse;
res_optname(search) -> res_search;
res_optname(retry) -> res_retry;
+res_optname(servfail_retry_timeout) -> res_servfail_retry_timeout;
res_optname(timeout) -> res_timeout;
res_optname(inet6) -> res_inet6;
res_optname(usevc) -> res_usevc;
@@ -448,6 +515,7 @@ res_check_option(recurse, R) when is_boolean(R) -> true;
res_check_option(search, SearchList) ->
res_check_list(SearchList, fun res_check_search/1);
res_check_option(retry, N) when is_integer(N), N > 0 -> true;
+res_check_option(servfail_retry_timeout, T) when is_integer(T), T >= 0 -> true;
res_check_option(timeout, T) when is_integer(T), T > 0 -> true;
res_check_option(inet6, Bool) when is_boolean(Bool) -> true;
res_check_option(usevc, Bool) when is_boolean(Bool) -> true;
@@ -787,6 +855,7 @@ lookup_socket(Socket) when is_port(Socket) ->
%% res_usevc Bool - use tcp only
%% res_id Integer - NS query identifier
%% res_retry Integer - Retry count for UDP query
+%% res_servfail_retry_timeout Integer - Timeout to next query after a failure
%% res_timeout Integer - UDP query timeout before retry
%% res_inet6 Bool - address family inet6 for gethostbyname/1
%% res_usevc Bool - use Virtual Circuit (TCP)
@@ -857,6 +926,7 @@ reset_db(Db) ->
{res_usevc, false},
{res_id, 0},
{res_retry, ?RES_RETRY},
+ {res_servfail_retry_timeout, ?RES_SERVFAIL_RETRY_TO},
{res_timeout, ?RES_TIMEOUT},
{res_inet6, false},
{res_edns, false},
@@ -1526,6 +1596,7 @@ rc_reqname(_) -> undefined.
is_res_set(domain) -> true;
is_res_set(lookup) -> true;
is_res_set(timeout) -> true;
+is_res_set(servfail_retry_timeout) -> true;
is_res_set(retry) -> true;
is_res_set(inet6) -> true;
is_res_set(usevc) -> true;
diff --git a/lib/kernel/src/inet_res.erl b/lib/kernel/src/inet_res.erl
index 7886ef83ac..620dfd0052 100644
--- a/lib/kernel/src/inet_res.erl
+++ b/lib/kernel/src/inet_res.erl
@@ -259,7 +259,7 @@ do_nslookup(Name, Class, Type, Opts, Timeout) ->
%%
-record(options, { % These must be sorted!
alt_nameservers,edns,inet6,nameservers,recurse,
- retry,timeout,udp_payload_size,usevc,
+ retry,servfail_retry_timeout,timeout,udp_payload_size,usevc,
verbose}). % this is a local option, not in inet_db
%%
%% Opts when is_list(Opts) -> #options{}
@@ -772,8 +772,18 @@ query_retries(_Q, _NSs, _Timer, Retry, Retry, S, Reason) ->
query_retries(_Q, [], _Timer, _Retry, _I, S, Reason) ->
query_retries_error(S, Reason);
query_retries(Q, NSs, Timer, Retry, I, S_0, Reason) ->
+ servfail_retry_wait(Q, I),
query_nss(Q, NSs, Timer, Retry, I, S_0, Reason, NSs).
+servfail_retry_wait(_Q, 0) ->
+ ok;
+servfail_retry_wait(#q{options = #options{servfail_retry_timeout = T}}, _)
+ when (T > 0) ->
+ receive after T -> ok end;
+servfail_retry_wait(_, _) ->
+ ok.
+
+
%% Loop for all name servers, for each:
%% If EDNS is enabled, try that first,
%% and for selected failures fall back to plain DNS.
diff --git a/lib/kernel/src/inet_res.hrl b/lib/kernel/src/inet_res.hrl
index 774b4074a5..c812550328 100644
--- a/lib/kernel/src/inet_res.hrl
+++ b/lib/kernel/src/inet_res.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,23 +21,43 @@
%% Dns & resolver definitions
%%
--define(RES_TIMEOUT, 2000). %% milli second between retries
--define(RES_RETRY, 3). %% number of retry
--define(RES_FILE_UPDATE_TM, 5). %% seconds between file_info
+%% milli second for requests
+-define(RES_TIMEOUT, 2000).
--define(CACHE_LIMIT, 100). %% number of cached dns_rr
--define(CACHE_REFRESH, 60*60*1000). %% refresh interval
+%% milli second to wait before next request after a failure
+-define(RES_SERVFAIL_RETRY_TO, 1500).
+
+%% number of retry
+-define(RES_RETRY, 3).
+
+%% seconds between file_info
+-define(RES_FILE_UPDATE_TM, 5).
+
+%% number of cached dns_rr
+-define(CACHE_LIMIT, 100).
+
+%% refresh interval
+-define(CACHE_REFRESH, 60*60*1000).
+
+%% maximum packet size
+-define(PACKETSZ, 512).
+
+%% maximum domain name
+-define(MAXDNAME, 256).
+
+%% maximum compressed domain name
+-define(MAXCDNAME, 255).
+
+%% maximum length of domain label
+-define(MAXLABEL, 63).
--define(PACKETSZ, 512). %% maximum packet size
--define(MAXDNAME, 256). %% maximum domain name
--define(MAXCDNAME, 255). %% maximum compressed domain name
--define(MAXLABEL, 63). %% maximum length of domain label
%% Number of bytes of fixed size data in query structure
--define(QFIXEDSZ, 4).
+-define(QFIXEDSZ, 4).
+
%% number of bytes of fixed size data in resource record
--define(RRFIXEDSZ, 10).
+-define(RRFIXEDSZ, 10).
%%
%% Internet nameserver port number
%%
--define(NAMESERVER_PORT, 53).
+-define(NAMESERVER_PORT, 53).
--
2.26.2