| 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. |