From fb8714c5aebd7fe957264d0f2234182f55f952fe Mon Sep 17 00:00:00 2001
From: Alexander Stephan
<[email protected]<mailto:[email protected]>>
Date: Fri, 15 Sep 2023 12:38:46 +0200
Subject: [PATCH 1/4] MEDIUM: server: Parse generic type-value pairs as
proxy-v2-options
This commit introduces a generic server-side parsing of type-value pair
arguments and allocation of a TLV list. This allows to 1) forward any TLV
type, 2) generally send out any TLV type, and 3) allows to specify concrete
values via an '=' after the type and a log fmt expression. If there is no
TLV found in the remote connection, an empty TLV is sent out.
---
include/haproxy/server-t.h | 10 +++++
src/server.c | 76 +++++++++++++++++++++++++++++++++++---
2 files changed, 81 insertions(+), 5 deletions(-)
diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h
index 1175a470e..7b93bf48f 100644
--- a/include/haproxy/server-t.h
+++ b/include/haproxy/server-t.h
@@ -256,6 +256,15 @@ enum __attribute__((__packed__)) srv_ws_mode {
SRV_WS_H2,
};
+/* Server-side TLV list, contains the types of the TLVs that should be sent
out.
+ * Additionally, it can contain data, if specified in the config.
+ */
+struct srv_pp_tlv_list {
+ struct list list;
+ struct list fmt;
+ unsigned char type;
+};
+
struct proxy;
struct server {
/* mostly config or admin stuff, doesn't change often */
@@ -421,6 +430,7 @@ struct server {
struct list srv_rec_item; /* to attach server to a srv record item */
struct list ip_rec_item; /* to attach server to a A or AAAA record
item */
struct ebpt_node host_dn; /* hostdn store for srvrq and state file
matching*/
+ struct list pp_tlvs; /* to send out PROXY protocol v2 TLVs */
struct task *srvrq_check; /* Task testing SRV record
expiration date for this server */
struct {
const char *file; /* file where the section appears */
diff --git a/src/server.c b/src/server.c
index 3673340d1..08f86d030 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1036,7 +1036,13 @@ static int srv_parse_proto(char **args, int *cur_arg,
static int srv_parse_proxy_v2_options(char **args, int *cur_arg,
struct proxy *px, struct server *newsrv, char **err)
{
- char *p, *n;
+ char *p = NULL, *n = NULL, *m = NULL;
+ char *key = NULL, *val = NULL;
+ char *endp = NULL;
+ unsigned char idx = 0;
+ size_t key_length = 0, val_length = 0;
+ struct srv_pp_tlv_list *srv_tlv = NULL;
+
for (p = args[*cur_arg+1]; p; p = n) {
n = strchr(p, ',');
if (n)
@@ -1061,13 +1067,61 @@ static int srv_parse_proxy_v2_options(char **args, int
*cur_arg,
newsrv->pp_opts |= SRV_PP_V2_CRC32C;
} else if (strcmp(p, "unique-id") == 0) {
newsrv->pp_opts |= SRV_PP_V2_UNIQUE_ID;
- } else
- goto fail;
+ } else {
+ /* reset val in case it was set before */
+ val = NULL;
+
+ /* try to split by '=' into generic pair key value pair
(<id>=<expr>) */
+ m = strchr(p, '=');
+ if (m) {
+ key_length = m - p;
+ key = (char *) malloc(key_length + 1);
+ if (unlikely(!key))
+ goto fail;
+ snprintf(key, key_length + 1, "%s", p);
+
+ val_length = strlen(p) - key_length;
+ val = (char *) malloc(val_length + 1);
+ if (unlikely(!val))
+ goto fail;
+ snprintf(val, val_length + 1, "%s", m + 1);
+ }
+ else {
+ key = (char *) malloc(strlen(p) + 1);
+ if (unlikely(!key))
+ goto fail;
+ snprintf(key, strlen(p) + 1, "%s", p);
+ }
+
+ errno = 0;
+ idx = strtoul(key, &endp, 0);
+ if (unlikely((endp && *endp) != '\0' || (key == endp) || (errno !=
0)))
+ goto fail;
+
+ /* processing is done in connection.c */
+ srv_tlv = malloc(sizeof(struct srv_pp_tlv_list));
+ if (unlikely(!srv_tlv))
+ goto fail;
+
+ srv_tlv->type = idx;
+ LIST_INIT(&srv_tlv->fmt);
+ if (val && unlikely(!parse_logformat_string(val, px, &srv_tlv->fmt,
LOG_OPT_HTTP, PR_CAP_LISTEN, err)))
+ goto fail;
+
+ LIST_APPEND(&newsrv->pp_tlvs, &srv_tlv->list);
+ free(key);
+ free(val);
+ }
}
return 0;
- fail:
+fail:
+ free(key);
+ free(val);
+ free(srv_tlv);
+ errno = 0;
+
if (err)
- memprintf(err, "'%s' : proxy v2 option not implemented", p);
+ memprintf(err, "'%s' : failed to set proxy v2 option", p);
return ERR_ALERT | ERR_FATAL;
}
@@ -2428,6 +2482,7 @@ struct server *new_server(struct proxy *proxy)
LIST_APPEND(&servers_list, &srv->global_list);
LIST_INIT(&srv->srv_rec_item);
LIST_INIT(&srv->ip_rec_item);
+ LIST_INIT(&srv->pp_tlvs);
MT_LIST_INIT(&srv->prev_deleted);
event_hdl_sub_list_init(&srv->e_subs);
srv->rid = 0; /* rid defaults to 0 */
@@ -2495,6 +2550,8 @@ void srv_free_params(struct server *srv)
struct server *srv_drop(struct server *srv)
{
struct server *next = NULL;
+ struct srv_pp_tlv_list *srv_tlv = NULL, *srv_tlv_back = NULL;
+ struct logformat_node *node = NULL, *node_back = NULL;
if (!srv)
goto end;
@@ -2527,6 +2584,15 @@ struct server *srv_drop(struct server *srv)
EXTRA_COUNTERS_FREE(srv->extra_counters);
+ list_for_each_entry_safe(srv_tlv, srv_tlv_back, &srv->pp_tlvs, list) {
+ list_for_each_entry_safe(node, node_back, &srv_tlv->fmt, list) {
+ free(node->arg);
+ free(node->expr);
+ LIST_DELETE(&node->list);
+ }
+ LIST_DELETE(&srv_tlv->list);
+ }
+
ha_free(&srv);
end:
--
2.35.3