-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmod_tcpproxy.lua
More file actions
121 lines (108 loc) · 3.83 KB
/
Copy pathmod_tcpproxy.lua
File metadata and controls
121 lines (108 loc) · 3.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
local st = require "util.stanza";
local xmlns_ibb = "http://jabber.org/protocol/ibb";
local xmlns_tcp = "http://prosody.im/protocol/tcpproxy";
local host_attr, port_attr = xmlns_tcp.."\1host", xmlns_tcp.."\1port";
local base64 = require "util.encodings".base64;
local b64, unb64 = base64.encode, base64.decode;
local host = module.host;
local open_connections = {};
local function new_session(jid, sid, conn)
if not open_connections[jid] then
open_connections[jid] = {};
end
open_connections[jid][sid] = conn;
end
local function close_session(jid, sid)
if open_connections[jid] then
open_connections[jid][sid] = nil;
if next(open_connections[jid]) == nil then
open_connections[jid] = nil;
end
return true;
end
end
function proxy_component(origin, stanza)
local ibb_tag = stanza.tags[1];
if (not (stanza.name == "iq" and stanza.attr.type == "set")
and stanza.name ~= "message")
or
(not (ibb_tag)
or ibb_tag.attr.xmlns ~= xmlns_ibb) then
if stanza.attr.type ~= "error" then
origin.send(st.error_reply(stanza, "cancel", "service-unavailable"));
end
return;
end
if ibb_tag.name == "open" then
-- Starting a new stream
local to_host, to_port = ibb_tag.attr[host_attr], ibb_tag.attr[port_attr];
local jid, sid = stanza.attr.from, ibb_tag.attr.sid;
if not (to_host and to_port) then
return origin.send(st.error_reply(stanza, "modify", "bad-request", "No host/port specified"));
elseif not sid or sid == "" then
return origin.send(st.error_reply(stanza, "modify", "bad-request", "No sid specified"));
elseif ibb_tag.attr.stanza ~= "message" then
return origin.send(st.error_reply(stanza, "modify", "bad-request", "Only 'message' stanza transport is supported"));
end
local conn, err = socket.tcp();
if not conn then
return origin.send(st.error_reply(stanza, "wait", "resource-constraint", err));
end
conn:settimeout(0);
local success, err = conn:connect(to_host, to_port);
if not success and err ~= "timeout" then
return origin.send(st.error_reply(stanza, "wait", "remote-server-not-found", err));
end
local listener,seq = {}, 0;
function listener.onconnect(conn)
origin.send(st.reply(stanza));
end
function listener.onincoming(conn, data)
origin.send(st.message({to=jid,from=host})
:tag("data", {xmlns=xmlns_ibb,seq=seq,sid=sid})
:text(b64(data)));
seq = seq + 1;
end
function listener.ondisconnect(conn, err)
origin.send(st.message({to=jid,from=host})
:tag("close", {xmlns=xmlns_ibb,sid=sid}));
close_session(jid, sid);
end
conn = server.wrapclient(conn, to_host, to_port, listener, "*a" );
new_session(jid, sid, conn);
elseif ibb_tag.name == "data" then
local conn = open_connections[stanza.attr.from][ibb_tag.attr.sid];
if conn then
local data = unb64(ibb_tag:get_text());
if data then
conn:write(data);
else
return origin.send(
st.error_reply(stanza, "modify", "bad-request", "Invalid data (base64?)")
);
end
else
return origin.send(st.error_reply(stanza, "cancel", "item-not-found"));
end
elseif ibb_tag.name == "close" then
if close_session(stanza.attr.from, ibb_tag.attr.sid) then
origin.send(st.reply(stanza));
else
return origin.send(st.error_reply(stanza, "cancel", "item-not-found"));
end
end
end
local function stanza_handler(event)
proxy_component(event.origin, event.stanza);
return true;
end
module:hook("iq/bare", stanza_handler, -1);
module:hook("message/bare", stanza_handler, -1);
module:hook("presence/bare", stanza_handler, -1);
module:hook("iq/full", stanza_handler, -1);
module:hook("message/full", stanza_handler, -1);
module:hook("presence/full", stanza_handler, -1);
module:hook("iq/host", stanza_handler, -1);
module:hook("message/host", stanza_handler, -1);
module:hook("presence/host", stanza_handler, -1);
require "core.componentmanager".register_component(host, function() end); -- COMPAT Prosody 0.7