]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] add the "except" keyword to the "forwardfor" option
authorWilly Tarreau <w@1wt.eu>
Sun, 25 Mar 2007 14:00:04 +0000 (16:00 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 25 Mar 2007 14:00:04 +0000 (16:00 +0200)
Patch from Bryan Germann for 1.2.17.
In some circumstances, it is useful not to add the X-Forwarded-For
header, for instance when the client is another reverse-proxy or
stunnel running on the same machine and which already adds it. This
patch adds the "except" keyword to the "forwardfor" option, allowing
to specify an address or network which will not be added to this
header.

doc/haproxy-en.txt
doc/haproxy-fr.txt
include/types/proxy.h
src/cfgparse.c
src/proto_http.c

index dbe78f5f50af9a4b879e0dc75cbd3c70aa535355..eecc6c3d6701d1654f4f282be04bee5ed113a598 100644 (file)
@@ -2142,7 +2142,12 @@ Examples :
 
 Also, the 'forwardfor' option creates an HTTP 'X-Forwarded-For' header which
 contains the client's IP address. This is useful to let the final web server
-know what the client address was (eg for statistics on domains).
+know what the client address was (eg for statistics on domains). Starting with
+version 1.3.8, it is possible to specify the "except" keyword followed by a
+source IP address or network for which no header will be added. This is very
+useful when another reverse-proxy which already adds the header runs on the
+same machine or in a known DMZ, the most common case being the local use of
+stunnel on the same system.
 
 Last, the 'httpclose' option removes any 'Connection' header both ways, and
 adds a 'Connection: close' header in each direction. This makes it easier to
@@ -2155,7 +2160,7 @@ Example :
         log  global
         option httplog
         option dontlognull
-        option forwardfor
+        option forwardfor except 127.0.0.1/8
         option httpclose
 
 Note that some HTTP servers do not necessarily close the connections when they
index 7f6d2318d1b72433e09091d3537a03eea955b991..7a2faf584dbbdffa3aa040acc161ba2948404c0e 100644 (file)
@@ -2223,7 +2223,12 @@ Exemples :
 
 De plus, l'option 'forwardfor' ajoute l'adresse IP du client dans un champ
 'X-Forwarded-For' de la requête, ce qui permet à un serveur web final de
-connaître l'adresse IP du client initial.
+connaître l'adresse IP du client initial. Depuis la version 1.3.8, il est
+possible de préciser le mot-clé "except" suivi d'une adresse ou un réseau
+IP source pour lequel l'entête ne sera pas ajouté. C'est très pratique dans le
+cas où un autre reverse-proxy ajoutant déjà l'entête est installé sur la même
+machine ou dans une DMZ connue. Le cas le plus fréquent est lié à l'utilisation
+de stunnel en local.
 
 Enfin, l'option 'httpclose' apparue dans la version 1.1.28/1.2.1 supprime tout
 en-tête de type 'Connection:' et ajoute 'Connection: close' dans les deux sens.
@@ -2237,7 +2242,7 @@ Exemple :
         log  global
         option httplog
         option dontlognull
-        option forwardfor
+        option forwardfor except 127.0.0.1/8
         option httpclose
 
 Notons que certains serveurs HTTP ne referment pas nécessairement la session
index a709ada5b35e6752d243d281edd77fc485a264b0..b598e4b2c8e133ab52ced65a38c8b887858b74ee 100644 (file)
@@ -113,6 +113,7 @@ struct proxy {
        unsigned int cum_feconn, cum_beconn;    /* cumulated number of processed sessions */
        unsigned int maxconn;                   /* max # of active sessions on the frontend */
        unsigned int fullconn;                  /* #conns on backend above which servers are used at full load */
+       struct in_addr except_net, except_mask; /* don't x-forward-for for this address. FIXME: should support IPv6 */
        unsigned failed_conns, failed_resp;     /* failed connect() and responses */
        unsigned denied_req, denied_resp;       /* blocked requests/responses because of security concerns */
        unsigned failed_req;                    /* failed requests (eg: invalid or timeout) */
index 4c1f032ec6bdb02d4208d8bc53e9e5113d356874..885a01bb5ed9cfd9a8eeaf5e30594c2f7df99538 100644 (file)
@@ -85,7 +85,6 @@ static const struct {
 #endif
        { "redispatch",   PR_O_REDISP,     PR_CAP_BE, 0 },
        { "keepalive",    PR_O_KEEPALIVE,  PR_CAP_NONE, 0 },
-       { "forwardfor",   PR_O_FWDFOR,     PR_CAP_FE | PR_CAP_BE, 0 },
        { "httpclose",    PR_O_HTTP_CLOSE, PR_CAP_FE | PR_CAP_BE, 0 },
        { "logasap",      PR_O_LOGASAP,    PR_CAP_FE, 0 },
        { "abortonclose", PR_O_ABRT_CLOSE, PR_CAP_BE, 0 },
@@ -501,6 +500,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args)
                /* set default values */
                curproxy->state = defproxy.state;
                curproxy->options = defproxy.options;
+               curproxy->except_net = defproxy.except_net;
+               curproxy->except_mask = defproxy.except_mask;
 
                if (curproxy->cap & PR_CAP_FE) {
                        curproxy->maxconn = defproxy.maxconn;
@@ -1022,6 +1023,27 @@ int cfg_parse_listen(const char *file, int linenum, char **args)
                        curproxy->options &= ~PR_O_HTTP_CHK;
                        curproxy->options |= PR_O_SSL3_CHK;
                }
+               else if (!strcmp(args[1], "forwardfor")) {
+                       /* insert x-forwarded-for field, but not for the
+                        * IP address listed as an except.
+                        */
+                       if (*(args[2])) {
+                               if (!strcmp(args[2], "except")) {
+                                       if (!*args[3] || !str2net(args[3], &curproxy->except_net, &curproxy->except_mask)) {
+                                               Alert("parsing [%s:%d] : '%s' only supports optional 'except' address[/mask].\n",
+                                                     file, linenum, args[0]);
+                                               return -1;
+                                       }
+                                       /* flush useless bits */
+                                       curproxy->except_net.s_addr &= curproxy->except_mask.s_addr;
+                               } else {
+                                       Alert("parsing [%s:%d] : '%s' only supports optional 'except' address[/mask].\n",
+                                             file, linenum, args[0]);
+                                       return -1;
+                               }
+                       }
+                       curproxy->options |= PR_O_FWDFOR;
+               }
                else {
                        Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
                        return -1;
index d3bc5f6659a519ea9fc7054ef7b2d57c28f382db..b01859080aa46be8981ae22a552935427cfb77ef 100644 (file)
@@ -1656,17 +1656,31 @@ int process_cli(struct session *t)
                 */
                if ((t->fe->options | t->be->beprm->options) & PR_O_FWDFOR) {
                        if (t->cli_addr.ss_family == AF_INET) {
-                               int len;
-                               unsigned char *pn;
-                               pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
-                               len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d",
-                                             pn[0], pn[1], pn[2], pn[3]);
-
-                               if (unlikely(http_header_add_tail2(req, &txn->req,
-                                                                  &txn->hdr_idx, trash, len)) < 0)
-                                       goto return_bad_req;
+                               /* Add an X-Forwarded-For header unless the source IP is
+                                * in the 'except' network range.
+                                */
+                               if ((!t->fe->except_mask.s_addr ||
+                                    (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->fe->except_mask.s_addr)
+                                    != t->fe->except_net.s_addr) &&
+                                   (!t->be->except_mask.s_addr ||
+                                    (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->be->except_mask.s_addr)
+                                    != t->be->except_net.s_addr)) {
+                                       int len;
+                                       unsigned char *pn;
+                                       pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
+
+                                       len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d",
+                                                     pn[0], pn[1], pn[2], pn[3]);
+
+                                       if (unlikely(http_header_add_tail2(req, &txn->req,
+                                                                          &txn->hdr_idx, trash, len)) < 0)
+                                               goto return_bad_req;
+                               }
                        }
                        else if (t->cli_addr.ss_family == AF_INET6) {
+                               /* FIXME: for the sake of completeness, we should also support
+                                * 'except' here, although it is mostly useless in this case.
+                                */
                                int len;
                                char pn[INET6_ADDRSTRLEN];
                                inet_ntop(AF_INET6,