mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-01-06 17:31:01 +01:00
MINOR: proxy: move 'originalto' option to http_ext
Just like forwarded (7239) header and forwardfor header, move parsing, logic and management of 'originalto' option into http_ext dedicated class. We're only doing this to standardize proxy http options management. Existing behavior remains untouched.
This commit is contained in:
parent
730b9836a6
commit
f958341610
@ -120,4 +120,9 @@ struct http_ext_xff {
|
||||
uint8_t mode;
|
||||
};
|
||||
|
||||
struct http_ext_xot {
|
||||
struct ist hdr_name; /* header to use - default: "x-original-to" */
|
||||
struct net_addr except_net; /* don't forward x-original-to for this address. */
|
||||
};
|
||||
|
||||
#endif /* !_HAPROXY_HTTPEXT_T_H */
|
||||
|
||||
@ -31,15 +31,19 @@ int http_validate_7239_header(struct ist hdr, int required_steps, struct forward
|
||||
|
||||
int http_handle_7239_header(struct stream *s, struct channel *req);
|
||||
int http_handle_xff_header(struct stream *s, struct channel *req);
|
||||
int http_handle_xot_header(struct stream *s, struct channel *req);
|
||||
|
||||
void http_ext_7239_clean(struct http_ext_7239 *);
|
||||
void http_ext_xff_clean(struct http_ext_xff *);
|
||||
void http_ext_xot_clean(struct http_ext_xot *);
|
||||
|
||||
void http_ext_7239_copy(struct http_ext_7239 *dest, const struct http_ext_7239 *orig);
|
||||
void http_ext_xff_copy(struct http_ext_xff *dest, const struct http_ext_xff *orig);
|
||||
void http_ext_xot_copy(struct http_ext_xot *dest, const struct http_ext_xot *orig);
|
||||
|
||||
int proxy_http_parse_7239(char **args, int cur_arg, struct proxy *curproxy, const struct proxy *defpx, const char *file, int linenum);
|
||||
int proxy_http_compile_7239(struct proxy *curproxy);
|
||||
int proxy_http_parse_xff(char **args, int cur_arg, struct proxy *curproxy, const struct proxy *defpx, const char *file, int linenum);
|
||||
int proxy_http_parse_xot(char **args, int cur_arg, struct proxy *curproxy, const struct proxy *defpx, const char *file, int linenum);
|
||||
|
||||
#endif /* !_HAPROXY_HTTPEXT_H */
|
||||
|
||||
@ -115,7 +115,7 @@ enum PR_SRV_STATE_FILE {
|
||||
#define PR_O_CONTSTATS 0x10000000 /* continuous counters */
|
||||
/* unused: 0x20000000 */
|
||||
#define PR_O_DISABLE404 0x40000000 /* Disable a server on a 404 response to a health-check */
|
||||
#define PR_O_ORGTO 0x80000000 /* insert x-original-to with destination address */
|
||||
#define PR_O_HTTP_XOT 0x80000000 /* insert x-original-to with destination address */
|
||||
|
||||
/* bits for proxy->options2 */
|
||||
#define PR_O2_SPLIC_REQ 0x00000001 /* transfer requests using linux kernel's splice() */
|
||||
@ -273,6 +273,8 @@ struct proxy_http {
|
||||
struct http_ext_7239 fwd;
|
||||
/* x-forward-for */
|
||||
struct http_ext_xff xff;
|
||||
/* x-original-to */
|
||||
struct http_ext_xot xot;
|
||||
};
|
||||
|
||||
struct proxy {
|
||||
@ -366,8 +368,6 @@ 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 net_addr except_xot_net; /* don't x-original-to for this address. */
|
||||
struct ist orgto_hdr_name; /* header to use - default: "x-original-to" */
|
||||
struct ist server_id_hdr_name; /* the header to use to send the server id (name) */
|
||||
int conn_retries; /* maximum number of connect retries */
|
||||
unsigned int retry_type; /* Type of retry allowed */
|
||||
|
||||
@ -2278,68 +2278,9 @@ stats_error_parsing:
|
||||
goto out;
|
||||
}
|
||||
else if (strcmp(args[1], "originalto") == 0) {
|
||||
int cur_arg;
|
||||
|
||||
/* insert x-original-to field, but not for the IP address listed as an except.
|
||||
* set default options (ie: bitfield, header name, etc)
|
||||
*/
|
||||
|
||||
curproxy->options |= PR_O_ORGTO;
|
||||
|
||||
istfree(&curproxy->orgto_hdr_name);
|
||||
curproxy->orgto_hdr_name = istdup(ist(DEF_XORIGINALTO_HDR));
|
||||
if (!isttest(curproxy->orgto_hdr_name))
|
||||
goto alloc_error;
|
||||
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_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;
|
||||
}
|
||||
cur_arg += 2;
|
||||
} else if (strcmp(args[cur_arg], "header") == 0) {
|
||||
/* suboption header - needs additional argument for it */
|
||||
if (*(args[cur_arg+1]) == 0) {
|
||||
ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
|
||||
file, linenum, args[0], args[1], args[cur_arg]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
istfree(&curproxy->orgto_hdr_name);
|
||||
curproxy->orgto_hdr_name = istdup(ist(args[cur_arg+1]));
|
||||
if (!isttest(curproxy->orgto_hdr_name))
|
||||
goto alloc_error;
|
||||
cur_arg += 2;
|
||||
} else {
|
||||
/* unknown suboption - catchall */
|
||||
ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except' and 'header'.\n",
|
||||
file, linenum, args[0], args[1]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
} /* end while loop */
|
||||
err_code |= proxy_http_parse_xot(args, 0, curproxy, curr_defproxy, file, linenum);
|
||||
if (err_code & ERR_FATAL)
|
||||
goto out;
|
||||
}
|
||||
else if (strcmp(args[1], "http-restrict-req-hdr-names") == 0) {
|
||||
if (alertif_too_many_args(2, file, linenum, args, &err_code))
|
||||
|
||||
@ -3982,11 +3982,11 @@ out_uri_auth_compat:
|
||||
curproxy->options &= ~PR_O_HTTP_XFF;
|
||||
}
|
||||
|
||||
if (curproxy->options & PR_O_ORGTO) {
|
||||
if (curproxy->options & PR_O_HTTP_XOT) {
|
||||
ha_warning("'option %s' ignored for %s '%s' as it requires HTTP mode.\n",
|
||||
"originalto", proxy_type_str(curproxy), curproxy->id);
|
||||
err_code |= ERR_WARN;
|
||||
curproxy->options &= ~PR_O_ORGTO;
|
||||
curproxy->options &= ~PR_O_HTTP_XOT;
|
||||
}
|
||||
|
||||
for (optnum = 0; cfg_opts[optnum].name; optnum++) {
|
||||
|
||||
@ -678,53 +678,12 @@ int http_process_request(struct stream *s, struct channel *req, int an_bit)
|
||||
}
|
||||
|
||||
/*
|
||||
* 10: add X-Original-To if either the frontend or the backend
|
||||
* add X-Original-To if either the frontend or the backend
|
||||
* asks for it.
|
||||
*/
|
||||
if ((sess->fe->options | s->be->options) & PR_O_ORGTO) {
|
||||
const struct sockaddr_storage *dst = sc_dst(s->scf);
|
||||
struct ist hdr = isttest(s->be->orgto_hdr_name) ? s->be->orgto_hdr_name : sess->fe->orgto_hdr_name;
|
||||
|
||||
if (dst && dst->ss_family == AF_INET) {
|
||||
/* Add an X-Original-To header unless the destination IP is
|
||||
* in the 'except' network range.
|
||||
*/
|
||||
if (ipcmp2net(dst, &sess->fe->except_xot_net) &&
|
||||
ipcmp2net(dst, &s->be->except_xot_net)) {
|
||||
unsigned char *pn = (unsigned char *)&((struct sockaddr_in *)dst)->sin_addr;
|
||||
|
||||
/* Note: we rely on the backend to get the header name to be used for
|
||||
* x-original-to, 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, "%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_fail_rewrite;
|
||||
}
|
||||
}
|
||||
else if (dst && dst->ss_family == AF_INET6) {
|
||||
/* Add an X-Original-To header unless the source IP is
|
||||
* in the 'except' network range.
|
||||
*/
|
||||
if (ipcmp2net(dst, &sess->fe->except_xot_net) &&
|
||||
ipcmp2net(dst, &s->be->except_xot_net)) {
|
||||
char pn[INET6_ADDRSTRLEN];
|
||||
|
||||
inet_ntop(AF_INET6,
|
||||
(const void *)&((struct sockaddr_in6 *)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_fail_rewrite;
|
||||
}
|
||||
}
|
||||
if ((sess->fe->options | s->be->options) & PR_O_HTTP_XOT) {
|
||||
if (unlikely(!http_handle_xot_header(s, req)))
|
||||
goto return_fail_rewrite;
|
||||
}
|
||||
|
||||
/* Filter the request headers if there are filters attached to the
|
||||
|
||||
145
src/http_ext.c
145
src/http_ext.c
@ -828,6 +828,67 @@ int http_handle_xff_header(struct stream *s, struct channel *req)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This function will try to inject x-original-to header if
|
||||
* configured on the frontend or the backend (or both)
|
||||
* Returns 1 for success and 0 for failure
|
||||
*/
|
||||
int http_handle_xot_header(struct stream *s, struct channel *req)
|
||||
{
|
||||
struct session *sess = s->sess;
|
||||
struct htx *htx = htxbuf(&req->buf);
|
||||
const struct sockaddr_storage *dst = sc_dst(s->scf);
|
||||
struct http_ext_xot *f_xot = ((sess->fe->options & PR_O_HTTP_XOT) ? &sess->fe->http.xot : NULL);
|
||||
struct http_ext_xot *b_xot = ((s->be->options & PR_O_HTTP_XOT) ? &s->be->http.xot : NULL);
|
||||
struct ist hdr;
|
||||
|
||||
/* xot is expected to be enabled on be, or fe, or both */
|
||||
BUG_ON(!f_xot && !b_xot);
|
||||
|
||||
hdr = ((b_xot) ? b_xot->hdr_name : f_xot->hdr_name);
|
||||
|
||||
if (dst && dst->ss_family == AF_INET) {
|
||||
/* Add an X-Original-To header unless the destination IP is
|
||||
* in the 'except' network range.
|
||||
*/
|
||||
if ((!f_xot || ipcmp2net(dst, &f_xot->except_net)) &&
|
||||
(!b_xot || ipcmp2net(dst, &b_xot->except_net))) {
|
||||
unsigned char *pn = (unsigned char *)&((struct sockaddr_in *)dst)->sin_addr;
|
||||
|
||||
/* Note: we rely on the backend to get the header name to be used for
|
||||
* x-original-to, 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, "%d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
|
||||
if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (dst && dst->ss_family == AF_INET6) {
|
||||
/* Add an X-Original-To header unless the source IP is
|
||||
* in the 'except' network range.
|
||||
*/
|
||||
if ((!f_xot || ipcmp2net(dst, &f_xot->except_net)) &&
|
||||
(!b_xot || ipcmp2net(dst, &b_xot->except_net))) {
|
||||
char pn[INET6_ADDRSTRLEN];
|
||||
|
||||
inet_ntop(AF_INET6,
|
||||
(const void *)&((struct sockaddr_in6 *)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))))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* =========== CONFIG ===========
|
||||
* below are helpers to parse http ext options from the config
|
||||
@ -1150,6 +1211,78 @@ int proxy_http_parse_xff(char **args, int cur_arg,
|
||||
return err_code;
|
||||
}
|
||||
|
||||
/* x-original-to */
|
||||
int proxy_http_parse_xot(char **args, int cur_arg,
|
||||
struct proxy *curproxy, const struct proxy *defpx,
|
||||
const char *file, int linenum)
|
||||
{
|
||||
int err_code = 0;
|
||||
|
||||
/* insert x-original-to field, but not for the IP address listed as an except.
|
||||
* set default options (ie: bitfield, header name, etc)
|
||||
*/
|
||||
|
||||
curproxy->options |= PR_O_HTTP_XOT;
|
||||
|
||||
istfree(&curproxy->http.xot.hdr_name);
|
||||
curproxy->http.xot.hdr_name = istdup(ist(DEF_XORIGINALTO_HDR));
|
||||
if (!isttest(curproxy->http.xot.hdr_name))
|
||||
return proxy_http_parse_oom(file, linenum);
|
||||
curproxy->http.xot.except_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->http.xot.except_net.addr.v4.ip, &curproxy->http.xot.except_net.addr.v4.mask)) {
|
||||
curproxy->http.xot.except_net.family = AF_INET;
|
||||
curproxy->http.xot.except_net.addr.v4.ip.s_addr &= curproxy->http.xot.except_net.addr.v4.mask.s_addr;
|
||||
}
|
||||
else if (*(args[cur_arg+1]) &&
|
||||
str62net(args[cur_arg+1], &curproxy->http.xot.except_net.addr.v6.ip, &mask)) {
|
||||
curproxy->http.xot.except_net.family = AF_INET6;
|
||||
len2mask6(mask, &curproxy->http.xot.except_net.addr.v6.mask);
|
||||
for (i = 0; i < 16; i++)
|
||||
curproxy->http.xot.except_net.addr.v6.ip.s6_addr[i] &= curproxy->http.xot.except_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;
|
||||
}
|
||||
cur_arg += 2;
|
||||
} else if (strcmp(args[cur_arg], "header") == 0) {
|
||||
/* suboption header - needs additional argument for it */
|
||||
if (*(args[cur_arg+1]) == 0) {
|
||||
ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
|
||||
file, linenum, args[0], args[1], args[cur_arg]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
istfree(&curproxy->http.xot.hdr_name);
|
||||
curproxy->http.xot.hdr_name = istdup(ist(args[cur_arg+1]));
|
||||
if (!isttest(curproxy->http.xot.hdr_name))
|
||||
return proxy_http_parse_oom(file, linenum);
|
||||
cur_arg += 2;
|
||||
} else {
|
||||
/* unknown suboption - catchall */
|
||||
ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except' and 'header'.\n",
|
||||
file, linenum, args[0], args[1]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
} /* end while loop */
|
||||
|
||||
out:
|
||||
return err_code;
|
||||
}
|
||||
|
||||
/*
|
||||
* =========== MGMT ===========
|
||||
* below are helpers to manage http ext options
|
||||
@ -1181,6 +1314,11 @@ void http_ext_xff_clean(struct http_ext_xff *clean)
|
||||
istfree(&clean->hdr_name);
|
||||
}
|
||||
|
||||
void http_ext_xot_clean(struct http_ext_xot *clean)
|
||||
{
|
||||
istfree(&clean->hdr_name);
|
||||
}
|
||||
|
||||
void http_ext_7239_copy(struct http_ext_7239 *dest, const struct http_ext_7239 *orig)
|
||||
{
|
||||
if (orig->c_file)
|
||||
@ -1217,3 +1355,10 @@ void http_ext_xff_copy(struct http_ext_xff *dest, const struct http_ext_xff *ori
|
||||
dest->mode = orig->mode;
|
||||
dest->except_net = orig->except_net;
|
||||
}
|
||||
|
||||
void http_ext_xot_copy(struct http_ext_xot *dest, const struct http_ext_xot *orig)
|
||||
{
|
||||
if (isttest(orig->hdr_name))
|
||||
dest->hdr_name = istdup(orig->hdr_name);
|
||||
dest->except_net = orig->except_net;
|
||||
}
|
||||
|
||||
10
src/proxy.c
10
src/proxy.c
@ -352,9 +352,9 @@ void free_proxy(struct proxy *p)
|
||||
pxdf->fct(p);
|
||||
|
||||
free(p->desc);
|
||||
istfree(&p->orgto_hdr_name);
|
||||
http_ext_7239_clean(&p->http.fwd);
|
||||
http_ext_xff_clean(&p->http.xff);
|
||||
http_ext_xot_clean(&p->http.xot);
|
||||
|
||||
task_destroy(p->task);
|
||||
|
||||
@ -1465,11 +1465,11 @@ void proxy_free_defaults(struct proxy *defproxy)
|
||||
istfree(&defproxy->monitor_uri);
|
||||
ha_free(&defproxy->defbe.name);
|
||||
ha_free(&defproxy->conn_src.iface_name);
|
||||
istfree(&defproxy->orgto_hdr_name);
|
||||
istfree(&defproxy->server_id_hdr_name);
|
||||
|
||||
http_ext_7239_clean(&defproxy->http.fwd);
|
||||
http_ext_xff_clean(&defproxy->http.xff);
|
||||
http_ext_xot_clean(&defproxy->http.xot);
|
||||
|
||||
list_for_each_entry_safe(acl, aclb, &defproxy->acl, list) {
|
||||
LIST_DELETE(&acl->list);
|
||||
@ -1646,16 +1646,14 @@ static int proxy_defproxy_cpy(struct proxy *curproxy, const struct proxy *defpro
|
||||
curproxy->options2 = defproxy->options2;
|
||||
curproxy->no_options = defproxy->no_options;
|
||||
curproxy->no_options2 = defproxy->no_options2;
|
||||
curproxy->except_xot_net = defproxy->except_xot_net;
|
||||
curproxy->retry_type = defproxy->retry_type;
|
||||
curproxy->tcp_req.inspect_delay = defproxy->tcp_req.inspect_delay;
|
||||
curproxy->tcp_rep.inspect_delay = defproxy->tcp_rep.inspect_delay;
|
||||
|
||||
if (defproxy->options & PR_O_HTTP_XFF)
|
||||
http_ext_xff_copy(&curproxy->http.xff, &defproxy->http.xff);
|
||||
|
||||
if (isttest(defproxy->orgto_hdr_name))
|
||||
curproxy->orgto_hdr_name = istdup(defproxy->orgto_hdr_name);
|
||||
if (defproxy->options & PR_O_HTTP_XOT)
|
||||
http_ext_xot_copy(&curproxy->http.xot, &defproxy->http.xot);
|
||||
|
||||
if (isttest(defproxy->server_id_hdr_name))
|
||||
curproxy->server_id_hdr_name = istdup(defproxy->server_id_hdr_name);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user