MEDIUM: http: add support for "set-tos" in http-request/http-response
This manipulates the TOS field of the IP header of outgoing packets sent
to the client. This can be used to set a specific DSCP traffic class based
on some request or response information. See RFC2474, 2597, 3260 and 4594
for more information.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index ef80690..c59b966 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -2669,7 +2669,7 @@
http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
add-header <name> <fmt> | set-header <name> <fmt> |
- set-nice <nice> | set-log-level <level> }
+ set-nice <nice> | set-log-level <level> | set-tos <tos> }
[ { if | unless } <condition> ]
Access control for Layer 7 requests
@@ -2743,6 +2743,15 @@
rule wins. This rule can be useful to disable health checks coming from
another equipment.
+ - "set-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 behaviour on
+ border routers based on some information from the request. See RFC 2474,
+ 2597, 3260 and 4594 for more information.
+
There is no limit to the number of http-request statements per instance.
It is important to know that http-request rules are processed very early in
@@ -2831,6 +2840,15 @@
rule wins. This rule can be useful to disable health checks coming from
another equipment.
+ - "set-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 behaviour on
+ border routers based on some information from the request. See RFC 2474,
+ 2597, 3260 and 4594 for more information.
+
There is no limit to the number of http-response statements per instance.
It is important to know that http-reqsponse rules are processed very early in
diff --git a/include/types/proto_http.h b/include/types/proto_http.h
index b201055..89980b1 100644
--- a/include/types/proto_http.h
+++ b/include/types/proto_http.h
@@ -248,6 +248,7 @@
HTTP_REQ_ACT_REDIR,
HTTP_REQ_ACT_SET_NICE,
HTTP_REQ_ACT_SET_LOGL,
+ HTTP_REQ_ACT_SET_TOS,
HTTP_REQ_ACT_MAX /* must always be last */
};
@@ -260,6 +261,7 @@
HTTP_RES_ACT_SET_HDR,
HTTP_RES_ACT_SET_NICE,
HTTP_RES_ACT_SET_LOGL,
+ HTTP_RES_ACT_SET_TOS,
HTTP_RES_ACT_MAX /* must always be last */
};
@@ -374,6 +376,7 @@
struct redirect_rule *redir; /* redirect rule or "http-request redirect" */
int nice; /* nice value for HTTP_REQ_ACT_SET_NICE */
int loglevel; /* log-level value for HTTP_REQ_ACT_SET_LOGL */
+ int tos; /* tos value for HTTP_REQ_ACT_SET_TOS */
} arg; /* arguments used by some actions */
};
@@ -389,6 +392,7 @@
} hdr_add; /* args used by "add-header" and "set-header" */
int nice; /* nice value for HTTP_RES_ACT_SET_NICE */
int loglevel; /* log-level value for HTTP_RES_ACT_SET_LOGL */
+ int tos; /* tos value for HTTP_RES_ACT_SET_TOS */
} arg; /* arguments used by some actions */
};
diff --git a/src/proto_http.c b/src/proto_http.c
index fe79c15..ea9e14c 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -3211,6 +3211,13 @@
s->task->nice = rule->arg.nice;
break;
+ case HTTP_REQ_ACT_SET_TOS:
+#ifdef IP_TOS
+ if (s->req->prod->conn->addr.to.ss_family == AF_INET)
+ setsockopt(s->req->prod->conn->t.sock.fd, IPPROTO_IP, IP_TOS, &rule->arg.tos, sizeof(rule->arg.tos));
+#endif
+ break;
+
case HTTP_REQ_ACT_SET_LOGL:
s->logs.level = rule->arg.loglevel;
break;
@@ -3284,6 +3291,13 @@
s->task->nice = rule->arg.nice;
break;
+ case HTTP_RES_ACT_SET_TOS:
+#ifdef IP_TOS
+ if (s->req->prod->conn->addr.to.ss_family == AF_INET)
+ setsockopt(s->req->prod->conn->t.sock.fd, IPPROTO_IP, IP_TOS, &rule->arg.tos, sizeof(rule->arg.tos));
+#endif
+ break;
+
case HTTP_RES_ACT_SET_LOGL:
s->logs.level = rule->arg.loglevel;
break;
@@ -8420,6 +8434,30 @@
else if (rule->arg.nice > 1024)
rule->arg.nice = 1024;
cur_arg++;
+ } else if (!strcmp(args[0], "set-tos")) {
+#ifdef IP_TOS
+ char *err;
+ rule->action = HTTP_REQ_ACT_SET_TOS;
+ cur_arg = 1;
+
+ if (!*args[cur_arg] ||
+ (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
+ Alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument (integer/hex value).\n",
+ file, linenum, args[0]);
+ goto out_err;
+ }
+
+ rule->arg.tos = strtol(args[cur_arg], &err, 0);
+ if (err && *err != '\0') {
+ Alert("parsing [%s:%d]: invalid character starting at '%s' in 'http-request %s' (integer/hex value expected).\n",
+ file, linenum, err, args[0]);
+ goto out_err;
+ }
+ cur_arg++;
+#else
+ Alert("parsing [%s:%d]: 'http-request %s' is not supported on this platform (IP_TOS undefined).\n", file, linenum, args[0]);
+ goto out_err;
+#endif
} else if (!strcmp(args[0], "set-log-level")) {
rule->action = HTTP_REQ_ACT_SET_LOGL;
cur_arg = 1;
@@ -8475,7 +8513,7 @@
cur_arg = 2;
return rule;
} else {
- Alert("parsing [%s:%d]: 'http-request' expects 'allow', 'deny', 'auth', 'redirect', 'tarpit', 'add-header', 'set-header', 'set-nice', 'set-log-level', but got '%s'%s.\n",
+ Alert("parsing [%s:%d]: 'http-request' expects 'allow', 'deny', 'auth', 'redirect', 'tarpit', 'add-header', 'set-header', 'set-nice', 'set-tos', 'set-log-level', but got '%s'%s.\n",
file, linenum, args[0], *args[0] ? "" : " (missing argument)");
goto out_err;
}
@@ -8539,6 +8577,30 @@
else if (rule->arg.nice > 1024)
rule->arg.nice = 1024;
cur_arg++;
+ } else if (!strcmp(args[0], "set-tos")) {
+#ifdef IP_TOS
+ char *err;
+ rule->action = HTTP_RES_ACT_SET_TOS;
+ cur_arg = 1;
+
+ if (!*args[cur_arg] ||
+ (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
+ Alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument (integer/hex value).\n",
+ file, linenum, args[0]);
+ goto out_err;
+ }
+
+ rule->arg.tos = strtol(args[cur_arg], &err, 0);
+ if (err && *err != '\0') {
+ Alert("parsing [%s:%d]: invalid character starting at '%s' in 'http-response %s' (integer/hex value expected).\n",
+ file, linenum, err, args[0]);
+ goto out_err;
+ }
+ cur_arg++;
+#else
+ Alert("parsing [%s:%d]: 'http-response %s' is not supported on this platform (IP_TOS undefined).\n", file, linenum, args[0]);
+ goto out_err;
+#endif
} else if (!strcmp(args[0], "set-log-level")) {
rule->action = HTTP_RES_ACT_SET_LOGL;
cur_arg = 1;
@@ -8575,7 +8637,7 @@
(proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR);
cur_arg += 2;
} else {
- Alert("parsing [%s:%d]: 'http-response' expects 'allow', 'deny', 'redirect', 'add-header', 'set-header', 'set-nice', 'set-log-level', but got '%s'%s.\n",
+ Alert("parsing [%s:%d]: 'http-response' expects 'allow', 'deny', 'redirect', 'add-header', 'set-header', 'set-nice', 'set-tos', 'set-log-level', but got '%s'%s.\n",
file, linenum, args[0], *args[0] ? "" : " (missing argument)");
goto out_err;
}