>Synopsis: relayd's 'listen on' support is incomplete
>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:
relayd's `listen on` syntax for relays is inconstent with httpd's.
httpd.conf(8):
> listen on address [tls] port number
> Set the listen address and port. This statement can be
specified
> multiple times.
relayd.conf(8):
> listen on address port port [tls]
> Specify the address and port for the relay to listen on.
The
> relay will accept incoming connections to the specified
address.
> If the tls keyword is present, the relay will accept
connections
> using the encrypted TLS protocol.
a. The location of the `tls` directive is different (but I've also
suggested maybe
that shouldn't even be there:
https://marc.info/?l=openbsd-bugs&m=158140394525562)
b. The address doesn't accept "*"
c. The listen can be specified multiple times but this isn't mentioned
in the manpage
nor the example.
d. Loading a tls listener fails with nonsense if it comes after any
other listener.
>How-To-Repeat:
a. Using `listen on .. tls` like httpd fails:
```
# relayd.conf
table <web> { "127.0.0.1" }
http protocol web {
# Return HTTP/HTML error pages to the client
return error
}
relay https_proxy {
listen on 0.0.0.0 tls port 443
protocol web
forward to <web> port 8080
}
```
producing:
```
$ doas pkill relayd ; doas relayd -d -v -f relayd.conf
doas ([email protected]) password:
startup
relayd.conf:11: syntax error
relayd.conf:13: protocol web defined twice
no actions, nothing to do
unused protocol: web
pfe exiting, pid 14820
ca exiting, pid 71629
hce exiting, pid 79574
ca exiting, pid 66728
ca exiting, pid 14844
relay exiting, pid 86318
relay exiting, pid 53154
relay exiting, pid 69497
```
b. This variant using `listen on *` fails:
```
# relayd.conf
table <web> { "127.0.0.1" }
http protocol web {
# Return HTTP/HTML error pages to the client
return error
}
relay https_proxy {
listen on * port 80
protocol web
forward to <web> port 8080
}
```
```
$ doas pkill relayd ; doas relayd -d -v -f relayd.conf
startup
relayd.conf:11: syntax error
relayd.conf:13: protocol web defined twice
no actions, nothing to do
unused protocol: web
hce exiting, pid 15860
ca exiting, pid 10897
ca exiting, pid 478
ca exiting, pid 84444
pfe exiting, pid 92126
relay exiting, pid 53380
relay exiting, pid 23032
relay exiting, pid 71637
```
c. Manually expanding "*" to two listen directives like httpd(8) does
works:
```
# relayd.conf
table <web> { "127.0.0.1" }
http protocol web {
# Return HTTP/HTML error pages to the client
return error
}
relay https_proxy {
listen on 0.0.0.0 port 80
listen on :: port 80
protocol web
forward to <web> port 8080
}
```
producing IPv4/IPv6 dual stack listeners:
```
$ doas pkill relayd ; doas relayd -d -v -f relayd.conf
startup
adding 1 hosts from table web:8080 (no check)
adding 1 hosts from table web:8080 (no check)
adding 1 hosts from table web:8080 (no check)
adding 1 hosts from table web:8080 (no check)
adding 1 hosts from table web:8080 (no check)
adding 1 hosts from table web:8080 (no check)
```
```
$ fstat | grep relayd | grep internet | grep stream
_relayd relayd 29109 10* internet stream tcp 0x0 *:80
_relayd relayd 29109 11* internet6 stream tcp 0x0 *:80
_relayd relayd 64089 10* internet stream tcp 0x0 *:80
_relayd relayd 64089 11* internet6 stream tcp 0x0 *:80
_relayd relayd 51163 10* internet stream tcp 0x0 *:80
_relayd relayd 51163 11* internet6 stream tcp 0x0 *:80
```
It would be extremely helpful in the future if this feature was
mentioned in the
manpage and example file.
d.
Get a cert so we can use HTTPS:
```
$ openssl req -x509 -newkey rsa:4096 -subj '/CN='"localhost" -nodes
-keyout localhost.key -out localhost.pem -days 3
$ doas cp localhost.pem /etc/ssl/localhost.crt
$ doas cp localhost.key /etc/ssl/private/localhost.key
```
This config works fine:
```
table <web> { "127.0.0.1" }
http protocol web {
# Return HTTP/HTML error pages to the client
return error
tls keypair localhost
}
relay https_proxy {
listen on 0.0.0.0 port 443 tls
#listen on :: port 443 tls
listen on 0.0.0.0 port 80
listen on :: port 80
protocol web
forward to <web> port 8080
}
```
producing working (IPv4,https), (IPv4,http), and (IPv6,http) sockets:
```
$ curl -4 --cacert /etc/ssl/localhost.crt https://localhost
<!DOCTYPE html>
<html>
<head>
<title>500 Internal Server Error</title>
<style type="text/css"><!--
body { background-color: #a00000; color: white; font-family: 'Comic
Sans MS', 'Chalkboard SE', 'Comic Neue', sans-serif; }
hr { border: 0; border-bottom: 1px dashed; }
--></style>
</head>
<body>
<h1>Internal Server Error</h1>
<div id='m'></div>
<div id='l'></div>
<hr><address>OpenBSD relayd at 0.0.0.0 port 443</address>
</body>
</html>
```
```
$ curl -4 http://localhost
<!DOCTYPE html>
<html>
<head>
<title>500 Internal Server Error</title>
<style type="text/css"><!--
body { background-color: #a00000; color: white; font-family: 'Comic
Sans MS', 'Chalkboard SE', 'Comic Neue', sans-serif; }
hr { border: 0; border-bottom: 1px dashed; }
--></style>
</head>
<body>
<h1>Internal Server Error</h1>
<div id='m'></div>
<div id='l'></div>
<hr><address>OpenBSD relayd at 0.0.0.0 port 80</address>
</body>
</html>
```
```
$ curl -6 http://localhost
<!DOCTYPE html>
<html>
<head>
<title>500 Internal Server Error</title>
<style type="text/css"><!--
body { background-color: #a00000; color: white; font-family: 'Comic
Sans MS', 'Chalkboard SE', 'Comic Neue', sans-serif; }
hr { border: 0; border-bottom: 1px dashed; }
--></style>
</head>
<body>
<h1>Internal Server Error</h1>
<div id='m'></div>
<div id='l'></div>
<hr><address>OpenBSD relayd at :: port 80</address>
</body>
</html>
```
But trying to enable the last combination fails:
```
# relayd.conf
table <web> { "127.0.0.1" }
http protocol web {
# Return HTTP/HTML error pages to the client
return error
tls keypair localhost
}
relay https_proxy {
listen on 0.0.0.0 port 443 tls
listen on :: port 443 tls
listen on 0.0.0.0 port 80
listen on :: port 80
protocol web
forward to <web> port 8080
}
```
```
$ doas pkill relayd ; doas relayd -d -v -f relayd.conf
startup
relayd.conf:18: cannot load certificates for relay https_proxy2:443
pfe exiting, pid 26880
ca exiting, pid 15627
ca exiting, pid 91004
ca exiting, pid 26754
hce exiting, pid 33589
relay exiting, pid 14187
relay exiting, pid 33426
relay exiting, pid 21591
```
This even happens with just
```
listen on :: port 443 tls
listen on 0.0.0.0 port 443 tls
```
or
```
listen on 0.0.0.0 port 443 tls
listen on :: port 443 tls
```
So it is *not* possible dual-stack a TLS relay.
>Fix:
a. is a consistency issue.
For problem b., workaround by manually expanding "*" into
`listen on 0.0.0.0` and `listen on ::`.
c. is a documentation issue.
For problem d., workaround by splitting the listeners into duplicate
relays:
```
table <web> { "127.0.0.1" }
http protocol web {
# Return HTTP/HTML error pages to the client
return error
tls keypair localhost
}
relay https_proxy {
listen on 0.0.0.0 port 443 tls
listen on 0.0.0.0 port 80
protocol web
forward to <web> port 8080
}
relay https_proxy6 {
listen on :: port 443 tls
listen on :: port 80
protocol web
forward to <web> port 8080
}
```