>Synopsis: relayd depends on the order of the 'forward' lines even when
>they should be unambiguous
>Category: system
>Environment:
System : OpenBSD 6.6
Details : OpenBSD 6.6 (GENERIC.MP) #372: Sat Oct 12 10:56:27 MDT
2019
[email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
Architecture: OpenBSD.amd64
Machine : amd64
>Description:
Most options in relayd.conf are order insensitive (except for filter
rules). But
when using `forward to <table>`, the order matters, even when there's
only a single
possible forward for each table.
(
originally reported at
*
https://www.reddit.com/r/openbsd/comments/eh6ll8/relayd_as_a_reverse_proxy_help_due_to_uncertainty/
*
https://www.reddit.com/r/openbsd/comments/3qb2c4/some_observations_about_relayd/
)
>How-To-Repeat:
Set up two backend http servers:
```
$ mkdir relayd-order-sensitive; cd relayd-order-sensitive
$ mkdir -p site app
$ mkdir -p logs # httpd insists on this
$ echo "Static Site" > site/index.html
$ echo "WebApp" > app/index.html
$
$ cat > httpd.conf <<EOF
chroot "."
server "site" {
listen on localhost port 8080
root "site"
directory auto index
}
server "app" {
listen on localhost port 8082
root "app"
request strip 1
directory auto index
}
EOF
$ doas httpd -f httpd.conf
$
$ # test:
$ curl http://localhost:8080/
Static Site
$ curl http://localhost:8082/app/
WebApp
```
Now, with this relayd.conf:
```
table <web> { "127.0.0.1" }
table <app> { "127.0.0.1" }
http protocol web {
match request path "/app/*" forward to <app>
}
relay P {
listen on 0.0.0.0 port 80
protocol web
forward to <web> port 8080
forward to <app> port 8082
}
```
The two backends successfully run on the same web origin:
```
$ curl http://localhost/
Static Site
$ curl http://localhost/app/
WebApp
```
And the httpd logs say / routed to "site" (i.e. :8080) and /app routed
to "app" (:8082).
```
$ tail -n 2 logs/access.log
site 127.0.0.1 - - [11/Feb/2020:02:16:22 -0500] "GET / HTTP/1.1" 200 12
app 127.0.0.1 - - [11/Feb/2020:02:16:24 -0500] "GET /app/ HTTP/1.1" 200
7
```
But switch around those forward lines:
```
table <web> { "127.0.0.1" }
table <app> { "127.0.0.1" }
http protocol web {
match request path "/app/*" forward to <app>
}
relay P {
listen on 0.0.0.0 port 80
protocol web
forward to <app> port 8082
forward to <web> port 8080
}
```
/app still works
```
$ curl http://localhost/app/
WebApp
```
but / fails
```
$ curl -v http://localhost/
* Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.66.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
* HTTP 1.0, assume close after body
< HTTP/1.0 301 Moved Permanently
< Connection: close
< Content-Length: 443
< Content-Type: text/html
< Date: Tue, 11 Feb 2020 07:18:27 GMT
< Location: http://localhost//
< Server: OpenBSD httpd
<
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>301 Moved Permanently</title>
<style type="text/css"><!--
body { background-color: white; color: black; font-family: 'Comic Sans
MS', 'Chalkboard SE', 'Comic Neue', sans-serif; }
hr { border: 0; border-bottom: 1px dashed; }
--></style>
</head>
<body>
<h1>301 Moved Permanently</h1>
<hr>
<address>OpenBSD httpd</address>
</body>
</html>
* Closing connection 0
```
looking in logs/access.log we see why: both are now routing to :8082.
```
$ tail -n 2 logs/access.log
app 127.0.0.1 - - [11/Feb/2020:02:18:01 -0500] "GET /app/ HTTP/1.1" 200
7
app 127.0.0.1 - - [11/Feb/2020:02:18:27 -0500] "GET / HTTP/1.1" 301 0
```
I can't understand why though. It seems like the rules are unambiguous.