25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-12-22 17:28:25 +01:00

Don't treat 'Host' header as a virtual XMPP host

Fixes #2989
This commit is contained in:
Evgeny Khramtsov 2019-08-13 18:30:28 +03:00
parent 0bb14bdc0b
commit 9ec69b8d62
5 changed files with 79 additions and 69 deletions

View File

@ -280,37 +280,29 @@ process_header(State, Data) ->
send_text(State1, Out), send_text(State1, Out),
process_header(State, {ok, {http_error, <<>>}}); process_header(State, {ok, {http_error, <<>>}});
{ok, http_eoh} -> {ok, http_eoh} ->
?DEBUG("(~w) http query: ~w ~p~n", ?DEBUG("(~w) http query: ~w ~p~n",
[State#state.socket, State#state.request_method, [State#state.socket, State#state.request_method,
element(2, State#state.request_path)]), element(2, State#state.request_path)]),
case ejabberd_router:is_my_route(State#state.request_host) of {State3, Out} = process_request(State),
true -> send_text(State3, Out),
{State3, Out} = process_request(State), case State3#state.request_keepalive of
send_text(State3, Out), true ->
case State3#state.request_keepalive of #state{sockmod = SockMod, socket = Socket,
true -> trail = State3#state.trail,
#state{sockmod = SockMod, socket = Socket, options = State#state.options,
trail = State3#state.trail, default_host = State#state.default_host,
options = State#state.options, custom_headers = State#state.custom_headers,
default_host = State#state.default_host, request_handlers = State#state.request_handlers,
custom_headers = State#state.custom_headers, addr_re = State#state.addr_re};
request_handlers = State#state.request_handlers, _ ->
addr_re = State#state.addr_re}; #state{end_of_request = true,
_ -> trail = State3#state.trail,
#state{end_of_request = true, options = State#state.options,
trail = State3#state.trail, default_host = State#state.default_host,
options = State#state.options, custom_headers = State#state.custom_headers,
default_host = State#state.default_host, request_handlers = State#state.request_handlers,
custom_headers = State#state.custom_headers, addr_re = State#state.addr_re}
request_handlers = State#state.request_handlers, end;
addr_re = State#state.addr_re}
end;
false ->
Out = make_text_output(State, 400, State#state.custom_headers,
<<"Host not served">>),
send_text(State, Out),
process_header(State, {ok, {http_error, <<>>}})
end;
_ -> _ ->
#state{end_of_request = true, #state{end_of_request = true,
options = State#state.options, options = State#state.options,
@ -475,7 +467,7 @@ process_request(#state{request_method = Method,
{error, _} = E -> throw(E) {error, _} = E -> throw(E)
end, end,
XFF = proplists:get_value('X-Forwarded-For', RequestHeaders, []), XFF = proplists:get_value('X-Forwarded-For', RequestHeaders, []),
IP = analyze_ip_xff(IPHere, XFF, Host), IP = analyze_ip_xff(IPHere, XFF),
Request = #request{method = Method, Request = #request{method = Method,
path = LPath, path = LPath,
q = LQuery, q = LQuery,
@ -526,12 +518,11 @@ make_bad_request(State) ->
[{xmlcdata, [{xmlcdata,
<<"400 Bad Request">>}]}])). <<"400 Bad Request">>}]}])).
analyze_ip_xff(IP, [], _Host) -> IP; analyze_ip_xff(IP, []) -> IP;
analyze_ip_xff({IPLast, Port}, XFF, Host) -> analyze_ip_xff({IPLast, Port}, XFF) ->
[ClientIP | ProxiesIPs] = str:tokens(XFF, <<", ">>) ++ [ClientIP | ProxiesIPs] = str:tokens(XFF, <<", ">>) ++
[misc:ip_to_list(IPLast)], [misc:ip_to_list(IPLast)],
ServerHost = ejabberd_router:host_of_route(Host), TrustedProxies = ejabberd_option:trusted_proxies(),
TrustedProxies = ejabberd_option:trusted_proxies(ServerHost),
IPClient = case is_ipchain_trusted(ProxiesIPs, IPClient = case is_ipchain_trusted(ProxiesIPs,
TrustedProxies) TrustedProxies)
of of

View File

@ -147,7 +147,7 @@
-export([sql_start_interval/0, sql_start_interval/1]). -export([sql_start_interval/0, sql_start_interval/1]).
-export([sql_type/0, sql_type/1]). -export([sql_type/0, sql_type/1]).
-export([sql_username/0, sql_username/1]). -export([sql_username/0, sql_username/1]).
-export([trusted_proxies/0, trusted_proxies/1]). -export([trusted_proxies/0]).
-export([use_cache/0, use_cache/1]). -export([use_cache/0, use_cache/1]).
-export([validate_stream/0]). -export([validate_stream/0]).
-export([version/0]). -export([version/0]).
@ -991,10 +991,7 @@ sql_username(Host) ->
-spec trusted_proxies() -> 'all' | [{inet:ip4_address() | inet:ip6_address(),byte()}]. -spec trusted_proxies() -> 'all' | [{inet:ip4_address() | inet:ip6_address(),byte()}].
trusted_proxies() -> trusted_proxies() ->
trusted_proxies(global). ejabberd_config:get_option({trusted_proxies, global}).
-spec trusted_proxies(global | binary()) -> 'all' | [{inet:ip4_address() | inet:ip6_address(),byte()}].
trusted_proxies(Host) ->
ejabberd_config:get_option({trusted_proxies, Host}).
-spec use_cache() -> boolean(). -spec use_cache() -> boolean().
use_cache() -> use_cache() ->

