xmpp4r 0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. data/COPYING +340 -0
  2. data/ChangeLog +28 -0
  3. data/LICENSE +59 -0
  4. data/README +20 -0
  5. data/Rakefile +103 -0
  6. data/UPDATING +40 -0
  7. data/data/doc/xmpp4r/examples/advanced/adventure/README +57 -0
  8. data/data/doc/xmpp4r/examples/advanced/adventure/adventure.rb +23 -0
  9. data/data/doc/xmpp4r/examples/advanced/adventure/adventuremuc.rb +136 -0
  10. data/data/doc/xmpp4r/examples/advanced/adventure/cube.xml +15 -0
  11. data/data/doc/xmpp4r/examples/advanced/adventure/tower.xml +69 -0
  12. data/data/doc/xmpp4r/examples/advanced/adventure/world.rb +425 -0
  13. data/data/doc/xmpp4r/examples/advanced/fileserve.conf +11 -0
  14. data/data/doc/xmpp4r/examples/advanced/fileserve.rb +344 -0
  15. data/data/doc/xmpp4r/examples/advanced/getonline.rb +56 -0
  16. data/data/doc/xmpp4r/examples/advanced/gtkmucclient.rb +315 -0
  17. data/data/doc/xmpp4r/examples/advanced/migrate.rb +89 -0
  18. data/data/doc/xmpp4r/examples/advanced/minimuc.rb +266 -0
  19. data/data/doc/xmpp4r/examples/advanced/recvfile.rb +83 -0
  20. data/data/doc/xmpp4r/examples/advanced/rosterdiscovery.rb +130 -0
  21. data/data/doc/xmpp4r/examples/advanced/sendfile.conf +10 -0
  22. data/data/doc/xmpp4r/examples/advanced/sendfile.rb +72 -0
  23. data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr.rb +51 -0
  24. data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr_jabber.rb +43 -0
  25. data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr_test.rb +10 -0
  26. data/data/doc/xmpp4r/examples/advanced/versionpoll.rb +90 -0
  27. data/data/doc/xmpp4r/examples/advanced/xmpping.rb +134 -0
  28. data/data/doc/xmpp4r/examples/advanced/xmppingrc.sample +9 -0
  29. data/data/doc/xmpp4r/examples/basic/change_password.rb +41 -0
  30. data/data/doc/xmpp4r/examples/basic/client.rb +68 -0
  31. data/data/doc/xmpp4r/examples/basic/component.rb +11 -0
  32. data/data/doc/xmpp4r/examples/basic/echo_nonthreaded.rb +32 -0
  33. data/data/doc/xmpp4r/examples/basic/echo_threaded.rb +32 -0
  34. data/data/doc/xmpp4r/examples/basic/jabbersend.rb +41 -0
  35. data/data/doc/xmpp4r/examples/basic/mass_sender.rb +67 -0
  36. data/data/doc/xmpp4r/examples/basic/mucinfo.rb +39 -0
  37. data/data/doc/xmpp4r/examples/basic/mucsimplebot.rb +83 -0
  38. data/data/doc/xmpp4r/examples/basic/register.rb +25 -0
  39. data/data/doc/xmpp4r/examples/basic/remove_registration.rb +18 -0
  40. data/data/doc/xmpp4r/examples/basic/roster.rb +42 -0
  41. data/data/doc/xmpp4r/examples/basic/rosterprint.rb +50 -0
  42. data/data/doc/xmpp4r/examples/basic/rosterrename.rb +34 -0
  43. data/data/doc/xmpp4r/examples/basic/rosterwatch.rb +172 -0
  44. data/data/doc/xmpp4r/examples/basic/send_vcard.rb +68 -0
  45. data/data/doc/xmpp4r/examples/basic/versionbot.rb +75 -0
  46. data/data/doc/xmpp4r/examples/buggy/jabber2jabber/jabber2jabber.rb +18 -0
  47. data/data/doc/xmpp4r/examples/buggy/miniedgarr_cgi.rb +192 -0
  48. data/data/doc/xmpp4r/examples/buggy/miniedgarr_watch.rb +82 -0
  49. data/lib/callbacks.rb +122 -0
  50. data/lib/xmpp4r/authenticationfailure.rb +13 -0
  51. data/lib/xmpp4r/bytestreams/helper/filetransfer.rb +315 -0
  52. data/lib/xmpp4r/bytestreams/helper/ibb/base.rb +256 -0
  53. data/lib/xmpp4r/bytestreams/helper/ibb/initiator.rb +30 -0
  54. data/lib/xmpp4r/bytestreams/helper/ibb/target.rb +46 -0
  55. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb +151 -0
  56. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/initiator.rb +85 -0
  57. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/server.rb +178 -0
  58. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/socks5.rb +56 -0
  59. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb +61 -0
  60. data/lib/xmpp4r/bytestreams/iq/bytestreams.rb +177 -0
  61. data/lib/xmpp4r/bytestreams/iq/si.rb +221 -0
  62. data/lib/xmpp4r/bytestreams.rb +11 -0
  63. data/lib/xmpp4r/client.rb +249 -0
  64. data/lib/xmpp4r/component.rb +103 -0
  65. data/lib/xmpp4r/connection.rb +166 -0
  66. data/lib/xmpp4r/dataforms/x/data.rb +248 -0
  67. data/lib/xmpp4r/dataforms.rb +1 -0
  68. data/lib/xmpp4r/debuglog.rb +34 -0
  69. data/lib/xmpp4r/delay/x/delay.rb +100 -0
  70. data/lib/xmpp4r/delay.rb +1 -0
  71. data/lib/xmpp4r/discovery/iq/discoinfo.rb +225 -0
  72. data/lib/xmpp4r/discovery/iq/discoitems.rb +162 -0
  73. data/lib/xmpp4r/discovery.rb +2 -0
  74. data/lib/xmpp4r/error.rb +230 -0
  75. data/lib/xmpp4r/errorexception.rb +32 -0
  76. data/lib/xmpp4r/feature_negotiation/iq/feature.rb +42 -0
  77. data/lib/xmpp4r/feature_negotiation.rb +1 -0
  78. data/lib/xmpp4r/idgenerator.rb +37 -0
  79. data/lib/xmpp4r/iq.rb +229 -0
  80. data/lib/xmpp4r/jid.rb +167 -0
  81. data/lib/xmpp4r/message.rb +171 -0
  82. data/lib/xmpp4r/muc/helper/mucbrowser.rb +107 -0
  83. data/lib/xmpp4r/muc/helper/mucclient.rb +382 -0
  84. data/lib/xmpp4r/muc/helper/simplemucclient.rb +222 -0
  85. data/lib/xmpp4r/muc/x/muc.rb +98 -0
  86. data/lib/xmpp4r/muc/x/mucuserinvite.rb +58 -0
  87. data/lib/xmpp4r/muc/x/mucuseritem.rb +148 -0
  88. data/lib/xmpp4r/muc.rb +6 -0
  89. data/lib/xmpp4r/presence.rb +255 -0
  90. data/lib/xmpp4r/query.rb +43 -0
  91. data/lib/xmpp4r/rexmladdons.rb +826 -0
  92. data/lib/xmpp4r/roster/helper/roster.rb +514 -0
  93. data/lib/xmpp4r/roster/iq/roster.rb +244 -0
  94. data/lib/xmpp4r/roster/x/roster.rb +155 -0
  95. data/lib/xmpp4r/roster.rb +4 -0
  96. data/lib/xmpp4r/sasl.rb +167 -0
  97. data/lib/xmpp4r/stream.rb +543 -0
  98. data/lib/xmpp4r/streamparser.rb +77 -0
  99. data/lib/xmpp4r/vcard/helper/vcard.rb +86 -0
  100. data/lib/xmpp4r/vcard/iq/vcard.rb +102 -0
  101. data/lib/xmpp4r/vcard.rb +3 -0
  102. data/lib/xmpp4r/version/helper/responder.rb +71 -0
  103. data/lib/xmpp4r/version/helper/simpleresponder.rb +44 -0
  104. data/lib/xmpp4r/version/iq/version.rb +118 -0
  105. data/lib/xmpp4r/version.rb +3 -0
  106. data/lib/xmpp4r/x.rb +43 -0
  107. data/lib/xmpp4r/xmlstanza.rb +174 -0
  108. data/lib/xmpp4r/xmpp4r.rb +16 -0
  109. data/lib/xmpp4r.rb +122 -0
  110. data/setup.rb +1360 -0
  111. data/test/bytestreams/tc_ibb.rb +186 -0
  112. data/test/bytestreams/tc_socks5bytestreams.rb +57 -0
  113. data/test/delay/tc_xdelay.rb +51 -0
  114. data/test/lib/clienttester.rb +110 -0
  115. data/test/muc/tc_muc_mucclient.rb +569 -0
  116. data/test/muc/tc_muc_simplemucclient.rb +72 -0
  117. data/test/roster/.tc_helper.rb.swp +0 -0
  118. data/test/roster/tc_helper.rb +389 -0
  119. data/test/roster/tc_iqqueryroster.rb +140 -0
  120. data/test/roster/tc_xroster.rb +70 -0
  121. data/test/tc_callbacks.rb +128 -0
  122. data/test/tc_class_names.rb +129 -0
  123. data/test/tc_client.rb +30 -0
  124. data/test/tc_error.rb +103 -0
  125. data/test/tc_idgenerator.rb +30 -0
  126. data/test/tc_iq.rb +109 -0
  127. data/test/tc_iqquery.rb +31 -0
  128. data/test/tc_jid.rb +202 -0
  129. data/test/tc_message.rb +114 -0
  130. data/test/tc_presence.rb +148 -0
  131. data/test/tc_stream.rb +182 -0
  132. data/test/tc_streamError.rb +87 -0
  133. data/test/tc_streamSend.rb +59 -0
  134. data/test/tc_streamThreaded.rb +168 -0
  135. data/test/tc_xmlstanza.rb +76 -0
  136. data/test/ts_xmpp4r.rb +34 -0
  137. data/test/vcard/tc_iqvcard.rb +52 -0
  138. data/test/version/tc_helper.rb +46 -0
  139. data/test/version/tc_iqqueryversion.rb +96 -0
  140. data/tools/doctoweb.bash +30 -0
  141. data/tools/gen_requires.bash +10 -0
  142. metadata +232 -0
