The idea of making a P2P messenger independent from corporations is not new, but developing a new protocol and client applications for it is quite an expensive and lengthy process. What if you use the good old XMPP, in which everything has long been thought out and filed?
But this is not a real peer-to-peer, you say, for XMPP to work you need your own server and domain. This is true, but we can run the server on localhost, and to communicate with the servers of other users use a hidden service in I2P virtual network. Using I2P will save us from having to pay for a domain with hosting, and will also protect our communications from criminal online surveillance.
Thus, we get:
- Hybrid P2P messenger that can be run on both user devices and a full-fledged server.
- Features that other P2P messengers lack: offline messages, storing contacts and history in the cloud, working with several clients with one account.
- Ready-made client applications for every taste.
- Due to the use of I2P, it is invulnerable to various *supervisions (sorry for the swearing).
Let's get down to implementation...
Installing I2P and creating a server tunnel
In this guide, we will use a lightweight C++ client as an I2P router i2pd. Installation instructions are in documentation.
After installation, we create a server I2P tunnel - this is a virtual address through which our XMPP server will be accessible to the rest of the world. To file tunnels.conf add the following lines:
[prosody-s2s]
type=server
host=127.0.0.1
port=5269
inport=5269
keys=prosody.dat
[prosody-c2s]
type=server
host=127.0.0.1
port=5222
inport=5222
keys=prosody.dat
If you plan to use it only on a localhost, you don’t need to add the prosody-c2s section. Reboot i2pd to apply the settings. We look for the I2P address of the created tunnel in the web console http://127.0.0.1:7070/ On the page I2P tunnels
.
You can also find out the b32 address of the new tunnel by grabbing the logs:
grep "New private keys file" /var/log/i2pd/i2pd.log | grep -Eo "([a-z0-9]+).b32.i2p" | tail -n1
Save this xxx.b32.i2p address, this will be the domain for your XMPP server.
Installing and configuring XMPP server
We will use as an XMPP server prosody, it is the lightest and there is a ready-made module for it to work via I2P. The installation is described in the official documentation, in Ubuntu it’s easy to do apt install prosody
.
For work mod_darknet
you need the lua library bit32. If you have lua version less than 5.2 (most likely) we perform apt install lua-bit32
.
Installing the module mod_darknet
. It is needed for prosody to make outgoing connections through the Socks5 i2pd server. Download this file to the prosody modules directory, usually this /usr/lib/prosody/modules
.
Now we edit the /etc/prosody/prosody.cfg.lua config. Replace xxx.b32.i2p
to your address:
interfaces = { "127.0.0.1" };
admins = { "admin@xxx.b32.i2p" };
modules_enabled = {
"roster"; "saslauth"; "tls"; "dialback"; "disco"; "posix"; "private"; "vcard"; "ping"; "register"; "admin_adhoc"; "darknet";
};
modules_disabled = {};
allow_registration = false;
darknet_only = true;
c2s_require_encryption = true;
s2s_secure_auth = false;
authentication = "internal_plain";
-- On Debian/Ubuntu
daemonize = true;
pidfile = "/var/run/prosody/prosody.pid";
log = {
error = "/var/log/prosody/prosody.err";
"*syslog";
}
certificates = "certs";
VirtualHost "xxx.b32.i2p";
ssl = {
key = "/etc/prosody/certs/xxx.b32.i2p.key";
certificate = "/etc/prosody/certs/xxx.b32.i2p.crt";
}
The last step in setting up prosody is generating encryption certificates. In niks it is done like this:
openssl genrsa -out /etc/prosody/certs/xxx.b32.i2p.key 2048
openssl req -new -x509 -key /etc/prosody/certs/xxx.b32.i2p.key -out /etc/prosody/certs/xxx.b32.i2p.crt -days 3650
chown root:prosody /etc/prosody/certs/*.b32.i2p.{key,crt}
chmod 640 /etc/prosody/certs/*.b32.i2p.{key,crt}
Reboot the prosody server to apply the settings.
A slight digression is needed here. In the I2P network, any connections are end-to-end encrypted and, it would seem, additional encryption is unnecessary here. But, in practice, it turned out to be easier to generate keys than to try to configure all programs to use plaintext. You can try, but I warned you.
Creating accounts and connecting clients
Adding an admin account:
prosodyctl adduser admin@xxx.b32.i2p
Now we configure the XMPP client (for example Pidgin).
If you are connecting to a localhost, then in the client settings we specify the connection to the server port 127.0.0.1 5222.
If you connect to the server remotely via I2P, then specify Socks in the proxy settings5 127.0.0.1:4447.
If everything is done correctly, you will be able to add other users to the I2P federation and chat with them. It is also possible to configure your already running server on the regular Internet to correspond with servers inside I2P. To do this, all other users will need to add mapping for your domain to their prosody config. For example, this is how I did it to communicate with the server i2p.rocks
:
darknet_map = {
["i2p.rocks"] = "ynkz7ebfkllljitiodcq52pa7fgqziomz4wa7tv4qiqldghpx4uq.b32.i2p";
["muc.i2p.rocks"] = "ynkz7ebfkllljitiodcq52pa7fgqziomz4wa7tv4qiqldghpx4uq.b32.i2p";
}
That's all. Happy chatting!