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.
This commit is contained in:
Willy Tarreau 2013-06-11 18:51:32 +02:00
parent 9a355ec257
commit 42cf39e3b9
3 changed files with 87 additions and 3 deletions

View File

@ -2669,7 +2669,7 @@ http-check send-state
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 @@ http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
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 @@ http-response { allow | deny | add-header <name> <fmt> | set-nice <nice> |
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

View File

@ -248,6 +248,7 @@ enum {
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 @@ enum {
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 http_req_rule {
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 @@ struct http_res_rule {
} 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 */
};

View File

@ -3211,6 +3211,13 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session
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 @@ http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session
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 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
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 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
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 @@ struct http_res_rule *parse_http_res_cond(const char **args, const char *file, i
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 @@ struct http_res_rule *parse_http_res_cond(const char **args, const char *file, i
(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;
}