Software /
code /
prosody
Comparison
plugins/mod_proxy65.lua @ 4679:5b52b5eaa03d
mod_proxy65: Port to portmanager, make a shared module
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Tue, 24 Apr 2012 18:50:22 +0100 |
parent | 4414:aa2e79f20962 |
child | 4685:3d90264c7b3d |
comparison
equal
deleted
inserted
replaced
4678:9613673f916a | 4679:5b52b5eaa03d |
---|---|
4 -- Copyright (C) 2009 Thilo Cestonaro | 4 -- Copyright (C) 2009 Thilo Cestonaro |
5 -- | 5 -- |
6 -- This project is MIT/X11 licensed. Please see the | 6 -- This project is MIT/X11 licensed. Please see the |
7 -- COPYING file in the source package for more information. | 7 -- COPYING file in the source package for more information. |
8 -- | 8 -- |
9 --[[ | |
10 * to restart the proxy in the console: e.g. | |
11 module:unload("proxy65"); | |
12 > server.removeserver(<proxy65_port>); | |
13 module:load("proxy65", <proxy65_jid>); | |
14 ]]-- | |
15 | 9 |
10 module:set_global(); | |
16 | 11 |
17 local module = module; | |
18 local tostring = tostring; | |
19 local jid_compare, jid_prep = require "util.jid".compare, require "util.jid".prep; | 12 local jid_compare, jid_prep = require "util.jid".compare, require "util.jid".prep; |
20 local st = require "util.stanza"; | 13 local st = require "util.stanza"; |
21 local connlisteners = require "net.connlisteners"; | |
22 local sha1 = require "util.hashes".sha1; | 14 local sha1 = require "util.hashes".sha1; |
15 local b64 = require "util.encodings".base64.encode; | |
23 local server = require "net.server"; | 16 local server = require "net.server"; |
24 local b64 = require "util.encodings".base64.encode; | |
25 | 17 |
26 local host, name = module:get_host(), "SOCKS5 Bytestreams Service"; | 18 local sessions, transfers = module:shared("sessions", "transfers"); |
27 local sessions, transfers = {}, {}; | |
28 | |
29 local proxy_port = module:get_option("proxy65_port") or 5000; | |
30 local proxy_interface = module:get_option("proxy65_interface") or "*"; | |
31 local proxy_address = module:get_option("proxy65_address") or (proxy_interface ~= "*" and proxy_interface) or host; | |
32 local proxy_acl = module:get_option("proxy65_acl"); | |
33 local max_buffer_size = 4096; | 19 local max_buffer_size = 4096; |
34 | 20 |
35 local connlistener = { default_port = proxy_port, default_interface = proxy_interface, default_mode = "*a" }; | 21 local listener = {}; |
36 | 22 |
37 function connlistener.onincoming(conn, data) | 23 function listener.onincoming(conn, data) |
38 local session = sessions[conn] or {}; | 24 local session = sessions[conn] or {}; |
39 | 25 |
40 local transfer = transfers[session.sha]; | 26 local transfer = transfers[session.sha]; |
41 if transfer and transfer.activated then -- copy data between initiator and target | 27 if transfer and transfer.activated then -- copy data between initiator and target |
42 local initiator, target = transfer.initiator, transfer.target; | 28 local initiator, target = transfer.initiator, transfer.target; |
82 module:log("debug", "Invalid SOCKS5 negotiation recieved: '%s'", b64(data)); | 68 module:log("debug", "Invalid SOCKS5 negotiation recieved: '%s'", b64(data)); |
83 end | 69 end |
84 end | 70 end |
85 end | 71 end |
86 | 72 |
87 function connlistener.ondisconnect(conn, err) | 73 function listener.ondisconnect(conn, err) |
88 local session = sessions[conn]; | 74 local session = sessions[conn]; |
89 if session then | 75 if session then |
90 if transfers[session.sha] then | 76 if transfers[session.sha] then |
91 local initiator, target = transfers[session.sha].initiator, transfers[session.sha].target; | 77 local initiator, target = transfers[session.sha].initiator, transfers[session.sha].target; |
92 if initiator == conn and target ~= nil then | 78 if initiator == conn and target ~= nil then |
99 -- Clean up any session-related stuff here | 85 -- Clean up any session-related stuff here |
100 sessions[conn] = nil; | 86 sessions[conn] = nil; |
101 end | 87 end |
102 end | 88 end |
103 | 89 |
104 module:add_identity("proxy", "bytestreams", name); | 90 function module.add_host(module) |
105 module:add_feature("http://jabber.org/protocol/bytestreams"); | 91 local host, name = module:get_host(), module:get_option_string("name", "SOCKS5 Bytestreams Service"); |
92 | |
93 local proxy_address = module:get_option("proxy65_address", host); | |
94 local proxy_port = module:get_option_number("proxy65_port", next(portmanager.get_active_services():search("proxy65", nil)[1])); | |
95 local proxy_acl = module:get_option("proxy65_acl"); | |
106 | 96 |
107 module:hook("iq-get/host/http://jabber.org/protocol/disco#info:query", function(event) | 97 module:add_identity("proxy", "bytestreams", name); |
108 local origin, stanza = event.origin, event.stanza; | 98 module:add_feature("http://jabber.org/protocol/bytestreams"); |
109 origin.send(st.reply(stanza):query("http://jabber.org/protocol/disco#info") | |
110 :tag("identity", {category='proxy', type='bytestreams', name=name}):up() | |
111 :tag("feature", {var="http://jabber.org/protocol/bytestreams"}) ); | |
112 return true; | |
113 end, -1); | |
114 | |
115 module:hook("iq-get/host/http://jabber.org/protocol/disco#items:query", function(event) | |
116 local origin, stanza = event.origin, event.stanza; | |
117 origin.send(st.reply(stanza):query("http://jabber.org/protocol/disco#items")); | |
118 return true; | |
119 end, -1); | |
120 | |
121 module:hook("iq-get/host/http://jabber.org/protocol/bytestreams:query", function(event) | |
122 local origin, stanza = event.origin, event.stanza; | |
123 | 99 |
124 -- check ACL | 100 module:hook("iq-get/host/http://jabber.org/protocol/disco#info:query", function(event) |
125 while proxy_acl and #proxy_acl > 0 do -- using 'while' instead of 'if' so we can break out of it | 101 local origin, stanza = event.origin, event.stanza; |
126 local jid = stanza.attr.from; | 102 origin.send(st.reply(stanza):query("http://jabber.org/protocol/disco#info") |
127 for _, acl in ipairs(proxy_acl) do | 103 :tag("identity", {category='proxy', type='bytestreams', name=name}):up() |
128 if jid_compare(jid, acl) then break; end | 104 :tag("feature", {var="http://jabber.org/protocol/bytestreams"}) ); |
105 return true; | |
106 end, -1); | |
107 | |
108 module:hook("iq-get/host/http://jabber.org/protocol/disco#items:query", function(event) | |
109 local origin, stanza = event.origin, event.stanza; | |
110 origin.send(st.reply(stanza):query("http://jabber.org/protocol/disco#items")); | |
111 return true; | |
112 end, -1); | |
113 | |
114 module:hook("iq-get/host/http://jabber.org/protocol/bytestreams:query", function(event) | |
115 local origin, stanza = event.origin, event.stanza; | |
116 | |
117 -- check ACL | |
118 while proxy_acl and #proxy_acl > 0 do -- using 'while' instead of 'if' so we can break out of it | |
119 local jid = stanza.attr.from; | |
120 for _, acl in ipairs(proxy_acl) do | |
121 if jid_compare(jid, acl) then break; end | |
122 end | |
123 module:log("warn", "Denying use of proxy for %s", tostring(stanza.attr.from)); | |
124 origin.send(st.error_reply(stanza, "auth", "forbidden")); | |
125 return true; | |
129 end | 126 end |
130 module:log("warn", "Denying use of proxy for %s", tostring(stanza.attr.from)); | 127 |
131 origin.send(st.error_reply(stanza, "auth", "forbidden")); | 128 local sid = stanza.tags[1].attr.sid; |
129 origin.send(st.reply(stanza):tag("query", {xmlns="http://jabber.org/protocol/bytestreams", sid=sid}) | |
130 :tag("streamhost", {jid=host, host=proxy_address, port=proxy_port})); | |
132 return true; | 131 return true; |
133 end | 132 end); |
134 | 133 |
135 local sid = stanza.tags[1].attr.sid; | 134 module:hook("iq-set/host/http://jabber.org/protocol/bytestreams:query", function(event) |
136 origin.send(st.reply(stanza):tag("query", {xmlns="http://jabber.org/protocol/bytestreams", sid=sid}) | 135 local origin, stanza = event.origin, event.stanza; |
137 :tag("streamhost", {jid=host, host=proxy_address, port=proxy_port})); | 136 |
138 return true; | 137 local query = stanza.tags[1]; |
139 end); | 138 local sid = query.attr.sid; |
140 | 139 local from = stanza.attr.from; |
141 module.unload = function() | 140 local to = query:get_child_text("activate"); |
142 connlisteners.deregister(module.host .. ':proxy65'); | 141 local prepped_to = jid_prep(to); |
142 | |
143 local info = "sid: "..tostring(sid)..", initiator: "..tostring(from)..", target: "..tostring(prepped_to or to); | |
144 if prepped_to and sid then | |
145 local sha = sha1(sid .. from .. prepped_to, true); | |
146 if not transfers[sha] then | |
147 module:log("debug", "Activation request has unknown session id; activation failed (%s)", info); | |
148 origin.send(st.error_reply(stanza, "modify", "item-not-found")); | |
149 elseif not transfers[sha].initiator then | |
150 module:log("debug", "The sender was not connected to the proxy; activation failed (%s)", info); | |
151 origin.send(st.error_reply(stanza, "cancel", "not-allowed", "The sender (you) is not connected to the proxy")); | |
152 --elseif not transfers[sha].target then -- can't happen, as target is set when a transfer object is created | |
153 -- module:log("debug", "The recipient was not connected to the proxy; activation failed (%s)", info); | |
154 -- origin.send(st.error_reply(stanza, "cancel", "not-allowed", "The recipient is not connected to the proxy")); | |
155 else -- if transfers[sha].initiator ~= nil and transfers[sha].target ~= nil then | |
156 module:log("debug", "Transfer activated (%s)", info); | |
157 transfers[sha].activated = true; | |
158 transfers[sha].target:resume(); | |
159 transfers[sha].initiator:resume(); | |
160 origin.send(st.reply(stanza)); | |
161 end | |
162 elseif to and sid then | |
163 module:log("debug", "Malformed activation jid; activation failed (%s)", info); | |
164 origin.send(st.error_reply(stanza, "modify", "jid-malformed")); | |
165 else | |
166 module:log("debug", "Bad request; activation failed (%s)", info); | |
167 origin.send(st.error_reply(stanza, "modify", "bad-request")); | |
168 end | |
169 return true; | |
170 end); | |
143 end | 171 end |
144 | 172 |
145 module:hook("iq-set/host/http://jabber.org/protocol/bytestreams:query", function(event) | 173 module:provides("net", { |
146 local origin, stanza = event.origin, event.stanza; | 174 default_port = 5000; |
147 | 175 listener = listener; |
148 local query = stanza.tags[1]; | 176 }); |
149 local sid = query.attr.sid; | |
150 local from = stanza.attr.from; | |
151 local to = query:get_child_text("activate"); | |
152 local prepped_to = jid_prep(to); | |
153 | |
154 local info = "sid: "..tostring(sid)..", initiator: "..tostring(from)..", target: "..tostring(prepped_to or to); | |
155 if prepped_to and sid then | |
156 local sha = sha1(sid .. from .. prepped_to, true); | |
157 if not transfers[sha] then | |
158 module:log("debug", "Activation request has unknown session id; activation failed (%s)", info); | |
159 origin.send(st.error_reply(stanza, "modify", "item-not-found")); | |
160 elseif not transfers[sha].initiator then | |
161 module:log("debug", "The sender was not connected to the proxy; activation failed (%s)", info); | |
162 origin.send(st.error_reply(stanza, "cancel", "not-allowed", "The sender (you) is not connected to the proxy")); | |
163 --elseif not transfers[sha].target then -- can't happen, as target is set when a transfer object is created | |
164 -- module:log("debug", "The recipient was not connected to the proxy; activation failed (%s)", info); | |
165 -- origin.send(st.error_reply(stanza, "cancel", "not-allowed", "The recipient is not connected to the proxy")); | |
166 else -- if transfers[sha].initiator ~= nil and transfers[sha].target ~= nil then | |
167 module:log("debug", "Transfer activated (%s)", info); | |
168 transfers[sha].activated = true; | |
169 transfers[sha].target:resume(); | |
170 transfers[sha].initiator:resume(); | |
171 origin.send(st.reply(stanza)); | |
172 end | |
173 elseif to and sid then | |
174 module:log("debug", "Malformed activation jid; activation failed (%s)", info); | |
175 origin.send(st.error_reply(stanza, "modify", "jid-malformed")); | |
176 else | |
177 module:log("debug", "Bad request; activation failed (%s)", info); | |
178 origin.send(st.error_reply(stanza, "modify", "bad-request")); | |
179 end | |
180 return true; | |
181 end); | |
182 | |
183 if not connlisteners.register(module.host .. ':proxy65', connlistener) then | |
184 module:log("error", "mod_proxy65: Could not establish a connection listener. Check your configuration please."); | |
185 module:log("error", "Possibly two proxy65 components are configured to share the same port."); | |
186 end | |
187 | |
188 connlisteners.start(module.host .. ':proxy65'); |