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"
|
||||
|
||||
|
||||
option forwardfor [ except <network> ]
|
||||
option forwardfor [ except <network> ] [ header <name> ]
|
||||
Enable insertion of the X-Forwarded-For header to requests sent to servers
|
||||
May be used in sections : defaults | frontend | listen | backend
|
||||
yes | yes | yes | yes
|
||||
Arguments :
|
||||
<network> is an optional argument used to disable this option for sources
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
when using this option.
|
||||
|
||||
Example :
|
||||
Examples :
|
||||
# Public HTTP address also used by stunnel on the same machine
|
||||
frontend www
|
||||
mode http
|
||||
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"
|
||||
|
||||
|
||||
|
||||
@ -108,6 +108,9 @@
|
||||
#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\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.
|
||||
*
|
||||
* 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 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 */
|
||||
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_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")) {
|
||||
/* insert x-forwarded-for field, but not for the
|
||||
* IP address listed as an except.
|
||||
int cur_arg;
|
||||
|
||||
/* 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")) {
|
||||
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]);
|
||||
|
||||
curproxy->options |= PR_O_FWDFOR;
|
||||
|
||||
free(curproxy->fwdfor_hdr_name);
|
||||
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;
|
||||
}
|
||||
/* 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]);
|
||||
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 {
|
||||
/* unknown suboption - catchall */
|
||||
Alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except' and 'header'.\n",
|
||||
file, linenum, args[0], args[1]);
|
||||
return -1;
|
||||
}
|
||||
curproxy->options |= PR_O_FWDFOR;
|
||||
} /* end while loop */
|
||||
}
|
||||
else {
|
||||
Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
|
||||
|
||||
@ -2214,8 +2214,19 @@ int process_cli(struct session *t)
|
||||
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]);
|
||||
/* 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, ": %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)
|
||||
@ -2231,7 +2242,21 @@ int process_cli(struct session *t)
|
||||
inet_ntop(AF_INET6,
|
||||
(const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
|
||||
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,
|
||||
&txn->hdr_idx, trash, len)) < 0)
|
||||
goto return_bad_req;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user