hrr_rb_ssh 0.3.0.pre1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -3
  3. data/.travis.yml +1 -0
  4. data/README.md +208 -46
  5. data/demo/client.rb +71 -0
  6. data/demo/echo_server.rb +8 -3
  7. data/demo/more_flexible_auth.rb +105 -0
  8. data/demo/multi_step_auth.rb +99 -0
  9. data/demo/server.rb +10 -4
  10. data/demo/subsystem_echo_server.rb +8 -3
  11. data/hrr_rb_ssh.gemspec +6 -6
  12. data/lib/hrr_rb_ssh.rb +1 -1
  13. data/lib/hrr_rb_ssh/algorithm/publickey.rb +0 -1
  14. data/lib/hrr_rb_ssh/algorithm/publickey/ecdsa_sha2.rb +12 -9
  15. data/lib/hrr_rb_ssh/algorithm/publickey/ecdsa_sha2/ecdsa_signature_blob.rb +2 -4
  16. data/lib/hrr_rb_ssh/algorithm/publickey/ecdsa_sha2/public_key_blob.rb +2 -4
  17. data/lib/hrr_rb_ssh/algorithm/publickey/ecdsa_sha2/signature.rb +2 -4
  18. data/lib/hrr_rb_ssh/algorithm/publickey/ssh_dss.rb +10 -7
  19. data/lib/hrr_rb_ssh/algorithm/publickey/ssh_dss/public_key_blob.rb +2 -4
  20. data/lib/hrr_rb_ssh/algorithm/publickey/ssh_dss/signature.rb +2 -4
  21. data/lib/hrr_rb_ssh/algorithm/publickey/ssh_rsa.rb +9 -6
  22. data/lib/hrr_rb_ssh/algorithm/publickey/ssh_rsa/public_key_blob.rb +2 -4
  23. data/lib/hrr_rb_ssh/algorithm/publickey/ssh_rsa/signature.rb +2 -4
  24. data/lib/hrr_rb_ssh/authentication.rb +103 -22
  25. data/lib/hrr_rb_ssh/authentication/constant.rb +14 -0
  26. data/lib/hrr_rb_ssh/authentication/method/keyboard_interactive.rb +44 -7
  27. data/lib/hrr_rb_ssh/authentication/method/keyboard_interactive/context.rb +16 -9
  28. data/lib/hrr_rb_ssh/authentication/method/keyboard_interactive/info_request.rb +7 -6
  29. data/lib/hrr_rb_ssh/authentication/method/keyboard_interactive/info_response.rb +5 -2
  30. data/lib/hrr_rb_ssh/authentication/method/none.rb +23 -7
  31. data/lib/hrr_rb_ssh/authentication/method/none/context.rb +15 -7
  32. data/lib/hrr_rb_ssh/authentication/method/password.rb +28 -7
  33. data/lib/hrr_rb_ssh/authentication/method/password/context.rb +16 -7
  34. data/lib/hrr_rb_ssh/authentication/method/publickey.rb +63 -10
  35. data/lib/hrr_rb_ssh/authentication/method/publickey/algorithm.rb +0 -1
  36. data/lib/hrr_rb_ssh/authentication/method/publickey/algorithm/functionable.rb +32 -8
  37. data/lib/hrr_rb_ssh/authentication/method/publickey/algorithm/signature_blob.rb +2 -4
  38. data/lib/hrr_rb_ssh/authentication/method/publickey/context.rb +11 -2
  39. data/lib/hrr_rb_ssh/client.rb +234 -0
  40. data/lib/hrr_rb_ssh/codable.rb +15 -13
  41. data/lib/hrr_rb_ssh/compat/ruby.rb +0 -1
  42. data/lib/hrr_rb_ssh/connection.rb +145 -75
  43. data/lib/hrr_rb_ssh/connection/channel.rb +342 -109
  44. data/lib/hrr_rb_ssh/connection/channel/channel_type/direct_tcpip.rb +24 -19
  45. data/lib/hrr_rb_ssh/connection/channel/channel_type/forwarded_tcpip.rb +24 -19
  46. data/lib/hrr_rb_ssh/connection/channel/channel_type/session.rb +19 -12
  47. data/lib/hrr_rb_ssh/connection/channel/channel_type/session/proc_chain.rb +0 -2
  48. data/lib/hrr_rb_ssh/connection/channel/channel_type/session/proc_chain/chain_context.rb +0 -3
  49. data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/env.rb +2 -5
  50. data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/env/context.rb +5 -4
  51. data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/exec.rb +2 -5
  52. data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/exec/context.rb +5 -4
  53. data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/pty_req.rb +2 -5
  54. data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/pty_req/context.rb +5 -4
  55. data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/shell.rb +2 -5
  56. data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/shell/context.rb +5 -4
  57. data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/subsystem.rb +2 -5
  58. data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/subsystem/context.rb +5 -4
  59. data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/window_change.rb +2 -5
  60. data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/window_change/context.rb +5 -4
  61. data/lib/hrr_rb_ssh/connection/global_request_handler.rb +14 -12
  62. data/lib/hrr_rb_ssh/connection/request_handler.rb +1 -3
  63. data/lib/hrr_rb_ssh/connection/request_handler/reference_env_request_handler.rb +0 -2
  64. data/lib/hrr_rb_ssh/connection/request_handler/reference_exec_request_handler.rb +4 -6
  65. data/lib/hrr_rb_ssh/connection/request_handler/reference_pty_req_request_handler.rb +10 -12
  66. data/lib/hrr_rb_ssh/connection/request_handler/reference_shell_request_handler.rb +4 -6
  67. data/lib/hrr_rb_ssh/connection/request_handler/reference_window_change_request_handler.rb +0 -2
  68. data/lib/hrr_rb_ssh/error/closed_authentication.rb +1 -1
  69. data/lib/hrr_rb_ssh/error/closed_connection.rb +1 -1
  70. data/lib/hrr_rb_ssh/error/closed_transport.rb +1 -1
  71. data/lib/hrr_rb_ssh/loggable.rb +42 -0
  72. data/lib/hrr_rb_ssh/message/001_ssh_msg_disconnect.rb +2 -4
  73. data/lib/hrr_rb_ssh/message/002_ssh_msg_ignore.rb +2 -4
  74. data/lib/hrr_rb_ssh/message/003_ssh_msg_unimplemented.rb +2 -4
  75. data/lib/hrr_rb_ssh/message/004_ssh_msg_debug.rb +2 -4
  76. data/lib/hrr_rb_ssh/message/005_ssh_msg_service_request.rb +2 -4
  77. data/lib/hrr_rb_ssh/message/006_ssh_msg_service_accept.rb +2 -4
  78. data/lib/hrr_rb_ssh/message/020_ssh_msg_kexinit.rb +2 -4
  79. data/lib/hrr_rb_ssh/message/021_ssh_msg_newkeys.rb +2 -4
  80. data/lib/hrr_rb_ssh/message/030_ssh_msg_kex_dh_gex_request_old.rb +2 -4
  81. data/lib/hrr_rb_ssh/message/030_ssh_msg_kexdh_init.rb +2 -4
  82. data/lib/hrr_rb_ssh/message/030_ssh_msg_kexecdh_init.rb +2 -4
  83. data/lib/hrr_rb_ssh/message/031_ssh_msg_kex_dh_gex_group.rb +2 -4
  84. data/lib/hrr_rb_ssh/message/031_ssh_msg_kexdh_reply.rb +2 -4
  85. data/lib/hrr_rb_ssh/message/031_ssh_msg_kexecdh_reply.rb +2 -4
  86. data/lib/hrr_rb_ssh/message/032_ssh_msg_kex_dh_gex_init.rb +2 -4
  87. data/lib/hrr_rb_ssh/message/033_ssh_msg_kex_dh_gex_reply.rb +2 -4
  88. data/lib/hrr_rb_ssh/message/034_ssh_msg_kex_dh_gex_request.rb +2 -4
  89. data/lib/hrr_rb_ssh/message/050_ssh_msg_userauth_request.rb +2 -4
  90. data/lib/hrr_rb_ssh/message/051_ssh_msg_userauth_failure.rb +2 -4
  91. data/lib/hrr_rb_ssh/message/052_ssh_msg_userauth_success.rb +2 -4
  92. data/lib/hrr_rb_ssh/message/060_ssh_msg_userauth_info_request.rb +2 -4
  93. data/lib/hrr_rb_ssh/message/060_ssh_msg_userauth_pk_ok.rb +2 -4
  94. data/lib/hrr_rb_ssh/message/061_ssh_msg_userauth_info_response.rb +2 -4
  95. data/lib/hrr_rb_ssh/message/080_ssh_msg_global_request.rb +2 -4
  96. data/lib/hrr_rb_ssh/message/081_ssh_msg_request_success.rb +2 -4
  97. data/lib/hrr_rb_ssh/message/082_ssh_msg_request_failure.rb +2 -4
  98. data/lib/hrr_rb_ssh/message/090_ssh_msg_channel_open.rb +2 -4
  99. data/lib/hrr_rb_ssh/message/091_ssh_msg_channel_open_confirmation.rb +2 -4
  100. data/lib/hrr_rb_ssh/message/092_ssh_msg_channel_open_failure.rb +2 -4
  101. data/lib/hrr_rb_ssh/message/093_ssh_msg_channel_window_adjust.rb +2 -4
  102. data/lib/hrr_rb_ssh/message/094_ssh_msg_channel_data.rb +2 -4
  103. data/lib/hrr_rb_ssh/message/095_ssh_msg_channel_extended_data.rb +2 -4
  104. data/lib/hrr_rb_ssh/message/096_ssh_msg_channel_eof.rb +2 -4
  105. data/lib/hrr_rb_ssh/message/097_ssh_msg_channel_close.rb +2 -4
  106. data/lib/hrr_rb_ssh/message/098_ssh_msg_channel_request.rb +3 -5
  107. data/lib/hrr_rb_ssh/message/099_ssh_msg_channel_success.rb +2 -4
  108. data/lib/hrr_rb_ssh/message/100_ssh_msg_channel_failure.rb +2 -4
  109. data/lib/hrr_rb_ssh/server.rb +16 -10
  110. data/lib/hrr_rb_ssh/transport.rb +113 -77
  111. data/lib/hrr_rb_ssh/transport/compression_algorithm/functionable.rb +5 -3
  112. data/lib/hrr_rb_ssh/transport/compression_algorithm/unfunctionable.rb +5 -3
  113. data/lib/hrr_rb_ssh/transport/encryption_algorithm/functionable.rb +5 -3
  114. data/lib/hrr_rb_ssh/transport/encryption_algorithm/unfunctionable.rb +5 -3
  115. data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman.rb +43 -37
  116. data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman/h0.rb +2 -4
  117. data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman_group_exchange.rb +87 -52
  118. data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman_group_exchange/h0.rb +2 -4
  119. data/lib/hrr_rb_ssh/transport/kex_algorithm/elliptic_curve_diffie_hellman.rb +43 -37
  120. data/lib/hrr_rb_ssh/transport/kex_algorithm/elliptic_curve_diffie_hellman/h0.rb +2 -4
  121. data/lib/hrr_rb_ssh/transport/mac_algorithm/functionable.rb +5 -3
  122. data/lib/hrr_rb_ssh/transport/mac_algorithm/unfunctionable.rb +5 -3
  123. data/lib/hrr_rb_ssh/transport/receiver.rb +8 -7
  124. data/lib/hrr_rb_ssh/transport/sender.rb +5 -3
  125. data/lib/hrr_rb_ssh/transport/sequence_number.rb +0 -4
  126. data/lib/hrr_rb_ssh/transport/server_host_key_algorithm.rb +0 -1
  127. data/lib/hrr_rb_ssh/transport/server_host_key_algorithm/functionable.rb +5 -3
  128. data/lib/hrr_rb_ssh/version.rb +1 -1
  129. metadata +18 -51
  130. data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519.rb +0 -61
  131. data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/openssh_private_key.rb +0 -29
  132. data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/openssh_private_key_content.rb +0 -26
  133. data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/pkey.rb +0 -158
  134. data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/public_key_blob.rb +0 -23
  135. data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/signature.rb +0 -23
  136. data/lib/hrr_rb_ssh/authentication/method/publickey/algorithm/ssh_ed25519.rb +0 -21
  137. data/lib/hrr_rb_ssh/compat/ruby/array.rb +0 -14
  138. data/lib/hrr_rb_ssh/logger.rb +0 -56
  139. data/lib/hrr_rb_ssh/transport/server_host_key_algorithm/ssh_ed25519.rb +0 -20
