On Sat, Oct 24, 2020 at 05:04:20PM +0200, Denis Fondras wrote:
> The 'strip' directive from httpd(8) is useful when forwarding to another
> server.
>
> This diff adds the feature to relayd(8).
>
> With :
> ----
> match request path "/server/*" tag psonoserver
> match request tagged psonoserver path strip 1
> match request tagged psonoserver forward to <psono_server>
> ----
>
> https://psono.pw/server/info/ is forwarded as <psono_server>/info
>
> Comments ? OK ?
>
Hi Dennis,
Thanks for working on this. I haven't tested the patch yet except compiling,
but this feature would be very nice to have imho.
I find the current "path replace" syntax confusing and it doesn't work for this
use-case.
Some comments below:
> Index: parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/relayd/parse.y,v
> retrieving revision 1.246
> diff -u -p -r1.246 parse.y
> --- parse.y 14 Sep 2020 11:30:25 -0000 1.246
> +++ parse.y 24 Oct 2020 14:52:36 -0000
> @@ -175,8 +175,8 @@ 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 SNMP SOCKET SPLICE SSL STICKYADDR STYLE TABLE TAG
> TAGGED TCP
> -%token TIMEOUT TLS TO ROUTER RTLABEL TRANSPARENT TRAP URL WITH TTL
> RTABLE
> +%token SESSION SNMP SOCKET SPLICE SSL STICKYADDR STRIP STYLE TABLE TAG
> TAGGED
> +%token TCP TIMEOUT TLS TO ROUTER RTLABEL TRANSPARENT TRAP URL WITH TTL
> RTABLE
> %token MATCH PARAMS RANDOM LEASTSTATES SRCHASH KEY CERTIFICATE
> PASSWORD ECDHE
> %token EDH TICKETS CONNECTION CONNECTIONS CONTEXT ERRORS STATE CHANGES
> CHECKS
> %token WEBSOCKETS
> @@ -1569,6 +1569,23 @@ 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 ((strip = calloc(11, sizeof(char))) == NULL) {
> + yyerror("calloc() failed");
> + YYERROR;
> + }
I think this could be a fatal("calloc"); call, like similar sections in this
file, because it is not a syntax error (YYERROR;).
> + sprintf(strip, "%lld", $3);
The calloc and sprintf could probably be rewritten to a single asprintf() call.
> + 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:
> @@ -2506,6 +2523,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 24 Oct 2020 14:52:36 -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 24 Oct 2020 14:52:36 -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 = strchr(path, '\0');
> + else
> + path = p;
> +
> + return (path);
> +}
> +
> Index: relayd.conf.5
> ===================================================================
> RCS file: /cvs/src/usr.sbin/relayd/relayd.conf.5,v
> retrieving revision 1.201
> diff -u -p -r1.201 relayd.conf.5
> --- relayd.conf.5 22 Oct 2020 08:00:24 -0000 1.201
> +++ relayd.conf.5 24 Oct 2020 14:52:36 -0000
> @@ -1287,6 +1287,16 @@ 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 .
> +.Ed
> .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 24 Oct 2020 14:52:36 -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 {
>
There are some trailing white-spaces also (grep " $").
(There are also some trailing TAB whitespace from the recent agentx merge by
the way.)
--
Kind regards,
Hiltjo