On Thu, Jan 07, 2021 at 04:56:14PM +0100, Denis Fondras wrote:
> Le Thu, Jan 07, 2021 at 12:03:54PM +0100, Hiltjo Posthuma a écrit :
> > Hi Denis,
> >
> > I like this feature. For example it would be useful for using relayd as a
> > reverse-proxy to forward it to an internal network running a httpd with some
> > service. Then the path can be stripped without having to touch this service
> > configuration.
> >
> > Like: https://example.com/myservice/ -> http://192.168.0.2/ .
> >
> > I've noticed a small thing while testing the patch. When the path is "/" and
> > "strip 1" is used it becomes "", the request becomes: "GET HTTP/1.0". Maybe
> > this should be instead: "/". The same thing happens with a "strip number"
> > higher than the amount of sub paths.
> >
> > It could be worked-around by prefiltering with a match rule, but maybe it is
> > more obvious to make the root "/" ? The way the function
> > server_root_strip() is
> > used by OpenBSD httpd is that it first does a filesystem path check/open(2).
> >
> >
>
Hi Denis,
Awesome, tested the patch below and it looks good to me!
> Thank you for testing.
>
> Here is an update:
>
> Index: parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/relayd/parse.y,v
> retrieving revision 1.250
> diff -u -p -r1.250 parse.y
> --- parse.y 29 Dec 2020 19:48:06 -0000 1.250
> +++ parse.y 7 Jan 2021 15:08:28 -0000
> @@ -175,7 +175,7 @@ typedef struct {
> %token LOOKUP METHOD MODE NAT NO DESTINATION NODELAY NOTHING ON PARENT
> PATH
> %token PFTAG PORT PREFORK PRIORITY PROTO QUERYSTR REAL REDIRECT RELAY
> REMOVE
> %token REQUEST RESPONSE RETRY QUICK RETURN ROUNDROBIN ROUTE SACK
> SCRIPT SEND
> -%token SESSION SOCKET SPLICE SSL STICKYADDR STYLE TABLE TAG TAGGED TCP
> +%token SESSION SOCKET SPLICE SSL STICKYADDR STRIP STYLE TABLE TAG
> TAGGED TCP
> %token TIMEOUT TLS TO ROUTER RTLABEL TRANSPARENT URL WITH TTL RTABLE
> %token MATCH PARAMS RANDOM LEASTSTATES SRCHASH KEY CERTIFICATE
> PASSWORD ECDHE
> %token EDH TICKETS CONNECTION CONNECTIONS CONTEXT ERRORS STATE CHANGES
> CHECKS
> @@ -1549,6 +1549,20 @@ ruleopts : METHOD STRING
> {
> rule->rule_kv[keytype].kv_option = $2;
> rule->rule_kv[keytype].kv_type = keytype;
> }
> + | PATH STRIP NUMBER {
> + char *strip = NULL;
> +
> + if ($3 < 0 || $3 > INT_MAX) {
> + yyerror("invalid strip number");
> + YYERROR;
> + }
> + if (asprintf(&strip, "%lld", $3) <= 0)
> + fatal("can't parse strip");
> + keytype = KEY_TYPE_PATH;
> + rule->rule_kv[keytype].kv_option = KEY_OPTION_STRIP;
> + rule->rule_kv[keytype].kv_value = strip;
> + rule->rule_kv[keytype].kv_type = keytype;
> + }
> | QUERYSTR key_option STRING value {
> switch ($2) {
> case KEY_OPTION_APPEND:
> @@ -2481,6 +2495,7 @@ lookup(char *s)
> { "ssl", SSL },
> { "state", STATE },
> { "sticky-address", STICKYADDR },
> + { "strip", STRIP },
> { "style", STYLE },
> { "table", TABLE },
> { "tag", TAG },
> Index: relay.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/relayd/relay.c,v
> retrieving revision 1.251
> diff -u -p -r1.251 relay.c
> --- relay.c 14 May 2020 17:27:38 -0000 1.251
> +++ relay.c 7 Jan 2021 15:08:28 -0000
> @@ -214,6 +214,9 @@ relay_ruledebug(struct relay_rule *rule)
> case KEY_OPTION_LOG:
> fprintf(stderr, "log ");
> break;
> + case KEY_OPTION_STRIP:
> + fprintf(stderr, "strip ");
> + break;
> case KEY_OPTION_NONE:
> break;
> }
> @@ -227,13 +230,15 @@ relay_ruledebug(struct relay_rule *rule)
> break;
> }
>
> + int kvv = (kv->kv_option == KEY_OPTION_STRIP ||
> + kv->kv_value == NULL);
> fprintf(stderr, "%s%s%s%s%s%s ",
> kv->kv_key == NULL ? "" : "\"",
> kv->kv_key == NULL ? "" : kv->kv_key,
> kv->kv_key == NULL ? "" : "\"",
> - kv->kv_value == NULL ? "" : " value \"",
> + kvv ? "" : " value \"",
> kv->kv_value == NULL ? "" : kv->kv_value,
> - kv->kv_value == NULL ? "" : "\"");
> + kvv ? "" : "\"");
> }
>
> if (rule->rule_tablename[0])
> Index: relay_http.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/relayd/relay_http.c,v
> retrieving revision 1.79
> diff -u -p -r1.79 relay_http.c
> --- relay_http.c 4 Sep 2020 13:09:14 -0000 1.79
> +++ relay_http.c 7 Jan 2021 15:08:28 -0000
> @@ -77,6 +77,7 @@ int relay_match_actions(struct ctl_rel
> struct relay_rule *, struct kvlist *, struct kvlist *,
> struct relay_table **);
> void relay_httpdesc_free(struct http_descriptor *);
> +char * server_root_strip(char *, int);
>
> static struct relayd *env = NULL;
>
> @@ -1421,14 +1422,16 @@ relay_httppath_test(struct ctl_relay_eve
>
> if (cre->dir == RELAY_DIR_RESPONSE || kv->kv_type != KEY_TYPE_PATH)
> return (0);
> - else if (kv->kv_key == NULL)
> - return (0);
> - else if (fnmatch(kv->kv_key, desc->http_path, 0) == FNM_NOMATCH)
> - return (-1);
> - else if (kv->kv_value != NULL && kv->kv_option == KEY_OPTION_NONE) {
> - query = desc->http_query == NULL ? "" : desc->http_query;
> - if (fnmatch(kv->kv_value, query, FNM_CASEFOLD) == FNM_NOMATCH)
> + else if (kv->kv_option != KEY_OPTION_STRIP) {
> + if (kv->kv_key == NULL)
> + return (0);
> + else if (fnmatch(kv->kv_key, desc->http_path, 0) == FNM_NOMATCH)
> return (-1);
> + else if (kv->kv_value != NULL && kv->kv_option ==
> KEY_OPTION_NONE) {
> + query = desc->http_query == NULL ? "" :
> desc->http_query;
> + if (fnmatch(kv->kv_value, query, FNM_CASEFOLD) ==
> FNM_NOMATCH)
> + return (-1);
> + }
> }
>
> relay_match(actions, kv, match, NULL);
> @@ -1554,7 +1557,7 @@ relay_apply_actions(struct ctl_relay_eve
> struct kv *host = NULL;
> const char *value;
> struct kv *kv, *match, *kp, *mp, kvcopy, matchcopy, key;
> - int addkv, ret;
> + int addkv, ret, nstrip;
> char buf[IBUF_READ_SIZE], *ptr;
> char *msg = NULL;
> const char *meth = NULL;
> @@ -1655,6 +1658,15 @@ relay_apply_actions(struct ctl_relay_eve
> case KEY_OPTION_LOG:
> /* perform this later */
> break;
> + case KEY_OPTION_STRIP:
> + nstrip = strtonum(kv->kv_value, 0, INT_MAX, NULL);
> + if (kv->kv_type == KEY_TYPE_PATH) {
> + if (kv_setkey(match,
> + server_root_strip(match->kv_key,
> + nstrip)) == -1)
> + goto fail;
> + }
> + break;
> default:
> fatalx("%s: invalid action", __func__);
> /* NOTREACHED */
> @@ -1932,3 +1944,19 @@ relay_match(struct kvlist *actions, stru
> TAILQ_INSERT_TAIL(actions, kv, kv_match_entry);
> }
> }
> +
> +char *
> +server_root_strip(char *path, int n)
> +{
> + char *p;
> +
> + /* Strip strip leading directories. Leading '/' is ignored. */
> + for (; n > 0 && *path != '\0'; n--)
> + if ((p = strchr(++path, '/')) != NULL)
> + path = p;
> + else
> + path--;
> +
> + return (path);
> +}
> +
> Index: relayd.conf.5
> ===================================================================
> RCS file: /cvs/src/usr.sbin/relayd/relayd.conf.5,v
> retrieving revision 1.202
> diff -u -p -r1.202 relayd.conf.5
> --- relayd.conf.5 30 Oct 2020 09:47:35 -0000 1.202
> +++ relayd.conf.5 7 Jan 2021 15:08:28 -0000
> @@ -1289,6 +1289,15 @@ for example:
> block path "/index.html"
> block path "/cgi-bin/t.cgi" value "foo=bar*"
> .Ed
> +.It Ic path strip Ar number
> +Strip
> +.Ar number
> +path components from the beginning of the path of the requested URL
> +when using the
> +.Ic http
> +protocol.
> +This type is only available with the direction
> +.Ic request .
> .It Ic query Ar option Oo Ar key Oo Ic value Ar value Oc Oc
> Look up the entity as a query variable in the URL when using the
> .Ic http
> Index: relayd.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v
> retrieving revision 1.262
> diff -u -p -r1.262 relayd.h
> --- relayd.h 14 Sep 2020 11:30:25 -0000 1.262
> +++ relayd.h 7 Jan 2021 15:08:28 -0000
> @@ -292,7 +292,8 @@ enum key_option {
> KEY_OPTION_SET,
> KEY_OPTION_REMOVE,
> KEY_OPTION_HASH,
> - KEY_OPTION_LOG
> + KEY_OPTION_LOG,
> + KEY_OPTION_STRIP
> };
>
> enum key_type {
>
--
Kind regards,
Hiltjo