MINOR: http-act/tcp-act: Add "set-mark" and "set-tos" for tcp content rules
It is now possible to set the Netfilter MARK and the TOS field value in all
packets sent to the client from any tcp-request rulesets or the "tcp-response
content" one. To do so, the parsing of "set-mark" and "set-tos" actions are
moved in tcp_act.c and the actions evaluation is handled in dedicated functions.
This patch may be backported as far as 2.2 if necessary.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 7843e04..9ffcc75 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -11897,6 +11897,16 @@
expected result is a boolean. If an error occurs, this action silently
fails and the actions evaluation continues.
+ - set-mark <mark>:
+ Is used to set the Netfilter MARK in 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 and by the
+ routing table. 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.
+
- set-src <expr> :
Is used to set the source IP address to the value of specified
expression. Useful if you want to mask source IP for privacy.
@@ -11963,6 +11973,17 @@
long as the address family supports a port, otherwise it forces the
destination address to IPv4 "0.0.0.0" before rewriting the port.
+ - set-tos <tos>:
+ 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.
+
+ See RFC 2474, 2597, 3260 and 4594 for more information.
+
- "silent-drop" :
This stops the evaluation of the rules and makes the client-facing
connection suddenly disappear using a system-dependent way that tries
@@ -12057,9 +12078,11 @@
- set-dst <expr>
- set-dst-port <expr>
- set-log-level <level>
+ - set-mark <mark>
- set-nice <nice>
- set-src <expr>
- set-src-port <expr>
+ - set-tos <tos>
- set-var(<var-name>) <expr>
- switch-mode http [ proto <name> ]
- unset-var(<var-name>)
@@ -12113,12 +12136,18 @@
The "set-log-level" is used to set the log level of the current session. More
information on how to use it at "http-request set-log-level".
+ The "set-mark" is used to set the Netfilter MARK in all packets sent to the
+ client. More information on how to use it at "http-request set-mark".
+
The "set-nice" is used to set the "nice" factor of the current session. More
information on how to use it at "http-request set-nice".
The "set-src" and "set-src-port" are used to set respectively the source IP
and port. More information on how to use it at "http-request set-src".
+ The "set-tos" is used to set the TOS or DSCP field value of packets sent to
+ the client. More information on how to use it at "http-request set-tos".
+
The "set-var" is used to set the content of a variable. The variable is
declared inline. For "tcp-request session" rules, only session-level
variables can be used, without any layer7 contents.
@@ -12363,11 +12392,21 @@
session. More information on how to use it at "http-response
set-log-level".
+ - set-mark <mark>
+ The "set-mark" is used to set the Netfilter MARK in all packets sent to
+ the client. More information on how to use it at "http-response
+ set-mark".
+
- set-nice <nice>
The "set-nice" is used to set the "nice" factor of the current
session. More information on how to use it at "http-response
set-nice".
+ - set-tos <tos>
+ The "set-tos" is used to set the TOS or DSCP field value of packets
+ sent to the client. More information on how to use it at "http-response
+ set-tos".
+
- set-var(<var-name>) <expr>
Sets a variable.
@@ -12510,10 +12549,12 @@
- sc-inc-gpc0(<sc-id>)
- sc-inc-gpc1(<sc-id>)
- sc-set-gpt0(<sc-id>) { <int> | <expr> }
+ - set-mark <mark>
- set-dst <expr>
- set-dst-port <expr>
- set-src <expr>
- set-src-port <expr>
+ - set-tos <tos>
- set-var(<var-name>) <expr>
- unset-var(<var-name>)
- silent-drop
diff --git a/include/haproxy/action-t.h b/include/haproxy/action-t.h
index 4f02163..773ccd1 100644
--- a/include/haproxy/action-t.h
+++ b/include/haproxy/action-t.h
@@ -81,8 +81,6 @@
/* common http actions .*/
ACT_HTTP_REDIR,
- ACT_HTTP_SET_TOS,
- ACT_HTTP_SET_MARK,
/* http request actions. */
ACT_HTTP_REQ_TARPIT,
diff --git a/src/http_act.c b/src/http_act.c
index 9e49d33..b77fd93 100644
--- a/src/http_act.c
+++ b/src/http_act.c
@@ -1315,71 +1315,6 @@
return ACT_RET_PRS_OK;
}
-/* 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 parse_http_set_tos(const char **args, int *orig_arg, struct proxy *px,
- struct act_rule *rule, char **err)
-{
-#ifdef IP_TOS
- char *endp;
- int cur_arg;
-
- rule->action = ACT_HTTP_SET_TOS;
-
- cur_arg = *orig_arg;
- if (!*args[cur_arg]) {
- memprintf(err, "expects exactly 1 argument (integer/hex value)");
- return ACT_RET_PRS_ERR;
- }
- rule->arg.http.i = 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;
- }
-
- LIST_INIT(&rule->arg.http.fmt);
- *orig_arg = cur_arg + 1;
- return ACT_RET_PRS_OK;
-#else
- memprintf(err, "not supported on this platform (IP_TOS undefined)");
- return ACT_RET_PRS_ERR;
-#endif
-}
-
-/* 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 parse_http_set_mark(const char **args, int *orig_arg, struct proxy *px,
- struct act_rule *rule, char **err)
-{
-#ifdef SO_MARK
- char *endp;
- int cur_arg;
-
- rule->action = ACT_HTTP_SET_MARK;
-
- cur_arg = *orig_arg;
- if (!*args[cur_arg]) {
- memprintf(err, "expects exactly 1 argument (integer/hex value)");
- return ACT_RET_PRS_ERR;
- }
- rule->arg.http.i = 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;
- }
-
- LIST_INIT(&rule->arg.http.fmt);
- *orig_arg = cur_arg + 1;
- global.last_checks |= LSTCHK_NETADM;
- return ACT_RET_PRS_OK;
-#else
- memprintf(err, "not supported on this platform (SO_MARK undefined)");
- return ACT_RET_PRS_ERR;
-#endif
-}
-
/* This function executes a early-hint action. It adds an HTTP Early Hint HTTP
* 103 response header with <.arg.http.str> name and with a value built
* according to <.arg.http.fmt> log line format. If it is the first early-hint
@@ -2458,11 +2393,9 @@
{ "set-header", parse_http_set_header, 0 },
{ "set-map", parse_http_set_map, KWF_MATCH_PREFIX },
{ "set-method", parse_set_req_line, 0 },
- { "set-mark", parse_http_set_mark, 0 },
{ "set-path", parse_set_req_line, 0 },
{ "set-pathq", parse_set_req_line, 0 },
{ "set-query", parse_set_req_line, 0 },
- { "set-tos", parse_http_set_tos, 0 },
{ "set-uri", parse_set_req_line, 0 },
{ "strict-mode", parse_http_strict_mode, 0 },
{ "tarpit", parse_http_deny, 0 },
@@ -2491,9 +2424,7 @@
{ "return", parse_http_return, 0 },
{ "set-header", parse_http_set_header, 0 },
{ "set-map", parse_http_set_map, KWF_MATCH_PREFIX },
- { "set-mark", parse_http_set_mark, 0 },
{ "set-status", parse_http_set_status, 0 },
- { "set-tos", parse_http_set_tos, 0 },
{ "strict-mode", parse_http_strict_mode, 0 },
{ "track-sc", parse_http_track_sc, KWF_MATCH_PREFIX },
{ "wait-for-body", parse_http_wait_for_body, 0 },
diff --git a/src/http_ana.c b/src/http_ana.c
index fc0b5bc..63ee760 100644
--- a/src/http_ana.c
+++ b/src/http_ana.c
@@ -2831,14 +2831,6 @@
rule_ret = HTTP_RULE_RES_ERROR;
goto end;
- case ACT_HTTP_SET_TOS:
- conn_set_tos(objt_conn(sess->origin), rule->arg.http.i);
- break;
-
- case ACT_HTTP_SET_MARK:
- conn_set_mark(objt_conn(sess->origin), rule->arg.http.i);
- break;
-
/* other flags exists, but normally, they never be matched. */
default:
break;
@@ -2958,14 +2950,6 @@
rule_ret = HTTP_RULE_RES_DENY;
goto end;
- case ACT_HTTP_SET_TOS:
- conn_set_tos(objt_conn(sess->origin), rule->arg.http.i);
- break;
-
- case ACT_HTTP_SET_MARK:
- conn_set_mark(objt_conn(sess->origin), rule->arg.http.i);
- break;
-
case ACT_HTTP_REDIR:
rule_ret = HTTP_RULE_RES_ABRT;
if (!http_apply_redirect_rule(rule->arg.redir, s, txn))
diff --git a/src/tcp_act.c b/src/tcp_act.c
index a6f0596..cb6c75f 100644
--- a/src/tcp_act.c
+++ b/src/tcp_act.c
@@ -236,6 +236,22 @@
return ACT_RET_ABRT;
}
+
+static enum act_return tcp_action_set_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]);
+ return ACT_RET_CONT;
+}
+
+static enum act_return tcp_action_set_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]);
+ return ACT_RET_CONT;
+}
+
+
/* parse "set-{src,dst}[-port]" action */
static enum act_parse_ret tcp_parse_set_src_dst(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
@@ -279,7 +295,76 @@
(*orig_arg)++;
+ return ACT_RET_PRS_OK;
+}
+
+
+/* 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)
+{
+#ifdef SO_MARK
+ char *endp;
+ unsigned int mark;
+
+ if (!*args[*cur_arg]) {
+ memprintf(err, "expects exactly 1 argument (integer/hex value)");
+ 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;
+ }
+
+ (*cur_arg)++;
+
+ /* Register processing function. */
+ rule->action_ptr = tcp_action_set_mark;
+ rule->action = ACT_CUSTOM;
+ rule->arg.act.p[0] = (void *)(uintptr_t)mark;
+ global.last_checks |= LSTCHK_NETADM;
+ return ACT_RET_PRS_OK;
+#else
+ memprintf(err, "not supported on this platform (SO_MARK undefined)");
+ return ACT_RET_PRS_ERR;
+#endif
+}
+
+
+/* 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)
+{
+#ifdef IP_TOS
+ char *endp;
+ int tos;
+
+ if (!*args[*cur_arg]) {
+ memprintf(err, "expects exactly 1 argument (integer/hex value)");
+ 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;
+ }
+
+ (*cur_arg)++;
+
+ /* Register processing function. */
+ rule->action_ptr = tcp_action_set_tos;
+ rule->action = ACT_CUSTOM;
+ rule->arg.act.p[0] = (void *)(uintptr_t)tos;
return ACT_RET_PRS_OK;
+#else
+ memprintf(err, "not supported on this platform (IP_TOS undefined)");
+ return ACT_RET_PRS_ERR;
+#endif
}
@@ -296,10 +381,12 @@
static struct action_kw_list tcp_req_conn_actions = {ILH, {
+ { "set-mark", tcp_parse_set_mark },
{ "set-src", tcp_parse_set_src_dst },
{ "set-src-port", tcp_parse_set_src_dst },
{ "set-dst" , tcp_parse_set_src_dst },
{ "set-dst-port", tcp_parse_set_src_dst },
+ { "set-tos", tcp_parse_set_tos },
{ "silent-drop", tcp_parse_silent_drop },
{ /* END */ }
}};
@@ -307,10 +394,12 @@
INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_req_conn_actions);
static struct action_kw_list tcp_req_sess_actions = {ILH, {
+ { "set-mark", tcp_parse_set_mark },
{ "set-src", tcp_parse_set_src_dst },
{ "set-src-port", tcp_parse_set_src_dst },
{ "set-dst" , tcp_parse_set_src_dst },
{ "set-dst-port", tcp_parse_set_src_dst },
+ { "set-tos", tcp_parse_set_tos },
{ "silent-drop", tcp_parse_silent_drop },
{ /* END */ }
}};
@@ -318,10 +407,12 @@
INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_actions);
static struct action_kw_list tcp_req_cont_actions = {ILH, {
+ { "set-mark", tcp_parse_set_mark },
{ "set-src", tcp_parse_set_src_dst },
{ "set-src-port", tcp_parse_set_src_dst },
{ "set-dst" , tcp_parse_set_src_dst },
{ "set-dst-port", tcp_parse_set_src_dst },
+ { "set-tos", tcp_parse_set_tos },
{ "silent-drop", tcp_parse_silent_drop },
{ /* END */ }
}};
@@ -329,6 +420,8 @@
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 },
{ "silent-drop", tcp_parse_silent_drop },
{ /* END */ }
}};
@@ -336,17 +429,21 @@
INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_cont_actions);
static struct action_kw_list http_req_actions = {ILH, {
+ { "set-mark", tcp_parse_set_mark },
{ "silent-drop", tcp_parse_silent_drop },
{ "set-src", tcp_parse_set_src_dst },
{ "set-src-port", tcp_parse_set_src_dst },
{ "set-dst", tcp_parse_set_src_dst },
{ "set-dst-port", tcp_parse_set_src_dst },
+ { "set-tos", tcp_parse_set_tos },
{ /* END */ }
}};
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 },
{ "silent-drop", tcp_parse_silent_drop },
{ /* END */ }
}};