]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: http: Add new 'set-src' option to http-request
authorAdis Nezirovic <anezirovic@haproxy.com>
Mon, 6 Jul 2015 13:44:30 +0000 (15:44 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 6 Jul 2015 14:17:28 +0000 (16:17 +0200)
This option enables overriding source IP address in a HTTP request. It is
useful when we want to set custom source IP (e.g. front proxy rewrites address,
but provides the correct one in headers) or we wan't to mask source IP address
for privacy or compliance.

It acts on any expression which produces correct IP address.

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

index dd418f4099428486e704ace3f84981a7577cf6b0..90834a71678a67e94a31200ac215b3bc5fb0cd53 100644 (file)
@@ -3672,6 +3672,22 @@ http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
 
          http-request set-var(req.my_var) req.fhdr(user-agent),lower
 
+    - set-src <expr> :
+      Is used to set the source IP address to the value of specified
+      expression. Useful when a proxy in front of HAProxy rewrites source IP,
+      but provides the correct IP in a HTTP header; or you want to mask
+      source IP for privacy.
+
+         <expr>    Is a standard HAProxy expression formed by a sample-fetch
+                   followed by some converters.
+
+      Example:
+
+         http-request set-src hdr(x-forwarded-for)
+         http-request set-src src,ipmask(24)
+
+      When set-src is successful, the source port is set to 0.
+
   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
index fc8647593f6570079e03efee6e0e1c9b93173e2e..9b14f268f5bbf5fc74194557881539052b658ef7 100644 (file)
@@ -262,6 +262,7 @@ enum {
        HTTP_REQ_ACT_SET_MAP,
        HTTP_REQ_ACT_CUSTOM_STOP,
        HTTP_REQ_ACT_CUSTOM_CONT,
+       HTTP_REQ_ACT_SET_SRC,
        HTTP_REQ_ACT_TRK_SC0,
        /* SC1, SC2, ... SCn */
        HTTP_REQ_ACT_TRK_SCMAX = HTTP_REQ_ACT_TRK_SC0 + MAX_SESS_STKCTR - 1,
index c24479240634b5963e0ccc9eeb902a7b308ee5a4..0ebc2c409991382b8c82f6c273169d696a7cbf59 100644 (file)
@@ -3674,6 +3674,27 @@ resume_execution:
                                                stkctr_set_flags(&s->stkctr[http_req_trk_idx(rule->action)], STKCTR_TRACK_BACKEND);
                                }
                        }
+                       break;
+
+               case HTTP_REQ_ACT_SET_SRC:
+                       if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn)) {
+                               struct sample *smp;
+
+                               smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.act.p[0], SMP_T_ADDR);
+
+                               if (smp) {
+                                       if (smp->type == SMP_T_IPV4) {
+                                               ((struct sockaddr_in *)&cli_conn->addr.from)->sin_family = AF_INET;
+                                               ((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr.s_addr = smp->data.ipv4.s_addr;
+                                               ((struct sockaddr_in *)&cli_conn->addr.from)->sin_port = 0;
+                                       } else if (smp->type == SMP_T_IPV6) {
+                                               ((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_family = AF_INET6;
+                                               memcpy(&((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_addr, &smp->data.ipv6, sizeof(struct in6_addr));
+                                               ((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_port = 0;
+                                       }
+                               }
+                       }
+                       break;
                }
        }
 
@@ -9528,6 +9549,39 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
                proxy->conf.lfs_line = proxy->conf.args.line;
 
                cur_arg += 2;
+       } else if (strncmp(args[0], "set-src", 7) == 0) {
+               struct sample_expr *expr;
+               unsigned int where;
+               char *err = NULL;
+
+               cur_arg = 1;
+               proxy->conf.args.ctx = ARGC_HRQ;
+
+               expr = sample_parse_expr((char **)args, &cur_arg, file, linenum, &err, &proxy->conf.args);
+               if (!expr) {
+                       Alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
+                             file, linenum, proxy_type_str(proxy), proxy->id, args[0], err);
+                       free(err);
+                       goto out_err;
+               }
+
+               where = 0;
+               if (proxy->cap & PR_CAP_FE)
+                       where |= SMP_VAL_FE_HRQ_HDR;
+               if (proxy->cap & PR_CAP_BE)
+                       where |= SMP_VAL_BE_HRQ_HDR;
+
+               if (!(expr->fetch->val & where)) {
+                       Alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule :"
+                             " fetch method '%s' extracts information from '%s', none of which is available here.\n",
+                             file, linenum, proxy_type_str(proxy), proxy->id, args[0],
+                             args[cur_arg-1], sample_src_names(expr->fetch->use));
+                       free(expr);
+                       goto out_err;
+               }
+
+               rule->arg.act.p[0] = expr;
+               rule->action = HTTP_REQ_ACT_SET_SRC;
        } else if (((custom = action_http_req_custom(args[0])) != NULL)) {
                char *errmsg = NULL;
                cur_arg = 1;
@@ -9539,7 +9593,7 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
                        goto out_err;
                }
        } else {
-               Alert("parsing [%s:%d]: 'http-request' expects 'allow', 'deny', 'auth', 'redirect', 'tarpit', 'add-header', 'set-header', 'replace-header', 'replace-value', 'set-nice', 'set-tos', 'set-mark', 'set-log-level', 'add-acl', 'del-acl', 'del-map', 'set-map', 'set-var', but got '%s'%s.\n",
+               Alert("parsing [%s:%d]: 'http-request' expects 'allow', 'deny', 'auth', 'redirect', 'tarpit', 'add-header', 'set-header', 'replace-header', 'replace-value', 'set-nice', 'set-tos', 'set-mark', 'set-log-level', 'add-acl', 'del-acl', 'del-map', 'set-map', 'set-var', 'set-src', but got '%s'%s.\n",
                      file, linenum, args[0], *args[0] ? "" : " (missing argument)");
                goto out_err;
        }