netsnmp 0.4.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|