costan-rtunnel 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +13 -0
- data/LICENSE +21 -0
- data/Manifest +49 -0
- data/README.markdown +84 -0
- data/Rakefile +45 -0
- data/bin/rtunnel_client +4 -0
- data/bin/rtunnel_server +4 -0
- data/lib/rtunnel.rb +20 -0
- data/lib/rtunnel/client.rb +308 -0
- data/lib/rtunnel/command_processor.rb +62 -0
- data/lib/rtunnel/command_protocol.rb +50 -0
- data/lib/rtunnel/commands.rb +233 -0
- data/lib/rtunnel/connection_id.rb +24 -0
- data/lib/rtunnel/core.rb +58 -0
- data/lib/rtunnel/crypto.rb +106 -0
- data/lib/rtunnel/frame_protocol.rb +34 -0
- data/lib/rtunnel/io_extensions.rb +54 -0
- data/lib/rtunnel/leak.rb +35 -0
- data/lib/rtunnel/rtunnel_client_cmd.rb +41 -0
- data/lib/rtunnel/rtunnel_server_cmd.rb +32 -0
- data/lib/rtunnel/server.rb +351 -0
- data/lib/rtunnel/socket_factory.rb +119 -0
- data/spec/client_spec.rb +47 -0
- data/spec/cmds_spec.rb +127 -0
- data/spec/integration_spec.rb +105 -0
- data/spec/server_spec.rb +21 -0
- data/spec/spec_helper.rb +3 -0
- data/test/command_stubs.rb +77 -0
- data/test/protocol_mocks.rb +43 -0
- data/test/scenario_connection.rb +109 -0
- data/test/test_client.rb +48 -0
- data/test/test_command_protocol.rb +82 -0
- data/test/test_commands.rb +49 -0
- data/test/test_connection_id.rb +30 -0
- data/test/test_crypto.rb +127 -0
- data/test/test_frame_protocol.rb +109 -0
- data/test/test_io_extensions.rb +70 -0
- data/test/test_server.rb +70 -0
- data/test/test_socket_factory.rb +42 -0
- data/test/test_tunnel.rb +186 -0
- data/test_data/authorized_keys2 +4 -0
- data/test_data/known_hosts +4 -0
- data/test_data/random_rsa_key +27 -0
- data/test_data/ssh_host_dsa_key +12 -0
- data/test_data/ssh_host_rsa_key +27 -0
- data/tests/_ab_test.rb +16 -0
- data/tests/_stress_test.rb +96 -0
- data/tests/lo_http_server.rb +55 -0
- metadata +121 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module RTunnel::SocketFactory
|
4
|
+
def self.split_address(address)
|
5
|
+
port_index = address.index /[^:]\:[^:]/
|
6
|
+
if port_index
|
7
|
+
[address[0, port_index + 1], address[port_index + 2, address.length]]
|
8
|
+
else
|
9
|
+
[address, nil]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.host_from_address(address)
|
14
|
+
address and split_address(address)[0]
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.port_from_address(address)
|
18
|
+
address and (port_string = split_address(address)[1]) and port_string.to_i
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.inbound?(options)
|
22
|
+
options[:inbound] or [:in_port, :in_host, :in_addr].any? { |k| options[k] }
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.bind_host(options)
|
26
|
+
options[:in_host] or host_from_address(options[:in_addr]) or '0.0.0.0'
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.bind_port(options)
|
30
|
+
options[:in_port] or port_from_address(options[:in_addr]) or 0
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.bind_socket_address(options)
|
34
|
+
Socket::pack_sockaddr_in bind_port(options), bind_host(options)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.connect_host(options)
|
38
|
+
options[:out_host] or host_from_address(options[:out_addr])
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.connect_port(options)
|
42
|
+
options[:out_port] or port_from_address(options[:out_addr])
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.connect_socket_address(options)
|
46
|
+
Socket::pack_sockaddr_in connect_port(options), connect_host(options)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.tcp?(options)
|
50
|
+
options[:tcp] or !options[:udp]
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.new_tcp_socket
|
54
|
+
Socket.new Socket::AF_INET, Socket::SOCK_STREAM, Socket::PF_UNSPEC
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.new_udp_socket
|
58
|
+
Socket.new Socket::AF_INET, Socket::SOCK_DGRAM, Socket::PF_UNSPEC
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.new_socket(options)
|
62
|
+
tcp?(options) ? new_tcp_socket : new_udp_socket
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.bind(socket, options)
|
66
|
+
socket.bind bind_socket_address(options)
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.connect(socket, options)
|
70
|
+
socket.connect connect_socket_address(options)
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.set_options(socket, options)
|
74
|
+
if options[:no_delay]
|
75
|
+
socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true
|
76
|
+
socket.sync = true
|
77
|
+
end
|
78
|
+
|
79
|
+
if options[:reuse_addr]
|
80
|
+
socket.setsockopt Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true
|
81
|
+
end
|
82
|
+
|
83
|
+
unless options[:reverse_lookup]
|
84
|
+
if socket.respond_to? :do_not_reverse_lookup
|
85
|
+
socket.do_not_reverse_lookup = true
|
86
|
+
else
|
87
|
+
# work around until the patch below actually gets committed:
|
88
|
+
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/2346
|
89
|
+
BasicSocket.do_not_reverse_lookup = true
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# new sockets coming out of socket.accept will have the given options set
|
95
|
+
def self.set_options_on_accept_sockets(socket, options)
|
96
|
+
socket.instance_variable_set :@rtunnel_factory_options, options
|
97
|
+
def socket.accept(*args)
|
98
|
+
sock, addr = super
|
99
|
+
RTunnel::SocketFactory.set_options sock, @rtunnel_factory_options
|
100
|
+
return sock, addr
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.socket(options = {})
|
105
|
+
s = new_socket options
|
106
|
+
set_options s, options
|
107
|
+
if inbound? options
|
108
|
+
bind s, options
|
109
|
+
set_options_on_accept_sockets s, options
|
110
|
+
else
|
111
|
+
connect s, options
|
112
|
+
end
|
113
|
+
s
|
114
|
+
end
|
115
|
+
|
116
|
+
def socket(options = {})
|
117
|
+
RTunnel::SocketFactory.socket(options)
|
118
|
+
end
|
119
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
require 'client'
|
4
|
+
|
5
|
+
include RTunnel
|
6
|
+
describe RTunnel::Client, "addresses" do
|
7
|
+
def o(opts)
|
8
|
+
{:control_address => 'x.com', :remote_listen_address => '5555', :tunnel_to_address => '6666'}.merge opts
|
9
|
+
end
|
10
|
+
|
11
|
+
before :all do
|
12
|
+
String.class_eval do
|
13
|
+
alias_method :orig_replace_with_ip!, :replace_with_ip!
|
14
|
+
define_method :replace_with_ip! do
|
15
|
+
self
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
after :all do
|
21
|
+
String.class_eval do
|
22
|
+
alias_method :replace_with_ip!, :orig_replace_with_ip!
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should use default control port if not specified" do
|
27
|
+
Client.new(o :control_address => 'asdf.net').
|
28
|
+
instance_eval { @control_address }.should == "asdf.net:#{DEFAULT_CONTROL_PORT}"
|
29
|
+
|
30
|
+
Client.new(o :control_address => 'asdf.net:1234').
|
31
|
+
instance_eval { @control_address }.should == "asdf.net:1234"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should use 0.0.0.0 for remote listen host if not specified" do
|
35
|
+
Client.new(o :control_address => 'asdf.net:1234', :remote_listen_address => '8888').
|
36
|
+
instance_eval { @remote_listen_address }.should == '0.0.0.0:8888'
|
37
|
+
|
38
|
+
Client.new(o :control_address => 'asdf.net:1234', :remote_listen_address => 'ip2.asdf.net:8888').
|
39
|
+
instance_eval { @remote_listen_address }.should == 'ip2.asdf.net:8888'
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should use localhost for tunnel to address if not specified" do
|
43
|
+
Client.new(o :tunnel_to_address => '5555').
|
44
|
+
instance_eval { @tunnel_to_address }.should == 'localhost:5555'
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
data/spec/cmds_spec.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
require 'cmds'
|
4
|
+
|
5
|
+
include RTunnel
|
6
|
+
|
7
|
+
describe RTunnel::CreateConnectionCommand do
|
8
|
+
it "should be able to serialize and parse itself" do
|
9
|
+
serialized = CreateConnectionCommand.new("id").to_s
|
10
|
+
|
11
|
+
cmd = Command.parse(serialized)
|
12
|
+
cmd.class.should == CreateConnectionCommand
|
13
|
+
cmd.conn_id.should == "id"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should be able to match itself and remove itself from the stream" do
|
17
|
+
serialized = CreateConnectionCommand.new("abcbdefg").to_s
|
18
|
+
|
19
|
+
Command.match(serialized).should == true
|
20
|
+
Command.parse(serialized)
|
21
|
+
serialized.should be_empty
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe RTunnel::SendDataCommand do
|
26
|
+
it "should be able to serialzied and parse itself" do
|
27
|
+
serialized = SendDataCommand.new("id", "here is some data").to_s
|
28
|
+
|
29
|
+
cmd = Command.parse(serialized)
|
30
|
+
cmd.class.should == SendDataCommand
|
31
|
+
cmd.conn_id.should == "id"
|
32
|
+
cmd.data.should == "here is some data"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should be able to match itself and remove itself from the stream" do
|
36
|
+
serialized = SendDataCommand.new("abcbdefg", "and here is some data").to_s
|
37
|
+
|
38
|
+
serialized << "WAY MORE CRAP DATA!!!"
|
39
|
+
|
40
|
+
Command.match(serialized).should == true
|
41
|
+
Command.parse(serialized)
|
42
|
+
serialized.should == "WAY MORE CRAP DATA!!!"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe RTunnel::CloseConnectionCommand do
|
47
|
+
it "should be able to serialize and parse itself" do
|
48
|
+
serialized = CloseConnectionCommand.new("id").to_s
|
49
|
+
|
50
|
+
cmd = Command.parse(serialized)
|
51
|
+
cmd.class.should == CloseConnectionCommand
|
52
|
+
cmd.conn_id.should == "id"
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should be able to match itself and remove itself from the stream" do
|
56
|
+
serialized = CloseConnectionCommand.new("abcbdefg").to_s
|
57
|
+
|
58
|
+
Command.match(serialized).should == true
|
59
|
+
Command.parse(serialized)
|
60
|
+
serialized.should be_empty
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe RTunnel::PingCommand do
|
65
|
+
it "should be able to serialize and parse itself" do
|
66
|
+
serialized = PingCommand.new.to_s
|
67
|
+
|
68
|
+
cmd = Command.parse(serialized)
|
69
|
+
cmd.class.should == PingCommand
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should be able to match itself and remove itself from the stream" do
|
73
|
+
serialized = PingCommand.new.to_s
|
74
|
+
|
75
|
+
Command.match(serialized).should == true
|
76
|
+
Command.parse(serialized)
|
77
|
+
serialized.should be_empty
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
describe RTunnel::RemoteListenCommand do
|
83
|
+
it "should be able to serialize and parse itself" do
|
84
|
+
serialized = RemoteListenCommand.new("0.0.0.0:1234").to_s
|
85
|
+
|
86
|
+
cmd = Command.parse(serialized)
|
87
|
+
cmd.class.should == RemoteListenCommand
|
88
|
+
cmd.address.should == "0.0.0.0:1234"
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should be able to match itself and remove itself from the stream" do
|
92
|
+
serialized = RemoteListenCommand.new("0.0.0.0:1234").to_s
|
93
|
+
|
94
|
+
Command.match(serialized).should == true
|
95
|
+
Command.parse(serialized)
|
96
|
+
serialized.should be_empty
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
describe RTunnel::Command do
|
102
|
+
it "should be able to match a command in a stream" do
|
103
|
+
Command.match("C1234abc|").should == true
|
104
|
+
Command.match("C1234abc").should == false
|
105
|
+
Command.match("C1234abc|C|").should == true
|
106
|
+
|
107
|
+
Command.match("Did|15|DATA").should == false
|
108
|
+
Command.match("Did|1|DATA").should == true
|
109
|
+
Command.match("Did|4|\0\0\0\0").should == true
|
110
|
+
|
111
|
+
data = "C1234abc|D1234abc|15|here is my dataX1234abc|L0.0.0.0:1234|CASDF"
|
112
|
+
cmd1 = Command.parse(data)
|
113
|
+
cmd2 = Command.parse(data)
|
114
|
+
cmd3 = Command.parse(data)
|
115
|
+
cmd4 = Command.parse(data)
|
116
|
+
cmd1.class.should == CreateConnectionCommand
|
117
|
+
cmd1.conn_id.should == "1234abc"
|
118
|
+
cmd2.class.should == SendDataCommand
|
119
|
+
cmd2.conn_id.should == "1234abc"
|
120
|
+
cmd3.class.should == CloseConnectionCommand
|
121
|
+
cmd3.conn_id.should == "1234abc"
|
122
|
+
cmd4.class.should == RemoteListenCommand
|
123
|
+
cmd4.address.should == "0.0.0.0:1234"
|
124
|
+
|
125
|
+
Command.match(data).should == false
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
require 'client'
|
4
|
+
require 'server'
|
5
|
+
|
6
|
+
describe "RTunnel" do
|
7
|
+
class TextServer < GServer
|
8
|
+
def initialize(port, text)
|
9
|
+
@text = text
|
10
|
+
super(port)
|
11
|
+
end
|
12
|
+
|
13
|
+
def serve(io)
|
14
|
+
io.write(@text)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def read_from_address(addr)
|
19
|
+
timeout(2) { TCPSocket.open(*addr.split(/:/)) {|s| s.read } }
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should work!" do
|
23
|
+
begin
|
24
|
+
server = RTunnel::Server.new(:control_address => 'localhost:9999')
|
25
|
+
client = RTunnel::Client.new(:control_address => 'localhost:9999', :remote_listen_address => '30002', :tunnel_to_address => '30003')
|
26
|
+
|
27
|
+
server.start
|
28
|
+
client.start
|
29
|
+
|
30
|
+
s = TextServer.new(30003, echo_text = "tunnel this txt plz!")
|
31
|
+
s.start
|
32
|
+
|
33
|
+
sleep 0.5
|
34
|
+
|
35
|
+
# direct connect (sanity check)
|
36
|
+
read_from_address('localhost:30003').should == echo_text
|
37
|
+
# tunneled connect
|
38
|
+
read_from_address('localhost:30002').should == echo_text
|
39
|
+
ensure
|
40
|
+
begin
|
41
|
+
client.stop
|
42
|
+
server.stop
|
43
|
+
s.stop
|
44
|
+
rescue
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should ping all clients periodically" do
|
50
|
+
begin
|
51
|
+
server = RTunnel::Server.new(:control_address => 'localhost:9999', :ping_interval => 0.2)
|
52
|
+
clients = []
|
53
|
+
clients << RTunnel::Client.new(:control_address => 'localhost:9999', :remote_listen_address => '30002', :tunnel_to_address => '30003')
|
54
|
+
clients << RTunnel::Client.new(:control_address => 'localhost:9999', :remote_listen_address => '30012', :tunnel_to_address => '30013')
|
55
|
+
server.start
|
56
|
+
clients.each{|c|c.start}
|
57
|
+
|
58
|
+
pings = Hash.new {|h,k| h[k] = [] }
|
59
|
+
t = Thread.new do
|
60
|
+
loop do
|
61
|
+
clients.each do |client|
|
62
|
+
pings[client] << client.instance_eval { @last_ping }
|
63
|
+
end
|
64
|
+
sleep 0.05
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
sleep 2
|
69
|
+
|
70
|
+
clients.each do |client|
|
71
|
+
# 2 seconds, 0.2 pings a sec = ~10 pings
|
72
|
+
(9..11).should include(pings[client].uniq.size)
|
73
|
+
end
|
74
|
+
ensure
|
75
|
+
t.kill
|
76
|
+
begin
|
77
|
+
clients.each{|c|c.stop}
|
78
|
+
server.stop
|
79
|
+
rescue
|
80
|
+
p $!,$@
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it "the client shouldnt fail even if there is no server running at the tunnel_to address" do
|
86
|
+
begin
|
87
|
+
server = RTunnel::Server.new(:control_address => 'localhost:9999')
|
88
|
+
client = RTunnel::Client.new(:control_address => 'localhost:9999', :remote_listen_address => '30002', :tunnel_to_address => '30003')
|
89
|
+
|
90
|
+
server.start
|
91
|
+
client.start
|
92
|
+
|
93
|
+
sleep 0.5
|
94
|
+
|
95
|
+
# tunneled connect
|
96
|
+
read_from_address('localhost:30002').should be_empty
|
97
|
+
ensure
|
98
|
+
begin
|
99
|
+
client.stop
|
100
|
+
server.stop
|
101
|
+
rescue
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/spec/server_spec.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
require 'server'
|
4
|
+
|
5
|
+
include RTunnel
|
6
|
+
describe RTunnel::Server, "addresses" do
|
7
|
+
it "control address should listen on all interfaces and use default control port if not specified" do
|
8
|
+
Server.new(:control_address => nil).
|
9
|
+
instance_eval { @control_address }.should == "0.0.0.0:#{DEFAULT_CONTROL_PORT}"
|
10
|
+
|
11
|
+
Server.new(:control_address => '5555').
|
12
|
+
instance_eval { @control_address }.should == "0.0.0.0:5555"
|
13
|
+
|
14
|
+
Server.new(:control_address => 'interface2').
|
15
|
+
instance_eval { @control_address }.should == "interface2:#{DEFAULT_CONTROL_PORT}"
|
16
|
+
|
17
|
+
Server.new(:control_address => 'interface2:2222').
|
18
|
+
instance_eval { @control_address }.should == "interface2:2222"
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# Contains generate_ and verify_ names for all RTunnel commands.
|
2
|
+
module CommandStubs
|
3
|
+
@@test_id1 = "1029384756ALSKDJFH"
|
4
|
+
@@test_id2 = "ALSKDJFH1029384756"
|
5
|
+
@@test_address = "192.168.43.95"
|
6
|
+
@@data = (0..255).to_a.pack('C*')
|
7
|
+
@@ekey = (128...192).to_a.pack('C*') * 8
|
8
|
+
@@pubfp = (0...128).to_a.pack('C*') * 5
|
9
|
+
|
10
|
+
def generate_keep_alive
|
11
|
+
RTunnel::KeepAliveCommand.new
|
12
|
+
end
|
13
|
+
def verify_keep_alive(cmd)
|
14
|
+
assert_equal RTunnel::KeepAliveCommand, cmd.class
|
15
|
+
end
|
16
|
+
|
17
|
+
def generate_create
|
18
|
+
RTunnel::CreateConnectionCommand.new @@test_id1
|
19
|
+
end
|
20
|
+
def verify_create(cmd)
|
21
|
+
assert_equal RTunnel::CreateConnectionCommand, cmd.class
|
22
|
+
assert_equal @@test_id1, cmd.connection_id
|
23
|
+
end
|
24
|
+
|
25
|
+
def generate_close
|
26
|
+
RTunnel::CloseConnectionCommand.new @@test_id2
|
27
|
+
end
|
28
|
+
def verify_close(cmd)
|
29
|
+
assert_equal RTunnel::CloseConnectionCommand, cmd.class
|
30
|
+
assert_equal @@test_id2, cmd.connection_id
|
31
|
+
end
|
32
|
+
|
33
|
+
def generate_listen
|
34
|
+
RTunnel::RemoteListenCommand.new @@test_address
|
35
|
+
end
|
36
|
+
def verify_listen(cmd)
|
37
|
+
assert_equal RTunnel::RemoteListenCommand, cmd.class
|
38
|
+
assert_equal @@test_address, cmd.address
|
39
|
+
end
|
40
|
+
|
41
|
+
def generate_send
|
42
|
+
RTunnel::SendDataCommand.new @@test_id1, @@data
|
43
|
+
end
|
44
|
+
def verify_send(cmd)
|
45
|
+
assert_equal RTunnel::SendDataCommand, cmd.class
|
46
|
+
assert_equal @@test_id1, cmd.connection_id
|
47
|
+
assert_equal @@data, cmd.data
|
48
|
+
end
|
49
|
+
|
50
|
+
def generate_set_sk
|
51
|
+
RTunnel::SetSessionKeyCommand.new @@ekey
|
52
|
+
end
|
53
|
+
def verify_set_sk(cmd)
|
54
|
+
assert_equal RTunnel::SetSessionKeyCommand, cmd.class
|
55
|
+
assert_equal @@ekey, cmd.encrypted_keys
|
56
|
+
end
|
57
|
+
|
58
|
+
def generate_gen_sk
|
59
|
+
RTunnel::GenerateSessionKeyCommand.new @@pubfp
|
60
|
+
end
|
61
|
+
def verify_gen_sk(cmd)
|
62
|
+
assert_equal RTunnel::GenerateSessionKeyCommand, cmd.class
|
63
|
+
assert_equal @@pubfp, cmd.public_key_fp
|
64
|
+
end
|
65
|
+
|
66
|
+
# An array with the names of all commands.
|
67
|
+
# Use these names to obtain the names of the genrate_ and verify_ methods.
|
68
|
+
def self.command_names
|
69
|
+
[:keep_alive, :create, :close, :listen, :send, :gen_sk, :set_sk]
|
70
|
+
end
|
71
|
+
|
72
|
+
# A sequence of command names useful for testing "real" connections.
|
73
|
+
def self.command_test_sequence
|
74
|
+
[:create, :keep_alive, :gen_sk, :set_sk, :keep_alive, :listen, :keep_alive,
|
75
|
+
:send, :send, :keep_alive, :keep_alive, :send, :close]
|
76
|
+
end
|
77
|
+
end
|