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:
--- /dev/null
+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
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;
}
}
+ 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;