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.
diff --git a/src/connection.c b/src/connection.c
index 728c0ec..4e48aa94 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -1241,12 +1241,12 @@
}
/* 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 @@
}
/* 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 @@
}
}
+ 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;
diff --git a/src/log.c b/src/log.c
index 8f502ac..2cac074 100644
--- a/src/log.c
+++ b/src/log.c
@@ -137,7 +137,7 @@
{ "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) */
diff --git a/src/server.c b/src/server.c
index 9655702..908439d 100644
--- a/src/server.c
+++ b/src/server.c
@@ -656,6 +656,8 @@
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;
}
diff --git a/src/stream_interface.c b/src/stream_interface.c
index 47cbd96..7bb864d 100644
--- a/src/stream_interface.c
+++ b/src/stream_interface.c
@@ -354,9 +354,12 @@
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 @@
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 @@
goto out_wait;
ret = make_proxy_line(trash.area, trash.size,
- objt_server(conn->target), conn);
+ objt_server(conn->target), conn,
+ NULL);
}
if (!ret)