[MEDIUM] add the "except" keyword to the "forwardfor" option

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.
This commit is contained in:
Willy Tarreau 2007-03-25 16:00:04 +02:00
parent 95c20aca35
commit 7ac51f61f5
5 changed files with 60 additions and 13 deletions

View 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

View 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

View 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) */

View 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;

View File

@ -1656,9 +1656,19 @@ 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) {
/* 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]);
@ -1666,7 +1676,11 @@ int process_cli(struct session *t)
&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,