Skip to content

Commit

Permalink
{...}: restrict access to external services to the module's host.
Browse files Browse the repository at this point in the history
Configurable, by default
  • Loading branch information
maranda committed Apr 23, 2020
1 parent 977ffd4 commit d8e80d7
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 83 deletions.
97 changes: 53 additions & 44 deletions plugins/mod_extdisco.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ local datetime = require "util.datetime".datetime;
local ipairs, pairs, now, tostring = ipairs, pairs, os.time, tostring;

local services = module:get_option_table("external_services", {});
local restricted = module:get_option_boolean("external_services_restricted", true);

local xmlns_extdisco = "urn:xmpp:extdisco:2";
local xmlns_extdisco_legacy = "urn:xmpp:extdisco:1";
Expand Down Expand Up @@ -63,60 +64,68 @@ local function render_credentials(host, type, info, reply)
end

local function process_iq_services(origin, stanza, proto)
local service = stanza:get_child("service", proto);
local service_type = service and service.attr.type;
local reply = st.reply(stanza);
reply:tag("services", { xmlns = proto });

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, reply, proto);
if (origin.host == module.host) or not restricted then
local service = stanza:get_child("service", proto);
local service_type = service and service.attr.type;
local reply = st.reply(stanza);
reply:tag("services", { xmlns = proto });

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, reply, proto);
end
else
render(host, service_type, service_info, reply, proto);
end
else
render(host, service_type, service_info, reply, proto);
end
end

module:log("debug", "%s requested external service data (%s type)...",
stanza.attr.from or origin.username .. "@" .. origin.host, service_type or "nil");
origin.send(reply);
module:log("debug", "%s requested external service data (%s type)...",
stanza.attr.from or origin.username .. "@" .. origin.host, service_type or "nil");
origin.send(reply);
else
origin.send(st.error_reply(stanza, "cancel", "not-allowed", "External services information is restricted"));
end
return true;
end

local function process_iq_credentials(origin, stanza, proto)
local credentials = stanza:get_child("credentials", proto):child_with_name("service");
if not credentials then
origin.send(st.error_reply(stanza, "modify", "bad-request"));
return true;
end
local function process_iq_credentials(origin, stanza, proto)
if (origin.host == module.host) or not restricted then
local credentials = stanza:get_child("credentials", proto):child_with_name("service");
if not credentials then
origin.send(st.error_reply(stanza, "modify", "bad-request"));
return true;
end

local host, type = credentials.attr.host, credentials.attr.type;
if not host then
origin.send(st.error_reply(stanza, "modify", "not-acceptable", "Please specify at least the hostname"));
return true;
end
local host, type = credentials.attr.host, credentials.attr.type;
if not host then
origin.send(st.error_reply(stanza, "modify", "not-acceptable", "Please specify at least the hostname"));
return true;
end

local service = services[host];
if not service then
origin.send(st.error_reply(stanza, "cancel", "item-not-found", "Specified service is not known"));
return true;
end
local service = services[host];
if not service then
origin.send(st.error_reply(stanza, "cancel", "item-not-found", "Specified service is not known"));
return true;
end

local reply = st.reply(stanza);
reply:tag("credentials", { xmlns = proto });
local found;
for i, info in pairs(service) do
found = render_credentials(host, type, info, reply);
end
if not found then
origin.send(st.error_reply(stanza, "cancel", "item-not-found", "The service doesn't need any credentials"));
return true;
end
local reply = st.reply(stanza);
reply:tag("credentials", { xmlns = proto });
local found;
for i, info in pairs(service) do
found = render_credentials(host, type, info, reply);
end
if not found then
origin.send(st.error_reply(stanza, "cancel", "item-not-found", "The service doesn't need any credentials"));
return true;
end

module:log("debug", "%s requested external service credentials for service host %s (type %s)...",
stanza.attr.from or origin.username .. "@" .. origin.host, host, type or "nil");
origin.send(reply);
module:log("debug", "%s requested external service credentials for service host %s (type %s)...",
stanza.attr.from or origin.username .. "@" .. origin.host, host, type or "nil");
origin.send(reply);
else
origin.send(st.error_reply(stanza, "cancel", "not-allowed", "You are forbidden from requesting temporary credentials, sorry"));
end
return true;
end

Expand Down
89 changes: 50 additions & 39 deletions plugins/mod_jingle_nodes.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ local relay_port = module:get_option_number("jingle_nodes_port", 3478);
local turn_credentials = module:get_option_boolean("jingle_nodes_turn_credentials", false);
local turn_credentials_secret = module:get_option_string("jingle_nodes_turn_secret");
local turn_credentials_ttl = module:get_option_number("jingle_nodes_turn_credentials_ttl", 6200);
local restricted = module:get_option_boolean("jingle_nodes_restricted", true);

local xmlns = "http://jabber.org/protocol/jinglenodes";
local xmlns_credentials = "http://jabber.org/protocol/jinglenodes#turncredentials";
Expand All @@ -33,58 +34,68 @@ end

