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); |
|