MEDIUM: sample: Add fetch for arbitrary TLVs
Based on the new, generic allocation infrastructure, a new sample fetch fc_pp_tlv is introduced. It is an abstraction for existing PPv2 TLV sample fetches. It takes any valid TLV ID as argument and returns the value as a string, similar to fc_pp_authority and fc_pp_unique_id.
This commit is contained in:
parent
fecc573da1
commit
f773ef721c
|
@ -20174,12 +20174,28 @@ fc_lost : integer
|
|||
Linux kernels before 2.4, the sample fetch fails.
|
||||
|
||||
fc_pp_authority : string
|
||||
Returns the authority TLV sent by the client in the PROXY protocol header,
|
||||
if any.
|
||||
Returns the first authority TLV sent by the client in the PROXY protocol
|
||||
header, if any.
|
||||
|
||||
fc_pp_unique_id : string
|
||||
Returns the unique ID TLV sent by the client in the PROXY protocol header,
|
||||
if any.
|
||||
Returns the first unique ID TLV sent by the client in the PROXY protocol
|
||||
header, if any.
|
||||
|
||||
fc_pp_tlv(<id>) : string
|
||||
Returns the TLV value for the given TLV ID which must be a numeric
|
||||
value between 0 and 255.
|
||||
|
||||
The received value must be smaller or equal to 1024 bytes. This is done to
|
||||
prevent potential DoS attacks. Values smaller or equal to 256 bytes will be
|
||||
able to be memory pooled. Therefore, try to restrict the length of sent
|
||||
values to 256 bytes for optimal performance.
|
||||
|
||||
Note that unlike fc_pp_authority and fc_pp_unique_id, fc_pp_tlv is able to
|
||||
iterate over all occurances of a requested TLV in case there are duplicate
|
||||
TLV IDs. The order of iteration matches the position in the PROXY protocol
|
||||
header. However, relying on duplicates should mostly be avoided as TLVs are
|
||||
typically assumed to be unique. Generally, finding duplicated TLV IDs
|
||||
indicates an error on the sender side of the PROXY protocol header.
|
||||
|
||||
fc_rcvd_proxy : boolean
|
||||
Returns true if the client initiated the connection with a PROXY protocol
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
varnishtest "Tests for fetching PROXY protocol v2 TLVs"
|
||||
feature ignore_unknown_macro
|
||||
|
||||
haproxy h1 -conf {
|
||||
defaults
|
||||
mode http
|
||||
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
|
||||
frontend echo
|
||||
bind "fd@${fe1}" accept-proxy
|
||||
tcp-request content set-var(sess.aws) fc_pp_tlv(0xEA),bytes(1) if { fc_pp_tlv(0xEE),bytes(0,1),hex eq 01 }
|
||||
tcp-request content set-var(sess.azure) fc_pp_tlv(0xEE),bytes(1) if { fc_pp_tlv(0xEA),bytes(0,1),hex eq 01 }
|
||||
|
||||
http-after-response set-header echo1 %[var(sess.aws)]
|
||||
http-after-response set-header echo2 %[var(sess.azure)]
|
||||
http-after-response set-header echo3 %[fc_pp_tlv(0xEB)]
|
||||
http-after-response set-header echo4 %[fc_pp_tlv(0xEC),length]
|
||||
http-request return status 200
|
||||
} -start
|
||||
|
||||
client c1 -connect ${h1_fe1_sock} {
|
||||
# PROXY v2 signature
|
||||
sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a"
|
||||
# version + PROXY
|
||||
sendhex "21"
|
||||
# TCP4
|
||||
sendhex "11"
|
||||
# length of the address (12) + length of the TLVs (14 + 10 + 9 + 131)
|
||||
sendhex "00 B0"
|
||||
# 127.0.0.1 42 127.0.0.1 1337
|
||||
sendhex "7F 00 00 01 7F 00 00 01 00 2A 05 39"
|
||||
|
||||
# PP2_TYPE_AWS (0xEA) + length of the value + PP2_SUBTYPE_AWS_VPCE_ID (0x01) + "aws-vpc-id"
|
||||
# See https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#custom-tlv for the respective definitions.
|
||||
sendhex "EA 00 0B 01 61 77 73 2D 76 70 63 2D 69 64"
|
||||
|
||||
# PP2_TYPE_AZURE (0xEE) + length of the value + PP2_SUBTYPE_AZURE_PRIVATEENDPOINT_LINKID (0x01) + "LINKID"
|
||||
# See https://learn.microsoft.com/en-us/azure/private-link/private-link-service-overview#getting-connection-information-using-tcp-proxy-v2
|
||||
# for the respective definitions.
|
||||
sendhex "EE 00 07 01 4C 49 4E 4B 49 44"
|
||||
|
||||
# custom type (0xEB) + length of the value + "custom"
|
||||
sendhex "EB 00 06 63 75 73 74 6F 6D"
|
||||
|
||||
# custom type (0xEC) + length of the value (128, does not fit in pool) + random data
|
||||
sendhex "EC 00 80 3A D9 32 9B 11 A7 29 81 14 B2 33 F0 C2 0D 7A 53 D1 97 28 74 4B 78 8A D3 10 C4 B1 88 42 9C 63 8E 8B 8A A0 B4 B0 E7 9D 20 27 0F 1E 53 4D 33 F7 5A D0 91 3F B8 C9 E9 16 C4 61 C5 13 02 92 64 9D D4 22 5C 8E 4E 0B 2D 2D 7D 9F 5D 97 9B 25 C4 12 7D 21 75 C8 15 92 6B 64 F2 5F C0 A9 0F 9A 7D 0A 6D 68 79 F4 56 18 6F 23 45 2A 9B 36 34 3A 47 43 32 29 18 6F 23 45 2A 9B 36 34 3A 47 43 32 29 32 29"
|
||||
|
||||
txreq -url "/"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.http.echo1 == "aws-vpc-id"
|
||||
expect resp.http.echo2 == "LINKID"
|
||||
expect resp.http.echo3 == "custom"
|
||||
expect resp.http.echo4 == 128
|
||||
} -run
|
|
@ -15,6 +15,7 @@
|
|||
#include <import/ebmbtree.h>
|
||||
|
||||
#include <haproxy/api.h>
|
||||
#include <haproxy/arg.h>
|
||||
#include <haproxy/cfgparse.h>
|
||||
#include <haproxy/connection.h>
|
||||
#include <haproxy/fd.h>
|
||||
|
@ -2258,11 +2259,77 @@ int smp_fetch_fc_rcvd_proxy(const struct arg *args, struct sample *smp, const ch
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function checks the TLV type converter configuration.
|
||||
* It expects the corresponding TLV type as a string representing the number.
|
||||
* args[0] will be turned into the numerical value of the TLV type string.
|
||||
*/
|
||||
static int smp_check_tlv_type(struct arg *args, char **err)
|
||||
{
|
||||
int type;
|
||||
char *endp;
|
||||
|
||||
type = strtoul(args[0].data.str.area, &endp, 0);
|
||||
if (endp && *endp != '\0') {
|
||||
memprintf(err, "Could not convert type '%s'", args[0].data.str.area);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (type < 0 || type > 255) {
|
||||
memprintf(err, "Invalid TLV Type '%s'", args[0].data.str.area);
|
||||
return 0;
|
||||
}
|
||||
|
||||
chunk_destroy(&args[0].data.str);
|
||||
args[0].type = ARGT_SINT;
|
||||
args[0].data.sint = type;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* fetch an arbitrary TLV from a PROXY protocol v2 header */
|
||||
int smp_fetch_fc_pp_tlv(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
||||
{
|
||||
int idx;
|
||||
struct connection *conn = NULL;
|
||||
struct conn_tlv_list *conn_tlv = NULL;
|
||||
|
||||
conn = objt_conn(smp->sess->origin);
|
||||
if (!conn)
|
||||
return 0;
|
||||
|
||||
if (conn->flags & CO_FL_WAIT_XPRT) {
|
||||
smp->flags |= SMP_F_MAY_CHANGE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (args[0].type != ARGT_SINT)
|
||||
return 0;
|
||||
|
||||
idx = args[0].data.sint;
|
||||
conn_tlv = smp->ctx.p ? smp->ctx.p : LIST_ELEM(conn->tlv_list.n, struct conn_tlv_list *, list);
|
||||
list_for_each_entry_from(conn_tlv, &conn->tlv_list, list) {
|
||||
if (conn_tlv->type == idx) {
|
||||
smp->flags |= SMP_F_NOT_LAST;
|
||||
smp->data.type = SMP_T_STR;
|
||||
smp->data.u.str.area = conn_tlv->value;
|
||||
smp->data.u.str.data = conn_tlv->len;
|
||||
smp->ctx.p = conn_tlv;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
smp->flags &= ~SMP_F_NOT_LAST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fetch the authority TLV from a PROXY protocol header */
|
||||
int smp_fetch_fc_pp_authority(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
||||
{
|
||||
struct connection *conn = NULL;
|
||||
struct conn_tlv_list *conn_tlv;
|
||||
struct conn_tlv_list *conn_tlv = NULL;
|
||||
|
||||
conn = objt_conn(smp->sess->origin);
|
||||
if (!conn)
|
||||
|
@ -2276,7 +2343,6 @@ int smp_fetch_fc_pp_authority(const struct arg *args, struct sample *smp, const
|
|||
conn_tlv = smp->ctx.p ? smp->ctx.p : LIST_ELEM(conn->tlv_list.n, struct conn_tlv_list *, list);
|
||||
list_for_each_entry_from(conn_tlv, &conn->tlv_list, list) {
|
||||
if (conn_tlv->type == PP2_TYPE_AUTHORITY) {
|
||||
smp->flags |= SMP_F_NOT_LAST;
|
||||
smp->data.type = SMP_T_STR;
|
||||
smp->data.u.str.area = conn_tlv->value;
|
||||
smp->data.u.str.data = conn_tlv->len;
|
||||
|
@ -2295,7 +2361,7 @@ int smp_fetch_fc_pp_authority(const struct arg *args, struct sample *smp, const
|
|||
int smp_fetch_fc_pp_unique_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
||||
{
|
||||
struct connection *conn = NULL;
|
||||
struct conn_tlv_list *conn_tlv;
|
||||
struct conn_tlv_list *conn_tlv = NULL;
|
||||
|
||||
conn = objt_conn(smp->sess->origin);
|
||||
if (!conn)
|
||||
|
@ -2309,7 +2375,6 @@ int smp_fetch_fc_pp_unique_id(const struct arg *args, struct sample *smp, const
|
|||
conn_tlv = smp->ctx.p ? smp->ctx.p : LIST_ELEM(conn->tlv_list.n, struct conn_tlv_list *, list);
|
||||
list_for_each_entry_from(conn_tlv, &conn->tlv_list, list) {
|
||||
if (conn_tlv->type == PP2_TYPE_UNIQUE_ID) {
|
||||
smp->flags |= SMP_F_NOT_LAST;
|
||||
smp->data.type = SMP_T_STR;
|
||||
smp->data.u.str.area = conn_tlv->value;
|
||||
smp->data.u.str.data = conn_tlv->len;
|
||||
|
@ -2398,6 +2463,7 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
|
|||
{ "fc_rcvd_proxy", smp_fetch_fc_rcvd_proxy, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
|
||||
{ "fc_pp_authority", smp_fetch_fc_pp_authority, 0, NULL, SMP_T_STR, SMP_USE_L4CLI },
|
||||
{ "fc_pp_unique_id", smp_fetch_fc_pp_unique_id, 0, NULL, SMP_T_STR, SMP_USE_L4CLI },
|
||||
{ "fc_pp_tlv", smp_fetch_fc_pp_tlv, ARG1(1, STR), smp_check_tlv_type, SMP_T_STR, SMP_USE_L4CLI },
|
||||
{ /* END */ },
|
||||
}};
|
||||
|
||||
|
|
Loading…
Reference in New Issue