Skip to content
2 changes: 1 addition & 1 deletion lib/kernel/src/gen_udp.erl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
%%
%% SPDX-License-Identifier: Apache-2.0
%%
%% Copyright Ericsson AB 1997-2025. All Rights Reserved.
%% Copyright Ericsson AB 1997-2026. 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.
Expand Down
50 changes: 40 additions & 10 deletions lib/kernel/src/inet.erl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
%%
%% SPDX-License-Identifier: Apache-2.0
%%
%% Copyright Ericsson AB 1997-2025. All Rights Reserved.
%% Copyright Ericsson AB 1997-2026. 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.
Expand Down Expand Up @@ -3969,13 +3969,14 @@ gethostbyaddr_tm_native(Addr, Timer, Opts) ->
{'ok', port()} | {'error', posix()}.

open(Fd, BAddr, BPort, Opts, Protocol, Family, Type, Module)
when is_integer(Fd), 0 =< Fd ->
when is_integer(Fd), 0 =< Fd, is_integer(BPort) ->
open_fd(Fd, BAddr, BPort, Opts, Protocol, Family, Type, Module);
open(Fd_or_OpenOpts, BAddr, BPort, Opts, Protocol, Family, Type, Module) ->
open(Fd_or_OpenOpts, BAddr, BPort, Opts, Protocol, Family, Type, Module)
when is_integer(BPort) ->
open_opts(
Fd_or_OpenOpts,
if
BAddr =:= undefined, BPort =/= 0 ->
BAddr =:= undefined, BPort > 0 ->
translate_ip(any, Family);
true ->
BAddr
Expand Down Expand Up @@ -4024,14 +4025,15 @@ open(Fd_or_OpenOpts, BAddr, BPort, Opts, Protocol, Family, Type, Module) ->
{'ok', port()} | {'error', posix()}.

open_bind(Fd, BAddr, BPort, Opts, Protocol, Family, Type, Module)
when is_integer(Fd), 0 =< Fd ->
when is_integer(Fd), 0 =< Fd, is_integer(BPort) ->
%% ?DBG([{fd, Fd},
%% {baddr, BAddr}, {bport, BPort},
%% {opts, Opts}, {proto, Protocol}, {fam, Family},
%% {type, Type}, {mod, Module}]),
open_fd(Fd, BAddr, BPort, Opts, Protocol, Family, Type, Module);
open_bind(
Fd_or_OpenOpts, BAddr, BPort, Opts, Protocol, Family, Type, Module) ->
Fd_or_OpenOpts, BAddr, BPort, Opts, Protocol, Family, Type, Module)
when is_integer(BPort) ->
%% ?DBG([{fd_or_openopts, Fd_or_OpenOpts},
%% {baddr, BAddr}, {bport, BPort},
%% {opts, Opts}, {proto, Protocol}, {fam, Family},
Expand Down Expand Up @@ -4117,11 +4119,39 @@ open_setopts(S, BAddr, BPort, Opts, Module) ->



bind(S, Addr, Port) when is_list(Addr) ->
bind(S, Addr, Port) when is_list(Addr), is_integer(Port) ->
bindx(S, Addr, Port);
bind(S, Addr, Port) ->
%% ?DBG([{s, S}, {addr, Addr}, {port, Port}]),
prim_inet:bind(S, Addr, Port).
bind(S, Addr, -1) ->
bind_random(S, Addr);
bind(S, Addr, Port) when is_integer(Port) ->
do_bind(S, Addr, Port).

do_bind(S, Addr, Port) ->
Result = prim_inet:bind(S, Addr, Port),
%% ?DBG([{s, S}, {addr, Addr}, {port, Port}, Result]),
Result.

bind_random(S, Addr) ->
Cnt = 3,
bind_random(S, Addr, Cnt).
%%
bind_random(S, Addr, 0 = _Cnt) ->
Port = 0,
do_bind(S, Addr, Port);
bind_random(S, Addr, Cnt) when is_integer(Cnt), 0 < Cnt ->
Port = inet_db:res_option(random_port),
bind_random(S, Addr, Cnt, Port).
%%
bind_random(S, Addr, _Cnt, 0 = Port) ->
do_bind(S, Addr, Port);
bind_random(S, Addr, Cnt, Port) when ?port(Port) ->
case prim_inet:bind(S, Addr, Port) of
{ok, _} = OK ->
%% ?DBG([{s, S}, {addr, Addr}, {port, Port}, OK]),
OK;
{error, _} ->
bind_random(S, Addr, Cnt - 1)
end.

bindx(S, [Addr], Port0) ->
{IP, Port} = set_bindx_port(Addr, Port0),
Expand Down
9 changes: 5 additions & 4 deletions lib/kernel/src/inet6_sctp.erl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
%%
%% SPDX-License-Identifier: Apache-2.0
%%
%% Copyright Ericsson AB 2007-2025. All Rights Reserved.
%% Copyright Ericsson AB 2007-2026. 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.
Expand Down Expand Up @@ -57,11 +57,12 @@ open(Opts) ->
ifaddr = Addr,
port = Port,
type = Type,
opts = SOs}} ->
opts = SOs}}
when ?port(Port) ->
inet:open_bind(
Fd, Addr, Port, SOs, ?PROTO, ?FAMILY, Type, ?MODULE);
Error ->
Error
{ok, _} -> {error, badarg};
Error -> Error
end.

