From 9fbbe05d6cd4a752314f6c91ad005f72913657e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=8F=D0=BD=20=D0=9C=D0=B8=D0=BD=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 13 Dec 2022 08:26:22 -0600 Subject: [PATCH] feat: Adds docs, config and scripts around the visitor mode. (#12658) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Moves handle of vnode from conferenceIQ stanza error to result. * feat: Handles redirected to visitor node event. * feat: Adds README and configurations. * squash: Drop comment. * copy edits * image fix * fix background for dark mode * fix the background * feat: Update s2soutinjection. * Update README commands formatting. * Update doc/extra-large-conference/README.md Co-authored-by: Saúl Ibarra Corretgé * squash: Creates a generateVisitorConfig helper. * squash: Moves the folder from doc. * squash: Update example. * squash: Drop config. * squash: Rename var to look like template. * squash: Fix plugins path. * squash: Fix sort order of import. * squash: Fix lint errors. Co-authored-by: scott boone Co-authored-by: Scott Boone Co-authored-by: Saúl Ibarra Corretgé --- conference.js | 28 +- doc/debian/jitsi-meet/jitsi-meet.example | 15 +- react/features/base/conference/functions.ts | 28 + react/features/base/config/configType.ts | 1 + resources/extra-large-conference/README.md | 88 + .../imgs/visitors-prosody.svg | 2109 +++++++++++++++++ .../extra-large-conference/pre-configure.sh | 51 + .../prosody-v.service.template | 46 + .../prosody.cfg.lua.visitor.template | 121 + resources/prosody-plugins/mod_certs_all.lua | 16 - .../mod_certs_s2soutinjection.lua | 19 + resources/prosody-plugins/mod_fmuc.lua | 6 - .../prosody-plugins/mod_s2s_whitelist.lua | 20 + .../prosody-plugins/mod_s2soutinjection.lua | 90 + .../prosody-plugins/mod_secure_interfaces.lua | 20 + .../prosody-plugins/mod_xxl_conference.lua | 22 +- 16 files changed, 2639 insertions(+), 41 deletions(-) create mode 100644 resources/extra-large-conference/README.md create mode 100644 resources/extra-large-conference/imgs/visitors-prosody.svg create mode 100755 resources/extra-large-conference/pre-configure.sh create mode 100644 resources/extra-large-conference/prosody-v.service.template create mode 100644 resources/extra-large-conference/prosody.cfg.lua.visitor.template delete mode 100644 resources/prosody-plugins/mod_certs_all.lua create mode 100644 resources/prosody-plugins/mod_certs_s2soutinjection.lua create mode 100644 resources/prosody-plugins/mod_s2s_whitelist.lua create mode 100644 resources/prosody-plugins/mod_s2soutinjection.lua create mode 100644 resources/prosody-plugins/mod_secure_interfaces.lua diff --git a/conference.js b/conference.js index bb9400208..ea4841a39 100644 --- a/conference.js +++ b/conference.js @@ -47,6 +47,7 @@ import { dataChannelClosed, dataChannelOpened, e2eRttChanged, + generateVisitorConfig, getConferenceOptions, kickedOut, lockStateChanged, @@ -277,7 +278,8 @@ class ConferenceConnector { /** * */ - constructor(resolve, reject) { + constructor(resolve, reject, conference) { + this._conference = conference; this._resolve = resolve; this._reject = reject; this.reconnectTimeout = null; @@ -336,6 +338,26 @@ class ConferenceConnector { break; } + case JitsiConferenceErrors.REDIRECTED: { + generateVisitorConfig(APP.store.getState(), params); + + connection.disconnect().then(() => { + connect(this._conference.roomName).then(con => { + const localTracks = getLocalTracks(APP.store.getState()['features/base/tracks']); + + const jitsiTracks = localTracks.map(t => t.jitsiTrack); + + // visitors connect muted + jitsiTracks.forEach(t => t.mute()); + + // TODO disable option to unmute audio or video + this._conference.startConference(con, jitsiTracks); + }); + }); + + break; + } + case JitsiConferenceErrors.GRACEFUL_SHUTDOWN: APP.UI.notifyGracefulShutdown(); break; @@ -732,7 +754,7 @@ export default { // XXX The API will take care of disconnecting from the XMPP // server (and, thus, leaving the room) on unload. return new Promise((resolve, reject) => { - new ConferenceConnector(resolve, reject).connect(); + new ConferenceConnector(resolve, reject, this).connect(); }); }, @@ -1349,7 +1371,7 @@ export default { this._createRoom(localTracks); return new Promise((resolve, reject) => { - new ConferenceConnector(resolve, reject).connect(); + new ConferenceConnector(resolve, reject, this).connect(); }); }, diff --git a/doc/debian/jitsi-meet/jitsi-meet.example b/doc/debian/jitsi-meet/jitsi-meet.example index b470f0642..fd3914ecd 100644 --- a/doc/debian/jitsi-meet/jitsi-meet.example +++ b/doc/debian/jitsi-meet/jitsi-meet.example @@ -15,6 +15,17 @@ upstream jvb1 { server 127.0.0.1:9090; keepalive 2; } +map $arg_vnode $prosody_node { + default prosody; + v1 v1; + v2 v2; + v3 v3; + v4 v4; + v5 v5; + v6 v6; + v7 v7; + v8 v8; +} server { listen 80; listen [::]:80; @@ -95,7 +106,7 @@ server { # BOSH location = /http-bind { - proxy_pass http://prosody/http-bind?prefix=$prefix&$args; + proxy_pass http://$prosody_node/http-bind?prefix=$prefix&$args; proxy_http_version 1.1; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Host $http_host; @@ -104,7 +115,7 @@ server { # xmpp websockets location = /xmpp-websocket { - proxy_pass http://prosody/xmpp-websocket?prefix=$prefix&$args; + proxy_pass http://$prosody_node/xmpp-websocket?prefix=$prefix&$args; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; diff --git a/react/features/base/conference/functions.ts b/react/features/base/conference/functions.ts index 8ff73c5b7..736fff76a 100644 --- a/react/features/base/conference/functions.ts +++ b/react/features/base/conference/functions.ts @@ -252,6 +252,34 @@ export function getConferenceOptions(stateful: IStateful) { return options; } +/** + * Returns an object aggregating the conference options. + * + * @param {IStateful} stateful - The redux store state. + * @param {Array} params - The received parameters. + * @returns {void} + */ +export function generateVisitorConfig(stateful: IStateful, params: Array) { + const [ vnode, focusJid ] = params; + + const config = toState(stateful)['features/base/config']; + + if (!config || !config.hosts) { + logger.warn('Wrong configuration, missing hosts.'); + + return; + } + + const oldDomain = config.hosts.domain; + + config.hosts.domain = `${vnode}.meet.jitsi`; + config.hosts.muc = config.hosts.muc.replace(oldDomain, config.hosts.domain); + config.hosts.visitorFocus = focusJid; + + config.bosh += `?vnode=${vnode}`; + config.websocket += `?vnode=${vnode}`; +} + /** * Returns the UTC timestamp when the first participant joined the conference. * diff --git a/react/features/base/config/configType.ts b/react/features/base/config/configType.ts index 24c1b658d..468deabfc 100644 --- a/react/features/base/config/configType.ts +++ b/react/features/base/config/configType.ts @@ -339,6 +339,7 @@ export interface IConfig { domain: string; focus?: string; muc: string; + visitorFocus: string; }; iAmRecorder?: boolean; iAmSipGateway?: boolean; diff --git a/resources/extra-large-conference/README.md b/resources/extra-large-conference/README.md new file mode 100644 index 000000000..2c324e486 --- /dev/null +++ b/resources/extra-large-conference/README.md @@ -0,0 +1,88 @@ +WARNING: This is still a Work In Progress + +The final implementation may diverge. Currently, only the participants after a +configured threshold will be just viewers (visitors) and there is no promotion +mechanism to become a main participant yet. + +TODO: +* Merge messaging between visitor nodes and main conference +* Polls +* Raise hand to be promoted to enter the main conference +* Make sure it works with tenants. + + +# Low-latency conference streaming to very large audiences + +To have a low-latency conference with a very large audience, the media and +signaling load must be spread beyond what can be handled by a typical Jitsi +installation. A call with 10k participants requires around 50 bridges on decent +vms (8+ cores). The main participants of a conference with a very large +audience will share a main prosody, like with normal conferences, and +additional prosody vms are needed to support signaling to the audience. + +In the example configuration we use a 16 core machine. Eight of the cores are +used for the main prosody and other services (nginx, jicofo, etc) and the other +eight cores are used to run prosody services for visitors, i.e., "visitor +prosodies". + +We consider 2000 participants per visitor node a safe value. So eight visitor +prosodies will be enough for one 10k participants meeting. + +diagram of a central prosody connected to several visitor prosodies + +# Configuration +Use the `pre-configure.sh` script to configure your system, passing it the +number of visitor prosodies to set up. +`./pre-configure.sh 8` + +The script will add for each visitor prosody: +- folders in `/etc/` +- a systemd unit file in `/lib/systemd/system/` +- a user for jicofo +- a config entry in jicofo.conf + +Setting up configuration for the main prosody is a manual process: +- Add to the enabled modules list in the general part (e.g. [here](https://github.com/bjc/prosody/blob/76bf6d511f851c7cde8a81257afaaae0fb7a4160/prosody.cfg.lua.dist#L33)): +``` + "s2s_bidi"; + "certs_s2soutinjection"; + "s2soutinjection"; + "s2s_whitelist"; +``` + +- Add the following config also in the general part (matching the number of prosodies you generated config for): +``` +-- targets must be IPs, not hostnames +s2s_connect_overrides = { + ["conference.v1.meet.jitsi"] = { "127.0.0.1", 52691 }; + ["conference.v2.meet.jitsi"] = { "127.0.0.1", 52692 }; + ["conference.v3.meet.jitsi"] = { "127.0.0.1", 52693 }; + ["conference.v4.meet.jitsi"] = { "127.0.0.1", 52694 }; + ["conference.v5.meet.jitsi"] = { "127.0.0.1", 52695 }; + ["conference.v6.meet.jitsi"] = { "127.0.0.1", 52696 }; + ["conference.v7.meet.jitsi"] = { "127.0.0.1", 52697 }; + ["conference.v8.meet.jitsi"] = { "127.0.0.1", 52698 }; +} +-- allowed list of server-2-server connections +s2s_whitelist = { + "conference.v1.meet.jitsi", "conference.v2.meet.jitsi", "conference.v3.meet.jitsi", "conference.v4.meet.jitsi", + "conference.v5.meet.jitsi", "conference.v6.meet.jitsi", "conference.v7.meet.jitsi", "conference.v8.meet.jitsi" +}; +``` + +- Make sure s2s is not in modules_disabled +- Enable `"xxl_conference";` module under the main virtual host (e.g. [here](https://github.com/jitsi/jitsi-meet/blob/f42772ec5bcc87ff6de17423d36df9bcad6e770d/doc/debian/jitsi-meet-prosody/prosody.cfg.lua-jvb.example#L57)) + +After configuring you can set the maximum number of main participants, before +redirecting to visitors. +``` +hocon -f /etc/jitsi/jicofo/jicofo.conf set "jicofo.visitors.max-participants" 30 +``` +Now restart prosody and jicofo +``` +service prosody restart +service jicofo restart +``` + +Now after the main 30 participants join, the rest will be visitors using the +visitor nodes. diff --git a/resources/extra-large-conference/imgs/visitors-prosody.svg b/resources/extra-large-conference/imgs/visitors-prosody.svg new file mode 100644 index 000000000..6e51cd139 --- /dev/null +++ b/resources/extra-large-conference/imgs/visitors-prosody.svg @@ -0,0 +1,2109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Canvas 1 + + Layer 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + P + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + v3 + + + + + + + + + + v4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + v1 + + + + + + + v2 + + + + + + + v5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/extra-large-conference/pre-configure.sh b/resources/extra-large-conference/pre-configure.sh new file mode 100755 index 000000000..7375157d2 --- /dev/null +++ b/resources/extra-large-conference/pre-configure.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +SCRIPT_DIR=`dirname "$0"` +cd $SCRIPT_DIR + +NUMBER_OF_INSTANCES=$1 + +if ! [[ $NUMBER_OF_INSTANCES =~ ^[0-9]+([.][0-9]+)?$ ]] ; then + echo "error: Not a number param" >&2; + exit 1 +fi + +echo "Will configure $NUMBER_OF_INSTANCES number of visitor prosodies" +set -e +set -x + +# Configure prosody instances +for (( i=1 ; i<=${NUMBER_OF_INSTANCES} ; i++ )); +do + cp prosody-v.service.template /lib/systemd/system/prosody-v${i}.service + sed -i "s/vX/v${i}/g" /lib/systemd/system/prosody-v${i}.service + mkdir /etc/prosody-v${i} + ln -s /etc/prosody/certs /etc/prosody-v${i}/certs + cp prosody.cfg.lua.visitor.template /etc/prosody-v${i}/prosody.cfg.lua + sed -i "s/vX/v${i}/g" /etc/prosody-v${i}/prosody.cfg.lua +done + +# Configure jicofo +HOCON_CONFIG="/etc/jitsi/jicofo/jicofo.conf" +hocon -f $HOCON_CONFIG set "jicofo.bridge.selection-strategy" "VisitorSelectionStrategy" +hocon -f $HOCON_CONFIG set "jicofo.bridge.visitor-selection-strategy" "RegionBasedBridgeSelectionStrategy" +hocon -f $HOCON_CONFIG set "jicofo.bridge.topology-strategy" "VisitorTopologyStrategy" + +PASS=$(hocon -f $HOCON_CONFIG get "jicofo.xmpp.client.password") +for (( i=1 ; i<=${NUMBER_OF_INSTANCES} ; i++ )); +do + prosodyctl --config /etc/prosody-v${i}/prosody.cfg.lua register focus auth.meet.jitsi $PASS + hocon -f $HOCON_CONFIG set "jicofo.xmpp.visitors.v${i}.enabled" true + hocon -f $HOCON_CONFIG set "jicofo.xmpp.visitors.v${i}.conference-service" "conference.v${i}.meet.jitsi" + hocon -f $HOCON_CONFIG set "jicofo.xmpp.visitors.v${i}.hostname" 127.0.0.1 + hocon -f $HOCON_CONFIG set "jicofo.xmpp.visitors.v${i}.port" 5222${i} + hocon -f $HOCON_CONFIG set "jicofo.xmpp.visitors.v${i}.domain" "auth.meet.jitsi" + hocon -f $HOCON_CONFIG set "jicofo.xmpp.visitors.v${i}.password" "${PASS}" + hocon -f $HOCON_CONFIG set "jicofo.xmpp.visitors.v${i}.disable-certificate-verification" true +done + +for (( i=1 ; i<=${NUMBER_OF_INSTANCES} ; i++ )); +do + service prosody-v${i} restart +done +service jicofo restart diff --git a/resources/extra-large-conference/prosody-v.service.template b/resources/extra-large-conference/prosody-v.service.template new file mode 100644 index 000000000..b37dcdfa7 --- /dev/null +++ b/resources/extra-large-conference/prosody-v.service.template @@ -0,0 +1,46 @@ +[Unit] +### see man systemd.unit +Description=Prosody vX (visitor vX) JVB XMPP Server +Documentation=https://prosody.im/doc + +Requires=network-online.target +After=network-online.target network.target mariadb.service mysql.service postgresql.service +Before=biboumi.service + +[Service] +### see man systemd.service +Type=simple + +# Start by executing the main executable +# Note: -F option requires Prosody 0.11.5 or later +ExecStart=/usr/bin/prosody --config /etc/prosody-vX/prosody.cfg.lua -F +ExecReload=/bin/kill -HUP $MAINPID +Restart=on-abnormal + +### see man systemd.exec +User=prosody +Group=prosody +UMask=0027 + +RuntimeDirectory=prosody-vX +ConfigurationDirectory=prosody-vX +StateDirectory=prosody-vX +StateDirectoryMode=0750 +LogsDirectory=prosody-vX +WorkingDirectory=~ + +# Set stdin to /dev/null since Prosody does not need it +StandardInput=null + +# Direct stdout/-err to journald for use with log = "*stdout" +StandardOutput=journal +StandardError=inherit + +# Allow binding low ports +AmbientCapabilities=CAP_NET_BIND_SERVICE + +[Install] +### see man systemd.unit +WantedBy=multi-user.target + +# vim: filetype=systemd diff --git a/resources/extra-large-conference/prosody.cfg.lua.visitor.template b/resources/extra-large-conference/prosody.cfg.lua.visitor.template new file mode 100644 index 000000000..329713fc5 --- /dev/null +++ b/resources/extra-large-conference/prosody.cfg.lua.visitor.template @@ -0,0 +1,121 @@ +---------- Server-wide settings ---------- +s2s_ports = { 52691 }; +c2s_ports = { 52221 } +http_ports = { 52801 } +https_ports = { 52811 } + +daemonize = true; + +-- we use a common jid for jicofo +admins = { + 'focus@auth.meet.jitsi' +} + +-- Enable use of native prosody 0.11 support for epoll over select +network_backend = 'epoll'; +network_settings = { + tcp_backlog = 511; +} + +modules_enabled = { + 'saslauth'; + 'tls'; + 'disco'; + 'posix'; + + 'secure_interfaces'; + + -- jitsi + 'websocket'; + 'bosh'; + 's2s_bidi'; + 's2s_whitelist'; +}; + +s2s_whitelist = {}; + +external_service_secret = '__turnSecret__'; + +external_services = { + { type = 'stun', host = 'jitmeet.example.com', port = 3478 }, + { type = 'turn', host = 'jitmeet.example.com', port = 3478, transport = 'udp', secret = true, ttl = 86400, algorithm = 'turn' }, + { type = 'turns', host = 'jitmeet.example.com', port = 5349, transport = 'tcp', secret = true, ttl = 86400, algorithm = 'turn' } +}; + +muc_mapper_domain_base = 'vX.meet.jitsi'; + +-- https://prosody.im/doc/modules/mod_smacks +smacks_max_unacked_stanzas = 5; +smacks_hibernation_time = 60; +-- this is dropped in 0.12 +smacks_max_hibernated_sessions = 1; +smacks_max_old_sessions = 1; + +unlimited_jids = { 'focus@auth.meet.jitsi' } +limits = { + c2s = { + rate = '512kb/s'; + }; +} + +modules_disabled = { + 'offline'; + 'pubsub'; + 'register'; +}; + +allow_registration = false; +authentication = 'internal_hashed' +storage = 'internal' +log = { + -- Log files (change 'info' to 'debug' for debug logs): + info = '/var/log/prosody-vX/prosody.log'; + error = '/var/log/prosody-vX/prosody.err'; +} + +consider_websocket_secure = true; +consider_bosh_secure = true; +bosh_max_inactivity = 60; + +plugin_paths = { '/usr/share/jitsi-meet/prosody-plugins/' } + +----------- Virtual hosts ----------- +VirtualHost 'vX.meet.jitsi' + authentication = 'jitsi-anonymous' + ssl = { + key = '/etc/prosody/certs/jitmeet.example.com.key'; + certificate = '/etc/prosody/certs/jitmeet.example.com.crt'; + } + modules_enabled = { + 'bosh'; + 'ping'; + 'external_services'; + 'smacks'; + 'jiconop'; + } + main_muc = 'conference.vX.meet.jitsi'; + +VirtualHost 'auth.meet.jitsi' + modules_enabled = { + 'limits_exception'; + 'ping'; + } + authentication = 'internal_hashed' + +Component 'conference.vX.meet.jitsi' 'muc' + storage = 'memory' + muc_room_cache_size = 10000 + restrict_room_creation = true + modules_enabled = { + 'muc_hide_all'; + 'muc_domain_mapper'; + 'muc_meeting_id'; + 'fmuc'; + } + muc_room_default_presence_broadcast = { + visitor = false; + participant = true; + moderator = true; + }; + muc_room_locking = false + muc_room_default_public_jids = true diff --git a/resources/prosody-plugins/mod_certs_all.lua b/resources/prosody-plugins/mod_certs_all.lua deleted file mode 100644 index 8d716feb6..000000000 --- a/resources/prosody-plugins/mod_certs_all.lua +++ /dev/null @@ -1,16 +0,0 @@ --- validates all certificates, global module --- Warning: use this only for testing purposes as it will accept all kind of certificates for s2s connections --- you can use https://modules.prosody.im/mod_s2s_whitelist.html for whitelisting only certain destinations -module:set_global(); - -function attach(event) - local session = event.session; - - session.cert_chain_status = 'valid'; - session.cert_identity_status = 'valid'; - - return true; -end -module:wrap_event('s2s-check-certificate', function (handlers, event_name, event_data) - return attach(event_data); -end); diff --git a/resources/prosody-plugins/mod_certs_s2soutinjection.lua b/resources/prosody-plugins/mod_certs_s2soutinjection.lua new file mode 100644 index 000000000..33c1fd1ff --- /dev/null +++ b/resources/prosody-plugins/mod_certs_s2soutinjection.lua @@ -0,0 +1,19 @@ +-- global module +-- validates certificates for all hosts used for s2soutinjection +module:set_global(); + +local s2s_overrides = module:get_option("s2s_connect_overrides"); + +function attach(event) + local session = event.session; + + if s2s_overrides and s2s_overrides[event.host] then + session.cert_chain_status = 'valid'; + session.cert_identity_status = 'valid'; + + return true; + end +end +module:wrap_event('s2s-check-certificate', function (handlers, event_name, event_data) + return attach(event_data); +end); diff --git a/resources/prosody-plugins/mod_fmuc.lua b/resources/prosody-plugins/mod_fmuc.lua index a867832bf..d5ed60584 100644 --- a/resources/prosody-plugins/mod_fmuc.lua +++ b/resources/prosody-plugins/mod_fmuc.lua @@ -7,12 +7,6 @@ --- }; --- Enable in global modules: 's2s_bidi' --- Make sure 's2s' is not in modules_disabled ---- TODO: Do we need the /etc/hosts changes? We can drop it for https://modules.prosody.im/mod_s2soutinjection.html ---- In /etc/hosts add: ---- vmmain-ip-address focus.domain.com ---- vmmain-ip-address conference.domain.com ---- vmmain-ip-address domain.com ---- Open port 5269 on the provider side and on the firewall of the machine, so the core node can access this visitor one local jid = require 'util.jid'; local st = require 'util.stanza'; diff --git a/resources/prosody-plugins/mod_s2s_whitelist.lua b/resources/prosody-plugins/mod_s2s_whitelist.lua new file mode 100644 index 000000000..c2f28040a --- /dev/null +++ b/resources/prosody-plugins/mod_s2s_whitelist.lua @@ -0,0 +1,20 @@ +-- Using version https://hg.prosody.im/prosody-modules/file/c1a8ce147885/mod_s2s_whitelist/mod_s2s_whitelist.lua +local st = require "util.stanza"; + +local whitelist = module:get_option_inherited_set("s2s_whitelist", {}); + +module:hook("route/remote", function (event) + if not whitelist:contains(event.to_host) then + module:send(st.error_reply(event.stanza, "cancel", "not-allowed", "Communication with this domain is restricted")); + return true; + end +end, 100); + +module:hook("s2s-stream-features", function (event) + if not whitelist:contains(event.origin.from_host) then + event.origin:close({ + condition = "policy-violation"; + text = "Communication with this domain is restricted"; + }); + end +end, 1000); diff --git a/resources/prosody-plugins/mod_s2soutinjection.lua b/resources/prosody-plugins/mod_s2soutinjection.lua new file mode 100644 index 000000000..d92f7023a --- /dev/null +++ b/resources/prosody-plugins/mod_s2soutinjection.lua @@ -0,0 +1,90 @@ +-- Using version https://hg.prosody.im/prosody-modules/file/4fb922aa0ace/mod_s2soutinjection/mod_s2soutinjection.lua +local st = require"util.stanza"; +local new_outgoing = require"core.s2smanager".new_outgoing; +local bounce_sendq = module:depends"s2s".route_to_new_session.bounce_sendq; +local initialize_filters = require "util.filters".initialize; + +local portmanager = require "core.portmanager"; + +local addclient = require "net.server".addclient; + +module:depends("s2s"); + +local sessions = module:shared("sessions"); + +local injected = module:get_option("s2s_connect_overrides"); + +-- The proxy_listener handles connection while still connecting to the proxy, +-- then it hands them over to the normal listener (in mod_s2s) +local proxy_listener = { default_port = nil, default_mode = "*a", default_interface = "*" }; + +function proxy_listener.onconnect(conn) + local session = sessions[conn]; + + -- Now the real s2s listener can take over the connection. + local listener = portmanager.get_service("s2s").listener; + + local log = session.log; + + local filter = initialize_filters(session); + + session.version = 1; + + session.sends2s = function (t) + log("debug", "sending (s2s over proxy): %s", (t.top_tag and t:top_tag()) or t:match("^[^>]*>?")); + if t.name then + t = filter("stanzas/out", t); + end + if t then + t = filter("bytes/out", tostring(t)); + if t then + return conn:write(tostring(t)); + end + end + end + + session.open_stream = function () + session.sends2s(st.stanza("stream:stream", { + xmlns='jabber:server', ["xmlns:db"]='jabber:server:dialback', + ["xmlns:stream"]='http://etherx.jabber.org/streams', + from=session.from_host, to=session.to_host, version='1.0', ["xml:lang"]='en'}):top_tag()); + end + + conn.setlistener(conn, listener); + + listener.register_outgoing(conn, session); + + listener.onconnect(conn); +end + +function proxy_listener.register_outgoing(conn, session) + session.direction = "outgoing"; + sessions[conn] = session; +end + +function proxy_listener.ondisconnect(conn, err) + sessions[conn] = nil; +end + +module:hook("route/remote", function(event) + local from_host, to_host, stanza = event.from_host, event.to_host, event.stanza; + local inject = injected and injected[to_host]; + if not inject then return end + module:log("debug", "opening a new outgoing connection for this stanza"); + local host_session = new_outgoing(from_host, to_host); + + -- Store in buffer + host_session.bounce_sendq = bounce_sendq; + host_session.sendq = { {tostring(stanza), stanza.attr.type ~= "error" and stanza.attr.type ~= "result" and st.reply(stanza)} }; + host_session.log("debug", "stanza [%s] queued until connection complete", tostring(stanza.name)); + + local host, port = inject[1] or inject, tonumber(inject[2]) or 5269; + + local conn = addclient(host, port, proxy_listener, "*a"); + + proxy_listener.register_outgoing(conn, host_session); + + host_session.conn = conn; + return true; +end, -2); + diff --git a/resources/prosody-plugins/mod_secure_interfaces.lua b/resources/prosody-plugins/mod_secure_interfaces.lua new file mode 100644 index 000000000..9816f26a5 --- /dev/null +++ b/resources/prosody-plugins/mod_secure_interfaces.lua @@ -0,0 +1,20 @@ +-- Using version https://hg.prosody.im/prosody-modules/file/6c806a99f802/mod_secure_interfaces/mod_secure_interfaces.lua +local secure_interfaces = module:get_option_set("secure_interfaces", { "127.0.0.1", "::1" }); + +module:hook("stream-features", function (event) + local session = event.origin; + if session.type ~= "c2s_unauthed" then return; end + local socket = session.conn:socket(); + if not socket.getsockname then + module:log("debug", "Unable to determine local address of incoming connection"); + return; + end + local localip = socket:getsockname(); + if secure_interfaces:contains(localip) then + module:log("debug", "Marking session from %s to %s as secure", session.ip or "[?]", localip); + session.secure = true; + session.conn.starttls = false; + else + module:log("debug", "Not marking session from %s to %s as secure", session.ip or "[?]", localip); + end +end, 2500); diff --git a/resources/prosody-plugins/mod_xxl_conference.lua b/resources/prosody-plugins/mod_xxl_conference.lua index 8fa942f2d..e93fcfc2a 100644 --- a/resources/prosody-plugins/mod_xxl_conference.lua +++ b/resources/prosody-plugins/mod_xxl_conference.lua @@ -56,29 +56,23 @@ local visitors_nodes = {}; --- Jicofo is connected to the room when sending this error module:log('info', 'Hook to iq/host'); module:hook('iq/full', function(event) - local session, stanza = event.origin, event.stanza; + local stanza = event.stanza; - if stanza.name ~= 'iq' or stanza.attr.type ~= 'error' or stanza.attr.from ~= focus_component_host then + if stanza.name ~= 'iq' or stanza.attr.type ~= 'result' or stanza.attr.from ~= focus_component_host then return; -- not IQ from jicofo. Ignore this event. end - local error = stanza:get_child('error'); - if error == nil then - return; -- not Conference IQ error. Ignore. - end - - local redirect = error:get_child('redirect', 'urn:ietf:params:xml:ns:xmpp-stanzas'); - local redirect_host = error:get_child_text('url', 'http://jitsi.org/jitmeet'); - - if not redirect or not redirect_host then + local conference = stanza:get_child('conference', 'http://jitsi.org/protocol/focus'); + if not conference then return; end -- let's send participants if any from the room to the visitors room -- TODO fix room name extract, make sure it works wit tenants - local main_room = error:get_child_text('main-room', 'http://jitsi.org/jitmeet'); + local main_room = conference.attr.room; + local vnode = conference.attr.vnode; - if not main_room then + if not main_room or not vnode then return; end @@ -88,7 +82,7 @@ module:hook('iq/full', function(event) return; -- room does not exists. Continue with normal flow end - local conference_service = muc_domain_prefix..'.'..redirect_host; + local conference_service = muc_domain_prefix..'.'..vnode..'.meet.jitsi'; if visitors_nodes[room.jid] and visitors_nodes[room.jid].nodes and