Goodbye ZNC, hello pounce.
(last time edited: 2021-04-22)
tags: irc, communication, bouncer
pounce is a multi-client, TLS-only IRC bouncer. It takes a simple approach, using a multiple-consumer ring buffer and the IRCv3.2 server-time extension to communicate with clients.
Looking around the Void Linux repositories I found out this little gem. It's a simple open-source IRC bouncer program written in C by June Bug, a programmer who's very into IRC communication. There are other bouncers around, including ZNC, which is the top notch bouncer all around. But I was also dissatisfied with the ZNC experience.
I want simpler things, I do not want all features that a bunch of programmers mentally masturbate of. I don't care about API, plugins that would break eventually when programming language interpreters get updated with a new version. I do not care about administration web panels and NGINX proxy pass to configure it. Fuck all that, it's stupid and the attack surface grows larger. Maybe I'm just too dumb to understand the complexity of big spaghetti code, maybe not. Maybe I don't wanna waste my time. Maybe I don't need all those features because I don't make profit by offering web services to Internet people. Maybe I just want to get things done.
Anyways. Pounce is good, pounce is love. Let's get the setup done.
First create a user in your personal server/workstation that will be running the bouncer connected 24/7.
# useradd -m -k '' pounce
And completely lock the account. Only root will have access to the account now.
# passwd -l pounce
It's better to run pounce via configuration files rather than using CLI arguments, but I will explain the basic usage for both ways.
Launch Pounce using a configuration file
local-host = irc.ourdomain.com # default value is localhost, meaning you'll access via IP, but you can choose your own domain local-port = 6697 # default port for all TLS/SSL irc connections local-priv = /path/to/letsencrypt/privkey.pem # preferably pointing to the letsencrypt certs local-cert = /path/to/letsencrypt/fullchain.pem # same as above local-pass = $6$f246kLc4kvK0gqCy$fsFGbhEefxe..................... # get a hashed password by using pounce -x, you will be prompted to enter a plain text password host = irc.freenode.net # server we are connecting to port = 6697 # default port, there are servers who don't accept TLS/SSL connections and you'll have to use 6669 join = ##linux,#voidlinux,#ascii.town # any channel you want the bouncer to join, comma-separated values nick = your_username real = your_realname away = something something not here quit = leaving
We need to save this configuration file inside this directory
Filename can be whatever you want.
Once we are done, run pounce as the pounce user.
$ pounce freenode.conf &
The bouncer will now be running in the background. How can we double check if everything is working correctly?
$ pgrep pounce
Now you can connect to your bouncer from your workstation by opening Irssi or a similar IRC client, for example WeeChat. Connect to irc.ourdomain.com using port 6697, TLS activated and the server password will be the unhashed password you entered before in the local-pass directive.
/connect -tls irc.ourdomain.com -w hellothisisthepassword
Optional: Launch Pounce using command-line arguments
Some sysadmins prefer to launch their programs via command-line with a bunch of arguments making it really cumbersome to understand at first glimpse, but this method is very useful for scripting situations. It really depends.
The same configuration I posted above can be achieved by running this command.
$ pounce -H irc.ourdomain.com -P 6697 -K /path/to/letsencrypt/privkey.pem -C /path/to/letsencrypt/fullchain.pem -h irc.freenode.net -p 6697 -j ##linux -u your_username
Replacing password authentication with self-signed TLS certificates
As I explained before, when we wanna login to our bouncer instance we input and send a plain-text password to the server, the server receives this password and compares it to the hashed string we obtained before. If the string matches, you get logged in.
Instead of entering a long ass password everytime we want to login to the bouncer, we can generate our client private key.
On your server side, in pounce user account, generate a private key. Warning! Do not share your privkey at all. (I'll explain it how to transfer it to your workstation later.). Optional for multi-users: You can create whatever quantity of clients you want.
$ pounce -g pounceprivkey.pem
Again on your server side, keep the public keys and save them in your
~/.config/pounce directory. Optional for multi-users: You can concatenate whatever quantity of generated public keys you want to into the pouncecert.pem file.
$ openssl x509 -in pounceprivkey.pem > ~/.config/pounce/pouncecert.pem
Now in your pounce configuration directory you can remove the local-pass directive and change it to local-ca.
... local-ca = /home/pounce/.config/pounce/pouncecert.pem ...
or as alternative use the command-line argument
-A to deploy your pounce.
$ pounce -H irc.ourdomain -P 6697 -K /path/to/letsencrypt/privkey.pem -C /path/to/letsencrypt/fullchain.pem -h irc.freenode.net -p 6697 -j ##linux -u your_username -A pounceprivkey.pem
Now we need to transfer to our workstation the private key pounceprivkey.pem we've made before; otherwise we won't be able to login.
From your workstation do this:
$ scp email@example.com:~/pounceprivkey.pem ~
Now it's very easy to login to our bouncer.
Using catgirl. This is an IRC client also made by June Bug:
$ catgirl -e -h freenode.yourdomain.com -c /home/your_username/pounceprivkey.pem
/connect -tls -tls_cert ~/pounceprivkey.pem irc.ourdomain.com
Identifying to IRC servers using CertFP (SASL external)
You can identify yourself to NickServ using a plain password, or you can opt using CertFP which is a more secure way to do.
First create a private key.
$ pounce -g ~/.config/pounce/freenode-username.pem
Then add this to your instance configuration.
client-cert = /home/pounce/.config/pounce/freenode-username.pem
or alternatively via command line argument using
Once you are connected to the server contact NickServ.
/query NickServ CERT ADD
You can list all added certificates:
/query NickServ CERT LIST
Now once everything has been configured, activate SASL.
Your configuration should look like this.
client-cert = /home/pounce/.config/pounce/freenode-username.pem sasl-external
Launch multiple Pounce instances using Calico
The calico daemon dispatches incoming TLS connections to instances of pounce by Server Name Indication (SNI). Instances of pounce should be configured with -U to bind to UNIX-domain sockets in the directory passed to calico. Note that calico is not a proxy. Incoming connections are passed directly to instances of pounce, which handle TLS negotiation. Instances of pounce and calico can be restarted independently of each other.
This program is also written by June Bug in addition to pounce. It's an extension that helps us deploy multiple bouncers.
I prefer using subdomain wildcard (*.ourdomain.com) certificates for my domain. Since it's an experimental VPS I don't need to be so strict. This simplifies deployment a lot. I don't need to extend my certificates for specific subdomain names everytime I wanna add a bouncer or start a new service. I talk about more about that here.
First log in into your pounce user account and create a new temporal directory. It will act as a socket.
$ mkdir /tmp/calico
Now run calico. It's not necessary to add a subdomain into the -H (host) argument. Calico will always be running in the background. You can then add and remove pounce instances.
$ calico -H ourdomain.com -P 6697 /tmp/calico &
Now if you have already set up multiple configurations launch them via commandline.
$ pounce -U /tmp/calico freenode.conf & pounce -U /tmp/calico rizon.conf &
Generating Let's Encrypt TLS/SSL certificates with Certbot
Certbot is a free, open source software tool for automatically using Let’s Encrypt certificates on manually-administrated websites to enable HTTPS. Certbot is made by the Electronic Frontier Foundation (EFF), a 501(c)3 nonprofit based in San Francisco, CA, that defends digital privacy, free speech, and innovation.
Creating certificates is not a big deal as it may seem. You can use Certbot plugins to deploy the certificates to specific web servers such as Apache or NGINX but we aren't gonna need that. Our bouncer doesn't need of any web server for anything. We just need the cert files. Create them manually with this command.
# certbot certonly --cert-name certs -d irc.ourdomain.com
They will be placed inside
Now we encounter a new problem. Our pounce user won't be able to read the certificates. They were generated under root account and placed in root directories under root permissions.
One solution among many is to create a separate UNIX user group. This solves a situation where many non-root programs need to access the certificates, such as uMurmur.
# groupadd tls-ssl-certs
Add the user pounce to the tls-ssl-certs group.
# usermod -aG tls-ssl-certs pounce
Change group recursively to every file and directory inside
# chgrp -R tls-ssl-certs /etc/letsencrypt
Modify permissions recursively so users inside tls-ssl-certs group can only read and execute.
# chmod -R g=rx /etc/letsencrypt
Modify permissions so Others cannot read, write, nor execute. This is done for better security but it's not completely necessary. Just a little detail.
# chmod -R o-rwx /etc/letsencrypt
Don't forget to relog-in into your pounce account in order to refresh permissions.
Creating a runit service for calico and pounce
Create a directory for the new calico runit service.
# mkdir /etc/sv/calico
Create a runit run file/script.
# touch /etc/sv/calico/run
Open the run file with a text editor.
# vim /etc/sv/calico/run
Copy and paste the following script. It checks if the temporal calico directory socket is created and then executes the calico daemon.
#!/bin/sh [ ! "$(pgrep calico)" ] && [ -d /tmp/calico ] && rm -rf /tmp/calico [ ! -d /tmp/calico ] && su pounce -c "mkdir -p /tmp/calico" exec chpst -u pounce calico -H yourdomain.com -P 6697 /tmp/calico
Add executable permissions.
# chmod +x /etc/sv/calico/run
Start the service.
# sv force-restart /var/service/calico
Now create the pounce service for an specific IRC server. The procedure is similar.
First create a service directory.
# mkdir /etc/sv/pounce-freenode
Create a run runit file/script.
# touch /etc/sv/pounce-freenode/run
Open the file using a text editor.
# vim /etc/sv/pounce/run
Add the following text.
#!/bin/sh sv start calico || exit 1 exec chpst -u pounce:tls-ssl-certs pounce -U /tmp/calico /home/pounce/.config/pounce/freenode.conf
Add executable permissions to the run file.
# chmod +x /etc/sv/pounce/run
Repeat the same for other bouncer instances.
Some IRC servers won't let you connect via their subdomain. That is fine. Use their Certificate Common Name instead of using the Subject Alternative Name. For example: euirc.net instead of irc.euirc.net.
Pounce and Calico should always be run as non-root.
Pounce uses only TLS (Transport Layer Security) by default which is a modern and updated implementation of SSL (Secure Sockets Layer). That's why in the tech community they refer it most of the time as TLS/SSL. SSL is deprecated.
Pounce has lots of potential for automation. I haven't seen any running service for multiple users yet but I'm willing to test and create one just for fun.
Save your configuration files somewhere.
Bouncer password and NickServ identification password should be different from each other as a basic security measure.