@@ -6,10 +6,8 @@ require 'hrr_rb_ssh/codable'
6
6
 
7
7
  module HrrRbSsh
8
8
  module Message
9
- module SSH_MSG_CHANNEL_OPEN
10
- class << self
11
- include Codable
12
- end
9
+ class SSH_MSG_CHANNEL_OPEN
10
+ include Codable
13
11
 
14
12
  ID = self.name.split('::').last
15
13
  VALUE = 90
@@ -6,10 +6,8 @@ require 'hrr_rb_ssh/codable'
6
6
 
7
7
  module HrrRbSsh
8
8
  module Message
9
- module SSH_MSG_CHANNEL_OPEN_CONFIRMATION
10
- class << self
11
- include Codable
12
- end
9
+ class SSH_MSG_CHANNEL_OPEN_CONFIRMATION
10
+ include Codable
13
11
 
14
12
  ID = self.name.split('::').last
15
13
  VALUE = 91
@@ -6,7 +6,7 @@ require 'hrr_rb_ssh/codable'
6
6
 
7
7
  module HrrRbSsh
8
8
  module Message
9
- module SSH_MSG_CHANNEL_OPEN_FAILURE
9
+ class SSH_MSG_CHANNEL_OPEN_FAILURE
10
10
  module ReasonCode
