diff --git a/doc/configuration.txt b/doc/configuration.txt index 066f93568..3e777fad2 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -2523,6 +2523,22 @@ http-request { allow | deny | auth [realm ] } See also : "stats http-request", section 3.4 about userlists and section 7 about ACL usage. +http-send-name-header [
] + Add the server name to a request. Use the header string given by
+ + May be used in sections: defaults | frontend | listen | backend + yes | no | yes | yes + + Arguments : + +
The header string to use to send the server name + + The "http-send-name-header" statement causes the name of the target + server to be added to the headers of an HTTP request. The name + is added with the header string proved. + + See also : "server" + id Set a persistent ID to a proxy. May be used in sections : defaults | frontend | listen | backend @@ -4760,7 +4776,8 @@ server
[:[port]] [param*] no | no | yes | yes Arguments : is the internal name assigned to this server. This name will - appear in logs and alerts. + appear in logs and alerts. If "http-send-server-name" is + set, it will be added to the request header sent to the server.
is the IPv4 or IPv6 address of the server. Alternatively, a resolvable hostname is supported, but this name will be resolved @@ -4787,7 +4804,8 @@ server
[:[port]] [param*] server first 10.1.1.1:1080 cookie first check inter 1000 server second 10.1.1.2:1080 cookie second check inter 1000 - See also: "default-server" and section 5 about server options + See also: "default-server", "http-send-name-header" and section 5 about + server options source [:] [usesrc { [:] | client | clientip } ] diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h index f5dcbce30..0eed363ea 100644 --- a/include/proto/proto_http.h +++ b/include/proto/proto_http.h @@ -71,6 +71,7 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s int http_process_request(struct session *t, struct buffer *req, int an_bit); int http_process_tarpit(struct session *s, struct buffer *req, int an_bit); int http_process_request_body(struct session *s, struct buffer *req, int an_bit); +int http_send_name_header(struct http_txn *txn, struct http_msg *msg, struct buffer *buf, struct proxy* be, const char* svr_name); int http_wait_for_response(struct session *s, struct buffer *rep, int an_bit); int http_process_res_common(struct session *t, struct buffer *rep, int an_bit, struct proxy *px); int http_request_forward_body(struct session *s, struct buffer *req, int an_bit); diff --git a/include/types/proxy.h b/include/types/proxy.h index 593260e2f..d0bc51caf 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -272,6 +272,8 @@ struct proxy { int fwdfor_hdr_len; /* length of "x-forwarded-for" header */ char *orgto_hdr_name; /* header to use - default: "x-original-to" */ int orgto_hdr_len; /* length of "x-original-to" header */ + char *server_id_hdr_name; /* the header to use to send the server id (name) */ + int server_id_hdr_len; /* the length of the id (name) header... name */ unsigned down_trans; /* up-down transitions */ unsigned down_time; /* total time the proxy was down */ diff --git a/src/cfgparse.c b/src/cfgparse.c index bf2eb36c4..b881cd94d 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1431,6 +1431,11 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) curproxy->orgto_hdr_name = strdup(defproxy.orgto_hdr_name); } + if (defproxy.server_id_hdr_len) { + curproxy->server_id_hdr_len = defproxy.server_id_hdr_len; + curproxy->server_id_hdr_name = strdup(defproxy.server_id_hdr_name); + } + if (curproxy->cap & PR_CAP_FE) { curproxy->maxconn = defproxy.maxconn; curproxy->backlog = defproxy.backlog; @@ -1560,6 +1565,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) defproxy.fwdfor_hdr_len = 0; free(defproxy.orgto_hdr_name); defproxy.orgto_hdr_len = 0; + free(defproxy.server_id_hdr_name); + defproxy.server_id_hdr_len = 0; free(defproxy.expect_str); if (defproxy.expect_regex) regfree(defproxy.expect_regex); @@ -2460,6 +2467,23 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) err_code |= warnif_cond_requires_resp(rule->cond, file, linenum); LIST_ADDQ(&curproxy->http_req_rules, &rule->list); } + else if (!strcmp(args[0], "http-send-name-header")) { /* send server name in request header */ + /* set the header name and length into the proxy structure */ + if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) + err_code |= ERR_WARN; + + if (!*args[1]) { + Alert("parsing [%s:%d] : '%s' requires a header string.\n", + file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + /* set the desired header name */ + free(curproxy->server_id_hdr_name); + curproxy->server_id_hdr_name = strdup(args[1]); + curproxy->server_id_hdr_len = strlen(curproxy->server_id_hdr_name); + } else if (!strcmp(args[0], "block")) { /* early blocking based on ACLs */ if (curproxy == &defproxy) { Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); diff --git a/src/proto_http.c b/src/proto_http.c index 1906916b3..c6cfb358c 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -3932,6 +3932,34 @@ int http_process_request_body(struct session *s, struct buffer *req, int an_bit) return 0; } +int http_send_name_header(struct http_txn *txn, struct http_msg *msg, struct buffer *buf, struct proxy* be, const char* srv_name) { + + struct hdr_ctx ctx; + + ctx.idx = 0; + + char *hdr_name = be->server_id_hdr_name; + int hdr_name_len = be->server_id_hdr_len; + + char *hdr_val; + + while (http_find_header2(hdr_name, hdr_name_len, msg->sol, &txn->hdr_idx, &ctx)) { + /* remove any existing values from the header */ + http_remove_header2(msg, buf, &txn->hdr_idx, &ctx); + } + + /* Add the new header requested with the server value */ + hdr_val = trash; + memcpy(hdr_val, hdr_name, hdr_name_len); + hdr_val += hdr_name_len; + *hdr_val++ = ':'; + *hdr_val++ = ' '; + hdr_val += strlcpy2(hdr_val, srv_name, trash + sizeof(trash) - hdr_val); + http_header_add_tail2(buf, msg, &txn->hdr_idx, trash, hdr_val - trash); + + return 0; +} + /* Terminate current transaction and prepare a new one. This is very tricky * right now but it works. */ diff --git a/src/session.c b/src/session.c index c46599092..d87813e37 100644 --- a/src/session.c +++ b/src/session.c @@ -1885,6 +1885,19 @@ struct task *process_session(struct task *t) if (s->si[1].state == SI_ST_ASS && srv && srv->rdr_len && (s->flags & SN_REDIRECTABLE)) perform_http_redirect(s, &s->si[1]); } while (s->si[1].state == SI_ST_ASS); + + /* Now we can add the server name to a header (if requested) */ + /* check for HTTP mode and proxy server_name_hdr_name != NULL */ + if ((s->flags && SN_BE_ASSIGNED) && + (s->be->mode == PR_MODE_HTTP) && + (s->be->server_id_hdr_name != NULL)) { + + http_send_name_header(&s->txn, + &s->txn.req, + s->req, + s->be, + target_srv(&s->target)->id); + } } /* Benchmarks have shown that it's optimal to do a full resync now */ diff --git a/tests/test-http-send-name-hdr.cfg b/tests/test-http-send-name-hdr.cfg new file mode 100644 index 000000000..65fc0d0e7 --- /dev/null +++ b/tests/test-http-send-name-hdr.cfg @@ -0,0 +1,33 @@ +# Test Rewriting Host header +global + maxconn 100 + +defaults + mode http + timeout client 10000 + timeout server 10000 + timeout connect 10000 + balance roundrobin + +listen send-name-silo-id + bind :8001 + + # Set the test conditions: Add a new header + http-send-name-header X-Silo-Id + server srv-silo1 127.0.0.1:8080 + + # Add headers containing the correct values for test verification + reqadd X-test-server-name-header:\ X-Silo-Id + reqadd X-test-server-name-value:\ srv-silo1 + +listen send-name-host + bind :8002 + + # Set the test conditions: Replace an existing header + http-send-name-header host + server srv-host 127.0.0.1:8080 + + # Add headers containing the correct values for test verification + reqadd X-test-server-name-header:\ Host + reqadd X-test-server-name-value:\ srv-host +