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
parents a0dfa3e5883c
children
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);