11
11
  SSH_OPEN_ADMINISTRATIVELY_PROHIBITED = 1
12
12
  SSH_OPEN_CONNECT_FAILED = 2
@@ -14,9 +14,7 @@ module HrrRbSsh
14
14
  SSH_OPEN_RESOURCE_SHORTAGE = 4
15
15
  end
16
16
 
17
- class << self
18
- include Codable
19
- end
17
+ include Codable
20
18
 
21
19
  ID = self.name.split('::').last
22
20
  VALUE = 92
@@ -6,10 +6,8 @@ require 'hrr_rb_ssh/codable'
6
6
 
7
7
  module HrrRbSsh
8
8
  module Message
9
- module SSH_MSG_CHANNEL_WINDOW_ADJUST
10
- class << self
11
- include Codable
12
- end
9
+ class SSH_MSG_CHANNEL_WINDOW_ADJUST
10
+ include Codable
13
11
 
14
12
  ID = self.name.split('::').last
15
13
  VALUE = 93
@@ -6,10 +6,8 @@ require 'hrr_rb_ssh/codable'
6
6
 
7
7
  module HrrRbSsh
8
8
  module Message
9
- module SSH_MSG_CHANNEL_DATA
10
- class << self
11
- include Codable
12
- end
9
+ class SSH_MSG_CHANNEL_DATA
10
+ include Codable
13
11
 
