coderrr-rtunnel 0.3.9 → 0.4.0

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 (55) hide show
  1. data/CHANGELOG +13 -0
  2. data/LICENSE +21 -0
  3. data/Manifest +48 -0
  4. data/README.markdown +40 -15
  5. data/Rakefile +31 -4
  6. data/bin/rtunnel_client +2 -1
  7. data/bin/rtunnel_server +2 -1
  8. data/lib/rtunnel.rb +20 -0
  9. data/lib/rtunnel/client.rb +308 -0
  10. data/lib/rtunnel/command_processor.rb +62 -0
  11. data/lib/rtunnel/command_protocol.rb +50 -0
  12. data/lib/rtunnel/commands.rb +233 -0
  13. data/lib/rtunnel/connection_id.rb +24 -0
  14. data/lib/rtunnel/core.rb +58 -0
  15. data/lib/rtunnel/crypto.rb +106 -0
  16. data/lib/rtunnel/frame_protocol.rb +34 -0
  17. data/lib/rtunnel/io_extensions.rb +54 -0
  18. data/lib/rtunnel/leak.rb +35 -0
  19. data/lib/rtunnel/rtunnel_client_cmd.rb +41 -0
  20. data/lib/rtunnel/rtunnel_server_cmd.rb +32 -0
  21. data/lib/rtunnel/server.rb +351 -0
  22. data/lib/rtunnel/socket_factory.rb +119 -0
  23. data/test/command_stubs.rb +77 -0
  24. data/test/protocol_mocks.rb +43 -0
  25. data/test/scenario_connection.rb +109 -0
  26. data/test/test_client.rb +48 -0
  27. data/test/test_command_protocol.rb +82 -0
  28. data/test/test_commands.rb +49 -0
  29. data/test/test_connection_id.rb +30 -0
  30. data/test/test_crypto.rb +127 -0
  31. data/test/test_frame_protocol.rb +109 -0
  32. data/test/test_io_extensions.rb +70 -0
  33. data/test/test_server.rb +70 -0
  34. data/test/test_socket_factory.rb +42 -0
  35. data/test/test_tunnel.rb +186 -0
  36. data/test_data/authorized_keys2 +4 -0
  37. data/test_data/known_hosts +4 -0
  38. data/test_data/random_rsa_key +27 -0
  39. data/test_data/ssh_host_dsa_key +12 -0
  40. data/test_data/ssh_host_rsa_key +27 -0
  41. data/tests/_ab_test.rb +16 -0
  42. data/tests/_stress_test.rb +96 -0
  43. data/tests/lo_http_server.rb +55 -0
  44. metadata +67 -27
  45. data/ab_test.rb +0 -23
  46. data/lib/client.rb +0 -150
  47. data/lib/cmds.rb +0 -166
  48. data/lib/core.rb +0 -58
  49. data/lib/rtunnel_client_cmd.rb +0 -23
  50. data/lib/rtunnel_server_cmd.rb +0 -18
  51. data/lib/server.rb +0 -197
  52. data/rtunnel.gemspec +0 -18
  53. data/rtunnel_client.rb +0 -3
  54. data/rtunnel_server.rb +0 -3
  55. data/stress_test.rb +0 -68
