hrr_rb_ssh 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5069234076e5c4f106d9ef733fd232fd0df99497fc64b948e9014d74a688f608
4
- data.tar.gz: 0f88f74186bf0c86aa0dd6e76770d0e028231105bb06bc4ea5870f97841194d3
3
+ metadata.gz: 045cac2e290061c0575c6a2f4d09e6c9ae4d45cadb5a82ed7f73ac440b97e9e9
4
+ data.tar.gz: 7ed94a74123486946cf35c6308af08e64fb8bda1108256a8390aecc46f4c67b1
5
5
  SHA512:
6
- metadata.gz: 5937b53c91ce899fbc3b0d0b97de9c336ad14fecda882ca24f6e9fc3184ec6b07123ae78bc7fdf3a11560ad3b268cb23277453d3f1ced91a5b1fb5054e3106f3
7
- data.tar.gz: c757a877562b34ca17a8015fc9829ad6babfa89dbb197b451a0a23a1c372bc2ba1ba0ce77e2756da6b63157384be7774d15dd569b8b349ed898186e8f8f1818d
6
+ metadata.gz: ed149cc2cba4cc2884c571ee11eb453b23ec593498a0f5ff0a3cb95c3d4cb36286c9559466210a7b9c336e2167b97bea87504e00d029d996a92d655de6f9beff
7
+ data.tar.gz: 76b80ab7c6635df3e9286d1a1203674d03e83209f577dce22c00d30d21042a727af22e1ed457943e7b54bf0843ebd0e184bb3ac240929ef0447a7356888d8516
data/README.md CHANGED
@@ -13,10 +13,10 @@ With hrr_rb_ssh, it is possible to write an SSH server easily, and also possible
13
13
 
