From d2a536e458f4cd7ffeadfe302c23bbfe263b0053 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 3 Jun 2024 07:11:10 +0200 Subject: Merging upstream version 3.0.0. Signed-off-by: Daniel Baumann --- src/tcp_act.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 193 insertions(+), 48 deletions(-) (limited to 'src/tcp_act.c') diff --git a/src/tcp_act.c b/src/tcp_act.c index 8b44047..c9c4a5c 100644 --- a/src/tcp_act.c +++ b/src/tcp_act.c @@ -71,6 +71,29 @@ static enum act_return tcp_action_attach_srv(struct act_rule *rule, struct proxy return ACT_RET_CONT; } +/* tries to extract integer value from rule's argument: + * if expr is set, computes expr and sets the result into + * else, it's already a numerical value, use it as-is. + * + * Returns 1 on success and 0 on failure. + */ +static int extract_int_from_rule(struct act_rule *rule, + struct proxy *px, struct session *sess, struct stream *s, + int *value) +{ + struct sample *smp; + + if (!rule->arg.expr_int.expr) { + *value = rule->arg.expr_int.value; + return 1; + } + smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr_int.expr, SMP_T_SINT); + if (!smp) + return 0; + *value = smp->data.u.sint; + return 1; +} + /* * Execute the "set-src" action. May be called from {tcp,http}request. * It only changes the address and tries to preserve the original port. If the @@ -389,19 +412,57 @@ static enum act_return tcp_exec_action_silent_drop(struct act_rule *rule, struct #if defined(SO_MARK) || defined(SO_USER_COOKIE) || defined(SO_RTABLE) -static enum act_return tcp_action_set_mark(struct act_rule *rule, struct proxy *px, - struct session *sess, struct stream *s, int flags) +static enum act_return tcp_action_set_fc_mark(struct act_rule *rule, struct proxy *px, + struct session *sess, struct stream *s, int flags) +{ + unsigned int mark; + + if (extract_int_from_rule(rule, px, sess, s, (int *)&mark)) + conn_set_mark(objt_conn(sess->origin), mark); + return ACT_RET_CONT; +} +static enum act_return tcp_action_set_bc_mark(struct act_rule *rule, struct proxy *px, + struct session *sess, struct stream *s, int flags) { - conn_set_mark(objt_conn(sess->origin), (uintptr_t)rule->arg.act.p[0]); + struct connection __maybe_unused *conn = (s && s->scb) ? sc_conn(s->scb) : NULL; + unsigned int mark; + + BUG_ON(!s || conn); + if (extract_int_from_rule(rule, px, sess, s, (int *)&mark)) { + /* connection does not exist yet, ensure it will be applied + * before connection is used by saving it within the stream + */ + s->bc_mark = mark; + s->flags |= SF_BC_MARK; + } return ACT_RET_CONT; } #endif #ifdef IP_TOS -static enum act_return tcp_action_set_tos(struct act_rule *rule, struct proxy *px, - struct session *sess, struct stream *s, int flags) +static enum act_return tcp_action_set_fc_tos(struct act_rule *rule, struct proxy *px, + struct session *sess, struct stream *s, int flags) +{ + int tos; + + if (extract_int_from_rule(rule, px, sess, s, &tos)) + conn_set_tos(objt_conn(sess->origin), tos); + return ACT_RET_CONT; +} +static enum act_return tcp_action_set_bc_tos(struct act_rule *rule, struct proxy *px, + struct session *sess, struct stream *s, int flags) { - conn_set_tos(objt_conn(sess->origin), (uintptr_t)rule->arg.act.p[0]); + struct connection __maybe_unused *conn = (s && s->scb) ? sc_conn(s->scb) : NULL; + int tos; + + BUG_ON(!s || conn); + if (extract_int_from_rule(rule, px, sess, s, &tos)) { + /* connection does not exist yet, ensure it will be applied + * before connection is used by saving it within the stream + */ + s->bc_tos = tos; + s->flags |= SF_BC_TOS; + } return ACT_RET_CONT; } #endif @@ -423,6 +484,14 @@ static void release_set_src_dst_action(struct act_rule *rule) release_sample_expr(rule->arg.expr); } +/* + * Release expr_int rule argument when action is no longer used + */ +static __maybe_unused void release_expr_int_action(struct act_rule *rule) +{ + release_sample_expr(rule->arg.expr_int.expr); +} + static int tcp_check_attach_srv(struct act_rule *rule, struct proxy *px, char **err) { struct proxy *be = NULL; @@ -451,10 +520,16 @@ static int tcp_check_attach_srv(struct act_rule *rule, struct proxy *px, char ** return 0; } - if ((rule->arg.attach_srv.name && (!srv->use_ssl || !srv->sni_expr)) || - (!rule->arg.attach_srv.name && srv->use_ssl && srv->sni_expr)) { - memprintf(err, "attach-srv rule: connection will never be used; either specify name argument in conjunction with defined SSL SNI on targeted server or none of these"); - return 0; + if (rule->arg.attach_srv.name) { + if (!srv->pool_conn_name) { + memprintf(err, "attach-srv rule has a name argument while server '%s/%s' does not use pool-conn-name; either reconfigure the server or remove the name argument from this attach-srv rule", ist0(be_name), ist0(sv_name)); + return 0; + } + } else { + if (srv->pool_conn_name) { + memprintf(err, "attach-srv rule has no name argument while server '%s/%s' uses pool-conn-name; either add a name argument to the attach-srv rule or reconfigure the server", ist0(be_name), ist0(sv_name)); + return 0; + } } rule->arg.attach_srv.srv = srv; @@ -565,29 +640,56 @@ static enum act_parse_ret tcp_parse_set_src_dst(const char **args, int *orig_arg /* Parse a "set-mark" action. It takes the MARK value as argument. It returns * ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error. */ -static enum act_parse_ret tcp_parse_set_mark(const char **args, int *cur_arg, struct proxy *px, - struct act_rule *rule, char **err) +static enum act_parse_ret tcp_parse_set_mark(const char **args, int *orig_arg, struct proxy *px, + struct act_rule *rule, char **err) { #if defined(SO_MARK) || defined(SO_USER_COOKIE) || defined(SO_RTABLE) + struct sample_expr *expr; char *endp; - unsigned int mark; + unsigned int where; + int cur_arg = *orig_arg; - if (!*args[*cur_arg]) { - memprintf(err, "expects exactly 1 argument (integer/hex value)"); + if (!*args[*orig_arg]) { + memprintf(err, "expects an argument"); return ACT_RET_PRS_ERR; } - mark = strtoul(args[*cur_arg], &endp, 0); - if (endp && *endp != '\0') { - memprintf(err, "invalid character starting at '%s' (integer/hex value expected)", endp); - return ACT_RET_PRS_ERR; + + /* value may be either an unsigned integer or an expression */ + rule->arg.expr_int.expr = NULL; + rule->arg.expr_int.value = strtoul(args[*orig_arg], &endp, 0); + if (*endp == '\0') { + /* valid unsigned integer */ + (*orig_arg)++; } + else { + /* invalid unsigned integer, fallback to expr */ + expr = sample_parse_expr((char **)args, orig_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL); + if (!expr) + return ACT_RET_PRS_ERR; - (*cur_arg)++; + where = 0; + if (px->cap & PR_CAP_FE) + where |= SMP_VAL_FE_HRQ_HDR; + if (px->cap & PR_CAP_BE) + where |= SMP_VAL_BE_HRQ_HDR; + + if (!(expr->fetch->val & where)) { + memprintf(err, + "fetch method '%s' extracts information from '%s', none of which is available here", + args[cur_arg-1], sample_src_names(expr->fetch->use)); + free(expr); + return ACT_RET_PRS_ERR; + } + rule->arg.expr_int.expr = expr; + } /* Register processing function. */ - rule->action_ptr = tcp_action_set_mark; + if (strcmp("set-bc-mark", args[cur_arg - 1]) == 0) + rule->action_ptr = tcp_action_set_bc_mark; + else + rule->action_ptr = tcp_action_set_fc_mark; // fc mark rule->action = ACT_CUSTOM; - rule->arg.act.p[0] = (void *)(uintptr_t)mark; + rule->release_ptr = release_expr_int_action; global.last_checks |= LSTCHK_NETADM; return ACT_RET_PRS_OK; #else @@ -600,29 +702,56 @@ static enum act_parse_ret tcp_parse_set_mark(const char **args, int *cur_arg, st /* Parse a "set-tos" action. It takes the TOS value as argument. It returns * ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error. */ -static enum act_parse_ret tcp_parse_set_tos(const char **args, int *cur_arg, struct proxy *px, - struct act_rule *rule, char **err) +static enum act_parse_ret tcp_parse_set_tos(const char **args, int *orig_arg, struct proxy *px, + struct act_rule *rule, char **err) { #ifdef IP_TOS + struct sample_expr *expr; char *endp; - int tos; + unsigned int where; + int cur_arg = *orig_arg; - if (!*args[*cur_arg]) { - memprintf(err, "expects exactly 1 argument (integer/hex value)"); + if (!*args[*orig_arg]) { + memprintf(err, "expects an argument"); return ACT_RET_PRS_ERR; } - tos = strtol(args[*cur_arg], &endp, 0); - if (endp && *endp != '\0') { - memprintf(err, "invalid character starting at '%s' (integer/hex value expected)", endp); - return ACT_RET_PRS_ERR; + + /* value may be either an integer or an expression */ + rule->arg.expr_int.expr = NULL; + rule->arg.expr_int.value = strtol(args[*orig_arg], &endp, 0); + if (*endp == '\0') { + /* valid integer */ + (*orig_arg)++; } + else { + /* invalid unsigned integer, fallback to expr */ + expr = sample_parse_expr((char **)args, orig_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL); + if (!expr) + return ACT_RET_PRS_ERR; - (*cur_arg)++; + where = 0; + if (px->cap & PR_CAP_FE) + where |= SMP_VAL_FE_HRQ_HDR; + if (px->cap & PR_CAP_BE) + where |= SMP_VAL_BE_HRQ_HDR; + + if (!(expr->fetch->val & where)) { + memprintf(err, + "fetch method '%s' extracts information from '%s', none of which is available here", + args[cur_arg-1], sample_src_names(expr->fetch->use)); + free(expr); + return ACT_RET_PRS_ERR; + } + rule->arg.expr_int.expr = expr; + } /* Register processing function. */ - rule->action_ptr = tcp_action_set_tos; + if (strcmp("set-bc-tos", args[cur_arg - 1]) == 0) + rule->action_ptr = tcp_action_set_bc_tos; + else + rule->action_ptr = tcp_action_set_fc_tos; // fc tos rule->action = ACT_CUSTOM; - rule->arg.act.p[0] = (void *)(uintptr_t)tos; + rule->release_ptr = release_expr_int_action; return ACT_RET_PRS_OK; #else memprintf(err, "not supported on this platform (IP_TOS undefined)"); @@ -672,10 +801,12 @@ static enum act_parse_ret tcp_parse_silent_drop(const char **args, int *cur_arg, static struct action_kw_list tcp_req_conn_actions = {ILH, { { "set-dst" , tcp_parse_set_src_dst }, { "set-dst-port", tcp_parse_set_src_dst }, - { "set-mark", tcp_parse_set_mark }, + { "set-fc-mark", tcp_parse_set_mark }, + { "set-fc-tos", tcp_parse_set_tos }, + { "set-mark", tcp_parse_set_mark }, // DEPRECATED, see set-fc-mark { "set-src", tcp_parse_set_src_dst }, { "set-src-port", tcp_parse_set_src_dst }, - { "set-tos", tcp_parse_set_tos }, + { "set-tos", tcp_parse_set_tos }, // DEPRECATED, see set-fc-tos { "silent-drop", tcp_parse_silent_drop }, { /* END */ } }}; @@ -686,10 +817,12 @@ static struct action_kw_list tcp_req_sess_actions = {ILH, { { "attach-srv" , tcp_parse_attach_srv }, { "set-dst" , tcp_parse_set_src_dst }, { "set-dst-port", tcp_parse_set_src_dst }, - { "set-mark", tcp_parse_set_mark }, + { "set-fc-mark", tcp_parse_set_mark }, + { "set-fc-tos", tcp_parse_set_tos }, + { "set-mark", tcp_parse_set_mark }, // DEPRECATED, see set-fc-mark { "set-src", tcp_parse_set_src_dst }, { "set-src-port", tcp_parse_set_src_dst }, - { "set-tos", tcp_parse_set_tos }, + { "set-tos", tcp_parse_set_tos }, // DEPRECATED, see set-fc-tos { "silent-drop", tcp_parse_silent_drop }, { /* END */ } }}; @@ -697,12 +830,16 @@ static struct action_kw_list tcp_req_sess_actions = {ILH, { INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_actions); static struct action_kw_list tcp_req_cont_actions = {ILH, { - { "set-src", tcp_parse_set_src_dst }, - { "set-src-port", tcp_parse_set_src_dst }, + { "set-bc-mark", tcp_parse_set_mark }, + { "set-bc-tos", tcp_parse_set_tos }, { "set-dst" , tcp_parse_set_src_dst }, { "set-dst-port", tcp_parse_set_src_dst }, - { "set-mark", tcp_parse_set_mark }, - { "set-tos", tcp_parse_set_tos }, + { "set-fc-mark", tcp_parse_set_mark }, + { "set-fc-tos", tcp_parse_set_tos }, + { "set-mark", tcp_parse_set_mark }, // DEPRECATED, see set-fc-mark + { "set-src", tcp_parse_set_src_dst }, + { "set-src-port", tcp_parse_set_src_dst }, + { "set-tos", tcp_parse_set_tos }, // DEPRECATED, see set-fc-tos { "silent-drop", tcp_parse_silent_drop }, { /* END */ } }}; @@ -710,8 +847,10 @@ static struct action_kw_list tcp_req_cont_actions = {ILH, { INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_actions); static struct action_kw_list tcp_res_cont_actions = {ILH, { - { "set-mark", tcp_parse_set_mark }, - { "set-tos", tcp_parse_set_tos }, + { "set-fc-mark", tcp_parse_set_mark }, + { "set-fc-tos", tcp_parse_set_tos }, + { "set-mark", tcp_parse_set_mark }, // DEPRECATED, see set-fc-mark + { "set-tos", tcp_parse_set_tos }, // DEPRECATED, see set-fc-tos { "silent-drop", tcp_parse_silent_drop }, { /* END */ } }}; @@ -719,12 +858,16 @@ static struct action_kw_list tcp_res_cont_actions = {ILH, { INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_cont_actions); static struct action_kw_list http_req_actions = {ILH, { + { "set-bc-mark", tcp_parse_set_mark }, + { "set-bc-tos", tcp_parse_set_tos }, { "set-dst", tcp_parse_set_src_dst }, { "set-dst-port", tcp_parse_set_src_dst }, - { "set-mark", tcp_parse_set_mark }, + { "set-fc-mark", tcp_parse_set_mark }, + { "set-fc-tos", tcp_parse_set_tos }, + { "set-mark", tcp_parse_set_mark }, // DEPRECATED, see set-fc-mark { "set-src", tcp_parse_set_src_dst }, { "set-src-port", tcp_parse_set_src_dst }, - { "set-tos", tcp_parse_set_tos }, + { "set-tos", tcp_parse_set_tos }, // DEPRECATED, see set-fc-tos { "silent-drop", tcp_parse_silent_drop }, { /* END */ } }}; @@ -732,8 +875,10 @@ static struct action_kw_list http_req_actions = {ILH, { INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_actions); static struct action_kw_list http_res_actions = {ILH, { - { "set-mark", tcp_parse_set_mark }, - { "set-tos", tcp_parse_set_tos }, + { "set-fc-mark", tcp_parse_set_mark }, + { "set-fc-tos", tcp_parse_set_tos }, + { "set-mark", tcp_parse_set_mark }, // DEPRECATED, see set-fc-mark + { "set-tos", tcp_parse_set_tos }, // DEPRECATED, see set-fc-tos { "silent-drop", tcp_parse_silent_drop }, { /* END */ } }}; -- cgit v1.2.3