XMPP reverse proxy and outgoing proxy https://github.com/moparisthebest/xmpp-proxy
Go to file
moparisthebest e8b218e316
Some checks failed
moparisthebest/xmpp-proxy/pipeline/head There was a failure building this commit
Add peek_bytes
2023-02-20 23:00:23 -05:00
.ci Initial commit 2021-04-12 23:40:44 -04:00
contrib Update readme 2022-07-16 20:55:05 -04:00
fuzz Fix fuzzing 2023-02-07 00:22:17 -05:00
integration Fallback to original domain for Host: if securely delegated websocket fails 2022-05-23 00:34:32 -04:00
src Add peek_bytes 2023-02-20 23:00:23 -05:00
.gitattributes Update Cargo.lock and try to fix incorrect language detection 2022-03-15 22:35:31 -04:00
.gitignore Add ejabberd integration tests, currently fails with prosody without dialback 2022-03-16 00:46:26 -04:00
.rustfmt.toml Initial commit 2021-04-12 23:40:44 -04:00
build.rs Implement optional support for systemd socket activation 2022-07-18 01:49:56 -04:00
Cargo.lock Upgrade quinn to 0.9 2023-02-19 20:49:27 -05:00
Cargo.toml Upgrade quinn to 0.9 2023-02-19 20:49:27 -05:00
check-all-features.sh Implement optional support for systemd socket activation 2022-07-18 01:49:56 -04:00
LICENSE.md Initial commit 2021-04-12 23:40:44 -04:00
README.md Update readme 2022-07-16 20:55:05 -04:00
xmpp-proxy.toml Add support for proxying outgoing WebSocket connections 2022-03-25 01:32:10 -04:00


logo
xmpp-proxy

Build Status

xmpp-proxy is a reverse proxy and outgoing proxy for XMPP servers and clients, providing STARTTLS, Direct TLS, QUIC, WebSocket C2S, and WebSocket S2S connectivity to plain-text XMPP servers and clients and limiting stanza sizes without an XML parser.

xmpp-proxy in reverse proxy (incoming) mode will:

  1. listen on any number of interfaces/ports
  2. accept any STARTTLS, Direct TLS, QUIC, or WebSocket c2s or s2s connections from the internet
  3. terminate TLS
  4. for s2s require a client cert and validate it correctly (using CAs, host-meta, host-meta2, and POSH) for SASL EXTERNAL auth
  5. connect them to a local real XMPP server over plain-text TCP
  6. send the PROXY protocol v1 header if configured, so the XMPP server knows the real client IP
  7. limit incoming stanza sizes as configured

xmpp-proxy in outgoing mode will:

  1. listen on any number of interfaces/ports
  2. accept any plain-text TCP or WebSocket connection from a local XMPP server or client
  3. look up the required SRV, host-meta, host-meta2, and POSH records
  4. connect to a real XMPP server across the internet over STARTTLS, Direct TLS, QUIC, or WebSocket
  5. fallback to next SRV target or defaults as required to fully connect
  6. perform all the proper required certificate validation logic
  7. limit incoming stanza sizes as configured

Installation