14
14
  - [Installation](#installation)
15
15
  - [Usage](#usage)
16
+ - [Requiring hrr\_rb\_ssh library](#requiring-hrr_rb_ssh-library)
17
+ - [Logging](#logging)
16
18
  - [Writing standard SSH server](#writing-standard-ssh-server)
17
- - [Requiring hrr\_rb\_ssh library](#requiring-hrr_rb_ssh-library)
18
19
  - [Starting server application](#starting-server-application)
19
- - [Logging](#logging)
20
20
  - [Registering pre\-generated secret keys for server host key](#registering-pre-generated-secret-keys-for-server-host-key)
21
21
  - [Defining authentications](#defining-authentications)
22
22
  - [Single authentication](#single-authentication)
@@ -32,6 +32,11 @@ With hrr_rb_ssh, it is possible to write an SSH server easily, and also possible
32
32
  - [Defining preferred algorithms (optional)](#defining-preferred-algorithms-optional)
33
33
  - [Hiding and/or simulating local SSH version](#hiding-and-or-simulating-local-ssh-version)
34
34
  - [Writing SSH client (Experimental)](#writing-ssh-client-experimental)
35
+ - [Starting SSH connection](#starting-ssh-connection)
36
+ - [Executing remote commands](#executing-remote-commands)
37
+ - [exec method](#exec-method)
38
+ - [shell method](#shell-method)
39
+ - [subsystem method](#subsystem-method)
35
40
  - [Demo](#demo)
36
41
  - [Supported Features](#supported-features)
37
42
  - [Connection layer](#connection-layer)
@@ -63,9 +68,7 @@ $ gem install hrr_rb_ssh
63
68
 
64
69
  ## Usage
65
70
 
66
- ### Writing standard SSH server
67
-
68
- #### Requiring `hrr_rb_ssh` library
71
+ ### Requiring `hrr_rb_ssh` library
69
72
 
70
73
  First of all, `hrr_rb_ssh` library needs to be loaded.
71
74
 
@@ -73,6 +76,33 @@ First of all, `hrr_rb_ssh` library needs to be loaded.
73
76
  require 'hrr_rb_ssh'
74
77
  ```
75
78
 
79
+ ### Logging
80
+
81
+ __IMPORTANT__: DEBUG log level outputs all communications between local and remote in human-readable plain-text including password and any secret. Be careful to use logging.
82
+
83
+ The library provides logging functionality. To enable logging of the library, you are to initialize `HrrRbSsh::Logger` class.
84
+
85
+ ```ruby
86
+ HrrRbSsh::Logger.initialize logger
87
+ ```
88
+
89
+ Where, the `logger` variable can be an instance of standard Logger class or user-defined logger class. What `HrrRbSsh::Logger` class requires for `logger` variable is that the `logger` instance responds to `#fatal`, `#error`, `#warn`, `#info` and `#debug`.
90
+
91
+ For instance, `logger` variable can be prepared like below.
92
+
93
+ ```ruby
94
+ logger = Logger.new STDOUT
95
+ logger.level = Logger::INFO
96
+ ```
97
+
98
+ To disable logging, you can un-initialize `HrrRbSsh::Logger`.
99
+
100
+ ```ruby
101
+ HrrRbSsh::Logger.uninitialize
102
+ ```
103
+
104
+ ### Writing standard SSH server
105
+
76
106
  #### Starting server application
77
107
 
78
108
  The library is to run on a socket IO. To start SSH server, running a server IO and accepting a connection are required. The 10022 port number is just an example.
@@ -98,31 +128,6 @@ end
98
128
 
99
129
  Where, an `options` variable is an instance of `Hash`, which has optional (or sometimes almost necessary) values.
100
130
 
101
- #### Logging
102
-
103
- __IMPORTANT__: DEBUG log level outputs all communications between local and remote in human-readable plain-text including password and any secret. Be careful to use logging.
104
-
105
- The library provides logging functionality. To enable logging of the library, you are to initialize `HrrRbSsh::Logger` class.
106
-
107
- ```ruby
108
- HrrRbSsh::Logger.initialize logger
109
- ```
110
-
111
- Where, the `logger` variable can be an instance of standard Logger class or user-defined logger class. What `HrrRbSsh::Logger` class requires for `logger` variable is that the `logger` instance responds to `#fatal`, `#error`, `#warn`, `#info` and `#debug`.
112
-
113
- For instance, `logger` variable can be prepared like below.
114
-
115
- ```ruby
116
- logger = Logger.new STDOUT
117
- logger.level = Logger::INFO
118
- ```
119
-
120
- To disable logging, you can un-initialize `HrrRbSsh::Logger`.
121
-
122
- ```ruby
123
- HrrRbSsh::Logger.uninitialize
124
- ```
125
-
126
131
  #### Registering pre-generated secret keys for server host key
127
132
 
128
133
  By default, server host keys are generated everytime the gem is loaded. To use pre-generated keys, it is possible to register the keys in HrrRbSsh::Transport through `options` variable. The secret key value must be PEM or DER format string. The below is an example of registering ecdsa-sha2-nistp256 secret key. The supported server host key algorithms are listed later in this document.
@@ -423,28 +428,25 @@ Please note that the beginning of the string must be `SSH-2.0-`. Otherwise SSH 2
423
428
 
424
429
  ### Writing SSH client (Experimental)
425
430
 
426
- #### Requiring `hrr_rb_ssh` library
431
+ #### Starting SSH connection
427
432
 
428
- First of all, `hrr_rb_ssh` library needs to be loaded.
433
+ The client mode can be started with `HrrRbSsh::Client.start`. The method takes `target` and `options` arguments. The `target` that the SSH client connects to can be one of:
429
434
 
430
- ```ruby
431
- require 'hrr_rb_ssh'
432
- ```
435
+ - (IO) An io that is open for input and output
436
+ - (Array) An array of the target host address or host name and its service port number
437
+ - (String) The target host address or host name; in this case the target service port number will be 22
433
438
 
434
- #### Starting SSH connection
435
-
436
- The client mode can be started with `HrrRbSsh::Client.start`. The method takes `address` and `options` arguments. The `address` is the target host address that the SSH client connects to. And the `options` contains various parameters for the SSH connection. At least `username` key must be set in the `options`. Also at least one of `password`, `publickey`, or `keyboard-interactive` needs to be set for authentication instead of authenticators that are used in server mode. Also as similar to server mode, it is possible to specify preferred transport algorithms and preferred authentication methods with the same keywords.
439
+ And the `options` contains various parameters for the SSH connection. At least `username` key must be set in the `options`. Also at least one of `password`, `publickey`, or `keyboard-interactive` needs to be set for authentication instead of authenticators that are used in server mode. Also as similar to server mode, it is possible to specify preferred transport algorithms and preferred authentication methods with the same keywords.
437
440
 
438
441
  ```ruby
439
- address = 'remotehost'
442
+ target = ['remotehost', 22]
440
443
  options = {
441
- port: 22,
442
444
  username: 'user1',
443
445
  password: 'password1',
444
446
  publickey: ['ssh-rsa', "/home/user1/.ssh/id_rsa")],
445
447
  authentication_preferred_authentication_methods = ['publickey', 'password'],
446
448
  }
447
- HrrRbSsh::Client.start(address, options) do |conn|
449
+ HrrRbSsh::Client.start(target, options) do |conn|
448
450
  # Do something here
449
451
  # For instance: conn.exec "command"
450
452
  end
@@ -460,6 +462,10 @@ The `exec` and `exec!` methods execute command on a remote host. Both takes a co
460
462
 
461
463
  The `exec!` method returns `[stdout, stderr]` outputs. Once the command is executed and the outputs are completed, then the method returns the value.
462
464
 
465
+ ```ruby
466
+ conn.exec! "command" # => [stdout, stderr]
467
+ ```
468
+
463
469
  On the other hand, `exec` method takes block like the below example and returns exit status of the command. When the command is executed and the outputs and reading them are finished, then `io_out` and `io_err` return EOF.
464
470
 
465
471
  ```ruby
@@ -478,6 +484,16 @@ conn.shell do |io_in, io_out, io_err|
478
484
  end
479
485
  ```
480
486
 
487
+ ##### subsystem method
488
+
489
+ The `subsystem` method is to start a subsystem on a remote host. The method takes a subsystem name argument and a block. Its block variable is also `io_in, io_out, io_err`. `subsystem` doesn't take `pty` nor `env` optional argument.
490
+
491
+ ```ruby
492
+ conn.subsystem("echo") do |io_in, io_out, io_err|
493
+ # Do something here
494
+ end
495
+ ```
496
+
481
497
  ### Demo
482
498
 
483
499
  The `demo/server.rb` shows a good example on how to use the hrr_rb_ssh library in SSH server mode. And the `demo/client.rb` shows an example on how to use the hrr_rb_ssh library in SSH client mode.
@@ -15,18 +15,17 @@ logger.level = Logger::INFO
15
15
  logger.level = Logger::DEBUG
16
16
  HrrRbSsh::Logger.initialize logger
17
17
 
18
- address = 'localhost'
18
+ target = ['localhost', 10022]
19
19
  options = {
20
- port: 10022,
21
20
  username: 'user1',
22
21
  password: 'password1',
23
- publickey: ['ssh-rsa', "/home/user1/.ssh/id_rsa")],
22
+ publickey: ['ssh-rsa', "/home/user1/.ssh/id_rsa"],
24
23
  keyboard_interactive: [
25
24
  'password1',
26
25
  #'password2' # when keyboard-interactive authentication requires 2nd response
27
26
  ],
28
27
  }
29
- HrrRbSsh::Client.start(address, options){ |conn|
28
+ HrrRbSsh::Client.start(target, options){ |conn|
30
29
  puts conn.exec!('ls -l') # => [out, err]
31
30
 
32
31
  puts conn.exec!('ls -l', pty: true) # => [out, err] # "ls -l" command will be run on PTY
@@ -55,4 +54,13 @@ HrrRbSsh::Client.start(address, options){ |conn|
55
54
  io_in.puts "exit"
56
55
  t.join
57
56
  }
57
+
58
+ conn.subsystem("echo"){ |io_in, io_out, io_err| # => exit status
59
+ t = Thread.new {
60
+ print io_out.readpartial(10240) rescue nil
61
+ }
62
+ io_in.puts "string"
63
+ t.join
64
+ io_in.close
65
+ }
58
66
  }
@@ -11,8 +11,8 @@ require 'hrr_rb_ssh/connection'
11
11
 
12
12
  module HrrRbSsh
13
13
  class Client
14
- def self.start address, options={}
15
- client = self.new address, options
14
+ def self.start target, options={}
15
+ client = self.new target, options
16
16
  client.start
17
17
  if block_given?
18
18
  begin
@@ -25,11 +25,19 @@ module HrrRbSsh
25
25
  end
26
26
  end
27
27
 
28
- def initialize address, tmp_options={}
28
+ def initialize target, tmp_options={}
29
29
  @logger = Logger.new self.class.name
30
30
  @closed = true
31
31
  options = initialize_options tmp_options
32
- io = TCPSocket.new address, options['port']
32
+ io = case target
33
+ when IO
34
+ target
35
+ when Array
36
+ io = TCPSocket.new *target
37
+ when String
38
+ port = 22
39
+ io = TCPSocket.new target, port
40
+ end
33
41
  transport = HrrRbSsh::Transport.new io, HrrRbSsh::Mode::CLIENT, options
34
42
  authentication = HrrRbSsh::Authentication.new transport, HrrRbSsh::Mode::CLIENT, options
35
43
  @connection = HrrRbSsh::Connection.new authentication, HrrRbSsh::Mode::CLIENT, options
@@ -38,7 +46,6 @@ module HrrRbSsh
38
46
  def initialize_options tmp_options
39
47
  tmp_options = Hash[tmp_options.map{|k, v| [k.to_s, v]}]
40
48
  options = {}
41
- options['port'] = tmp_options['port'] || 22
42
49
  options['username'] = tmp_options['username']
43
50
  options['authentication_preferred_authentication_methods'] = tmp_options['authentication_preferred_authentication_methods']
44
51
  options['client_authentication_password'] = tmp_options['password']
@@ -194,5 +201,32 @@ module HrrRbSsh
194
201
  end
195
202
  channel_exit_status = channel.exit_status rescue nil
196
203
  end
204
+
205
+ def subsystem name
206
+ @logger.debug { "start subsystem" }
207
+ begin
208
+ @logger.info { "Opning channel" }
209
+ channel = @connection.request_channel_open "session"
210
+ @logger.info { "Channel opened" }
211
+ channel.send_channel_request_subsystem name
212
+ yield channel.io
213
+ rescue => e
214
+ @logger.error { "Failed opening channel" }
215
+ @logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
216
+ raise "Error in subsystem"
217
+ ensure
218
+ if channel
219
+ @logger.info { "closing channel IOs" }
220
+ channel.io.each{ |io| io.close rescue nil }
221
+ @logger.info { "channel IOs closed" }
222
+ @logger.info { "closing channel" }
223
+ @logger.info { "wait until threads closed in channel" }
224
+ channel.wait_until_closed
225
+ channel.close
226
+ @logger.info { "channel closed" }
227
+ end
228
+ end
229
+ channel_exit_status = channel.exit_status rescue nil
230
+ end
197
231
  end
198
232
  end
@@ -125,6 +125,8 @@ module HrrRbSsh
125
125
  else
126
126
  @logger.warn { "skip sending exit-status because exitstatus is not an instance of Integer" }
127
127
  end
128
+ elsif from == :sender_thread
129
+ send_channel_eof
128
130
  end
129
131
  send_channel_close
130
132
  rescue Error::ClosedConnection => e
@@ -389,9 +391,9 @@ module HrrRbSsh
389
391
  rescue => e
390
392
  @logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
391
393
  @r_io_in.close rescue nil
392
- close
393
394
  end
394
395
  end
396
+ close from=:sender_thread
395
397
  @logger.info { "sender thread closed" }
396
398
  }
397
399
  end
@@ -2,5 +2,5 @@
2
2
  # vim: et ts=2 sw=2
3
3
 
4
4
  module HrrRbSsh
5
- VERSION = "0.3.0"
5
+ VERSION = "0.3.1"
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hrr_rb_ssh
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - hirura
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-14 00:00:00.000000000 Z
11
+ date: 2019-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ed25519