mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 07:37:02 +02:00
MEDIUM: http-ana: Add IPv6 support for forwardfor and orignialto options
A network may be specified to avoid header addition for "forwardfor" and "orignialto" option via the "except" parameter. However, only IPv4 networks/addresses are supported. This patch adds the support of IPv6. To do so, the net_addr structure is used to store the parameter value in the proxy structure. And ipcmp2net() function is used to perform the comparison. This patch should fix the issue #1145. It depends on the following commit: * c6ce0ab MINOR: tools: Add function to compare an address to a network address * 5587287 MINOR: tools: Add net_addr structure describing a network addess
This commit is contained in:
parent
9553de7fec
commit
5d1def623a
@ -7973,7 +7973,7 @@ option forwardfor [ except <network> ] [ header <name> ] [ if-none ]
|
||||
header for a known source address or network by adding the "except" keyword
|
||||
followed by the network address. In this case, any source IP matching the
|
||||
network will not cause an addition of this header. Most common uses are with
|
||||
private networks or 127.0.0.1.
|
||||
private networks or 127.0.0.1. IPv4 and IPv6 are both supported.
|
||||
|
||||
Alternatively, the keyword "if-none" states that the header will only be
|
||||
added if it is not present. This should only be used in perfectly trusted
|
||||
@ -8773,7 +8773,7 @@ option originalto [ except <network> ] [ header <name> ]
|
||||
header for a known source address or network by adding the "except" keyword
|
||||
followed by the network address. In this case, any source IP matching the
|
||||
network will not cause an addition of this header. Most common uses are with
|
||||
private networks or 127.0.0.1.
|
||||
private networks or 127.0.0.1. IPv4 and IPv6 are both supported.
|
||||
|
||||
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. Note that the backend's
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <haproxy/stats-t.h>
|
||||
#include <haproxy/tcpcheck-t.h>
|
||||
#include <haproxy/thread-t.h>
|
||||
#include <haproxy/tools-t.h>
|
||||
#include <haproxy/uri_auth-t.h>
|
||||
|
||||
/* values for proxy->mode */
|
||||
@ -341,9 +342,8 @@ struct proxy {
|
||||
unsigned int fe_sps_lim; /* limit on new sessions per second on the frontend */
|
||||
unsigned int fullconn; /* #conns on backend above which servers are used at full load */
|
||||
unsigned int tot_fe_maxconn; /* #maxconn of frontends linked to that backend, it is used to compute fullconn */
|
||||
struct in_addr except_net, except_mask; /* don't x-forward-for for this address. FIXME: should support IPv6 */
|
||||
struct in_addr except_to; /* don't x-original-to for this address. */
|
||||
struct in_addr except_mask_to; /* the netmask for except_to. */
|
||||
struct net_addr except_xff_net; /* don't x-forward-for for this address. */
|
||||
struct net_addr except_xot_net; /* don't x-original-to for this address. */
|
||||
char *fwdfor_hdr_name; /* header to use - default: "x-forwarded-for" */
|
||||
char *orgto_hdr_name; /* header to use - default: "x-original-to" */
|
||||
int fwdfor_hdr_len; /* length of "x-forwarded-for" header */
|
||||
|
@ -2107,20 +2107,35 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||
free(curproxy->fwdfor_hdr_name);
|
||||
curproxy->fwdfor_hdr_name = strdup(DEF_XFORWARDFOR_HDR);
|
||||
curproxy->fwdfor_hdr_len = strlen(DEF_XFORWARDFOR_HDR);
|
||||
curproxy->except_xff_net.family = AF_UNSPEC;
|
||||
|
||||
/* 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") == 0) {
|
||||
unsigned char mask;
|
||||
int i;
|
||||
|
||||
/* suboption except - needs additional argument for it */
|
||||
if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_net, &curproxy->except_mask)) {
|
||||
if (*(args[cur_arg+1]) &&
|
||||
str2net(args[cur_arg+1], 1, &curproxy->except_xff_net.addr.v4.ip, &curproxy->except_xff_net.addr.v4.mask)) {
|
||||
curproxy->except_xff_net.family = AF_INET;
|
||||
curproxy->except_xff_net.addr.v4.ip.s_addr &= curproxy->except_xff_net.addr.v4.mask.s_addr;
|
||||
}
|
||||
else if (*(args[cur_arg+1]) &&
|
||||
str62net(args[cur_arg+1], &curproxy->except_xff_net.addr.v6.ip, &mask)) {
|
||||
curproxy->except_xff_net.family = AF_INET6;
|
||||
len2mask6(mask, &curproxy->except_xff_net.addr.v6.mask);
|
||||
for (i = 0; i < 16; i++)
|
||||
curproxy->except_xff_net.addr.v6.ip.s6_addr[i] &= curproxy->except_xff_net.addr.v6.mask.s6_addr[i];
|
||||
}
|
||||
else {
|
||||
ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
|
||||
file, linenum, args[0], args[1], args[cur_arg]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
/* flush useless bits */
|
||||
curproxy->except_net.s_addr &= curproxy->except_mask.s_addr;
|
||||
cur_arg += 2;
|
||||
} else if (strcmp(args[cur_arg], "header") == 0) {
|
||||
/* suboption header - needs additional argument for it */
|
||||
@ -2158,20 +2173,34 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||
free(curproxy->orgto_hdr_name);
|
||||
curproxy->orgto_hdr_name = strdup(DEF_XORIGINALTO_HDR);
|
||||
curproxy->orgto_hdr_len = strlen(DEF_XORIGINALTO_HDR);
|
||||
curproxy->except_xot_net.family = AF_UNSPEC;
|
||||
|
||||
/* loop to go through arguments - start at 2, since 0+1 = "option" "originalto" */
|
||||
cur_arg = 2;
|
||||
while (*(args[cur_arg])) {
|
||||
if (strcmp(args[cur_arg], "except") == 0) {
|
||||
unsigned char mask;
|
||||
int i;
|
||||
|
||||
/* suboption except - needs additional argument for it */
|
||||
if (!*(args[cur_arg+1]) || !str2net(args[cur_arg+1], 1, &curproxy->except_to, &curproxy->except_mask_to)) {
|
||||
if (*(args[cur_arg+1]) &&
|
||||
str2net(args[cur_arg+1], 1, &curproxy->except_xot_net.addr.v4.ip, &curproxy->except_xot_net.addr.v4.mask)) {
|
||||
curproxy->except_xot_net.family = AF_INET;
|
||||
curproxy->except_xot_net.addr.v4.ip.s_addr &= curproxy->except_xot_net.addr.v4.mask.s_addr;
|
||||
}
|
||||
else if (*(args[cur_arg+1]) &&
|
||||
str62net(args[cur_arg+1], &curproxy->except_xot_net.addr.v6.ip, &mask)) {
|
||||
curproxy->except_xot_net.family = AF_INET6;
|
||||
len2mask6(mask, &curproxy->except_xot_net.addr.v6.mask);
|
||||
for (i = 0; i < 16; i++)
|
||||
curproxy->except_xot_net.addr.v6.ip.s6_addr[i] &= curproxy->except_xot_net.addr.v6.mask.s6_addr[i];
|
||||
}
|
||||
else {
|
||||
ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
|
||||
file, linenum, args[0], args[1], args[cur_arg]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
/* flush useless bits */
|
||||
curproxy->except_to.s_addr &= curproxy->except_mask_to.s_addr;
|
||||
cur_arg += 2;
|
||||
} else if (strcmp(args[cur_arg], "header") == 0) {
|
||||
/* suboption header - needs additional argument for it */
|
||||
|
@ -673,12 +673,8 @@ int http_process_request(struct stream *s, struct channel *req, int an_bit)
|
||||
/* Add an X-Forwarded-For header unless the source IP is
|
||||
* in the 'except' network range.
|
||||
*/
|
||||
if ((!sess->fe->except_mask.s_addr ||
|
||||
(((struct sockaddr_in *)cli_conn->src)->sin_addr.s_addr & sess->fe->except_mask.s_addr)
|
||||
!= sess->fe->except_net.s_addr) &&
|
||||
(!s->be->except_mask.s_addr ||
|
||||
(((struct sockaddr_in *)cli_conn->src)->sin_addr.s_addr & s->be->except_mask.s_addr)
|
||||
!= s->be->except_net.s_addr)) {
|
||||
if (ipcmp2net(cli_conn->src, &sess->fe->except_xff_net) &&
|
||||
ipcmp2net(cli_conn->src, &s->be->except_xff_net)) {
|
||||
unsigned char *pn = (unsigned char *)&((struct sockaddr_in *)cli_conn->src)->sin_addr;
|
||||
|
||||
/* Note: we rely on the backend to get the header name to be used for
|
||||
@ -692,23 +688,26 @@ int http_process_request(struct stream *s, struct channel *req, int an_bit)
|
||||
}
|
||||
}
|
||||
else if (cli_conn && conn_get_src(cli_conn) && cli_conn->src->ss_family == AF_INET6) {
|
||||
/* FIXME: for the sake of completeness, we should also support
|
||||
* 'except' here, although it is mostly useless in this case.
|
||||
/* Add an X-Forwarded-For header unless the source IP is
|
||||
* in the 'except' network range.
|
||||
*/
|
||||
char pn[INET6_ADDRSTRLEN];
|
||||
if (ipcmp2net(cli_conn->src, &sess->fe->except_xff_net) &&
|
||||
ipcmp2net(cli_conn->src, &s->be->except_xff_net)) {
|
||||
char pn[INET6_ADDRSTRLEN];
|
||||
|
||||
inet_ntop(AF_INET6,
|
||||
(const void *)&((struct sockaddr_in6 *)(cli_conn->src))->sin6_addr,
|
||||
pn, sizeof(pn));
|
||||
inet_ntop(AF_INET6,
|
||||
(const void *)&((struct sockaddr_in6 *)(cli_conn->src))->sin6_addr,
|
||||
pn, sizeof(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.
|
||||
*/
|
||||
chunk_printf(&trash, "%s", pn);
|
||||
if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
|
||||
goto return_int_err;
|
||||
/* 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.
|
||||
*/
|
||||
chunk_printf(&trash, "%s", pn);
|
||||
if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
|
||||
goto return_int_err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -717,20 +716,15 @@ int http_process_request(struct stream *s, struct channel *req, int an_bit)
|
||||
* asks for it.
|
||||
*/
|
||||
if ((sess->fe->options | s->be->options) & PR_O_ORGTO) {
|
||||
struct ist hdr = ist2(s->be->orgto_hdr_len ? s->be->orgto_hdr_name : sess->fe->orgto_hdr_name,
|
||||
s->be->orgto_hdr_len ? s->be->orgto_hdr_len : sess->fe->orgto_hdr_len);
|
||||
|
||||
/* FIXME: don't know if IPv6 can handle that case too. */
|
||||
if (cli_conn && conn_get_dst(cli_conn) && cli_conn->dst->ss_family == AF_INET) {
|
||||
/* Add an X-Original-To header unless the destination IP is
|
||||
* in the 'except' network range.
|
||||
*/
|
||||
if (cli_conn->dst->ss_family == AF_INET &&
|
||||
((!sess->fe->except_mask_to.s_addr ||
|
||||
(((struct sockaddr_in *)cli_conn->dst)->sin_addr.s_addr & sess->fe->except_mask_to.s_addr)
|
||||
!= sess->fe->except_to.s_addr) &&
|
||||
(!s->be->except_mask_to.s_addr ||
|
||||
(((struct sockaddr_in *)cli_conn->dst)->sin_addr.s_addr & s->be->except_mask_to.s_addr)
|
||||
!= s->be->except_to.s_addr))) {
|
||||
struct ist hdr;
|
||||
if (ipcmp2net(cli_conn->dst, &sess->fe->except_xot_net) &&
|
||||
ipcmp2net(cli_conn->dst, &s->be->except_xot_net)) {
|
||||
unsigned char *pn = (unsigned char *)&((struct sockaddr_in *)cli_conn->dst)->sin_addr;
|
||||
|
||||
/* Note: we rely on the backend to get the header name to be used for
|
||||
@ -738,16 +732,33 @@ int http_process_request(struct stream *s, struct channel *req, int an_bit)
|
||||
* However, if the backend did not specify any option, we have to rely
|
||||
* on the frontend's header name.
|
||||
*/
|
||||
if (s->be->orgto_hdr_len)
|
||||
hdr = ist2(s->be->orgto_hdr_name, s->be->orgto_hdr_len);
|
||||
else
|
||||
hdr = ist2(sess->fe->orgto_hdr_name, sess->fe->orgto_hdr_len);
|
||||
|
||||
chunk_printf(&trash, "%d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
|
||||
if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
|
||||
goto return_int_err;
|
||||
}
|
||||
}
|
||||
else if (cli_conn && conn_get_dst(cli_conn) && cli_conn->dst->ss_family == AF_INET6) {
|
||||
/* Add an X-Original-To header unless the source IP is
|
||||
* in the 'except' network range.
|
||||
*/
|
||||
if (ipcmp2net(cli_conn->dst, &sess->fe->except_xot_net) &&
|
||||
ipcmp2net(cli_conn->dst, &s->be->except_xot_net)) {
|
||||
char pn[INET6_ADDRSTRLEN];
|
||||
|
||||
inet_ntop(AF_INET6,
|
||||
(const void *)&((struct sockaddr_in6 *)(cli_conn->dst))->sin6_addr,
|
||||
pn, sizeof(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.
|
||||
*/
|
||||
chunk_printf(&trash, "%s", pn);
|
||||
if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
|
||||
goto return_int_err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have no server assigned yet and we're balancing on url_param
|
||||
|
@ -1229,10 +1229,8 @@ struct proxy *alloc_new_proxy(const char *name, unsigned int cap, const char *fi
|
||||
curproxy->no_options = defproxy->no_options;
|
||||
curproxy->no_options2 = defproxy->no_options2;
|
||||
curproxy->bind_proc = defproxy->bind_proc;
|
||||
curproxy->except_net = defproxy->except_net;
|
||||
curproxy->except_mask = defproxy->except_mask;
|
||||
curproxy->except_to = defproxy->except_to;
|
||||
curproxy->except_mask_to = defproxy->except_mask_to;
|
||||
curproxy->except_xff_net = defproxy->except_xff_net;
|
||||
curproxy->except_xot_net = defproxy->except_xot_net;
|
||||
curproxy->retry_type = defproxy->retry_type;
|
||||
|
||||
if (defproxy->fwdfor_hdr_len) {
|
||||
|
Loading…
Reference in New Issue
Block a user