Software /
code /
prosody-modules
Comparison
mod_proxy65/mod_proxy65.lua @ 65:a35eb0764ac6
mod_proxy65: tcp connection of initiator and target are established
author | Thilo Cestonaro <thilo@cestona.ro> |
---|---|
date | Wed, 28 Oct 2009 00:03:28 +0100 |
parent | 64:853c3c7e9936 |
child | 66:b86ae5e21a56 |
comparison
equal
deleted
inserted
replaced
64:853c3c7e9936 | 65:a35eb0764ac6 |
---|---|
14 local component_register = require "core.componentmanager".register_component; | 14 local component_register = require "core.componentmanager".register_component; |
15 local component_deregister = require "core.componentmanager".deregister_component; | 15 local component_deregister = require "core.componentmanager".deregister_component; |
16 local configmanager = require "core.configmanager"; | 16 local configmanager = require "core.configmanager"; |
17 local config_get = require "core.configmanager".get; | 17 local config_get = require "core.configmanager".get; |
18 local connlisteners_register = require "net.connlisteners".register; | 18 local connlisteners_register = require "net.connlisteners".register; |
19 local connlisteners_start = require "net.connlisteners".start; | |
19 local connlisteners_deregister = require "net.connlisteners".deregister; | 20 local connlisteners_deregister = require "net.connlisteners".deregister; |
20 local adns, dns = require "net.adns", require "net.dns"; | 21 local adns, dns = require "net.adns", require "net.dns"; |
21 local add_task = require "util.timer".add_task; | 22 local add_task = require "util.timer".add_task; |
22 local max_dns_depth = config.get("*", "core", "dns_max_depth") or 3; | 23 local max_dns_depth = config.get("*", "core", "dns_max_depth") or 3; |
23 local dns_timeout = config.get("*", "core", "dns_timeout") or 60; | 24 local dns_timeout = config.get("*", "core", "dns_timeout") or 60; |
25 local serialize = require "util.serialization".serialize; | |
26 local sha1 = require "util.hashes".sha1; | |
24 | 27 |
25 local replies_cache = {}; | 28 local replies_cache = {}; |
26 local _host = module:get_host(); | 29 local _host = module:get_host(); |
27 local _name = "SOCKS5 Bytestreams Service"; | 30 local _name = "SOCKS5 Bytestreams Service"; |
28 local _config = config_get(_host, "core", "proxy65"); | |
29 local connlistener = {registered=false}; | 31 local connlistener = {registered=false}; |
32 local _config = {}; | |
30 local sessions = {}; | 33 local sessions = {}; |
34 local transfers = {}; | |
31 local component; | 35 local component; |
32 | 36 |
33 if _config == nil then | 37 _config.port = config_get(_host, "core", "port"); |
34 _config = {}; | 38 _config.interface = config_get(_host, "core", "interface"); |
35 end | 39 |
36 if _config.port == nil then | 40 if _config.port == nil then |
37 _config.port = 5000; | 41 _config.port = 5000; |
38 end | 42 end |
39 | 43 |
44 local function bin2hex(bin) | |
45 return bin:gsub(".", function (c) return ("%02x"):format(c:byte()); end) | |
46 end | |
47 | |
48 function new_session(conn) | |
49 local w = function(s) conn.write(s:gsub("\n", "\r\n")); end; | |
50 local session = { conn = conn; | |
51 send = function (t) w(tostring(t)); end; | |
52 print = function (t) w("| "..tostring(t).."\n"); end; | |
53 disconnect = function () conn.close(); end; | |
54 }; | |
55 | |
56 return session; | |
57 end | |
58 | |
59 function connlistener.listener(conn, data) | |
60 module:log("debug", "listener called....") | |
61 local session = sessions[conn]; | |
62 | |
63 if data ~= nil then module:log("debug", bin2hex(data)); end | |
64 if not session and data ~= nil and data:byte() == string.char(5):byte() and data:len() > 2 then | |
65 local nmethods = data:sub(2):byte(); | |
66 local methods = data:sub(3); | |
67 local supported = false; | |
68 for i=1, nmethods, 1 do | |
69 if(methods:sub(i):byte() == string.char(0):byte()) then | |
70 supported = true; | |
71 break; | |
72 end | |
73 end | |
74 if(supported) then | |
75 module:log("debug", "new session found ... ") | |
76 session = new_session(conn); | |
77 sessions[conn] = session; | |
78 session.send(string.char(5, 0)); | |
79 end | |
80 elseif data ~= nil and data:len() > 6 and | |
81 data:sub(1):byte() == string.char(5):byte() and -- SOCKS5 has 5 in first byte | |
82 data:sub(2):byte() == string.char(1):byte() and -- CMD must be 1 | |
83 data:sub(3):byte() == string.char(0):byte() and -- RSV must be 0 | |
84 data:sub(4):byte() == string.char(3):byte() and -- ATYP must be 3 | |
85 data:sub(-2):byte() == string.char(0):byte() and data:sub(-1):byte() == string.char(0):byte() -- PORT must be 0, size 2 byte | |
86 then | |
87 local sha = data:sub(6, data:len() - 2); | |
88 module:log("debug", "gotten sha: >%s<", sha); | |
89 if transfers[sha] == nil then | |
90 transfers[sha] = {}; | |
91 transfers[sha].target = conn; | |
92 module:log("debug", "target connected ... "); | |
93 elseif transfers[sha].target ~= nil then | |
94 transfers[sha].initiator = conn; | |
95 module:log("debug", "initiator connected ... "); | |
96 end | |
97 session.send(string.char(5, 0, 0, 3, 40) .. sha .. string.char(0, 0)); -- VER, REP, RSV, ATYP, BND.ADDR (sha), BND.PORT (2 Byte) | |
98 end | |
99 end | |
100 | |
101 function connlistener.disconnect(conn, err) | |
102 | |
103 end | |
104 | |
105 local function get_disco_info(stanza) | |
106 local reply = replies_cache.disco_info; | |
107 if reply == nil then | |
108 reply = st.iq({type='result', from=_host}):query("http://jabber.org/protocol/disco#info") | |
109 :tag("identity", {category='proxy', type='bytestreams', name=_name}):up() | |
110 :tag("feature", {var="http://jabber.org/protocol/bytestreams"}); | |
111 replies_cache.disco_info = reply; | |
112 end | |
113 | |
114 reply.attr.id = stanza.attr.id; | |
115 reply.attr.to = stanza.attr.from; | |
116 return reply; | |
117 end | |
118 | |
119 local function get_disco_items(stanza) | |
120 local reply = replies_cache.disco_items; | |
121 if reply == nil then | |
122 reply = st.iq({type='result', from=_host}):query("http://jabber.org/protocol/disco#items"); | |
123 replies_cache.disco_info = reply; | |
124 end | |
125 | |
126 reply.attr.id = stanza.attr.id; | |
127 reply.attr.to = stanza.attr.from; | |
128 return reply; | |
129 end | |
130 | |
131 local function get_stream_host(stanza) | |
132 local reply = replies_cache.stream_host; | |
133 local sid = stanza.tags[1].attr.sid; | |
134 if reply == nil then | |
135 reply = st.iq({type="result", from=_host}) | |
136 :query("http://jabber.org/protocol/bytestreams") | |
137 :tag("streamhost", {jid=_host, host=_config.interface, port=_config.port}); -- TODO get the correct data | |
138 replies_cache.stream_host = reply; | |
139 end | |
140 | |
141 reply.attr.id = stanza.attr.id; | |
142 reply.attr.to = stanza.attr.from; | |
143 reply.tags[1].attr.sid = sid; | |
144 return reply; | |
145 end | |
146 | |
147 module.unload = function() | |
148 component_deregister(_host); | |
149 connlisteners_deregister("proxy65"); | |
150 end | |
151 | |
152 local function set_activation(stanza) | |
153 local from = nil; | |
154 local to = nil; | |
155 local sid = nil; | |
156 local reply = nil; | |
157 if stanza.attr ~= nil then | |
158 from = stanza.attr.from; | |
159 end | |
160 if stanza.tags[1] ~= nil and tostring(stanza.tags[1].name) == "query" then | |
161 if stanza.tags[1].attr ~= nil then | |
162 sid = stanza.tags[1].attr.sid; | |
163 end | |
164 if stanza.tags[1].tags[1] ~= nil and tostring(stanza.tags[1].tags[1].name) == "activate" then | |
165 to = stanza.tags[1].tags[1][1]; | |
166 end | |
167 end | |
168 if from ~= nil and to ~= nil and sid ~= nil then | |
169 reply = st.iq({type="result", from=_host}); | |
170 reply.attr.id = stanza.attr.id; | |
171 end | |
172 return reply, from, to, sid; | |
173 end | |
174 | |
175 local function forward(initiator, target) | |
176 module:log("debug", "forward it ...."); | |
177 end | |
178 | |
179 | |
40 local function register() | 180 local function register() |
41 connlistener = { default_port = _config.port; default_interface = _config.interface }; | 181 connlistener.default_port = _config.port; |
182 connlistener.default_interface = "*"; | |
183 connlistener.default_mode = "*a"; | |
42 connlistener.registered = connlisteners_register('proxy65', connlistener); | 184 connlistener.registered = connlisteners_register('proxy65', connlistener); |
43 if(connlistener.registered == false) then | 185 if(connlistener.registered == false) then |
44 error("Proxy65: Could not establish a connection listener. Check your configuration please."); | 186 error("Proxy65: Could not establish a connection listener. Check your configuration please."); |
45 else | 187 else |
188 connlistener.handler = connlisteners_start('proxy65'); | |
189 module:log("debug", "Connection listener registered ... ") | |
46 module:add_item("proxy65", {jid=_host, name=_name}) | 190 module:add_item("proxy65", {jid=_host, name=_name}) |
47 component = component_register(_host, function(origin, stanza) | 191 component = component_register(_host, function(origin, stanza) |
48 local to_node, to_host, to_resource = jid_split(stanza.attr.to); | 192 local to_node, to_host, to_resource = jid_split(stanza.attr.to); |
49 if to_node == nil then | 193 if to_node == nil then |
50 local type = stanza.attr.type; | 194 local type = stanza.attr.type; |
55 origin.send(get_disco_info(stanza)); | 199 origin.send(get_disco_info(stanza)); |
56 return true; | 200 return true; |
57 elseif xmlns == "http://jabber.org/protocol/disco#items" then | 201 elseif xmlns == "http://jabber.org/protocol/disco#items" then |
58 origin.send(get_disco_items(stanza)); | 202 origin.send(get_disco_items(stanza)); |
59 return true; | 203 return true; |
60 elseif xmlns == "http://jabber.org/protocol/bytestreams" and stanza.tags[1].attr.sid ~= nil then | 204 elseif xmlns == "http://jabber.org/protocol/bytestreams" then |
61 origin.send(get_stream_host(stanza)); | 205 origin.send(get_stream_host(stanza)); |
62 return true; | 206 return true; |
207 end | |
208 elseif stanza.name == "iq" and type == "set" then | |
209 local reply, from, to, sid = set_activation(stanza); | |
210 if reply ~= nil and from ~= nil and to ~= nil and sid ~= nil then | |
211 module:log("debug", "need to build sha1 of data: from: %s, to: %s, sid: %s", from, to, sid); | |
212 local sha = sha1(sid .. from .. to, true); | |
213 module:log("debug", "generated sha: %s", sha); | |
214 if(transfers[sha] ~= nil and transfers[sha].initiator ~= nil and transfers[sha].target ~= nil) then | |
215 origin.send(reply); | |
216 forward(transfers[sha].initiator, transfers[sha].target); | |
217 transfers[sha] = nil; | |
218 end | |
63 end | 219 end |
64 end | 220 end |
65 end | 221 end |
66 return; | 222 return; |
67 end); | 223 end); |
113 if _config.interface ~= nil then | 269 if _config.interface ~= nil then |
114 register(); | 270 register(); |
115 else | 271 else |
116 getDefaultIP(_host); -- try to DNS lookup module:host() | 272 getDefaultIP(_host); -- try to DNS lookup module:host() |
117 end | 273 end |
118 | |
119 function new_session(conn) | |
120 local w = function(s) conn.write(s:gsub("\n", "\r\n")); end; | |
121 local session = { conn = conn; | |
122 send = function (t) w(tostring(t)); end; | |
123 print = function (t) w("| "..tostring(t).."\n"); end; | |
124 disconnect = function () conn.close(); end; | |
125 }; | |
126 | |
127 return session; | |
128 end | |
129 | |
130 function connlistener.listener(conn, data) | |
131 local session = sessions[conn]; | |
132 | |
133 if not session then | |
134 session = new_session(conn); | |
135 sessions[conn] = session; | |
136 end | |
137 if data then | |
138 end | |
139 end | |
140 | |
141 function connlistener.disconnect(conn, err) | |
142 | |
143 end | |
144 | |
145 local function get_disco_info(stanza) | |
146 local reply = replies_cache.disco_info; | |
147 if reply == nil then | |
148 reply = st.iq({type='result', from=_host}):query("http://jabber.org/protocol/disco#info") | |
149 :tag("identity", {category='proxy', type='bytestreams', name=_name}):up() | |
150 :tag("feature", {var="http://jabber.org/protocol/bytestreams"}); | |
151 replies_cache.disco_info = reply; | |
152 end | |
153 | |
154 reply.attr.id = stanza.attr.id; | |
155 reply.attr.to = stanza.attr.from; | |
156 return reply; | |
157 end | |
158 | |
159 local function get_disco_items(stanza) | |
160 local reply = replies_cache.disco_items; | |
161 if reply == nil then | |
162 reply = st.iq({type='result', from=_host}):query("http://jabber.org/protocol/disco#items"); | |
163 replies_cache.disco_info = reply; | |
164 end | |
165 | |
166 reply.attr.id = stanza.attr.id; | |
167 reply.attr.to = stanza.attr.from; | |
168 return reply; | |
169 end | |
170 | |
171 local function get_stream_host(stanza) | |
172 local reply = replies_cache.stream_host; | |
173 if reply == nil then | |
174 reply = st.iq({type="result", from=_host}) | |
175 :query("http://jabber.org/protocol/bytestreams") | |
176 :tag("streamhost", {jid=_host, host=_config.interface, port=_config.port}); -- TODO get the correct data | |
177 replies_cache.stream_host = reply; | |
178 end | |
179 | |
180 reply.attr.id = stanza.attr.id; | |
181 reply.attr.to = stanza.attr.from; | |
182 reply.tags[1].attr.sid = stanza.tags[1].attr.sid; | |
183 return reply; | |
184 end | |
185 | |
186 module.unload = function() | |
187 component_deregister(_host); | |
188 connlisteners_deregister("proxy65"); | |
189 end |