another meaningless subtitle

Nginx and XMPP over TLS

· by fabio · Read in about 3 min · (487 Words)
Centos Ejabberd Nginx

XMPP over TLS (formerly XEP-0368) is a clever mechanism that allows users to connect to a XMPP server from networks that restrict outgoing traffic only to specific ports; this block is circumvent by routing XMPP traffic via port TCP 433.
If the server hosts only a XMPP server setting up XMPP over TLS is pretty easy, just instruct the server to listen on port 443.
If the server also runs a webserver which is listening on port 443 things are a bit more complicated; luckily Nginx provides a way to manage XMPP traffic and redirect it to the XMPP server.

Nginx

Nginx binaries from Nginx’s official CentOS 7 repos are already compiled with the required module (ngx_stream_ssl_preread_module).
What’s left for us to do is configure the webserver to redirect XMPP traffic to the XMPP server.

$ cat /etc/nginx/nginx.conf

stream {
    upstream httpserver {
        server localhost:8443;   # webserver_host:webserver_port
    }

    upstream xmppserver {
        server localhost:5223;   # xmpp_server_host:xmpp_over_tls_port
    }

    map $ssl_preread_alpn_protocols $upstream {
        default httpserver;
        "xmpp-client" xmppserver;
    }

    server {
        listen 443;

        ssl_preread on;
        proxy_pass $upstream;
    }
}

Also be sure to change Nginx virtual hosts accordingly, those should listen to port TCP 8443 instead of the usual TCP 443.

Ejabberd

Ejabberd configuration is pretty easy, just add a second c2s listener on port TCP 5223.

$ cat /usr/local/etc/ejabberd/ejabberd.yml

listen:
  -
    port: 5223
    ip: "::"
    module: ejabberd_c2s
    max_stanza_size: 65536
    shaper: c2s_shaper
    access: c2s
    tls: true

DNS records

A crucial part of having working XMPP over TLS is setting up a few DNS records:

scheme: _service._proto.name TTL class SRV priority weight port target

_xmpps-client._tcp.example.org. 86400 IN SRV 5  0 443  xmpp.example.org.
_xmpp-client._tcp.example.org.  86400 IN SRV 10 0 443  xmpp.example.org.
_xmpp-client._tcp.example.org.  86400 IN SRV 15 0 5222 xmpp.example.org.

SELinux

Here comes the fun part, we picked port 8433 for Nginx to listen to because that is one of the few ports that it can bind.
To check what those ports are run:

$ semanage port -l | grep http_port_t
http_port_t                    tcp      80, 81, 443, 488, 8008, 8009, 8443, 9000

Ejabberd should have no issues to bind port TCP 5223, the only thing left to do is create a SELinux module to allow Nginx from redirecting traffic from port TCP 443 to TCP 5223.
Be sure to have auditd service installed and running and also the package policycoreutils-python installed on your system.
To create a new SELinux module run:

$ ausearch -c 'nginx' --raw | audit2allow -M nginx-xmppovertls
$ semodule -i nginx-xmppovertls.pp

Personal considerations

My personal opinion is that XMPP over TLS is a very very bad idea because it encourage the users to connect from monitored networks that they should not even consider using in the first place.
If you care about privacy buy a VPS and setup a VPN so you can use freedom restricting networks without leaking any data.
Unfortunately users tend to want all the features enabled even if the are actually harmful, so we get stuff like XEP-0368.