reverse-tunnel 0.0.1

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.
@@ -0,0 +1,3 @@
1
+ module ReverseTunnel
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'reverse-tunnel/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "reverse-tunnel"
8
+ gem.version = ReverseTunnel::VERSION
9
+ gem.authors = ["Alban Peignier", "Florent Peyraud"]
10
+ gem.email = ["alban@tryphon.eu", "florent@tryphon.eu"]
11
+ gem.description = %q{Create easily a tunnel to forward connection (like a ssh) to the client host}
12
+ gem.summary = %q{Forward a tcp connection to client host}
13
+ gem.homepage = "http://projects.tryphon.eu/projects/reverse-tunnel"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_runtime_dependency "eventmachine"
21
+ gem.add_runtime_dependency "msgpack"
22
+ gem.add_runtime_dependency "eventmachine_httpserver"
23
+ gem.add_runtime_dependency "json"
24
+ gem.add_runtime_dependency "trollop"
25
+ gem.add_runtime_dependency "SyslogLogger"
26
+
27
+ gem.add_development_dependency "simplecov"
28
+ gem.add_development_dependency "rspec"
29
+ gem.add_development_dependency "guard"
30
+ gem.add_development_dependency "guard-rspec"
31
+ gem.add_development_dependency "rake"
32
+ gem.add_development_dependency "rest-client"
33
+ end
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+
3
+ describe ReverseTunnel::CLI do
4
+
5
+ describe "#debug=" do
6
+
7
+ context "when true" do
8
+ it "should change Logger level to debug" do
9
+ ReverseTunnel.logger.level = Logger::INFO
10
+ lambda {
11
+ subject.debug = true
12
+ }.should change(ReverseTunnel.logger, :level).to(Logger::DEBUG)
13
+ end
14
+ end
15
+
16
+ context "when false" do
17
+ it "should change Logger level to info" do
18
+ ReverseTunnel.logger.level = Logger::DEBUG
19
+ lambda {
20
+ subject.debug = false
21
+ }.should change(ReverseTunnel.logger, :level).to(Logger::INFO)
22
+ end
23
+ end
24
+
25
+ after do
26
+ ReverseTunnel.reset_logger!
27
+ end
28
+
29
+ end
30
+
31
+ describe "#syslog=" do
32
+
33
+ context "when true" do
34
+
35
+ it "should change ReverseTunnel.logger to Syslog::Logger" do
36
+ subject.syslog = true
37
+ ReverseTunnel.logger.should be_instance_of(Syslog::Logger)
38
+ end
39
+
40
+ after do
41
+ ReverseTunnel.reset_logger!
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+
48
+
49
+
50
+
51
+
52
+ end
53
+
54
+
55
+ describe ReverseTunnel::CLI::Configurator do
56
+
57
+ describe "#server=" do
58
+
59
+ it "should parse ip and port" do
60
+ subject.should_receive(:server_host=).with("host")
61
+ subject.should_receive(:server_port=).with(4893)
62
+
63
+ subject.server = "host:4893"
64
+ end
65
+
66
+ end
67
+
68
+ end
69
+
70
+ describe ReverseTunnel::CLI::Client do
71
+
72
+ describe "#api=" do
73
+
74
+ it "should parse ip and port" do
75
+ subject.should_receive(:api_host=).with("host")
76
+ subject.should_receive(:api_port=).with(4895)
77
+
78
+ subject.api = "host:4895"
79
+ end
80
+
81
+ end
82
+
83
+ describe "#token" do
84
+
85
+ it "should use first argument" do
86
+ subject.stub :arguments => [ "token"]
87
+ subject.token.should == "token"
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+
94
+ describe ReverseTunnel::CLI::Server do
95
+
96
+ describe "#api=" do
97
+
98
+ it "should parse ip and port" do
99
+ subject.should_receive(:api_host=).with("host")
100
+ subject.should_receive(:api_port=).with(4894)
101
+
102
+ subject.api = "host:4894"
103
+ end
104
+
105
+ end
106
+
107
+ describe "#local=" do
108
+
109
+ it "should parse ip and port range" do
110
+ subject.should_receive(:local_host=).with("host")
111
+ subject.should_receive(:local_port_range=).with(123..456)
112
+
113
+ subject.local = "host:123-456"
114
+ end
115
+
116
+ end
117
+
118
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ require "rest_client"
4
+ require "json"
5
+
6
+ describe ReverseTunnel::Client::ApiServer do
7
+
8
+ let(:tunnel) { mock :to_json => '{"token":"1008B1A077343ED8B7AAAC9BC580","local_port":22,"server_host":"localhost","server_port":4893,"local_connections":[],"connection":{"created_at":"2012-12-27 12:13:50 +0100"}}' }
9
+
10
+ let(:api_host) { "127.0.0.1" }
11
+ let(:api_port) { 38589 }
12
+
13
+ def url(path)
14
+ "http://#{api_host}:#{api_port}#{path}"
15
+ end
16
+
17
+ def get(path)
18
+ JSON.parse RestClient.get url(path)
19
+ end
20
+
21
+ def wait_api
22
+ 5.times do
23
+ begin
24
+ s = TCPSocket.new(api_host, api_port)
25
+ s.close
26
+ return true
27
+ rescue Errno::ECONNREFUSED
28
+ sleep 0.1
29
+ end
30
+ end
31
+ end
32
+
33
+ def wait_api_stopped
34
+ 5.times do
35
+ begin
36
+ s = TCPSocket.new(api_host, api_port)
37
+ s.close
38
+ sleep 0.1
39
+ rescue Errno::ECONNREFUSED
40
+ return true
41
+ end
42
+ end
43
+ end
44
+
45
+ before do
46
+ Thread.new do
47
+ EventMachine.run do
48
+ EventMachine.start_server api_host, api_port, ReverseTunnel::Client::ApiServer, tunnel
49
+ end
50
+ end
51
+
52
+ wait_api
53
+ end
54
+
55
+ describe "GET '/status'" do
56
+
57
+ it "should return tunnel description" do
58
+ get("/status").should == JSON.parse(tunnel.to_json)
59
+ end
60
+
61
+ it "should accept requests on /tunnels.json" do
62
+ get("/status.json").should == get("/status")
63
+ end
64
+
65
+ end
66
+
67
+ after do
68
+ EventMachine.stop
69
+ wait_api_stopped
70
+ end
71
+
72
+ end
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe ReverseTunnel::Client do
4
+
5
+ describe "#server_host" do
6
+
7
+ it "should be nil by default" do
8
+ subject.server_host.should be_nil
9
+ end
10
+
11
+ end
12
+
13
+ describe "#server_port" do
14
+
15
+ it "should be 4893 by default" do
16
+ subject.server_port.should == 4893
17
+ end
18
+
19
+ end
20
+
21
+ describe "#local_port" do
22
+
23
+ it "should be 22 by default" do
24
+ subject.local_port.should == 22
25
+ end
26
+
27
+ end
28
+
29
+ describe "#api_host" do
30
+
31
+ it "should be nil by default" do
32
+ subject.api_host.should be_nil
33
+ end
34
+
35
+ end
36
+
37
+ describe "#api_port" do
38
+
39
+ it "should be 4895 by default" do
40
+ subject.api_port.should == 4895
41
+ end
42
+
43
+ end
44
+
45
+ describe "#tunnel" do
46
+ it "should use server_host" do
47
+ subject.server_host = "localhost"
48
+ subject.tunnel.host.should == "localhost"
49
+ end
50
+
51
+ it "should use server_port" do
52
+ subject.server_port = 123
53
+ subject.tunnel.port.should == 123
54
+ end
55
+
56
+ it "should use local_port" do
57
+ subject.local_port = 123
58
+ subject.tunnel.local_port.should == 123
59
+ end
60
+ end
61
+
62
+ describe "#start_api" do
63
+ it "should use api_host and api_port" do
64
+ subject.api_host = "localhost"
65
+ subject.api_port = 123
66
+
67
+ EventMachine.should_receive(:start_server).with("localhost", 123, anything, anything)
68
+ subject.start_api
69
+ end
70
+
71
+ it "should not start api if api_host is not defined" do
72
+ subject.api_host = nil
73
+
74
+ EventMachine.should_not_receive(:start_server)
75
+ subject.start_api
76
+ end
77
+ end
78
+
79
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe Message do
4
+
5
+ end
6
+
7
+ describe Message::Data do
8
+ subject { Message::Data.new(123, "dummy") }
9
+
10
+ its(:type) { should == :data }
11
+
12
+ it { should be_data }
13
+
14
+ it "should have the same session_id after pack/unpack" do
15
+ Message.unpack(subject.pack).session_id.should == subject.session_id
16
+ end
17
+
18
+ it "should have the same data after pack/unpack" do
19
+ Message.unpack(subject.pack).data.should == subject.data
20
+ end
21
+ end
22
+
23
+ describe Message::OpenSession do
24
+ its(:type) { should == :open_session }
25
+
26
+ it { should be_open_session }
27
+
28
+ it "should have the same session_id after pack/unpack" do
29
+ subject.session_id = 123
30
+ Message.unpack(subject.pack).session_id.should == subject.session_id
31
+ end
32
+ end
33
+
34
+ describe Message::OpenTunnel do
35
+ its(:type) { should == :open_tunnel }
36
+
37
+ it { should be_open_tunnel }
38
+
39
+ it "should have the same token after pack/unpack" do
40
+ subject.token = 123
41
+ Message.unpack(subject.pack).token.should == subject.token
42
+ end
43
+ end
44
+
45
+ describe Message::Ping do
46
+ its(:type) { should == :ping }
47
+
48
+ it { should be_ping }
49
+
50
+ it "should have the same sequence_number after pack/unpack" do
51
+ subject.sequence_number = 123
52
+ Message.unpack(subject.pack).sequence_number.should == subject.sequence_number
53
+ end
54
+ end
55
+
@@ -0,0 +1,125 @@
1
+ require 'spec_helper'
2
+
3
+ require "rest_client"
4
+ require "json"
5
+
6
+ describe ReverseTunnel::Server::ApiServer do
7
+
8
+ let(:server) { ReverseTunnel::Server.new }
9
+
10
+ let(:api_host) { "127.0.0.1" }
11
+ let(:api_port) { 38589 }
12
+
13
+ def url(path)
14
+ "http://#{api_host}:#{api_port}#{path}"
15
+ end
16
+
17
+ def get(path)
18
+ JSON.parse RestClient.get url(path)
19
+ end
20
+
21
+ def post(path, params)
22
+ JSON.parse RestClient.post url(path), params.to_json
23
+ end
24
+
25
+ def delete(path)
26
+ JSON.parse RestClient.delete url(path)
27
+ end
28
+
29
+ def wait_api
30
+ 5.times do
31
+ begin
32
+ s = TCPSocket.new(api_host, api_port)
33
+ s.close
34
+ return true
35
+ rescue Errno::ECONNREFUSED
36
+ sleep 0.1
37
+ end
38
+ end
39
+ end
40
+
41
+ def wait_api_stopped
42
+ 5.times do
43
+ begin
44
+ s = TCPSocket.new(api_host, api_port)
45
+ s.close
46
+ sleep 0.1
47
+ rescue Errno::ECONNREFUSED
48
+ return true
49
+ end
50
+ end
51
+ end
52
+
53
+ before do
54
+ Thread.new do
55
+ EventMachine.run do
56
+ EventMachine.start_server api_host, api_port, ReverseTunnel::Server::ApiServer, server
57
+ end
58
+ end
59
+
60
+ wait_api
61
+ end
62
+
63
+ describe "GET '/tunnels'" do
64
+
65
+ it "should return an empty array without tunnels" do
66
+ get("/tunnels").should be_empty
67
+ end
68
+
69
+ it "should return tunnels description" do
70
+ tunnel = server.tunnels.create
71
+ get("/tunnels").should include("token" => tunnel.token, "local_port" => tunnel.local_port)
72
+ end
73
+
74
+ it "should accept requests on /tunnels.json" do
75
+ get("/tunnels.json").should == get("/tunnels")
76
+ end
77
+
78
+ end
79
+
80
+ describe "POST '/tunnels'" do
81
+
82
+ it "should create a new tunnel" do
83
+ post("/tunnels", :token => "dummy")
84
+ server.tunnels.find("dummy").should_not be_nil
85
+ end
86
+
87
+ it "should return new tunnel description" do
88
+ post("/tunnels", :token => "dummy")["token"].should == "dummy"
89
+ end
90
+
91
+ end
92
+
93
+ describe "GET '/tunnels/:id'" do
94
+
95
+ it "should return tunnel description" do
96
+ tunnel = server.tunnels.create
97
+ get("/tunnels/#{tunnel.token}")["local_port"].should == tunnel.local_port
98
+ end
99
+
100
+ it "should return a 404 when tunnel doesn't exist" do
101
+ lambda { get("/tunnels/123") }.should raise_error(RestClient::ResourceNotFound)
102
+ end
103
+
104
+ end
105
+
106
+ describe "DELETE '/tunnels/:id'" do
107
+
108
+ it "should delete the specified tunnel" do
109
+ tunnel = server.tunnels.create
110
+ delete("/tunnels/#{tunnel.token}")
111
+ server.tunnels.find(tunnel.token).should be_nil
112
+ end
113
+
114
+ it "should return a 404 when tunnel doesn't exist" do
115
+ lambda { delete("/tunnels/123") }.should raise_error(RestClient::ResourceNotFound)
116
+ end
117
+
118
+ end
119
+
120
+ after do
121
+ EventMachine.stop
122
+ wait_api_stopped
123
+ end
124
+
125
+ end