module:hook("iq-get/host/"..xmlns..":services", function (event)
local origin, stanza = event.origin, event.stanza;
local reply = st.reply(stanza);
reply:tag("services", { xmlns = xmlns });

if relay_tcp then
reply:tag("relay", { policy = "public", address = relay_host, protocol = "tcp" }):up()
reply:tag("tracker", { policy = "public", address = relay_host, protocol = "tcp" }):up()
reply:tag("turn", { policy = "public", address = relay_host, protocol = "tcp" }):up()
reply:tag("stun", { policy = "public", address = relay_host, port = tostring(relay_port), protocol = "tcp" }):up()
end
if relay_udp then
reply:tag("relay", { policy = "public", address = relay_host, protocol = "udp" }):up()
reply:tag("tracker", { policy = "public", address = relay_host, protocol = "udp" }):up()
reply:tag("turn", { policy = "public", address = relay_host, protocol = "udp" }):up()
reply:tag("stun", { policy = "public", address = relay_host, port = tostring(relay_port), protocol = "udp" }):up()
end
if (origin.host == module.host) or not restricted then
local reply = st.reply(stanza);
reply:tag("services", { xmlns = xmlns });

module:log("debug", "%s queried for jingle relay nodes...", stanza.attr.from or origin.username.."@"..origin.host);
origin.send(reply);
if relay_tcp then
reply:tag("relay", { policy = "public", address = relay_host, protocol = "tcp" }):up()
reply:tag("tracker", { policy = "public", address = relay_host, protocol = "tcp" }):up()
reply:tag("turn", { policy = "public", address = relay_host, protocol = "tcp" }):up()
reply:tag("stun", { policy = "public", address = relay_host, port = tostring(relay_port), protocol = "tcp" }):up()
end
if relay_udp then
reply:tag("relay", { policy = "public", address = relay_host, protocol = "udp" }):up()
reply:tag("tracker", { policy = "public", address = relay_host, protocol = "udp" }):up()
reply:tag("turn", { policy = "public", address = relay_host, protocol = "udp" }):up()
reply:tag("stun", { policy = "public", address = relay_host, port = tostring(relay_port), protocol = "udp" }):up()
end

module:log("debug", "%s queried for jingle relay nodes...", stanza.attr.from or origin.username.."@"..origin.host);
origin.send(reply);
else
origin.send(st.error_reply(stanza, "cancel", "not-allowed", "Querying jingle relay nodes information is restricted"));
end
return true;
end);

if turn_credentials and turn_credentials_secret then
module:hook("iq-get/host/"..xmlns_credentials..":turn", function (event)
local origin, stanza = event.origin, event.stanza;
local turn = stanza:get_child("turn", xmlns_credentials);
local protocol = turn and turn.attr.protocol;

if not protocol then
origin.send(st.error_reply(stanza, "modify", "bad-request", "Please specify the transport in the request"));
return true;
end
if (origin.host == module.host) or not restricted then
local turn = stanza:get_child("turn", xmlns_credentials);
local protocol = turn and turn.attr.protocol;

if protocol == "tcp" and not relay_tcp then
origin.send(st.error_reply(stanza, "cancel", "item-not-found", "TCP not supported"));
return true;
elseif protocol == "udp" and not relay_udp then
origin.send(st.error_reply(stanza, "cancel", "item-not-found", "UDP not supported"));
return true;
end
if not protocol then
origin.send(st.error_reply(stanza, "modify", "bad-request", "Please specify the transport in the request"));
return true;
end

local user, pass = generate_nonce();
if protocol == "tcp" and not relay_tcp then
origin.send(st.error_reply(stanza, "cancel", "item-not-found", "TCP not supported"));
return true;
elseif protocol == "udp" and not relay_udp then
origin.send(st.error_reply(stanza, "cancel", "item-not-found", "UDP not supported"));
return true;
end

local reply = st.reply(stanza);
reply:tag("turn", {
ttl = tostring(turn_credentials_ttl),
uri = "turn:"..relay_host..":"..tostring(relay_port).."?transport="..protocol,
username = user,
password = pass,
});
local user, pass = generate_nonce();

local reply = st.reply(stanza);
reply:tag("turn", {
ttl = tostring(turn_credentials_ttl),
uri = "turn:"..relay_host..":"..tostring(relay_port).."?transport="..protocol,
username = user,
password = pass,
});

module:log("debug", "%s queried %s turn credentials...", stanza.attr.from or origin.username.."@"..origin.host, protocol);
origin.send(reply);
module:log("debug", "%s queried %s turn credentials...", stanza.attr.from or origin.username.."@"..origin.host, protocol);
origin.send(reply);
else
origin.send(st.error_reply(stanza, "cancel", "not-allowed", "You are forbidden from requesting TURN credentials, sorry"));
end
return true;
end);
end

0 comments on commit d8e80d7

Please sign in to comment.