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 +4 -4
- data/README.md +57 -41
- data/demo/client.rb +12 -4
- data/lib/hrr_rb_ssh/client.rb +39 -5
- data/lib/hrr_rb_ssh/connection/channel.rb +3 -1
- data/lib/hrr_rb_ssh/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 045cac2e290061c0575c6a2f4d09e6c9ae4d45cadb5a82ed7f73ac440b97e9e9
|
4
|
+
data.tar.gz: 7ed94a74123486946cf35c6308af08e64fb8bda1108256a8390aecc46f4c67b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
###
|
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
|
-
####
|
431
|
+
#### Starting SSH connection
|
427
432
|
|
428
|
-
|
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
|
-
|
431
|
-
|
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
|
-
|
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
|
-
|
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(
|
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.
|
data/demo/client.rb
CHANGED
@@ -15,18 +15,17 @@ logger.level = Logger::INFO
|
|
15
15
|
logger.level = Logger::DEBUG
|
16
16
|
HrrRbSsh::Logger.initialize logger
|
17
17
|
|
18
|
-
|
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(
|
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
|
}
|
data/lib/hrr_rb_ssh/client.rb
CHANGED
@@ -11,8 +11,8 @@ require 'hrr_rb_ssh/connection'
|
|
11
11
|
|
12
12
|
module HrrRbSsh
|
13
13
|
class Client
|
14
|
-
def self.start
|
15
|
-
client = self.new
|
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
|
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 =
|
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
|
data/lib/hrr_rb_ssh/version.rb
CHANGED
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.
|
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-
|
11
|
+
date: 2019-07-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ed25519
|