diff --git a/include/proto/checks.h b/include/proto/checks.h index fb33746cf..d0c827bd7 100644 --- a/include/proto/checks.h +++ b/include/proto/checks.h @@ -63,6 +63,8 @@ static inline void tcp_check_keywords_register(struct action_kw_list *kw_list) } void deinit_proxy_tcpcheck(struct proxy *px); +int dup_tcpcheck_vars(struct list *dst, struct list *src); + /* Declared here, but the definitions are in flt_spoe.c */ int spoe_prepare_healthcheck_request(char **req, int *len); int spoe_handle_healthcheck_response(char *frame, size_t size, char *err, int errlen); diff --git a/include/types/checks.h b/include/types/checks.h index 94ce5f228..c44fe8e39 100644 --- a/include/types/checks.h +++ b/include/types/checks.h @@ -302,10 +302,18 @@ struct tcpcheck_rule { #define TCPCHK_RULES_SHARED 0x00000001 /* Set for shared list of tcp-check rules */ #define TCPCHK_RULES_DEF 0x00000002 /* Ruleset inherited from the default section */ +/* A list of tcp-check vars, to be registered before executing a ruleset */ +struct tcpcheck_var { + struct ist name; /* the variable name with the scope */ + struct sample_data data; /* the data associated to the variable */ + struct list list; /* element to chain tcp-check vars */ +}; + /* a list of tcp-check rules */ struct tcpcheck_rules { - unsigned int flags; /* flags applied to the rules */ - struct list *list; /* the list of tcpcheck_rules */ + unsigned int flags; /* flags applied to the rules */ + struct list *list; /* the list of tcpcheck_rules */ + struct list preset_vars; /* The list of variable to preset before executing the ruleset */ }; /* A list of tcp-check rules with a name */ diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c index f098b16b6..0b2ef1583 100644 --- a/src/cfgparse-listen.c +++ b/src/cfgparse-listen.c @@ -305,6 +305,15 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) curproxy->tcpcheck_rules.flags = (defproxy.tcpcheck_rules.flags | TCPCHK_RULES_DEF); curproxy->tcpcheck_rules.list = defproxy.tcpcheck_rules.list; + if (!LIST_ISEMPTY(&defproxy.tcpcheck_rules.preset_vars)) { + if (!dup_tcpcheck_vars(&curproxy->tcpcheck_rules.preset_vars, + &defproxy.tcpcheck_rules.preset_vars)) { + ha_alert("parsing [%s:%d] : failed to duplicate tcpcheck preset-vars\n", + file, linenum); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + } if (defproxy.expect_str) { curproxy->expect_str = strdup(defproxy.expect_str); diff --git a/src/checks.c b/src/checks.c index c26f17707..6820d2874 100644 --- a/src/checks.c +++ b/src/checks.c @@ -3279,6 +3279,8 @@ static int tcpcheck_main(struct check *check) rule = check->current_step; } else { + struct tcpcheck_var *var; + /* First evaluation, create a session */ check->sess = session_new(&checks_fe, NULL, (check->server ? &check->server->obj_type : NULL)); if (!check->sess) { @@ -3288,6 +3290,16 @@ static int tcpcheck_main(struct check *check) } vars_init(&check->vars, SCOPE_CHECK); rule = LIST_NEXT(check->tcpcheck_rules->list, typeof(rule), list); + + /* Preset tcp-check variables */ + list_for_each_entry(var, &check->tcpcheck_rules->preset_vars, list) { + struct sample smp; + + memset(&smp, 0, sizeof(smp)); + smp_set_owner(&smp, check->proxy, check->sess, NULL, SMP_OPT_FINAL); + smp.data = var->data; + vars_set_by_name_ifexist(var->name.ptr, var->name.len, &smp); + } } list_for_each_entry_from(rule, check->tcpcheck_rules->list, list) { @@ -3538,6 +3550,80 @@ static void free_tcpcheck(struct tcpcheck_rule *rule, int in_pool) free(rule); } + +static __maybe_unused struct tcpcheck_var *tcpcheck_var_create(const char *name) +{ + struct tcpcheck_var *var = NULL; + + var = calloc(1, sizeof(*var)); + if (var == NULL) + return NULL; + + var->name = ist2(strdup(name), strlen(name)); + if (var->name.ptr == NULL) { + free(var); + return NULL; + } + + LIST_INIT(&var->list); + return var; +} + +static void tcpcheck_var_release(struct tcpcheck_var *var) +{ + if (!var) + return; + + free(var->name.ptr); + if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) + free(var->data.u.str.area); + else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) + free(var->data.u.meth.str.area); + free(var); +} + +int dup_tcpcheck_vars(struct list *dst, struct list *src) +{ + struct tcpcheck_var *var, *new = NULL; + + list_for_each_entry(var, src, list) { + new = tcpcheck_var_create(var->name.ptr); + if (!new) + goto error; + new->data.type = var->data.type; + if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) { + if (chunk_dup(&new->data.u.str, &var->data.u.str) == NULL) + goto error; + if (var->data.type == SMP_T_STR) + new->data.u.str.area[new->data.u.str.data] = 0; + } + else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) { + if (chunk_dup(&new->data.u.str, &var->data.u.str) == NULL) + goto error; + new->data.u.str.area[new->data.u.str.data] = 0; + new->data.u.meth.meth = var->data.u.meth.meth; + } + else + new->data.u = var->data.u; + LIST_ADDQ(dst, &new->list); + } + return 1; + + error: + free(new); + return 0; +} + +static void free_tcpcheck_vars(struct list *vars) +{ + struct tcpcheck_var *var, *back; + + list_for_each_entry_safe(var, back, vars, list) { + LIST_DEL(&var->list); + tcpcheck_var_release(var); + } +} + void email_alert_free(struct email_alert *alert) { struct tcpcheck_rule *rule, *back; @@ -3550,6 +3636,7 @@ void email_alert_free(struct email_alert *alert) LIST_DEL(&rule->list); free_tcpcheck(rule, 1); } + free_tcpcheck_vars(&alert->rules.preset_vars); free(alert->rules.list); alert->rules.list = NULL; } @@ -3757,6 +3844,7 @@ static int enqueue_one_email_alert(struct proxy *p, struct server *s, if (!alert->rules.list) goto error; LIST_INIT(alert->rules.list); + LIST_INIT(&alert->rules.preset_vars); /* unused for email alerts */ alert->srv = s; if ((tcpcheck = pool_alloc(pool_head_tcpcheck_rule)) == NULL) @@ -4122,6 +4210,7 @@ void deinit_proxy_tcpcheck(struct proxy *px) LIST_DEL(&chk->list); free_tcpcheck(chk, 0); } + free_tcpcheck_vars(&px->tcpcheck_rules.preset_vars); free(px->tcpcheck_rules.list); end: diff --git a/src/proxy.c b/src/proxy.c index d2d6a43d6..2614325ca 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -877,6 +877,7 @@ void init_new_proxy(struct proxy *p) LIST_INIT(&p->conf.errors); LIST_INIT(&p->conf.args.list); LIST_INIT(&p->filter_configs); + LIST_INIT(&p->tcpcheck_rules.preset_vars); /* Timeouts are defined as -1 */ proxy_reset_timeouts(p);