back to twinlog

Aquarius: PoC

I wanted something to hack on tonight, so being the nerd in search of esoterica I wrote a quick implementation of Aquarius, ie. a non-private non-reliable stripped down protocol resembling Gemini on top of UDP.

Aquarius: an emergency lifeboat version of Gemini?

/aqserv.py

/aqget.py

I might move those files later. They're in a stupid place right now.

Anyway, this server now runs aqserv.py on port 1970 and if you download the client (aqget.py) you can try the protocol out. But *PLEASE* remember: this protocol is *significantly* worse than Gemini in almost all cases. Try not to fall in love with it.

UPDATE 2020-07-28: Sean Conner noted that this protocol is vulnerable to amplification attacks. I'll shut down the server in a couple of days. Feel free to experiment until then, but please don't use the server for DDoS! :)

Traffic overview

Using Wireshark, I logged the traffic on port 1970 for the command

python aqget.py aquarius://hannuhartikainen.fi/twinlog/2020-07-27_aquarius.gemini

and on port 1965 for the command

SSLKEYFILE=/tmp/sslkeys gemget gemini://hannuhartikainen.fi/twinlog/2020-07-27_aquarius.gemini

to get a comparison of what happens with each protocol.

With Aquarius, it's simple and plain when it works:

1. Client sends plaintext request: aquarius://hannuhartikainen.fi/twinlog/<CRLF>

2. Server sends six UDP packets with plaintext contents.

If all goes well, every packet reaches their destination in the correct order. If not, some 508-byte chunks of the content may be in the wrong order, some may be missing, and the data may be garbled. ¯\_(ツ)_/¯

With Gemini, both TCP and TLS make me scratch my head.

1. SYN

2. SYN+ACK

3. ACK

4. TLS handshake

5. The actual content

6. ACKs after every packet

7. FIN+ACK

8. RST

I feel like I should understand TCP better but I don't. :(

Traffic statistics

╔══════════════════╦══════════╦════════╗
║                  ║ Aquarius ║ Gemini ║
╠══════════════════╬══════════╬════════╣
║ sent packets     ║ 1        ║ 11     ║
╠══════════════════╬══════════╬════════╣
║ sent bytes       ║ 109      ║ 1235   ║
╠══════════════════╬══════════╬════════╣
║ received packets ║ 6        ║ 10     ║
╠══════════════════╬══════════╬════════╣
║ received bytes   ║ 2968     ║ 5427   ║
╠══════════════════╬══════════╬════════╣
║ total time (ms)  ║ 20       ║ 101    ║
╚══════════════════╩══════════╩════════╝

The file size is 2700 bytes, which is quite normal for text/gemini. My ping to the server is 16ms.

The maximum "safe" size for UDP payload over IPv4 is 508 bytes, though 1432 (safe for IPv6) probably works almost as well. The response would have *just* fit into two packets with the larger packet size. That would not really affect speed, though, as all the packets are sent as a burst.

NOTE: this comparison is needlessly bad for Gemini as the server has a large RSA certificate.

My thoughts

In this case, Gemini had about 50/50 content/overhead. With connectionless UDP you get much less overhead, until you start to need retries.

But consider where we come from. On the web it's typical to get 2.7MB or more of overhead (SPA, tracking scripts, you name it) for 2700 bytes of text content. Web pages don't load in 100 milliseconds. I'm happy if they load in 2 seconds.

We get confidentiality and integrity in this case for about 3KB of traffic and 80 milliseconds. It's a ridiculously good deal.

Still, if I wanted a battery-powered embedded server I'd much rather have Aquarius than Gemini. But realistically I'm browsing text content on a laptop or a phone. The main power consumption comes from the display backlight.