mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-12 08:49:29 +00:00
MEDIUM: proxy_protocol: Support sending unique IDs using PPv2
This patch adds the `unique-id` option to `proxy-v2-options`. If this option is set a unique ID will be generated based on the `unique-id-format` while sending the proxy protocol v2 header and stored as the unique id for the first stream of the connection. This feature is meant to be used in `tcp` mode. It works on HTTP mode, but might result in inconsistent unique IDs for the first request on a keep-alive connection, because the unique ID for the first stream is generated earlier than the others. Now that we can send unique IDs in `tcp` mode the `%ID` log variable is made available in TCP mode.
This commit is contained in:
parent
d1b15b6e9b
commit
cf6e0c8a83
@ -12657,13 +12657,23 @@ send-proxy-v2
|
||||
this section and send-proxy" option of the "bind" keyword.
|
||||
|
||||
proxy-v2-options <option>[,<option>]*
|
||||
The "proxy-v2-options" parameter add option to send in PROXY protocol version
|
||||
2 when "send-proxy-v2" is used. Options available are "ssl" (see also
|
||||
send-proxy-v2-ssl), "cert-cn" (see also "send-proxy-v2-ssl-cn"), "ssl-cipher":
|
||||
name of the used cipher, "cert-sig": signature algorithm of the used
|
||||
certificate, "cert-key": key algorithm of the used certificate), "authority":
|
||||
host name value passed by the client (only sni from a tls connection is
|
||||
supported), "crc32c": checksum of the proxy protocol v2 header.
|
||||
The "proxy-v2-options" parameter add options to send in PROXY protocol
|
||||
version 2 when "send-proxy-v2" is used. Options available are:
|
||||
|
||||
- ssl : See also "send-proxy-v2-ssl".
|
||||
- cert-cn : See also "send-proxy-v2-ssl-cn".
|
||||
- ssl-cipher: Name of the used cipher.
|
||||
- cert-sig : Signature algorithm of the used certificate.
|
||||
- cert-key : Key algorithm of the used certificate
|
||||
- authority : Host name value passed by the client (only SNI from a TLS
|
||||
connection is supported).
|
||||
- crc32c : Checksum of the PROXYv2 header.
|
||||
- unique-id : Send a unique ID generated using the frontend's
|
||||
"unique-id-format" within the PROXYv2 header.
|
||||
This unique-id is primarily meant for "mode tcp". It can
|
||||
lead to unexpected results in "mode http", because the
|
||||
generated unique ID is also used for the first HTTP request
|
||||
within a Keep-Alive connection.
|
||||
|
||||
send-proxy-v2-ssl
|
||||
The "send-proxy-v2-ssl" parameter enforces use of the PROXY protocol version
|
||||
|
@ -47,9 +47,9 @@ int conn_fd_check(struct connection *conn);
|
||||
|
||||
/* receive a PROXY protocol header over a connection */
|
||||
int conn_recv_proxy(struct connection *conn, int flag);
|
||||
int make_proxy_line(char *buf, int buf_len, struct server *srv, struct connection *remote);
|
||||
int make_proxy_line(char *buf, int buf_len, struct server *srv, struct connection *remote, struct stream *strm);
|
||||
int make_proxy_line_v1(char *buf, int buf_len, struct sockaddr_storage *src, struct sockaddr_storage *dst);
|
||||
int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct connection *remote);
|
||||
int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct connection *remote, struct stream *strm);
|
||||
|
||||
int conn_subscribe(struct connection *conn, void *xprt_ctx, int event_type, struct wait_event *es);
|
||||
int conn_unsubscribe(struct connection *conn, void *xprt_ctx, int event_type, struct wait_event *es);
|
||||
|
@ -154,6 +154,7 @@ enum srv_initaddr {
|
||||
#define SRV_PP_V2_SSL_CIPHER 0x0040 /* proxy protocol version 2 with cipher used */
|
||||
#define SRV_PP_V2_AUTHORITY 0x0080 /* proxy protocol version 2 with authority */
|
||||
#define SRV_PP_V2_CRC32C 0x0100 /* proxy protocol version 2 with crc32c */
|
||||
#define SRV_PP_V2_UNIQUE_ID 0x0200 /* proxy protocol version 2 with unique ID */
|
||||
|
||||
/* function which act on servers need to return various errors */
|
||||
#define SRV_STATUS_OK 0 /* everything is OK. */
|
||||
|
42
reg-tests/connection/proxy_protocol_send_unique_id.vtc
Normal file
42
reg-tests/connection/proxy_protocol_send_unique_id.vtc
Normal file
@ -0,0 +1,42 @@
|
||||
varnishtest "Check that the unique ID TLV is properly sent"
|
||||
|
||||
#REQUIRE_VERSION=2.2
|
||||
|
||||
feature ignore_unknown_macro
|
||||
|
||||
haproxy h1 -conf {
|
||||
defaults
|
||||
mode http
|
||||
log global
|
||||
unique-id-format %{+X}o\ TEST-%[req.hdr(in)]
|
||||
|
||||
listen sender
|
||||
bind "fd@${feS}"
|
||||
|
||||
unique-id-header unique_id
|
||||
|
||||
server example ${h1_feR_addr}:${h1_feR_port} send-proxy-v2 proxy-v2-options unique-id
|
||||
|
||||
listen receiver
|
||||
bind "fd@${feR}" accept-proxy
|
||||
|
||||
http-request set-var(txn.http_unique_id) req.hdr(unique_id)
|
||||
http-request set-var(txn.proxy_unique_id) fc_pp_unique_id
|
||||
http-after-response set-header http_unique_id %[var(txn.http_unique_id)]
|
||||
http-after-response set-header proxy_unique_id %[var(txn.proxy_unique_id)]
|
||||
http-request return status 200
|
||||
} -start
|
||||
|
||||
# Validate that a correct header passes
|
||||
client c1 -connect ${h1_feS_sock} {
|
||||
txreq -url "/" \
|
||||
-hdr "in: foo"
|
||||
rxresp
|
||||
expect resp.http.http_unique_id == "TEST-foo"
|
||||
expect resp.http.proxy_unique_id == "TEST-foo"
|
||||
txreq -url "/" \
|
||||
-hdr "in: bar"
|
||||
rxresp
|
||||
expect resp.http.http_unique_id == "TEST-bar"
|
||||
expect resp.http.proxy_unique_id == "TEST-foo"
|
||||
} -run
|
@ -1241,12 +1241,12 @@ int conn_recv_socks4_proxy_response(struct connection *conn)
|
||||
}
|
||||
|
||||
/* Note: <remote> is explicitly allowed to be NULL */
|
||||
int make_proxy_line(char *buf, int buf_len, struct server *srv, struct connection *remote)
|
||||
int make_proxy_line(char *buf, int buf_len, struct server *srv, struct connection *remote, struct stream *strm)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (srv && (srv->pp_opts & SRV_PP_V2)) {
|
||||
ret = make_proxy_line_v2(buf, buf_len, srv, remote);
|
||||
ret = make_proxy_line_v2(buf, buf_len, srv, remote, strm);
|
||||
}
|
||||
else {
|
||||
if (remote && conn_get_src(remote) && conn_get_dst(remote))
|
||||
@ -1353,7 +1353,7 @@ static int make_tlv(char *dest, int dest_len, char type, uint16_t length, const
|
||||
}
|
||||
|
||||
/* Note: <remote> is explicitly allowed to be NULL */
|
||||
int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct connection *remote)
|
||||
int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct connection *remote, struct stream *strm)
|
||||
{
|
||||
const char pp2_signature[] = PP2_SIGNATURE;
|
||||
void *tlv_crc32c_p = NULL;
|
||||
@ -1468,6 +1468,20 @@ int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct connec
|
||||
}
|
||||
}
|
||||
|
||||
if (srv->pp_opts & SRV_PP_V2_UNIQUE_ID) {
|
||||
struct session* sess = strm_sess(strm);
|
||||
struct ist unique_id = stream_generate_unique_id(strm, &sess->fe->format_unique_id);
|
||||
|
||||
value = unique_id.ptr;
|
||||
value_len = unique_id.len;
|
||||
|
||||
if (value_len >= 0) {
|
||||
if ((buf_len - ret) < sizeof(struct tlv))
|
||||
return 0;
|
||||
ret += make_tlv(&buf[ret], (buf_len - ret), PP2_TYPE_UNIQUE_ID, value_len, value);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
if (srv->pp_opts & SRV_PP_V2_SSL) {
|
||||
struct tlv_ssl *tlv;
|
||||
|
@ -137,7 +137,7 @@ static const struct logformat_type logformat_keywords[] = {
|
||||
{ "CC", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL }, /* client cookie */
|
||||
{ "CS", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL }, /* server cookie */
|
||||
{ "H", LOG_FMT_HOSTNAME, PR_MODE_TCP, LW_INIT, NULL }, /* Hostname */
|
||||
{ "ID", LOG_FMT_UNIQUEID, PR_MODE_HTTP, LW_BYTES, NULL }, /* Unique ID */
|
||||
{ "ID", LOG_FMT_UNIQUEID, PR_MODE_TCP, LW_BYTES, NULL }, /* Unique ID */
|
||||
{ "ST", LOG_FMT_STATUS, PR_MODE_TCP, LW_RESP, NULL }, /* status code */
|
||||
{ "T", LOG_FMT_DATEGMT, PR_MODE_TCP, LW_INIT, NULL }, /* date GMT */
|
||||
{ "Ta", LOG_FMT_Ta, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time active (tr to end) */
|
||||
|
@ -656,6 +656,8 @@ static int srv_parse_proxy_v2_options(char **args, int *cur_arg,
|
||||
newsrv->pp_opts |= SRV_PP_V2_AUTHORITY;
|
||||
} else if (!strcmp(p, "crc32c")) {
|
||||
newsrv->pp_opts |= SRV_PP_V2_CRC32C;
|
||||
} else if (!strcmp(p, "unique-id")) {
|
||||
newsrv->pp_opts |= SRV_PP_V2_UNIQUE_ID;
|
||||
} else
|
||||
goto fail;
|
||||
}
|
||||
|
@ -354,9 +354,12 @@ int conn_si_send_proxy(struct connection *conn, unsigned int flag)
|
||||
if (cs && cs->data_cb == &si_conn_cb) {
|
||||
struct stream_interface *si = cs->data;
|
||||
struct conn_stream *remote_cs = objt_cs(si_opposite(si)->end);
|
||||
struct stream *strm = si_strm(si);
|
||||
|
||||
ret = make_proxy_line(trash.area, trash.size,
|
||||
objt_server(conn->target),
|
||||
remote_cs ? remote_cs->conn : NULL);
|
||||
remote_cs ? remote_cs->conn : NULL,
|
||||
strm);
|
||||
/* We may not have a conn_stream yet, if we don't
|
||||
* know which mux to use, because it will be decided
|
||||
* during the SSL handshake. In this case, there should
|
||||
@ -371,7 +374,8 @@ int conn_si_send_proxy(struct connection *conn, unsigned int flag)
|
||||
|
||||
ret = make_proxy_line(trash.area, trash.size,
|
||||
objt_server(conn->target),
|
||||
objt_conn(sess->origin));
|
||||
objt_conn(sess->origin),
|
||||
NULL);
|
||||
}
|
||||
else {
|
||||
/* The target server expects a LOCAL line to be sent first. Retrieving
|
||||
@ -381,7 +385,8 @@ int conn_si_send_proxy(struct connection *conn, unsigned int flag)
|
||||
goto out_wait;
|
||||
|
||||
ret = make_proxy_line(trash.area, trash.size,
|
||||
objt_server(conn->target), conn);
|
||||
objt_server(conn->target), conn,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
|
Loading…
Reference in New Issue
Block a user