Software / code / prosody-modules
Comparison
mod_proxy65/proxy65/mod_proxy65.lua @ 63:d0f5a16e7a66
mod_proxy65: create connection listener, interface a. port are configureable but not needed
| author | Thilo Cestonaro <thilo@cestona.ro> |
|---|---|
| date | Mon, 26 Oct 2009 23:25:29 +0100 |
| parent | 31:a0dfa3e5883c |
comparison
equal
deleted
inserted
replaced
| 62:0dfd65bfedb0 | 63:d0f5a16e7a66 |
|---|---|
| 6 | 6 |
| 7 if module:get_host_type() ~= "component" then | 7 if module:get_host_type() ~= "component" then |
| 8 error("proxy65 should be loaded as a component, please see http://prosody.im/doc/components", 0); | 8 error("proxy65 should be loaded as a component, please see http://prosody.im/doc/components", 0); |
| 9 end | 9 end |
| 10 | 10 |
| 11 local _host = module:get_host(); | |
| 12 local _name = "SOCKS5 Bytestreams Service"; | |
| 13 | 11 |
| 14 local jid_split = require "util.jid".split; | 12 local jid_split = require "util.jid".split; |
| 15 local st = require "util.stanza"; | 13 local st = require "util.stanza"; |
| 16 local register_component = require "core.componentmanager".register_component; | 14 local component_register = require "core.componentmanager".register_component; |
| 17 local deregister_component = require "core.componentmanager".deregister_component; | 15 local component_deregister = require "core.componentmanager".deregister_component; |
| 18 local configmanager = require "core.configmanager"; | 16 local configmanager = require "core.configmanager"; |
| 17 local config_get = require "core.configmanager".get; | |
| 18 local connlisteners_register = require "net.connlisteners".register; | |
| 19 local connlisteners_deregister = require "net.connlisteners".deregister; | |
| 20 local adns, dns = require "net.adns", require "net.dns"; | |
| 21 local add_task = require "util.timer".add_task; | |
| 22 local max_dns_depth = config.get("*", "core", "dns_max_depth") or 3; | |
| 23 local dns_timeout = config.get("*", "core", "dns_timeout") or 60; | |
| 19 | 24 |
| 20 local replies_cache = {}; | 25 local replies_cache = {}; |
| 26 local _host = module:get_host(); | |
| 27 local _name = "SOCKS5 Bytestreams Service"; | |
| 28 local _config = config_get(_host, "core", "proxy65"); | |
| 29 local connlistener = {registered=false}; | |
| 30 local sessions = {}; | |
| 31 local component; | |
| 21 | 32 |
| 22 --[[ | 33 if _config == nil then |
| 23 <iq type='result' | 34 _config = {}; |
| 24 from='streamhostproxy.example.net' | 35 end |
| 25 to='initiator@example.com/foo' | 36 if _config.port == nil then |
| 26 id='proxy_info'> | 37 _config.port = 5000; |
| 27 <query xmlns='http://jabber.org/protocol/disco#info'> | 38 end |
| 28 <identity category='proxy' | 39 |
| 29 type='bytestreams' | 40 local function register() |
| 30 name='SOCKS5 Bytestreams Service'/> | 41 connlistener = { default_port = _config.port; default_interface = _config.interface }; |
| 31 <feature var='http://jabber.org/protocol/bytestreams'/> | 42 connlistener.registered = connlisteners_register('proxy65', connlistener); |
| 32 </query> | 43 if(connlistener.registered == false) then |
| 33 </iq> | 44 error("Proxy65: Could not establish a connection listener. Check your configuration please."); |
| 34 ]]-- | 45 else |
| 46 module:add_item("proxy65", {jid=_host, name=_name}) | |
| 47 component = component_register(_host, function(origin, stanza) | |
| 48 local to_node, to_host, to_resource = jid_split(stanza.attr.to); | |
| 49 if to_node == nil then | |
| 50 local type = stanza.attr.type; | |
| 51 if type == "error" or type == "result" then return; end | |
| 52 if stanza.name == "iq" and type == "get" then | |
| 53 local xmlns = stanza.tags[1].attr.xmlns | |
| 54 if xmlns == "http://jabber.org/protocol/disco#info" then | |
| 55 origin.send(get_disco_info(stanza)); | |
| 56 return true; | |
| 57 elseif xmlns == "http://jabber.org/protocol/disco#items" then | |
| 58 origin.send(get_disco_items(stanza)); | |
| 59 return true; | |
| 60 elseif xmlns == "http://jabber.org/protocol/bytestreams" and stanza.tags[1].attr.sid ~= nil then | |
| 61 origin.send(get_stream_host(stanza)); | |
| 62 return true; | |
| 63 end | |
| 64 end | |
| 65 end | |
| 66 return; | |
| 67 end); | |
| 68 end | |
| 69 end | |
| 70 | |
| 71 local function getDefaultIP(host) | |
| 72 local handle; | |
| 73 handle = adns.lookup(function (reply) | |
| 74 handle = nil; | |
| 75 | |
| 76 -- COMPAT: This is a compromise for all you CNAME-(ab)users :) | |
| 77 if not (reply and reply[#reply] and reply[#reply].a) then | |
| 78 local count = max_dns_depth; | |
| 79 reply = dns.peek(host, "CNAME", "IN"); | |
| 80 while count > 0 and reply and reply[#reply] and not reply[#reply].a and reply[#reply].cname do | |
| 81 module:log("debug", "Looking up %s (DNS depth is %d)", tostring(reply[#reply].cname), count); | |
| 82 reply = dns.peek(reply[#reply].cname, "A", "IN") or dns.peek(reply[#reply].cname, "CNAME", "IN"); | |
| 83 count = count - 1; | |
| 84 end | |
| 85 end | |
| 86 -- end of CNAME resolving | |
| 87 | |
| 88 if reply and reply[#reply] and reply[#reply].a then | |
| 89 module:log("debug", "DNS reply for %s gives us %s", host, reply[#reply].a); | |
| 90 _config.interface = reply[#reply].a | |
| 91 return register(); | |
| 92 else | |
| 93 module:log("debug", "DNS lookup failed to get a response for %s", host); | |
| 94 if host:find(".") ~= nil then | |
| 95 host = host:gsub("^[^%.]*%.", ""); | |
| 96 if host:find(".") ~= nil then -- still one dot left? | |
| 97 return getDefaultIP(host); | |
| 98 end | |
| 99 end | |
| 100 error("Proxy65: Could not get an interface to bind to. Please configure one."); | |
| 101 end | |
| 102 end, host, "A", "IN"); | |
| 103 | |
| 104 -- Set handler for DNS timeout | |
| 105 add_task(dns_timeout, function () | |
| 106 if handle then | |
| 107 adns.cancel(handle, true); | |
| 108 end | |
| 109 end); | |
| 110 return true; | |
| 111 end | |
| 112 | |
| 113 if _config.interface ~= nil then | |
| 114 register(); | |
| 115 else | |
| 116 getDefaultIP(_host); -- try to DNS lookup module:host() | |
| 117 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 | |
| 35 local function get_disco_info(stanza) | 145 local function get_disco_info(stanza) |
| 36 local reply = replies_cache.disco_info; | 146 local reply = replies_cache.disco_info; |
| 37 if reply == nil then | 147 if reply == nil then |
| 38 reply = st.iq({type='result', from=_host}):query("http://jabber.org/protocol/disco#info") | 148 reply = st.iq({type='result', from=_host}):query("http://jabber.org/protocol/disco#info") |
| 39 :tag("identity", {category='proxy', type='bytestreams', name=_name}):up() | 149 :tag("identity", {category='proxy', type='bytestreams', name=_name}):up() |
| 56 reply.attr.id = stanza.attr.id; | 166 reply.attr.id = stanza.attr.id; |
| 57 reply.attr.to = stanza.attr.from; | 167 reply.attr.to = stanza.attr.from; |
| 58 return reply; | 168 return reply; |
| 59 end | 169 end |
| 60 | 170 |
| 61 --[[ | |
| 62 <iq type='result' | |
| 63 from='streamhostproxy.example.net' | |
| 64 to='initiator@example.com/foo' | |
| 65 id='discover'> | |
| 66 <query xmlns='http://jabber.org/protocol/bytestreams'> | |
| 67 sid='vxf9n471bn46'> | |
| 68 <streamhost | |
| 69 jid='streamhostproxy.example.net' | |
| 70 host='24.24.24.1' | |
| 71 zeroconf='_jabber.bytestreams'/> | |
| 72 </query> | |
| 73 </iq> | |
| 74 ]]-- | |
| 75 local function get_stream_host(stanza) | 171 local function get_stream_host(stanza) |
| 76 local reply = replies_cache.stream_host; | 172 local reply = replies_cache.stream_host; |
| 77 if reply == nil then | 173 if reply == nil then |
| 78 reply = st.iq({type="result", from=_host}) | 174 reply = st.iq({type="result", from=_host}) |
| 79 :query("http://jabber.org/protocol/bytestreams") | 175 :query("http://jabber.org/protocol/bytestreams") |
| 80 :tag("streamhost", {jid=_host, host="24.24.24.1", zeroconf="_jabber.bytestreams"}); -- TODO get the correct data | 176 :tag("streamhost", {jid=_host, host=_config.interface, port=_config.port}); -- TODO get the correct data |
| 81 replies_cache.stream_host = reply; | 177 replies_cache.stream_host = reply; |
| 82 end | 178 end |
| 83 | 179 |
| 84 reply.attr.id = stanza.attr.id; | 180 reply.attr.id = stanza.attr.id; |
| 85 reply.attr.to = stanza.attr.from; | 181 reply.attr.to = stanza.attr.from; |
| 86 reply.tags[1].attr.sid = stanza.tags[1].attr.sid; | 182 reply.tags[1].attr.sid = stanza.tags[1].attr.sid; |
| 87 return reply; | 183 return reply; |
| 88 end | 184 end |
| 89 | 185 |
| 90 module.unload = function() | 186 module.unload = function() |
| 91 deregister_component(_host); | 187 component_deregister(_host); |
| 188 connlisteners_deregister("proxy65"); | |
| 92 end | 189 end |
| 93 | |
| 94 module:add_item("proxy", {jid=_host, name=_name}) | |
| 95 | |
| 96 component = register_component(_host, function(origin, stanza) | |
| 97 local to_node, to_host, to_resource = jid_split(stanza.attr.to); | |
| 98 if to_node == nil then | |
| 99 local type = stanza.attr.type; | |
| 100 if type == "error" or type == "result" then return; end | |
| 101 if stanza.name == "iq" and type == "get" then | |
| 102 local xmlns = stanza.tags[1].attr.xmlns | |
| 103 if xmlns == "http://jabber.org/protocol/disco#info" then | |
| 104 origin.send(get_disco_info(stanza)); | |
| 105 return true; | |
| 106 elseif xmlns == "http://jabber.org/protocol/disco#items" then | |
| 107 origin.send(get_disco_items(stanza)); | |
| 108 return true; | |
| 109 elseif xmlns == "http://jabber.org/protocol/bytestreams" and stanza.tags[1].attr.sid ~= nil then | |
| 110 origin.send(get_stream_host(stanza)); | |
| 111 return true; | |
| 112 end | |
| 113 end | |
| 114 end | |
| 115 return; | |
| 116 end); |