14
12
  ID = self.name.split('::').last
15
13
  VALUE = 94
@@ -6,14 +6,12 @@ require 'hrr_rb_ssh/codable'
6
6
 
7
7
  module HrrRbSsh
8
8
  module Message
9
- module SSH_MSG_CHANNEL_EXTENDED_DATA
9
+ class SSH_MSG_CHANNEL_EXTENDED_DATA
10
10
  module DataTypeCode
11
11
  SSH_EXTENDED_DATA_STDERR = 1
12
12
  end
13
13
 
14
- class << self
15
- include Codable
16
- end
14
+ include Codable
17
15
 
18
16
  ID = self.name.split('::').last
19
17
  VALUE = 95
@@ -6,10 +6,8 @@ require 'hrr_rb_ssh/codable'
6
6
 
7
7
  module HrrRbSsh
8
8
  module Message
9
- module SSH_MSG_CHANNEL_EOF
10
- class << self
11
- include Codable
12
- end
9
+ class SSH_MSG_CHANNEL_EOF
10
+ include Codable
13
11
 
14
12
  ID = self.name.split('::').last
15
13
  VALUE = 96
@@ -6,10 +6,8 @@ require 'hrr_rb_ssh/codable'
6
6
 
7
7
  module HrrRbSsh
8
8
  module Message
9
- module SSH_MSG_CHANNEL_CLOSE
10
- class << self
11
- include Codable
12
- end
9
+ class SSH_MSG_CHANNEL_CLOSE
10
+ include Codable
13
11
 
14
12
  ID = self.name.split('::').last
15
13
  VALUE = 97
@@ -6,7 +6,7 @@ require 'hrr_rb_ssh/codable'
6
6
 
7
7
  module HrrRbSsh
8
8
  module Message
9
- module SSH_MSG_CHANNEL_REQUEST
9
+ class SSH_MSG_CHANNEL_REQUEST
10
10
  module SignalName
11
11
  ABRT = 'ABRT'
12
12
  ALRM = 'ALRM'
@@ -82,14 +82,12 @@ module HrrRbSsh
82
82
  TTY_OP_OSPEED = 129
83
83
  end
84
84
 
85
- class << self
86
- include Codable
87
- end
85
+ include Codable
88
86
 
89
87
  ID = self.name.split('::').last
90
88
  VALUE = 98
91
89
 
92
- TERMINAL_MODE_INV = TerminalMode.constants.map{|c| [TerminalMode.const_get(c), c.to_s]}.to_h
90
+ TERMINAL_MODE_INV = TerminalMode.constants.map{|c| [TerminalMode.const_get(c), c.to_s]}.inject(Hash.new){ |h, (k, v)| h.update({k => v}) }
93
91
 
