From fb8714c5aebd7fe957264d0f2234182f55f952fe Mon Sep 17 00:00:00 2001 From: Alexander Stephan <alexander.step...@sap.com> 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