@@ -0,0 +1,151 @@
1
+ require 'socket'
2
+ require 'thread'
3
+ require 'timeout'
4
+ require 'digest/sha1'
5
+
6
+ require 'callbacks'
7
+
8
+ module Jabber
9
+ module Bytestreams
10
+ ##
11
+ # SOCKS5 Bytestreams (JEP-0065) implementation
12
+ #
13
+ # Don't use directly, use SOCKS5BytestreamsInitiator
14
+ # and SOCKS5BytestreamsTarget
15
+ class SOCKS5Bytestreams
16
+ ##
17
+ # [StreamHost] the SOCKS connection is using
18
+ attr_reader :streamhost_used
19
+
20
+ ##
21
+ # SOCKS connection timeout (for trying multiple streamhosts)
22
+ #
23
+ # default: nil, use the OS' default timeout
24
+ attr_accessor :connect_timeout
25
+
26
+ def initialize(stream, session_id, initiator_jid, target_jid)
27
+ @stream = stream
28
+ @session_id = session_id
29
+ @initiator_jid = (initiator_jid.kind_of?(String) ? JID.new(initiator_jid) : initiator_jid)
30
+ @target_jid = (target_jid.kind_of?(String) ? JID.new(target_jid) : target_jid)
31
+ @socks = nil
32
+ @connect_timeout = nil
33
+ @streamhost_used = nil
34
+ @streamhost_cbs = CallbackList.new
35
+ end
36
+
37
+ ##
38
+ # Add a callback that will be called when there is action regarding
39
+ # SOCKS stream-hosts
40
+ #
41
+ # Usage of this callback is optional and serves informational purposes only.
42
+ #
43
+ # block takes three arguments:
44
+ # * The StreamHost instance that is currently being tried
45
+ # * State information (is either :connecting, :authenticating, :success or :failure)
46
+ # * The exception value for the state :failure, else nil
47
+ def add_streamhost_callback(priority = 0, ref = nil, &block)
48
+ @streamhost_cbs.add(priority, ref, block)
49
+ end
50
+
51
+ ##
52
+ # Receive from the stream-host
53
+ # length:: [Fixnum] Amount of bytes (Will be passed to TCPSocket#read for the underlying SOCKS5 connection)
54
+ # result:: [String] (or [nil] if finished)
55
+ def read(length=nil)
56
+ @socks.read(length)
57
+ end
58
+
59
+ ##
60
+ # Flush the SOCKS5 socket
61
+ def flush
62
+ @socks.flush
63
+ end
64
+
65
+ ##
66
+ # Send to the stream-host
67
+ # buf:: [String] Data
68
+ # result:: [Fixnum] Amount of bytes sent
69
+ def write(buf)
70
+ @socks.write(buf)
71
+ # FIXME: On FreeBSD this throws Errno::EPERM after it has already written a few
72
+ # kilobytes, and when there are multiple sockets. ktrace told, that this originates
73
+ # from the syscall, not ruby.
74
+ end
75
+
76
+ ##
77
+ # Close the stream-host connection
78
+ def close
79
+ @socks.close
80
+ end
81
+
82
+ ##
83
+ # Query a JID for its stream-host information
84
+ #
85
+ # SOCKS5BytestreamsInitiator#add_streamhost can do this for you.
86
+ # Use this method if you plan to do multiple transfers, so
87
+ # you can cache the result.
88
+ # stream:: [Stream] to operate on
89
+ # streamhost:: [JID] of the proxy
90
+ # my_jid:: [JID] Optional sender JID for Component operation
91
+ def self.query_streamhost(stream, streamhost, my_jid=nil)
92
+ res = nil
93
+
94
+ iq = Iq::new(:get, streamhost)
95
+ iq.from = my_jid
96
+ iq.add(IqQueryBytestreams.new)
97
+ stream.send_with_id(iq) { |reply|
98
+ if reply.type == :result
99
+ reply.query.each_element { |e|
100
+ if e.kind_of?(StreamHost)
101
+ e.jid = reply.from # Help misconfigured proxys
102
+ res = e
103
+ end
104
+ }
105
+ end
106
+ true
107
+ }
108
+
109
+ if res and res.jid and res.host and res.port
110
+ res
111
+ else
112
+ nil
113
+ end
114
+ end
115
+
116
+ private
117
+
118
+ ##
119
+ # The address the stream-host expects from us.
120
+ # According to JEP-0096 this is the SHA1 hash
121
+ # of the concatenation of session_id,
122
+ # initiator_jid and target_jid.
123
+ # result:: [String] SHA1 hash
124
+ def stream_address
125
+ Digest::SHA1.new("#{@session_id}#{@initiator_jid}#{@target_jid}").hexdigest
126
+ end
127
+
128
+ ##
129
+ # Try a streamhost
130
+ # result:: [SOCKS5Socket]
131
+ def connect_socks(streamhost)
132
+ Timeout::timeout(@connect_timeout, Errno::ETIMEDOUT) {
133
+ Jabber::debuglog("SOCKS5 Bytestreams: connecting to proxy #{streamhost.jid} (#{streamhost.host}:#{streamhost.port})")
134
+ @streamhost_cbs.process(streamhost, :connecting, nil)
135
+ socks = SOCKS5Socket.new(streamhost.host, streamhost.port)
136
+
137
+ Jabber::debuglog("SOCKS5 Bytestreams: connected, authenticating")
138
+ @streamhost_cbs.process(streamhost, :authenticating, nil)
139
+ socks.auth
140
+
141
+ socks.connect_domain(stream_address, 0)
142
+
143
+ Jabber::debuglog("SOCKS5 Bytestreams: connected")
144
+ @streamhost_cbs.process(streamhost, :success, nil)
145
+
146
+ socks
147
+ }
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,85 @@
1
+ module Jabber
2
+ module Bytestreams
3
+ ##
4
+ # SOCKS5Bytestreams implementation for the initiator side
5
+ class SOCKS5BytestreamsInitiator < SOCKS5Bytestreams
6
+ attr_reader :streamhosts
7
+
8
+ def initialize(stream, session_id, initiator_jid, target_jid)
9
+ super
10
+ @streamhosts = []
11
+ end
12
+
13
+ ##
14
+ # Add a streamhost which will be offered to the target
15
+ #
16
+ # streamhost:: can be:
17
+ # * [StreamHost] if already got all information (host/port)
18
+ # * [SOCKS5BytestreamsServer] if this is the local streamhost
19
+ # * [String] or [JID] if information should be automatically resolved by SOCKS5Bytestreams::query_streamhost
20
+ def add_streamhost(streamhost)
21
+ if streamhost.kind_of?(StreamHost)
22
+ @streamhosts << streamhost
23
+ elsif streamhost.kind_of?(SOCKS5BytestreamsServer)
24
+ streamhost.each_streamhost(@initiator_jid) { |sh|
25
+ @streamhosts << sh
26
+ }
27
+ elsif streamhost.kind_of?(String) or streamhost.kind_of?(JID)
28
+ @streamhosts << SOCKS5Bytestreams::query_streamhost(@stream, streamhost, @initiator_jid)
29
+ else
30
+ raise "Unknwon streamhost type: #{streamhost.class}"
31
+ end
32
+ end
33
+
34
+ ##
35
+ # Send the configured streamhosts to the target,
36
+ # wait for an answer and
37
+ # connect to the host the target chose.
38
+ def open
39
+ iq1 = Iq::new(:set, @target_jid)
40
+ iq1.from = @initiator_jid
41
+ bs = iq1.add IqQueryBytestreams.new(@session_id)
42
+ @streamhosts.each { |se|
43
+ bs.add(se)
44
+ }
45
+
46
+ peer_used = nil
47
+ @stream.send_with_id(iq1) { |response|
48
+ if response.type == :result and response.query.kind_of?(IqQueryBytestreams)
49
+ peer_used = response.query.streamhost_used
50
+ raise "No streamhost-used" unless peer_used
51
+ raise "Invalid streamhost-used" unless peer_used.jid
52
+ end
53
+ true
54
+ }
55
+
56
+ @streamhost_used = nil
57
+ @streamhosts.each { |sh|
58
+ if peer_used.jid == sh.jid
59
+ @streamhost_used = sh
60
+ break
61
+ end
62
+ }
63
+ if @streamhost_used.jid == @initiator_jid
64
+ # This is our own JID, so the target chose SOCKS5BytestreamsServer
65
+ @socks = @streamhost_used.server.peer_sock(stream_address)
66
+ raise "Target didn't connect" unless @socks
67
+ @streamhost_cbs.process(@streamhost_used, :success, nil)
68
+ else
69
+ begin
70
+ @socks = connect_socks(@streamhost_used)
71
+ rescue Exception => e
72
+ Jabber::debuglog("SOCKS5 Bytestreams: #{e.class}: #{e}\n#{e.backtrace.join("\n")}")
73
+ @streamhost_cbs.process(@streamhost_used, :failure, e)
74
+ raise e
75
+ end
76
+ iq2 = Iq::new(:set, @streamhost_used.jid)
77
+ iq2.add(IqQueryBytestreams.new(@session_id)).activate = @target_jid.to_s
78
+ @stream.send_with_id(iq2) { |reply|
79
+ reply.type == :result
80
+ }
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,178 @@
1
+ module Jabber
2
+ module Bytestreams
3
+ ##
4
+ # The SOCKS5BytestreamsServer is an implementation of a SOCKS5 server.
5
+ #
6
+ # You can use it if you're reachable by your SOCKS5Bytestreams peers,
7
+ # thus avoiding use of an external proxy.
8
+ #
9
+ # ==Usage:
10
+ # * Instantiate with an unfirewalled port
11
+ # * Add your external IP addresses with SOCKS5BytestreamsServer#add_address
12
+ # * Once you've got an *outgoing* SOCKS5BytestreamsInitiator, do
13
+ # <tt>SOCKS5BytestreamsInitiator#add_streamhost(my_socks5bytestreamsserver)</tt>
14
+ # *before* you do <tt>SOCKS5BytestreamsInitiator#open</tt>
15
+ class SOCKS5BytestreamsServer
16
+ ##
17
+ # Start a local SOCKS5BytestreamsServer
18
+ #
19
+ # Will start to listen on the given TCP port and
20
+ # accept new peers
21
+ # port:: [Fixnum] TCP port to listen on
22
+ def initialize(port)
23
+ @port = port
24
+ @addresses = []
25
+ @peers = []
26
+ @peers_lock = Mutex.new
27
+ socket = TCPServer.new(port)
28
+
29
+ Thread.new {
30
+ loop {
31
+ peer = SOCKS5BytestreamsPeer.new(socket.accept)
32
+ Thread.new {
33
+ begin
34
+ peer.start
35
+ rescue
36
+ Jabber::debuglog("SOCKS5 BytestreamsServer: Error accepting peer: #{$!}")
37
+ end
38
+ }
39
+ @peers_lock.synchronize {
40
+ @peers << peer
41
+ }
42
+ }
43
+ }
44
+ end
45
+
46
+ ##
47
+ # Find the socket a peer is associated to
48
+ # addr:: [String] Address like SOCKS5Bytestreams#stream_address
49
+ # result:: [TCPSocker] or [nil]
50
+ def peer_sock(addr)
51
+ res = nil
52
+ @peers_lock.synchronize {
53
+ removes = []
54
+
55
+ @peers.each { |peer|
56
+ if peer.socket and peer.socket.closed?
57
+ # Queue peers with closed socket for removal
58
+ removes << peer
59
+ elsif peer.address == addr and res.nil?
60
+ res = peer.socket
61
+ else
62
+ # If we sent multiple addresses of our own, clients may
63
+ # connect multiple times. Close these connections here.
64
+ removes << peer
65
+ end
66
+ }
67
+
68
+ # If we sent multiple addresses of our own, clients may
69
+ # connect multiple times. Close these connections here.
70
+ @peers.delete_if { |peer|
71
+ if removes.include? peer
72
+ peer.socket.close rescue IOError
73
+ true
74
+ else
75
+ false
76
+ end
77
+ }
78
+ }
79
+
80
+ res
81
+ end
82
+
83
+ ##
84
+ # Add an external IP address
85
+ #
86
+ # This is a must-have, as SOCKS5BytestreamsInitiator must inform
87
+ # the target where to connect
88
+ def add_address(address)
89
+ @addresses << address
90
+ end
91
+
92
+ ##
93
+ # Iterate through all configured addresses,
94
+ # yielding SOCKS5BytestreamsServerStreamHost
95
+ # instances, which should be passed to
96
+ # SOCKS5BytestreamsInitiator#add_streamhost
97
+ #
98
+ # This will be automatically invoked if you pass an instance
99
+ # of SOCKS5BytestreamsServer to
100
+ # SOCKS5BytestreamsInitiator#add_streamhost
101
+ # my_jid:: [JID] My Jabber-ID
102
+ def each_streamhost(my_jid, &block)
103
+ @addresses.each { |address|
104
+ yield SOCKS5BytestreamsServerStreamHost.new(self, my_jid, address, @port)
105
+ }
106
+ end
107
+ end
108
+
109
+ ##
110
+ # A subclass of StreamHost which possesses a
111
+ # server attribute, to let SOCKS5BytestreamsInitiator
112
+ # know this is the local SOCKS5BytestreamsServer
113
+ class SOCKS5BytestreamsServerStreamHost < StreamHost
114
+ attr_reader :server
115
+ def initialize(server, jid=nil, host=nil, port=nil)
116
+ super(jid, host, port)
117
+ @server = server
118
+ end
119
+ end
120
+
121
+ ##
122
+ # This class will be instantiated by SOCKS5BytestreamsServer
123
+ # upon accepting a new connection
124
+ class SOCKS5BytestreamsPeer
125
+ attr_reader :address, :socket
126
+
127
+ ##
128
+ # Initialize a new peer
129
+ # socket:: [TCPSocket]
130
+ def initialize(socket)
131
+ @socket = socket
132
+ Jabber::debuglog("SOCKS5 BytestreamsServer: accepted peer #{@socket.peeraddr[2]}:#{@socket.peeraddr[1]}")
133
+ end
134
+
135
+ ##
136
+ # Start handshake process
137
+ def start
138
+ auth_ver = @socket.getc
139
+ if auth_ver != 5
140
+ # Unsupported version
141
+ @socket.close
142
+ return
143
+ end
144
+
145
+ auth_nmethods = @socket.getc
146
+ auth_methods = @socket.read(auth_nmethods)
147
+ unless auth_methods.index("\x00")
148
+ # Client won't accept no authentication
149
+ @socket.write("\x05\xff")
150
+ @socket.close
151
+ return
152
+ end
153
+ @socket.write("\x05\x00")
154
+ Jabber::debuglog("SOCKS5 BytestreamsServer: peer #{@socket.peeraddr[2]}:#{@socket.peeraddr[1]} authenticated")
155
+
156
+ req = @socket.read(4)
157
+ if req != "\x05\x01\x00\x03"
158
+ # Unknown version, command, reserved, address-type
159
+ @socket.close
160
+ return
161
+ end
162
+ req_addrlen = @socket.getc
163
+ req_addr = @socket.read(req_addrlen)
164
+ req_port = @socket.read(2)
165
+ if req_port != "\x00\x00"
166
+ # Port is not 0
167
+ @socket.write("\x05\x01")
168
+ @socket.close
169
+ return
170
+ end
171
+ @socket.write("\x05\x00\x00\x03#{req_addrlen.chr}#{req_addr}\x00\x00")
172
+ Jabber::debuglog("SOCKS5 BytestreamsServer: peer #{@socket.peeraddr[2]}:#{@socket.peeraddr[1]} connected for #{req_addr}")
173
+
174
+ @address = req_addr
175
+ end
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,56 @@
1
+ require 'socket'
2
+
3
+ module Jabber
4
+ module Bytestreams
5
+ ##
6
+ # Can be thrown upon communication error with
7
+ # a SOCKS5 proxy
8
+ class SOCKS5Error < RuntimeError; end
9
+
10
+ ##
11
+ # A SOCKS5 client implementation
12
+ #
13
+ # ==Usage:
14
+ # * Initialize with proxy's address and port
15
+ # * Authenticate
16
+ # * Connect to target host
17
+ class SOCKS5Socket < TCPSocket
18
+ ##
19
+ # Connect to SOCKS5 proxy
20
+ def initialize(socks_host, socks_port)
21
+ super(socks_host, socks_port)
22
+ end
23
+
24
+ ##
25
+ # Authenticate for SOCKS5 proxy
26
+ #
27
+ # Currently supports only 'no authentication required'
28
+ def auth
29
+ write("\x05\x01\x00")
30
+ buf = read(2)
31
+ if buf.nil? or buf != "\x05\x00"
32
+ close
33
+ raise SOCKS5Error.new("Invalid SOCKS5 authentication: #{buf.inspect}")
34
+ end
35
+
36
+ self
37
+ end
38
+
39
+ ##
40
+ # Issue a CONNECT request to a host name
41
+ # which is to be resolved by the proxy.
42
+ # domain:: [String] Host name
43
+ # port:: [Fixnum] Port number
44
+ def connect_domain(domain, port)
45
+ write("\x05\x01\x00\x03#{domain.size.chr}#{domain}#{[port].pack("n")}")
46
+ buf = read(7 + domain.size)
47
+ if buf.nil? or buf[0..1] != "\005\000"
48
+ close
49
+ raise SOCKS5Error.new("Invalid SOCKS5 connect: #{buf.inspect}")
50
+ end
51
+
52
+ self
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,61 @@
1
+ module Jabber
2
+ module Bytestreams
3
+ ##
4
+ # SOCKS5 Bytestreams implementation of the target site
5
+ class SOCKS5BytestreamsTarget < SOCKS5Bytestreams
6
+ ##
7
+ # Wait until the stream has been established
8
+ #
9
+ # May raise various exceptions
10
+ def accept
11
+ error = nil
12
+ connect_lock = Mutex.new
13
+ connect_lock.lock
14
+
15
+ @stream.add_iq_callback(200, self) { |iq|
16
+ if iq.type == :set and iq.from == @initiator_jid and iq.to == @target_jid and iq.query.kind_of?(IqQueryBytestreams)
17
+ begin
18
+ @stream.delete_iq_callback(self)
19
+
20
+ iq.query.each_element('streamhost') { |streamhost|
21
+ if streamhost.host and streamhost.port and not @socks
22
+ begin
23
+ @socks = connect_socks(streamhost)
24
+ @streamhost_used = streamhost
25
+ rescue Exception => e
26
+ Jabber::debuglog("SOCKS5 Bytestreams: #{e.class}: #{e}\n#{e.backtrace.join("\n")}")
27
+ @streamhost_cbs.process(streamhost, :failure, e)
28
+ end
29
+ end
30
+ }
31
+
32
+ reply = iq.answer(false)
33
+ if @streamhost_used
34
+ reply.type = :result
35
+ reply.add(IqQueryBytestreams.new)
36
+ reply.query.add(StreamHostUsed.new(@streamhost_used.jid))
37
+ else
38
+ reply.type = :error
39
+ reply.add(Error.new('item-not-found'))
40
+ end
41
+ @stream.send(reply)
42
+ rescue Exception => e
43
+ error = e
44
+ end
45
+
46
+ connect_lock.unlock
47
+ true
48
+ else
49
+ false
50
+ end
51
+ }
52
+
53
+ connect_lock.lock
54
+ connect_lock.unlock
55
+ raise error if error
56
+ (@socks != nil)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
@@ -0,0 +1,177 @@
1
+ # =XMPP4R - XMPP Library for Ruby
2
+ # License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
3
+ # Website::http://home.gna.org/xmpp4r/
4
+
5
+ module Jabber
6
+ module Bytestreams
7
+ ##
8
+ # Class for accessing <query/> elements with
9
+ # xmlns='http://jabber.org/protocol/bytestreams'
10
+ # in <iq/> stanzas.
11
+ class IqQueryBytestreams < IqQuery
12
+ NS_BYTESTREAMS = 'http://jabber.org/protocol/bytestreams'
13
+
14
+ ##
15
+ # Initialize such a <query/>
16
+ # sid:: [String] Session-ID
17
+ # mode:: [Symbol] :tcp or :udp
18
+ def initialize(sid=nil, mode=nil)
19
+ super()
20
+ add_namespace(IqQueryBytestreams::NS_BYTESTREAMS)
21
+ self.sid = sid
22
+ self.mode = mode
23
+ end
24
+
25
+ def typed_add(xe)
26
+ if xe.kind_of?(REXML::Element) and xe.name == 'streamhost'
27
+ super StreamHost.new.import(xe)
28
+ elsif xe.kind_of?(REXML::Element) and xe.name == 'streamhost-used'
29
+ super StreamHostUsed.new.import(xe)
30
+ else
31
+ super xe
32
+ end
33
+ end
34
+
35
+ ##
36
+ # Session-ID
37
+ def sid
38
+ attributes['sid']
39
+ end
40
+
41
+ ##
42
+ # Set Session-ID
43
+ def sid=(s)
44
+ attributes['sid'] = s
45
+ end
46
+
47
+ ##
48
+ # Transfer mode
49
+ # result:: :tcp or :udp
50
+ def mode
51
+ case attributes['mode']
52
+ when 'udp' then :udp
53
+ else :tcp
54
+ end
55
+ end
56
+
57
+ ##
58
+ # Set the transfer mode
59
+ # m:: :tcp or :udp
60
+ def mode=(m)
61
+ case m
62
+ when :udp then attributes['mode'] = 'udp'
63
+ else attributes['mode'] = 'tcp'
64
+ end
65
+ end
66
+
67
+ ##
68
+ # Get the <streamhost-used/> child
69
+ # result:: [StreamHostUsed]
70
+ def streamhost_used
71
+ first_element('streamhost-used')
72
+ end
73
+
74
+ ##
75
+ # Get the text of the <activate/> child
76
+ # result:: [JID] or [nil]
77
+ def activate
78
+ j = first_element_text('activate')
79
+ j ? JID.new(j) : nil
80
+ end
81
+
82
+ ##
83
+ # Set the text of the <activate/> child
84
+ # s:: [JID]
85
+ def activate=(s)
86
+ replace_element_text('activate', s ? s.to_s : nil)
87
+ end
88
+ end
89
+
90
+ IqQuery.add_namespaceclass(IqQueryBytestreams::NS_BYTESTREAMS, IqQueryBytestreams)
91
+
92
+ ##
93
+ # <streamhost/> element, normally appear
94
+ # as children of IqQueryBytestreams
95
+ class StreamHost < REXML::Element
96
+ ##
97
+ # Initialize a <streamhost/> element
98
+ # jid:: [JID]
99
+ # host:: [String] Hostname or IP address
100
+ # port:: [Fixnum] Port number
101
+ def initialize(jid=nil, host=nil, port=nil)
102
+ super('streamhost')
103
+ self.jid = jid
104
+ self.host = host
105
+ self.port = port
106
+ end
107
+
108
+ ##
109
+ # Get the JID of the streamhost
110
+ def jid
111
+ (a = attributes['jid']) ? JID.new(a) : nil
112
+ end
113
+
114
+ ##
115
+ # Set the JID of the streamhost
116
+ def jid=(j)
117
+ attributes['jid'] = (j ? j.to_s : nil)
118
+ end
119
+
120
+ ##
121
+ # Get the host address of the streamhost
122
+ def host
123
+ attributes['host']
124
+ end
125
+
126
+ ##
127
+ # Set the host address of the streamhost
128
+ def host=(h)
129
+ attributes['host'] = h
130
+ end
131
+
132
+ ##
133
+ # Get the zeroconf attribute of the streamhost
134
+ def zeroconf
135
+ attributes['zeroconf']
136
+ end
137
+
138
+ ##
139
+ # Set the zeroconf attribute of the streamhost
140
+ def zeroconf=(s)
141
+ attributes['zeroconf'] = s
142
+ end
143
+
144
+ ##
145
+ # Get the port number of the streamhost
146
+ def port
147
+ p = attributes['port'].to_i
148
+ (p == 0 ? nil : p)
149
+ end
150
+
151
+ ##
152
+ # Set the port number of the streamhost
153
+ def port=(p)
154
+ attributes['port'] = p.to_s
155
+ end
156
+ end
157
+
158
+ ##
159
+ # <streamhost-used/> element, normally appears
160
+ # as child of IqQueryBytestreams
161
+ class StreamHostUsed < REXML::Element
162
+ def initialize(jid=nil)
163
+ super('streamhost-used')
164
+ self.jid = jid
165
+ end
166
+
167
+ def jid
168
+ (a = attributes['jid']) ? JID.new(a) : nil
169
+ end
170
+
171
+ def jid=(j)
172
+ attributes['jid'] = (j ? j.to_s : nil)
173
+ end
174
+ end
175
+ end
176
+ end
177
+