MINOR: server: Add parser support for set-proxy-v2-tlv-fmt

This commit introduces a generic server-side parsing of type-value pair
arguments and allocation of a TLV list via a new keyword called
set-proxy-v2-tlv-fmt.

This allows to 1) forward any TLV type with the help of fc_pp_tlv,
2) generally, send out any TLV type and value via a log format expression.
To have this fully working the connection will need to be updated in
a follow-up commit to actually respect the new server TLV list.

default-server support has also been implemented.
This commit is contained in:
Alexander Stephan 2023-10-28 20:51:26 +02:00 committed by Willy Tarreau
parent 2d213b268e
commit 6f4bfed3a2
2 changed files with 157 additions and 46 deletions

View File

@ -256,6 +256,16 @@ 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 a format string, if specified in the config.
*/
struct srv_pp_tlv_list {
struct list list;
struct list fmt;
char *fmt_string;
unsigned char type;
};
struct proxy;
struct server {
/* mostly config or admin stuff, doesn't change often */
@ -427,6 +437,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 */

View File

@ -1325,6 +1325,69 @@ static int srv_parse_send_proxy_v2(char **args, int *cur_arg,
return srv_enable_pp_flags(newsrv, SRV_PP_V2);
}
/* Parse the "set-proxy-v2-tlv-fmt" server keyword */
static int srv_parse_set_proxy_v2_tlv_fmt(char **args, int *cur_arg,
struct proxy *px, struct server *newsrv, char **err)
{
char *error = NULL, *cmd = NULL;
unsigned int tlv_type = 0;
struct srv_pp_tlv_list *srv_tlv = NULL;
cmd = args[*cur_arg];
if (!*cmd) {
memprintf(err, "'%s' : could not read set-proxy-v2-tlv-fmt command", args[*cur_arg]);
goto fail;
}
cmd += strlen("set-proxy-v2-tlv-fmt");
if (*cmd == '(') {
cmd++; /* skip the '(' */
errno = 0;
tlv_type = strtoul(cmd, &error, 0); /* convert TLV ID */
if (unlikely((cmd == error) || (errno != 0))) {
memprintf(err, "'%s' : could not convert TLV ID", args[*cur_arg]);
goto fail;
}
if (errno == EINVAL) {
memprintf(err, "'%s' : could not find a valid number for the TLV ID", args[*cur_arg]);
goto fail;
}
if (*error != ')') {
memprintf(err, "'%s' : expects set-proxy-v2-tlv(<TLV ID>)", args[*cur_arg]);
goto fail;
}
if (tlv_type > 0xFF) {
memprintf(err, "'%s' : the maximum allowed TLV ID is %d", args[*cur_arg], 0xFF);
goto fail;
}
}
srv_tlv = malloc(sizeof(struct srv_pp_tlv_list));
if (unlikely(!srv_tlv)) {
memprintf(err, "'%s' : failed to parse allocate TLV entry", args[*cur_arg]);
goto fail;
}
srv_tlv->type = tlv_type;
srv_tlv->fmt_string = strdup(args[*cur_arg + 1]);
if (unlikely(!srv_tlv->fmt_string)) {
memprintf(err, "'%s' : failed to save format string for parsing", args[*cur_arg]);
free(srv_tlv->fmt_string);
goto fail;
}
LIST_APPEND(&newsrv->pp_tlvs, &srv_tlv->list);
(*cur_arg)++;
return 0;
fail:
free(srv_tlv);
errno = 0;
return ERR_ALERT | ERR_FATAL;
}
/* Parse the "slowstart" server keyword */
static int srv_parse_slowstart(char **args, int *cur_arg,
struct proxy *curproxy, struct server *newsrv, char **err)
@ -1950,6 +2013,7 @@ static struct srv_kw_list srv_kws = { "ALL", { }, {
{ "resolvers", srv_parse_resolvers, 1, 1, 0 }, /* Configure the resolver to use for name resolution */
{ "send-proxy", srv_parse_send_proxy, 0, 1, 1 }, /* Enforce use of PROXY V1 protocol */
{ "send-proxy-v2", srv_parse_send_proxy_v2, 0, 1, 1 }, /* Enforce use of PROXY V2 protocol */
{ "set-proxy-v2-tlv-fmt", srv_parse_set_proxy_v2_tlv_fmt, 0, 1, 1 }, /* Set TLV of PROXY V2 protocol */
{ "shard", srv_parse_shard, 1, 1, 1 }, /* Server shard (only in peers protocol context) */
{ "slowstart", srv_parse_slowstart, 1, 1, 1 }, /* Set the warm-up timer for a previously failed server */
{ "source", srv_parse_source, -1, 1, 1 }, /* Set the source address to be used to connect to the server */
@ -2331,6 +2395,8 @@ int srv_prepare_for_resolution(struct server *srv, const char *hostname)
*/
void srv_settings_cpy(struct server *srv, const struct server *src, int srv_tmpl)
{
struct srv_pp_tlv_list *srv_tlv = NULL, *new_srv_tlv = NULL;
/* Connection source settings copy */
srv_conn_src_cpy(srv, src);
@ -2445,6 +2511,26 @@ void srv_settings_cpy(struct server *srv, const struct server *src, int srv_tmpl
srv->check.via_socks4 = src->check.via_socks4;
srv->socks4_addr = src->socks4_addr;
srv->log_bufsize = src->log_bufsize;
LIST_INIT(&srv->pp_tlvs);
list_for_each_entry(srv_tlv, &src->pp_tlvs, list) {
if (srv_tlv == NULL)
break;
new_srv_tlv = malloc(sizeof(struct srv_pp_tlv_list));
if (unlikely(!new_srv_tlv)) {
free(new_srv_tlv);
break;
}
new_srv_tlv->fmt_string = strdup(srv_tlv->fmt_string);
if (unlikely(!new_srv_tlv->fmt_string)) {
free(new_srv_tlv);
free(new_srv_tlv->fmt_string);
break;
}
new_srv_tlv->type = srv_tlv->type;
LIST_APPEND(&srv->pp_tlvs, &new_srv_tlv->list);
}
}
/* allocate a server and attach it to the global servers_list. Returns
@ -2466,6 +2552,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 */
@ -3119,7 +3206,7 @@ static int _srv_parse_sni_expr_init(char **args, int cur_arg,
}
/* Server initializations finalization.
* Initialize health check, agent check and SNI expression if enabled.
* Initialize health check, agent check, SNI expression and outgoing TLVs if enabled.
* Must not be called for a default server instance.
*
* This function is first intended to be used through parse_server to
@ -3131,6 +3218,7 @@ static int _srv_parse_finalize(char **args, int cur_arg,
{
int ret;
char *errmsg = NULL;
struct srv_pp_tlv_list *srv_tlv = NULL;
if (srv->do_check && srv->trackit) {
ha_alert("unable to enable checks and tracking at the same time!\n");
@ -3161,6 +3249,18 @@ static int _srv_parse_finalize(char **args, int cur_arg,
px->srv_act++;
}
list_for_each_entry(srv_tlv, &srv->pp_tlvs, list) {
LIST_INIT(&srv_tlv->fmt);
if (srv_tlv->fmt_string && unlikely(!parse_logformat_string(srv_tlv->fmt_string,
srv->proxy, &srv_tlv->fmt, 0, SMP_VAL_BE_SRV_CON, &errmsg))) {
if (errmsg) {
ha_alert("%s\n", errmsg);
free(errmsg);
}
return ERR_ALERT | ERR_FATAL;
}
}
srv_lb_commit_status(srv);
return 0;