Title: Add a TLS layer to your Gopher server | |
Author: Solène | |
Date: 07 March 2019 | |
Tags: gopher openbsd | |
Description: | |
Hi, | |
In this article I will explain how to setup a gopher server supporting | |
TLS. Gopher TLS support is not "official" as there is currently no RFC | |
to define it. It has been recently chose by the community how to make | |
it work, while keeping compatibility with old servers / clients. | |
The way to do it is really simple. | |
Client A tries to connects to Server B, Client A tries TLS handshake, | |
if Server B answers correctly to the TLS handshakes, then Client A | |
sends the gopher request and Server B answers the gopher requests. If | |
Server B doesn't understand the TLS handshakes, then it will probably | |
output a regular gopher page, then this is throwed and Client A | |
retries the connection using plaintext gopher and Server B answers the | |
gopher request. | |
This is easy to achieve because gopher protocol doesn't require the | |
server to send anything to the client before the client sends its | |
request. | |
The way to add the TLS layer and the dispatching can be achieved using | |
**sslh** and **relayd**. You could use haproxy instead of relayd, but | |
the latter is in OpenBSD base system so I will use it. Thanks parazyd | |
for sharing about sslh for this use case. | |
**sslh** is a protocol demultiplexer, it listens on a port, and | |
depending on what it receives, it will try to guess the protocol used | |
by the client and send it to the according backend. It's first purpose | |
was to make ssh available on port 443 while still having https daemon | |
working on that server. | |
Here is a schema of the setup | |
+→ relayd for TLS + forwarding | |
↑ ↓ | |
↑ tls? ↓ | |
client -> sslh TCP 70 → + ↓ | |
↓ not tls ↓ | |
↓ ↓ | |
+→ → → → → → → gopher daemon | |
on localhost | |
This method allows to wrap any server to make it TLS compatible. The | |
best case would be to have TLS compatibles servers which do all the | |
work without requiring sslh and something to add the TLS. But it's | |
currently a way to show TLS for gopher is real. | |
## Relayd | |
The relayd(1) part is easy, you first need a x509 certificate for the | |
TLS part, I will not explain here how to get one, there are already | |
plenty of how-to and one can use let's encrypt with acme-client(1) to | |
get one on OpenBSD. | |
We will write our configuration in **/etc/relayd.conf** | |
log connection | |
relay "gopher" { | |
listen on 127.0.0.1 port 7000 tls | |
forward to 127.0.0.1 port 7070 | |
} | |
In this example, relayd listens on port 7000 and our gopher daemon | |
listens on port 7070. According to relayd.conf(5), relayd will look | |
for the certificate at the following places: | |
`/etc/ssl/private/$LISTEN_ADDRESS:$PORT.key` and | |
`/etc/ssl/$LISTEN_ADDRESS:$PORT.crt`, with the current example you | |
will need the files: /etc/ssl/private/127.0.0.1:7000.key and | |
/etc/ssl/127.0.0.1:7000.crt | |
relayd can be enabled and started using rcctl: | |
# rcctl enable relayd | |
# rcctl start relayd | |
## Gopher daemon | |
Choose your favorite gopher daemon, I recommend geomyidae but any | |
other valid daemon will work, just make it listening on the correct | |
address and port combination. | |
# pkg_add geomyidae | |
# rcctl enable geomyidae | |
# rcctl set geomyidae flags -p 7070 | |
# rcctl start geomyidae | |
## SSLH | |
We will use sslh_fork (but sslh_select would be valid too, they have | |
differents pros/cons). The `--tls` parameters tells where to forward a | |
TLS connection while `--ssh` will forward to the gopher daemon. This | |
is so because the protocol ssh is already configured within sslh and | |
acts exactly like a gopher daemon: the client doesn't expect the | |
server to be the first sending data. | |
# pkg_add sslh | |
# rcctl enable sslh_fork | |
# rcctl set sslh_fork flags --tls 127.0.0.1:7000 --ssh | |
127.0.0.1:7070 -p 0.0.0.0:70 | |
# rcctl start sslh_fork | |
## Client | |
You can easily test if this works using openssl to connect by hand to | |
the port 70 | |
$ openssl s_client -connect 127.0.0.1:7000 | |
can send a gopher request like "/" and you should get a result. Using | |
telnet on the same address and port should give the same result. | |
My gopher client **clic** already supports gopher TLS and is available | |
at git://bitreich.org/clic and only requires the ecl common lisp | |
interpreter to compile. |