]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: proxy: move 'originalto' option to http_ext
authorAurelien DARRAGON <adarragon@haproxy.com>
Thu, 29 Dec 2022 14:45:41 +0000 (15:45 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 27 Jan 2023 14:18:59 +0000 (15:18 +0100)
Just like forwarded (7239) header and forwardfor header, move parsing,
logic and management of 'originalto' option into http_ext dedicated class.

We're only doing this to standardize proxy http options management.
Existing behavior remains untouched.

include/haproxy/http_ext-t.h
include/haproxy/http_ext.h
include/haproxy/proxy-t.h
src/cfgparse-listen.c
src/cfgparse.c
src/http_ana.c
src/http_ext.c
src/proxy.c

index 65a105c21863169098ef5eba574d8b82bf8eb993..22f5633ec3ed5f9eea638f176ae9d91dc9a8fafe 100644 (file)
@@ -120,4 +120,9 @@ struct http_ext_xff {
        uint8_t         mode;
 };
 
+struct http_ext_xot {
+       struct ist      hdr_name;   /* header to use - default: "x-original-to" */
+       struct net_addr except_net; /* don't forward x-original-to for this address. */
+};
+
 #endif /* !_HAPROXY_HTTPEXT_T_H */
index 7f12830ba1b8dd05384309be18e1ce2effc82d8a..63ecafb2b7d21390d5c7bf5367ae5bc4a5b60774 100644 (file)
@@ -31,15 +31,19 @@ int http_validate_7239_header(struct ist hdr, int required_steps, struct forward
 
 int http_handle_7239_header(struct stream *s, struct channel *req);
 int http_handle_xff_header(struct stream *s, struct channel *req);
+int http_handle_xot_header(struct stream *s, struct channel *req);
 
 void http_ext_7239_clean(struct http_ext_7239 *);
 void http_ext_xff_clean(struct http_ext_xff *);
+void http_ext_xot_clean(struct http_ext_xot *);
 
 void http_ext_7239_copy(struct http_ext_7239 *dest, const struct http_ext_7239 *orig);
 void http_ext_xff_copy(struct http_ext_xff *dest, const struct http_ext_xff *orig);
+void http_ext_xot_copy(struct http_ext_xot *dest, const struct http_ext_xot *orig);
 
 int proxy_http_parse_7239(char **args, int cur_arg, struct proxy *curproxy, const struct proxy *defpx, const char *file, int linenum);
 int proxy_http_compile_7239(struct proxy *curproxy);
 int proxy_http_parse_xff(char **args, int cur_arg, struct proxy *curproxy, const struct proxy *defpx, const char *file, int linenum);
+int proxy_http_parse_xot(char **args, int cur_arg, struct proxy *curproxy, const struct proxy *defpx, const char *file, int linenum);
 
 #endif /* !_HAPROXY_HTTPEXT_H */
index 0f682ef45fcf5b833e759ef3768ef36ae8916c72..8391f9fbc39223c9d36963a034f3dce13fbf99e1 100644 (file)
@@ -115,7 +115,7 @@ enum PR_SRV_STATE_FILE {
 #define PR_O_CONTSTATS 0x10000000      /* continuous counters */
 /* unused: 0x20000000 */
 #define PR_O_DISABLE404 0x40000000      /* Disable a server on a 404 response to a health-check */
-#define PR_O_ORGTO      0x80000000      /* insert x-original-to with destination address */
+#define PR_O_HTTP_XOT   0x80000000      /* insert x-original-to with destination address */
 
 /* bits for proxy->options2 */
 #define PR_O2_SPLIC_REQ        0x00000001      /* transfer requests using linux kernel's splice() */
@@ -273,6 +273,8 @@ struct proxy_http {
        struct http_ext_7239       fwd;
        /* x-forward-for */
        struct http_ext_xff        xff;
+       /* x-original-to */
+       struct http_ext_xot        xot;
 };
 
 struct proxy {
@@ -366,8 +368,6 @@ struct proxy {
        unsigned int fe_sps_lim;                /* limit on new sessions per second on the frontend */
        unsigned int fullconn;                  /* #conns on backend above which servers are used at full load */
        unsigned int tot_fe_maxconn;            /* #maxconn of frontends linked to that backend, it is used to compute fullconn */
-       struct net_addr except_xot_net;         /* don't x-original-to for this address. */
-       struct ist orgto_hdr_name;                      /* header to use - default: "x-original-to" */
        struct ist server_id_hdr_name;                   /* the header to use to send the server id (name) */
        int conn_retries;                       /* maximum number of connect retries */
        unsigned int retry_type;                /* Type of retry allowed */
index 112fac3254be897bd42671395fa4e120cf9c6ae6..20965c877408d4938dca85b9334990c1d8653766 100644 (file)
@@ -2278,68 +2278,9 @@ stats_error_parsing:
                                goto out;
                }
                else if (strcmp(args[1], "originalto") == 0) {
-                       int cur_arg;
-
-                       /* insert x-original-to field, but not for the IP address listed as an except.
-                        * set default options (ie: bitfield, header name, etc)
-                        */
-
-                       curproxy->options |= PR_O_ORGTO;
-
-                       istfree(&curproxy->orgto_hdr_name);
-                       curproxy->orgto_hdr_name = istdup(ist(DEF_XORIGINALTO_HDR));
-                       if (!isttest(curproxy->orgto_hdr_name))
-                               goto alloc_error;
-                       curproxy->except_xot_net.family = AF_UNSPEC;
-
-                       /* loop to go through arguments - start at 2, since 0+1 = "option" "originalto" */
-                       cur_arg = 2;
-                       while (*(args[cur_arg])) {
-                               if (strcmp(args[cur_arg], "except") == 0) {
-                                       unsigned char mask;
-                                       int i;
-
-                                       /* suboption except - needs additional argument for it */
-                                       if (*(args[cur_arg+1]) &&
-                                           str2net(args[cur_arg+1], 1, &curproxy->except_xot_net.addr.v4.ip, &curproxy->except_xot_net.addr.v4.mask)) {
-                                               curproxy->except_xot_net.family = AF_INET;
-                                               curproxy->except_xot_net.addr.v4.ip.s_addr &= curproxy->except_xot_net.addr.v4.mask.s_addr;
-                                       }
-                                       else if (*(args[cur_arg+1]) &&
-                                                str62net(args[cur_arg+1], &curproxy->except_xot_net.addr.v6.ip, &mask)) {
-                                               curproxy->except_xot_net.family = AF_INET6;
-                                               len2mask6(mask, &curproxy->except_xot_net.addr.v6.mask);
-                                               for (i = 0; i < 16; i++)
-                                                       curproxy->except_xot_net.addr.v6.ip.s6_addr[i] &= curproxy->except_xot_net.addr.v6.mask.s6_addr[i];
-                                       }
-                                       else {
-                                               ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
-                                                        file, linenum, args[0], args[1], args[cur_arg]);
-                                               err_code |= ERR_ALERT | ERR_FATAL;
-                                               goto out;
-                                       }
-                                       cur_arg += 2;
-                               } else if (strcmp(args[cur_arg], "header") == 0) {
-                                       /* suboption header - needs additional argument for it */
-                                       if (*(args[cur_arg+1]) == 0) {
-                                               ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
-                                                        file, linenum, args[0], args[1], args[cur_arg]);
-                                               err_code |= ERR_ALERT | ERR_FATAL;
-                                               goto out;
-                                       }
-                                       istfree(&curproxy->orgto_hdr_name);
-                                       curproxy->orgto_hdr_name = istdup(ist(args[cur_arg+1]));
-                                       if (!isttest(curproxy->orgto_hdr_name))
-                                               goto alloc_error;
-                                       cur_arg += 2;
-                               } else {
-                                       /* unknown suboption - catchall */
-                                       ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except' and 'header'.\n",
-                                                file, linenum, args[0], args[1]);
-                                       err_code |= ERR_ALERT | ERR_FATAL;
-                                       goto out;
-                               }
-                       } /* end while loop */
+                       err_code |= proxy_http_parse_xot(args, 0, curproxy, curr_defproxy, file, linenum);
+                       if (err_code & ERR_FATAL)
+                               goto out;
                }
                else if (strcmp(args[1], "http-restrict-req-hdr-names") == 0) {
                        if (alertif_too_many_args(2, file, linenum, args, &err_code))
index 358a587528ca35b8ef1e1cc5f9f25631b1b6971a..ecb75a73aff20306322d849021ede23191da6ebd 100644 (file)
@@ -3982,11 +3982,11 @@ out_uri_auth_compat:
                                curproxy->options &= ~PR_O_HTTP_XFF;
                        }
 
-                       if (curproxy->options & PR_O_ORGTO) {
+                       if (curproxy->options & PR_O_HTTP_XOT) {
                                ha_warning("'option %s' ignored for %s '%s' as it requires HTTP mode.\n",
                                           "originalto", proxy_type_str(curproxy), curproxy->id);
                                err_code |= ERR_WARN;
-                               curproxy->options &= ~PR_O_ORGTO;
+                               curproxy->options &= ~PR_O_HTTP_XOT;
                        }
 
                        for (optnum = 0; cfg_opts[optnum].name; optnum++) {
index 36014718ab26fdc69fd802017cfc515ed6edd052..fe5044e068f2d0dbec79550e5bffacb6f87d1114 100644 (file)
@@ -678,53 +678,12 @@ int http_process_request(struct stream *s, struct channel *req, int an_bit)
        }
 
        /*
-        * 10: add X-Original-To if either the frontend or the backend
+        * add X-Original-To if either the frontend or the backend
         * asks for it.
         */
-       if ((sess->fe->options | s->be->options) & PR_O_ORGTO) {
-               const struct sockaddr_storage *dst = sc_dst(s->scf);
-               struct ist hdr = isttest(s->be->orgto_hdr_name) ? s->be->orgto_hdr_name : sess->fe->orgto_hdr_name;
-
-               if (dst && dst->ss_family == AF_INET) {
-                       /* Add an X-Original-To header unless the destination IP is
-                        * in the 'except' network range.
-                        */
-                       if (ipcmp2net(dst, &sess->fe->except_xot_net) &&
-                           ipcmp2net(dst, &s->be->except_xot_net)) {
-                               unsigned char *pn = (unsigned char *)&((struct sockaddr_in *)dst)->sin_addr;
-
-                               /* Note: we rely on the backend to get the header name to be used for
-                                * x-original-to, because the header is really meant for the backends.
-                                * However, if the backend did not specify any option, we have to rely
-                                * on the frontend's header name.
-                                */
-                               chunk_printf(&trash, "%d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
-                               if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
-                                       goto return_fail_rewrite;
-                       }
-               }
-               else if (dst && dst->ss_family == AF_INET6) {
-                       /* Add an X-Original-To header unless the source IP is
-                        * in the 'except' network range.
-                        */
-                       if (ipcmp2net(dst, &sess->fe->except_xot_net) &&
-                           ipcmp2net(dst, &s->be->except_xot_net)) {
-                               char pn[INET6_ADDRSTRLEN];
-
-                               inet_ntop(AF_INET6,
-                                         (const void *)&((struct sockaddr_in6 *)dst)->sin6_addr,
-                                         pn, sizeof(pn));
-
-                               /* Note: we rely on the backend to get the header name to be used for
-                                * x-forwarded-for, because the header is really meant for the backends.
-                                * However, if the backend did not specify any option, we have to rely
-                                * on the frontend's header name.
-                                */
-                               chunk_printf(&trash, "%s", pn);
-                               if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
-                                       goto return_fail_rewrite;
-                       }
-               }
+       if ((sess->fe->options | s->be->options) & PR_O_HTTP_XOT) {
+               if (unlikely(!http_handle_xot_header(s, req)))
+                       goto return_fail_rewrite;
        }
 
        /* Filter the request headers if there are filters attached to the
index e5c39c2b0ae375c389d18415056c1dd0672fc27d..6a922e6f572effcd25fd08fb8ee0aca472f49630 100644 (file)
@@ -828,6 +828,67 @@ int http_handle_xff_header(struct stream *s, struct channel *req)
        return 1;
 }
 
+/* This function will try to inject x-original-to header if
+ * configured on the frontend or the backend (or both)
+ * Returns 1 for success and 0 for failure
+ */
+int http_handle_xot_header(struct stream *s, struct channel *req)
+{
+       struct session *sess = s->sess;
+       struct htx *htx = htxbuf(&req->buf);
+       const struct sockaddr_storage *dst = sc_dst(s->scf);
+       struct http_ext_xot *f_xot = ((sess->fe->options & PR_O_HTTP_XOT) ? &sess->fe->http.xot : NULL);
+       struct http_ext_xot *b_xot = ((s->be->options & PR_O_HTTP_XOT) ? &s->be->http.xot : NULL);
+       struct ist hdr;
+
+       /* xot is expected to be enabled on be, or fe, or both */
+       BUG_ON(!f_xot && !b_xot);
+
+       hdr = ((b_xot) ? b_xot->hdr_name : f_xot->hdr_name);
+
+       if (dst && dst->ss_family == AF_INET) {
+               /* Add an X-Original-To header unless the destination IP is
+                * in the 'except' network range.
+                */
+               if ((!f_xot || ipcmp2net(dst, &f_xot->except_net)) &&
+                   (!b_xot || ipcmp2net(dst, &b_xot->except_net))) {
+                       unsigned char *pn = (unsigned char *)&((struct sockaddr_in *)dst)->sin_addr;
+
+                       /* Note: we rely on the backend to get the header name to be used for
+                        * x-original-to, because the header is really meant for the backends.
+                        * However, if the backend did not specify any option, we have to rely
+                        * on the frontend's header name.
+                        */
+                       chunk_printf(&trash, "%d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
+                       if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
+                               return 0;
+               }
+       }
+       else if (dst && dst->ss_family == AF_INET6) {
+               /* Add an X-Original-To header unless the source IP is
+                * in the 'except' network range.
+                */
+               if ((!f_xot || ipcmp2net(dst, &f_xot->except_net)) &&
+                   (!b_xot || ipcmp2net(dst, &b_xot->except_net))) {
+                       char pn[INET6_ADDRSTRLEN];
+
+                       inet_ntop(AF_INET6,
+                                 (const void *)&((struct sockaddr_in6 *)dst)->sin6_addr,
+                                 pn, sizeof(pn));
+
+                       /* Note: we rely on the backend to get the header name to be used for
+                        * x-forwarded-for, because the header is really meant for the backends.
+                        * However, if the backend did not specify any option, we have to rely
+                        * on the frontend's header name.
+                        */
+                       chunk_printf(&trash, "%s", pn);
+                       if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
+                               return 0;
+               }
+       }
+       return 1;
+}
+
 /*
  * =========== CONFIG ===========
  * below are helpers to parse http ext options from the config
@@ -1150,6 +1211,78 @@ int proxy_http_parse_xff(char **args, int cur_arg,
        return err_code;
 }
 
+/* x-original-to */
+int proxy_http_parse_xot(char **args, int cur_arg,
+                         struct proxy *curproxy, const struct proxy *defpx,
+                         const char *file, int linenum)
+{
+       int err_code = 0;
+
+       /* insert x-original-to field, but not for the IP address listed as an except.
+        * set default options (ie: bitfield, header name, etc)
+        */
+
+       curproxy->options |= PR_O_HTTP_XOT;
+
+       istfree(&curproxy->http.xot.hdr_name);
+       curproxy->http.xot.hdr_name = istdup(ist(DEF_XORIGINALTO_HDR));
+       if (!isttest(curproxy->http.xot.hdr_name))
+               return proxy_http_parse_oom(file, linenum);
+       curproxy->http.xot.except_net.family = AF_UNSPEC;
+
+       /* loop to go through arguments - start at 2, since 0+1 = "option" "originalto" */
+       cur_arg = 2;
+       while (*(args[cur_arg])) {
+               if (strcmp(args[cur_arg], "except") == 0) {
+                       unsigned char mask;
+                       int i;
+
+                       /* suboption except - needs additional argument for it */
+                       if (*(args[cur_arg+1]) &&
+                           str2net(args[cur_arg+1], 1, &curproxy->http.xot.except_net.addr.v4.ip, &curproxy->http.xot.except_net.addr.v4.mask)) {
+                               curproxy->http.xot.except_net.family = AF_INET;
+                               curproxy->http.xot.except_net.addr.v4.ip.s_addr &= curproxy->http.xot.except_net.addr.v4.mask.s_addr;
+                       }
+                       else if (*(args[cur_arg+1]) &&
+                                str62net(args[cur_arg+1], &curproxy->http.xot.except_net.addr.v6.ip, &mask)) {
+                               curproxy->http.xot.except_net.family = AF_INET6;
+                               len2mask6(mask, &curproxy->http.xot.except_net.addr.v6.mask);
+                               for (i = 0; i < 16; i++)
+                                       curproxy->http.xot.except_net.addr.v6.ip.s6_addr[i] &= curproxy->http.xot.except_net.addr.v6.mask.s6_addr[i];
+                       }
+                       else {
+                               ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
+                                        file, linenum, args[0], args[1], args[cur_arg]);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
+                       }
+                       cur_arg += 2;
+               } else if (strcmp(args[cur_arg], "header") == 0) {
+                       /* suboption header - needs additional argument for it */
+                       if (*(args[cur_arg+1]) == 0) {
+                               ha_alert("parsing [%s:%d] : '%s %s %s' expects <header_name> as argument.\n",
+                                        file, linenum, args[0], args[1], args[cur_arg]);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
+                       }
+                       istfree(&curproxy->http.xot.hdr_name);
+                       curproxy->http.xot.hdr_name = istdup(ist(args[cur_arg+1]));
+                       if (!isttest(curproxy->http.xot.hdr_name))
+                               return proxy_http_parse_oom(file, linenum);
+                       cur_arg += 2;
+               } else {
+                       /* unknown suboption - catchall */
+                       ha_alert("parsing [%s:%d] : '%s %s' only supports optional values: 'except' and 'header'.\n",
+                                file, linenum, args[0], args[1]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+       } /* end while loop */
+
+ out:
+       return err_code;
+}
+
 /*
  * =========== MGMT ===========
  * below are helpers to manage http ext options
@@ -1181,6 +1314,11 @@ void http_ext_xff_clean(struct http_ext_xff *clean)
        istfree(&clean->hdr_name);
 }
 
+void http_ext_xot_clean(struct http_ext_xot *clean)
+{
+       istfree(&clean->hdr_name);
+}
+
 void http_ext_7239_copy(struct http_ext_7239 *dest, const struct http_ext_7239 *orig)
 {
        if (orig->c_file)
@@ -1217,3 +1355,10 @@ void http_ext_xff_copy(struct http_ext_xff *dest, const struct http_ext_xff *ori
        dest->mode = orig->mode;
        dest->except_net = orig->except_net;
 }
+
+void http_ext_xot_copy(struct http_ext_xot *dest, const struct http_ext_xot *orig)
+{
+       if (isttest(orig->hdr_name))
+               dest->hdr_name = istdup(orig->hdr_name);
+       dest->except_net = orig->except_net;
+}
index 802d3c790d7b024bd064e6fbccb3693410fa0a72..efb8ddbe1bf2d187c7de452aedad8ac416ecde33 100644 (file)
@@ -352,9 +352,9 @@ void free_proxy(struct proxy *p)
                pxdf->fct(p);
 
        free(p->desc);
-       istfree(&p->orgto_hdr_name);
        http_ext_7239_clean(&p->http.fwd);
        http_ext_xff_clean(&p->http.xff);
+       http_ext_xot_clean(&p->http.xot);
 
        task_destroy(p->task);
 
@@ -1465,11 +1465,11 @@ void proxy_free_defaults(struct proxy *defproxy)
        istfree(&defproxy->monitor_uri);
        ha_free(&defproxy->defbe.name);
        ha_free(&defproxy->conn_src.iface_name);
-       istfree(&defproxy->orgto_hdr_name);
        istfree(&defproxy->server_id_hdr_name);
 
        http_ext_7239_clean(&defproxy->http.fwd);
        http_ext_xff_clean(&defproxy->http.xff);
+       http_ext_xot_clean(&defproxy->http.xot);
 
        list_for_each_entry_safe(acl, aclb, &defproxy->acl, list) {
                LIST_DELETE(&acl->list);
@@ -1646,16 +1646,14 @@ static int proxy_defproxy_cpy(struct proxy *curproxy, const struct proxy *defpro
        curproxy->options2 = defproxy->options2;
        curproxy->no_options = defproxy->no_options;
        curproxy->no_options2 = defproxy->no_options2;
-       curproxy->except_xot_net = defproxy->except_xot_net;
        curproxy->retry_type = defproxy->retry_type;
        curproxy->tcp_req.inspect_delay = defproxy->tcp_req.inspect_delay;
        curproxy->tcp_rep.inspect_delay = defproxy->tcp_rep.inspect_delay;
 
        if (defproxy->options & PR_O_HTTP_XFF)
                http_ext_xff_copy(&curproxy->http.xff, &defproxy->http.xff);
-
-       if (isttest(defproxy->orgto_hdr_name))
-               curproxy->orgto_hdr_name = istdup(defproxy->orgto_hdr_name);
+       if (defproxy->options & PR_O_HTTP_XOT)
+               http_ext_xot_copy(&curproxy->http.xot, &defproxy->http.xot);
 
        if (isttest(defproxy->server_id_hdr_name))
                curproxy->server_id_hdr_name = istdup(defproxy->server_id_hdr_name);