Configuration

  • mkdir /etc/xmpp-proxy/ && cp xmpp-proxy.toml /etc/xmpp-proxy/
  • edit /etc/xmpp-proxy/xmpp-proxy.toml as needed, file is annotated clearly with comments
  • put your TLS key/cert in /etc/xmpp-proxy/
  • Example systemd unit is provided in xmpp-proxy.service and locks it down with bare minimum permissions. Need to set the permissions correctly: chown -Rv 'systemd-network:' /etc/xmpp-proxy/
  • start xmpp-proxy: Usage: xmpp-proxy [/path/to/xmpp-proxy.toml (default /etc/xmpp-proxy/xmpp-proxy.toml]

How do I adapt my running Prosody config to use this instead?

You have 2 options here, use xmpp-proxy as only a reverse proxy, or as both reverse and outgoing proxy, I'll cover both:

Reverse proxy and outgoing proxy

In this mode both prosody doesn't need to do any TLS at all, so it needs no certs. xmpp-proxy need proper TLS certificates, move prosody's TLS key to /etc/xmpp-proxy/le.key and TLS cert to /etc/xmpp-proxy/fullchain.cer, and use the provided xmpp-proxy.toml configuration as-is.

Edit /etc/prosody/prosody.cfg.lua, Add these to modules_enabled:

"net_proxy";
"s2s_outgoing_proxy";

Until prosody-modules is updated, use my new module mod_s2s_outgoing_proxy.lua.

Add this config:

-- only need to listen on localhost
interfaces = { "127.0.0.1" }

-- we don't need prosody doing any encryption, xmpp-proxy does this now
-- these are likely set to true somewhere in your file, find them, make them false
-- you can also remove all certificates from your config
s2s_require_encryption = false
s2s_secure_auth = false
c2s_require_encryption = false
allow_unencrypted_plain_auth = true

-- xmpp-proxy outgoing is listening on this port, make all outgoing s2s connections directly to here
s2s_outgoing_proxy = { "127.0.0.1", 15270 }

-- handle PROXY protocol on these ports
proxy_port_mappings = {
    [15222] = "c2s",
    [15269] = "s2s"
}

-- don't listen on any normal c2s/s2s ports (xmpp-proxy listens on these now)
-- you might need to comment these out further down in your config file if you set them
c2s_ports = {}
legacy_ssl_ports = {}
-- you MUST have at least one s2s_ports defined if you want outgoing S2S to work, don't ask.. 
s2s_ports = {15268}
Reverse proxy only, prosody makes outgoing connections directly itself

In this mode both prosody and xmpp-proxy need proper TLS certificates, copy prosody's TLS key to /etc/xmpp-proxy/le.key and TLS cert to /etc/xmpp-proxy/fullchain.cer, and use the provided xmpp-proxy.toml configuration as-is.

Edit /etc/prosody/prosody.cfg.lua, Add these to modules_enabled:

"net_proxy";
"secure_interfaces";

Until prosody-modules is updated, use my patched version of mod_secure_interfaces.lua which also works for s2s.

Add this config:

-- trust connections coming to these IPs
secure_interfaces = { "127.0.0.1", "::1" }

-- handle PROXY protocol on these ports
proxy_port_mappings = {
    [15222] = "c2s",
    [15269] = "s2s"
}

-- don't listen on any normal c2s/s2s ports (xmpp-proxy listens on these now)
-- you might need to comment these out further down in your config file if you set them
c2s_ports = {}
legacy_ssl_ports = {}
-- you MUST have at least one s2s_ports defined if you want outgoing S2S to work, don't ask.. 
s2s_ports = {15268}

Customize the build

If you are a grumpy power user who wants to build xmpp-proxy with exactly the features you want, nothing less, nothing more, this section is for you!

xmpp-proxy has multiple compile-time features, some of which are required, they are grouped as such:

choose between 1-4 directions:

  1. c2s-incoming - enables a server to accept incoming c2s connections
  2. c2s-outgoing - enables a client to make outgoing c2s connections
  3. s2s-incoming - enables a server to accept incoming s2s connections
  4. s2s-outgoing - enables a server to make outgoing s2s connections

choose between 1-3 transport protocols:

  1. tls - enables STARTTLS/TLS support
  2. quic - enables QUIC support
  3. websocket - enables WebSocket support, also enables TLS incoming support if the appropriate directions are enabled

choose exactly 1 of these methods to get trusted CA roots, not needed if only c2s-incoming is enabled:

  1. tls-ca-roots-native - reads CA roots from operating system
  2. tls-ca-roots-bundled - bundles CA roots into the binary from the webpki-roots project

choose any of these optional features:

  1. logging - enables configurable logging

So to build only supporting reverse proxy STARTTLS/TLS, no QUIC, run: cargo build --release --no-default-features --features c2s-incoming,s2s-incoming,tls To build a reverse proxy only, but supporting all of STARTTLS/TLS/QUIC, run: cargo build --release --no-default-features --features c2s-incoming,s2s-incoming,tls,quic

Development

  1. check-all-features.sh is used to check compilation with all supported feature permutations
  2. integration/test.sh uses Rootless podman to run many tests through xmpp-proxy on a real network with real dns, web, and xmpp servers, all of these should pass before pushing commits, and write new tests to cover new functionality.
  3. To submit code changes submit a PR on github or code.moparisthebest.com or send me a patch via email, XMPP, fediverse, or carrier pigeon.

License

GNU/AGPLv3 - Check LICENSE.md for details

Thanks rxml for afl-fuzz seeds

Todo

  1. write "host-meta2" XEP for QUIC and WebSocket S2S Discovery
  2. optional systemd integration
  3. seamless Tor integration, connecting to and from .onion domains