SSH Drivers
SSH modules interface with devices or servers that communicate using the SSH 1.99/2.0 protocol. SSH 1 is considered obsolete due to inherent security flaws and not supported.
SSH modules are similar to Device Drivers with an additional exec function, where supported by the remote. Unfortunately most AV devices seem to only support interactive shell, which is akin to telnet.

Authentication

Supports the following authentication methods:
  • none
  • public key
  • password
These settings must be defined in the JSON settings (dependency or driver instance) and would typically look like:
1
{
2
"ssh": {
3
"username": "account_name",
4
"$password": "password", // $ sign will encrypt the password and/or private key
5
"$key_data": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAqccvUza8FCinI4X8HSiXwIqQN6TGvcNBJnjPqGJxlstq1IfU\nkFa3S9eJl+CBkyjfvJ5ggdLN0S2EuGWwc/bdE3LKOWX8F15tFP0=\n-----END RSA PRIVATE KEY-----"
6
}
7
}
Copied!

Sending an exec request

If supported requests can be sent using the exec function. There are two modes of operation, depending on how much response data is required and requests can be performed in parallel.
1
# =================
2
# Request semantics
3
# =================
4
# Simple request. (these are equivalent)
5
exec('command –a')
6
exec('command', '-a')
7
8
# Simple request. Complex arguments
9
exec('setname -full Stephen von Takach') # This will fail
10
exec('setname', '-full', 'Stephen von Takach') # Will succeed, escaped properly
11
12
13
# ==============================
14
# Accessing responses (promises)
15
# ==============================
16
17
# .value pauses execution and waits for the response before continuing
18
exec('command', '-a').value # => return all output as a string or raise error
19
20
# .then provides callbacks so execution is not paused
21
exec('command', '-a').then { |response|
22
# Process response
23
}.catch { |error|
24
# Handle error
25
}
26
27
# Commands are queued by default as many devices can only handle a single request at a time.
28
# However you can perform requests in parallel
29
tasks = []
30
tasks << exec('command1', '-a', wait: false)
31
tasks << exec('command2', '-a', wait: false)
32
tasks << exec('command3', '-a', wait: false)
33
34
# Wait until all commands have completed (optional)
35
response_array = thread.all(tasks).value
Copied!
There is a more complicated request form that provides access to exit codes and individual data streams.
1
status = exec('uname', '-a') do |channel, stream, data|
2
logger.debug { data } if stream == :stdout
3
logger.error { data } if stream == :stderr
4
end
5
status.value # => {exit_code: 137, exit_signal: 9}
Copied!

Exec request options

Option
Default Value
Description
wait
true
do we want to wait for a response before we continue processing
delay
0
minimum delay time between sends (milliseconds)
delay_on_receive
0
time to delay the next transmit after receiving data (milliseconds)
retries
2
number of times we’ll retry a command if it has timed out
timeout
5000
amount of time we’ll wait for a response to a command before retrying (milliseconds)
priority
50
so we can perform commands in preference to others
Last modified 2yr ago