]> granicus.if.org Git - ejabberd/commitdiff
Support for X-Forwarded-For HTTP header (EJAB-1356)
authorBadlop <badlop@process-one.net>
Tue, 7 Dec 2010 15:47:32 +0000 (16:47 +0100)
committerBadlop <badlop@process-one.net>
Tue, 7 Dec 2010 15:47:55 +0000 (16:47 +0100)
doc/guide.tex
src/web/ejabberd_http.erl

index f77e1ee83693f8c8d91df10ddcff67aedc27a502..d3db10338c7bb8c562b265bccd748089d20829d7 100644 (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
index 313e0f26409b98ee642e6f7fe7966034224fcd40..37f56d08503f7ff4be5373d3cbc531ab08e2adba 100644 (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, []).