MEDIUM: http: add the "set-mark" action on http-request/http-response rules

"set-mark" is used to set the Netfilter MARK on 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.
This commit is contained in:
Willy Tarreau 2013-06-11 19:34:13 +02:00
parent 42cf39e3b9
commit 51347ed94c
3 changed files with 90 additions and 5 deletions

View File

@ -2669,7 +2669,8 @@ 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-tos <tos> }
set-nice <nice> | set-log-level <level> | set-tos <tos> |
set-mark <mark> }
[ { if | unless } <condition> ]
Access control for Layer 7 requests
@ -2752,6 +2753,15 @@ http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
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 <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.
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 <realm>] | redirect <rule> |
about ACL usage.
http-response { allow | deny | add-header <name> <fmt> | set-nice <nice> |
set-header <name> <fmt> | set-log-level <level> }
[ { if | unless } <condition> ]
set-header <name> <fmt> | set-log-level <level> |
set-mark <mark> } [ { if | unless } <condition> ]
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 <name> <fmt> | set-nice <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 <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.
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

@ -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 */
};

View File

@ -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;
}