costan-rtunnel 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.
- 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
|