diff --git a/doc/configuration.txt b/doc/configuration.txt index ef80690d5..c59b9665c 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -2669,7 +2669,7 @@ http-check send-state http-request { allow | deny | tarpit | auth [realm ] | redirect | add-header | set-header | - set-nice | set-log-level } + set-nice | set-log-level | set-tos } [ { if | unless } ] Access control for Layer 7 requests @@ -2743,6 +2743,15 @@ http-request { allow | deny | tarpit | auth [realm ] | redirect | 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 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 | set-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 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 b20105529..89980b16e 100644 --- a/include/types/proto_http.h +++ b/include/types/proto_http.h @@ -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 */ }; diff --git a/src/proto_http.c b/src/proto_http.c index fe79c1573..ea9e14cb7 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -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; }