94
92
  DEFINITION = [
95
93
  #[DataType, Field Name]
@@ -6,10 +6,8 @@ require 'hrr_rb_ssh/codable'
6
6
 
7
7
  module HrrRbSsh
8
8
  module Message
9
- module SSH_MSG_CHANNEL_SUCCESS
10
- class << self
11
- include Codable
12
- end
9
+ class SSH_MSG_CHANNEL_SUCCESS
10
+ include Codable
13
11
 
14
12
  ID = self.name.split('::').last
15
13
  VALUE = 99
@@ -6,10 +6,8 @@ require 'hrr_rb_ssh/codable'
6
6
 
7
7
  module HrrRbSsh
8
8
  module Message
9
- module SSH_MSG_CHANNEL_FAILURE
10
- class << self
11
- include Codable
12
- end
9
+ class SSH_MSG_CHANNEL_FAILURE
10
+ include Codable
13
11
 
14
12
  ID = self.name.split('::').last
15
13
  VALUE = 100
@@ -1,29 +1,35 @@
1
1
  # coding: utf-8
2
2
  # vim: et ts=2 sw=2
3
3
 
4
- require 'hrr_rb_ssh/logger'
4
+ require 'hrr_rb_ssh/loggable'
5
5
  require 'hrr_rb_ssh/transport'
6
6
  require 'hrr_rb_ssh/authentication'
7
7
  require 'hrr_rb_ssh/connection'
8
8
 
9
9
  module HrrRbSsh
10
10
  class Server
11
- def self.start io, options={}
12
- server = self.new options
11
+ include Loggable
12
+
13
+ def self.start io, options={}, logger: nil
14
+ server = self.new options, logger: logger
13
15
  server.start io
14
16
  end
15
17
 
16
- def initialize options={}
17
- @logger = Logger.new self.class.name
18
+ def initialize options={}, logger: nil
19
+ self.logger = logger
18
20
  @options = options
19
21
  end
20
22
 
21
23
  def start io
22
- @logger.info { "start server service" }
23
- transport = HrrRbSsh::Transport.new io, HrrRbSsh::Mode::SERVER, @options
24
- authentication = HrrRbSsh::Authentication.new transport, @options
25
- connection = HrrRbSsh::Connection.new authentication, @options
26
- connection.start
24
+ log_info { "start server service" }
25
+ transport = Transport.new io, Mode::SERVER, @options, logger: logger
26
+ authentication = Authentication.new transport, Mode::SERVER, @options, logger: logger
27
+ connection = Connection.new authentication, Mode::SERVER, @options, logger: logger
28
+ begin
29
+ connection.start
30
+ rescue Error::ClosedConnection
31
+ end
32
+ log_info { "server service finished" }
27
33
  end
28
34
  end
29
35
  end
@@ -3,7 +3,7 @@
3
3
 
4
4
  require 'monitor'
5
5
  require 'hrr_rb_ssh/version'
6
- require 'hrr_rb_ssh/logger'
6
+ require 'hrr_rb_ssh/loggable'
7
7
  require 'hrr_rb_ssh/data_type'
8
8
  require 'hrr_rb_ssh/message'
9
9
  require 'hrr_rb_ssh/error/closed_transport'
@@ -20,10 +20,12 @@ require 'hrr_rb_ssh/transport/compression_algorithm'
20
20
 
21
21
  module HrrRbSsh
22
22
  class Transport
23
+ include Loggable
23
24
  include Constant
24
25
 
25
26
  attr_reader \
26
27
  :io,
28
+ :mode,
27
29
  :supported_encryption_algorithms,
28
30
  :supported_server_host_key_algorithms,
29
31
  :supported_kex_algorithms,
@@ -49,20 +51,19 @@ module HrrRbSsh
49
51
  :i_s,
50
52
  :session_id
51
53
 
52
- def initialize io, mode, options={}
54
+ def initialize io, mode, options={}, logger: nil
55
+ self.logger = logger
56
+
53
57
  @io = io
54
58
  @mode = mode
55
59
  @options = options
56
60
 
57
- @logger = Logger.new self.class.name
58
-
59
61
  @closed = nil
60
- @disconnected = nil
61
62
 
62
63
  @in_kex = false
63
64
 
64
- @sender = Sender.new
65
- @receiver = Receiver.new
65
+ @sender = Sender.new logger: logger
66
+ @receiver = Receiver.new logger: logger
66
67
 
67
68
  @sender_monitor = Monitor.new
68
69
  @receiver_monitor = Monitor.new
@@ -86,15 +87,16 @@ module HrrRbSsh
86
87
  end
87
88
 
88
89
  def send payload
90
+ raise Error::ClosedTransport if @closed
89
91
  @sender_monitor.synchronize do
90
92
  begin
91
93
  @sender.send self, payload
92
- rescue Errno::EPIPE => e
93
- @logger.warn { "IO is Broken PIPE" }
94
+ rescue IOError, SystemCallError => e
95
+ log_info { "#{e.message} (#{e.class})" }
94
96
  close
95
97
  raise Error::ClosedTransport
96
98
  rescue => e
97
- @logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
99
+ log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
98
100
  close
99
101
  raise Error::ClosedTransport
100
102
  end
@@ -108,25 +110,24 @@ module HrrRbSsh
108
110
  payload = @receiver.receive self
109
111
  case payload[0,1].unpack("C")[0]
110
112
  when Message::SSH_MSG_DISCONNECT::VALUE
111
- message = Message::SSH_MSG_DISCONNECT.decode payload
112
- @logger.debug { "received disconnect message: #{message.inspect}" }
113
- @disconnected = true
113
+ log_info { "received disconnect message" }
114
+ message = Message::SSH_MSG_DISCONNECT.new(logger: logger).decode payload
114
115
  close
115
116
  raise Error::ClosedTransport
116
117
  when Message::SSH_MSG_IGNORE::VALUE
117
- message = Message::SSH_MSG_IGNORE.decode payload
118
- @logger.debug { "received ignore message: #{message.inspect}" }
118
+ log_info { "received ignore message" }
119
+ message = Message::SSH_MSG_IGNORE.new(logger: logger).decode payload
119
120
  receive
120
121
  when Message::SSH_MSG_UNIMPLEMENTED::VALUE
121
- message = Message::SSH_MSG_UNIMPLEMENTED.decode payload
122
- @logger.debug { "received unimplemented message: #{message.inspect}" }
122
+ log_info { "received unimplemented message" }
123
+ message = Message::SSH_MSG_UNIMPLEMENTED.new(logger: logger).decode payload
123
124
  receive
124
125
  when Message::SSH_MSG_DEBUG::VALUE
125
- message = Message::SSH_MSG_DEBUG.decode payload
126
- @logger.debug { "received debug message: #{message.inspect}" }
126
+ log_info { "received debug message" }
127
+ message = Message::SSH_MSG_DEBUG.new(logger: logger).decode payload
127
128
  receive
128
129
  when Message::SSH_MSG_KEXINIT::VALUE
129
- @logger.debug { "received kexinit message" }
130
+ log_info { "received kexinit message" }
130
131
  if @in_kex
131
132
  payload
132
133
  else
@@ -137,20 +138,13 @@ module HrrRbSsh
137
138
  payload
138
139
  end
139
140
  rescue Error::ClosedTransport
140
- raise Error::ClosedTransport
141
- rescue EOFError => e
142
- close
143
- raise Error::ClosedTransport
144
- rescue IOError => e
145
- @logger.warn { "IO is closed" }
146
- close
147
- raise Error::ClosedTransport
148
- rescue Errno::ECONNRESET => e
149
- @logger.warn { "IO is RESET" }
141
+ raise
142
+ rescue EOFError, IOError, SystemCallError => e
143
+ log_info { "#{e.message} (#{e.class})" }
150
144
  close
151
145
  raise Error::ClosedTransport
152
146
  rescue => e
153
- @logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
147
+ log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
154
148
  close
155
149
  raise Error::ClosedTransport
156
150
  end
@@ -158,36 +152,47 @@ module HrrRbSsh
158
152
  end
159
153
 
160
154
  def start
161
- @logger.info { "start transport" }
162
-
155
+ log_info { "start transport" }
163
156
  begin
164
157
  exchange_version
165
158
  exchange_key
166
-
167
159
  case @mode
168
160
  when Mode::SERVER
169
161
  verify_service_request
162
+ when Mode::CLIENT
163
+ send_service_request
170
164
  end
171
-
172
165
  @closed = false
173
- rescue EOFError => e
166
+ rescue Error::ClosedTransport
167
+ raise
168
+ rescue EOFError, IOError, SystemCallError => e
169
+ log_info { "#{e.message} (#{e.class})" }
174
170
  close
171
+ raise Error::ClosedTransport
175
172
  rescue => e
176
- @logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
173
+ log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
177
174
  close
175
+ raise Error::ClosedTransport
178
176
  else
179
- @logger.info { "transport started" }
177
+ log_info { "transport started" }
180
178
  end
181
179
  end
182
180
 
183
181
  def close
184
- return if @closed
185
- @logger.info { "close transport" }
186
- @closed = true
187
- disconnect
188
- @incoming_compression_algorithm.close
189
- @outgoing_compression_algorithm.close
190
- @logger.info { "transport closed" }
182
+ @sender_monitor.synchronize do
183
+ return if @closed
184
+ log_info { "close transport" }
185
+ begin
186
+ disconnect
187
+ @incoming_compression_algorithm.close
188
+ @outgoing_compression_algorithm.close
189
+ rescue => e
190
+ log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
191
+ ensure
192
+ @closed = true
193
+ log_info { "transport closed" }
194
+ end
195
+ end
191
196
  end
192
197
 
193
198
  def closed?
@@ -195,17 +200,9 @@ module HrrRbSsh
195
200
  end
196
201
 
197
202
  def disconnect
198
- return if @disconnected
199
- @logger.info { "disconnect transport" }
200
- @disconnected = true
201
- begin
202
- send_disconnect
203
- rescue IOError
204
- @logger.warn { "IO is closed" }
205
- rescue => e
206
- @logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
207
- end
208
- @logger.info { "transport disconnected" }
203
+ log_info { "disconnect transport" }
204
+ send_disconnect
205
+ log_info { "transport disconnected" }
209
206
  end
210
207
 
211
208
  def exchange_version
@@ -235,7 +232,7 @@ module HrrRbSsh
235
232
  end
236
233
 
237
234
  def start_kex_algorithm
238
- @kex_algorithm.start self, @mode
235
+ @kex_algorithm.start self
239
236
  end
240
237
 
241
238
  def verify_service_request
@@ -314,10 +311,10 @@ module HrrRbSsh
314
311
  if str_io.string[-2..-1] == "#{CR}#{LF}"
315
312
  if str_io.string[0..3] == "SSH-"
316
313
  @remote_version = str_io.string[0..-3]
317
- @logger.info { "received remote version string: #{@remote_version}" }
314
+ log_info { "received remote version string: #{@remote_version}" }
318
315
  break
319
316
  else
320
- @logger.info { "received message before remote version string: #{str_io.string}" }
317
+ log_info { "received message before remote version string: #{str_io.string}" }
321
318
  str_io.rewind
322
319
  str_io.truncate(0)
323
320
  end
@@ -343,8 +340,16 @@ module HrrRbSsh
343
340
  :'description' => "disconnected by user",
344
341
  :'language tag' => ""
345
342
  }