close(S) ->
Expand Down
4 changes: 3 additions & 1 deletion lib/kernel/src/inet6_udp.erl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
%%
%% SPDX-License-Identifier: Apache-2.0
%%
%% Copyright Ericsson AB 1997-2025. All Rights Reserved.
%% Copyright Ericsson AB 1997-2026. 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.
Expand Down Expand Up @@ -66,6 +66,8 @@ open(Port, Opts) ->
port = BPort,
opts = SockOpts}}
when is_map(BAddr); % sockaddr_in()
BPort =:= -1, ?ip6(BAddr);
BPort =:= -1, BAddr =:= undefined;
?port(BPort), ?ip6(BAddr);
?port(BPort), BAddr =:= undefined ->
%% ?DBG(['udp-options',
Expand Down
71 changes: 60 additions & 11 deletions lib/kernel/src/inet_db.erl
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ 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, servfail_retry_timeout, inet6, usevc,
timeout, retry, servfail_retry_timeout, inet6, usevc, random,
edns, udp_payload_size, dnssec_ok, resolv_conf, hosts_file,
socks5_server, socks5_port, socks5_methods, socks5_noproxy,
udp, sctp, tcp, host, cache_size, cache_refresh, lookup], []).
Expand Down Expand Up @@ -360,6 +360,10 @@ get_rc([K | Ks], Ls) ->
res_usevc,
false,
Ks, Ls);
random -> get_rc(random,
res_random,
true,
Ks, Ls);
edns -> get_rc(edns,
res_edns,
false,
Expand Down Expand Up @@ -451,18 +455,15 @@ get_rc_hosts([], Ls) ->
get_rc_hosts([{{_Fam, IP}, Names} | Hosts], Ls) ->
get_rc_hosts(Hosts, [{host, IP, Names} | Ls]).

%% Some odd features stuffed into this API
%%
res_option(next_id) ->
generate_next_id();
res_option(random_port) ->
generate_random_port();
%%
%% Resolver options
%%
res_option(next_id) ->
Cnt = ets:update_counter(inet_db, res_id, 1),
case Cnt band 16#ffff of
0 ->
_ = ets:update_counter(inet_db, res_id, -Cnt),
0;
Id ->
Id
end;
res_option(Option) ->
case res_optname(Option) of
undefined ->
Expand Down Expand Up @@ -492,6 +493,7 @@ res_optname(servfail_retry_timeout) -> res_servfail_retry_timeout;
res_optname(timeout) -> res_timeout;
res_optname(inet6) -> res_inet6;
res_optname(usevc) -> res_usevc;
res_optname(random) -> res_random;
res_optname(edns) -> res_edns;
res_optname(udp_payload_size) -> res_udp_payload_size;
res_optname(dnssec_ok) -> res_dnssec_ok;
Expand Down Expand Up @@ -527,6 +529,7 @@ 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;
res_check_option(random, Bool) when is_boolean(Bool) -> true;
res_check_option(edns, V) when V =:= false; V =:= 0 -> true;
res_check_option(udp_payload_size, S) when is_integer(S), S >= 512 -> true;
res_check_option(dnssec_ok, D) when is_boolean(D) -> true;
Expand Down Expand Up @@ -892,13 +895,13 @@ take_socket_type(MRef) ->
%% res_search [Domain] - list of domains for short names
%% res_domain Domain - local domain for short names
%% res_recurse Bool - recursive query
%% 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)
%% res_random Bool - use random res_id and port number
%% res_edns false|Integer - false or EDNS version
%% res_udp_payload_size Integer - size for EDNS, both query and reply
%% res_dnssec_ok Bool - the DO bit in RFC6891 & RFC3225
Expand Down Expand Up @@ -972,6 +975,7 @@ reset_db(Db) ->
{res_lookup, []},
{res_recurse, true},
{res_usevc, false},
{res_random, true},
{res_id, 0},
{res_retry, ?RES_RETRY},
{res_servfail_retry_timeout, ?RES_SERVFAIL_RETRY_TO},
Expand Down Expand Up @@ -1661,6 +1665,7 @@ is_res_set(servfail_retry_timeout) -> true;
is_res_set(retry) -> true;
is_res_set(inet6) -> true;
is_res_set(usevc) -> true;
is_res_set(random) -> true;
is_res_set(edns) -> true;
is_res_set(udp_payload_size) -> true;
is_res_set(dnssec_ok) -> true;
Expand Down Expand Up @@ -2089,3 +2094,47 @@ handle_take_socket_type(Db, MRef) ->
[] -> % Already demonitor'ed
error
end.

%%----------------------------------------------------------------------
%% Random DNS Transaction ID and origin port number
%%----------------------------------------------------------------------

generate_next_id() ->
case ets:lookup_element(inet_db, res_random, 2) of
true ->
case crypto_rand_range(1 bsl 16) of
Id when is_integer(Id), 0 =< Id, Id < 1 bsl 16 -> Id;
undefined ->
generate_next_id_legacy()
end;
false ->
generate_next_id_legacy()
end.

generate_next_id_legacy() ->
ets:update_counter(inet_db, res_id, {2, 1, 16#ffff, 0}).

generate_random_port() ->
Min = 1024,
Range = (1 bsl 16) - Min,
case crypto_rand_range(Range) of
V when is_integer(V), 0 =< V, V < Range -> Min + V;
undefined -> 0
end.

%% We use `crypto:rand_uniform/2` here, which is the simplest to use,
%% but it is deprecated, for outdated reasons. In really old, now obsolete,
%% libcrypto versions the function was not cryptographically strong,
%% but since OpenSSL 1.1.0 that is no longer the case.
-compile({nowarn_deprecated_function, {crypto,rand_uniform,2}}).

crypto_rand_range(Range) when is_integer(Range), 0 < Range ->
%% This is how crypto itself checks if it is loaded
case application:get_env(crypto, fips_mode) of
undefined -> undefined;
{ok, Fips} when is_boolean(Fips) ->
try crypto:rand_uniform(0, Range) of
N when is_integer(N), 0 =< N, N < Range -> N
catch error : low_entropy -> undefined
end
end.
Loading