Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/processone/ejabberd.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Khramtsov <ekhramtsov@process-one.net>2019-06-23 13:12:00 +0300
committerEvgeny Khramtsov <ekhramtsov@process-one.net>2019-06-23 13:12:00 +0300
commit83c291c0647c8feba188640656fa84bf3b325731 (patch)
treea9ec1058fd0cbc706f394dfa64f492dd50261cd7
parente477a8c2201cb341aeeca23be49cf64188d96567 (diff)
Respond with 'Bad Request' to unexpected 'Host' header
Where "unexpected" means the host in 'Host' header is not a registered route. The rationale is to avoid propagation of uknown "Host" further in the code, which may lead to nasty errors related to reading configuration values, calling functions from ejabberd_router.erl, etc.
-rw-r--r--src/ejabberd_http.erl90
1 files changed, 43 insertions, 47 deletions
diff --git a/src/ejabberd_http.erl b/src/ejabberd_http.erl
index 39413e2f3..6f90cfcd7 100644
--- a/src/ejabberd_http.erl
+++ b/src/ejabberd_http.erl
@@ -127,14 +127,12 @@ init(SockMod, Socket, Opts) ->
RequestHandlers = proplists:get_value(request_handlers, Opts, []),
?DEBUG("S: ~p~n", [RequestHandlers]),
- DefaultHost = proplists:get_value(default_host, Opts),
{ok, RE} = re:compile(<<"^(?:\\[(.*?)\\]|(.*?))(?::(\\d+))?$">>),
CustomHeaders = proplists:get_value(custom_headers, Opts, []),
State = #state{sockmod = SockMod1,
socket = Socket1,
- default_host = DefaultHost,
custom_headers = CustomHeaders,
options = Opts,
request_handlers = RequestHandlers,
@@ -264,19 +262,20 @@ process_header(State, Data) ->
{http_header, _, 'Accept-Language' = Name, _, Langs}} ->
State#state{request_lang = parse_lang(Langs),
request_headers = add_header(Name, Langs, State)};
- {ok, {http_header, _, 'Host' = Name, _, Host}} ->
+ {ok, {http_header, _, 'Host' = Name, _, Value}} ->
+ {Host, Port, TP} = get_transfer_protocol(State#state.addr_re, SockMod, Value),
State#state{request_host = Host,
- request_headers = add_header(Name, Host, State)};
+ request_port = Port,
+ request_tp = TP,
+ request_headers = add_header(Name, Value, State)};
{ok, {http_header, _, Name, _, Value}} when is_binary(Name) ->
State#state{request_headers =
add_header(normalize_header_name(Name), Value, State)};
{ok, {http_header, _, Name, _, Value}} ->
State#state{request_headers =
add_header(Name, Value, State)};
- {ok, http_eoh}
- when State#state.request_host == undefined ->
- ?DEBUG("An HTTP request without 'Host' HTTP "
- "header was received.", []),
+ {ok, http_eoh} when State#state.request_host == undefined;
+ State#state.request_host == error ->
{State1, Out} = process_request(State),
send_text(State1, Out),
process_header(State, {ok, {http_error, <<>>}});
@@ -284,32 +283,33 @@ process_header(State, Data) ->
?DEBUG("(~w) http query: ~w ~p~n",
[State#state.socket, State#state.request_method,
element(2, State#state.request_path)]),
- {HostProvided, Port, TP} =
- get_transfer_protocol(State#state.addr_re, SockMod,
- State#state.request_host),
- Host = get_host_really_served(State#state.default_host,
- HostProvided),
- State2 = State#state{request_host = Host,
- request_port = Port, request_tp = TP},
- {State3, Out} = process_request(State2),
- 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}
+ 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;
_ ->
#state{end_of_request = true,
@@ -323,14 +323,6 @@ process_header(State, Data) ->
add_header(Name, Value, State)->
[{Name, Value} | State#state.request_headers].
-get_host_really_served(undefined, Provided) ->
- Provided;
-get_host_really_served(Default, Provided) ->
- case ejabberd_router:is_my_host(Provided) of
- true -> Provided;
- false -> Default
- end.
-
get_transfer_protocol(RE, SockMod, HostPort) ->
{Proto, DefPort} = case SockMod of
gen_tcp -> {http, 80};
@@ -338,15 +330,15 @@ get_transfer_protocol(RE, SockMod, HostPort) ->
end,
{Host, Port} = case re:run(HostPort, RE, [{capture,[1,2,3],binary}]) of
nomatch ->
- {<<"0.0.0.0">>, DefPort};
+ {error, DefPort};
{match, [<<>>, H, <<>>]} ->
- {H, DefPort};
+ {jid:nameprep(H), DefPort};
{match, [H, <<>>, <<>>]} ->
- {H, DefPort};
+ {jid:nameprep(H), DefPort};
{match, [<<>>, H, PortStr]} ->
- {H, binary_to_integer(PortStr)};
+ {jid:nameprep(H), binary_to_integer(PortStr)};
{match, [H, <<>>, PortStr]} ->
- {H, binary_to_integer(PortStr)}
+ {jid:nameprep(H), binary_to_integer(PortStr)}
end,
{Host, Port, Proto}.
@@ -438,6 +430,10 @@ process_request(#state{request_host = undefined,
custom_headers = CustomHeaders} = State) ->
{State, make_text_output(State, 400, CustomHeaders,
<<"Missing Host header">>)};
+process_request(#state{request_host = error,
+ custom_headers = CustomHeaders} = State) ->
+ {State, make_text_output(State, 400, CustomHeaders,
+ <<"Malformed Host header">>)};
process_request(#state{request_method = Method,
request_auth = Auth,
request_lang = Lang,