View File

@ -698,6 +698,7 @@ globals() ->
sm_cache_life_time, sm_cache_life_time,
sm_cache_missed, sm_cache_missed,
sm_cache_size, sm_cache_size,
trusted_proxies,
validate_stream, validate_stream,
version, version,
websocket_origin, websocket_origin,

View File

@ -213,31 +213,36 @@ process(RPath,
#request{auth = Auth, lang = Lang, host = HostHTTP, #request{auth = Auth, lang = Lang, host = HostHTTP,
method = Method} = method = Method} =
Request) -> Request) ->
case get_auth_admin(Auth, HostHTTP, RPath, Method) of case ejabberd_router:is_my_host(HostHTTP) of
{ok, {User, Server}} -> true ->
AJID = get_jid(Auth, HostHTTP, Method), case get_auth_admin(Auth, HostHTTP, RPath, Method) of
process_admin(global, {ok, {User, Server}} ->
Request#request{path = RPath, AJID = get_jid(Auth, HostHTTP, Method),
us = {User, Server}}, process_admin(global,
AJID); Request#request{path = RPath,
{unauthorized, <<"no-auth-provided">>} -> us = {User, Server}},
{401, AJID);
[{<<"WWW-Authenticate">>, {unauthorized, <<"no-auth-provided">>} ->
<<"basic realm=\"ejabberd\"">>}], {401,
ejabberd_web:make_xhtml([?XCT(<<"h1">>, [{<<"WWW-Authenticate">>,
?T("Unauthorized"))])}; <<"basic realm=\"ejabberd\"">>}],
{unauthorized, Error} -> ejabberd_web:make_xhtml([?XCT(<<"h1">>,
{BadUser, _BadPass} = Auth, ?T("Unauthorized"))])};
{IPT, _Port} = Request#request.ip, {unauthorized, Error} ->
IPS = ejabberd_config:may_hide_data(misc:ip_to_list(IPT)), {BadUser, _BadPass} = Auth,
?WARNING_MSG("Access of ~p from ~p failed with error: ~p", {IPT, _Port} = Request#request.ip,
[BadUser, IPS, Error]), IPS = ejabberd_config:may_hide_data(misc:ip_to_list(IPT)),
{401, ?WARNING_MSG("Access of ~p from ~p failed with error: ~p",
[{<<"WWW-Authenticate">>, [BadUser, IPS, Error]),
<<"basic realm=\"auth error, retry login " {401,
"to ejabberd\"">>}], [{<<"WWW-Authenticate">>,
ejabberd_web:make_xhtml([?XCT(<<"h1">>, <<"basic realm=\"auth error, retry login "
?T("Unauthorized"))])} "to ejabberd\"">>}],
ejabberd_web:make_xhtml([?XCT(<<"h1">>,
?T("Unauthorized"))])}
end;
false ->
ejabberd_web:error(not_found)
end. end.
get_auth_admin(Auth, HostHTTP, RPath, Method) -> get_auth_admin(Auth, HostHTTP, RPath, Method) ->

View File

@ -95,13 +95,29 @@ process([<<"register.css">>],
process([<<"new">>], process([<<"new">>],
#request{method = 'GET', lang = Lang, host = Host, #request{method = 'GET', lang = Lang, host = Host,
ip = IP}) -> ip = IP}) ->
{Addr, _Port} = IP, form_new_get(Host, Lang, Addr); case ejabberd_router:is_my_host(Host) of
true ->
{Addr, _Port} = IP,
form_new_get(Host, Lang, Addr);
false ->
{400, [], <<"Host not served">>}
end;
process([<<"delete">>], process([<<"delete">>],
#request{method = 'GET', lang = Lang, host = Host}) -> #request{method = 'GET', lang = Lang, host = Host}) ->
form_del_get(Host, Lang); case ejabberd_router:is_my_host(Host) of
true ->
form_del_get(Host, Lang);
false ->
{400, [], <<"Host not served">>}
end;
process([<<"change_password">>], process([<<"change_password">>],
#request{method = 'GET', lang = Lang, host = Host}) -> #request{method = 'GET', lang = Lang, host = Host}) ->
form_changepass_get(Host, Lang); case ejabberd_router:is_my_host(Host) of
true ->
form_changepass_get(Host, Lang);
false ->
{400, [], <<"Host not served">>}
end;
process([<<"new">>], process([<<"new">>],
#request{method = 'POST', q = Q, ip = {Ip, _Port}, #request{method = 'POST', q = Q, ip = {Ip, _Port},
lang = Lang, host = _HTTPHost}) -> lang = Lang, host = _HTTPHost}) ->