From 84608ed754c1a92e85e03036e8b0cd0949721ffb Mon Sep 17 00:00:00 2001 From: Alexander Stephan <alexander.step...@sap.com<mailto:alexander.step...@sap.com>> Date: Fri, 15 Sep 2023 12:42:36 +0200 Subject: [PATCH 2/4] MEDIUM: connection: Send out generically allocated proxy-v2-options
This commit removes the previous limitations on the existing, fixed PPv2 TLV types that can be sent out. This is done by leveraging the previously implemented parsing. We iterate over the server TLV list and either forward or send a new TLV, depending on whether a TLV exists in the remote connection. --- doc/configuration.txt | 20 ++++++++ .../proxy_protocol_send_generic.vtc | 35 +++++++++++++ src/connection.c | 51 +++++++++++++++++-- 3 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 reg-tests/connection/proxy_protocol_send_generic.vtc diff --git a/doc/configuration.txt b/doc/configuration.txt index 14f6b906d..aeff9e4db 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -16671,6 +16671,26 @@ proxy-v2-options <option>[,<option>]* generated unique ID is also used for the first HTTP request within a Keep-Alive connection. + Besides, you can specify the type of TLV numerically instead. + + Example 1: + server example 127.0.0.1:2319 send-proxy-v2 proxy-v2-options crc32c,0xEE + + The following logic applies: By default, the remote frontend connection is + searched for the value 0xEE. If found, it is simply forwarded. Otherwise, + a TLV with the ID "0xEE" and empty payload is sent out. In addition, crc32c + is also set here. + + You can also specify a key-value pair <id>=<fmt> syntax. <id> represents the + 8 bit TLV type field in the range of 0 to 255. It can be expressed in decimal + or hexadecimal format (prefixed by "0x"). + + Example 2: + server example_server 127.0.0.1:2319 send-proxy-v2 proxy-v2-options 0xEE=%[str("foo")] + + This will always send out the value "foo". Another common use case would be to + reference a variable. + send-proxy-v2-ssl The "send-proxy-v2-ssl" parameter enforces use of the PROXY protocol version 2 over any connection established to this server. The PROXY protocol informs diff --git a/reg-tests/connection/proxy_protocol_send_generic.vtc b/reg-tests/connection/proxy_protocol_send_generic.vtc new file mode 100644 index 000000000..e0bd15a1b --- /dev/null +++ b/reg-tests/connection/proxy_protocol_send_generic.vtc @@ -0,0 +1,35 @@ +varnishtest "Check that generic TLV IDs are sent properly" + +#REQUIRE_VERSION=2.2 + +feature ignore_unknown_macro + +haproxy h1 -conf { + defaults + mode http + log global + + listen sender + bind "fd@${feS}" + server example ${h1_feR_addr}:${h1_feR_port} send-proxy-v2 proxy-v2-options 0xE1=%[str("foo")],0xE2 + + listen receiver + bind "fd@${feR}" accept-proxy + + # Check that the TLV value is set in the backend. + http-request set-var(txn.custom_tlv_a) fc_pp_tlv(0xE1) + http-after-response set-header proxy_custom_tlv_a %[var(txn.custom_tlv_a)] + + # Check that TLVs without an value are sent out. + http-request set-var(txn.custom_tlv_b) fc_pp_tlv(0xE2) + http-after-response set-header proxy_custom_tlv_b %[var(txn.custom_tlv_b)] + + http-request return status 200 +} -start + +client c1 -connect ${h1_feS_sock} { + txreq -url "/" + rxresp + expect resp.http.proxy_custom_tlv_a == "foo" + expect resp.http.proxy_custom_tlv_b == "" +} -run diff --git a/src/connection.c b/src/connection.c index 5f7226aae..51584b1ed 100644 --- a/src/connection.c +++ b/src/connection.c @@ -22,6 +22,7 @@ #include <haproxy/frontend.h> #include <haproxy/hash.h> #include <haproxy/list.h> +#include <haproxy/log.h> #include <haproxy/log-t.h> #include <haproxy/namespace.h> #include <haproxy/net_helper.h> @@ -548,7 +549,7 @@ struct connection *conn_new(void *target) /* Releases a connection previously allocated by conn_new() */ void conn_free(struct connection *conn) { - struct conn_tlv_list *tlv, *tlv_back = NULL; + struct conn_tlv_list *tlv = NULL, *tlv_back = NULL; if (conn_is_back(conn)) conn_backend_deinit(conn); @@ -1920,10 +1921,12 @@ static int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct int ret = 0; struct proxy_hdr_v2 *hdr = (struct proxy_hdr_v2 *)buf; struct sockaddr_storage null_addr = { .ss_family = 0 }; + struct srv_pp_tlv_list *srv_tlv = NULL; const struct sockaddr_storage *src = &null_addr; const struct sockaddr_storage *dst = &null_addr; - const char *value; - int value_len; + const char *value = ""; + int value_len = 0; + int found = 0; if (buf_len < PP2_HEADER_LEN) return 0; @@ -1993,6 +1996,48 @@ static int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct } } + if (strm) { + struct buffer *replace = NULL; + + list_for_each_entry(srv_tlv, &srv->pp_tlvs, list) { + replace = NULL; + + if (!LIST_ISEMPTY(&srv_tlv->fmt)) { + replace = alloc_trash_chunk(); + if (unlikely(!replace)) + return 0; + replace->data = build_logline(strm, replace->area, replace->size, &srv_tlv->fmt); + + if (unlikely((buf_len - ret) < sizeof(struct tlv))) { + free_trash_chunk(replace); + return 0; + } + ret += make_tlv(&buf[ret], (buf_len - ret), srv_tlv->type, replace->data, replace->area); + free_trash_chunk(replace); + } + else { + found = 0; + /* Fall back to use TLV value from remote connection, if available */ + if (remote) { + struct conn_tlv_list *remote_tlv = NULL; + + /* Search in remote connection TLV list */ + list_for_each_entry(remote_tlv, &remote->tlv_list, list) { + if (remote_tlv->type != srv_tlv->type) + continue; + ret += make_tlv(&buf[ret], (buf_len - ret), srv_tlv->type, remote_tlv->len, remote_tlv->value); + found = 1; + break; + } + } + if (!found) + /* Create empty TLV as no value was specified */ + ret += make_tlv(&buf[ret], (buf_len - ret), srv_tlv->type, 0, NULL); + } + } + } + + /* Handle predefined TLVs as usual */ if (srv->pp_opts & SRV_PP_V2_CRC32C) { uint32_t zero_crc32c = 0; -- 2.35.3