346
- payload = Message::SSH_MSG_DISCONNECT.encode message
347
- send payload
343
+ payload = Message::SSH_MSG_DISCONNECT.new(logger: logger).encode message
344
+ @sender_monitor.synchronize do
345
+ begin
346
+ @sender.send self, payload
347
+ rescue IOError, SystemCallError => e
348
+ log_info { "#{e.message} (#{e.class})" }
349
+ rescue => e
350
+ log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
351
+ end
352
+ end
348
353
  end
349
354
 
350
355
  def send_kexinit
@@ -364,7 +369,7 @@ module HrrRbSsh
364
369
  :'first_kex_packet_follows' => false,
365
370
  :'0 (reserved for future extension)' => 0,
366
371
  }
367
- payload = Message::SSH_MSG_KEXINIT.encode message
372
+ payload = Message::SSH_MSG_KEXINIT.new(logger: logger).encode message
368
373
  send payload
369
374
 
370
375
  case @mode
@@ -382,7 +387,7 @@ module HrrRbSsh
382
387
  when Mode::CLIENT
383
388
  @i_s = payload
384
389
  end
385
- message = Message::SSH_MSG_KEXINIT.decode payload
390
+ message = Message::SSH_MSG_KEXINIT.new(logger: logger).decode payload
386
391
  update_remote_algorithms message
