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
@@ -0,0 +1,42 @@
1
+ require 'rtunnel'
2
+
3
+ require 'test/unit'
4
+
5
+ class SocketFactoryTest < Test::Unit::TestCase
6
+ SF = RTunnel::SocketFactory
7
+
8
+ def setup
9
+
10
+ end
11
+
12
+ def teardown
13
+
14
+ end
15
+
16
+ def test_host_from_address
17
+ assert_equal nil, SF.host_from_address(nil)
18
+ assert_equal '127.0.0.1', SF.host_from_address('127.0.0.1')
19
+ assert_equal '127.0.0.1', SF.host_from_address('127.0.0.1:1234')
20
+ assert_equal 'fe80::1%lo0', SF.host_from_address('fe80::1%lo0')
21
+ assert_equal 'fe80::1%lo0', SF.host_from_address('fe80::1%lo0:19020')
22
+ end
23
+
24
+ def test_port_from_address
25
+ assert_equal nil, SF.port_from_address(nil)
26
+ assert_equal nil, SF.port_from_address('127.0.0.1')
27
+ assert_equal 1234, SF.port_from_address('127.0.0.1:1234')
28
+ assert_equal nil, SF.port_from_address('fe80::1%lo0')
29
+ assert_equal 19020, SF.port_from_address('fe80::1%lo0:19020')
30
+ end
31
+
32
+ def test_inbound
33
+ assert SF.inbound?(:in_port => 1)
34
+ assert SF.inbound?(:in_host => '1')
35
+ assert SF.inbound?(:in_addr => '1')
36
+ assert SF.inbound?(:inbound => true)
37
+ assert !SF.inbound?(:out_port => 1)
38
+ assert !SF.inbound?(:out_host => '1')
39
+ assert !SF.inbound?(:out_addr => '1')
40
+ end
41
+ end
42
+
@@ -0,0 +1,186 @@
1
+ require 'rtunnel'
2
+
3
+ require 'test/unit'
4
+
5
+ require 'rubygems'
6
+ require 'eventmachine'
7
+
8
+ require 'test/scenario_connection.rb'
9
+
10
+ # Integration tests ensuring that we can start a tunnel.
11
+ class TunnelTest < Test::Unit::TestCase
12
+ def setup
13
+ super
14
+
15
+ @connection_time = 0.001
16
+ @secure_connection_time = 0.5
17
+ @log_level = 'debug'
18
+ @local_host = '127.0.0.1'
19
+ @listen_port = 21335
20
+ @tunnel_port = 21336
21
+ @control_port = 21337
22
+ @key_file = 'test_data/ssh_host_rsa_key'
23
+ @hosts_file = 'test_data/known_hosts'
24
+
25
+ @tunnel_server = new_server
26
+ @tunnel_client = new_client
27
+ end
28
+
29
+ def new_server(extra_options = {})
30
+ RTunnel::Server.new({
31
+ :control_address => "#{@local_host}:#{@control_port}",
32
+ :log_level => @log_level
33
+ }.merge(extra_options))
34
+ end
35
+
36
+ def new_client(extra_options = {})
37
+ RTunnel::Client.new({
38
+ :control_address => "#{@local_host}:#{@control_port}",
39
+ :remote_listen_address => "#{@local_host}:#{@listen_port}",
40
+ :tunnel_to_address => "#{@local_host}:#{@tunnel_port}",
41
+ :log_level => @log_level
42
+ }.merge(extra_options))
43
+ end
44
+
45
+ def tunnel_test(connection_time = nil)
46
+ @stop_proc = proc do
47
+ @tunnel_client.stop
48
+ @tunnel_server.stop
49
+ @stop_proc = nil
50
+ end
51
+
52
+ EventMachine::run do
53
+ @tunnel_server.start
54
+ @tunnel_client.start
55
+
56
+ if connection_time
57
+ EventMachine.add_timer(connection_time) { yield }
58
+ else
59
+ EventMachine.next_tick { yield }
60
+ end
61
+ end
62
+ end
63
+
64
+ def test_client_driven_tunnel
65
+ tunnel_test do
66
+ @tunnel_server.on_remote_listen do
67
+ EventMachine::start_server @local_host, @tunnel_port,
68
+ ScenarioConnection, self, [[:recv, 'Hello'], [:send, 'World'],
69
+ [:unbind], [:stop, @stop_proc]]
70
+
71
+ EventMachine::connect @local_host, @listen_port,
72
+ ScenarioConnection, self, [[:send, 'Hello'], [:recv, 'World'],
73
+ [:close]]
74
+ end
75
+ end
76
+ end
77
+
78
+ def test_server_driven_tunnel
79
+ tunnel_test do
80
+ @tunnel_server.on_remote_listen do
81
+ EventMachine::start_server @local_host, @tunnel_port,
82
+ ScenarioConnection, self, [[:send, 'Hello'], [:recv, 'World'],
83
+ [:close]]
84
+
85
+ EventMachine::connect @local_host, @listen_port,
86
+ ScenarioConnection, self, [[:recv, 'Hello'], [:send, 'World'],
87
+ [:unbind], [:stop]]
88
+ end
89
+ end
90
+ end
91
+
92
+ def test_two_tunnels
93
+ start_second = lambda do
94
+ @tunnel_client.stop
95
+ @tunnel_client.start
96
+ @tunnel_server.on_remote_listen do
97
+ EventMachine::connect @local_host, @listen_port,
98
+ ScenarioConnection, self, [[:send, 'Hello'], [:recv, 'World'],
99
+ [:unbind], [:stop, @stop_proc]]
100
+ end
101
+ end
102
+
103
+ tunnel_test do
104
+ @tunnel_server.on_remote_listen do
105
+ EventMachine::start_server @local_host, @tunnel_port,
106
+ ScenarioConnection, self, [[:recv, 'Hello'], [:send, 'World'],
107
+ [:close], [:recv, 'Hello'], [:send, 'World'], [:close]]
108
+
109
+ EventMachine::connect @local_host, @listen_port,
110
+ ScenarioConnection, self, [[:send, 'Hello'], [:recv, 'World'],
111
+ [:proc, start_second], [:unbind]]
112
+ end
113
+ end
114
+ end
115
+
116
+ def test_secure_tunnel
117
+ @tunnel_server = new_server :authorized_keys => @hosts_file
118
+ @tunnel_client = new_client :private_key => @key_file
119
+ tunnel_test do
120
+ @tunnel_server.on_remote_listen do
121
+ EventMachine::start_server @local_host, @tunnel_port,
122
+ ScenarioConnection, self, [[:recv, 'Hello'], [:send, 'World'],
123
+ [:unbind], [:stop, @stop_proc]]
124
+
125
+ EventMachine::connect @local_host, @listen_port,
126
+ ScenarioConnection, self, [[:send, 'Hello'], [:recv, 'World'],
127
+ [:close]]
128
+ end
129
+ end
130
+ end
131
+
132
+ def test_secure_async_tunnel
133
+ @tunnel_server = new_server :authorized_keys => @hosts_file
134
+ @tunnel_client = new_client :private_key => @key_file
135
+ tunnel_test do
136
+ @tunnel_server.on_remote_listen do
137
+ EventMachine::start_server @local_host, @tunnel_port,
138
+ ScenarioConnection, self, [[:send, 'World'], [:recv, 'Hello'],
139
+ [:unbind], [:stop, @stop_proc]]
140
+
141
+ EventMachine::connect @local_host, @listen_port,
142
+ ScenarioConnection, self, [[:send, 'Hello'], [:recv, 'World'],
143
+ [:close]]
144
+ end
145
+ end
146
+ end
147
+
148
+ def test_bad_listen_address
149
+ @tunnel_server = new_server
150
+ @tunnel_client = new_client :remote_listen_address =>
151
+ "18.70.0.160:#{@listen_port}"
152
+
153
+ tunnel_test do
154
+ EventMachine::start_server @local_host, @tunnel_port,
155
+ ScenarioConnection, self, []
156
+
157
+ EventMachine::connect @local_host, @listen_port,
158
+ ScenarioConnection, self, [[:unbind], [:stop, @stop_proc]]
159
+ end
160
+ end
161
+
162
+ # TODO: fix this
163
+ def test_secure_server_rejects_unsecure_client
164
+ @tunnel_server = new_server :authorized_keys => @hosts_file
165
+ tunnel_test(@secure_connection_time) do
166
+ EventMachine::start_server @local_host, @tunnel_port,
167
+ ScenarioConnection, self, []
168
+
169
+ EventMachine::connect @local_host, @listen_port,
170
+ ScenarioConnection, self, [[:unbind], [:stop, @stop_proc]]
171
+ end
172
+ end
173
+
174
+ # hrmf... this is testing security and its not 100% reliable... but I can't think of a better way
175
+ def test_secure_server_rejects_unauthorized_key
176
+ @tunnel_server = new_server :authorized_keys => @hosts_file
177
+ @tunnel_client = new_client :private_key => 'test_data/random_rsa_key'
178
+ tunnel_test(@secure_connection_time) do
179
+ EventMachine::start_server @local_host, @tunnel_port,
180
+ ScenarioConnection, self, []
181
+
182
+ EventMachine::connect @local_host, @listen_port,
183
+ ScenarioConnection, self, [[:unbind], [:stop, @stop_proc]]
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,4 @@
1
+ no-port-forwarding,no-agent-forwarding,command="/usr/NX/bin/nxnode" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== stub@github.org
2
+ no-port-forwarding,no-agent-forwarding,command="/usr/NX/bin/nxnode" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq7VciLo2wB+/2ThHXejC/kgkN205zlyS5cvN40Mqi3qvRVS75X1RawDoLot8eJ9KCYqZFr2Dr73d/EQNltN7dKJoPIj1IKxoraWkyNFbhhzpYuOltg9oO5UBSTNLupqla7zcdj4IwCCkBYk4+TS0dwmi20buOJ0FPY5PgbzmMnUiV9ipBqeJSdZB+TePH1gqlt7AP/6ti/0gxb2K7F69dZl/BSxMEzRCfBlTFC3f/4n8IdCuSJvNxxY+TtRnLL5CKUhj9QaIBan6JCkdRvVOBY7wmsNT8nGDzfDFSDD3KKn93g4LRkyMeaYlSDLxKy8PnNhjWgBNH1YNYyicsGfBKQ== costan@obsidian.local
3
+ no-port-forwarding,no-agent-forwarding,command="/usr/NX/bin/nxnode" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3tPhdPUFGAYyrT1quRSOevLbAdKAJ6Ovwqw0m99R0QkqUwMUh09pgedWZeij7HtAHtoWPrNFev8FrwcwnL14NgA/gwNnXxbqd4twC1HyFShUf7POry8bz3Qk+84STHeMY8++hhn8LgNyfuVQswHoW661aqieLM6pF8q8xIUtkXA7daNpJAL4nTN1TxgUoCDpCa0EbUPkGpwFPNtGPuokRXNOCR9g8T6LmPQbzGUTc4CzFfQ9rrHaimqkEmRWJbBOaik1bdQNqOh6MUDDuUSpkJV7fwu3bl4fF5/1kw2HCREEjJmESOYnZhOS+MCp1qAUcuXqpMqXD8ATNsuXqrIhTQ== stub@rubyforge.org
4
+ no-port-forwarding,no-agent-forwarding,command="/usr/NX/bin/nxnode" ssh-dss AAAAB3NzaC1kc3MAAACBAPdWp4HhWUoNawosyEBvrhPSbjhCJiKnVWiUS6bo0BCGzTHhugrkv2HgtlKhWo8nqTw5E4YxzFVyZ0YQt4m7NYDLTZVjrqbIpL/3F5qNXco127O/im0cG27AKC8Jf7knmUTjd8EBhtK65tNDmxPtzKQtemlNTVPX1VccOn6eLtn1AAAAFQDtQC21TJrf/p5WNsU9UIJzO9/hIwAAAIEAgwTrIfleQMEAK9N3xeMVZpAGfSAoX6owLtk3z+iQ3rM9FRvM/CgezOgezLowJghkw/bcQDmMuudBUuijrM3zZWdr6eqoNbFTR/KKiUx3cYf0LAHNPbXfVz+P7BXqjcEj75qnwuHQMp7vNMg+dmV40UA2TiC5/8QlaZVwkOSPN6gAAACAPMGJEFkoR0ayfkd0S/tnY9ilO17T6rdoDuF25ATtNUd6Zji6tslxBkQFWtTeinO3rGkqJRPndq0wp3E33AOHhJE/FOIlWl4Tf6aeU95Y4enYujKQDiImSTXmdiw5wq/LFdc3a2waOUvuI+647wxgHhqTmD7xI2biGZLYN9Oasy0= costan@obsidian.local
@@ -0,0 +1,4 @@
1
+ github.com,65.74.177.129 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
2
+ obsidian.local ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq7VciLo2wB+/2ThHXejC/kgkN205zlyS5cvN40Mqi3qvRVS75X1RawDoLot8eJ9KCYqZFr2Dr73d/EQNltN7dKJoPIj1IKxoraWkyNFbhhzpYuOltg9oO5UBSTNLupqla7zcdj4IwCCkBYk4+TS0dwmi20buOJ0FPY5PgbzmMnUiV9ipBqeJSdZB+TePH1gqlt7AP/6ti/0gxb2K7F69dZl/BSxMEzRCfBlTFC3f/4n8IdCuSJvNxxY+TtRnLL5CKUhj9QaIBan6JCkdRvVOBY7wmsNT8nGDzfDFSDD3KKn93g4LRkyMeaYlSDLxKy8PnNhjWgBNH1YNYyicsGfBKQ==
3
+ rubyforge.org,205.234.109.19 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3tPhdPUFGAYyrT1quRSOevLbAdKAJ6Ovwqw0m99R0QkqUwMUh09pgedWZeij7HtAHtoWPrNFev8FrwcwnL14NgA/gwNnXxbqd4twC1HyFShUf7POry8bz3Qk+84STHeMY8++hhn8LgNyfuVQswHoW661aqieLM6pF8q8xIUtkXA7daNpJAL4nTN1TxgUoCDpCa0EbUPkGpwFPNtGPuokRXNOCR9g8T6LmPQbzGUTc4CzFfQ9rrHaimqkEmRWJbBOaik1bdQNqOh6MUDDuUSpkJV7fwu3bl4fF5/1kw2HCREEjJmESOYnZhOS+MCp1qAUcuXqpMqXD8ATNsuXqrIhTQ==
4
+ obsidian.local ssh-dss AAAAB3NzaC1kc3MAAACBAPdWp4HhWUoNawosyEBvrhPSbjhCJiKnVWiUS6bo0BCGzTHhugrkv2HgtlKhWo8nqTw5E4YxzFVyZ0YQt4m7NYDLTZVjrqbIpL/3F5qNXco127O/im0cG27AKC8Jf7knmUTjd8EBhtK65tNDmxPtzKQtemlNTVPX1VccOn6eLtn1AAAAFQDtQC21TJrf/p5WNsU9UIJzO9/hIwAAAIEAgwTrIfleQMEAK9N3xeMVZpAGfSAoX6owLtk3z+iQ3rM9FRvM/CgezOgezLowJghkw/bcQDmMuudBUuijrM3zZWdr6eqoNbFTR/KKiUx3cYf0LAHNPbXfVz+P7BXqjcEj75qnwuHQMp7vNMg+dmV40UA2TiC5/8QlaZVwkOSPN6gAAACAPMGJEFkoR0ayfkd0S/tnY9ilO17T6rdoDuF25ATtNUd6Zji6tslxBkQFWtTeinO3rGkqJRPndq0wp3E33AOHhJE/FOIlWl4Tf6aeU95Y4enYujKQDiImSTXmdiw5wq/LFdc3a2waOUvuI+647wxgHhqTmD7xI2biGZLYN9Oasy0=
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEowIBAAKCAQEAoSWzcqViB/JUz6Zd80c3km114/OWfxbGo/xeZqJm4s9+kR8o
3
+ xtFjfbj9oDiuckSkAPNQW5VUWCeeNdpNjLmBe4Jm40R+FfibLOR5lw5I/7jVozBZ
4
+ gQKuF395ODgbOwGXMsmRc1xViDYsOzo4A/f+5WhbpG20AtBz6+mg3yDLWXDffhat
5
+ ecRf7PvWvlkj0QtL6538a7OE4MY75pCiTLWWbHJnBoQgNmYFZZdBaarHsenlKSQ9
6
+ P6xL6ENyDOom3/Xk9bvqHQNNvgHyN4e4PRAtZUqsjyoRMm8sfDIJhK+cvpvqqWWm
7
+ QK1ef1Fb1yXnmjkmUfx15UXxGgB79v3/vYWmJwIBIwKCAQBugECJIPLDntsSC64j
8
+ KYUxNR2jn7enmpbW2PBGYLuUNoKsp6buu3dsJxRQm+VVq2klOSEo220JP7zxukPO
9
+ Ng+lJjfsTDkzoyiTz95Y89pI88WxusEIAdZ2g0vOx2MhJamB6U3LcoPLHdUv7Wg9
10
+ PFcDtUYnm66i2BT5ikJtHc1EpBTte71pZVRQsHYEsgcnNfsIc9hpXZacQ8CxF3Cc
11
+ gM35GRSC7z/UVouyMbhQCjeKrlR/aZIE1whpnWpdOa+AeYtdndwxn6gNeplV8lA1
12
+ 8J0mpQlsy9i8cl2Nx/euN+dAW87zI3kwm1znj4pHF5e12v+SziZqnjuI4PhxNJO1
13
+ CSRLAoGBAM9WfBRkVuWv+RdVm5VBpSwvBDytJpqcSbTxkypmV7sN6I4A2rBcNws9
14
+ IaJ7Bf+ZxG4R8THXg5jCt1yfjIwMYrQ1Jg7aVALwF+JzeZgGTWFYJwCcC5VXCvy7
15
+ gsJhnboBPVuM3Vxhz98nHKUngbLDbV8Sl+DVp1NDJ+tDJqY6tVZNAoGBAMb38M+G
16
+ ZF9HVr33Oe7LjLxQRiQk5G6gmbidZfOszK797/BxYd1vMMPEl8d56zcYkeaIDmvL
17
+ xHGLhoT6vtA4N0WCuk96USBk7JrRYhXoGTw0yFOJyopzPWdR66iaVbF/g1aknzki
18
+ pZfb2LeyocztlxKJTUe0IocEkHu5aqzFeFBDAoGBAI4srNrIdhnXwL+LKNtgNr82
19
+ LsqFXEzC8LaXBdPuaAs8vLklKD5rHm4bSkOHjxWrRN3DKQw8Andg8sMrk5M7sWWg
20
+ yaPI6SaWAb/aJ34wNQ+M54tjsCvj6kbm+pPrKlOpFCGFKhN2RWXRrT4MdjFwEHu0
21
+ +m5JXMthP/HHpXlM1B3rAoGBAMFIoMmYfsL01+u89nLxnqhN+v6KPP3AlVRBITXb
22
+ D/pzBldJkkTSaeK++de4Q5SbhmrqkaqLbl+sHEaqcDf8GG9pDMI8Ts8C9HkjLBVH
23
+ 3f/4wppLVwomze9W5OztslSnwWocQucLts4Iw+WmNscSsANgzrqu/PgwUddGZ6CF
24
+ UE33AoGBAJ3VCQx0hwDSIQuuakjUb5ouPup+8B1A7wspGirkQNlTZ1F2q4Zug/Fp
25
+ dovyzPZuV3/0dVDNbQzz21gRuiE2I/l9uF4Bz2LqY1Jg1R9WuQH5sdRG0ncf6Ikn
26
+ 1LRLgE2tCGGfhLUi2vDMwORx1o46p4hboF8ZaOBK1+WIwNnfRGNl
27
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,12 @@
1
+ -----BEGIN DSA PRIVATE KEY-----
2
+ MIIBvAIBAAKBgQD3VqeB4VlKDWsKLMhAb64T0m44QiYip1VolEum6NAQhs0x4boK
3
+ 5L9h4LZSoVqPJ6k8OROGMcxVcmdGELeJuzWAy02VY66myKS/9xeajV3KNduzv4pt
4
+ HBtuwCgvCX+5J5lE43fBAYbSuubTQ5sT7cykLXppTU1T19VXHDp+ni7Z9QIVAO1A
5
+ LbVMmt/+nlY2xT1QgnM73+EjAoGBAIME6yH5XkDBACvTd8XjFWaQBn0gKF+qMC7Z
6
+ N8/okN6zPRUbzPwoHszoHsy6MCYIZMP23EA5jLrnQVLoo6zN82Vna+nqqDWxU0fy
7
+ iolMd3GH9CwBzT2131c/j+wV6o3BI++ap8Lh0DKe7zTIPnZleNFANk4guf/EJWmV
8
+ cJDkjzeoAoGAPMGJEFkoR0ayfkd0S/tnY9ilO17T6rdoDuF25ATtNUd6Zji6tslx
9
+ BkQFWtTeinO3rGkqJRPndq0wp3E33AOHhJE/FOIlWl4Tf6aeU95Y4enYujKQDiIm
10
+ STXmdiw5wq/LFdc3a2waOUvuI+647wxgHhqTmD7xI2biGZLYN9Oasy0CFQDL/9Z1
11
+ fSLn88m1sUeWAZ4Ys2IIxw==
12
+ -----END DSA PRIVATE KEY-----
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEoQIBAAKCAQEAq7VciLo2wB+/2ThHXejC/kgkN205zlyS5cvN40Mqi3qvRVS7
3
+ 5X1RawDoLot8eJ9KCYqZFr2Dr73d/EQNltN7dKJoPIj1IKxoraWkyNFbhhzpYuOl
4
+ tg9oO5UBSTNLupqla7zcdj4IwCCkBYk4+TS0dwmi20buOJ0FPY5PgbzmMnUiV9ip
5
+ BqeJSdZB+TePH1gqlt7AP/6ti/0gxb2K7F69dZl/BSxMEzRCfBlTFC3f/4n8IdCu
6
+ SJvNxxY+TtRnLL5CKUhj9QaIBan6JCkdRvVOBY7wmsNT8nGDzfDFSDD3KKn93g4L
7
+ RkyMeaYlSDLxKy8PnNhjWgBNH1YNYyicsGfBKQIBIwKCAQA/xwUc13Nr7okWKtit
8
+ 2hyKVU9HyXve7y8/aPSzf1jx+l5blIBN7LfXSXrPdaNCvtJbULyEygxXN+S8yNHY
9
+ 73b/b4XNV3D9gd281x/y0WsjL09fPpyitUP435LDatL8Ks+6TXZ1D7obedaFtqAi
10
+ DEMHpH5Rch33xUsW3RY3gK1F8GHzYh+zMd0llH8w6IVBv0hrWttyp+4By1dhXA3L
11
+ alYYOlGbu5cNuJfz50v4T/uB9F63JqHtAxEjqD7SvjCUbogGPxEH1k4Or+3xGuvR
12
+ yTPaiuR9kehBstjbqc91rTLnGOr5a1VUIq6++0tCVOXQa+x5J5zCu/baGTdfkgRU
13
+ loILAoGBAOHQcGIEgD1xHwFX9AafarF+1j4pPkM1p2u+9DNTIl1f2Rk6yOHlHZGF
14
+ mfozMyh6l4HpvPTT7nflM4YR0JWJNbQIpCY8CdYKMXBVWcH4PXuqwyGKJBZMXWkn
15
+ hKvelJ0UZUwx5+n8fTmSxLcIIlz5uKEE5k23/3cKkP7P6+Z6YuIZAoGBAMKpYBkM
16
+ A4JMJ3QJ5TVsdFOoO0b1wThRgQTZR6ic9rNeXnZiL0mmr44DX2T1rTnEm6KZv2f2
17
+ kWLQp5jx8BPFI+TUv16j4xrnnuHPhuBordCYQizSPcxXqL8b8a/KU+S5xofRjwB6
18
+ +8szd/JmGFDY8WgWrtIL32TdRhcIFg0Dg1mRAoGAE1sCUYtbcvsRSUINmirr41QD
19
+ vC9rvJ4y6/pss/Eu1M2zhdHWtEbWphLEDiGlTJzLKGR96Rl61xOlVKJw9t/gCB3/
20
+ cP3U9RbRCaDqb7YxJ9tvz6zBQ71nF6RNM02XtbFKgt+0yunBlzh3QuNwqOI0ZZK0
21
+ p5Ntqx4pr3DoVZV2MKMCgYBprGdeDdYE54MhvDqZWCHkRWIB8x+/fLPAzbkvpap+
22
+ oPFzdyD8GKhxqg82zoKbs991hqm8GCMJwboRMuFp0WtBtVHxjCrUF1ZAEZJckJje
23
+ 85GjTY9DCwPVdZHUdSY6VjiS33mD6v23c7YkgJDbbnRrtIrJy+5MsqJkRjfbLcr2
24
+ GwKBgQCWDKVM8mZJcmM3KJwzBWh+b5T7tIbOBFaCvOBq4G0UUZGytWVUaddSbdh5
25
+ YJ+1CoLDB+Wp3U95B1USQuSYwwr0wOYy42HBII7HnkaphT9HgDIhgvttFhX162oC
26
+ bRizr31NgiGtgJbHJ9QPhaLvn3mZtZAFfRaEEdZslUzqRSACww==
27
+ -----END RSA PRIVATE KEY-----
data/tests/_ab_test.rb ADDED
@@ -0,0 +1,16 @@
1
+ base_dir = File.dirname(__FILE__)
2
+ lo_server_file = File.join(base_dir, '../tests/lo_http_server.rb')
3
+ lo_port = 4000
4
+ Kernel.system "ruby #{lo_server_file} start #{lo_port}"
5
+
6
+ fork{ exec "ruby #{base_dir}/../lib/rtunnel/rtunnel_server.rb > /dev/null 2>&1" }
7
+ fork{ exec "ruby #{base_dir}/../lib/rtunnel/rtunnel_client.rb -c localhost -f 5000 -t 4000 > /dev/null" }
8
+
9
+ sleep 2
10
+
11
+ (puts "you need ab (apache bench) to run this stress test" ; exit) if %x{which ab}.empty?
12
+
13
+ Process.wait fork { exec("ab -c 500 -n 10000 http://localhost:5000/") }
14
+
15
+ puts "done, hit ^C"
16
+ sleep 999999
@@ -0,0 +1,96 @@
1
+ require 'rubygems'
2
+ require 'eventmachine'
3
+ require 'logger'
4
+ require 'stringio'
5
+
6
+ CONCURRENT_CONNECTIONS = 50
7
+ DISPLAY_RTUNNEL_OUTPUT = true
8
+ TUNNEL_PORT = 5000
9
+ HTTP_PORT = 4444
10
+
11
+ #################
12
+
13
+ TUNNEL_URI = "http://localhost:#{TUNNEL_PORT}"
14
+ srand(0) # deterministic random data
15
+ EXPECTED_DATA = Array.new(16*1024) { rand(?z).chr }*''
16
+
17
+ $pids = [$$]
18
+
19
+ def cleanup
20
+ puts $!, $@ if $!
21
+
22
+ # move the current process to the end of the kill list
23
+ $pids << $pids.delete($$)
24
+ $pids.each {|pid| Process.kill 9, pid rescue nil }
25
+
26
+ exit!
27
+ end
28
+
29
+ at_exit { cleanup }
30
+
31
+ ENV['RTUNNEL_DEBUG'] = '1' if DISPLAY_RTUNNEL_OUTPUT
32
+
33
+ base_dir = File.join(File.dirname(__FILE__), '..', 'bin')
34
+ $pids << fork{ exec "ruby", "-Ilib", "#{base_dir}/rtunnel_server" }
35
+ $pids << fork{ exec "ruby", "-Ilib", "#{base_dir}/rtunnel_client", '-c', '127.0.0.1', '-f', TUNNEL_PORT.to_s, '-t', "127.0.0.1:#{HTTP_PORT}" }
36
+
37
+ $pids << fork do
38
+ require 'thin'
39
+
40
+ app = lambda do |env|
41
+ body = env['rack.input'].string
42
+ if body != EXPECTED_DATA
43
+ p body, EXPECTED_DATA
44
+ puts "server received BAD DATA!"
45
+
46
+ cleanup
47
+ end
48
+
49
+ [200, {}, EXPECTED_DATA]
50
+ end
51
+
52
+ Thin::Server.new('localhost', HTTP_PORT, app).start
53
+ end
54
+
55
+ puts 'wait 2 secs...'
56
+ sleep 2
57
+
58
+ module Stresser
59
+ @@open_connections = 0
60
+
61
+ def post_init
62
+ @@open_connections += 1
63
+ send_data "POST / HTTP/1.0\r\nContent-Length: #{EXPECTED_DATA.size}\r\n\r\n#{EXPECTED_DATA}"
64
+ @data = ''
65
+ print '('; $stdout.flush
66
+ end
67
+
68
+ def receive_data(data)
69
+ @data << data
70
+ print '.'; $stdout.flush
71
+ end
72
+
73
+ def unbind
74
+ if @data.gsub(/\A.+\r\n\r\n/m,'') != EXPECTED_DATA
75
+ p EXPECTED_DATA, @data
76
+ puts "client received BAD DATA!"
77
+
78
+ cleanup
79
+ end
80
+
81
+ print ')'; $stdout.flush
82
+
83
+ @@open_connections -= 1
84
+ EventMachine.stop_event_loop if @@open_connections == 0
85
+ end
86
+ end
87
+
88
+ loop do
89
+ EventMachine.run do
90
+ CONCURRENT_CONNECTIONS.times do
91
+ EventMachine.connect 'localhost', TUNNEL_PORT, Stresser
92
+ end
93
+ end
94
+
95
+ puts
96
+ end
@@ -0,0 +1,55 @@
1
+ require 'net/http'
2
+ require 'socket'
3
+ require 'time'
4
+
5
+ require 'rubygems'
6
+ require 'simple-daemon'
7
+
8
+ class LoHttpServer < SimpleDaemon::Base
9
+ def send_headers(socket, status, length = 0, mime_type = 'text/html', headers = {})
10
+ reason = headers[:reason] || {200 => 'OK', 404 => 'File not found'}[status]
11
+
12
+ response_line = "HTTP/1.1 #{status} #{reason}\r\n"
13
+
14
+ response_headers = { 'Connection' => 'close', 'Server' => 'Rubylicious/1.0', 'Date' => Time.now.rfc2822,
15
+ 'Content-Type' => mime_type, 'Content-Length' => length }.merge headers
16
+
17
+ socket.write response_line
18
+ socket.write response_headers.to_a.map { |k,v| k.to_s + ': ' + v.to_s }.join("\r\n") + "\r\n\r\n"
19
+ end
20
+
21
+ def send_html(socket, html_data = "Loopback page\n")
22
+ send_headers(socket, 200, html_data.length)
23
+ socket.write html_data
24
+ socket.close
25
+ end
26
+
27
+ def run(listen_port)
28
+ listen_socket = TCPServer.new listen_port
29
+
30
+ loop do
31
+ client_socket = listen_socket.accept
32
+ Thread.new do
33
+ begin
34
+ print client_socket.readpartial(16384), "\n"
35
+ send_html client_socket
36
+ rescue
37
+ print "#{$!.class.name}: #{$!}\n"
38
+ print $!.backtrace.join("\n"), "\n"
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ SimpleDaemon::WORKING_DIRECTORY = File.dirname(__FILE__)
45
+
46
+ def self.start
47
+ port = ARGV[1] || 3000
48
+ self.new.run(port)
49
+ end
50
+
51
+ def self.stop
52
+ end
53
+ end
54
+
55
+ LoHttpServer.daemonize