Support for X-Forwarded-For HTTP header (EJAB-1356)

This commit is contained in:
Badlop 2010-12-07 16:47:32 +01:00
parent fd828c3e9b
commit b83dd9f954
2 changed files with 36 additions and 3 deletions

View File

@ -824,7 +824,7 @@ The available modules, their purpose and the options allowed by each one are:
\titem{\texttt{ejabberd\_http}}
Handles incoming HTTP connections.\\
Options: \texttt{captcha}, \texttt{certfile}, \texttt{http\_bind}, \texttt{http\_poll},
\texttt{request\_handlers}, \texttt{tls}, \texttt{web\_admin}\\
\texttt{request\_handlers}, \texttt{tls}, \texttt{trusted\_proxies}, \texttt{web\_admin}\\
\end{description}
@ -946,6 +946,10 @@ This is a detailed description of each option allowed by the listening modules:
which can be enabled in \ejabberd{} with the option \term{starttls}.
If this option is set, you should also set the \option{certfile} option.
The option \term{tls} can also be used in \term{ejabberd\_http} to support HTTPS.
\titem{\{trusted\_proxies, all | [IpString]\}} \ind{options!trusted\_proxies}
Specify what proxies are trusted when an HTTP request contains the header \term{X-Forwarded-For}
You can specify \term{all} to allow all proxies, or specify a list of IPs in string format.
The default value is: \term{["127.0.0.1"]}
\titem{web\_admin} \ind{options!web\_admin}\ind{web admin}This option
enables the Web Admin for \ejabberd{} administration which is available
at \verb|http://server:port/admin/|. Login and password are the username and

View File

@ -362,13 +362,15 @@ process_request(#state{request_method = Method,
LQ ->
LQ
end,
{ok, IP} =
{ok, IPHere} =
case SockMod of
gen_tcp ->
inet:peername(Socket);
_ ->
SockMod:peername(Socket)
end,
XFF = proplists:get_value('X-Forwarded-For', RequestHeaders, []),
IP = analyze_ip_xff(IPHere, XFF, Host),
Request = #request{method = Method,
path = LPath,
q = LQuery,
@ -409,13 +411,15 @@ process_request(#state{request_method = Method,
request_headers = RequestHeaders,
request_handlers = RequestHandlers} = State)
when (Method=:='POST' orelse Method=:='PUT') andalso is_integer(Len) ->
{ok, IP} =
{ok, IPHere} =
case SockMod of
gen_tcp ->
inet:peername(Socket);
_ ->
SockMod:peername(Socket)
end,
XFF = proplists:get_value('X-Forwarded-For', RequestHeaders, []),
IP = analyze_ip_xff(IPHere, XFF, Host),
case SockMod of
gen_tcp ->
inet:setopts(Socket, [{packet, 0}]);
@ -466,6 +470,31 @@ process_request(State) ->
ejabberd_web:make_xhtml([{xmlelement, "h1", [],
[{xmlcdata, "400 Bad Request"}]}])).
%% Support for X-Forwarded-From
analyze_ip_xff(IP, [], _Host) ->
IP;
analyze_ip_xff({IPLast, Port}, XFF, Host) ->
[ClientIP | ProxiesIPs] = string:tokens(XFF, ", ")
++ [inet_parse:ntoa(IPLast)],
TrustedProxies = case ejabberd_config:get_local_option(
{trusted_proxies, Host}) of
undefined -> [];
TPs -> TPs
end,
IPClient = case is_ipchain_trusted(ProxiesIPs, TrustedProxies) of
true ->
{ok, IPFirst} = inet_parse:address(ClientIP),
?DEBUG("The IP ~w was replaced with ~w due to header "
"X-Forwarded-For: ~s", [IPLast, IPFirst, XFF]),
IPFirst;
false ->
IPLast
end,
{IPClient, Port}.
is_ipchain_trusted(_UserIPs, all) ->
true;
is_ipchain_trusted(UserIPs, TrustedIPs) ->
[] == UserIPs -- ["127.0.0.1" | TrustedIPs].
recv_data(State, Len) ->
recv_data(State, Len, []).