diff --git a/src/config/mongoose_config_spec.erl b/src/config/mongoose_config_spec.erl index f60c5310e9a..b79a3e0ef99 100644 --- a/src/config/mongoose_config_spec.erl +++ b/src/config/mongoose_config_spec.erl @@ -149,7 +149,7 @@ host_config() -> <<"modules">> => modules(), <<"acl">> => acl(), <<"access">> => access(), - <<"s2s">> => s2s() + <<"s2s">> => host_s2s() }, wrap = none }. @@ -868,39 +868,53 @@ access_rule_item() -> format_items = map }. -%% path: (host_config[].)s2s +%% path: s2s s2s() -> #section{ - items = #{<<"dns">> => s2s_dns(), - <<"outgoing">> => s2s_outgoing(), - <<"use_starttls">> => #option{type = atom, - validate = {enum, [false, optional, required, - required_trusted]}, - wrap = {global_config, s2s_use_starttls}}, - <<"certfile">> => #option{type = string, - validate = non_empty, - wrap = {global_config, s2s_certfile}}, - <<"default_policy">> => #option{type = atom, - validate = {enum, [allow, deny]}, - wrap = {host_config, s2s_default_policy}}, - <<"host_policy">> => #list{items = s2s_host_policy(), - format_items = map, - wrap = {host_config, s2s_host_policy}}, - <<"address">> => #list{items = s2s_address(), - format_items = map, - wrap = {global_config, s2s_address}}, - <<"ciphers">> => #option{type = string, - wrap = {global_config, s2s_ciphers}}, - <<"shared">> => #option{type = binary, - validate = non_empty, - wrap = {host_config, s2s_shared}}, - <<"max_retry_delay">> => #option{type = integer, - validate = positive, - wrap = {host_config, s2s_max_retry_delay}} - }, + items = maps:merge(s2s_global_items(), s2s_host_items()), + wrap = none, + include = always + }. + +%% path: host_config[].s2s +host_s2s() -> + #section{ + items = s2s_host_items(), wrap = none }. +s2s_host_items() -> + #{<<"default_policy">> => #option{type = atom, + validate = {enum, [allow, deny]}, + wrap = {host_config, s2s_default_policy}}, + <<"host_policy">> => #list{items = s2s_host_policy(), + format_items = map, + wrap = {host_config, s2s_host_policy}}, + <<"shared">> => #option{type = binary, + validate = non_empty, + wrap = {host_config, s2s_shared}}, + <<"max_retry_delay">> => #option{type = integer, + validate = positive, + wrap = {host_config, s2s_max_retry_delay}} + }. + +s2s_global_items() -> + #{<<"dns">> => s2s_dns(), + <<"outgoing">> => s2s_outgoing(), + <<"use_starttls">> => #option{type = atom, + validate = {enum, [false, optional, required, + required_trusted]}, + wrap = {global_config, s2s_use_starttls}}, + <<"certfile">> => #option{type = string, + validate = non_empty, + wrap = {global_config, s2s_certfile}}, + <<"address">> => #list{items = s2s_address(), + format_items = map, + wrap = {global_config, s2s_address}}, + <<"ciphers">> => #option{type = string, + wrap = {global_config, s2s_ciphers}} + }. + %% path: (host_config[].)s2s.dns s2s_dns() -> #section{ @@ -908,26 +922,31 @@ s2s_dns() -> validate = positive}, <<"retries">> => #option{type = integer, validate = positive}}, - wrap = {global_config, s2s_dns_options} + format_items = map, + include = always, + defaults = #{<<"timeout">> => 10, + <<"retries">> => 2}, + wrap = {global_config, s2s_dns} }. %% path: (host_config[].)s2s.outgoing s2s_outgoing() -> #section{ items = #{<<"port">> => #option{type = integer, - validate = port, - wrap = {global_config, outgoing_s2s_port}}, + validate = port}, <<"ip_versions">> => #list{items = #option{type = integer, - validate = {enum, [4, 6]}, - process = fun ?MODULE:process_s2s_address_family/1}, - validate = unique_non_empty, - wrap = {global_config, outgoing_s2s_families}}, + validate = {enum, [4, 6]}}, + validate = unique_non_empty}, <<"connection_timeout">> => #option{type = int_or_infinity, - validate = positive, - wrap = {global_config, outgoing_s2s_timeout}} + validate = positive} }, - wrap = none + format_items = map, + include = always, + defaults = #{<<"port">> => 5269, + <<"ip_versions">> => [4, 6], + <<"connection_timeout">> => 10000}, + wrap = {global_config, s2s_outgoing} }. %% path: (host_config[].)s2s.host_policy[] diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 6562c988074..6285afca2ed 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -296,10 +296,10 @@ open_socket1({_, _, _, _, _, _, _, _} = Addr, Port) -> open_socket2(inet6, Addr, Port); %% Hostname open_socket1(Host, Port) -> - lists:foldl(fun(_Family, {ok, _Socket} = R) -> + lists:foldl(fun(_IPVersion, {ok, _Socket} = R) -> R; - (Family, _) -> - Addrs = get_addrs(Host, Family), + (IPVersion, _) -> + Addrs = get_addrs(Host, IPVersion), lists:foldl(fun(_Addr, {ok, _Socket} = R) -> R; (Addr, _) -> @@ -998,9 +998,7 @@ get_addr_port(Server) -> -spec srv_lookup(jid:server()) -> {'error', atom()} | {'ok', inet:hostent()}. srv_lookup(Server) -> - Options = mongoose_config:get_opt(s2s_dns_options, []), - TimeoutMs = timer:seconds(proplists:get_value(timeout, Options, 10)), - Retries = proplists:get_value(retries, Options, 2), + #{timeout := TimeoutMs, retries := Retries} = mongoose_config:get_opt(s2s_dns), srv_lookup(Server, TimeoutMs, Retries). @@ -1044,18 +1042,10 @@ test_get_addr_port(Server) -> end, [], lists:seq(1, 100000)). --spec get_addrs(Host :: atom() | binary() | string(), - Family :: 'inet4' | 'inet6' | 'ipv4' | 'ipv6' - ) -> [inet:ip_address()]. -get_addrs(Host, Family) when is_binary(Host) -> - get_addrs(binary_to_list(Host), Family); -get_addrs(Host, Family) -> - Type = case Family of - inet4 -> inet; - ipv4 -> inet; - inet6 -> inet6; - ipv6 -> inet6 - end, +-spec get_addrs(Host :: atom() | binary() | string(), inet | inet6) -> [inet:ip_address()]. +get_addrs(Host, Type) when is_binary(Host) -> + get_addrs(binary_to_list(Host), Type); +get_addrs(Host, Type) -> case inet:gethostbyname(Host, Type) of {ok, #hostent{h_addr_list = Addrs}} -> ?LOG_DEBUG(#{what => s2s_srv_resolve_success, @@ -1068,12 +1058,12 @@ get_addrs(Host, Family) -> end. --spec outgoing_s2s_port() -> integer(). +-spec outgoing_s2s_port() -> inet:port_number(). outgoing_s2s_port() -> - mongoose_config:get_opt(outgoing_s2s_port, 5269). + mongoose_config:get_opt([s2s_outgoing, port]). --spec outgoing_s2s_families() -> ['ipv4' | 'ipv6', ...]. +-spec outgoing_s2s_families() -> [inet:address_family(), ...]. outgoing_s2s_families() -> %% DISCUSSION: Why prefer IPv4 first? %% @@ -1086,11 +1076,14 @@ outgoing_s2s_families() -> %% AAAA records for their sites due to the mentioned %% quality of current IPv6 connectivity. Making IPv6 the a %% `fallback' may avoid these problems elegantly. - mongoose_config:get_opt(outgoing_s2s_families, [ipv4, ipv6]). + [ip_version_to_family(V) || V <- mongoose_config:get_opt([s2s_outgoing, ip_versions])]. + +ip_version_to_family(4) -> inet; +ip_version_to_family(6) -> inet6. -spec outgoing_s2s_timeout() -> non_neg_integer() | infinity. outgoing_s2s_timeout() -> - mongoose_config:get_opt(outgoing_s2s_timeout, 10000). + mongoose_config:get_opt([s2s_outgoing, connection_timeout], 10000). %% @doc Human readable S2S logging: Log only new outgoing connections as INFO %% Do not log dialback diff --git a/test/config_parser_SUITE.erl b/test/config_parser_SUITE.erl index 6503f1de1c4..2d34c333ae2 100644 --- a/test/config_parser_SUITE.erl +++ b/test/config_parser_SUITE.erl @@ -1431,27 +1431,32 @@ access_merge_host_and_global(_Config) -> %% tests: s2s s2s_dns_timeout(_Config) -> - ?cfg(s2s_dns_options, [{timeout, 5}], #{<<"s2s">> => #{<<"dns">> => #{<<"timeout">> => 5}}}), + ?cfg([s2s_dns, timeout], 10, #{}), % default + ?cfg([s2s_dns, timeout], 5, #{<<"s2s">> => #{<<"dns">> => #{<<"timeout">> => 5}}}), ?err(#{<<"s2s">> => #{<<"dns">> => #{<<"timeout">> => 0}}}). s2s_dns_retries(_Config) -> - ?cfg(s2s_dns_options, [{retries, 1}], #{<<"s2s">> => #{<<"dns">> => #{<<"retries">> => 1}}}), + ?cfg([s2s_dns, retries], 2, #{}), % default + ?cfg([s2s_dns, retries], 1, #{<<"s2s">> => #{<<"dns">> => #{<<"retries">> => 1}}}), ?err(#{<<"s2s">> => #{<<"dns">> => #{<<"retries">> => 0}}}). s2s_outgoing_port(_Config) -> - ?cfg(outgoing_s2s_port, 5270, #{<<"s2s">> => #{<<"outgoing">> => #{<<"port">> => 5270}}}), + ?cfg([s2s_outgoing, port], 5269, #{}), % default + ?cfg([s2s_outgoing, port], 5270, #{<<"s2s">> => #{<<"outgoing">> => #{<<"port">> => 5270}}}), ?err(#{<<"s2s">> => #{<<"outgoing">> => #{<<"port">> => <<"http">>}}}). s2s_outgoing_ip_versions(_Config) -> - ?cfg(outgoing_s2s_families, [ipv6, ipv4], + ?cfg([s2s_outgoing, ip_versions], [4, 6], #{}), % default + ?cfg([s2s_outgoing, ip_versions], [6, 4], #{<<"s2s">> => #{<<"outgoing">> => #{<<"ip_versions">> => [6, 4]}}}), ?err(#{<<"s2s">> => #{<<"outgoing">> => #{<<"ip_versions">> => []}}}), ?err(#{<<"s2s">> => #{<<"outgoing">> => #{<<"ip_versions">> => [<<"http">>]}}}). s2s_outgoing_timeout(_Config) -> - ?cfg(outgoing_s2s_timeout, 5, - #{<<"s2s">> => #{<<"outgoing">> => #{<<"connection_timeout">> => 5}}}), - ?cfg(outgoing_s2s_timeout, infinity, + ?cfg([s2s_outgoing, connection_timeout], 10000, #{}), % default + ?cfg([s2s_outgoing, connection_timeout], 5000, + #{<<"s2s">> => #{<<"outgoing">> => #{<<"connection_timeout">> => 5000}}}), + ?cfg([s2s_outgoing, connection_timeout], infinity, #{<<"s2s">> => #{<<"outgoing">> => #{<<"connection_timeout">> => <<"infinity">>}}}), ?err(#{<<"s2s">> => #{<<"outgoing">> => #{<<"connection_timeout">> => 0}}}). @@ -3218,8 +3223,6 @@ compare_nodes([{auth_method, _}], V1, V2) when is_atom(V1) -> ?eq([V1], V2); compare_nodes([{s2s_addr, _}], {_, _, _, _} = IP1, IP2) -> ?eq(inet:ntoa(IP1), IP2); -compare_nodes([s2s_dns_options], V1, V2) -> - compare_unordered_lists(V1, V2); compare_nodes([{modules, _}, mod_extdisco], V1, V2) -> compare_ordered_lists(V1, V2, fun compare_unordered_lists/2); compare_nodes([{modules, _}, _Module], V1, V2) -> diff --git a/test/config_parser_SUITE_data/s2s_only.toml b/test/config_parser_SUITE_data/s2s_only.toml index 5343e54ba1c..d6fa64fdfd7 100644 --- a/test/config_parser_SUITE_data/s2s_only.toml +++ b/test/config_parser_SUITE_data/s2s_only.toml @@ -11,8 +11,8 @@ default_policy = "allow" ciphers = "TLSv1.2:TLSv1.3" outgoing.port = 5299 - outgoing.connection_timeout = 10000 - outgoing.ip_versions = [4, 6] + outgoing.connection_timeout = 4000 + outgoing.ip_versions = [6, 4] dns.timeout = 30 dns.retries = 1 shared = "shared secret" diff --git a/test/config_parser_helper.erl b/test/config_parser_helper.erl index df09295f5c4..a6ed145d430 100644 --- a/test/config_parser_helper.erl +++ b/test/config_parser_helper.erl @@ -22,6 +22,10 @@ options("host_types") -> {registration_timeout, 600}, {routing_modules, mongoose_router:default_routing_modules()}, {sm_backend, {mnesia, []}}, + {s2s_dns, #{retries => 2, timeout => 10}}, + {s2s_outgoing, #{connection_timeout => 10000, + ip_versions => [4, 6], + port => 5269}}, {{auth, <<"another host type">>}, auth_with_methods(#{})}, {{auth, <<"localhost">>}, auth_with_methods(#{rdbms => #{users_number_estimate => false}})}, @@ -79,6 +83,10 @@ options("miscellaneous") -> {periodic_report, 10800000}, report, {tracking_id, "UA-123456789"}]}]}, + {s2s_dns, #{retries => 2, timeout => 10}}, + {s2s_outgoing, #{connection_timeout => 10000, + ip_versions => [4, 6], + port => 5269}}, {sm_backend, {mnesia, []}}, {{auth, <<"anonymous.localhost">>}, custom_auth()}, {{auth, <<"localhost">>}, custom_auth()}, @@ -101,6 +109,10 @@ options("modules") -> {rdbms_server_type, generic}, {registration_timeout, 600}, {routing_modules, mongoose_router:default_routing_modules()}, + {s2s_dns, #{retries => 2, timeout => 10}}, + {s2s_outgoing, #{connection_timeout => 10000, + ip_versions => [4, 6], + port => 5269}}, {sm_backend, {mnesia, []}}, {{auth, <<"dummy_host">>}, default_auth()}, {{auth, <<"localhost">>}, default_auth()}, @@ -229,11 +241,15 @@ options("mongooseim-pgsql") -> {server_name_indication, disable}, {verify, verify_peer}]}]}}]}, {redis, <<"localhost">>, global_distrib, [{workers, 10}], []}]}, - {outgoing_s2s_port, 5299}, {rdbms_server_type, generic}, {registration_timeout, infinity}, {routing_modules, mongoose_router:default_routing_modules()}, + {s2s_address, #{<<"fed1">> => "127.0.0.1"}}, {s2s_certfile, "tools/ssl/mongooseim/server.pem"}, + {s2s_dns, #{retries => 2, timeout => 10}}, + {s2s_outgoing, #{connection_timeout => 10000, + ip_versions => [4, 6], + port => 5299}}, {s2s_use_starttls, optional}, {services, [{service_admin_extra, @@ -265,7 +281,6 @@ options("mongooseim-pgsql") -> {{replaced_wait_timeout, <<"anonymous.localhost">>}, 2000}, {{replaced_wait_timeout, <<"localhost">>}, 2000}, {{replaced_wait_timeout, <<"localhost.bis">>}, 2000}, - {s2s_address, #{<<"fed1">> => "127.0.0.1"}}, {{s2s_default_policy, <<"anonymous.localhost">>}, allow}, {{s2s_default_policy, <<"localhost">>}, allow}, {{s2s_default_policy, <<"localhost.bis">>}, allow}, @@ -346,6 +361,10 @@ options("outgoing_pools") -> {registration_timeout, 600}, {routing_modules, mongoose_router:default_routing_modules()}, {sm_backend, {mnesia, []}}, + {s2s_dns, #{retries => 2, timeout => 10}}, + {s2s_outgoing, #{connection_timeout => 10000, + ip_versions => [4, 6], + port => 5269}}, {{auth, <<"anonymous.localhost">>}, default_auth()}, {{auth, <<"localhost">>}, default_auth()}, {{auth, <<"localhost.bis">>}, default_auth()}, @@ -365,15 +384,11 @@ options("s2s_only") -> {listen, []}, {loglevel, warning}, {mongooseimctl_access_commands, []}, - {outgoing_s2s_families, [ipv4, ipv6]}, - {outgoing_s2s_port, 5299}, - {outgoing_s2s_timeout, 10000}, {rdbms_server_type, generic}, {registration_timeout, 600}, {routing_modules, mongoose_router:default_routing_modules()}, {s2s_certfile, "tools/ssl/mongooseim/server.pem"}, {s2s_ciphers, "TLSv1.2:TLSv1.3"}, - {s2s_dns_options, [{retries, 1}, {timeout, 30}]}, {s2s_use_starttls, optional}, {sm_backend, {mnesia, []}}, {{auth, <<"dummy_host">>}, default_auth()}, @@ -384,6 +399,10 @@ options("s2s_only") -> {{replaced_wait_timeout, <<"localhost">>}, 2000}, {s2s_address, #{<<"fed1">> => "127.0.0.1", <<"fed2">> => {"127.0.0.1", 8765}}}, + {s2s_dns, #{retries => 1, timeout => 30}}, + {s2s_outgoing, #{connection_timeout => 4000, + ip_versions => [6, 4], + port => 5299}}, {{s2s_default_policy, <<"dummy_host">>}, allow}, {{s2s_default_policy, <<"localhost">>}, allow}, {{s2s_max_retry_delay, <<"dummy_host">>}, 30}, diff --git a/test/mongoose_config_SUITE.erl b/test/mongoose_config_SUITE.erl index 44adb8e5569..ccc8f849135 100644 --- a/test/mongoose_config_SUITE.erl +++ b/test/mongoose_config_SUITE.erl @@ -184,6 +184,10 @@ minimal_config_opts() -> {rdbms_server_type, generic}, {registration_timeout, 600}, {routing_modules, mongoose_router:default_routing_modules()}, + {s2s_dns, #{retries => 2,timeout => 10}}, + {s2s_outgoing, #{connection_timeout => 10000, + ip_versions => [4, 6], + port => 5269}}, {sm_backend, {mnesia, []}}, {{auth, <<"localhost">>}, config_parser_helper:default_auth()}, {{modules, <<"localhost">>}, #{}},