MINOR: connection: Send out generic, user-defined server TLVs

To follow-up the implementation of the new set-proxy-v2-tlv-fmt
keyword in the server, the connection is updated to use the previously
allocated TLVs. If no value was specified, we send out an empty TLV.
As the feature is fully working with this commit, documentation and a
test for the server and default-server are added as well.
This commit is contained in:
Alexander Stephan 2023-10-28 20:57:07 +02:00 committed by Willy Tarreau
parent 6f4bfed3a2
commit ce7501de79
3 changed files with 124 additions and 2 deletions

View File

@ -16742,6 +16742,22 @@ send-proxy-v2
of this version of the protocol. See also the "no-send-proxy-v2" option of
this section and send-proxy" option of the "bind" keyword.
set-proxy-v2-tlv-fmt(<id>) <fmt>
The "set-proxy-v2-tlv-fmt" parameter is used to send arbitrary PROXY protocol
version 2 TLVs. For the type (<id>) range of the defined TLV type please refer
to section 2.2.8. of the proxy protocol specification. However, the value can
be chosen freely as long as it does not exceed the maximum length of 65,535
bytes. It can also be used for forwarding TLVs by using the fetch "fc_pp_tlv"
to retrieve a received TLV from the frontend. It may be used as a server or
a default-server option. It must be used in combination with send-proxy-v2
such that PPv2 TLVs are actually sent out.
Example:
server srv1 192.168.1.1:80 send-proxy-v2 set-proxy-v2-tlv-fmt(0x20) %[fc_pp_tlv(0x20)]
In this case, we fetch the TLV with the type 0x20 as a string and set as the value
of a newly created TLV that also has the type 0x20.
proxy-v2-options <option>[,<option>]*
The "proxy-v2-options" parameter add options to send in PROXY protocol
version 2 when "send-proxy-v2" is used. Options available are:

View File

@ -0,0 +1,74 @@
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
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
listen sender
bind "fd@${feS}"
server example ${h1_feR_addr}:${h1_feR_port} send-proxy-v2 set-proxy-v2-tlv-fmt(0xE1) %[str("foo")] set-proxy-v2-tlv-fmt(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)]
# Note that we do not check for an invalid TLV ID as that would result in an
# parser error anway.
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
# Ensure that we achieve the same via a default-server.
haproxy h2 -conf {
defaults
mode http
log global
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
listen sender
bind "fd@${feS}"
default-server send-proxy-v2 set-proxy-v2-tlv-fmt(0xE1) %[str("bar")]
server example ${h1_feR_addr}:${h1_feR_port}
listen receiver
bind "fd@${feR}" accept-proxy
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)]
http-request return status 200
} -start
client c2 -connect ${h2_feS_sock} {
txreq -url "/"
rxresp
expect resp.http.proxy_custom_tlv_a == "bar"
} -run

View File

@ -1927,10 +1927,11 @@ 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;
if (buf_len < PP2_HEADER_LEN)
return 0;
@ -2000,6 +2001,37 @@ 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;
/* Users will always need to provide a value, in case of forwarding, they should use fc_pp_tlv.
* for generic types. Otherwise, we will send an empty TLV.
*/
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 {
/* 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;