387
392
  end
388
393
 
@@ -390,28 +395,38 @@ module HrrRbSsh
390
395
  message = {
391
396
  :'message number' => Message::SSH_MSG_NEWKEYS::VALUE,
392
397
  }
393
- payload = Message::SSH_MSG_NEWKEYS.encode message
398
+ payload = Message::SSH_MSG_NEWKEYS.new(logger: logger).encode message
394
399
  send payload
395
400
  end
396
401
 
397
402
  def receive_newkeys payload
398
- message = Message::SSH_MSG_NEWKEYS.decode payload
403
+ message = Message::SSH_MSG_NEWKEYS.new(logger: logger).decode payload
399
404
  end
400
405
 
401
- def receive_service_request
406
+ def send_service_request
407
+ message = {
408
+ :'message number' => Message::SSH_MSG_SERVICE_REQUEST::VALUE,
409
+ :'service name' => 'ssh-userauth',
410
+ }
411
+ payload = Message::SSH_MSG_SERVICE_REQUEST.new(logger: logger).encode message
412
+ send payload
413
+
402
414
  payload = @receiver.receive self
403
- message = Message::SSH_MSG_SERVICE_REQUEST.decode payload
415
+ message = Message::SSH_MSG_SERVICE_ACCEPT.new(logger: logger).decode payload
416
+ end
404
417
 
405
- message
418
+ def receive_service_request
419
+ payload = @receiver.receive self
420
+ message = Message::SSH_MSG_SERVICE_REQUEST.new(logger: logger).decode payload
406
421
  end
407
422
 
408
423
  def send_service_accept service_name
409
- message = {
410
- :'message number' => Message::SSH_MSG_SERVICE_ACCEPT::VALUE,
411
- :'service name' => service_name,
412
- }
413
- payload = Message::SSH_MSG_SERVICE_ACCEPT.encode message
414
- send payload
424
+ message = {
425
+ :'message number' => Message::SSH_MSG_SERVICE_ACCEPT::VALUE,
426
+ :'service name' => service_name,
427
+ }
428
+ payload = Message::SSH_MSG_SERVICE_ACCEPT.new(logger: logger).encode message
429
+ send payload
415
430
  end
416
431
 
417
432
  def update_remote_algorithms message
@@ -430,14 +445,14 @@ module HrrRbSsh
430
445
  when Mode::SERVER
431
446
  kex_algorithm_name = @remote_kex_algorithms.find{ |a| @local_kex_algorithms.include? a } or raise
432
447
  server_host_key_algorithm_name = @remote_server_host_key_algorithms.find{ |a| @local_server_host_key_algorithms.include? a } or raise
448
+ server_secret_host_key = @options.fetch('transport_server_secret_host_keys', {}).fetch(server_host_key_algorithm_name, nil)
433
449
  when Mode::CLIENT
434
450
  kex_algorithm_name = @local_kex_algorithms.find{ |a| @remote_kex_algorithms.include? a } or raise
435
451
  server_host_key_algorithm_name = @local_server_host_key_algorithms.find{ |a| @remote_server_host_key_algorithms.include? a } or raise
452
+ server_secret_host_key = nil
436
453
  end
