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

openSUSE Build Service is sponsored by