]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: http: add the "set-mark" action on http-request/http-response rules
authorWilly Tarreau <w@1wt.eu>
Tue, 11 Jun 2013 17:34:13 +0000 (19:34 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 11 Jun 2013 17:34:13 +0000 (19:34 +0200)
"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.

doc/configuration.txt
include/types/proto_http.h
src/proto_http.c

index c59b9665cbb478406f41698dbc938582d035b06c..a04c6f763b6815ddacc4665cb7b587c1c8cd4a20 100644 (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
index 89980b16e8303343de17bbc6591570f6994f455c..1d7c92ffe987a33d8be4949e6cd5cb41d974f511 100644 (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 */
 };
 
index ea9e14cb735d822b927fabe23e9671ba90d62009..2164a85b08010dfb9091cdf4c08360e74c7debac 100644 (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;
        }