From c20d745028dcf2c772c581ae2cae2f88df565679 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 17 Jun 2025 17:31:49 +0200 Subject: [PATCH] New option hosts_alias and function resolve_host_alias/1 (4400) --- src/ejabberd_config.erl | 40 ++++++++++++++++++++++++++++++++++++ src/ejabberd_http.erl | 2 +- src/ejabberd_option.erl | 5 +++++ src/ejabberd_options.erl | 9 ++++++++ src/ejabberd_options_doc.erl | 17 +++++++++++++++ 5 files changed, 72 insertions(+), 1 deletion(-) diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 3a556d7f6..3344a3f15 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -39,6 +39,7 @@ -export([callback_modules/1]). -export([set_option/2]). -export([get_defined_keywords/1, get_predefined_keywords/1, replace_keywords/2, replace_keywords/3]). +-export([resolve_host_alias/1]). %% Deprecated functions -export([get_option/2]). @@ -510,6 +511,45 @@ get_predefined_keywords(Host) -> {<<"VERSION">>, misc:semver_to_xxyy( ejabberd_option:version())}]. + +resolve_host_alias(Host) -> + case lists:member(Host, ejabberd_option:hosts()) of + true -> + Host; + false -> + resolve_host_alias2(Host) + end. + +resolve_host_alias2(Host) -> + Result = + lists:filter(fun({Alias1, _Vhost}) -> is_glob_match(Host, Alias1) end, + ejabberd_option:hosts_alias()), + case Result of + [{_, Vhost} | _] when is_binary(Vhost) -> + ?DEBUG("(~p) Alias host '~s' resolved into vhost '~s'", [self(), Host, Vhost]), + Vhost; + [] -> + ?DEBUG("(~p) Request sent to host '~s', which isn't a vhost or an alias", + [self(), Host]), + Host + end. + +%% Copied from ejabberd-2.0.0/src/acl.erl +is_regexp_match(String, RegExp) -> + case ejabberd_regexp:run(String, RegExp) of + nomatch -> + false; + match -> + true; + {error, ErrDesc} -> + io:format("Wrong regexp ~p in ACL: ~p", [RegExp, ErrDesc]), + false + end. + +is_glob_match(String, <<"!", Glob/binary>>) -> + not is_regexp_match(String, ejabberd_regexp:sh_to_awk(Glob)); +is_glob_match(String, Glob) -> + is_regexp_match(String, ejabberd_regexp:sh_to_awk(Glob)). %% @format-end %%%=================================================================== diff --git a/src/ejabberd_http.erl b/src/ejabberd_http.erl index 0e09c26c9..0ca7d3ff0 100644 --- a/src/ejabberd_http.erl +++ b/src/ejabberd_http.erl @@ -273,7 +273,7 @@ process_header(State, Data) -> request_headers = add_header(Name, Langs, State)}; {ok, {http_header, _, 'Host' = Name, _, Value}} -> {Host, Port, TP} = get_transfer_protocol(State#state.addr_re, SockMod, Value), - State#state{request_host = Host, + State#state{request_host = ejabberd_config:resolve_host_alias(Host), request_port = Port, request_tp = TP, request_headers = add_header(Name, Value, State)}; diff --git a/src/ejabberd_option.erl b/src/ejabberd_option.erl index d9ded9bdf..3a69da867 100644 --- a/src/ejabberd_option.erl +++ b/src/ejabberd_option.erl @@ -55,6 +55,7 @@ -export([hide_sensitive_log_data/0, hide_sensitive_log_data/1]). -export([host_config/0]). -export([hosts/0]). +-export([hosts_alias/0]). -export([include_config_file/0, include_config_file/1]). -export([install_contrib_modules/0]). -export([jwt_auth_only_rule/0, jwt_auth_only_rule/1]). @@ -479,6 +480,10 @@ host_config() -> hosts() -> ejabberd_config:get_option({hosts, global}). +-spec hosts_alias() -> [{binary(),binary()}]. +hosts_alias() -> + ejabberd_config:get_option({hosts_alias, global}). + -spec include_config_file() -> any(). include_config_file() -> include_config_file(global). diff --git a/src/ejabberd_options.erl b/src/ejabberd_options.erl index 489320840..521687aa2 100644 --- a/src/ejabberd_options.erl +++ b/src/ejabberd_options.erl @@ -182,6 +182,13 @@ opt_type(host_config) -> [unique])); opt_type(hosts) -> econf:non_empty(econf:list(econf:domain(), [unique])); +opt_type(hosts_alias) -> + econf:and_then( + econf:map(econf:domain(), econf:domain(), [unique]), + econf:map( + econf:domain(), + econf:enum(ejabberd_config:get_option(hosts)), + [unique])); opt_type(include_config_file) -> econf:any(); opt_type(install_contrib_modules) -> @@ -587,6 +594,7 @@ options() -> {extauth_program, undefined}, {fqdn, fun fqdn/1}, {hide_sensitive_log_data, false}, + {hosts_alias, []}, {host_config, []}, {include_config_file, []}, {language, <<"en">>}, @@ -766,6 +774,7 @@ globals() -> ext_api_path_oauth, fqdn, hosts, + hosts_alias, host_config, install_contrib_modules, listen, diff --git a/src/ejabberd_options_doc.erl b/src/ejabberd_options_doc.erl index cbbc4be9f..375de0ca2 100644 --- a/src/ejabberd_options_doc.erl +++ b/src/ejabberd_options_doc.erl @@ -712,6 +712,23 @@ doc() -> " domain.tld:", " auth_method:", " - ldap"]}}, + {hosts_alias, + #{value => "{Alias: Host}", + desc => + ?T("Define aliases for existing vhosts managed by ejabberd. " + "An alias may be a regexp expression. " + "This option is only consulted by the 'ejabberd_http' listener."), + note => "added in 25.xx", + example => + ["hosts:", + " - domain.tld", + " - example.org", + "", + "hosts_alias:", + " xmpp.domain.tld: domain.tld", + " jabber.domain.tld: domain.tld", + " mytest.net: example.org", + " \"exa*\": example.org"]}}, {include_config_file, #{value => "[Filename, ...\\] | {Filename: Options}", desc =>