diff --git a/doc/configuration.txt b/doc/configuration.txt index c59b9665c..a04c6f763 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -2669,7 +2669,8 @@ http-check send-state http-request { allow | deny | tarpit | auth [realm ] | redirect | add-header | set-header | - set-nice | set-log-level | set-tos } + set-nice | set-log-level | set-tos | + set-mark } [ { if | unless } ] Access control for Layer 7 requests @@ -2752,6 +2753,15 @@ http-request { allow | deny | tarpit | auth [realm ] | redirect | border routers based on some information from the request. See RFC 2474, 2597, 3260 and 4594 for more information. + - "set-mark" is used to set the Netfilter MARK on all packets sent to the + client to the value passed in 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. + 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 @@ -2788,8 +2798,8 @@ http-request { allow | deny | tarpit | auth [realm ] | redirect | about ACL usage. http-response { allow | deny | add-header | set-nice | - set-header | set-log-level } - [ { if | unless } ] + set-header | set-log-level | + set-mark } [ { if | unless } ] Access control for Layer 7 responses May be used in sections: defaults | frontend | listen | backend @@ -2849,6 +2859,15 @@ http-response { allow | deny | add-header | set-nice | border routers based on some information from the request. See RFC 2474, 2597, 3260 and 4594 for more information. + - "set-mark" is used to set the Netfilter MARK on all packets sent to the + client to the value passed in 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. + 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 89980b16e..1d7c92ffe 100644 --- a/include/types/proto_http.h +++ b/include/types/proto_http.h @@ -249,6 +249,7 @@ enum { HTTP_REQ_ACT_SET_NICE, HTTP_REQ_ACT_SET_LOGL, HTTP_REQ_ACT_SET_TOS, + HTTP_REQ_ACT_SET_MARK, HTTP_REQ_ACT_MAX /* must always be last */ }; @@ -262,6 +263,7 @@ enum { HTTP_RES_ACT_SET_NICE, HTTP_RES_ACT_SET_LOGL, HTTP_RES_ACT_SET_TOS, + HTTP_RES_ACT_SET_MARK, HTTP_RES_ACT_MAX /* must always be last */ }; @@ -377,6 +379,7 @@ struct http_req_rule { 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 */ + int mark; /* nfmark value for HTTP_REQ_ACT_SET_MARK */ } arg; /* arguments used by some actions */ }; @@ -393,6 +396,7 @@ struct http_res_rule { 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 */ + int mark; /* nfmark value for HTTP_RES_ACT_SET_MARK */ } arg; /* arguments used by some actions */ }; diff --git a/src/proto_http.c b/src/proto_http.c index ea9e14cb7..2164a85b0 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -3218,6 +3218,12 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session #endif break; + case HTTP_REQ_ACT_SET_MARK: +#ifdef SO_MARK + setsockopt(s->req->prod->conn->t.sock.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark)); +#endif + break; + case HTTP_REQ_ACT_SET_LOGL: s->logs.level = rule->arg.loglevel; break; @@ -3298,6 +3304,12 @@ http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session #endif break; + case HTTP_RES_ACT_SET_MARK: +#ifdef SO_MARK + setsockopt(s->req->prod->conn->t.sock.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark)); +#endif + break; + case HTTP_RES_ACT_SET_LOGL: s->logs.level = rule->arg.loglevel; break; @@ -8457,6 +8469,31 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i #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-mark")) { +#ifdef SO_MARK + char *err; + rule->action = HTTP_REQ_ACT_SET_MARK; + 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.mark = strtoul(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++; + global.last_checks |= LSTCHK_NETADM; +#else + Alert("parsing [%s:%d]: 'http-request %s' is not supported on this platform (SO_MARK 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; @@ -8513,7 +8550,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-tos', '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-mark', 'set-log-level', but got '%s'%s.\n", file, linenum, args[0], *args[0] ? "" : " (missing argument)"); goto out_err; } @@ -8600,6 +8637,31 @@ struct http_res_rule *parse_http_res_cond(const char **args, const char *file, i #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-mark")) { +#ifdef SO_MARK + char *err; + rule->action = HTTP_RES_ACT_SET_MARK; + 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.mark = strtoul(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++; + global.last_checks |= LSTCHK_NETADM; +#else + Alert("parsing [%s:%d]: 'http-response %s' is not supported on this platform (SO_MARK 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; @@ -8637,7 +8699,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-tos', '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-mark', 'set-log-level', but got '%s'%s.\n", file, linenum, args[0], *args[0] ? "" : " (missing argument)"); goto out_err; }