data/lib/core.rb DELETED
@@ -1,58 +0,0 @@
1
- require 'resolv'
2
-
3
- module RTunnel
4
- VERSION = '0.3.9'
5
-
6
- DEFAULT_CONTROL_PORT = 19050
7
- PING_TIMEOUT = 10
8
- end
9
-
10
- if ENV['RTUNNEL_DEBUG']
11
- def D(msg)
12
- puts msg
13
- end
14
- else
15
- def D(*a);end
16
- end
17
-
18
- class << Thread
19
- def safe(*a)
20
- Thread.new(*a) do
21
- begin
22
- yield
23
- rescue Exception
24
- puts $!.inspect
25
- puts $!.backtrace.join("\n")
26
- end
27
- end
28
- end
29
- end
30
-
31
- class String
32
- def replace_with_ip!
33
- host = self.split(/:/).first
34
-
35
- ip = timeout(5) { Resolv.getaddress(host) }
36
-
37
- self.replace(self.gsub(host, ip))
38
- rescue Exception
39
- puts "Error resolving #{host}"
40
- raise
41
- end
42
- end
43
-
44
- class IO
45
- def while_reading(data = nil, &b)
46
- while buf = readpartial_rescued(1024)
47
- data << buf if data
48
- yield buf if block_given?
49
- end
50
- data
51
- end
52
-
53
- def readpartial_rescued(size)
54
- readpartial(size)
55
- rescue EOFError
56
- nil
57
- end
58
- end
@@ -1,23 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- $LOAD_PATH << 'lib'
4
- require 'optparse'
5
- require 'client'
6
-
7
- control_address = tunnel_from_address = tunnel_to_address = remote_listen_address = nil
8
-
9
- (opts = OptionParser.new do |o|
10
- o.on("-c", "--control-address ADDRESS") { |a| control_address = a }
11
- o.on("-f", "--remote-listen-port ADDRESS") { |a| remote_listen_address = a }
12
- o.on("-t", "--tunnel-to ADDRESS") { |a| tunnel_to_address = a }
13
- end).parse! rescue (puts opts; exit)
14
-
15
- (puts opts; exit) if [control_address, remote_listen_address, tunnel_to_address].include? nil
16
-
17
- client = RTunnel::Client.new(
18
- :control_address => control_address,
19
- :remote_listen_address => remote_listen_address,
20
- :tunnel_to_address => tunnel_to_address
21
- )
22
- client.start
23
- client.join
@@ -1,18 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- $LOAD_PATH << 'lib'
4
- require 'optparse'
5
- require 'server'
6
-
7
- control_address = tunnel_port = nil
8
-
9
- (opts = OptionParser.new do |o|
10
- o.on("-c", "--control ADDRESS") { |a| control_address = a }
11
- end).parse! rescue (puts opts; exit)
12
-
13
- server = RTunnel::Server.new(
14
- :control_address => control_address
15
- )
16
-
17
- server.start
18
- server.join
data/lib/server.rb DELETED
@@ -1,197 +0,0 @@
1
- require 'rubygems'
2
- gem 'uuidtools', '>=1.0.2'
3
- require 'uuidtools'
4
-
5
- require 'core'
6
- require 'cmds'
7
-
8
- require 'gserver'
9
-
10
- Socket.do_not_reverse_lookup = true
11
-
12
- module RTunnel
13
- # listens for incoming connections to tunnel
14
- class RemoteListenServer < GServer
15
- CONNECTIONS = {}
16
- CONTROL_CONNECTION_MAPPING = {}
17
-
18
- def initialize(port, host, control_connection)
19
- super(port, host, 10)
20
- @control_connection = control_connection
21
- @maxConnections = 1024
22
- end
23
-
24
- def serve(sock)
25
- D "new incoming connection"
26
-
27
- conn_id = UUID.timestamp_create.hexdigest
28
- CONNECTIONS[conn_id] = sock
29
- CONTROL_CONNECTION_MAPPING[conn_id] = @control_connection
30
- begin
31
- ControlServer.new_tunnel(conn_id)
32
-
33
- sock.while_reading do |buf|
34
- begin
35
- ControlServer.send_data(conn_id, buf)
36
- rescue Exception
37
- D "error talking on control connection, dropping incoming connection: #{$!.inspect}"
38
- break
39
- end
40
- end
41
- rescue IOError
42
- raise unless $!.message =~ /stream closed/i
43
- end
44
-
45
- ControlServer.close_tunnel(conn_id)
46
-
47
- CONNECTIONS.delete conn_id
48
- CONTROL_CONNECTION_MAPPING.delete conn_id
49
-
50
- D "sock closed"
51
- rescue
52
- p $!
53
- puts $!.backtrace.join("\n")
54
- end
55
- end
56
-
57
- class ControlServer < GServer
58
- @@control_connections = []
59
- @@remote_listen_servers = []
60
-
61
- @@m = Mutex.new
62
-
63
- attr_accessor :ping_interval
64
-
65
- def initialize(*args)
66
- super
67
- @maxConnections = 1024
68
- end
69
-
70
- class << self
71
- def new_tunnel(conn_id)
72
- D "sending create connection command: #{conn_id}"
73
-
74
- @@m.synchronize { control_connection_for(conn_id).write CreateConnectionCommand.new(conn_id) }
75
- end
76
-
77
- def send_data(conn_id, data)
78
- @@m.synchronize { control_connection_for(conn_id).write SendDataCommand.new(conn_id, data) }
79
- end
80
-
81
- def close_tunnel(conn_id)
82
- D "sending close connection command"
83
-
84
- @@m.synchronize { control_connection_for(conn_id).write CloseConnectionCommand.new(conn_id) }
85
- end
86
-
87
- private
88
-
89
- def control_connection_for(conn_id)
90
- RemoteListenServer::CONTROL_CONNECTION_MAPPING[conn_id]
91
- end
92
- end
93
-
94
- def starting
95
- start_pinging
96
- end
97
-
98
- def serve(sock)
99
- D "new control connection"
100
- @@control_connections << sock
101
- sock.sync = true
102
-
103
- cmd_queue = ""
104
- sock.while_reading(cmd_queue = '') do
105
- while Command.match(cmd_queue)
106
- case cmd = Command.parse(cmd_queue)
107
- when RemoteListenCommand
108
- @@m.synchronize do
109
- addr, port = cmd.address.split(/:/)
110
- if rls = @@remote_listen_servers.detect {|s| s.port == port.to_i }
111
- rls.stop
112
- @@remote_listen_servers.delete rls
113
- end
114
- (new_rls = RemoteListenServer.new(port, addr, sock)).start
115
- @@remote_listen_servers << new_rls
116
- end
117
- D "listening for remote connections on #{cmd.address}"
118
- when SendDataCommand
119
- conn = RemoteListenServer::CONNECTIONS[cmd.conn_id]
120
- begin
121
- conn.write(cmd.data) if conn
122
- rescue Errno::EPIPE
123
- D "broken pipe on #{cmd.conn_id}"
124
- end
125
- when CloseConnectionCommand
126
- if connection = RemoteListenServer::CONNECTIONS[cmd.conn_id]
127
- D "closing remote connection: #{cmd.conn_id}"
128
- connection.close
129
- end
130
- else
131
- D "bad command received: #{cmd.inspect}"
132
- end
133
- end
134
- end
135
- rescue Errno::ECONNRESET
136
- D "client disconnected (conn reset)"
137
- rescue
138
- D $!.inspect
139
- D $@*"\n"
140
- raise
141
- ensure
142
- @@control_connections.delete sock
143
- end
144
-
145
- def stopping
146
- @ping_thread.kill
147
- @@remote_listen_server.stop
148
- end
149
-
150
- private
151
-
152
- def start_pinging
153
- @ping_thread = Thread.safe do
154
- loop do
155
- sleep @ping_interval
156
-
157
- @@m.synchronize do
158
- @@control_connections.each {|cc| cc.write PingCommand.new }
159
- end
160
- end
161
- end
162
- end
163
- end
164
-
165
- class Server
166
- def initialize(options = {})
167
- @control_address = options[:control_address]
168
- if ! @control_address
169
- @control_address = "0.0.0.0:#{DEFAULT_CONTROL_PORT}" if ! @control_address
170
- elsif @control_address =~ /^\d+$/
171
- @control_address.insert 0, "0.0.0.0:"
172
- elsif @control_address !~ /:\d+$/
173
- @control_address << ":#{DEFAULT_CONTROL_PORT}"
174
- end
175
- @control_host = @control_address.split(/:/).first
176
-
177
- @ping_interval = options[:ping_interval] || 2.0
178
- end
179
-
180
- def start
181
- @control_server = ControlServer.new(*@control_address.split(/:/).reverse)
182
- @control_server.ping_interval = @ping_interval
183
- @control_server.audit = true
184
-
185
- @control_server.start
186
- end
187
-
188
- def join
189
- @control_server.join
190
- end
191
-
192
- def stop
193
- @control_server.shutdown
194
- ControlServer.stop(@control_server.port, @control_server.host)
195
- end
196
- end
197
- end
data/rtunnel.gemspec DELETED
@@ -1,18 +0,0 @@
1
- Gem::Specification.new do |s|
2
- s.name = "rtunnel"
3
- s.version = "0.3.9"
4
- s.summary = "reverse tunnel server and client"
5
- s.email = "coderrr.contact@gmail.com"
6
- s.homepage = "http://github.com/coderrr/rtunnel"
7
- s.description = "reverse tunnel server and client"
8
- s.has_rdoc = false
9
- s.authors = ["coderrr"]
10
- s.files = [
11
- "lib/rtunnel_server_cmd.rb", "lib/client.rb", "lib/core.rb", "lib/rtunnel_client_cmd.rb", "lib/server.rb", "lib/cmds.rb", "bin/rtunnel_server", "bin/rtunnel_client",
12
- "ab_test.rb", "README.markdown", "rtunnel.gemspec", "stress_test.rb", "Rakefile", "rtunnel_client.rb", "rtunnel_server.rb"
13
- ]
14
- s.test_files = [
15
- "spec/integration_spec.rb", "spec/spec_helper.rb", "spec/client_spec.rb", "spec/cmds_spec.rb", "spec/server_spec.rb"
16
- ]
17
- s.add_dependency("uuidtools", [">= 1.0.2"])
18
- end
data/rtunnel_client.rb DELETED
@@ -1,3 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- load 'lib/rtunnel_client_cmd.rb'
data/rtunnel_server.rb DELETED
@@ -1,3 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- load 'lib/rtunnel_server_cmd.rb'
data/stress_test.rb DELETED
@@ -1,68 +0,0 @@
1
- require 'rubygems'
2
- require 'thin'
3
-
4
- require 'lib/core'
5
-
6
- require 'logger'
7
- require 'stringio'
8
-
9
-
10
- CONCURRENT_CONNECTIONS = 25
11
- DISPLAY_RTUNNEL_OUTPUT = false
12
- TUNNEL_PORT = 5000
13
- HTTP_PORT = 4444
14
-
15
- #################
16
-
17
- pids = []
18
- at_exit do
19
- pids.each {|pid| Process.kill 9, pid }
20
- p $!
21
- puts "done, hit ^C"
22
- sleep 999999
23
- end
24
-
25
- module Enumerable
26
- def parallel_map
27
- self.map do |e|
28
- Thread.new(e) do |element|
29
- yield element
30
- end
31
- end.map {|thread| thread.value }
32
- end
33
- end
34
-
35
- TUNNEL_URI = "http://localhost:#{TUNNEL_PORT}"
36
- EXPECTED_DATA = (0..10*1024).map{0until(c=rand(?z).chr)=~/(?!_)\w/;c}*'' # gen random string GOLF FTW!
37
- puts EXPECTED_DATA
38
-
39
- app = lambda { |env| [200, {}, EXPECTED_DATA] }
40
- server = ::Thin::Server.new('localhost', HTTP_PORT, app)
41
- Thread.new { server.start }
42
-
43
- base_dir = File.dirname(__FILE__)
44
-
45
- d = !DISPLAY_RTUNNEL_OUTPUT
46
- pids << fork{ exec "ruby #{base_dir}/rtunnel_server.rb #{d && '> /dev/null'} 2>&1" }
47
- pids << fork{ exec "ruby #{base_dir}/rtunnel_client.rb -c localhost -f #{TUNNEL_PORT} -t #{HTTP_PORT} #{d &&' > /dev/null'} 2>&1" }
48
-
49
- puts 'wait 2 secs'
50
- sleep 2
51
-
52
- STDOUT.sync = true
53
- 999999999.times do |i|
54
- puts i if i%10 == 0
55
- threads = []
56
- CONCURRENT_CONNECTIONS.times do
57
- threads << Thread.new do
58
- text = %x{curl --silent #{TUNNEL_URI}}
59
- if text != EXPECTED_DATA
60
- puts "BAD!!!!"*1000
61
- puts "response: #{text.inspect}"
62
- exit
63
- end
64
- end
65
- end
66
-
67
- threads.parallel_map {|t| t.join; print '.'; STDOUT.flush }
68
- end