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 |