netsnmp 0.4.0 → 0.6.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.
- checksums.yaml +4 -4
- data/README.md +6 -3
- data/lib/netsnmp/message.rb +22 -6
- data/lib/netsnmp/mib.rb +11 -1
- data/lib/netsnmp/pdu.rb +1 -1
- data/lib/netsnmp/scoped_pdu.rb +2 -0
- data/lib/netsnmp/security_parameters.rb +10 -2
- data/lib/netsnmp/session.rb +3 -3
- data/lib/netsnmp/v3_session.rb +28 -9
- data/lib/netsnmp/version.rb +1 -1
- data/sig/message.rbs +6 -0
- data/sig/scoped_pdu.rbs +2 -0
- data/sig/security_parameters.rbs +2 -2
- data/spec/client_spec.rb +56 -35
- data/spec/handlers/celluloid_spec.rb +12 -12
- data/spec/security_parameters_spec.rb +18 -0
- data/spec/support/celluloid.rb +11 -7
- data/spec/support/request_examples.rb +13 -4
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 93b380d735dc2250a9c3528e7ab1e6c70147124a6dc439fe7dd4eac1f4c0fd55
|
4
|
+
data.tar.gz: 52db8f559bc3485ab4802d72ccba98fb29429a0b9a0cceec13fc5a489409e35e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a7573fe1ca2f0d78a3ca4d88d8054b9fd872078352d8ed3f700525e049719d601fe8f7dda94f0ff77b866e75961eb26af80a4acd332e04d390c433405970fd7
|
7
|
+
data.tar.gz: 3524298a40a89f5364a27cfe0444f7e298016822439020c04b203960cc4c77622453f9a48d6c01ea1e072c3a004705299b6a8f34a89cb1ce00f66a98f3919d7a
|
data/README.md
CHANGED
@@ -31,6 +31,7 @@ $ gem install netsnmp
|
|
31
31
|
This gem provides:
|
32
32
|
|
33
33
|
* Implementation in ruby of the SNMP Protocol for v3, v2c and v1 (most notable the rfc3414 and 3826).
|
34
|
+
* SNMPv3 USM supporting MD5/SHA/SHA256 auth and DES/AES128 privacy crypto algorithms.
|
34
35
|
* Client/Manager API with simple interface for get, genext, set and walk.
|
35
36
|
* Pure Ruby.
|
36
37
|
* Support for concurrency and evented I/O.
|
@@ -80,7 +81,7 @@ manager.get(oid: "sysName.0") #=> 'tt'
|
|
80
81
|
# SNMP walk
|
81
82
|
# sysORDescr
|
82
83
|
manager.walk(oid: "sysORDescr").each do |oid_code, value|
|
83
|
-
# do something with them
|
84
|
+
# do something with them
|
84
85
|
puts "for #{oid_code}: #{value}"
|
85
86
|
end
|
86
87
|
|
@@ -214,8 +215,8 @@ gem 'netsnmp'
|
|
214
215
|
|
215
216
|
# or, in the command line
|
216
217
|
|
217
|
-
$ gem install netsnmp
|
218
|
-
```
|
218
|
+
$ gem install netsnmp
|
219
|
+
```
|
219
220
|
|
220
221
|
and `netsnmp` will automatically pick it up.
|
221
222
|
|
@@ -245,6 +246,8 @@ This library supports and is tested against ruby versions 2.1 or more recent, in
|
|
245
246
|
|
246
247
|
All encoding/decoding/encryption/decryption/digests are done using `openssl`, which is (still) a part of the standard library. If at some point `openssl` is removed and not specifically distributed, you'll have to install it yourself. Hopefully this will never happen.
|
247
248
|
|
249
|
+
It also uses the `openssl` ASN.1 API to encode/decode BERs, which is known to be strict, and [may not be able to decode PDUs if not compliant with the supported RFC](https://github.com/swisscom/ruby-netsnmp/issues/47).
|
250
|
+
|
248
251
|
## Debugging
|
249
252
|
|
250
253
|
You can either set the `NETSNMP_DEBUG` to the desided debug level (currently, 1 and 2). The logs will be written to stderr.
|
data/lib/netsnmp/message.rb
CHANGED
@@ -7,8 +7,7 @@ module NETSNMP
|
|
7
7
|
|
8
8
|
prepend Loggable
|
9
9
|
|
10
|
-
|
11
|
-
PRIVNONE = OpenSSL::ASN1::OctetString.new("")
|
10
|
+
PRIVNONE = OpenSSL::ASN1::OctetString.new("")
|
12
11
|
MSG_MAX_SIZE = OpenSSL::ASN1::Integer.new(65507).with_label(:max_message_size)
|
13
12
|
MSG_SECURITY_MODEL = OpenSSL::ASN1::Integer.new(3).with_label(:security_model) # usmSecurityModel
|
14
13
|
MSG_VERSION = OpenSSL::ASN1::Integer.new(3).with_label(:message_version)
|
@@ -16,6 +15,10 @@ module NETSNMP
|
|
16
15
|
|
17
16
|
def initialize(**); end
|
18
17
|
|
18
|
+
def verify(stream, auth_param, security_level, security_parameters:)
|
19
|
+
security_parameters.verify(stream.sub(auth_param, authnone(security_parameters.auth_protocol).value), auth_param, security_level: security_level)
|
20
|
+
end
|
21
|
+
|
19
22
|
# @param [String] payload of an snmp v3 message which can be decoded
|
20
23
|
# @param [NETSMP::SecurityParameters, #decode] security_parameters knowns how to decode the stream
|
21
24
|
#
|
@@ -51,9 +54,7 @@ module NETSNMP
|
|
51
54
|
log(level: 2) { asn_tree.to_hex }
|
52
55
|
log(level: 2) { sec_params_asn.to_hex }
|
53
56
|
|
54
|
-
# validate_authentication
|
55
57
|
auth_param = auth_param.value
|
56
|
-
security_parameters.verify(stream.sub(auth_param, AUTHNONE.value), auth_param, security_level: security_level)
|
57
58
|
|
58
59
|
engine_boots = engine_boots.value.to_i
|
59
60
|
engine_time = engine_time.value.to_i
|
@@ -65,6 +66,9 @@ module NETSNMP
|
|
65
66
|
|
66
67
|
log { "received response PDU" }
|
67
68
|
pdu = ScopedPDU.decode(encoded_pdu)
|
69
|
+
pdu.auth_param = auth_param
|
70
|
+
pdu.security_level = security_level
|
71
|
+
|
68
72
|
log(level: 2) { pdu.to_hex }
|
69
73
|
[pdu, engine_id.value, engine_boots, engine_time]
|
70
74
|
end
|
@@ -86,7 +90,7 @@ module NETSNMP
|
|
86
90
|
OpenSSL::ASN1::Integer.new(engine_boots).with_label(:engine_boots),
|
87
91
|
OpenSSL::ASN1::Integer.new(engine_time).with_label(:engine_time),
|
88
92
|
OpenSSL::ASN1::OctetString.new(security_parameters.username).with_label(:username),
|
89
|
-
|
93
|
+
authnone(security_parameters.auth_protocol),
|
90
94
|
salt_param
|
91
95
|
]).with_label(:security_params)
|
92
96
|
log(level: 2) { sec_params.to_hex }
|
@@ -115,10 +119,22 @@ module NETSNMP
|
|
115
119
|
log { "signing V3 message..." }
|
116
120
|
auth_salt = OpenSSL::ASN1::OctetString.new(signature).with_label(:auth)
|
117
121
|
log(level: 2) { auth_salt.to_hex }
|
118
|
-
|
122
|
+
none_der = authnone(security_parameters.auth_protocol).to_der
|
123
|
+
encoded[encoded.index(none_der), none_der.size] = auth_salt.to_der
|
119
124
|
log { Hexdump.dump(encoded) }
|
120
125
|
end
|
121
126
|
encoded
|
122
127
|
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
# https://datatracker.ietf.org/doc/html/rfc7860#section-4.2.2 part 3
|
132
|
+
# https://datatracker.ietf.org/doc/html/rfc3414#section-6.3.2 part 3
|
133
|
+
def authnone(auth_protocol)
|
134
|
+
# The digest in the msgAuthenticationParameters field is replaced by the 12 zero octets.
|
135
|
+
# 24 octets for sha256
|
136
|
+
number_of_octets = auth_protocol == :sha256 ? 24 : 12
|
137
|
+
OpenSSL::ASN1::OctetString.new("\x00" * number_of_octets).with_label(:auth_mask)
|
138
|
+
end
|
123
139
|
end
|
124
140
|
end
|
data/lib/netsnmp/mib.rb
CHANGED
@@ -33,7 +33,9 @@ module NETSNMP
|
|
33
33
|
if idx
|
34
34
|
mod = prefix[0..(idx - 1)]
|
35
35
|
type = prefix[(idx + 2)..-1]
|
36
|
-
|
36
|
+
unless module_loaded?(mod)
|
37
|
+
return unless load(mod)
|
38
|
+
end
|
37
39
|
else
|
38
40
|
type = prefix
|
39
41
|
end
|
@@ -84,6 +86,14 @@ module NETSNMP
|
|
84
86
|
true
|
85
87
|
end
|
86
88
|
|
89
|
+
def module_loaded?(mod)
|
90
|
+
if File.file?(mod)
|
91
|
+
@modules_loaded.include?(mod)
|
92
|
+
else
|
93
|
+
@modules_loaded.map { |path| File.basename(path, ".*") }.include?(mod)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
87
97
|
TYPES = ["OBJECT IDENTIFIER", "OBJECT-TYPE", "MODULE-IDENTITY"].freeze
|
88
98
|
|
89
99
|
STATIC_MIB_TO_OID = {
|
data/lib/netsnmp/pdu.rb
CHANGED
data/lib/netsnmp/scoped_pdu.rb
CHANGED
@@ -22,13 +22,13 @@ module NETSNMP
|
|
22
22
|
# The 150 Seconds is specified in https://www.ietf.org/rfc/rfc2574.txt 2.2.3
|
23
23
|
TIMELINESS_THRESHOLD = 150
|
24
24
|
|
25
|
-
attr_reader :security_level, :username
|
25
|
+
attr_reader :security_level, :username, :auth_protocol
|
26
26
|
attr_reader :engine_id
|
27
27
|
|
28
28
|
# @param [String] username the snmp v3 username
|
29
29
|
# @param [String] engine_id the device engine id (initialized to '' for report)
|
30
30
|
# @param [Symbol, integer] security_level allowed snmp v3 security level (:auth_priv, :auth_no_priv, etc)
|
31
|
-
# @param [Symbol, nil] auth_protocol a supported authentication protocol (currently supported: :md5, :sha)
|
31
|
+
# @param [Symbol, nil] auth_protocol a supported authentication protocol (currently supported: :md5, :sha, :sha256)
|
32
32
|
# @param [Symbol, nil] priv_protocol a supported privacy protocol (currently supported: :des, :aes)
|
33
33
|
# @param [String, nil] auth_password the authentication password
|
34
34
|
# @param [String, nil] priv_password the privacy password
|
@@ -110,6 +110,12 @@ module NETSNMP
|
|
110
110
|
|
111
111
|
key = auth_key.dup
|
112
112
|
|
113
|
+
# SHA256 => https://datatracker.ietf.org/doc/html/rfc7860#section-4.2.2
|
114
|
+
# The 24 first octets of HMAC are taken as the computed MAC value
|
115
|
+
return OpenSSL::HMAC.digest("SHA256", key, message)[0, 24] if @auth_protocol == :sha256
|
116
|
+
|
117
|
+
# MD5 => https://datatracker.ietf.org/doc/html/rfc3414#section-6.3.2
|
118
|
+
# SHA1 => https://datatracker.ietf.org/doc/html/rfc3414#section-7.3.2
|
113
119
|
key << "\x00" * (@auth_protocol == :md5 ? 48 : 44)
|
114
120
|
k1 = key.xor(IPAD)
|
115
121
|
k2 = key.xor(OPAD)
|
@@ -120,6 +126,7 @@ module NETSNMP
|
|
120
126
|
|
121
127
|
digest.reset
|
122
128
|
digest << (k2 + d1)
|
129
|
+
# The 12 first octets of the digest are taken as the computed MAC value
|
123
130
|
digest.digest[0, 12]
|
124
131
|
end
|
125
132
|
|
@@ -204,6 +211,7 @@ module NETSNMP
|
|
204
211
|
@digest ||= case @auth_protocol
|
205
212
|
when :md5 then OpenSSL::Digest::MD5.new
|
206
213
|
when :sha then OpenSSL::Digest::SHA1.new
|
214
|
+
when :sha256 then OpenSSL::Digest::SHA256.new
|
207
215
|
else
|
208
216
|
raise Error, "unsupported auth protocol: #{@auth_protocol}"
|
209
217
|
end
|
data/lib/netsnmp/session.rb
CHANGED
@@ -75,7 +75,7 @@ module NETSNMP
|
|
75
75
|
|
76
76
|
def initialize(host, port, timeout:)
|
77
77
|
@socket = UDPSocket.new
|
78
|
-
@
|
78
|
+
@destaddr = Socket.sockaddr_in(port, host)
|
79
79
|
@timeout = timeout
|
80
80
|
end
|
81
81
|
|
@@ -90,13 +90,13 @@ module NETSNMP
|
|
90
90
|
|
91
91
|
def write(payload)
|
92
92
|
perform_io do
|
93
|
-
@socket.
|
93
|
+
@socket.sendmsg(payload, Socket::MSG_DONTWAIT | Socket::MSG_NOSIGNAL, @destaddr)
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
97
|
def recv(bytesize = MAXPDUSIZE)
|
98
98
|
perform_io do
|
99
|
-
datagram, = @socket.
|
99
|
+
datagram, = @socket.recvmsg_nonblock(bytesize, Socket::MSG_DONTWAIT)
|
100
100
|
datagram
|
101
101
|
end
|
102
102
|
end
|
data/lib/netsnmp/v3_session.rb
CHANGED
@@ -24,14 +24,7 @@ module NETSNMP
|
|
24
24
|
log { "sending request..." }
|
25
25
|
encoded_request = encode(pdu)
|
26
26
|
encoded_response = @transport.send(encoded_request)
|
27
|
-
response_pdu, *
|
28
|
-
if response_pdu.type == 8
|
29
|
-
varbind = response_pdu.varbinds.first
|
30
|
-
if varbind.oid == "1.3.6.1.6.3.15.1.1.2.0" # IdNotInTimeWindow
|
31
|
-
_, @engine_boots, @engine_time = args
|
32
|
-
raise IdNotInTimeWindowError, "request timestamp is already out of time window"
|
33
|
-
end
|
34
|
-
end
|
27
|
+
response_pdu, * = decode(encoded_response)
|
35
28
|
response_pdu
|
36
29
|
end
|
37
30
|
|
@@ -85,7 +78,33 @@ module NETSNMP
|
|
85
78
|
end
|
86
79
|
|
87
80
|
def decode(stream, security_parameters: @security_parameters)
|
88
|
-
@message_serializer.decode(stream, security_parameters: security_parameters)
|
81
|
+
return_pdu = @message_serializer.decode(stream, security_parameters: security_parameters)
|
82
|
+
|
83
|
+
pdu, *args = return_pdu
|
84
|
+
|
85
|
+
# usmStats: http://oidref.com/1.3.6.1.6.3.15.1.1
|
86
|
+
if pdu.type == 8
|
87
|
+
case pdu.varbinds.first.oid
|
88
|
+
when "1.3.6.1.6.3.15.1.1.1.0" # usmStatsUnsupportedSecLevels
|
89
|
+
raise Error, "Unsupported security level"
|
90
|
+
when "1.3.6.1.6.3.15.1.1.2.0" # usmStatsNotInTimeWindows
|
91
|
+
_, @engine_boots, @engine_time = args
|
92
|
+
raise IdNotInTimeWindowError, "Not in time window"
|
93
|
+
when "1.3.6.1.6.3.15.1.1.3.0" # usmStatsUnknownUserNames
|
94
|
+
raise Error, "Unknown user name"
|
95
|
+
when "1.3.6.1.6.3.15.1.1.4.0" # usmStatsUnknownEngineIDs
|
96
|
+
raise Error, "Unknown engine ID" unless @security_parameters.must_revalidate?
|
97
|
+
when "1.3.6.1.6.3.15.1.1.5.0" # usmStatsWrongDigests
|
98
|
+
raise Error, "Authentication failure (incorrect password, community or key)"
|
99
|
+
when "1.3.6.1.6.3.15.1.1.6.0" # usmStatsDecryptionErrors
|
100
|
+
raise Error, "Decryption error"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# validate_authentication
|
105
|
+
@message_serializer.verify(stream, pdu.auth_param, pdu.security_level, security_parameters: @security_parameters)
|
106
|
+
|
107
|
+
return_pdu
|
89
108
|
end
|
90
109
|
end
|
91
110
|
end
|
data/lib/netsnmp/version.rb
CHANGED
data/sig/message.rbs
CHANGED
@@ -2,8 +2,14 @@ module NETSNMP
|
|
2
2
|
class Message
|
3
3
|
prepend Loggable
|
4
4
|
|
5
|
+
def verify: (String stream, String auth_param, Integer? security_level, security_parameters: SecurityParameters) -> void
|
6
|
+
|
5
7
|
def decode: (String stream, security_parameters: SecurityParameters) -> [ScopedPDU, String, Integer, Integer]
|
6
8
|
|
7
9
|
def encode: (ScopedPDU pdu, security_parameters: SecurityParameters, ?engine_boots: Integer, ?engine_time: Integer) -> String
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def authnone: (SecurityParameters::auth_protocol?) -> OpenSSL::ASN1::ASN1Data
|
8
14
|
end
|
9
15
|
end
|
data/sig/scoped_pdu.rbs
CHANGED
data/sig/security_parameters.rbs
CHANGED
@@ -4,11 +4,10 @@ module NETSNMP
|
|
4
4
|
|
5
5
|
type security_level = :noauth | :auth_no_priv | :auth_priv | 0 | 1 | 3 | nil
|
6
6
|
|
7
|
-
type auth_protocol = :md5 | :sha
|
7
|
+
type auth_protocol = :md5 | :sha | :sha256
|
8
8
|
type priv_protocol = :des | :aes
|
9
9
|
|
10
10
|
|
11
|
-
@auth_protocol: auth_protocol?
|
12
11
|
@auth_password: String?
|
13
12
|
@priv_protocol: priv_protocol?
|
14
13
|
@priv_password: String?
|
@@ -18,6 +17,7 @@ module NETSNMP
|
|
18
17
|
attr_reader security_level: security_level
|
19
18
|
attr_reader username: String
|
20
19
|
attr_reader engine_id: String
|
20
|
+
attr_reader auth_protocol: auth_protocol?
|
21
21
|
|
22
22
|
def engine_id=: (String id) -> void
|
23
23
|
|
data/spec/client_spec.rb
CHANGED
@@ -23,19 +23,19 @@ RSpec.describe NETSNMP::Client do
|
|
23
23
|
let(:next_oid) { "1.3.6.1.2.1.1.6.0" }
|
24
24
|
let(:walk_oid) { "1.3.6.1.2.1.1" }
|
25
25
|
let(:set_oid) { "sysUpTime.0" } # sysUpTimeInstance
|
26
|
-
let(:get_result) { "
|
27
|
-
let(:next_result) { "
|
26
|
+
let(:get_result) { "zeus.snmplabs.com (you can change this!)" }
|
27
|
+
let(:next_result) { "San Francisco, California, United States" }
|
28
28
|
let(:walk_result) do
|
29
|
-
|
30
|
-
1.3.6.1.2.1.1.1.0:
|
31
|
-
1.3.6.1.2.1.1.2.0
|
32
|
-
1.3.6.1.2.1.1.3.0
|
33
|
-
1.3.6.1.2.1.1.4.0
|
34
|
-
1.3.6.1.2.1.1.5.0
|
35
|
-
1.3.6.1.2.1.1.6.0
|
36
|
-
1.3.6.1.2.1.1.7.0
|
37
|
-
1.3.6.1.2.1.1.8.0
|
38
|
-
|
29
|
+
{
|
30
|
+
"1.3.6.1.2.1.1.1.0" => "Linux zeus 4.8.6.5-smp #2 SMP Sun Nov 13 14:58:11 CDT 2016 i686",
|
31
|
+
"1.3.6.1.2.1.1.2.0" => "1.3.6.1.4.1.8072.3.2.10",
|
32
|
+
"1.3.6.1.2.1.1.3.0" => /Timeticks: \(\d+\) \d+ days, \d+:\d+:\d+\.\d+/,
|
33
|
+
"1.3.6.1.2.1.1.4.0" => "SNMP Laboratories, info@snmplabs.com",
|
34
|
+
"1.3.6.1.2.1.1.5.0" => "zeus.snmplabs.com (you can change this!)",
|
35
|
+
"1.3.6.1.2.1.1.6.0" => "San Francisco, California, United States",
|
36
|
+
"1.3.6.1.2.1.1.7.0" => "72",
|
37
|
+
"1.3.6.1.2.1.1.8.0" => /Timeticks: \(\d+\) \d+ days, \d+:\d+:\d+\.\d+/
|
38
|
+
}
|
39
39
|
end
|
40
40
|
let(:set_oid_result) { 43 }
|
41
41
|
end
|
@@ -52,19 +52,19 @@ RSpec.describe NETSNMP::Client do
|
|
52
52
|
let(:next_oid) { "1.3.6.1.2.1.1.6.0" }
|
53
53
|
let(:walk_oid) { "system" }
|
54
54
|
let(:set_oid) { "sysUpTime.0" }
|
55
|
-
let(:get_result) { "
|
56
|
-
let(:next_result) { "
|
55
|
+
let(:get_result) { "zeus.snmplabs.com (you can change this!)" }
|
56
|
+
let(:next_result) { "San Francisco, California, United States" }
|
57
57
|
let(:walk_result) do
|
58
|
-
|
59
|
-
1.3.6.1.2.1.1.1.0:
|
60
|
-
1.3.6.1.2.1.1.2.0
|
61
|
-
1.3.6.1.2.1.1.3.0
|
62
|
-
1.3.6.1.2.1.1.4.0
|
63
|
-
1.3.6.1.2.1.1.5.0
|
64
|
-
1.3.6.1.2.1.1.6.0
|
65
|
-
1.3.6.1.2.1.1.7.0
|
66
|
-
1.3.6.1.2.1.1.8.0
|
67
|
-
|
58
|
+
{
|
59
|
+
"1.3.6.1.2.1.1.1.0" => "Linux zeus 4.8.6.5-smp #2 SMP Sun Nov 13 14:58:11 CDT 2016 i686",
|
60
|
+
"1.3.6.1.2.1.1.2.0" => "1.3.6.1.4.1.8072.3.2.10",
|
61
|
+
"1.3.6.1.2.1.1.3.0" => /Timeticks: \(\d+\) \d+ days, \d+:\d+:\d+\.\d+/,
|
62
|
+
"1.3.6.1.2.1.1.4.0" => "SNMP Laboratories, info@snmplabs.com",
|
63
|
+
"1.3.6.1.2.1.1.5.0" => "zeus.snmplabs.com (you can change this!)",
|
64
|
+
"1.3.6.1.2.1.1.6.0" => "San Francisco, California, United States",
|
65
|
+
"1.3.6.1.2.1.1.7.0" => "72",
|
66
|
+
"1.3.6.1.2.1.1.8.0" => /Timeticks: \(\d+\) \d+ days, \d+:\d+:\d+\.\d+/
|
67
|
+
}
|
68
68
|
end
|
69
69
|
let(:set_oid_result) { 43 }
|
70
70
|
|
@@ -101,18 +101,18 @@ RSpec.describe NETSNMP::Client do
|
|
101
101
|
let(:set_oid) { "sysUpTime.0" } # sysUpTimeInstance
|
102
102
|
let(:walk_oid) { "1.3.6.1.2.1.1.9.1.3" }
|
103
103
|
let(:get_result) { "tt" }
|
104
|
-
let(:next_result) { "KK12" }
|
104
|
+
let(:next_result) { "KK12 (edit /etc/snmp/snmpd.conf)" }
|
105
105
|
let(:walk_result) do
|
106
|
-
|
107
|
-
1.3.6.1.2.1.1.9.1.3.1
|
108
|
-
1.3.6.1.2.1.1.9.1.3.2
|
109
|
-
1.3.6.1.2.1.1.9.1.3.3
|
110
|
-
1.3.6.1.2.1.1.9.1.3.4
|
111
|
-
1.3.6.1.2.1.1.9.1.3.5
|
112
|
-
1.3.6.1.2.1.1.9.1.3.6
|
113
|
-
1.3.6.1.2.1.1.9.1.3.7
|
114
|
-
1.3.6.1.2.1.1.9.1.3.8
|
115
|
-
|
106
|
+
{
|
107
|
+
"1.3.6.1.2.1.1.9.1.3.1" => "The SNMP Management Architecture MIB.",
|
108
|
+
"1.3.6.1.2.1.1.9.1.3.2" => "The MIB for Message Processing and Dispatching.",
|
109
|
+
"1.3.6.1.2.1.1.9.1.3.3" => "The management information definitions for the SNMP User-based Security Model.",
|
110
|
+
"1.3.6.1.2.1.1.9.1.3.4" => "The MIB module for SNMPv2 entities",
|
111
|
+
"1.3.6.1.2.1.1.9.1.3.5" => "The MIB module for managing TCP implementations",
|
112
|
+
"1.3.6.1.2.1.1.9.1.3.6" => "The MIB module for managing IP and ICMP implementations",
|
113
|
+
"1.3.6.1.2.1.1.9.1.3.7" => "The MIB module for managing UDP implementations",
|
114
|
+
"1.3.6.1.2.1.1.9.1.3.8" => "View-based Access Control Model for SNMP."
|
115
|
+
}
|
116
116
|
end
|
117
117
|
let(:set_oid_result) { 43 }
|
118
118
|
context "with a no auth no priv policy" do
|
@@ -157,6 +157,15 @@ RSpec.describe NETSNMP::Client do
|
|
157
157
|
let(:protocol_options) { version_options.merge(user_options).merge(extra_options) }
|
158
158
|
end
|
159
159
|
end
|
160
|
+
context "speaking sha256" do
|
161
|
+
let(:user_options) do
|
162
|
+
{ username: "authsha256", security_level: :auth_no_priv,
|
163
|
+
auth_password: "maplesyrup", auth_protocol: :sha256 }
|
164
|
+
end
|
165
|
+
it_behaves_like "an snmp client" do
|
166
|
+
let(:protocol_options) { version_options.merge(user_options).merge(extra_options) }
|
167
|
+
end
|
168
|
+
end
|
160
169
|
end
|
161
170
|
context "with an auth priv policy" do
|
162
171
|
context "auth in md5, encrypting in des" do
|
@@ -177,6 +186,18 @@ RSpec.describe NETSNMP::Client do
|
|
177
186
|
end
|
178
187
|
it_behaves_like "an snmp client" do
|
179
188
|
let(:protocol_options) { version_options.merge(user_options).merge(extra_options) }
|
189
|
+
|
190
|
+
context "with wrong auth password and wrong encrypting password" do
|
191
|
+
let(:user_options) do
|
192
|
+
{ username: "authprivmd5des", auth_password: "wrongpassword",
|
193
|
+
auth_protocol: :md5, priv_password: "maplesyrup",
|
194
|
+
priv_protocol: :des }
|
195
|
+
end
|
196
|
+
let(:protocol_options) { version_options.merge(user_options).merge(extra_options) }
|
197
|
+
it "raises authentication error" do
|
198
|
+
expect { subject.get(oid: get_oid) }.to raise_error(NETSNMP::Error, "Authentication failure (incorrect password, community or key)")
|
199
|
+
end
|
200
|
+
end
|
180
201
|
end
|
181
202
|
end
|
182
203
|
|
@@ -4,7 +4,7 @@ require "celluloid/io"
|
|
4
4
|
require_relative "../support/request_examples"
|
5
5
|
require_relative "../support/celluloid"
|
6
6
|
|
7
|
-
RSpec.describe "with cellulloid", type: :celluloid
|
7
|
+
RSpec.describe "with cellulloid", type: :celluloid do
|
8
8
|
include CelluloidHelpers
|
9
9
|
let(:user_options) do
|
10
10
|
{ username: "authprivmd5des", auth_password: "maplesyrup",
|
@@ -17,18 +17,18 @@ RSpec.describe "with cellulloid", type: :celluloid, if: RUBY_ENGINE == "truffler
|
|
17
17
|
let(:set_oid) { "1.3.6.1.2.1.1.3.0" } # sysUpTimeInstance
|
18
18
|
let(:walk_oid) { "1.3.6.1.2.1.1.9.1.3" }
|
19
19
|
let(:get_result) { "tt" }
|
20
|
-
let(:next_result) { "KK12" }
|
20
|
+
let(:next_result) { "KK12 (edit /etc/snmp/snmpd.conf)" }
|
21
21
|
let(:walk_result) do
|
22
|
-
|
23
|
-
1.3.6.1.2.1.1.9.1.3.1
|
24
|
-
1.3.6.1.2.1.1.9.1.3.2
|
25
|
-
1.3.6.1.2.1.1.9.1.3.3
|
26
|
-
1.3.6.1.2.1.1.9.1.3.4
|
27
|
-
1.3.6.1.2.1.1.9.1.3.5
|
28
|
-
1.3.6.1.2.1.1.9.1.3.6
|
29
|
-
1.3.6.1.2.1.1.9.1.3.7
|
30
|
-
1.3.6.1.2.1.1.9.1.3.8
|
31
|
-
|
22
|
+
{
|
23
|
+
"1.3.6.1.2.1.1.9.1.3.1" => "The SNMP Management Architecture MIB.",
|
24
|
+
"1.3.6.1.2.1.1.9.1.3.2" => "The MIB for Message Processing and Dispatching.",
|
25
|
+
"1.3.6.1.2.1.1.9.1.3.3" => "The management information definitions for the SNMP User-based Security Model.",
|
26
|
+
"1.3.6.1.2.1.1.9.1.3.4" => "The MIB module for SNMPv2 entities",
|
27
|
+
"1.3.6.1.2.1.1.9.1.3.5" => "The MIB module for managing TCP implementations",
|
28
|
+
"1.3.6.1.2.1.1.9.1.3.6" => "The MIB module for managing IP and ICMP implementations",
|
29
|
+
"1.3.6.1.2.1.1.9.1.3.7" => "The MIB module for managing UDP implementations",
|
30
|
+
"1.3.6.1.2.1.1.9.1.3.8" => "View-based Access Control Model for SNMP."
|
31
|
+
}
|
32
32
|
end
|
33
33
|
|
34
34
|
before(:all) { Celluloid.boot }
|
@@ -13,6 +13,13 @@ RSpec.describe NETSNMP::SecurityParameters do
|
|
13
13
|
subject { described_class.new(security_level: :auth_priv, auth_protocol: :sha, username: "username", engine_id: engine_id, auth_password: "maplesyrup", priv_password: "maplesyrup") }
|
14
14
|
it { expect(subject.send(:passkey, password).b).to eq("\x9f\xb5\xcc\x03\x81\x49\x7b\x37\x93\x52\x89\x39\xff\x78\x8d\x5d\x79\x14\x52\x11".b) }
|
15
15
|
end
|
16
|
+
context "sha256" do
|
17
|
+
subject do
|
18
|
+
described_class.new(security_level: :auth_priv, auth_protocol: :sha256, username: "username", engine_id: engine_id, auth_password: "maplesyrup", priv_password: "maplesyrup")
|
19
|
+
end
|
20
|
+
|
21
|
+
it { expect(subject.send(:passkey, password).b).to eq("\xABQ\x01M\x1E\a\x7F`\x17\xDF+\x12\xBE\xE5\xF5\xAAr\x991w\xE9\xBBV\x9CM\xFFZL\xA0\xB4\xAF\xAC".b) }
|
22
|
+
end
|
16
23
|
end
|
17
24
|
|
18
25
|
describe "keys" do
|
@@ -34,11 +41,22 @@ RSpec.describe NETSNMP::SecurityParameters do
|
|
34
41
|
priv_password: password,
|
35
42
|
engine_id: engine_id)
|
36
43
|
end
|
44
|
+
let(:sha256_sec) do
|
45
|
+
described_class.new(security_level: :auth_priv,
|
46
|
+
auth_protocol: :sha256,
|
47
|
+
priv_protocol: :des,
|
48
|
+
username: "username",
|
49
|
+
auth_password: password,
|
50
|
+
priv_password: password,
|
51
|
+
engine_id: engine_id)
|
52
|
+
end
|
37
53
|
it do
|
38
54
|
expect(md5_sec.send(:auth_key)).to eq("\x52\x6f\x5e\xed\x9f\xcc\xe2\x6f\x89\x64\xc2\x93\x07\x87\xd8\x2b".b)
|
39
55
|
expect(md5_sec.send(:priv_key)).to eq("\x52\x6f\x5e\xed\x9f\xcc\xe2\x6f\x89\x64\xc2\x93\x07\x87\xd8\x2b".b)
|
40
56
|
expect(sha_sec.send(:auth_key)).to eq("\x66\x95\xfe\xbc\x92\x88\xe3\x62\x82\x23\x5f\xc7\x15\x1f\x12\x84\x97\xb3\x8f\x3f".b)
|
41
57
|
expect(sha_sec.send(:priv_key)).to eq("\x66\x95\xfe\xbc\x92\x88\xe3\x62\x82\x23\x5f\xc7\x15\x1f\x12\x84\x97\xb3\x8f\x3f".b)
|
58
|
+
expect(sha256_sec.send(:auth_key)).to eq("\x89\x82\xE0\xE5I\xE8f\xDB6\x1Akb]\x84\xCC\xCC\x11\x16-E>\xE8\xCE:dE\xC2\xD6wo\x0F\x8B".b)
|
59
|
+
expect(sha256_sec.send(:priv_key)).to eq("\x89\x82\xE0\xE5I\xE8f\xDB6\x1Akb]\x84\xCC\xCC\x11\x16-E>\xE8\xCE:dE\xC2\xD6wo\x0F\x8B".b)
|
42
60
|
end
|
43
61
|
end
|
44
62
|
|
data/spec/support/celluloid.rb
CHANGED
@@ -26,7 +26,7 @@ module CelluloidHelpers
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
class Proxy
|
29
|
+
class Proxy
|
30
30
|
MAXPDUSIZE = 0xffff + 1
|
31
31
|
|
32
32
|
def initialize(host, port)
|
@@ -35,18 +35,22 @@ module CelluloidHelpers
|
|
35
35
|
@timeout = 2
|
36
36
|
end
|
37
37
|
|
38
|
-
def
|
39
|
-
@socket.
|
38
|
+
def send(payload)
|
39
|
+
@socket.send(payload, 0)
|
40
|
+
recv
|
40
41
|
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
def wait(mode)
|
43
|
+
def recv(bytesize = MAXPDUSIZE)
|
45
44
|
Celluloid.timeout(@timeout) do
|
46
|
-
@socket.
|
45
|
+
datagram, = @socket.recvfrom(bytesize)
|
46
|
+
datagram
|
47
47
|
end
|
48
48
|
rescue Celluloid::TaskTimeout
|
49
49
|
raise Timeout::Error, "Timeout after #{@timeout} seconds"
|
50
50
|
end
|
51
|
+
|
52
|
+
def close
|
53
|
+
@socket.close
|
54
|
+
end
|
51
55
|
end
|
52
56
|
end
|
@@ -22,8 +22,8 @@ RSpec.shared_examples "an snmp client" do
|
|
22
22
|
let(:value) { subject.get({ oid: get_oid }, oid: next_oid) }
|
23
23
|
it "returns the values for both" do
|
24
24
|
expect(value).to be_a(Array)
|
25
|
-
expect(value).to include(
|
26
|
-
expect(value).to include(
|
25
|
+
expect(value).to include(get_result)
|
26
|
+
expect(value).to include(next_result)
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -40,8 +40,17 @@ RSpec.shared_examples "an snmp client" do
|
|
40
40
|
describe "#walk" do
|
41
41
|
let(:value) { subject.walk(oid: walk_oid) }
|
42
42
|
it "fetches the varbinds for the next oid" do
|
43
|
-
|
44
|
-
|
43
|
+
value.each do |oid, val|
|
44
|
+
match = walk_result[oid]
|
45
|
+
case match
|
46
|
+
when String
|
47
|
+
expect(val.to_s).to eq(match)
|
48
|
+
when Regexp
|
49
|
+
expect(val.to_s).to match(match)
|
50
|
+
else
|
51
|
+
next
|
52
|
+
end
|
53
|
+
end
|
45
54
|
end
|
46
55
|
end
|
47
56
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: netsnmp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tiago Cardoso
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-07-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parslet
|
@@ -104,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
104
|
version: '0'
|
105
105
|
requirements:
|
106
106
|
- net-snmp
|
107
|
-
rubygems_version: 3.2.
|
107
|
+
rubygems_version: 3.2.15
|
108
108
|
signing_key:
|
109
109
|
specification_version: 4
|
110
110
|
summary: SNMP Client library
|