pagoda-tunnel 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +16 -0
- data/lib/pagoda-tunnel.rb +157 -0
- data/pagoda-tunnel.gemspec +31 -0
- data/spec/tunnel_spec.rb +34 -0
- metadata +74 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
|
4
|
+
desc "Run all specs"
|
5
|
+
RSpec::Core::RakeTask.new('spec') do |t|
|
6
|
+
t.rspec_opts = ['--colour --format documentation']
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Create tag v#{Pagoda::Tunnel::VERSION}"
|
10
|
+
task :tag do
|
11
|
+
|
12
|
+
puts "tagging version v#{Pagoda::Tunnel::VERSION}"
|
13
|
+
`git tag -a v#{Pagoda::Tunnel::VERSION} -m "Version #{Pagoda::Tunnel::VERSION}"`
|
14
|
+
`git push origin --tags`
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require 'socket'
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
module Pagoda
|
6
|
+
class Tunnel
|
7
|
+
VERSION = "0.1.0"
|
8
|
+
# Your code goes here...
|
9
|
+
|
10
|
+
def initialize(type, user, pass, app, instance, port = 3306)
|
11
|
+
@type = type
|
12
|
+
@user = user
|
13
|
+
@pass = pass
|
14
|
+
@app = app
|
15
|
+
@instance = instance
|
16
|
+
@port = port
|
17
|
+
end
|
18
|
+
|
19
|
+
def port_available?(ip, port)
|
20
|
+
begin
|
21
|
+
Timeout::timeout(1) do
|
22
|
+
begin
|
23
|
+
s = TCPSocket.new(ip, port)
|
24
|
+
s.close
|
25
|
+
return false
|
26
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
27
|
+
return true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
rescue Timeout::Error
|
31
|
+
end
|
32
|
+
return true
|
33
|
+
end
|
34
|
+
|
35
|
+
def next_available_port(start_port)
|
36
|
+
until port_available?("0.0.0.0", start_port)
|
37
|
+
# puts "port #{start_port} was not available"
|
38
|
+
start_port += 1
|
39
|
+
end
|
40
|
+
start_port
|
41
|
+
end
|
42
|
+
|
43
|
+
def start
|
44
|
+
|
45
|
+
[:INT, :TERM].each do |sig|
|
46
|
+
Signal.trap(sig) do
|
47
|
+
puts "Tunnel Closed."
|
48
|
+
puts "-----------------------------------------------"
|
49
|
+
puts
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
remote_host = "tunnel.pagodabox.com" # switch to tunnel.pagodabox.com
|
55
|
+
remote_port = 443
|
56
|
+
|
57
|
+
max_threads = 20
|
58
|
+
threads = []
|
59
|
+
|
60
|
+
chunk = 4096*4096
|
61
|
+
|
62
|
+
# puts "start TCP server"
|
63
|
+
# puts "+> Opening Tunnel"
|
64
|
+
@port = next_available_port(@port)
|
65
|
+
retrys = 0
|
66
|
+
begin
|
67
|
+
proxy_server = TCPServer.new('0.0.0.0', @port)
|
68
|
+
rescue Exception => e
|
69
|
+
@port += 1
|
70
|
+
retry if retrys < 4
|
71
|
+
# puts "unable to connect to #{@port}. The algorithm is broken"
|
72
|
+
exit
|
73
|
+
end
|
74
|
+
|
75
|
+
puts
|
76
|
+
puts "Tunnel Established! Accepting connections on :"
|
77
|
+
puts "-----------------------------------------------"
|
78
|
+
puts
|
79
|
+
puts "HOST : 127.0.0.1 (or localhost)"
|
80
|
+
puts "PORT : #{@port}"
|
81
|
+
puts "USER : (found in pagodabox dashboard)"
|
82
|
+
puts "PASS : (found in pagodabox dashboard)"
|
83
|
+
puts
|
84
|
+
puts "-----------------------------------------------"
|
85
|
+
puts "(note : ctrl-c To close this tunnel)"
|
86
|
+
|
87
|
+
loop do
|
88
|
+
|
89
|
+
# puts "start a new thread for every client connection"
|
90
|
+
threads << Thread.new(proxy_server.accept) do |client_socket|
|
91
|
+
begin
|
92
|
+
# puts "client connection"
|
93
|
+
begin
|
94
|
+
server_socket = TCPSocket.new(remote_host, remote_port)
|
95
|
+
ssl_context = OpenSSL::SSL::SSLContext.new()
|
96
|
+
ssl_socket = OpenSSL::SSL::SSLSocket.new(server_socket, ssl_context)
|
97
|
+
ssl_socket.sync_close = true
|
98
|
+
ssl_socket.connect
|
99
|
+
rescue Errno::ECONNREFUSED
|
100
|
+
# puts "connection refused"
|
101
|
+
client_socket.close
|
102
|
+
raise
|
103
|
+
end
|
104
|
+
|
105
|
+
# puts "authenticate"
|
106
|
+
if ssl_socket.readpartial(chunk) == "auth"
|
107
|
+
# puts "authentication"
|
108
|
+
# puts "auth=#{@type}:#{@user}:#{@pass}:#{@app}:#{@instance}"
|
109
|
+
ssl_socket.write "auth=#{@type}:#{@user}:#{@pass}:#{@app}:#{@instance}"
|
110
|
+
if ssl_socket.readpartial(chunk) == "success"
|
111
|
+
# puts "successful connection"
|
112
|
+
else
|
113
|
+
# puts "failed connection"
|
114
|
+
end
|
115
|
+
else
|
116
|
+
# puts "danger will robbinson! abort!"
|
117
|
+
end
|
118
|
+
|
119
|
+
loop do
|
120
|
+
# puts "wait for data on either socket"
|
121
|
+
(ready_sockets, dummy, dummy) = IO.select([client_socket, ssl_socket])
|
122
|
+
|
123
|
+
# puts "full duplex connection until data stream ends"
|
124
|
+
begin
|
125
|
+
ready_sockets.each do |socket|
|
126
|
+
data = socket.readpartial(chunk)
|
127
|
+
if socket == client_socket
|
128
|
+
# puts "SERVER <== CLIENT"
|
129
|
+
ssl_socket.write data
|
130
|
+
ssl_socket.flush
|
131
|
+
else
|
132
|
+
# puts "SERVER ==> CLIENT"
|
133
|
+
client_socket.write data
|
134
|
+
client_socket.flush
|
135
|
+
end
|
136
|
+
end
|
137
|
+
rescue EOFError
|
138
|
+
break
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
rescue StandardError => error
|
143
|
+
end
|
144
|
+
client_socket.close rescue StandardError
|
145
|
+
ssl_socket.close rescue StandardError
|
146
|
+
end
|
147
|
+
|
148
|
+
# puts "clean up the dead threads, and wait until we have available threads"
|
149
|
+
threads = threads.select { |thread| thread.alive? ? true : (thread.join; false) }
|
150
|
+
while threads.size >= max_threads
|
151
|
+
sleep 1
|
152
|
+
threads = threads.select { |thread| thread.alive? ? true : (thread.join; false) }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "pagoda-tunnel"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "pagoda-tunnel"
|
7
|
+
s.version = Pagoda::Tunnel::VERSION
|
8
|
+
s.authors = ["Lyon"]
|
9
|
+
s.email = ["lyon@delorum.com"]
|
10
|
+
s.homepage = "http://www.pagodabox.com"
|
11
|
+
s.summary = %q{Pagodabox Tunnel gem}
|
12
|
+
s.description = %q{Pagodabox container tunnel. Allows users to tunnel into pagodabox db's.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "pagoda-tunnel"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# Development
|
22
|
+
s.add_development_dependency "rspec"
|
23
|
+
# s.add_development_dependency "simplecov"
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
# Production
|
28
|
+
s.add_dependency "rest-client"
|
29
|
+
|
30
|
+
|
31
|
+
end
|
data/spec/tunnel_spec.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
require 'pagoda-tunnel'
|
3
|
+
|
4
|
+
describe Pagoda::Tunnel do
|
5
|
+
|
6
|
+
it "can create a connection" do
|
7
|
+
tunnel = Pagoda::Tunnel.new(nil,nil,nil,nil,nil)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "cannot find an open port" do
|
11
|
+
tunnel = Pagoda::Tunnel.new(nil,nil,nil,nil,nil)
|
12
|
+
tunnel.port_available?("0.0.0.0", 3309).should == true
|
13
|
+
end
|
14
|
+
|
15
|
+
it "finds an open port" do
|
16
|
+
sock = TCPServer.new("0.0.0.0", 40000)
|
17
|
+
tunnel = Pagoda::Tunnel.new(nil,nil,nil,nil,nil)
|
18
|
+
tunnel.port_available?("0.0.0.0", 40000).should == false
|
19
|
+
sock.close
|
20
|
+
end
|
21
|
+
|
22
|
+
it "searches until it finds an available port" do
|
23
|
+
tunnel = Pagoda::Tunnel.new(nil,nil,nil,nil,nil)
|
24
|
+
tunnel.should_receive(:port_available?).with("0.0.0.0", 40000).and_return false
|
25
|
+
tunnel.should_receive(:port_available?).with("0.0.0.0", 40001).and_return false
|
26
|
+
tunnel.should_receive(:port_available?).with("0.0.0.0", 40002).and_return false
|
27
|
+
tunnel.should_receive(:port_available?).with("0.0.0.0", 40003).and_return true
|
28
|
+
STDOUT.stub(:puts)
|
29
|
+
tunnel.next_available_port(40000).should == 40003
|
30
|
+
end
|
31
|
+
|
32
|
+
it "needs more testing"
|
33
|
+
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pagoda-tunnel
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Lyon
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-12 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &2156757880 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2156757880
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rest-client
|
27
|
+
requirement: &2156757260 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2156757260
|
36
|
+
description: Pagodabox container tunnel. Allows users to tunnel into pagodabox db's.
|
37
|
+
email:
|
38
|
+
- lyon@delorum.com
|
39
|
+
executables: []
|
40
|
+
extensions: []
|
41
|
+
extra_rdoc_files: []
|
42
|
+
files:
|
43
|
+
- .gitignore
|
44
|
+
- Gemfile
|
45
|
+
- Rakefile
|
46
|
+
- lib/pagoda-tunnel.rb
|
47
|
+
- pagoda-tunnel.gemspec
|
48
|
+
- spec/tunnel_spec.rb
|
49
|
+
homepage: http://www.pagodabox.com
|
50
|
+
licenses: []
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project: pagoda-tunnel
|
69
|
+
rubygems_version: 1.8.10
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: Pagodabox Tunnel gem
|
73
|
+
test_files:
|
74
|
+
- spec/tunnel_spec.rb
|