destination address to IPv4 "0.0.0.0" before rewriting the port.
-set-fc-mark <mark>
+set-fc-mark { <mark> | <expr> }
Usable in: TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
X | X | X | X | X | X | -
This is used to set the Netfilter/IPFW MARK on all packets sent to the client
- to the value passed in <mark> on platforms which support it. This value is an
- unsigned 32 bit value which can be matched by netfilter/ipfw and by the
- routing table or monitoring the packets through DTrace. It can be expressed
- both in decimal or hexadecimal format (prefixed by "0x").
- This can be useful to force certain packets to take a different route (for
- example a cheaper network path for bulk downloads). This works on Linux
- kernels 2.6.32 and above and requires admin privileges, as well on FreeBSD
- and OpenBSD.
-
-
-set-fc-tos <tos>
+ to the value passed in <mark> or <expr> on platforms which support it. This
+ value is an unsigned 32 bit value which can be matched by netfilter/ipfw and
+ by the routing table or monitoring the packets through DTrace. <mark> can be
+ expressed both in decimal or hexadecimal format (prefixed by "0x").
+ Alternatively, <expr> can be used: it is a standard HAProxy expression formed
+ by a sample-fetch followed by some converters which must resolve to integer
+ type. This action can be useful to force certain packets to take a different
+ route (for example a cheaper network path for bulk downloads). This works on
+ Linux kernels 2.6.32 and above and requires admin privileges, as well on
+ FreeBSD and OpenBSD.
+
+
+set-fc-tos { <tos | <expr> }
Usable in: TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
X | X | X | X | X | X | -
This is used to set the TOS or DSCP field value of packets sent to the client
- to the value passed in <tos> on platforms which support this. This value
- represents the whole 8 bits of the IP TOS field, and can be expressed both in
- decimal or hexadecimal format (prefixed by "0x"). Note that only the 6 higher
- bits are used in DSCP or TOS, and the two lower bits are always 0. This can
- be used to adjust some routing behavior on border routers based on some
- information from the request.
+ to the value passed in <tos> or <expr> on platforms which support this. This
+ value represents the whole 8 bits of the IP TOS field. Note that only the 6
+ higher bits are used in DSCP or TOS, and the two lower bits are always 0.
+ Alternatively, <expr> can be used: it is a standard HAProxy expression formed
+ by a sample-fetch followed by some converters which must resolve to integer
+ type. This action can be used to adjust some routing behavior on border
+ routers based on some information from the request.
See RFC 2474, 2597, 3260 and 4594 for more information.
return ACT_RET_CONT;
}
+/* tries to extract integer value from rule's argument:
+ * if expr is set, computes expr and sets the result into <value>
+ * 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
static enum act_return tcp_action_set_fc_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]);
+ 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;
}
#endif
static enum act_return tcp_action_set_fc_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]);
+ int tos;
+
+ if (extract_int_from_rule(rule, px, sess, s, &tos))
+ conn_set_tos(objt_conn(sess->origin), tos);
return ACT_RET_CONT;
}
#endif
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;
/* 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_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
/* 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_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)");