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

View File

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

View File

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

View File

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

View File

@ -95,13 +95,29 @@ process([<<"register.css">>],
process([<<"new">>],
#request{method = 'GET', lang = Lang, host = Host,
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">>],
#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">>],
#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">>],
#request{method = 'POST', q = Q, ip = {Ip, _Port},
lang = Lang, host = _HTTPHost}) ->