Which linux distro are you using? I'm on debian jessie.... You can also use "coturn". This is the modern version of rfc5766-turn-server.
Hi cubAfull, I installed "coturn" and I followed your guidelines everything looks ok till I got to "metronome host configuration" not sure how to map these fields to my configuration: Code: turncredentials_secret = "YoUrSecReTAuthStrinG"; turncredentials_host = "turn.your.domain"; turncredentials_port = "3478"; turncredentials_ttl = "3600"; Here's my configuration, I added port & host per STUN configuration: Code: external_services = { ["turn.mydomain.com"] = { [1] = { port = "3478", transport = "udp", type = "turn" }, [2] = { port = "3478", transport = "tcp", type = "turn" } } }; Thanks for your support. Cheers,
Well, first you need to download and enable this two modules: mod_turncredentials and mod_extdisco, please note, I don't know if metronome have or work with this modules! With mod_turncredentials you don't have to insert "external_services = {..." because this is the purpose of this module. Advertise the STUN/TURN services and let only registered users use the TURN service.
Hi Michael, I have some time today and start to play with metronome and found the problem with the script spawn. It's an incompatible mod_auth_external with the actual version of metronome. Edit: See this post: https://www.howtoforge.com/community/threads/xmpp-with-ispconfig.68501/page-2#post-351845 Regard, Michael
Hello everyone, I am watching this thread with interest. Congrats for your work at all on the XMPP module. I found another small bug, but detrimental to proper functioning in multi-server environment. When a domain is added or modified, dns entries are pushed, but it appears that the DNS server(s) ID is not provided. I don't know very well the management of templates on ISPConfig, any idea of what happens?
Hi CubAfull, I just want to update you on "coturn" after installation and enabling all required modules, I was able to make Audio/Video/ShareScreen between 2 Jitsi windows client, In my opinion this would be really a big plus to "Metronome" server. Best Regards.
Hi CubAfull, Sorry, I just found out, the Jitsi app uses their own turn servers as soon I unchecked it, and added my turn server now I'm getting error 401 Unauthorized in my turn logs !!! Code: 242303: handle_udp_packet: New UDP endpoint: local addr 192.168.0.40:3478, remote addr XXX.XXX.XXX.XXX:5020 242303: session 001000000000000035: realm <turn.XXXXXi.com> user <>: incoming packet message processed, error 401: Unauthorized 242303: session 001000000000000035: realm <turn.XXXXX.com> user <>: incoming packet BINDING processed, success 242303: check_stun_auth: Cannot find credentials of user <[email protected]>
Hi CubAfull, One more update, what i found out in the JITSI client, when you edit your account under "ICE" if I uncheck (Use Jitsi's STUN server in case no other servers are available", without adding any STU servers then it is working OK, it is discovering my TURN server and authenticating. Can you please check if this authentication is OK??? I replaced my IP and domain with xxxxxx Code: 357: handle_udp_packet: New UDP endpoint: local addr 192.168.0.40:3478, remote addr xxx.xxx.xxx.xxx:5040 357: session 001000000000000005: realm <turn.xxxxxx.com> user <>: incoming packet BINDING processed, success Thanks .
fix in https://git.ispconfig.org/ispconfig/ispconfig3/commit/77eb71fca0550857e00740ff69cd8e1a08133094
Nice catch @alexalouit @ccoudsi maybe yo need to add the proper DNS records for STUN/TURN discovery. Please check this page: https://wiki.xmpp.org/web/SRV_Records I reed >here< that Jitsi in't compatible with turncredentials mechanism? Also note that the prosody turncredentials module isn't compatible with metronome. Right now, in metronome, I'm testing this module modded by me. Just replace your actual mod_turncredentials code with this: UPDATED Code: -- * Metronome IM * -- -- This file is part of the Metronome XMPP server and is released under the -- ISC License, please see the LICENSE file in this source package for more -- information about copyright and licensing. -- XEP-0215 implementation for time-limited turn credentials -- in Metronome XMPP server. --turncredentials_secret = "keepthissecret"; --turncredentials = { -- ["turn.example.com"] = { -- [1] = { port = "3478", transport = "udp", type = "stun" }, -- [2] = { port = "3478", transport = "tcp", type = "stun" }, -- [3] = { port = "5349", transport = "tcp", type = "stuns" }, -- [4] = { port = "3478", transport = "udp", type = "turn" }, -- [5] = { port = "3478", transport = "tcp", type = "turn" }, -- [6] = { port = "5349", transport = "tcp", type = "turns" } -- } --}; local st = require "util.stanza"; local ipairs, pairs = ipairs, pairs; local secret = module:get_option_string("turncredentials_secret"); local ttl = module:get_option_number("turncredentials_ttl", 86400); local services = module:get_option_table("turncredentials", {}); local hmac_sha1 = require "util.hmac".sha1; local base64 = require "util.encodings".base64; local os_time = os.time; if not (secret) then module:log("error", "turncredentials: missing turncredentials_secret param."); return; end local xmlns_extdisco = "urn:xmpp:extdisco:1"; module:add_feature(xmlns_extdisco); local function render(host, type, info, userpart, nonce, reply) if not type or info.type == type then local data = {}; data.host = host; data.port = info.port; data.transport = info.transport; data.type = info.type; if info.type == "turn" or info.type == "turns" then data.username = userpart; data.password = nonce; end module:log("debug", "turncredentials: sending reply for "..info.type.." request."); reply:tag("service", data):up(); end end module:hook_global("config-reloaded", function() secret = module:get_option_string("turncredentials_secret"); ttl = module:get_option_number("turncredentials_ttl", 86400); services = module:get_option_table("turncredentials", {}); end); module:hook("iq-get/host/"..xmlns_extdisco..":services", function (event) local origin, stanza = event.origin, event.stanza; local service = stanza:get_child("services", xmlns_extdisco); local service_type = service and service.attr.type; local now = os_time() + ttl; local userpart = tostring(now); local nonce = base64.encode(hmac_sha1(secret, tostring(userpart), false)); local reply = st.reply(stanza); reply:tag("services", { xmlns = xmlns_extdisco }); for host, service_info in pairs(services) do if #service_info > 0 then for i, info in ipairs(service_info) do render(host, service_type, info, userpart, nonce, reply); end else render(host, service_type, service_info, userpart, nonce, reply); end end return origin.send(reply); end); module:hook("iq-get/host/"..xmlns_extdisco..":credentials", function (event) local origin, stanza = event.origin, event.stanza; return origin.send(st.error_reply( stanza, "cancel", "feature-not-implemented", "Retrieving short-term credentials is not supported" )); end); With this module in metronome.conf.lua you must set for example this options: UPDATED Code: turncredentials_secret = "keepthissecret"; turncredentials = { ["turn.example.com"] = { [1] = { port = "3478", transport = "udp", type = "stun" }, [2] = { port = "3478", transport = "tcp", type = "stun" }, [3] = { port = "5349", transport = "tcp", type = "stuns" }, [4] = { port = "3478", transport = "udp", type = "turn" }, [5] = { port = "3478", transport = "tcp", type = "turn" }, [6] = { port = "5349", transport = "tcp", type = "turns" } } }; Small update to the mod_auth_external (working fine here): Code: -- * Metronome IM * local nodeprep = require "util.encodings".stringprep.nodeprep; local lpc = require "lpc"; local config = require "core.configmanager"; local log = module._log; local host = module.host; local script_type = config.get(host, "external_auth_protocol") or "generic"; assert(script_type == "ejabberd" or script_type == "generic"); local command = config.get(host, "external_auth_command") or ""; assert(type(command) == "string"); assert(not host:find(":")); local new_sasl = require "util.sasl".new; local external_backend = module:require "sasl_aux".external_backend; local plain_test = module:require "sasl_aux".hashed_plain_test; local pid; local readfile; local writefile; local function send_query(text) if pid and lpc.wait(pid,1) ~= nil then log("debug","error, process died, force reopen"); pid=nil; end if not pid then log("debug", "Opening process " .. command); pid, writefile, readfile = lpc.run(command); end if not pid then log("debug", "Process failed to open"); return nil; end log("debug", "send_query check: " .. text); writefile:write(text); writefile:flush(); if script_type == "ejabberd" then return readfile:read(4); elseif script_type == "generic" then return readfile:read(); end end function do_query(kind, username, password) if not username then return nil, "not-acceptable"; end username = nodeprep(username); if not username then return nil, "jid-malformed"; end local query = (password and "%s:%s:%s:%s" or "%s:%s:%s"):format(kind, username, host, password); local len = #query if len > 1000 then return nil, "policy-violation"; end if script_type == "ejabberd" then local lo = len % 256; local hi = (len - lo) / 256; query = string.char(hi, lo)..query; end if script_type == "generic" then query = query..'\n'; end local response = send_query(query); if (script_type == "ejabberd" and response == "\0\2\0\0") or (script_type == "generic" and response == "0") then return nil, "not-authorized"; elseif (script_type == "ejabberd" and response == "\0\2\0\1") or (script_type == "generic" and response == "1") then return true; else log("debug", "Nonsense back"); return nil, "internal-server-error"; end log("debug", "response: " .. response); end function new_external_provider(host) local provider = { name = "external" }; function provider.test_password(username, password) log("debug", "test_password check: " .. username .. " " .. password); return do_query("auth", username, password); end function provider.set_password(username, password) log("debug", "set_password check: " .. username .. " " .. password); return do_query("setpass", username, password); end function provider.user_exists(username) log("debug", "user_exists check: " .. username); return do_query("isuser", username); end function provider.create_user(username, password) log("debug", "create_user check: " .. username .. " " .. password); return nil, "Account creation/modification not available."; end function provider.get_sasl_handler(session) local testpass_authentication_profile = { external = session.secure and external_backend, plain_test = plain_test, session = session, host = host }; if session.secure then testpass_authentication_profile.order = { "external", "plain_test" }; else testpass_authentication_profile.order = { "plain_test" }; end return new_sasl(module.host, testpass_authentication_profile); end return provider; end module:add_item("auth-provider", new_external_provider(host));
Hi CubAfull, Because I'm using internal authentication this what I did: I replaced your "mod_turncredentials " with my current module, and I added your "metronome.conf.lua" to my "/etc/metronome/hosts/mydomain.com.cfg.lua " the results is, I was able to do a voice call between 2 PC's using Jitsi but the quality of the voice is very bad, so I went back to my original settings and everything is OK, Audio & Video & Share Desktop !! I was monitoring "turn" logs in both configurations and both looks similar !!! How I can verify if Jitsi using my turn server for the communications ???? From my "turn" log it looks OK example : Code: 415171: handle_udp_packet: New UDP endpoint: local addr 192.168.0.40:3478, remote addr xxx.xxx.xxx.xxx:5008 415171: session 000000000000000053: realm <turn.mydomain.com> user <>: incoming packet BINDING processed, success One more thing, I removed my "external_services" section in my "mydomain.cfg.lua" and restarted metronome and I still able to make a voice and video calls ??? Code: external_services = { ["turn.mydomain.com"] = { [1] = { port = "3478", transport = "udp", type = "turn", secret = "MySecretpassword" }, [2] = { port = "3478", transport = "tcp", type = "turn", secret= "MySecretpassword" } }, ["stun.mydomain.com"] = { [1] = { port = "3478", transport = "udp", type = "stun", secret = "MySecretpassword" }, [2] = { port = "3478", transport = "tcp", type = "stun", secret= "MySecretpassword" } } }; FYI, I added the following services to my DNS: Code: _turn._tcp.mydomain.com _turns._tcp.mydomain.com _turn._udp.mydomain.com _stun._tcp.mydomain.com _stuns._tcp.mydomain.com _stun._udp.mydomain.com Regarding the link you sent me >here< it looks this conversation was in 2014 about "Jitsi Android" BTW, Here's the code for Jitsi Android >here< I was able to build and test on my Android phone. Because I didn't find Android app that supports "jingle". >>>>Ok, I just compared the files and saw your modifications I will implement external authentication and see the results Cheers,
Hi CubAfull, I updated the following files: My "mod_turncredentials.lua" with your modifications My "domain.cfg.lua" with your "metronome.conf.lua" (Basically I replaced my external section with your modifications, and I enabled External Auth) My "mod_auth_external.lua" with your "mod_auth_external.lua" The results is as follow: PSI (audio) ok --> turn log errors: Code: incoming packet message processed, error 401: Unauthorized JItsi (audio & video) Ok, takes more time to connect -->turn log errors: Code: incoming packet message processed, error 401: Unauthorized So, I'm confused how it works with the 401 errors ?? Also, I noticed you removed the modifications from "mod_auth_external.lua " which suppose to make metronome work with ISPconfig XMPP users ?? so, how it is working now?? One more thing I noticed metronome complains about some folders not found example "offline" ... Cheers,
Hi, This is how is working right now in my servers... Modules from this post (updated): https://www.howtoforge.com/community/threads/xmpp-with-ispconfig.68501/page-2#post-351845 DNS SRV records ONLY for STUN. (Jitsi use this) You see this "401: Unauthorized" message because Jitsi don't support XEP-0215 (time-limited turn credentials) When you make a call in Jitsi, go to: Code: %LOCALAPPDATA%\Jitsi\log You most see this (with your server IP): Code: Auto discovered harvester is STUN harvester(srvr: xxx.xxx.xxx.xxx:3478/udp) I use the turncredentials module only for Jappix (it support XEP-0215) Use the updated module I post. For me is working ok.
Hi CubAfull, I just updated the modules and removed "turn" services from DNS, now it is working OK, but if I use "Jitsi", it takes 20 seconds to start ringing on the other side, not sure why?? it was almost instantaneously before !! I noticed this error: Code: Nov 26 10:42:53 anon.MYDOMAIN.com:turncredentials error turncredentials: missing turncredentials_secret param. I went back to my configuration and it looks ok where: /etc/turnserver.conf Code: lt-cred-mech use-auth-secret static-auth-secret= keepthissecret realm=turn.mydomain.com cert=/etc/metronome/certs/ mydomain.com.cert pkey=/etc/metronome/certs/ mydomain.com.key and I have added the following to my " /etc/metronome/hosts/ mydomain.com.cfg.lua" Code: turncredentials_secret = "keepthissecret"; turncredentials = { ["turn.MYDOMAIN.com"] = { [1] = { port = "3478", transport = "udp", type = "stun" }, [2] = { port = "3478", transport = "tcp", type = "stun" }, [3] = { port = "5349", transport = "tcp", type = "stuns" }, [4] = { port = "3478", transport = "udp", type = "turn" }, [5] = { port = "3478", transport = "tcp", type = "turn" }, [6] = { port = "5349", transport = "tcp", type = "turns" } } }; Do I have the "turncredentials_secret" missing from some other file?? Cheers,
Hi, you need to add this params to the global config (/etc/metronome/metronome.conf.lua) before any defines host, not in the host config. For the mod_websockets problem, just remove the s from the word websockets in your loaded modules. Use just "websocket".
Hi CubAfull, Thanks for your support, I don't see any more obvious errors, the only thing left is the 20 seconds delay to start ringing on the receiver side, any ideas where should I look???Do you see this issue?? I remember when I switched from internal authentication to external this issue came up !!! Cheers,
Mmmm in my case, making a call from my office to my house using Jitsi or Jappix the ringing is almost instant. When you make a call with Jitsi, do you see "Auto discovered harvester is STUN harvester(srvr: xxx.xxx.xxx.xxx:3478/udp)" in the Jitsi log?
Yes, I see " harvester is STUN": Code: 12:10:16.983 INFO: [89] impl.protocol.jabber.IceUdpTransportManager.createIceAgent().173 Auto discovered harvester is STUN harvester(srvr: xxx.xxx.xxx.xxx:3478/udp) Also I see the harvester is TURN too later in the log: Code: 13:13:12.853 INFO: [622] impl.protocol.jabber.IceUdpTransportManager.createIceAgent().173 Auto discovered harvester is TURN harvester(srvr: xxx.xxx.xxx.xxx:3478/udp)