437
-
438
- server_secret_host_key = @options.fetch('transport_server_secret_host_keys', {}).fetch(server_host_key_algorithm_name, nil)
439
- @kex_algorithm = KexAlgorithm[kex_algorithm_name].new
440
454
  @server_host_key_algorithm = ServerHostKeyAlgorithm[server_host_key_algorithm_name].new server_secret_host_key
455
+ @kex_algorithm = KexAlgorithm[kex_algorithm_name].new
441
456
  end
442
457
 
443
458
  def update_encryption_mac_compression_algorithms
@@ -458,6 +473,15 @@ module HrrRbSsh
458
473
  outgoing_crpt_iv = @kex_algorithm.iv_s_to_c self, outgoing_encryption_algorithm_name
459
474
  incoming_crpt_key = @kex_algorithm.key_c_to_s self, incoming_encryption_algorithm_name
460
475
  outgoing_crpt_key = @kex_algorithm.key_s_to_c self, outgoing_encryption_algorithm_name
476
+ when Mode::CLIENT
477
+ encryption_algorithm_s_to_c_name = @local_encryption_algorithms_server_to_client.find{ |a| @remote_encryption_algorithms_server_to_client.include? a } or raise
478
+ encryption_algorithm_c_to_s_name = @local_encryption_algorithms_client_to_server.find{ |a| @remote_encryption_algorithms_client_to_server.include? a } or raise
479
+ incoming_encryption_algorithm_name = encryption_algorithm_s_to_c_name
480
+ outgoing_encryption_algorithm_name = encryption_algorithm_c_to_s_name
481
+ incoming_crpt_iv = @kex_algorithm.iv_s_to_c self, incoming_encryption_algorithm_name
482
+ outgoing_crpt_iv = @kex_algorithm.iv_c_to_s self, outgoing_encryption_algorithm_name
483
+ incoming_crpt_key = @kex_algorithm.key_s_to_c self, incoming_encryption_algorithm_name
484
+ outgoing_crpt_key = @kex_algorithm.key_c_to_s self, outgoing_encryption_algorithm_name
461
485
  end
462
486
  @incoming_encryption_algorithm = EncryptionAlgorithm[incoming_encryption_algorithm_name].new Direction::INCOMING, incoming_crpt_iv, incoming_crpt_key
463
487
  @outgoing_encryption_algorithm = EncryptionAlgorithm[outgoing_encryption_algorithm_name].new Direction::OUTGOING, outgoing_crpt_iv, outgoing_crpt_key
@@ -472,6 +496,13 @@ module HrrRbSsh
472
496
  outgoing_mac_algorithm_name = mac_algorithm_s_to_c_name
473
497
  incoming_mac_key = @kex_algorithm.mac_c_to_s self, incoming_mac_algorithm_name
474
498
  outgoing_mac_key = @kex_algorithm.mac_s_to_c self, outgoing_mac_algorithm_name
499
+ when Mode::CLIENT
500
+ mac_algorithm_s_to_c_name = @local_mac_algorithms_server_to_client.find{ |a| @remote_mac_algorithms_server_to_client.include? a } or raise
501
+ mac_algorithm_c_to_s_name = @local_mac_algorithms_client_to_server.find{ |a| @remote_mac_algorithms_client_to_server.include? a } or raise
502
+ incoming_mac_algorithm_name = mac_algorithm_s_to_c_name
503
+ outgoing_mac_algorithm_name = mac_algorithm_c_to_s_name
504
+ incoming_mac_key = @kex_algorithm.mac_s_to_c self, incoming_mac_algorithm_name
505
+ outgoing_mac_key = @kex_algorithm.mac_c_to_s self, outgoing_mac_algorithm_name
475
506
  end
476
507
  @incoming_mac_algorithm = MacAlgorithm[incoming_mac_algorithm_name].new incoming_mac_key
477
508
  @outgoing_mac_algorithm = MacAlgorithm[outgoing_mac_algorithm_name].new outgoing_mac_key
@@ -484,6 +515,11 @@ module HrrRbSsh
484
515
  compression_algorithm_s_to_c_name = @remote_compression_algorithms_server_to_client.find{ |a| @local_compression_algorithms_server_to_client.include? a } or raise
485
516
  incoming_compression_algorithm_name = compression_algorithm_c_to_s_name
486
517
  outgoing_compression_algorithm_name = compression_algorithm_s_to_c_name
518
+ when Mode::CLIENT
519
+ compression_algorithm_s_to_c_name = @local_compression_algorithms_server_to_client.find{ |a| @remote_compression_algorithms_server_to_client.include? a } or raise
520
+ compression_algorithm_c_to_s_name = @local_compression_algorithms_client_to_server.find{ |a| @remote_compression_algorithms_client_to_server.include? a } or raise
521
+ incoming_compression_algorithm_name = compression_algorithm_s_to_c_name
522
+ outgoing_compression_algorithm_name = compression_algorithm_c_to_s_name
487
523
  end
488
524
  @incoming_compression_algorithm.close
489
525
  @outgoing_compression_algorithm.close