mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-12-07 18:51:21 +01:00
[MINOR] permit renaming of x-forwarded-for header
Because I needed it in my situation - here's a quick patch to allow changing of the "x-forwarded-for" header by using a suboption to "option forwardfor". Suboption "header XYZ" will set the header from "x-forwarded-for" to "XYZ". Default is still "x-forwarded-for" if the header value isn't defined. Also the suboption 'except a.b.c.d/z' still works on the same line. So it's now: option forwardfor [except a.b.c.d[/z]] [header XYZ]
This commit is contained in:
parent
dd64f8d394
commit
af72a1d8ec
@ -1836,13 +1836,15 @@ no option forceclose
|
|||||||
See also : "option httpclose"
|
See also : "option httpclose"
|
||||||
|
|
||||||
|
|
||||||
option forwardfor [ except <network> ]
|
option forwardfor [ except <network> ] [ header <name> ]
|
||||||
Enable insertion of the X-Forwarded-For header to requests sent to servers
|
Enable insertion of the X-Forwarded-For header to requests sent to servers
|
||||||
May be used in sections : defaults | frontend | listen | backend
|
May be used in sections : defaults | frontend | listen | backend
|
||||||
yes | yes | yes | yes
|
yes | yes | yes | yes
|
||||||
Arguments :
|
Arguments :
|
||||||
<network> is an optional argument used to disable this option for sources
|
<network> is an optional argument used to disable this option for sources
|
||||||
matching <network>
|
matching <network>
|
||||||
|
<name> an optional argument to specify a different "X-Forwarded-For"
|
||||||
|
header name.
|
||||||
|
|
||||||
Since HAProxy works in reverse-proxy mode, the servers see its IP address as
|
Since HAProxy works in reverse-proxy mode, the servers see its IP address as
|
||||||
their client address. This is sometimes annoying when the client's IP address
|
their client address. This is sometimes annoying when the client's IP address
|
||||||
@ -1851,7 +1853,16 @@ option forwardfor [ except <network> ]
|
|||||||
This header contains a value representing the client's IP address. Since this
|
This header contains a value representing the client's IP address. Since this
|
||||||
header is always appended at the end of the existing header list, the server
|
header is always appended at the end of the existing header list, the server
|
||||||
must be configured to always use the last occurrence of this header only. See
|
must be configured to always use the last occurrence of this header only. See
|
||||||
the server's manual to find how to enable use of this standard header.
|
the server's manual to find how to enable use of this standard header. Note
|
||||||
|
that only the last occurrence of the header must be used, since it is really
|
||||||
|
possible that the client has already brought one.
|
||||||
|
|
||||||
|
The keyword "header" may be used to supply a different header name to replace
|
||||||
|
the default "X-Forwarded-For". This can be useful where you might already
|
||||||
|
have a "X-Forwarded-For" header from a different application (eg: stunnel),
|
||||||
|
and you need preserve it. Also if your backend server doesn't use the
|
||||||
|
"X-Forwarded-For" header and requires different one (eg: Zeus Web Servers
|
||||||
|
require "X-Cluster-Client-IP").
|
||||||
|
|
||||||
Sometimes, a same HAProxy instance may be shared between a direct client
|
Sometimes, a same HAProxy instance may be shared between a direct client
|
||||||
access and a reverse-proxy access (for instance when an SSL reverse-proxy is
|
access and a reverse-proxy access (for instance when an SSL reverse-proxy is
|
||||||
@ -1862,19 +1873,26 @@ option forwardfor [ except <network> ]
|
|||||||
private networks or 127.0.0.1.
|
private networks or 127.0.0.1.
|
||||||
|
|
||||||
This option may be specified either in the frontend or in the backend. If at
|
This option may be specified either in the frontend or in the backend. If at
|
||||||
least one of them uses it, the header will be added.
|
least one of them uses it, the header will be added. Note that the backend's
|
||||||
|
setting of the header subargument takes precedence over the frontend's if
|
||||||
|
both are defined.
|
||||||
|
|
||||||
It is important to note that as long as HAProxy does not support keep-alive
|
It is important to note that as long as HAProxy does not support keep-alive
|
||||||
connections, only the first request of a connection will receive the header.
|
connections, only the first request of a connection will receive the header.
|
||||||
For this reason, it is important to ensure that "option httpclose" is set
|
For this reason, it is important to ensure that "option httpclose" is set
|
||||||
when using this option.
|
when using this option.
|
||||||
|
|
||||||
Example :
|
Examples :
|
||||||
# Public HTTP address also used by stunnel on the same machine
|
# Public HTTP address also used by stunnel on the same machine
|
||||||
frontend www
|
frontend www
|
||||||
mode http
|
mode http
|
||||||
option forwardfor except 127.0.0.1 # stunnel already adds the header
|
option forwardfor except 127.0.0.1 # stunnel already adds the header
|
||||||
|
|
||||||
|
# Those servers want the IP Address in X-Client
|
||||||
|
backend www
|
||||||
|
mode http
|
||||||
|
option forwardfor header X-Client
|
||||||
|
|
||||||
See also : "option httpclose"
|
See also : "option httpclose"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -108,6 +108,9 @@
|
|||||||
#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
|
#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
|
||||||
#define DEF_SMTP_CHECK_REQ "HELO localhost\r\n"
|
#define DEF_SMTP_CHECK_REQ "HELO localhost\r\n"
|
||||||
|
|
||||||
|
// X-Forwarded-For header default
|
||||||
|
#define DEF_XFORWARDFOR_HDR "X-Forwarded-For"
|
||||||
|
|
||||||
/* Default connections limit.
|
/* Default connections limit.
|
||||||
*
|
*
|
||||||
* A system limit can be enforced at build time in order to avoid using haproxy
|
* A system limit can be enforced at build time in order to avoid using haproxy
|
||||||
|
|||||||
@ -206,6 +206,8 @@ struct proxy {
|
|||||||
unsigned int maxconn; /* max # of active sessions on the frontend */
|
unsigned int maxconn; /* max # of active sessions on the frontend */
|
||||||
unsigned int fullconn; /* #conns on backend above which servers are used at full load */
|
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 */
|
struct in_addr except_net, except_mask; /* don't x-forward-for for this address. FIXME: should support IPv6 */
|
||||||
|
char *fwdfor_hdr_name; /* header to use - default: "x-forwarded-for" */
|
||||||
|
int fwdfor_hdr_len; /* length of "x-forwarded-for" header */
|
||||||
|
|
||||||
unsigned down_trans; /* up-down transitions */
|
unsigned down_trans; /* up-down transitions */
|
||||||
unsigned down_time; /* total time the proxy was down */
|
unsigned down_time; /* total time the proxy was down */
|
||||||
|
|||||||
@ -1443,25 +1443,49 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!strcmp(args[1], "forwardfor")) {
|
else if (!strcmp(args[1], "forwardfor")) {
|
||||||
/* insert x-forwarded-for field, but not for the
|
int cur_arg;
|
||||||
* IP address listed as an except.
|
|
||||||
|
/* insert x-forwarded-for field, but not for the IP address listed as an except.
|
||||||
|
* set default options (ie: bitfield, header name, etc)
|
||||||
*/
|
*/
|
||||||
if (*(args[2])) {
|
|
||||||
if (!strcmp(args[2], "except")) {
|
curproxy->options |= PR_O_FWDFOR;
|
||||||
if (!*args[3] || !str2net(args[3], &curproxy->except_net, &curproxy->except_mask)) {
|
|
||||||
Alert("parsing [%s:%d] : '%s' only supports optional 'except' address[/mask].\n",
|
free(curproxy->fwdfor_hdr_name);
|
||||||
file, linenum, args[0]);
|
curproxy->fwdfor_hdr_name = strdup(DEF_XFORWARDFOR_HDR);
|
||||||
|
curproxy->fwdfor_hdr_len = strlen(DEF_XFORWARDFOR_HDR);
|
||||||
|
|
||||||
|
/* loop to go through arguments - start at 2, since 0+1 = "option" "forwardfor" */
|
||||||
|
cur_arg = 2;
|
||||||
|
while (*(args[cur_arg])) {
|
||||||
|
if (!strcmp(args[cur_arg], "except")) {
|
||||||
|
/* suboption except - needs additional argument for it */
|
||||||
|
if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], &curproxy->except_net, &curproxy->except_mask)) {
|
||||||
|
Alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
|
||||||
|
file, linenum, args[0], args[1], args[cur_arg]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* flush useless bits */
|
/* flush useless bits */
|
||||||
curproxy->except_net.s_addr &= curproxy->except_mask.s_addr;
|
curproxy->except_net.s_addr &= curproxy->except_mask.s_addr;
|
||||||
|
cur_arg += 2;
|
||||||
|
} else if (!strcmp(args[cur_arg], "header")) {
|
||||||
|
/* suboption header - needs additional argument for it */
|
||||||
|
if (*(args[cur_arg+1]) == 0) {
|
||||||
|
Alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
|
||||||
|
file, linenum, args[0], args[1], args[cur_arg]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(curproxy->fwdfor_hdr_name);
|
||||||
|
curproxy->fwdfor_hdr_name = strdup(args[cur_arg+1]);
|
||||||
|
curproxy->fwdfor_hdr_len = strlen(curproxy->fwdfor_hdr_name);
|
||||||
|
cur_arg += 2;
|
||||||
} else {
|
} else {
|
||||||
Alert("parsing [%s:%d] : '%s' only supports optional 'except' address[/mask].\n",
|
/* unknown suboption - catchall */
|
||||||
file, linenum, args[0]);
|
Alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except' and 'header'.\n",
|
||||||
|
file, linenum, args[0], args[1]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
} /* end while loop */
|
||||||
curproxy->options |= PR_O_FWDFOR;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
|
Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
|
||||||
|
|||||||
@ -2214,10 +2214,21 @@ int process_cli(struct session *t)
|
|||||||
unsigned char *pn;
|
unsigned char *pn;
|
||||||
pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
|
pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
|
||||||
|
|
||||||
len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d",
|
/* Note: we rely on the backend to get the header name to be used for
|
||||||
pn[0], pn[1], pn[2], pn[3]);
|
* x-forwarded-for, because the header is really meant for the backends.
|
||||||
|
* However, if the backend did not specify any option, we have to rely
|
||||||
|
* on the frontend's header name.
|
||||||
|
*/
|
||||||
|
if (t->be->fwdfor_hdr_len) {
|
||||||
|
len = t->be->fwdfor_hdr_len;
|
||||||
|
memcpy(trash, t->be->fwdfor_hdr_name, len);
|
||||||
|
} else {
|
||||||
|
len = t->fe->fwdfor_hdr_len;
|
||||||
|
memcpy(trash, t->fe->fwdfor_hdr_name, len);
|
||||||
|
}
|
||||||
|
len += sprintf(trash + len, ": %d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
|
||||||
|
|
||||||
if (unlikely(http_header_add_tail2(req, &txn->req,
|
if (unlikely(http_header_add_tail2(req, &txn->req,
|
||||||
&txn->hdr_idx, trash, len)) < 0)
|
&txn->hdr_idx, trash, len)) < 0)
|
||||||
goto return_bad_req;
|
goto return_bad_req;
|
||||||
}
|
}
|
||||||
@ -2231,7 +2242,21 @@ int process_cli(struct session *t)
|
|||||||
inet_ntop(AF_INET6,
|
inet_ntop(AF_INET6,
|
||||||
(const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
|
(const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
|
||||||
pn, sizeof(pn));
|
pn, sizeof(pn));
|
||||||
len = sprintf(trash, "X-Forwarded-For: %s", pn);
|
|
||||||
|
/* Note: we rely on the backend to get the header name to be used for
|
||||||
|
* x-forwarded-for, because the header is really meant for the backends.
|
||||||
|
* However, if the backend did not specify any option, we have to rely
|
||||||
|
* on the frontend's header name.
|
||||||
|
*/
|
||||||
|
if (t->be->fwdfor_hdr_len) {
|
||||||
|
len = t->be->fwdfor_hdr_len;
|
||||||
|
memcpy(trash, t->be->fwdfor_hdr_name, len);
|
||||||
|
} else {
|
||||||
|
len = t->fe->fwdfor_hdr_len;
|
||||||
|
memcpy(trash, t->fe->fwdfor_hdr_name, len);
|
||||||
|
}
|
||||||
|
len += sprintf(trash + len, ": %s", pn);
|
||||||
|
|
||||||
if (unlikely(http_header_add_tail2(req, &txn->req,
|
if (unlikely(http_header_add_tail2(req, &txn->req,
|
||||||
&txn->hdr_idx, trash, len)) < 0)
|
&txn->hdr_idx, trash, len)) < 0)
|
||||||
goto return_bad_req;
|
goto return_bad_req;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user