ircxmpp is a simple one-to-one bridge between IRC and XMPP.
Usage: IX_JID=j@xmpp IX_PASS=xmpp IX_HOST=irc.srv IX_PORT=6666 IX_CHANNEL=#c IX_MUC=muc@xmpp ircxmpp
- one XMPP user needs to be created on XMPP server, identified by jid and password
- prepend # to irc.srv hostname (#irc.srv) to connect with TLS
- change port to 6697 (or whatever is used) when connecting with TLS
- replace muc with the MUC XMPP group to connect to
Configure the MUC room and XMPP server if possible:
- disable sending full jids, because every IRC user has same bare JID, only nickname changes
- default visitors as participants or make ircxmpp XMPP a participant in MUC room
- disable any per-JID or per-IP limits, ircxmpp connects multiple times
- MAM may be enabled, since old messages will never be sent to IRC
- disable any MUC password protection or allow JID of ircxmpp to connect
Configure the IRC channel or server if possible:
- disable any per-IP limits, ircxmpp connects multiple times. libera chat is okay with that.
- use a bot to set XMPP users to have +o, +v or +h to prevent flood kicks
- disable invite-only mode on channel. you may use IRC channel passwords.
Required environment variables for configuration of a bridge:
- IX_JID JID of ircxmpp user on XMPP server to connect with
- IX_PASS password for XMPP authentication of ircxmpp user
- IX_HOST hostname of the IRC server, prefix the value with # to connect with TLS
- IX_PORT port of the IRC server to connect to, choose apropriate for plaintext/TLS
- IX_CHANNEL channel on IRC server to bridge
- IX_MUC multi-user chat on XMPP server to bridge
Optional environment variables for configuration of a bridge:
- IX_CHPASS set to IRC channel password if channel on IRC is password protected
- IX_DOMAIN start the built in DNS server and spoof IRC hostnames (more info below)
Optional environment variables for global configuration: (those do not have numbered counterparts)
- IX_LOOPDELAY delay after each event loop cycle in microseconds, defaults to 10 ms.
- IX_DNS_PORT port on which the DNS server should run, if it's enabled, by default 53
- IX_DNS_IP IP on which to listen for DNS queries. by default this is INADDR_ANY-0.0.0.0
Operation principle:
- ircxmpp initiates two control connections, one to XMPP server, one to IRC server, and joins
- when user joins in XMPP, a bridge connection is established to IRC and joins the channel
- when user joins in IRC, a bridge connection is established to XMPP and joins the MUC
- when a chat is made in IRC, it's reflected on the correct bridge connection in XMPP
- when a chat is made in XMPP, it's reflected on the correct bridge connection in IRC
- when user quits in IRC, resources are freed for the bridge, connection to XMPP is dropped
- when user quits in XMPP, resources are freed for the bridge, connection to IRC is dropped
- control connections are reconnected automatically and remain connected till exit.
- program can be stopped by sending a SIGTERM or SIGINT (well, or SIGKILL for that matter)
- topic changes are reflected in XMPP MUC as messages
To implement:
- private messages
- ctcp messages (ACTION - /me) and perhaps file upload (that'd be hard)
- subject changing
- automatic +v/+h/+o botnet juggling between bridge IRC connections and control IRC conn
- reusing bridge and control connections with same nick to different channels on same network
Notes:
- when connecting to a channel with already joined nicks, they're not connected to XMPP until they send a message or change their nick. only after that are they bridged, and the sent message is not lost. implementing this would require parsing NAMES list, which only contains nicks and not usernames and hostnames, and would also impact performance, especially on MAM-enabled MUCs that send a lot of history on XMPP join for every connection. XMPP MUCs also tend to slow down with a large number of connections, whereas IRC channels don't.
- if possible, send core dumps of crashes to my email address anton@šijanec.eu.
- coredumps contain passwords and some chats, so make sure to change XMPP password before
- to capture core dumps of systemd services (when installed on debian), use systemd-coredump
Debian installation, systemd service and precompiled dynamically linked binaries:
- packages in my ppa on http://prog.sijanec.eu/ (amd64, arm64, armel, i386, src, dbgsym, lib)
- after adding the archive and running apt update, install with apt install ircxmpp
- edit the configuration file with environment variables in /etc/ircxmpp
- run the service with service ircxmpp start, enable it at boot with systemctl enable ircxmpp
- ci/cd: http://jenkins.sijanec.eu/job/ircxmpp for amd64, arm64 and armel
Security:
- do not trust this program.
- if you find a (security) vulnerability or any issue, please email anton@šijanec.eu.
- whenever possible, run the program in a chroot jail as an unpriviledged user. Running with systemd (service ircxmpp start) does that.
Running multiple irc<->xmpp links at the same time:
- first link's environment variables are still in format IX_JID, IX_PASS, IX_HOST and so on
- second link's environment variables are in format IX_JID2, IX_PASS2, IX_HOST2 and so on
- this means you concatenate the config environment variable with the digit
- digits must be consecutive from 2 to infinity, vars without digit (1st link) are required
- IX_LOOPDELAY applies to all links, as there is no delay between individual links (no 2, 3)
Compilation and manual install from source:
- git clone https://git.sijanec.eu/sijanec/ircxmpp
- cd ircxmpp
- make # tested compilers: gcc, clang and tcc. make -e CC=tcc, make -e CC=clang, ...
- make install # not required, but otherwise LD_LIBRARY_PATH=. ./ircxmpp for libircxmpp.so
Using as a library:
- you may only use functions after #endif in ircxmpp.h, handler struct is opaque
- after make install, ircxmpp.h and libircxmpp.so are placed in /usr/{include,lib}
- #include <ircxmpp.h> and link with -lircxmpp
- functions return nothing (except ircxmpp_init) and log to standard error
- do not call ircxmpp_set_*() functions after first call to ircxmpp_run_once()
- actual main function of the ircxmpp program is in ircxmpp.c between #else and #endif
- in the 0.0.x stage, no binary compatiblity is guaranteed. nothing is guaranteed.
Gentoo/openrc?:
- http://github.com/OpenRC/openrc/pull/517 needs to be merged before for increased security
Built-in DNS server for spoofing IRC hostnames:
- IRC hostnames can be spoofed so that they look like the XMPP JID domain of the XMPP user
- you need to run the program with CAP_NET_BIND_SERVICE, on debian systemd this is by default
- you need a domain name, on which you set a wildcard record to A record to server's IP
+ for example *.ircxmpp.example. IN A 192.168.0.2 (this is for IRC PTR verification)
- in the in-addr.arpa zone for you IP address, add a NS record pointing to your server
+ for example 2.0.168.193.in-addr.arpa. IN NS server.ircxmpp.example.
- start ircxmpp with the configuration variable IX_DOMAIN=ircxmpp.example.
- read the logs! the built in DNS server might spam bind: permission denied errors
- when a bridge will connect to IRC, the IRC server will query the ircxmpp NS for PTR
- when a request is received by the ircxmpp NS, last XMPP user's JID hostname will be sent
+ let's say xmpp.server.de.ircxmpp.example; ircxmpp.example appended for verification
- IRC server will then verify that this domain really points to your IP address-that wildcard
Built-in DNS server for spoofing IRC hostnames when using the program as a library:
- call ircxmpp_set_domain with your domain suffix to which JID host and dot will be prepended
- you can set your callback with ircxmpp_set_set_domain_setter
- callback is called when domain change is wanted even if ircxmpp_set_dns is false
- with this you can differently publish the domain name for spoofing, perhaps with nsupdate
- otherwise if ircxmpp_set_dns is true, internal DNS server works as described above
IPv6:
- Haha, remember this is C you're talking about! That'd require writing code!
- TODO: add support in DNS server for ip6 (binding to AF_INET6 sockets, ip6 memmem, ...)
- TODO: use irc_connect6 somehow in libircclient, libstrophe should already work with IPv6
-- Anton Luka Šijanec <anton@sijanec.eu> Fri, 29 Apr 2022 17:00:00 +0200