From 7d081f02a43651d781a3a30a51ae19abdceb5683 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Thu, 15 Apr 2021 09:38:37 +0200 Subject: [PATCH] MINOR: tcp_samples: Add samples to get src/dst info of the backend connection This patch adds 4 new sample fetches to get the source and the destination info (ip address and port) of the backend connection : * bc_dst : Returns the destination address of the backend connection * bc_dst_port : Returns the destination port of the backend connection * bc_src : Returns the source address of the backend connection * bc_src_port : Returns the source port of the backend connection The configuration manual was updated accordingly. --- doc/configuration.txt | 20 +++++++++++++ src/tcp_sample.c | 67 ++++++++++++++++++++++++++----------------- 2 files changed, 61 insertions(+), 26 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index 61c2a6dd9c..4241f9227d 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -17247,11 +17247,31 @@ table may be specified with the "sc*" form, in which case the currently tracked key will be looked up into this alternate table instead of the table currently being tracked. +bc_dst : ip + This is the destination ip address of the connection on the server side, + which is the server address HAProxy connected to. It is of type IP and works + on both IPv4 and IPv6 tables. On IPv6 tables, IPv4 address is mapped to its + IPv6 equivalent, according to RFC 4291. + +bc_dst_port : integer + Returns an integer value corresponding to the destination TCP port of the + connection on the server side, which is the port HAproxy connected to. + bc_http_major : integer Returns the backend connection's HTTP major version encoding, which may be 1 for HTTP/0.9 to HTTP/1.1 or 2 for HTTP/2. Note, this is based on the on-wire encoding and not the version present in the request header. +bc_src : ip + This is the source ip address of the connection on the server side, which is + the server address haproxy connected from. It is of type IP and works on both + IPv4 and IPv6 tables. On IPv6 tables, IPv4 addresses are mapped to their IPv6 + equivalent, according to RFC 4291. + +bc_src_port : integer + Returns an integer value corresponding to the TCP source port of the + connection on the server side, which is the port HAproxy connected from. + be_id : integer Returns an integer containing the current backend's id. It can be used in frontends with responses to check which backend processed the request. It can diff --git a/src/tcp_sample.c b/src/tcp_sample.c index 06ad6c6355..4fbd98c1c4 100644 --- a/src/tcp_sample.c +++ b/src/tcp_sample.c @@ -41,27 +41,28 @@ #include -/* Fetch the connection's source IPv4/IPv6 address. Note that this is also - * directly called by stick_table.c and as such must remain publicly visible. +/* Fetch the connection's source IPv4/IPv6 address. Depending on the keyword, it + * may be the frontend or the backend connection. */ static int smp_fetch_src(const struct arg *args, struct sample *smp, const char *kw, void *private) { - struct connection *cli_conn = objt_conn(smp->sess->origin); + struct connection *conn = (kw[0] != 'b') ? objt_conn(smp->sess->origin) : + smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL; - if (!cli_conn) + if (!conn) return 0; - if (!conn_get_src(cli_conn)) + if (!conn_get_src(conn)) return 0; - switch (cli_conn->src->ss_family) { + switch (conn->src->ss_family) { case AF_INET: - smp->data.u.ipv4 = ((struct sockaddr_in *)cli_conn->src)->sin_addr; + smp->data.u.ipv4 = ((struct sockaddr_in *)conn->src)->sin_addr; smp->data.type = SMP_T_IPV4; break; case AF_INET6: - smp->data.u.ipv6 = ((struct sockaddr_in6 *)cli_conn->src)->sin6_addr; + smp->data.u.ipv6 = ((struct sockaddr_in6 *)conn->src)->sin6_addr; smp->data.type = SMP_T_IPV6; break; default: @@ -72,45 +73,51 @@ smp_fetch_src(const struct arg *args, struct sample *smp, const char *kw, void * return 1; } -/* set temp integer to the connection's source port */ +/* set temp integer to the connection's source port. Depending on the + * keyword, it may be the frontend or the backend connection. + */ static int -smp_fetch_sport(const struct arg *args, struct sample *smp, const char *k, void *private) +smp_fetch_sport(const struct arg *args, struct sample *smp, const char *kw, void *private) { - struct connection *cli_conn = objt_conn(smp->sess->origin); + struct connection *conn = (kw[0] != 'b') ? objt_conn(smp->sess->origin) : + smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL; - if (!cli_conn) + if (!conn) return 0; - if (!conn_get_src(cli_conn)) + if (!conn_get_src(conn)) return 0; smp->data.type = SMP_T_SINT; - if (!(smp->data.u.sint = get_host_port(cli_conn->src))) + if (!(smp->data.u.sint = get_host_port(conn->src))) return 0; smp->flags = 0; return 1; } -/* fetch the connection's destination IPv4/IPv6 address */ +/* fetch the connection's destination IPv4/IPv6 address. Depending on the + * keyword, it may be the frontend or the backend connection. + */ static int smp_fetch_dst(const struct arg *args, struct sample *smp, const char *kw, void *private) { - struct connection *cli_conn = objt_conn(smp->sess->origin); + struct connection *conn = (kw[0] != 'b') ? objt_conn(smp->sess->origin) : + smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL; - if (!cli_conn) + if (!conn) return 0; - if (!conn_get_dst(cli_conn)) + if (!conn_get_dst(conn)) return 0; - switch (cli_conn->dst->ss_family) { + switch (conn->dst->ss_family) { case AF_INET: - smp->data.u.ipv4 = ((struct sockaddr_in *)cli_conn->dst)->sin_addr; + smp->data.u.ipv4 = ((struct sockaddr_in *)conn->dst)->sin_addr; smp->data.type = SMP_T_IPV4; break; case AF_INET6: - smp->data.u.ipv6 = ((struct sockaddr_in6 *)cli_conn->dst)->sin6_addr; + smp->data.u.ipv6 = ((struct sockaddr_in6 *)conn->dst)->sin6_addr; smp->data.type = SMP_T_IPV6; break; default: @@ -161,20 +168,23 @@ int smp_fetch_src_is_local(const struct arg *args, struct sample *smp, const cha return smp->data.u.sint >= 0; } -/* set temp integer to the frontend connexion's destination port */ +/* set temp integer to the connexion's destination port. Depending on the + * keyword, it may be the frontend or the backend connection. + */ static int smp_fetch_dport(const struct arg *args, struct sample *smp, const char *kw, void *private) { - struct connection *cli_conn = objt_conn(smp->sess->origin); + struct connection *conn = (kw[0] != 'b') ? objt_conn(smp->sess->origin) : + smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL; - if (!cli_conn) + if (!conn) return 0; - if (!conn_get_dst(cli_conn)) + if (!conn_get_dst(conn)) return 0; smp->data.type = SMP_T_SINT; - if (!(smp->data.u.sint = get_host_port(cli_conn->dst))) + if (!(smp->data.u.sint = get_host_port(conn->dst))) return 0; smp->flags = 0; @@ -383,6 +393,11 @@ smp_fetch_fc_reordering(const struct arg *args, struct sample *smp, const char * * instance v4/v6 must be declared v4. */ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, { + { "bc_dst", smp_fetch_dst, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV }, + { "bc_dst_port", smp_fetch_dport, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV }, + { "bc_src", smp_fetch_src, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV }, + { "bc_src_port", smp_fetch_sport, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV }, + { "dst", smp_fetch_dst, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI }, { "dst_is_local", smp_fetch_dst_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI }, { "dst_port", smp_fetch_dport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI }, -- 2.39.5