Packages
erldns
11.1.0
11.1.0
11.0.3
11.0.2
11.0.1
11.0.0
10.6.0
10.5.6
10.5.5
10.5.4
10.5.3
10.5.2
10.5.1
10.5.0
10.4.4
10.4.3
10.4.2
10.4.1
10.4.0
10.3.0
10.2.1
10.2.0
10.1.0
10.0.0
10.0.0-rc4
10.0.0-rc3
10.0.0-rc2
10.0.0-rc1
9.1.0
9.0.0
9.0.0-rc3
9.0.0-rc2
9.0.0-rc1
8.1.0
8.0.0
8.0.0-rc6
8.0.0-rc5
8.0.0-rc4
8.0.0-rc3
8.0.0-rc2
8.0.0-rc1
7.0.0
7.0.0-rc9
7.0.0-rc8
7.0.0-rc7
7.0.0-rc6
7.0.0-rc5
7.0.0-rc4
7.0.0-rc3
7.0.0-rc2
7.0.0-rc12
7.0.0-rc11
7.0.0-rc10
7.0.0-rc1
6.0.2
6.0.1
6.0.0
5.0.0
4.3.1
4.3.0
4.2.4
4.2.3
4.2.2
4.2.1
4.2.0
4.1.2
4.1.1
4.1.0
4.0.0
3.0.0
1.0.0
Erlang Authoritative DNS Server
Current section
Files
Jump to
Current section
Files
src/erldns_config.erl
-module(erldns_config).
-moduledoc "Provide application-wide configuration access.".
-export([
use_root_hints/0,
socket_opts/2,
split_socket_opts/1,
split_socket_opts/2,
balances_load/0,
socket_count/1,
socket_count/2
]).
-doc "Use IANA DNS root servers as hints".
-spec use_root_hints() -> boolean().
use_root_hints() ->
case application:get_env(erldns, use_root_hints) of
{ok, Flag} when is_boolean(Flag) ->
Flag;
_ ->
true
end.
-doc false.
-spec socket_opts([atom() | tuple()], os:type()) -> [atom() | tuple()].
socket_opts(Opts, OsType) ->
reuse_opts(family_opts(Opts, OsType), OsType).
%% Windows and OpenBSD reject `{ipv6_v6only, false}', so a dual-stack wildcard
%% never binds there; fall back to IPv4 rather than not listening at all.
family_opts(Opts, OsType) ->
case lists:member({ipv6_v6only, false}, Opts) andalso not supports_dual_stack(OsType) of
true ->
[inet | Opts -- [inet6, {ipv6_v6only, false}]];
false ->
Opts
end.
%% `reuseaddr' is left to ranch and `base_udp_opts/0', which set it already;
%% ranch also rejects it as an explicit listen option.
reuse_opts(Opts, OsType) ->
case reuse_opt(OsType) of
none -> Opts;
Opt -> Opts ++ [{Opt, true} || not lists:keymember(Opt, 1, Opts)]
end.
%% On FreeBSD `SO_REUSEPORT_LB' is a distinct option from `SO_REUSEPORT', and
%% asking for both leaves the classic non-balancing one in charge: measured, all
%% traffic reaches the last socket bound. Linux maps the two onto one option and
%% DragonFly, whose implementation FreeBSD adapted, balances under the plain
%% name, so `reuseport' is right for both. Windows shares no ports at all.
reuse_opt({win32, _}) ->
none;
reuse_opt({unix, freebsd}) ->
reuseport_lb;
reuse_opt(_) ->
reuseport.
supports_dual_stack({win32, _}) ->
false;
supports_dual_stack({unix, openbsd}) ->
false;
supports_dual_stack(_) ->
true.
-doc false.
-spec split_socket_opts([atom() | tuple()]) -> [[atom() | tuple()]].
split_socket_opts(Opts) ->
split_socket_opts(Opts, os:type()).
%% One option list per socket family a listener should bind. FreeBSD's
%% `SO_REUSEPORT_LB' does not balance IPv4 traffic arriving on a dual-stack
%% socket, so a wildcard listener there delivers every packet to one acceptor.
%% Giving the acceptors a family each restores balancing within both. Only
%% FreeBSD is known to need this; platforms without CI keep one socket.
-doc false.
-spec split_socket_opts([atom() | tuple()], os:type()) -> [[atom() | tuple()]].
split_socket_opts(Opts, OsType) ->
case lists:member({ipv6_v6only, false}, Opts) andalso not balances_dual_stack(OsType) of
true ->
Rest = Opts -- [inet6, {ipv6_v6only, false}, {ip, any}],
[
[inet, {ip, any} | Rest],
[inet6, {ipv6_v6only, true}, {ip, any} | Rest]
];
false ->
[Opts]
end.
balances_dual_stack({unix, freebsd}) ->
false;
balances_dual_stack(_) ->
true.
-doc false.
-spec balances_load() -> boolean().
balances_load() ->
balances_load(os:type()).
%% Whether the kernel spreads traffic across sockets sharing a port rather than
%% delivering all of it to one of them. These two are the platforms CI measures
%% doing so; everywhere else the extra acceptors bind but never receive.
%% DragonFly is likely to belong here, since its own implementation is the one
%% FreeBSD adapted, but nothing verifies that.
-spec balances_load(os:type()) -> boolean().
balances_load({unix, linux}) ->
true;
balances_load({unix, freebsd}) ->
true;
balances_load(_) ->
false.
-doc false.
-spec socket_count(pos_integer()) -> pos_integer().
socket_count(Wanted) ->
socket_count(Wanted, os:type()).
%% How many sockets a listener should open on one port. Windows refuses to bind
%% a second, so the extras would each fail to start rather than start smaller.
-doc false.
-spec socket_count(pos_integer(), os:type()) -> pos_integer().
socket_count(_, {win32, _}) ->
1;
socket_count(Wanted, _) ->
Wanted.