From 02b2fe4d2be8f2aa90eb8491f4c330fd53ea7885 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 4 Feb 2021 00:49:07 +0100 Subject: prosody.cfg.lua.dist: Add note about 'localhost' --- prosody.cfg.lua.dist | 3 +++ 1 file changed, 3 insertions(+) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 5dfa68b8..ade77ff4 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -196,6 +196,9 @@ certificates = "certs" -- Settings under each VirtualHost entry apply *only* to that host. VirtualHost "localhost" +-- Prosody requires at least one enabled VirtualHost to function. You can +-- safely remove or disable 'localhost' once you have added another. + --VirtualHost "example.com" -- certificate = "/path/to/example.crt" -- cgit v1.2.3 From 225e6d21e823b7199d41f58b8b661a298c78347a Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 10 Feb 2022 18:02:59 +0100 Subject: prosody.cfg.lua.dist: Add new modules mod_admin_shell enabled by default because it's awesome! mod_smacks and mod_bookmarks under recommended since they're recommended by the compliance suite XEP-0459 Invites under nice to have and enabled by default to enable a somewhat nice out of the box experience Other new modules mostly under Other mod_external_services left out since it's an advanced thing --- prosody.cfg.lua.dist | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index ade77ff4..b1a1c323 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -56,6 +56,8 @@ modules_enabled = { "vcard4"; -- User profiles (stored in PEP) "vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard "limits"; -- Enable bandwidth limiting for XMPP connections + "bookmarks"; -- Synchronise open rooms between clients + "smacks"; -- Stream management and resumption (XEP-0198) -- Nice to have "version"; -- Replies to server version requests @@ -63,17 +65,23 @@ modules_enabled = { "time"; -- Let others know the time here on this server "ping"; -- Replies to XMPP pings with pongs "register"; -- Allow users to register on this server using a client and change passwords + "invites"; -- Create and manage invites + "invites_register"; -- Create accounts using invites + "invites_adhoc"; -- Create invites via AdHoc command --"mam"; -- Store messages in an archive and allow users to access it --"csi_simple"; -- Simple Mobile optimizations + --"turn_external"; -- Provide external TURN (and STUN) service -- Admin interfaces "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands --"admin_telnet"; -- Opens telnet console interface on localhost port 5582 + "admin_shell"; -- Allow secure administration via an UNIX socket -- HTTP modules --"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP" --"websocket"; -- XMPP over WebSockets --"http_files"; -- Serve static files from a directory over HTTP + --"http_openmetrics"; -- for exposing metrics to stats collectors -- Other specific functionality --"groups"; -- Shared roster support @@ -84,6 +92,9 @@ modules_enabled = { --"motd"; -- Send a message to users when they log in --"legacyauth"; -- Legacy authentication. Only used by some old clients and bots. --"proxy65"; -- Enables a file transfer proxy service which clients behind NAT can use + --"mimicking"; -- Prevent address spoofing + --"tombstones"; -- Prevent registration of deleted accounts + --"s2s_bidi"; -- Bi-directional server-to-server (XEP-0288) } -- These modules are auto-loaded, but should you want @@ -213,6 +224,9 @@ VirtualHost "localhost" --- Store MUC messages in an archive and allow users to access it --modules_enabled = { "muc_mam" } +---Set up a file sharing component +--Component "share.example.com" "http_file_share" + ---Set up an external component (default component port is 5347) -- -- External components allow adding various services, such as gateways/ -- cgit v1.2.3 From a37682ba2e398eabeb3de0b14760488ae121bba7 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 5 Feb 2022 18:10:41 +0100 Subject: prosody.cfg.lua.dist: Remove installer_plugin_path Most users shouldn't need to add this, and it works out of the box. Not important enough to justify having it in the default config. --- prosody.cfg.lua.dist | 4 ---- 1 file changed, 4 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index b1a1c323..03413ef8 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -32,10 +32,6 @@ admins = { } -- will look for modules first. For community modules, see https://modules.prosody.im/ --plugin_paths = {} --- Single directory for custom prosody plugins and/or Lua libraries installation --- This path takes priority over plugin_paths, when prosody is searching for modules ---installer_plugin_path = "" - -- This is the list of modules Prosody will load on startup. -- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too. -- Documentation for bundled modules can be found at: https://prosody.im/doc/modules -- cgit v1.2.3 From c8515415ec9ea46ced67cd7a9e74e9a4c3abebce Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 5 Feb 2022 18:14:17 +0100 Subject: prosody.cfg.lua.dist: Remove mention of deprecated daemonize option Just run ./prosody like me! --- prosody.cfg.lua.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 03413ef8..7f25f36d 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -178,7 +178,7 @@ log = { info = "prosody.log"; -- Change 'info' to 'debug' for verbose logging error = "prosody.err"; -- "*syslog"; -- Uncomment this for logging to syslog - -- "*console"; -- Log to the console, useful for debugging with daemonize=false + -- "*console"; -- Log to the console, useful for debugging when running in the foreground } -- Uncomment to enable statistics -- cgit v1.2.3 From 99e90a99142facdeffd4af56ae1c7b8360609c9e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 5 Feb 2022 18:17:52 +0100 Subject: prosody.cfg.lua.dist: Remove https_certificate, this should Just Work now --- prosody.cfg.lua.dist | 3 --- 1 file changed, 3 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 7f25f36d..d3796f63 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -195,9 +195,6 @@ log = { -- Location of directory to find certificates in (relative to main config file): certificates = "certs" --- HTTPS currently only supports a single certificate, specify it here: ---https_certificate = "certs/localhost.crt" - ----------- Virtual hosts ----------- -- You need to add a VirtualHost entry for each domain you wish Prosody to serve. -- Settings under each VirtualHost entry apply *only* to that host. -- cgit v1.2.3 From deccf683d20f69e3f5dbfef349e34767191bb466 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 10 Feb 2022 17:15:18 +0100 Subject: prosody.cfg.lua.dist: Move Dialback down Mostly a source of security issues lately --- prosody.cfg.lua.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index d3796f63..f2a80e52 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -41,7 +41,6 @@ modules_enabled = { "roster"; -- Allow users to have a roster. Recommended ;) "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in. "tls"; -- Add support for secure TLS on c2s/s2s connections - "dialback"; -- s2s dialback support "disco"; -- Service discovery -- Not essential, but recommended @@ -54,6 +53,7 @@ modules_enabled = { "limits"; -- Enable bandwidth limiting for XMPP connections "bookmarks"; -- Synchronise open rooms between clients "smacks"; -- Stream management and resumption (XEP-0198) + "dialback"; -- s2s dialback support -- Nice to have "version"; -- Replies to server version requests -- cgit v1.2.3 From ca1d202df0464ad72e98d7d341c407d271d7d64a Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 10 Feb 2022 18:35:39 +0100 Subject: prosody.cfg.lua.dist: Remove mod_http_files Serving web pages outside of specialized modules seems like a rare use case that doesn't warrant a spot in the default config file. Many users seem to have it confused with mod_http_upload, so removing it should help with that. --- prosody.cfg.lua.dist | 1 - 1 file changed, 1 deletion(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index f2a80e52..0d6c2ef4 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -76,7 +76,6 @@ modules_enabled = { -- HTTP modules --"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP" --"websocket"; -- XMPP over WebSockets - --"http_files"; -- Serve static files from a directory over HTTP --"http_openmetrics"; -- for exposing metrics to stats collectors -- Other specific functionality -- cgit v1.2.3 From a53ffcca735a64ed727e38d9f440a75b08b0ab9b Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 10 Feb 2022 15:48:34 +0000 Subject: mod_legacyauth: Default to require encryption --- plugins/mod_legacyauth.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_legacyauth.lua b/plugins/mod_legacyauth.lua index 941806d3..52f2c143 100644 --- a/plugins/mod_legacyauth.lua +++ b/plugins/mod_legacyauth.lua @@ -12,7 +12,7 @@ local st = require "util.stanza"; local t_concat = table.concat; local secure_auth_only = module:get_option("c2s_require_encryption", - module:get_option("require_encryption")) + module:get_option("require_encryption", true)) or not(module:get_option("allow_unencrypted_plain_auth")); local sessionmanager = require "core.sessionmanager"; -- cgit v1.2.3 From a02e872f8651ea4729697bd7ccc88f7f952c3f04 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 10 Feb 2022 15:49:01 +0000 Subject: mod_invites_register: Default to require encryption In line with the Prosody-wide default change for 0.12. --- plugins/mod_invites_register.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_invites_register.lua b/plugins/mod_invites_register.lua index e02b5bc0..9a5570ab 100644 --- a/plugins/mod_invites_register.lua +++ b/plugins/mod_invites_register.lua @@ -4,7 +4,7 @@ local jid_bare = require "util.jid".bare; local rostermanager = require "core.rostermanager"; local require_encryption = module:get_option_boolean("c2s_require_encryption", - module:get_option_boolean("require_encryption", false)); + module:get_option_boolean("require_encryption", true)); local invite_only = module:get_option_boolean("registration_invite_only", true); local invites; -- cgit v1.2.3 From 73d1bb12184cd5bc91c5996ecc574149d9637d73 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 25 Dec 2021 16:23:40 +0100 Subject: various: Require encryption by default for real These options have been specified (and enabled) in the default config file for a long time. However if unspecified in the config, they were not enabled. Now they are. This may result in a change of behaviour for people using very old config files that lack the require_encryption options. But that's what we want. --- CHANGES | 1 + plugins/mod_register_ibr.lua | 2 +- plugins/mod_s2s.lua | 2 +- plugins/mod_s2s_bidi.lua | 2 +- plugins/mod_saslauth.lua | 2 +- plugins/mod_tls.lua | 4 ++-- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index 9bd2182e..83efa5c2 100644 --- a/CHANGES +++ b/CHANGES @@ -33,6 +33,7 @@ TRUNK - Pluggable authorization providers (mod_authz_) - Easy use of Mozilla TLS recommendations presets - Unencrypted HTTP port (5280) restricted to loopback by default +- require_encryption options default to 'true' if unspecified ### HTTP diff --git a/plugins/mod_register_ibr.lua b/plugins/mod_register_ibr.lua index 83d284c8..8042de7e 100644 --- a/plugins/mod_register_ibr.lua +++ b/plugins/mod_register_ibr.lua @@ -18,7 +18,7 @@ local util_error = require "util.error"; local additional_fields = module:get_option("additional_registration_fields", {}); local require_encryption = module:get_option_boolean("c2s_require_encryption", - module:get_option_boolean("require_encryption", false)); + module:get_option_boolean("require_encryption", true)); pcall(function () module:depends("register_limits"); diff --git a/plugins/mod_s2s.lua b/plugins/mod_s2s.lua index 836cf347..655cb599 100644 --- a/plugins/mod_s2s.lua +++ b/plugins/mod_s2s.lua @@ -40,7 +40,7 @@ local opt_keepalives = module:get_option_boolean("s2s_tcp_keepalives", module:ge local secure_auth = module:get_option_boolean("s2s_secure_auth", false); -- One day... local secure_domains, insecure_domains = module:get_option_set("s2s_secure_domains", {})._items, module:get_option_set("s2s_insecure_domains", {})._items; -local require_encryption = module:get_option_boolean("s2s_require_encryption", false); +local require_encryption = module:get_option_boolean("s2s_require_encryption", true); local stanza_size_limit = module:get_option_number("s2s_stanza_size_limit", 1024*512); local measure_connections_inbound = module:metric( diff --git a/plugins/mod_s2s_bidi.lua b/plugins/mod_s2s_bidi.lua index 28e047de..addcd6e2 100644 --- a/plugins/mod_s2s_bidi.lua +++ b/plugins/mod_s2s_bidi.lua @@ -10,7 +10,7 @@ local st = require "util.stanza"; local xmlns_bidi_feature = "urn:xmpp:features:bidi" local xmlns_bidi = "urn:xmpp:bidi"; -local require_encryption = module:get_option_boolean("s2s_require_encryption", false); +local require_encryption = module:get_option_boolean("s2s_require_encryption", true); module:hook("s2s-stream-features", function(event) local origin, features = event.origin, event.features; diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua index 212b977a..30d7acfa 100644 --- a/plugins/mod_saslauth.lua +++ b/plugins/mod_saslauth.lua @@ -17,7 +17,7 @@ local errors = require "util.error"; local usermanager_get_sasl_handler = require "core.usermanager".get_sasl_handler; -local secure_auth_only = module:get_option_boolean("c2s_require_encryption", module:get_option_boolean("require_encryption", false)); +local secure_auth_only = module:get_option_boolean("c2s_require_encryption", module:get_option_boolean("require_encryption", true)); local allow_unencrypted_plain_auth = module:get_option_boolean("allow_unencrypted_plain_auth", false) local insecure_mechanisms = module:get_option_set("insecure_sasl_mechanisms", allow_unencrypted_plain_auth and {} or {"PLAIN", "LOGIN"}); local disabled_mechanisms = module:get_option_set("disable_sasl_mechanisms", { "DIGEST-MD5" }); diff --git a/plugins/mod_tls.lua b/plugins/mod_tls.lua index 9b80486a..afc1653a 100644 --- a/plugins/mod_tls.lua +++ b/plugins/mod_tls.lua @@ -10,8 +10,8 @@ local create_context = require "core.certmanager".create_context; local rawgetopt = require"core.configmanager".rawget; local st = require "util.stanza"; -local c2s_require_encryption = module:get_option("c2s_require_encryption", module:get_option("require_encryption")); -local s2s_require_encryption = module:get_option("s2s_require_encryption"); +local c2s_require_encryption = module:get_option("c2s_require_encryption", module:get_option("require_encryption", true)); +local s2s_require_encryption = module:get_option("s2s_require_encryption", true); local allow_s2s_tls = module:get_option("s2s_allow_encryption") ~= false; local s2s_secure_auth = module:get_option("s2s_secure_auth"); -- cgit v1.2.3 From 406b90d31deb1578a545401e0be190d11f2f6aba Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 10 Feb 2022 17:15:55 +0100 Subject: core.certmanager: Turn soft dependency on LuaSec into a hard The default network backend server_epoll already requires LuaSec so Prosody won't even start without it, so we can get rid of these lines here too. --- core/certmanager.lua | 16 +++------------- util/dependencies.lua | 2 +- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/core/certmanager.lua b/core/certmanager.lua index 684b240c..2585716f 100644 --- a/core/certmanager.lua +++ b/core/certmanager.lua @@ -6,20 +6,10 @@ -- COPYING file in the source package for more information. -- -local softreq = require"util.dependencies".softreq; -local ssl = softreq"ssl"; -if not ssl then - return { - create_context = function () - return nil, "LuaSec (required for encryption) was not found"; - end; - reload_ssl_config = function () end; - } -end - +local ssl = require "ssl"; local configmanager = require "core.configmanager"; local log = require "util.logger".init("certmanager"); -local ssl_context = ssl.context or softreq"ssl.context"; +local ssl_context = ssl.context or require "ssl.context"; local ssl_newcontext = ssl.newcontext; local new_config = require"util.sslconfig".new; local stat = require "lfs".attributes; @@ -48,7 +38,7 @@ end local luasec_major, luasec_minor = ssl._VERSION:match("^(%d+)%.(%d+)"); local luasec_version = tonumber(luasec_major) * 100 + tonumber(luasec_minor); -local luasec_has = ssl.config or softreq"ssl.config" or { +local luasec_has = ssl.config or { algorithms = { ec = luasec_version >= 5; }; diff --git a/util/dependencies.lua b/util/dependencies.lua index 4cd45a05..d7836404 100644 --- a/util/dependencies.lua +++ b/util/dependencies.lua @@ -85,7 +85,7 @@ local function check_dependencies() { "Debian/Ubuntu", "sudo apt install lua-sec" }; { "luarocks", "luarocks install luasec" }; { "Source", "https://github.com/brunoos/luasec" }; - }, "SSL/TLS support will not be available", err); + }, nil, err); end local bit, err = softreq"util.bitcompat"; -- cgit v1.2.3 From ecf01c937d3fd7289a53bdba402e00a36a1c10c0 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 14 Feb 2022 15:58:08 +0000 Subject: prosody.cfg.lua.dist: Remove require_encryption options Reasons: - These now default to enabled when not specified since 38b5b05407be - Practically all servers require encryption these days for c2s/s2s. - Disabling encryption can be considered a special case that doesn't need to be in the default config file. --- prosody.cfg.lua.dist | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 0d6c2ef4..54426d6f 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -105,16 +105,6 @@ modules_disabled = { -- For more information see https://prosody.im/doc/creating_accounts allow_registration = false --- Force clients to use encrypted connections? This option will --- prevent clients from authenticating unless they are using encryption. - -c2s_require_encryption = true - --- Force servers to use encrypted connections? This option will --- prevent servers from authenticating unless they are using encryption. - -s2s_require_encryption = true - -- Force certificate authentication for server-to-server connections? s2s_secure_auth = false -- cgit v1.2.3 From 067a0ad4d8e8831f5cac75099926d60a7bad6323 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 10 Feb 2022 19:54:14 +0000 Subject: usermanager, mod_saslauth: Default to internal_hashed if no auth module specified The default config was updated in this way long ago, but if no option was present in the config, Prosody would load internal_plain. This change can result in changes (for the better) for people using very old configuration files lacking an 'authentication' setting. --- CHANGES | 1 + core/usermanager.lua | 2 +- plugins/mod_saslauth.lua | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 83efa5c2..8e3a556c 100644 --- a/CHANGES +++ b/CHANGES @@ -34,6 +34,7 @@ TRUNK - Easy use of Mozilla TLS recommendations presets - Unencrypted HTTP port (5280) restricted to loopback by default - require_encryption options default to 'true' if unspecified +- Authentication module defaults to 'internal_hashed' if unspecified ### HTTP diff --git a/core/usermanager.lua b/core/usermanager.lua index ca4e2baa..45f104fa 100644 --- a/core/usermanager.lua +++ b/core/usermanager.lua @@ -23,7 +23,7 @@ local hosts = prosody.hosts; local setmetatable = setmetatable; -local default_provider = "internal_plain"; +local default_provider = "internal_hashed"; local _ENV = nil; -- luacheck: std none diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua index 30d7acfa..ab863aa3 100644 --- a/plugins/mod_saslauth.lua +++ b/plugins/mod_saslauth.lua @@ -309,7 +309,7 @@ module:hook("stream-features", function(event) return; end - local authmod = module:get_option_string("authentication", "internal_plain"); + local authmod = module:get_option_string("authentication", "internal_hashed"); if available_mechanisms:empty() then log("warn", "No available SASL mechanisms, verify that the configured authentication module '%s' is loaded and configured correctly", authmod); return; -- cgit v1.2.3 From 601c2fb6dd9b26269d067899a6dec714da5c5557 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 14 Feb 2022 15:49:43 +0000 Subject: prosody.cfg.lua.dist: Enable csi_simple by default It was added here in 2018, and at that time probably a bit too new to be enabled by default. Times change, and most people have this enabled now. --- prosody.cfg.lua.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 54426d6f..5089780f 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -56,6 +56,7 @@ modules_enabled = { "dialback"; -- s2s dialback support -- Nice to have + "csi_simple"; -- Simple Mobile optimizations "version"; -- Replies to server version requests "uptime"; -- Report how long server has been running "time"; -- Let others know the time here on this server @@ -65,7 +66,6 @@ modules_enabled = { "invites_register"; -- Create accounts using invites "invites_adhoc"; -- Create invites via AdHoc command --"mam"; -- Store messages in an archive and allow users to access it - --"csi_simple"; -- Simple Mobile optimizations --"turn_external"; -- Provide external TURN (and STUN) service -- Admin interfaces -- cgit v1.2.3 From c67bda6d514dac370315e64e582afd9a8966c028 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 14 Feb 2022 15:51:13 +0000 Subject: prosody.cfg.lua.dist: TURN configuration improvements and example --- prosody.cfg.lua.dist | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 5089780f..35aa0065 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -66,7 +66,7 @@ modules_enabled = { "invites_register"; -- Create accounts using invites "invites_adhoc"; -- Create invites via AdHoc command --"mam"; -- Store messages in an archive and allow users to access it - --"turn_external"; -- Provide external TURN (and STUN) service + --"turn_external"; -- Provide external STUN/TURN service for e.g. audio/video calls -- Admin interfaces "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands @@ -161,6 +161,17 @@ archive_expires_after = "1w" -- Remove archived messages after 1 week -- You can also configure messages to be stored in-memory only. For more -- archiving options, see https://prosody.im/doc/modules/mod_mam + +-- Audio/video call relay (STUN/TURN) +-- To ensure clients connected to the server can establish connections for +-- low-latency media streaming (such as audio and video calls), it is +-- recommended to run a STUN/TURN server for clients to use. If you do this, +-- specify the details here so clients can discover it. +-- Find more information at https://prosody.im/doc/turn + +--turn_external_host = "turn.example.com" +--turn_external_secret = "your-secret-turn-access-token" + -- Logging configuration -- For advanced logging see https://prosody.im/doc/logging log = { -- cgit v1.2.3 From 274b2a0249d921f2cb98874073f60ea360159af4 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 14 Feb 2022 15:59:03 +0000 Subject: prosody.cfg.lua.dist: Update s2s_secure_auth comment and default --- prosody.cfg.lua.dist | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 35aa0065..844c0f8a 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -105,9 +105,10 @@ modules_disabled = { -- For more information see https://prosody.im/doc/creating_accounts allow_registration = false --- Force certificate authentication for server-to-server connections? +-- Require valid certificates for server-to-server connections? +-- If false, other methods such as dialback (DNS) may be used instead. -s2s_secure_auth = false +s2s_secure_auth = true -- Some servers have invalid or self-signed certificates. You can list -- remote domains here that will not be required to authenticate using -- cgit v1.2.3 From fde42d8486b1573ce7a5a6d8837c9e758cabfb2b Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 14 Feb 2022 16:01:34 +0000 Subject: prosody.cfg.lua.dist: Comment improvements --- prosody.cfg.lua.dist | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 844c0f8a..1a268188 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -122,7 +122,8 @@ s2s_secure_auth = true --s2s_secure_domains = { "jabber.org" } --- Enable rate limits for incoming client and server connections +-- Enable rate limits for incoming client and server connections. These help +-- protect from excessive resource consumption and denial-of-service attacks. limits = { c2s = { @@ -224,7 +225,7 @@ VirtualHost "localhost" ---Set up an external component (default component port is 5347) -- -- External components allow adding various services, such as gateways/ --- transports to other networks like ICQ, MSN and Yahoo. For more info +-- bridges to non-XMPP networks and services. For more info -- see: https://prosody.im/doc/components#adding_an_external_component -- --Component "gateway.example.com" -- cgit v1.2.3 From 25cb355e101c2b76e0fa190b2fca3c8c991a7a4a Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 14 Feb 2022 16:27:58 +0000 Subject: prosody.cfg.lua.dist: Improve section-like layout via headers and spacing --- prosody.cfg.lua.dist | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 1a268188..d4956434 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -105,6 +105,7 @@ modules_disabled = { -- For more information see https://prosody.im/doc/creating_accounts allow_registration = false +-- Server-to-server authentication -- Require valid certificates for server-to-server connections? -- If false, other methods such as dialback (DNS) may be used instead. @@ -122,6 +123,8 @@ s2s_secure_auth = true --s2s_secure_domains = { "jabber.org" } + +-- Rate limits -- Enable rate limits for incoming client and server connections. These help -- protect from excessive resource consumption and denial-of-service attacks. @@ -134,11 +137,14 @@ limits = { }; } +-- Authentication -- Select the authentication backend to use. The 'internal' providers -- use Prosody's configured data storage to store the authentication data. authentication = "internal_hashed" + +-- Storage -- Select the storage backend to use. By default Prosody uses flat files -- in its configured data directory, but it also supports more backends -- through modules. An "sql" backend is included by default, but requires @@ -174,6 +180,7 @@ archive_expires_after = "1w" -- Remove archived messages after 1 week --turn_external_host = "turn.example.com" --turn_external_secret = "your-secret-turn-access-token" + -- Logging configuration -- For advanced logging see https://prosody.im/doc/logging log = { @@ -183,10 +190,12 @@ log = { -- "*console"; -- Log to the console, useful for debugging when running in the foreground } + -- Uncomment to enable statistics -- For more info see https://prosody.im/doc/statistics -- statistics = "internal" + -- Certificates -- Every virtual host and component needs a certificate so that clients and -- servers can securely verify its identity. Prosody will automatically load -- cgit v1.2.3 From 94140346fffb660695ff1eaf472c61eb92ef29f2 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 14 Feb 2022 16:29:38 +0000 Subject: prosody.cfg.lua.dist: Comment improvements: authentication --- prosody.cfg.lua.dist | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index d4956434..d7b47fc7 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -140,9 +140,14 @@ limits = { -- Authentication -- Select the authentication backend to use. The 'internal' providers -- use Prosody's configured data storage to store the authentication data. +-- For more information see https://prosody.im/doc/authentication authentication = "internal_hashed" +-- Many authentication providers, including the default one, allow you to +-- create user accounts via Prosody's admin interfaces. For details, see the +-- documentation at https://prosody.im/doc/creating_accounts + -- Storage -- Select the storage backend to use. By default Prosody uses flat files -- cgit v1.2.3 From c3f82ad2e9868b49cbc429f44559c652200fa088 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 14 Feb 2022 16:30:01 +0000 Subject: prosody.cfg.lua.dist: Comment improvements: s2s authentication --- prosody.cfg.lua.dist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index d7b47fc7..78f65e42 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -113,8 +113,8 @@ s2s_secure_auth = true -- Some servers have invalid or self-signed certificates. You can list -- remote domains here that will not be required to authenticate using --- certificates. They will be authenticated using DNS instead, even --- when s2s_secure_auth is enabled. +-- certificates. They will be authenticated using other methods instead, +-- even when s2s_secure_auth is enabled. --s2s_insecure_domains = { "insecure.example" } -- cgit v1.2.3 From db4d41bd5aeb2bdd5b32d4f0e50775cc2b5404de Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 11 Feb 2022 00:16:36 +0100 Subject: prosody.cfg.lua.dist: Remove allow_registration in favor of invites This settings should now only be used by public servers, which have their own documentation --- prosody.cfg.lua.dist | 3 --- 1 file changed, 3 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 78f65e42..ab4072cc 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -101,9 +101,6 @@ modules_disabled = { -- "posix"; -- POSIX functionality, sends server to background, etc. } --- Disable account creation by default, for security --- For more information see https://prosody.im/doc/creating_accounts -allow_registration = false -- Server-to-server authentication -- Require valid certificates for server-to-server connections? -- cgit v1.2.3 From 9fbf5bf7add64c6059af859a15bcaeda386395ec Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 12 Feb 2022 18:47:22 +0100 Subject: net.server_epoll: Disable verbose mode by default --- net/server_epoll.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/server_epoll.lua b/net/server_epoll.lua index faa6a1b5..fa275d71 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -68,8 +68,7 @@ local default_config = { __index = { min_wait = 0.001; -- Enable extra noisy debug logging - -- TODO disable once considered stable - verbose = true; + verbose = false; -- EXPERIMENTAL -- Whether to kill connections in case of callback errors. -- cgit v1.2.3 From 09f6d8f21d321dc352553924da3ae63ea99482c0 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 13 Feb 2022 21:52:43 +0100 Subject: prosody.cfg.lua.dist: Remove example certificate, this should just work --- prosody.cfg.lua.dist | 1 - 1 file changed, 1 deletion(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index ab4072cc..8f5f43cc 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -218,7 +218,6 @@ VirtualHost "localhost" --VirtualHost "example.com" --- certificate = "/path/to/example.crt" ------ Components ------ -- You can specify components to add hosts that provide special services, -- cgit v1.2.3 From 1990010e21321f2df3720aeae5aac56480fd13e8 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 2 Mar 2022 14:22:02 +0000 Subject: prosody.cfg.lua.dist: Remove network_backend option The only sensible option for most people these days is "epoll". The option is still supported, but it should only be needed by packagers for specific platforms (e.g. BSD may choose libevent for kqueue) or other special cases. --- prosody.cfg.lua.dist | 4 ---- 1 file changed, 4 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 8f5f43cc..cb4718a3 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -23,10 +23,6 @@ -- Example: admins = { "user1@example.com", "user2@example.net" } admins = { } --- Prosody includes several alternative modules for keeping track of network connections. --- For more information see: https://prosody.im/doc/network_backend ---network_backend = "epoll" - -- Prosody will always look in its source directory for modules, but -- this option allows you to specify additional locations where Prosody -- will look for modules first. For community modules, see https://modules.prosody.im/ -- cgit v1.2.3 From eda989030aee68514bac22b6ccefa5801a847246 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 2 Mar 2022 14:27:05 +0000 Subject: prosody.cfg.lua.dist: Reword plugin_paths to de-emphasize Prosody's source dir The previous wording may contribute to people trying to install custom modules to Prosody's source directory instead of adding to plugin_paths. --- prosody.cfg.lua.dist | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index cb4718a3..8a6bac59 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -23,9 +23,8 @@ -- Example: admins = { "user1@example.com", "user2@example.net" } admins = { } --- Prosody will always look in its source directory for modules, but --- this option allows you to specify additional locations where Prosody --- will look for modules first. For community modules, see https://modules.prosody.im/ +-- You can use this option allows you to specify additional locations where Prosody +-- will first look for modules. For community modules, see https://modules.prosody.im/ --plugin_paths = {} -- This is the list of modules Prosody will load on startup. -- cgit v1.2.3 From 4102ef8e05fe21ac650f86ba11c1eca8081f827d Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 2 Mar 2022 14:27:28 +0000 Subject: prosody.cfg.lua.dist: Remove mod_admin_telnet mod_admin_shell should preferably be used instead --- prosody.cfg.lua.dist | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 8a6bac59..128ba836 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -65,8 +65,7 @@ modules_enabled = { -- Admin interfaces "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands - --"admin_telnet"; -- Opens telnet console interface on localhost port 5582 - "admin_shell"; -- Allow secure administration via an UNIX socket + "admin_shell"; -- Allow secure administration via 'prosodyctl shell' -- HTTP modules --"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP" -- cgit v1.2.3 From 55dd856a507a69b68b04ec2ec961fd9c55ac6ecc Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 2 Mar 2022 14:32:02 +0000 Subject: prosody.cfg.lua.dist: Improve mod_mam description to indicate its purpose --- prosody.cfg.lua.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 128ba836..13912349 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -60,7 +60,7 @@ modules_enabled = { "invites"; -- Create and manage invites "invites_register"; -- Create accounts using invites "invites_adhoc"; -- Create invites via AdHoc command - --"mam"; -- Store messages in an archive and allow users to access it + --"mam"; -- Store recent messages to allow multi-device synchronization --"turn_external"; -- Provide external STUN/TURN service for e.g. audio/video calls -- Admin interfaces -- cgit v1.2.3 From 855f8db6adc3e86cd54991f194356d5e9bb9f391 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 2 Mar 2022 14:32:32 +0000 Subject: prosody.cfg.lua.dist: Alphabetical ordering of modules within each section --- prosody.cfg.lua.dist | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 13912349..e617c3a0 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -33,33 +33,33 @@ admins = { } modules_enabled = { -- Generally required + "disco"; -- Service discovery "roster"; -- Allow users to have a roster. Recommended ;) "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in. "tls"; -- Add support for secure TLS on c2s/s2s connections - "disco"; -- Service discovery -- Not essential, but recommended + "blocklist"; -- Allow users to block communications with other users + "bookmarks"; -- Synchronise open rooms between clients "carbons"; -- Keep multiple clients in sync + "dialback"; -- s2s dialback support + "limits"; -- Enable bandwidth limiting for XMPP connections "pep"; -- Enables users to publish their avatar, mood, activity, playing music and more "private"; -- Private XML storage (for room bookmarks, etc.) - "blocklist"; -- Allow users to block communications with other users + "smacks"; -- Stream management and resumption (XEP-0198) "vcard4"; -- User profiles (stored in PEP) "vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard - "limits"; -- Enable bandwidth limiting for XMPP connections - "bookmarks"; -- Synchronise open rooms between clients - "smacks"; -- Stream management and resumption (XEP-0198) - "dialback"; -- s2s dialback support -- Nice to have "csi_simple"; -- Simple Mobile optimizations - "version"; -- Replies to server version requests - "uptime"; -- Report how long server has been running - "time"; -- Let others know the time here on this server - "ping"; -- Replies to XMPP pings with pongs - "register"; -- Allow users to register on this server using a client and change passwords "invites"; -- Create and manage invites "invites_register"; -- Create accounts using invites "invites_adhoc"; -- Create invites via AdHoc command + "ping"; -- Replies to XMPP pings with pongs + "register"; -- Allow users to register on this server using a client and change passwords + "time"; -- Let others know the time here on this server + "uptime"; -- Report how long server has been running + "version"; -- Replies to server version requests --"mam"; -- Store recent messages to allow multi-device synchronization --"turn_external"; -- Provide external STUN/TURN service for e.g. audio/video calls @@ -69,21 +69,21 @@ modules_enabled = { -- HTTP modules --"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP" - --"websocket"; -- XMPP over WebSockets --"http_openmetrics"; -- for exposing metrics to stats collectors + --"websocket"; -- XMPP over WebSockets -- Other specific functionality - --"groups"; -- Shared roster support - --"server_contact_info"; -- Publish contact information for this service --"announce"; -- Send announcement to all online users - --"welcome"; -- Welcome users who register accounts - --"watchregistrations"; -- Alert admins of registrations - --"motd"; -- Send a message to users when they log in + --"groups"; -- Shared roster support --"legacyauth"; -- Legacy authentication. Only used by some old clients and bots. - --"proxy65"; -- Enables a file transfer proxy service which clients behind NAT can use --"mimicking"; -- Prevent address spoofing - --"tombstones"; -- Prevent registration of deleted accounts + --"motd"; -- Send a message to users when they log in + --"proxy65"; -- Enables a file transfer proxy service which clients behind NAT can use --"s2s_bidi"; -- Bi-directional server-to-server (XEP-0288) + --"server_contact_info"; -- Publish contact information for this service + --"tombstones"; -- Prevent registration of deleted accounts + --"watchregistrations"; -- Alert admins of registrations + --"welcome"; -- Welcome users who register accounts } -- These modules are auto-loaded, but should you want -- cgit v1.2.3 From ebf9f9d157c048291687984912014d398482f1c5 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 2 Mar 2022 15:20:21 +0000 Subject: prosody.cfg.lua.dist: Improved descriptions for a number of modules --- prosody.cfg.lua.dist | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index e617c3a0..c56062dd 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -40,21 +40,21 @@ modules_enabled = { -- Not essential, but recommended "blocklist"; -- Allow users to block communications with other users - "bookmarks"; -- Synchronise open rooms between clients - "carbons"; -- Keep multiple clients in sync - "dialback"; -- s2s dialback support + "bookmarks"; -- Synchronise the list of open rooms between clients + "carbons"; -- Keep multiple online clients in sync + "dialback"; -- Support for verifying remote servers using DNS "limits"; -- Enable bandwidth limiting for XMPP connections - "pep"; -- Enables users to publish their avatar, mood, activity, playing music and more - "private"; -- Private XML storage (for room bookmarks, etc.) + "pep"; -- Allow users to store public and private data in their account + "private"; -- Legacy account storage mechanism (XEP-0049) "smacks"; -- Stream management and resumption (XEP-0198) "vcard4"; -- User profiles (stored in PEP) "vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard -- Nice to have - "csi_simple"; -- Simple Mobile optimizations + "csi_simple"; -- Simple but effective traffic optimizations for mobile devices "invites"; -- Create and manage invites - "invites_register"; -- Create accounts using invites - "invites_adhoc"; -- Create invites via AdHoc command + "invites_adhoc"; -- Allow admins/users to create invitations via their client + "invites_register"; -- Allows invited users to create accounts "ping"; -- Replies to XMPP pings with pongs "register"; -- Allow users to register on this server using a client and change passwords "time"; -- Let others know the time here on this server -- cgit v1.2.3 From a4d57c4fc733a85518a821f799f3ee821962899b Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 2 Mar 2022 16:53:52 +0000 Subject: prosody.cfg.lua.dist: Add comments explaining the individual TURN options --- prosody.cfg.lua.dist | 3 +++ 1 file changed, 3 insertions(+) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index c56062dd..dd80ffa1 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -173,7 +173,10 @@ archive_expires_after = "1w" -- Remove archived messages after 1 week -- specify the details here so clients can discover it. -- Find more information at https://prosody.im/doc/turn +-- Specify the address of the TURN service (you may use the same domain as XMPP) --turn_external_host = "turn.example.com" + +-- This secret must be set to the same value in both Prosody and the TURN server --turn_external_secret = "your-secret-turn-access-token" -- cgit v1.2.3 From ab4b25e28f22ffd3dd2810a3e25efcda57c474f4 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 3 Mar 2022 10:23:10 +0000 Subject: prosody.cfg.lua.dist: Fix plugin_paths description (thanks Zash) --- prosody.cfg.lua.dist | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index dd80ffa1..bdbf1a3f 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -23,8 +23,9 @@ -- Example: admins = { "user1@example.com", "user2@example.net" } admins = { } --- You can use this option allows you to specify additional locations where Prosody --- will first look for modules. For community modules, see https://modules.prosody.im/ +-- This option allows you to specify additional locations where Prosody +-- will search first for modules. For additional modules you can install, see +-- the community module repository at https://modules.prosody.im/ --plugin_paths = {} -- This is the list of modules Prosody will load on startup. -- cgit v1.2.3 From 0b44cfec12cfaae679fb68cc75835698a0bd2709 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 3 Mar 2022 10:24:59 +0000 Subject: prosody.cfg.lua.dist: Remove comment about mod_*.lua above modules_enabled This is a very old statement, but people generally don't need to check for the files, and shouldn't be encouraged to put them in Prosody's source dir. The installer will be the way forward for most people, and hg for the rest. Manually moving files into the right place is not something most users should be doing. --- prosody.cfg.lua.dist | 1 - 1 file changed, 1 deletion(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index bdbf1a3f..267a650c 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -29,7 +29,6 @@ admins = { } --plugin_paths = {} -- This is the list of modules Prosody will load on startup. --- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too. -- Documentation for bundled modules can be found at: https://prosody.im/doc/modules modules_enabled = { -- cgit v1.2.3 From 09bdd816594d43ef6b40a218f78cfee1a09891a3 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 4 Mar 2022 15:00:30 +0000 Subject: COPYING: An overdue update. Also add some clarity about third-party code. --- COPYING | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/COPYING b/COPYING index 14850bfe..951f1d5d 100644 --- a/COPYING +++ b/COPYING @@ -1,5 +1,12 @@ -Copyright (c) 2008-2011 Matthew Wild -Copyright (c) 2008-2011 Waqas Hussain +All source code in this project is released under the below MIT license. Some +components are not authored by the Prosody maintainers, but such code is +itself either released under a MIT license or declared public domain. + +--- + +Copyright (C) 2008-2022 Matthew Wild +Copyright (C) 2008-2020 Waqas Hussain +Copyright (C) 2010-2022 Kim Alvefur Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,3 +25,16 @@ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--- + +util-src/encodings.c: + Parts included from Lua 5.3. Copyright (C) 1994-2015 Lua.org, PUC-Rio. + +util-src/signal.c: + Copyright (C) 2007 Patrick J. Donnelly (batrick@batbytes.com) + See full copyright notice in the source file. + +net/dns.lua: + public domain 20080404 lua@ztact.com + -- cgit v1.2.3 From fe56effa55147a7deb8ee754c092af899e662c73 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 4 Mar 2022 15:03:02 +0000 Subject: util.struct: Import Roberto 'struct' library v0.3 Downloaded from http://www.inf.puc-rio.br/~roberto/struct/ This is for compatibility with Lua 5.2 (and 5.1). Eventually we can replace this with string.pack/string.unpack which are available in 5.3+. --- COPYING | 4 + GNUmakefile | 4 +- util-src/GNUmakefile | 3 +- util-src/struct.c | 422 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 431 insertions(+), 2 deletions(-) create mode 100644 util-src/struct.c diff --git a/COPYING b/COPYING index 951f1d5d..3519dcc2 100644 --- a/COPYING +++ b/COPYING @@ -35,6 +35,10 @@ util-src/signal.c: Copyright (C) 2007 Patrick J. Donnelly (batrick@batbytes.com) See full copyright notice in the source file. +util-src/struct.c: + Copyright (C) 2010-2018 Lua.org, PUC-Rio. All rights reserved. + See full copyright notice in the source file. + net/dns.lua: public domain 20080404 lua@ztact.com diff --git a/GNUmakefile b/GNUmakefile index a86a0b7e..829a1c3e 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -31,7 +31,9 @@ ifeq ($(EXCERTS),yes) -$(MAKE) -C certs localhost.crt example.com.crt endif -install: prosody.install prosodyctl.install prosody.cfg.lua.install util/encodings.so util/encodings.so util/pposix.so util/signal.so +CMODULES=util/encodings.so util/encodings.so util/pposix.so util/signal.so util/struct.so + +install: prosody.install prosodyctl.install prosody.cfg.lua.install $(CMODULES) $(MKDIR) $(BIN) $(CONFIG) $(MODULES) $(SOURCE) $(MKDIR_PRIVATE) $(DATA) $(MKDIR) $(MAN)/man1 diff --git a/util-src/GNUmakefile b/util-src/GNUmakefile index 0b96bf41..810f39f7 100644 --- a/util-src/GNUmakefile +++ b/util-src/GNUmakefile @@ -7,7 +7,8 @@ INSTALL_DATA=install -m644 TARGET?=../util/ ALL=encodings.so hashes.so net.so pposix.so signal.so table.so \ - ringbuffer.so time.so poll.so compat.so strbitop.so + ringbuffer.so time.so poll.so compat.so strbitop.so \ + struct.so ifdef RANDOM ALL+=crand.so diff --git a/util-src/struct.c b/util-src/struct.c new file mode 100644 index 00000000..40fdffac --- /dev/null +++ b/util-src/struct.c @@ -0,0 +1,422 @@ +/* +** {====================================================== +** Library for packing/unpacking structures. +** $Id: struct.c,v 1.8 2018/05/16 11:00:23 roberto Exp $ +** See Copyright Notice at the end of this file +** ======================================================= +*/ +/* +** Valid formats: +** > - big endian +** < - little endian +** ![num] - alignment +** x - pading +** b/B - signed/unsigned byte +** h/H - signed/unsigned short +** l/L - signed/unsigned long +** T - size_t +** i/In - signed/unsigned integer with size 'n' (default is size of int) +** cn - sequence of 'n' chars (from/to a string); when packing, n==0 means + the whole string; when unpacking, n==0 means use the previous + read number as the string length +** s - zero-terminated string +** f - float +** d - double +** ' ' - ignored +*/ + + +#include +#include +#include +#include + + +#include "lua.h" +#include "lauxlib.h" + + +#if (LUA_VERSION_NUM >= 502) + +#define luaL_register(L,n,f) luaL_newlib(L,f) + +#endif + + +/* basic integer type */ +#if !defined(STRUCT_INT) +#define STRUCT_INT long +#endif + +typedef STRUCT_INT Inttype; + +/* corresponding unsigned version */ +typedef unsigned STRUCT_INT Uinttype; + + +/* maximum size (in bytes) for integral types */ +#define MAXINTSIZE 32 + +/* is 'x' a power of 2? */ +#define isp2(x) ((x) > 0 && ((x) & ((x) - 1)) == 0) + +/* dummy structure to get alignment requirements */ +struct cD { + char c; + double d; +}; + + +#define PADDING (sizeof(struct cD) - sizeof(double)) +#define MAXALIGN (PADDING > sizeof(int) ? PADDING : sizeof(int)) + + +/* endian options */ +#define BIG 0 +#define LITTLE 1 + + +static union { + int dummy; + char endian; +} const native = {1}; + + +typedef struct Header { + int endian; + int align; +} Header; + + +static int getnum (const char **fmt, int df) { + if (!isdigit(**fmt)) /* no number? */ + return df; /* return default value */ + else { + int a = 0; + do { + a = a*10 + *((*fmt)++) - '0'; + } while (isdigit(**fmt)); + return a; + } +} + + +#define defaultoptions(h) ((h)->endian = native.endian, (h)->align = 1) + + + +static size_t optsize (lua_State *L, char opt, const char **fmt) { + switch (opt) { + case 'B': case 'b': return sizeof(char); + case 'H': case 'h': return sizeof(short); + case 'L': case 'l': return sizeof(long); + case 'T': return sizeof(size_t); + case 'f': return sizeof(float); + case 'd': return sizeof(double); + case 'x': return 1; + case 'c': return getnum(fmt, 1); + case 'i': case 'I': { + int sz = getnum(fmt, sizeof(int)); + if (sz > MAXINTSIZE) + luaL_error(L, "integral size %d is larger than limit of %d", + sz, MAXINTSIZE); + return sz; + } + default: return 0; /* other cases do not need alignment */ + } +} + + +/* +** return number of bytes needed to align an element of size 'size' +** at current position 'len' +*/ +static int gettoalign (size_t len, Header *h, int opt, size_t size) { + if (size == 0 || opt == 'c') return 0; + if (size > (size_t)h->align) + size = h->align; /* respect max. alignment */ + return (size - (len & (size - 1))) & (size - 1); +} + + +/* +** options to control endianess and alignment +*/ +static void controloptions (lua_State *L, int opt, const char **fmt, + Header *h) { + switch (opt) { + case ' ': return; /* ignore white spaces */ + case '>': h->endian = BIG; return; + case '<': h->endian = LITTLE; return; + case '!': { + int a = getnum(fmt, MAXALIGN); + if (!isp2(a)) + luaL_error(L, "alignment %d is not a power of 2", a); + h->align = a; + return; + } + default: { + const char *msg = lua_pushfstring(L, "invalid format option '%c'", opt); + luaL_argerror(L, 1, msg); + } + } +} + + +static void putinteger (lua_State *L, luaL_Buffer *b, int arg, int endian, + int size) { + lua_Number n = luaL_checknumber(L, arg); + Uinttype value; + char buff[MAXINTSIZE]; + if (n < 0) + value = (Uinttype)(Inttype)n; + else + value = (Uinttype)n; + if (endian == LITTLE) { + int i; + for (i = 0; i < size; i++) { + buff[i] = (value & 0xff); + value >>= 8; + } + } + else { + int i; + for (i = size - 1; i >= 0; i--) { + buff[i] = (value & 0xff); + value >>= 8; + } + } + luaL_addlstring(b, buff, size); +} + + +static void correctbytes (char *b, int size, int endian) { + if (endian != native.endian) { + int i = 0; + while (i < --size) { + char temp = b[i]; + b[i++] = b[size]; + b[size] = temp; + } + } +} + + +static int b_pack (lua_State *L) { + luaL_Buffer b; + const char *fmt = luaL_checkstring(L, 1); + Header h; + int arg = 2; + size_t totalsize = 0; + defaultoptions(&h); + lua_pushnil(L); /* mark to separate arguments from string buffer */ + luaL_buffinit(L, &b); + while (*fmt != '\0') { + int opt = *fmt++; + size_t size = optsize(L, opt, &fmt); + int toalign = gettoalign(totalsize, &h, opt, size); + totalsize += toalign; + while (toalign-- > 0) luaL_addchar(&b, '\0'); + switch (opt) { + case 'b': case 'B': case 'h': case 'H': + case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */ + putinteger(L, &b, arg++, h.endian, size); + break; + } + case 'x': { + luaL_addchar(&b, '\0'); + break; + } + case 'f': { + float f = (float)luaL_checknumber(L, arg++); + correctbytes((char *)&f, size, h.endian); + luaL_addlstring(&b, (char *)&f, size); + break; + } + case 'd': { + double d = luaL_checknumber(L, arg++); + correctbytes((char *)&d, size, h.endian); + luaL_addlstring(&b, (char *)&d, size); + break; + } + case 'c': case 's': { + size_t l; + const char *s = luaL_checklstring(L, arg++, &l); + if (size == 0) size = l; + luaL_argcheck(L, l >= (size_t)size, arg, "string too short"); + luaL_addlstring(&b, s, size); + if (opt == 's') { + luaL_addchar(&b, '\0'); /* add zero at the end */ + size++; + } + break; + } + default: controloptions(L, opt, &fmt, &h); + } + totalsize += size; + } + luaL_pushresult(&b); + return 1; +} + + +static lua_Number getinteger (const char *buff, int endian, + int issigned, int size) { + Uinttype l = 0; + int i; + if (endian == BIG) { + for (i = 0; i < size; i++) { + l <<= 8; + l |= (Uinttype)(unsigned char)buff[i]; + } + } + else { + for (i = size - 1; i >= 0; i--) { + l <<= 8; + l |= (Uinttype)(unsigned char)buff[i]; + } + } + if (!issigned) + return (lua_Number)l; + else { /* signed format */ + Uinttype mask = (Uinttype)(~((Uinttype)0)) << (size*8 - 1); + if (l & mask) /* negative value? */ + l |= mask; /* signal extension */ + return (lua_Number)(Inttype)l; + } +} + + +static int b_unpack (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); + size_t ld; + const char *data = luaL_checklstring(L, 2, &ld); + size_t pos = (size_t)luaL_optinteger(L, 3, 1) - 1; + int n = 0; /* number of results */ + luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); + defaultoptions(&h); + while (*fmt) { + int opt = *fmt++; + size_t size = optsize(L, opt, &fmt); + pos += gettoalign(pos, &h, opt, size); + luaL_argcheck(L, size <= ld - pos, 2, "data string too short"); + /* stack space for item + next position */ + luaL_checkstack(L, 2, "too many results"); + switch (opt) { + case 'b': case 'B': case 'h': case 'H': + case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */ + int issigned = islower(opt); + lua_Number res = getinteger(data+pos, h.endian, issigned, size); + lua_pushnumber(L, res); n++; + break; + } + case 'x': { + break; + } + case 'f': { + float f; + memcpy(&f, data+pos, size); + correctbytes((char *)&f, sizeof(f), h.endian); + lua_pushnumber(L, f); n++; + break; + } + case 'd': { + double d; + memcpy(&d, data+pos, size); + correctbytes((char *)&d, sizeof(d), h.endian); + lua_pushnumber(L, d); n++; + break; + } + case 'c': { + if (size == 0) { + if (n == 0 || !lua_isnumber(L, -1)) + luaL_error(L, "format 'c0' needs a previous size"); + size = lua_tonumber(L, -1); + lua_pop(L, 1); n--; + luaL_argcheck(L, size <= ld - pos, 2, "data string too short"); + } + lua_pushlstring(L, data+pos, size); n++; + break; + } + case 's': { + const char *e = (const char *)memchr(data+pos, '\0', ld - pos); + if (e == NULL) + luaL_error(L, "unfinished string in data"); + size = (e - (data+pos)) + 1; + lua_pushlstring(L, data+pos, size - 1); n++; + break; + } + default: controloptions(L, opt, &fmt, &h); + } + pos += size; + } + lua_pushinteger(L, pos + 1); /* next position */ + return n + 1; +} + + +static int b_size (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); + size_t pos = 0; + defaultoptions(&h); + while (*fmt) { + int opt = *fmt++; + size_t size = optsize(L, opt, &fmt); + pos += gettoalign(pos, &h, opt, size); + if (opt == 's') + luaL_argerror(L, 1, "option 's' has no fixed size"); + else if (opt == 'c' && size == 0) + luaL_argerror(L, 1, "option 'c0' has no fixed size"); + if (!isalnum(opt)) + controloptions(L, opt, &fmt, &h); + pos += size; + } + lua_pushinteger(L, pos); + return 1; +} + +/* }====================================================== */ + + + +static const struct luaL_Reg thislib[] = { + {"pack", b_pack}, + {"unpack", b_unpack}, + {"size", b_size}, + {NULL, NULL} +}; + + +LUALIB_API int luaopen_util_struct (lua_State *L); + +LUALIB_API int luaopen_util_struct (lua_State *L) { + luaL_register(L, "struct", thislib); + return 1; +} + + +/****************************************************************************** +* Copyright (C) 2010-2018 Lua.org, PUC-Rio. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +******************************************************************************/ + -- cgit v1.2.3 From ab835fed13e300b3a49131296917f5038eb6c06c Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 4 Mar 2022 15:22:45 +0000 Subject: util.hex: Deprecate to/from in favour of encode/decode, for consistency! --- plugins/mod_auth_internal_hashed.lua | 2 +- plugins/mod_storage_xep0227.lua | 4 ++-- spec/util_hashes_spec.lua | 12 ++++++------ spec/util_hmac_spec.lua | 28 ++++++++++++++-------------- util/dns.lua | 2 +- util/hex.lua | 6 +++++- util/ip.lua | 2 +- util/uuid.lua | 2 +- 8 files changed, 31 insertions(+), 27 deletions(-) diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua index 1b0e76ed..cf851eef 100644 --- a/plugins/mod_auth_internal_hashed.lua +++ b/plugins/mod_auth_internal_hashed.lua @@ -14,7 +14,7 @@ local usermanager = require "core.usermanager"; local generate_uuid = require "util.uuid".generate; local new_sasl = require "util.sasl".new; local hex = require"util.hex"; -local to_hex, from_hex = hex.to, hex.from; +local to_hex, from_hex = hex.encode, hex.decode; local saslprep = require "util.encodings".stringprep.saslprep; local secure_equals = require "util.hashes".equals; diff --git a/plugins/mod_storage_xep0227.lua b/plugins/mod_storage_xep0227.lua index 1a7baaeb..9a3ca002 100644 --- a/plugins/mod_storage_xep0227.lua +++ b/plugins/mod_storage_xep0227.lua @@ -68,11 +68,11 @@ local function createOuterXml(user, host) end local function hex_to_base64(s) - return base64.encode(hex.from(s)); + return base64.encode(hex.decode(s)); end local function base64_to_hex(s) - return base64.encode(hex.from(s)); + return base64.encode(hex.decode(s)); end local handlers = {}; diff --git a/spec/util_hashes_spec.lua b/spec/util_hashes_spec.lua index 3639dd4e..51a4a79c 100644 --- a/spec/util_hashes_spec.lua +++ b/spec/util_hashes_spec.lua @@ -10,28 +10,28 @@ describe("PBKDF2-HMAC-SHA1", function () local S = "salt" local c = 1 local DK = "0c60c80f961f0e71f3a9b524af6012062fe037a6"; - assert.equal(DK, hex.to(hashes.pbkdf2_hmac_sha1(P, S, c))); + assert.equal(DK, hex.encode(hashes.pbkdf2_hmac_sha1(P, S, c))); end); it("test vector 2", function () local P = "password" local S = "salt" local c = 2 local DK = "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"; - assert.equal(DK, hex.to(hashes.pbkdf2_hmac_sha1(P, S, c))); + assert.equal(DK, hex.encode(hashes.pbkdf2_hmac_sha1(P, S, c))); end); it("test vector 3", function () local P = "password" local S = "salt" local c = 4096 local DK = "4b007901b765489abead49d926f721d065a429c1"; - assert.equal(DK, hex.to(hashes.pbkdf2_hmac_sha1(P, S, c))); + assert.equal(DK, hex.encode(hashes.pbkdf2_hmac_sha1(P, S, c))); end); it("test vector 4 #SLOW", function () local P = "password" local S = "salt" local c = 16777216 local DK = "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984"; - assert.equal(DK, hex.to(hashes.pbkdf2_hmac_sha1(P, S, c))); + assert.equal(DK, hex.encode(hashes.pbkdf2_hmac_sha1(P, S, c))); end); end); @@ -41,14 +41,14 @@ describe("PBKDF2-HMAC-SHA256", function () local S = "salt"; local c = 1 local DK = "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b"; - assert.equal(DK, hex.to(hashes.pbkdf2_hmac_sha256(P, S, c))); + assert.equal(DK, hex.encode(hashes.pbkdf2_hmac_sha256(P, S, c))); end); it("test vector 2", function () local P = "password"; local S = "salt"; local c = 2 local DK = "ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43"; - assert.equal(DK, hex.to(hashes.pbkdf2_hmac_sha256(P, S, c))); + assert.equal(DK, hex.encode(hashes.pbkdf2_hmac_sha256(P, S, c))); end); end); diff --git a/spec/util_hmac_spec.lua b/spec/util_hmac_spec.lua index a2125c3a..8d6274aa 100644 --- a/spec/util_hmac_spec.lua +++ b/spec/util_hmac_spec.lua @@ -7,8 +7,8 @@ local hmac = require "util.hmac"; local hex = require "util.hex"; describe("Test case 1", function () - local Key = hex.from("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); - local Data = hex.from("4869205468657265"); + local Key = hex.decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); + local Data = hex.decode("4869205468657265"); describe("HMAC-SHA-256", function () it("works", function() assert.equal("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7", hmac.sha256(Key, Data, true)) @@ -21,8 +21,8 @@ describe("Test case 1", function () end); end); describe("Test case 2", function () - local Key = hex.from("4a656665"); - local Data = hex.from("7768617420646f2079612077616e7420666f72206e6f7468696e673f"); + local Key = hex.decode("4a656665"); + local Data = hex.decode("7768617420646f2079612077616e7420666f72206e6f7468696e673f"); describe("HMAC-SHA-256", function () it("works", function() assert.equal("5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843", hmac.sha256(Key, Data, true)) @@ -35,8 +35,8 @@ describe("Test case 2", function () end); end); describe("Test case 3", function () - local Key = hex.from("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); - local Data = hex.from("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"); + local Key = hex.decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + local Data = hex.decode("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"); describe("HMAC-SHA-256", function () it("works", function() assert.equal("773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe", hmac.sha256(Key, Data, true)) @@ -49,8 +49,8 @@ describe("Test case 3", function () end); end); describe("Test case 4", function () - local Key = hex.from("0102030405060708090a0b0c0d0e0f10111213141516171819"); - local Data = hex.from("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"); + local Key = hex.decode("0102030405060708090a0b0c0d0e0f10111213141516171819"); + local Data = hex.decode("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"); describe("HMAC-SHA-256", function () it("works", function() assert.equal("82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b", hmac.sha256(Key, Data, true)) @@ -63,8 +63,8 @@ describe("Test case 4", function () end); end); describe("Test case 5", function () - local Key = hex.from("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"); - local Data = hex.from("546573742057697468205472756e636174696f6e"); + local Key = hex.decode("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"); + local Data = hex.decode("546573742057697468205472756e636174696f6e"); describe("HMAC-SHA-256", function () it("works", function() assert.equal("a3b6167473100ee06e0c796c2955552b", hmac.sha256(Key, Data, true):sub(1,128/4)) @@ -77,8 +77,8 @@ describe("Test case 5", function () end); end); describe("Test case 6", function () - local Key = hex.from("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); - local Data = hex.from("54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a65204b6579202d2048617368204b6579204669727374"); + local Key = hex.decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + local Data = hex.decode("54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a65204b6579202d2048617368204b6579204669727374"); describe("HMAC-SHA-256", function () it("works", function() assert.equal("60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54", hmac.sha256(Key, Data, true)) @@ -91,8 +91,8 @@ describe("Test case 6", function () end); end); describe("Test case 7", function () - local Key = hex.from("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); - local Data = hex.from("5468697320697320612074657374207573696e672061206c6172676572207468616e20626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520686173686564206265666f7265206265696e6720757365642062792074686520484d414320616c676f726974686d2e"); + local Key = hex.decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + local Data = hex.decode("5468697320697320612074657374207573696e672061206c6172676572207468616e20626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520686173686564206265666f7265206265696e6720757365642062792074686520484d414320616c676f726974686d2e"); describe("HMAC-SHA-256", function () it("works", function() assert.equal("9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2", hmac.sha256(Key, Data, true)) diff --git a/util/dns.lua b/util/dns.lua index 9d80d1ec..3b58e03e 100644 --- a/util/dns.lua +++ b/util/dns.lua @@ -13,7 +13,7 @@ local s_format = string.format; local s_sub = string.sub; local iana_data = require "util.dnsregistry"; -local tohex = require "util.hex".to; +local tohex = require "util.hex".encode; local inet_ntop = require "util.net".ntop; -- Simplified versions of Waqas DNS parsers diff --git a/util/hex.lua b/util/hex.lua index 4cc28d33..6202620f 100644 --- a/util/hex.lua +++ b/util/hex.lua @@ -23,4 +23,8 @@ local function from(s) return (s_gsub(s_lower(s), "%X*(%x%x)%X*", hex_to_char)); end -return { to = to, from = from } +return { + encode = to, decode = from; + -- COMPAT w/pre-0.12: + to = to, from = from; +}; diff --git a/util/ip.lua b/util/ip.lua index 20b92466..4b450934 100644 --- a/util/ip.lua +++ b/util/ip.lua @@ -67,7 +67,7 @@ function ip_methods:normal() end function ip_methods.bits(ip) - return hex.to(ip.packed):upper():gsub(".", hex2bits); + return hex.encode(ip.packed):upper():gsub(".", hex2bits); end function ip_methods.bits_full(ip) diff --git a/util/uuid.lua b/util/uuid.lua index f4fd21f6..54ea99b4 100644 --- a/util/uuid.lua +++ b/util/uuid.lua @@ -8,7 +8,7 @@ local random = require "util.random"; local random_bytes = random.bytes; -local hex = require "util.hex".to; +local hex = require "util.hex".encode; local m_ceil = math.ceil; local function get_nibbles(n) -- cgit v1.2.3 From 5cfe0d220dcae3b92cdf5ee22ab50409150e0628 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 4 Mar 2022 15:23:32 +0000 Subject: net.stun: New library that implements STUN/TURN parsing/serialization --- net/stun.lua | 292 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 net/stun.lua diff --git a/net/stun.lua b/net/stun.lua new file mode 100644 index 00000000..aefc4b27 --- /dev/null +++ b/net/stun.lua @@ -0,0 +1,292 @@ +local base64 = require "util.encodings".base64; +local hashes = require "util.hashes"; +local net = require "util.net"; +local random = require "util.random"; +local struct = require "util.struct"; + +--- Private helpers + +-- XORs a string with another string +local function sxor(x, y) + local r = {}; + for i = 1, #x do + r[i] = string.char(bit32.bxor(x:byte(i), y:byte(i))); + end + return table.concat(r); +end + +--- Public helpers + +-- Following draft-uberti-behave-turn-rest-00, convert a 'secret' string +-- into a username/password pair that can be used to auth to a TURN server +local function get_user_pass_from_secret(secret, ttl, opt_username) + ttl = ttl or 86400; + local username; + if opt_username then + username = ("%d:%s"):format(os.time() + ttl, opt_username); + else + username = ("%d"):format(os.time() + ttl); + end + local password = base64.encode(hashes.hmac_sha1(secret, username)); + return username, password, ttl; +end + +-- Following RFC 8489 9.2, convert credentials to a HMAC key for signing +local function get_long_term_auth_key(realm, username, password) + return hashes.md5(username..":"..realm..":"..password); +end + +--- Packet building/parsing + +local packet_methods = {}; +local packet_mt = { __index = packet_methods }; + +local magic_cookie = string.char(0x21, 0x12, 0xA4, 0x42); + +local methods = { + binding = 0x001; + -- TURN + allocate = 0x003; + refresh = 0x004; + send = 0x006; + data = 0x007; + create_permission = 0x008; + channel_bind = 0x009; +}; +local method_lookup = {}; +for name, value in pairs(methods) do + method_lookup[name] = value; + method_lookup[value] = name; +end + +local classes = { + request = 0; + indication = 1; + success = 2; + error = 3; +}; +local class_lookup = {}; +for name, value in pairs(classes) do + class_lookup[name] = value; + class_lookup[value] = name; +end + +local attributes = { + ["mapped-address"] = 0x0001; + ["username"] = 0x0006; + ["message-integrity"] = 0x0008; + ["error-code"] = 0x0009; + ["unknown-attributes"] = 0x000A; + ["realm"] = 0x0014; + ["nonce"] = 0x0015; + ["xor-mapped-address"] = 0x0020; + ["software"] = 0x8022; + ["alternate-server"] = 0x8023; + ["fingerprint"] = 0x8028; + ["message-integrity-sha256"] = 0x001C; + ["password-algorithm"] = 0x001D; + ["userhash"] = 0x001E; + ["password-algorithms"] = 0x8002; + ["alternate-domains"] = 0x8003; + + -- TURN + ["requested-transport"] = 0x0019; +}; +local attribute_lookup = {}; +for name, value in pairs(attributes) do + attribute_lookup[name] = value; + attribute_lookup[value] = name; +end + +function packet_methods:serialize_header(length) + assert(#self.transaction_id == 12, "invalid transaction id length"); + local header = struct.pack(">I2I2", + self.type, + length + )..magic_cookie..self.transaction_id; + return header; +end + +function packet_methods:serialize() + local payload = table.concat(self.attributes); + return self:serialize_header(#payload)..payload; +end + +function packet_methods:is_request() + return bit32.band(self.type, 0x0110) == 0x0000; +end + +function packet_methods:is_indication() + return bit32.band(self.type, 0x0110) == 0x0010; +end + +function packet_methods:is_success_resp() + return bit32.band(self.type, 0x0110) == 0x0100; +end + +function packet_methods:is_err_resp() + return bit32.band(self.type, 0x0110) == 0x0110; +end + +function packet_methods:get_method() + local method = bit32.bor( + bit32.rshift(bit32.band(self.type, 0x3E00), 2), + bit32.rshift(bit32.band(self.type, 0x00E0), 1), + bit32.band(self.type, 0x000F) + ); + return method, method_lookup[method]; +end + +function packet_methods:get_class() + local class = bit32.bor( + bit32.rshift(bit32.band(self.type, 0x0100), 7), + bit32.rshift(bit32.band(self.type, 0x0010), 4) + ); + return class, class_lookup[class]; +end + +function packet_methods:set_type(method, class) + if type(method) == "string" then + method = assert(method_lookup[method:lower()], "unknown method: "..method); + end + if type(class) == "string" then + class = assert(classes[class], "unknown class: "..class); + end + self.type = bit32.bor( + bit32.lshift(bit32.band(method, 0x1F80), 2), + bit32.lshift(bit32.band(method, 0x0070), 1), + bit32.band(method, 0x000F), + bit32.lshift(bit32.band(class, 0x0002), 7), + bit32.lshift(bit32.band(class, 0x0001), 4) + ); +end + +local function _serialize_attribute(attr_type, value) + local len = #value; + local padding = string.rep("\0", (4 - len)%4); + return struct.pack(">I2I2", + attr_type, len + )..value..padding; +end + +function packet_methods:add_attribute(attr_type, value) + if type(attr_type) == "string" then + attr_type = assert(attributes[attr_type], "unknown attribute: "..attr_type); + end + table.insert(self.attributes, _serialize_attribute(attr_type, value)); +end + +function packet_methods:deserialize(bytes) + local type, len, cookie = struct.unpack(">I2I2I4", bytes); + assert(#bytes == (len + 20), "incorrect packet length"); + assert(cookie == 0x2112A442, "invalid magic cookie"); + self.type = type; + self.transaction_id = bytes:sub(9, 20); + self.attributes = {}; + local pos = 21; + while pos < #bytes do + local attr_hdr = bytes:sub(pos, pos+3); + assert(#attr_hdr == 4, "packet truncated in attribute header"); + local attr_type, attr_len = struct.unpack(">I2I2", attr_hdr); --luacheck: ignore 211/attr_type + if attr_len == 0 then + table.insert(self.attributes, attr_hdr); + pos = pos + 20; + else + local data = bytes:sub(pos + 4, pos + 3 + attr_len); + assert(#data == attr_len, "packet truncated in attribute value"); + table.insert(self.attributes, attr_hdr..data); + local n_padding = (4 - attr_len)%4; + pos = pos + 4 + attr_len + n_padding; + end + end + return self; +end + +function packet_methods:get_attribute(attr_type) + if type(attr_type) == "string" then + attr_type = assert(attribute_lookup[attr_type:lower()], "unknown attribute: "..attr_type); + end + for _, attribute in ipairs(self.attributes) do + if struct.unpack(">I2", attribute) == attr_type then + return attribute:sub(5); + end + end +end + +local addr_families = { "IPv4", "IPv6" }; +function packet_methods:get_mapped_address() + local data = self:get_attribute("mapped-address"); + if not data then return; end + local family, port = struct.unpack("x>BI2", data); + local addr = data:sub(5); + return { + family = addr_families[family] or "unknown"; + port = port; + address = net.ntop(addr); + }; +end + +function packet_methods:get_xor_mapped_address() + local data = self:get_attribute("xor-mapped-address"); + if not data then return; end + local family, port = struct.unpack("x>BI2", data); + local addr = sxor(data:sub(5), magic_cookie..self.transaction_id); + return { + family = addr_families[family] or "unknown"; + port = bit32.bxor(port, 0x2112); + address = net.ntop(addr); + address_raw = data:sub(5); + }; +end + +function packet_methods:add_message_integrity(key) + -- Add attribute with a dummy value so we can artificially increase + -- the packet 'length' + self:add_attribute("message-integrity", string.rep("\0", 20)); + -- Get the packet data, minus the message-integrity attribute itself + local pkt = self:serialize():sub(1, -25); + local hash = hashes.hmac_sha1(key, pkt, false); + self.attributes[#self.attributes] = nil; + assert(#hash == 20, "invalid hash length"); + self:add_attribute("message-integrity", hash); +end + +do + local transports = { + udp = 0x11; + }; + function packet_methods:add_requested_transport(transport) + local transport_code = transports[transport]; + assert(transport_code, "unsupported transport: "..tostring(transport)); + self:add_attribute("requested-transport", string.char( + transport_code, 0x00, 0x00, 0x00 + )); + end +end + +function packet_methods:get_error() + local err_attr = self:get_attribute("error-code"); + if not err_attr then + return nil; + end + local number = err_attr:byte(4); + local class = bit32.band(0x07, err_attr:byte(3)); + local msg = err_attr:sub(5); + return (class*100)+number, msg; +end + +local function new_packet(method, class) + local p = setmetatable({ + transaction_id = random.bytes(12); + length = 0; + attributes = {}; + }, packet_mt); + p:set_type(method or "binding", class or "request"); + return p; +end + +return { + new_packet = new_packet; + get_user_pass_from_secret = get_user_pass_from_secret; + get_long_term_auth_key = get_long_term_auth_key; +}; -- cgit v1.2.3 From e01f2cf25fa35e6525dd12d6063d53065d2d8c33 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 4 Mar 2022 15:28:44 +0000 Subject: util.prosodyctl: check turn: New command to verify STUN/TURN service is operational --- util/prosodyctl/check.lua | 165 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 163 insertions(+), 2 deletions(-) diff --git a/util/prosodyctl/check.lua b/util/prosodyctl/check.lua index b4e38056..f2b84c7a 100644 --- a/util/prosodyctl/check.lua +++ b/util/prosodyctl/check.lua @@ -60,6 +60,108 @@ local function check_probe(base_url, probe_module, target) return false, "Probe endpoint did not return a success status"; end +local function check_turn_service(turn_service) + local stun = require "net.stun"; + + -- Create UDP socket for communication with the server + local sock = assert(require "socket".udp()); + sock:setsockname("*", 0); + sock:setpeername(turn_service.host, turn_service.port); + sock:settimeout(10); + + -- Helper function to receive a packet + local function receive_packet() + local raw_packet, err = sock:receive(); + if not raw_packet then + return nil, err; + end + return stun.new_packet():deserialize(raw_packet); + end + + local result = { warnings = {} }; + + -- Send a "binding" query, i.e. a request for our external IP/port + local bind_query = stun.new_packet("binding", "request"); + bind_query:add_attribute("software", "prosodyctl check turn"); + sock:send(bind_query:serialize()); + + local bind_result, err = receive_packet(); + if not bind_result then + result.error = "No STUN response: "..err; + return result; + elseif bind_result:is_err_resp() then + result.error = ("STUN server returned error: %d (%s)"):format(bind_result:get_error()); + return result; + elseif not bind_result:is_success_resp() then + result.error = ("Unexpected STUN response: %d (%s)"):format(bind_result:get_type()); + return result; + end + + result.external_ip = bind_result:get_xor_mapped_address(); + if not result.external_ip then + result.error = "STUN server did not return an address"; + return result; + end + + -- Send a TURN "allocate" request. Expected to fail due to auth, but + -- necessary to obtain a valid realm/nonce from the server. + local pre_request = stun.new_packet("allocate", "request"); + sock:send(pre_request:serialize()); + + local pre_result, err = receive_packet(); + if not pre_result then + result.error = "No initial TURN response: "..err; + return result; + elseif pre_result:is_success_resp() then + result.error = "TURN server does not have authentication enabled"; + return result; + end + + local realm = pre_result:get_attribute("realm"); + local nonce = pre_result:get_attribute("nonce"); + + if not realm then + table.insert(result.warnings, "TURN server did not return an authentication realm"); + end + if not nonce then + table.insert(result.warnings, "TURN server did not return a nonce"); + end + + -- Use the configured secret to obtain temporary user/pass credentials + local turn_user, turn_pass = stun.get_user_pass_from_secret(turn_service.secret); + + -- Send a TURN allocate request, will fail if auth is wrong + local alloc_request = stun.new_packet("allocate", "request"); + alloc_request:add_requested_transport("udp"); + alloc_request:add_attribute("username", turn_user); + if realm then + alloc_request:add_attribute("realm", realm); + end + if nonce then + alloc_request:add_attribute("nonce", nonce); + end + local key = stun.get_long_term_auth_key(realm or turn_service.host, turn_user, turn_pass); + alloc_request:add_message_integrity(key); + sock:send(alloc_request:serialize()); + + -- Check the response + local alloc_response, err = receive_packet(); + if not alloc_response then + result.error = "TURN server did not response to allocation request: "..err; + return; + elseif alloc_response:is_err_resp() then + result.error = ("TURN allocation failed: %d (%s)"):format(alloc_response:get_error()); + return result; + elseif not alloc_response:is_success_resp() then + result.error = ("Unexpected TURN response: %d (%s)"):format(alloc_response:get_type()); + return result; + end + + -- No errors? Ok! + + return result; +end + local function skip_bare_jid_hosts(host) if jid_split(host) then -- See issue #779 @@ -80,8 +182,8 @@ local function check(arg) local ok = true; local function disabled_hosts(host, conf) return host ~= "*" and conf.enabled ~= false; end local function enabled_hosts() return it.filter(disabled_hosts, pairs(configmanager.getconfig())); end - if not (what == nil or what == "disabled" or what == "config" or what == "dns" or what == "certs" or what == "connectivity") then - show_warning("Don't know how to check '%s'. Try one of 'config', 'dns', 'certs', 'disabled' or 'connectivity'.", what); + if not (what == nil or what == "disabled" or what == "config" or what == "dns" or what == "certs" or what == "connectivity" or what == "turn") then + show_warning("Don't know how to check '%s'. Try one of 'config', 'dns', 'certs', 'disabled', 'turn' or 'connectivity'.", what); show_warning("Note: The connectivity check will connect to a remote server."); return 1; end @@ -920,6 +1022,65 @@ local function check(arg) print("Note: The connectivity check only checks the reachability of the domain.") print("Note: It does not ensure that the check actually reaches this specific prosody instance.") end + + if what == "turn" then + local turn_enabled_hosts = {}; + local turn_services = {}; + + for host in enabled_hosts() do + local has_external_turn = modulemanager.get_modules_for_host(host):contains("turn_external"); + if has_external_turn then + table.insert(turn_enabled_hosts, host); + local turn_host = configmanager.get(host, "turn_external_host") or host; + local turn_port = configmanager.get(host, "turn_external_port") or 3478; + local turn_secret = configmanager.get(host, "turn_external_secret"); + if not turn_secret then + print("Error: Your configuration is missing a turn_external_secret for "..host); + print("Error: TURN will not be advertised for this host."); + ok = false; + else + local turn_id = ("%s:%d"):format(turn_host, turn_port); + if turn_services[turn_id] and turn_services[turn_id].secret ~= turn_secret then + print("Error: Your configuration contains multiple differing secrets"); + print(" for the TURN service at "..turn_id.." - we will only test one."); + elseif not turn_services[turn_id] then + turn_services[turn_id] = { + host = turn_host; + port = turn_port; + secret = turn_secret; + }; + end + end + end + end + + if what == "turn" then + local count = it.count(pairs(turn_services)); + if count == 0 then + print("Error: Unable to find any TURN services configured. Enable mod_turn_external!"); + else + print("Identified "..tostring(count).." TURN services."); + print(""); + end + end + + for turn_id, turn_service in pairs(turn_services) do + print("Testing "..turn_id.."..."); + + local result = check_turn_service(turn_service); + if #result.warnings > 0 then + print(("%d warnings:\n\n "):format(#result.warnings)); + print(table.concat(result.warnings, "\n ")); + end + if result.error then + print("Error: "..result.error.."\n"); + ok = false; + else + print("Success!\n"); + end + end + end + if not ok then print("Problems found, see above."); else -- cgit v1.2.3 From 27943c671cab85e37cac86e96f9bd0a064c1c689 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 28 Jun 2021 03:56:45 +0200 Subject: util.bit53: Add left- and right shift operations While not used by anything in Prosody, it is known to be used by some 3rd party modules. --- util/bit53.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util/bit53.lua b/util/bit53.lua index 4b5c2e9c..06799a97 100644 --- a/util/bit53.lua +++ b/util/bit53.lua @@ -3,5 +3,7 @@ return { band = function (a, b) return a & b end; bor = function (a, b) return a | b end; bxor = function (a, b) return a ~ b end; + rshift = function (a, n) return a >> n end; + lshift = function (a, n) return a << n end; }; -- cgit v1.2.3 From 1f257ecbb43ef08ae142f2b628819d327d066ee0 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 4 Mar 2022 16:55:32 +0100 Subject: net.stun: Use util.strbitop Improves performance since the whole procedure is done in C --- net/stun.lua | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/net/stun.lua b/net/stun.lua index aefc4b27..688becc3 100644 --- a/net/stun.lua +++ b/net/stun.lua @@ -3,17 +3,7 @@ local hashes = require "util.hashes"; local net = require "util.net"; local random = require "util.random"; local struct = require "util.struct"; - ---- Private helpers - --- XORs a string with another string -local function sxor(x, y) - local r = {}; - for i = 1, #x do - r[i] = string.char(bit32.bxor(x:byte(i), y:byte(i))); - end - return table.concat(r); -end +local sxor = require"util.strbitop".sxor; --- Public helpers -- cgit v1.2.3 From 7579bee6bbc8d851687a98a0569f45126592d0b1 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 4 Mar 2022 16:58:28 +0100 Subject: net.stun: Use util.bitcompat to deal with bit module variances across Lua versions --- net/stun.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/net/stun.lua b/net/stun.lua index 688becc3..a718d4ef 100644 --- a/net/stun.lua +++ b/net/stun.lua @@ -3,6 +3,7 @@ local hashes = require "util.hashes"; local net = require "util.net"; local random = require "util.random"; local struct = require "util.struct"; +local bit32 = require"util.bitcompat"; local sxor = require"util.strbitop".sxor; --- Public helpers -- cgit v1.2.3 From a6265e45a04a7f7d5ae39c5608f7a350be1410db Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 4 Mar 2022 16:13:05 +0000 Subject: net.stun: Add tests for serialization/deserialization --- spec/net_stun_spec.lua | 100 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 spec/net_stun_spec.lua diff --git a/spec/net_stun_spec.lua b/spec/net_stun_spec.lua new file mode 100644 index 00000000..9b6e844a --- /dev/null +++ b/spec/net_stun_spec.lua @@ -0,0 +1,100 @@ +local hex = require "util.hex"; + +local function parse(pkt_desc) + local result = {}; + for line in pkt_desc:gmatch("([^\n]+)\n") do + local b1, b2, b3, b4 = line:match("^%s*(%x%x) (%x%x) (%x%x) (%x%x)%s"); + if b1 then + table.insert(result, b1); + table.insert(result, b2); + table.insert(result, b3); + table.insert(result, b4); + end + end + return hex.decode(table.concat(result)); +end + +local sample_packet = parse[[ + 00 01 00 60 Request type and message length + 21 12 a4 42 Magic cookie + 78 ad 34 33 } + c6 ad 72 c0 } Transaction ID + 29 da 41 2e } + 00 06 00 12 USERNAME attribute header + e3 83 9e e3 } + 83 88 e3 83 } + aa e3 83 83 } Username value (18 bytes) and padding (2 bytes) + e3 82 af e3 } + 82 b9 00 00 } + 00 15 00 1c NONCE attribute header + 66 2f 2f 34 } + 39 39 6b 39 } + 35 34 64 36 } + 4f 4c 33 34 } Nonce value + 6f 4c 39 46 } + 53 54 76 79 } + 36 34 73 41 } + 00 14 00 0b REALM attribute header + 65 78 61 6d } + 70 6c 65 2e } Realm value (11 bytes) and padding (1 byte) + 6f 72 67 00 } + 00 08 00 14 MESSAGE-INTEGRITY attribute header + f6 70 24 65 } + 6d d6 4a 3e } + 02 b8 e0 71 } HMAC-SHA1 fingerprint + 2e 85 c9 a2 } + 8c a8 96 66 } +]]; + +--print(hex.encode(sample_packet)) +print(sample_packet) + +describe("net.stun", function () + local stun = require "net.stun"; + + it("works", function () + local packet = stun.new_packet(); + assert.is_string(packet:serialize()); + end); + + it("can decode the sample packet", function () + local packet = stun.new_packet():deserialize(sample_packet); + assert(packet); + local method, method_name = packet:get_method(); + assert.equal(1, method); + assert.equal("binding", method_name); + assert.equal("example.org", packet:get_attribute("realm")); + end); + + it("can generate the sample packet", function () + -- These values, and the sample packet, come from RFC 5769 2.4 + local username = string.char( + -- U+30DE KATAKANA LETTER MA + 0xE3, 0x83, 0x9E, + -- U+30C8 KATAKANA LETTER TO + 0xE3, 0x83, 0x88, + -- U+30EA KATAKANA LETTER RI + 0xE3, 0x83, 0xAA, + -- U+30C3 KATAKANA LETTER SMALL TU + 0xE3, 0x83, 0x83, + -- U+30AF KATAKANA LETTER KU + 0xE3, 0x82, 0xAF, + -- U+30B9 KATAKANA LETTER SU + 0xE3, 0x82, 0xB9 + ); + + -- Password: "TheMtr" and "TheMatrIX" (without + -- quotes) respectively before and after SASLprep processing + local password = "TheMatrIX"; + local realm = "example.org"; + + local p3 = stun.new_packet("binding", "request"); + p3.transaction_id = hex.decode("78AD3433C6AD72C029DA412E"); + p3:add_attribute("username", username); + p3:add_attribute("nonce", "f//499k954d6OL34oL9FSTvy64sA"); + p3:add_attribute("realm", realm); + local key = stun.get_long_term_auth_key(realm, username, password); + p3:add_message_integrity(key); + assert.equal(sample_packet, p3:serialize()); + end); +end); -- cgit v1.2.3