From 4498559c082617ba85cd40b3df5f383da3fd9d44 Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Sat, 16 Jul 2022 20:55:05 -0400 Subject: [PATCH] Update readme --- README.md | 33 +++++++++++++++++++----------- contrib/logo/xmpp_proxy_color.png | Bin 0 -> 23654 bytes 2 files changed, 21 insertions(+), 12 deletions(-) create mode 100644 contrib/logo/xmpp_proxy_color.png diff --git a/README.md b/README.md index db4be28..61fbe2a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@


- logo + logo
xmpp-proxy
@@ -10,24 +10,22 @@ [![Build Status](https://ci.moparisthe.best/job/moparisthebest/job/xmpp-proxy/job/master/badge/icon%3Fstyle=plastic)](https://ci.moparisthe.best/job/moparisthebest/job/xmpp-proxy/job/master/) -xmpp-proxy is a reverse proxy and outgoing proxy for XMPP servers and clients, providing STARTTLS, -[Direct TLS](https://xmpp.org/extensions/xep-0368.html), [QUIC](https://datatracker.ietf.org/doc/html/draft-ietf-quic-transport), -and [WebSocket](https://datatracker.ietf.org/doc/html/rfc7395) connectivity to plain-text XMPP servers and clients and -limiting stanza sizes without an XML parser. +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. connect them to a local real XMPP server over plain-text TCP - 5. send the [PROXY protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) v1 header if configured, so the - XMPP server knows the real client IP - 6. limit incoming stanza sizes as configured + 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 records + 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 @@ -169,5 +167,16 @@ GNU/AGPLv3 - Check LICENSE.md for details Thanks [rxml](https://github.com/horazont/rxml) for afl-fuzz seeds -#### todo - 1. XEP for XMPP-over-QUIC and XMPP-S2S-over-WebSocket +#### Todo + 1. write "host-meta2" XEP for QUIC and WebSocket S2S Discovery + 2. optional [systemd](https://www.freedesktop.org/software/systemd/man/sd_listen_fds.html) [integration](https://mgdm.net/weblog/systemd/) + 3. seamless Tor integration, connecting to and from .onion domains + +[STARTTLS]: https://datatracker.ietf.org/doc/html/rfc6120#section-5 +[Direct TLS]: https://xmpp.org/extensions/xep-0368.html +[QUIC]: https://xmpp.org/extensions/xep-0467.html +[WebSocket C2S]: https://datatracker.ietf.org/doc/html/rfc7395 +[WebSocket S2S]: https://xmpp.org/extensions/xep-0468.html +[POSH]: https://datatracker.ietf.org/doc/html/rfc7711 +[host-meta]: https://xmpp.org/extensions/xep-0156.html +[PROXY protocol]: https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt diff --git a/contrib/logo/xmpp_proxy_color.png b/contrib/logo/xmpp_proxy_color.png new file mode 100644 index 0000000000000000000000000000000000000000..21f8f3a4ca3494bcb49cfef6d42135437b5449ad GIT binary patch literal 23654 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

9$FZwAZ0~s-V2p)fSIXY22r+2w&$KUWss*ZvcmL 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 JPDHLkV1hM;G8+H@ literal 0 HcmV?d00001