netsnmp 0.3.0 → 0.4.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 +18 -3
- data/lib/netsnmp.rb +2 -44
- data/lib/netsnmp/client.rb +1 -1
- data/lib/netsnmp/encryption/aes.rb +1 -3
- data/lib/netsnmp/encryption/des.rb +0 -2
- data/lib/netsnmp/errors.rb +1 -0
- data/lib/netsnmp/extensions.rb +113 -0
- data/lib/netsnmp/loggable.rb +36 -0
- data/lib/netsnmp/message.rb +70 -28
- data/lib/netsnmp/mib.rb +38 -27
- data/lib/netsnmp/pdu.rb +19 -8
- data/lib/netsnmp/scoped_pdu.rb +6 -2
- data/lib/netsnmp/security_parameters.rb +19 -11
- data/lib/netsnmp/session.rb +10 -1
- data/lib/netsnmp/v3_session.rb +17 -7
- data/lib/netsnmp/varbind.rb +11 -12
- data/lib/netsnmp/version.rb +1 -1
- data/sig/loggable.rbs +16 -0
- data/sig/message.rbs +5 -3
- data/sig/mib.rbs +4 -1
- data/sig/netsnmp.rbs +0 -4
- data/sig/pdu.rbs +1 -1
- data/sig/security_parameters.rbs +4 -2
- data/sig/session.rbs +2 -0
- data/spec/client_spec.rb +18 -0
- data/spec/spec_helper.rb +0 -1
- data/spec/varbind_spec.rb +5 -3
- metadata +13 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60a9c68e56e5ad0600d056eedd315d8639cfd3965aa5e1eb62f5f3f935b4ad6a
|
4
|
+
data.tar.gz: ea560ac1131bff9ca6af0fec5e426bd37edbfbc7520ceb629f1de279a905ced0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8410a3a38d7d7eab07692009ae4d870dbae8e7abc50dbc724d9ad3f8a4e029b441ffba62e9477ae587f8845a561cb0ba2e2c5613540d615bdce0cf62cb448098
|
7
|
+
data.tar.gz: 85d0d898983f99dedb4a71cf6bd33f665cfda496bb8a60eb76be36a96de6f28a9984505c564701bfab6bf74e8367544ec2f5adbcf8faf152d9a71679b73b5df1
|
data/README.md
CHANGED
@@ -32,7 +32,7 @@ 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
34
|
* Client/Manager API with simple interface for get, genext, set and walk.
|
35
|
-
*
|
35
|
+
* Pure Ruby.
|
36
36
|
* Support for concurrency and evented I/O.
|
37
37
|
|
38
38
|
## Why?
|
@@ -54,11 +54,12 @@ All of these issues are resolved here.
|
|
54
54
|
## Features
|
55
55
|
|
56
56
|
* Client Interface, which supports SNMP v3, v2c, and v1
|
57
|
-
* Supports get, getnext, set and walk calls
|
58
|
-
* MIB support
|
57
|
+
* Supports get, getnext, set and walk calls
|
58
|
+
* MIB support
|
59
59
|
* Proxy IO object support (for eventmachine/celluloid-io)
|
60
60
|
* Ruby >= 2.1 support (modern)
|
61
61
|
* Pure Ruby (no FFI)
|
62
|
+
* Easy PDU debugging
|
62
63
|
|
63
64
|
## Examples
|
64
65
|
|
@@ -236,10 +237,24 @@ NETSNMP::Client.new(share_options.merge(proxy: router_proxy, security_parameters
|
|
236
237
|
end
|
237
238
|
```
|
238
239
|
|
240
|
+
## Compatibility
|
241
|
+
|
242
|
+
This library supports and is tested against ruby versions 2.1 or more recent, including ruby 3. It also supports and tests against Truffleruby.
|
243
|
+
|
239
244
|
## OpenSSL
|
240
245
|
|
241
246
|
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.
|
242
247
|
|
248
|
+
## Debugging
|
249
|
+
|
250
|
+
You can either set the `NETSNMP_DEBUG` to the desided debug level (currently, 1 and 2). The logs will be written to stderr.
|
251
|
+
|
252
|
+
You can also set it for a specific client:
|
253
|
+
|
254
|
+
```ruby
|
255
|
+
manager2 = NETSNMP::Client.new(debug: $stderr, debug_level: 2, ....)
|
256
|
+
```
|
257
|
+
|
243
258
|
|
244
259
|
## Tests
|
245
260
|
|
data/lib/netsnmp.rb
CHANGED
@@ -33,51 +33,9 @@ rescue LoadError
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
module NETSNMP
|
37
|
-
module IsNumericExtensions
|
38
|
-
refine String do
|
39
|
-
def integer?
|
40
|
-
each_byte do |byte|
|
41
|
-
return false unless byte >= 48 && byte <= 57
|
42
|
-
end
|
43
|
-
true
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
module StringExtensions
|
49
|
-
# If you wonder why this is there: the oauth feature uses a refinement to enhance the
|
50
|
-
# Regexp class locally with #match? , but this is never tested, because ActiveSupport
|
51
|
-
# monkey-patches the same method... Please ActiveSupport, stop being so intrusive!
|
52
|
-
# :nocov:
|
53
|
-
refine(String) do
|
54
|
-
def match?(*args)
|
55
|
-
!match(*args).nil?
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.debug=(io)
|
61
|
-
@debug_output = io
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.debug(&blk)
|
65
|
-
@debug_output << blk.call + "\n" if @debug_output
|
66
|
-
end
|
67
|
-
|
68
|
-
unless defined?(Hexdump) # support the hexdump gem
|
69
|
-
module Hexdump
|
70
|
-
def self.dump(data, width: 8)
|
71
|
-
pairs = data.unpack("H*").first.scan(/.{4}/)
|
72
|
-
pairs.each_slice(width).map do |row|
|
73
|
-
row.join(" ")
|
74
|
-
end.join("\n")
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
36
|
require "netsnmp/errors"
|
37
|
+
require "netsnmp/extensions"
|
38
|
+
require "netsnmp/loggable"
|
81
39
|
|
82
40
|
require "netsnmp/timeticks"
|
83
41
|
|
data/lib/netsnmp/client.rb
CHANGED
@@ -22,13 +22,12 @@ module NETSNMP
|
|
22
22
|
end
|
23
23
|
|
24
24
|
encrypted_data = cipher.update(decrypted_data) + cipher.final
|
25
|
-
NETSNMP.debug { "encrypted:\n#{Hexdump.dump(encrypted_data)}" }
|
26
25
|
|
27
26
|
[encrypted_data, salt]
|
28
27
|
end
|
29
28
|
|
30
29
|
def decrypt(encrypted_data, salt:, engine_boots:, engine_time:)
|
31
|
-
raise Error, "invalid priv salt received" unless (salt.length % 8).zero?
|
30
|
+
raise Error, "invalid priv salt received" unless !salt.empty? && (salt.length % 8).zero?
|
32
31
|
|
33
32
|
cipher = OpenSSL::Cipher::AES128.new(:CFB)
|
34
33
|
cipher.padding = 0
|
@@ -39,7 +38,6 @@ module NETSNMP
|
|
39
38
|
cipher.key = aes_key
|
40
39
|
cipher.iv = iv
|
41
40
|
decrypted_data = cipher.update(encrypted_data) + cipher.final
|
42
|
-
NETSNMP.debug { "decrypted:\n#{Hexdump.dump(decrypted_data)}" }
|
43
41
|
|
44
42
|
hlen, bodylen = OpenSSL::ASN1.traverse(decrypted_data) { |_, _, x, y, *| break x, y }
|
45
43
|
decrypted_data.byteslice(0, hlen + bodylen)
|
@@ -24,7 +24,6 @@ module NETSNMP
|
|
24
24
|
end
|
25
25
|
|
26
26
|
encrypted_data = cipher.update(decrypted_data) + cipher.final
|
27
|
-
NETSNMP.debug { "encrypted:\n#{Hexdump.dump(encrypted_data)}" }
|
28
27
|
[encrypted_data, salt]
|
29
28
|
end
|
30
29
|
|
@@ -41,7 +40,6 @@ module NETSNMP
|
|
41
40
|
cipher.key = des_key
|
42
41
|
cipher.iv = iv
|
43
42
|
decrypted_data = cipher.update(encrypted_data) + cipher.final
|
44
|
-
NETSNMP.debug { "decrypted:\n#{Hexdump.dump(decrypted_data)}" }
|
45
43
|
|
46
44
|
hlen, bodylen = OpenSSL::ASN1.traverse(decrypted_data) { |_, _, x, y, *| break x, y }
|
47
45
|
decrypted_data.byteslice(0, hlen + bodylen)
|
data/lib/netsnmp/errors.rb
CHANGED
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NETSNMP
|
4
|
+
module IsNumericExtensions
|
5
|
+
refine String do
|
6
|
+
def integer?
|
7
|
+
each_byte do |byte|
|
8
|
+
return false unless byte >= 48 && byte <= 57
|
9
|
+
end
|
10
|
+
true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module StringExtensions
|
16
|
+
refine(String) do
|
17
|
+
unless String.method_defined?(:match?)
|
18
|
+
def match?(*args)
|
19
|
+
!match(*args).nil?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
unless String.method_defined?(:unpack1)
|
24
|
+
def unpack1(format)
|
25
|
+
unpack(format).first
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module ASNExtensions
|
32
|
+
ASN_COLORS = {
|
33
|
+
OpenSSL::ASN1::Sequence => 34, # blue
|
34
|
+
OpenSSL::ASN1::OctetString => 32, # green
|
35
|
+
OpenSSL::ASN1::Integer => 33, # yellow
|
36
|
+
OpenSSL::ASN1::ObjectId => 35, # magenta
|
37
|
+
OpenSSL::ASN1::ASN1Data => 36 # cyan
|
38
|
+
}.freeze
|
39
|
+
|
40
|
+
# basic types
|
41
|
+
ASN_COLORS.each_key do |klass|
|
42
|
+
refine(klass) do
|
43
|
+
def to_hex
|
44
|
+
"#{colorize_hex} (#{value.to_s.inspect})"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# composite types
|
50
|
+
refine(OpenSSL::ASN1::Sequence) do
|
51
|
+
def to_hex
|
52
|
+
values = value.map(&:to_der).join
|
53
|
+
hex_values = value.map(&:to_hex).map { |s| s.gsub(/(\t+)/) { "\t#{Regexp.last_match(1)}" } }.map { |s| "\n\t#{s}" }.join
|
54
|
+
der = to_der
|
55
|
+
der = der.sub(values, "")
|
56
|
+
|
57
|
+
"#{colorize_hex(der)}#{hex_values}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
refine(OpenSSL::ASN1::ASN1Data) do
|
62
|
+
attr_reader :label
|
63
|
+
|
64
|
+
def with_label(label)
|
65
|
+
@label = label
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_hex
|
70
|
+
case value
|
71
|
+
when Array
|
72
|
+
values = value.map(&:to_der).join
|
73
|
+
hex_values = value.map(&:to_hex)
|
74
|
+
.map { |s| s.gsub(/(\t+)/) { "\t#{Regexp.last_match(1)}" } }
|
75
|
+
.map { |s| "\n\t#{s}" }.join
|
76
|
+
der = to_der
|
77
|
+
der = der.sub(values, "")
|
78
|
+
else
|
79
|
+
der = to_der
|
80
|
+
hex_values = nil
|
81
|
+
end
|
82
|
+
|
83
|
+
"#{colorize_hex(der)}#{hex_values}"
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def colorize_hex(der = to_der)
|
89
|
+
hex = Hexdump.dump(der, separator: " ")
|
90
|
+
lbl = @label || self.class.name.split("::").last
|
91
|
+
"#{lbl}: \e[#{ASN_COLORS[self.class]}m#{hex}\e[0m"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
module Hexdump
|
97
|
+
using StringExtensions
|
98
|
+
|
99
|
+
def self.dump(data, width: 8, in_groups_of: 4, separator: "\n")
|
100
|
+
pairs = data.unpack1("H*").scan(/.{#{in_groups_of}}/)
|
101
|
+
pairs.each_slice(width).map do |row|
|
102
|
+
row.join(" ")
|
103
|
+
end.join(separator)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Like a string, but it prints an hex-string version of itself
|
108
|
+
class HexString < String
|
109
|
+
def inspect
|
110
|
+
Hexdump.dump(self, in_groups_of: 2, separator: " ")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NETSNMP
|
4
|
+
module Loggable
|
5
|
+
DEBUG = ENV.key?("NETSNMP_DEBUG") ? $stderr : nil
|
6
|
+
DEBUG_LEVEL = (ENV["NETSNMP_DEBUG"] || 1).to_i
|
7
|
+
|
8
|
+
def initialize(debug: DEBUG, debug_level: DEBUG_LEVEL, **opts)
|
9
|
+
super(**opts)
|
10
|
+
@debug = debug
|
11
|
+
@debug_level = debug_level
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
COLORS = {
|
17
|
+
black: 30,
|
18
|
+
red: 31,
|
19
|
+
green: 32,
|
20
|
+
yellow: 33,
|
21
|
+
blue: 34,
|
22
|
+
magenta: 35,
|
23
|
+
cyan: 36,
|
24
|
+
white: 37
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
def log(level: @debug_level)
|
28
|
+
return unless @debug
|
29
|
+
return unless @debug_level >= level
|
30
|
+
|
31
|
+
debug_stream = @debug
|
32
|
+
|
33
|
+
debug_stream << (+"\n" << yield << "\n")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/netsnmp/message.rb
CHANGED
@@ -2,41 +2,71 @@
|
|
2
2
|
|
3
3
|
module NETSNMP
|
4
4
|
# Factory for the SNMP v3 Message format
|
5
|
-
|
6
|
-
|
5
|
+
class Message
|
6
|
+
using ASNExtensions
|
7
7
|
|
8
|
-
|
8
|
+
prepend Loggable
|
9
|
+
|
10
|
+
AUTHNONE = OpenSSL::ASN1::OctetString.new("\x00" * 12).with_label(:auth_mask)
|
9
11
|
PRIVNONE = OpenSSL::ASN1::OctetString.new("")
|
10
|
-
MSG_MAX_SIZE = OpenSSL::ASN1::Integer.new(65507)
|
11
|
-
MSG_SECURITY_MODEL = OpenSSL::ASN1::Integer.new(3) # usmSecurityModel
|
12
|
-
MSG_VERSION = OpenSSL::ASN1::Integer.new(3)
|
12
|
+
MSG_MAX_SIZE = OpenSSL::ASN1::Integer.new(65507).with_label(:max_message_size)
|
13
|
+
MSG_SECURITY_MODEL = OpenSSL::ASN1::Integer.new(3).with_label(:security_model) # usmSecurityModel
|
14
|
+
MSG_VERSION = OpenSSL::ASN1::Integer.new(3).with_label(:message_version)
|
13
15
|
MSG_REPORTABLE = 4
|
14
16
|
|
17
|
+
def initialize(**); end
|
18
|
+
|
15
19
|
# @param [String] payload of an snmp v3 message which can be decoded
|
16
20
|
# @param [NETSMP::SecurityParameters, #decode] security_parameters knowns how to decode the stream
|
17
21
|
#
|
18
22
|
# @return [NETSNMP::ScopedPDU] the decoded PDU
|
19
23
|
#
|
20
24
|
def decode(stream, security_parameters:)
|
21
|
-
|
22
|
-
|
25
|
+
log { "received encoded V3 message" }
|
26
|
+
log { Hexdump.dump(stream) }
|
27
|
+
asn_tree = OpenSSL::ASN1.decode(stream).with_label(:v3_message)
|
28
|
+
|
29
|
+
version, headers, sec_params, pdu_payload = asn_tree.value
|
30
|
+
version.with_label(:message_version)
|
31
|
+
headers.with_label(:headers)
|
32
|
+
sec_params.with_label(:security_params)
|
33
|
+
pdu_payload.with_label(:pdu)
|
34
|
+
|
35
|
+
_, _, message_flags, = headers.value
|
23
36
|
|
24
|
-
|
37
|
+
# get last byte
|
38
|
+
# discard the left-outermost bits and keep the remaining two
|
39
|
+
security_level = message_flags.with_label(:message_flags).value.unpack("C*").last & 3
|
25
40
|
|
26
|
-
|
41
|
+
sec_params_asn = OpenSSL::ASN1.decode(sec_params.value).with_label(:security_params)
|
42
|
+
|
43
|
+
engine_id, engine_boots, engine_time, username, auth_param, priv_param = sec_params_asn.value
|
44
|
+
engine_id.with_label(:engine_id)
|
45
|
+
engine_boots.with_label(:engine_boots)
|
46
|
+
engine_time.with_label(:engine_time)
|
47
|
+
username.with_label(:username)
|
48
|
+
auth_param.with_label(:auth_param)
|
49
|
+
priv_param.with_label(:priv_param)
|
50
|
+
|
51
|
+
log(level: 2) { asn_tree.to_hex }
|
52
|
+
log(level: 2) { sec_params_asn.to_hex }
|
27
53
|
|
28
54
|
# validate_authentication
|
29
|
-
|
55
|
+
auth_param = auth_param.value
|
56
|
+
security_parameters.verify(stream.sub(auth_param, AUTHNONE.value), auth_param, security_level: security_level)
|
30
57
|
|
31
|
-
engine_boots = engine_boots.to_i
|
32
|
-
engine_time = engine_time.to_i
|
58
|
+
engine_boots = engine_boots.value.to_i
|
59
|
+
engine_time = engine_time.value.to_i
|
33
60
|
|
34
|
-
encoded_pdu = security_parameters.decode(pdu_payload, salt: priv_param,
|
61
|
+
encoded_pdu = security_parameters.decode(pdu_payload, salt: priv_param.value,
|
35
62
|
engine_boots: engine_boots,
|
36
|
-
engine_time: engine_time
|
63
|
+
engine_time: engine_time,
|
64
|
+
security_level: security_level)
|
37
65
|
|
66
|
+
log { "received response PDU" }
|
38
67
|
pdu = ScopedPDU.decode(encoded_pdu)
|
39
|
-
|
68
|
+
log(level: 2) { pdu.to_hex }
|
69
|
+
[pdu, engine_id.value, engine_boots, engine_time]
|
40
70
|
end
|
41
71
|
|
42
72
|
# @param [NETSNMP::ScopedPDU] the PDU to encode in the message
|
@@ -45,36 +75,48 @@ module NETSNMP
|
|
45
75
|
# @return [String] the byte representation of an SNMP v3 Message
|
46
76
|
#
|
47
77
|
def encode(pdu, security_parameters:, engine_boots: 0, engine_time: 0)
|
78
|
+
log(level: 2) { pdu.to_hex }
|
79
|
+
log { "encoding PDU in V3 message..." }
|
48
80
|
scoped_pdu, salt_param = security_parameters.encode(pdu, salt: PRIVNONE,
|
49
81
|
engine_boots: engine_boots,
|
50
82
|
engine_time: engine_time)
|
51
83
|
|
52
84
|
sec_params = OpenSSL::ASN1::Sequence.new([
|
53
|
-
OpenSSL::ASN1::OctetString.new(security_parameters.engine_id),
|
54
|
-
OpenSSL::ASN1::Integer.new(engine_boots),
|
55
|
-
OpenSSL::ASN1::Integer.new(engine_time),
|
56
|
-
OpenSSL::ASN1::OctetString.new(security_parameters.username),
|
85
|
+
OpenSSL::ASN1::OctetString.new(security_parameters.engine_id).with_label(:engine_id),
|
86
|
+
OpenSSL::ASN1::Integer.new(engine_boots).with_label(:engine_boots),
|
87
|
+
OpenSSL::ASN1::Integer.new(engine_time).with_label(:engine_time),
|
88
|
+
OpenSSL::ASN1::OctetString.new(security_parameters.username).with_label(:username),
|
57
89
|
AUTHNONE,
|
58
90
|
salt_param
|
59
|
-
])
|
91
|
+
]).with_label(:security_params)
|
92
|
+
log(level: 2) { sec_params.to_hex }
|
93
|
+
|
60
94
|
message_flags = MSG_REPORTABLE | security_parameters.security_level
|
61
|
-
message_id = OpenSSL::ASN1::Integer.new(SecureRandom.random_number(2147483647))
|
95
|
+
message_id = OpenSSL::ASN1::Integer.new(SecureRandom.random_number(2147483647)).with_label(:message_id)
|
62
96
|
headers = OpenSSL::ASN1::Sequence.new([
|
63
|
-
message_id,
|
64
|
-
|
97
|
+
message_id,
|
98
|
+
MSG_MAX_SIZE,
|
99
|
+
OpenSSL::ASN1::OctetString.new([String(message_flags)].pack("h*")).with_label(:message_flags),
|
65
100
|
MSG_SECURITY_MODEL
|
66
|
-
])
|
101
|
+
]).with_label(:headers)
|
67
102
|
|
68
103
|
encoded = OpenSSL::ASN1::Sequence([
|
69
104
|
MSG_VERSION,
|
70
105
|
headers,
|
71
|
-
OpenSSL::ASN1::OctetString.new(sec_params.to_der),
|
106
|
+
OpenSSL::ASN1::OctetString.new(sec_params.to_der).with_label(:security_params),
|
72
107
|
scoped_pdu
|
73
|
-
]).
|
108
|
+
]).with_label(:v3_message)
|
109
|
+
log(level: 2) { encoded.to_hex }
|
110
|
+
|
111
|
+
encoded = encoded.to_der
|
112
|
+
log { Hexdump.dump(encoded) }
|
74
113
|
signature = security_parameters.sign(encoded)
|
75
114
|
if signature
|
76
|
-
|
115
|
+
log { "signing V3 message..." }
|
116
|
+
auth_salt = OpenSSL::ASN1::OctetString.new(signature).with_label(:auth)
|
117
|
+
log(level: 2) { auth_salt.to_hex }
|
77
118
|
encoded.sub!(AUTHNONE.to_der, auth_salt.to_der)
|
119
|
+
log { Hexdump.dump(encoded) }
|
78
120
|
end
|
79
121
|
encoded
|
80
122
|
end
|
data/lib/netsnmp/mib.rb
CHANGED
@@ -48,12 +48,10 @@ module NETSNMP
|
|
48
48
|
[prefix, *suffix].join(".")
|
49
49
|
end
|
50
50
|
|
51
|
-
# This is a helper function, do not rely on this functionality in future
|
52
|
-
# versions
|
53
51
|
def identifier(oid)
|
54
|
-
@object_identifiers.select do |_,
|
55
|
-
|
56
|
-
end
|
52
|
+
@object_identifiers.select do |_, ids_oid|
|
53
|
+
oid.start_with?(ids_oid)
|
54
|
+
end.sort_by(&:size).first
|
57
55
|
end
|
58
56
|
|
59
57
|
#
|
@@ -86,7 +84,7 @@ module NETSNMP
|
|
86
84
|
true
|
87
85
|
end
|
88
86
|
|
89
|
-
TYPES = ["OBJECT
|
87
|
+
TYPES = ["OBJECT IDENTIFIER", "OBJECT-TYPE", "MODULE-IDENTITY"].freeze
|
90
88
|
|
91
89
|
STATIC_MIB_TO_OID = {
|
92
90
|
"iso" => "1"
|
@@ -98,41 +96,54 @@ module NETSNMP
|
|
98
96
|
def do_load(mod)
|
99
97
|
data = @parser_mutex.synchronize { PARSER.parse(File.read(mod)) }
|
100
98
|
|
101
|
-
imports = load_imports(data)
|
99
|
+
imports = load_imports(data[:imports])
|
102
100
|
|
103
|
-
|
104
|
-
|
101
|
+
declarations = Hash[
|
102
|
+
data[:declarations].reject { |dec| !dec.key?(:name) || !TYPES.include?(dec[:type]) }
|
103
|
+
.map { |dec| [String(dec[:name]), String(dec[:value]).split(/ +/)] }
|
104
|
+
]
|
105
105
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
STATIC_MIB_TO_OID[cp] || @object_identifiers[cp] || begin
|
111
|
-
imported_mod, = imports.find do |_, identifiers|
|
112
|
-
identifiers.include?(cp)
|
113
|
-
end
|
106
|
+
declarations.each do |nme, value|
|
107
|
+
store_oid_in_identifiers(nme, value, imports: imports, declarations: declarations)
|
108
|
+
end
|
109
|
+
end
|
114
110
|
|
115
|
-
|
111
|
+
def store_oid_in_identifiers(nme, value, imports:, declarations:)
|
112
|
+
oid = value.flat_map do |cp|
|
113
|
+
if cp.integer?
|
114
|
+
cp
|
115
|
+
elsif @object_identifiers.key?(cp)
|
116
|
+
@object_identifiers[cp]
|
117
|
+
elsif declarations.key?(cp)
|
118
|
+
store_oid_in_identifiers(cp, declarations[cp], imports: imports, declarations: declarations)
|
119
|
+
@object_identifiers[cp]
|
120
|
+
else
|
121
|
+
STATIC_MIB_TO_OID[cp] || begin
|
122
|
+
imported_mod, = imports.find do |_, identifiers|
|
123
|
+
identifiers.include?(cp)
|
124
|
+
end
|
116
125
|
|
117
|
-
|
126
|
+
raise Error, "didn't find a module to import \"#{cp}\" from" unless imported_mod
|
118
127
|
|
119
|
-
|
120
|
-
|
128
|
+
load(imported_mod)
|
129
|
+
|
130
|
+
@object_identifiers[cp]
|
121
131
|
end
|
122
|
-
end
|
132
|
+
end
|
133
|
+
end.join(".")
|
123
134
|
|
124
|
-
|
125
|
-
end
|
135
|
+
@object_identifiers[nme] = oid
|
126
136
|
end
|
127
137
|
|
128
138
|
#
|
129
139
|
# Reformats the import lists into an hash indexed by module name, to a list of
|
130
140
|
# imported names
|
131
141
|
#
|
132
|
-
def load_imports(
|
133
|
-
return unless
|
142
|
+
def load_imports(imports)
|
143
|
+
return unless imports
|
134
144
|
|
135
|
-
|
145
|
+
imports = [imports] unless imports.respond_to?(:to_ary)
|
146
|
+
imports.each_with_object({}) do |import, imp|
|
136
147
|
imp[String(import[:name])] = case import[:ids]
|
137
148
|
when Hash
|
138
149
|
[String(import[:ids][:name])]
|
data/lib/netsnmp/pdu.rb
CHANGED
@@ -5,7 +5,11 @@ module NETSNMP
|
|
5
5
|
# Abstracts the PDU base structure into a ruby object. It gives access to its varbinds.
|
6
6
|
#
|
7
7
|
class PDU
|
8
|
+
using ASNExtensions
|
9
|
+
|
8
10
|
MAXREQUESTID = 2147483647
|
11
|
+
|
12
|
+
using ASNExtensions
|
9
13
|
class << self
|
10
14
|
def decode(der)
|
11
15
|
asn_tree = case der
|
@@ -53,6 +57,7 @@ module NETSNMP
|
|
53
57
|
when :inform then 6
|
54
58
|
when :trap then 7
|
55
59
|
when :response then 2
|
60
|
+
when :report then 8
|
56
61
|
else raise Error, "#{type} is not supported as type"
|
57
62
|
end
|
58
63
|
new(type: typ, **args)
|
@@ -85,6 +90,10 @@ module NETSNMP
|
|
85
90
|
to_asn.to_der
|
86
91
|
end
|
87
92
|
|
93
|
+
def to_hex
|
94
|
+
to_asn.to_hex
|
95
|
+
end
|
96
|
+
|
88
97
|
# Adds a request varbind to the pdu
|
89
98
|
#
|
90
99
|
# @param [OID] oid a valid oid
|
@@ -96,25 +105,27 @@ module NETSNMP
|
|
96
105
|
alias << add_varbind
|
97
106
|
|
98
107
|
def to_asn
|
99
|
-
request_id_asn = OpenSSL::ASN1::Integer.new(@request_id)
|
100
|
-
error_asn = OpenSSL::ASN1::Integer.new(@error_status)
|
101
|
-
error_index_asn = OpenSSL::ASN1::Integer.new(@error_index)
|
108
|
+
request_id_asn = OpenSSL::ASN1::Integer.new(@request_id).with_label(:request_id)
|
109
|
+
error_asn = OpenSSL::ASN1::Integer.new(@error_status).with_label(:error)
|
110
|
+
error_index_asn = OpenSSL::ASN1::Integer.new(@error_index).with_label(:error_index)
|
102
111
|
|
103
|
-
varbind_asns = OpenSSL::ASN1::Sequence.new(@varbinds.map(&:to_asn))
|
112
|
+
varbind_asns = OpenSSL::ASN1::Sequence.new(@varbinds.map(&:to_asn)).with_label(:varbinds)
|
104
113
|
|
105
114
|
request_asn = OpenSSL::ASN1::ASN1Data.new([request_id_asn,
|
106
115
|
error_asn, error_index_asn,
|
107
116
|
varbind_asns], @type,
|
108
|
-
:CONTEXT_SPECIFIC)
|
117
|
+
:CONTEXT_SPECIFIC).with_label(:request)
|
109
118
|
|
110
|
-
OpenSSL::ASN1::Sequence.new([*encode_headers_asn, request_asn])
|
119
|
+
OpenSSL::ASN1::Sequence.new([*encode_headers_asn, request_asn]).with_label(:pdu)
|
111
120
|
end
|
112
121
|
|
113
122
|
private
|
114
123
|
|
115
124
|
def encode_headers_asn
|
116
|
-
[
|
117
|
-
|
125
|
+
[
|
126
|
+
OpenSSL::ASN1::Integer.new(@version).with_label(:snmp_version),
|
127
|
+
OpenSSL::ASN1::OctetString.new(@community).with_label(:community)
|
128
|
+
]
|
118
129
|
end
|
119
130
|
|
120
131
|
# http://www.tcpipguide.com/free/t_SNMPVersion2SNMPv2MessageFormats-5.htm#Table_219
|
data/lib/netsnmp/scoped_pdu.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
module NETSNMP
|
4
4
|
class ScopedPDU < PDU
|
5
|
+
using ASNExtensions
|
6
|
+
|
5
7
|
attr_reader :engine_id
|
6
8
|
|
7
9
|
def initialize(type:, headers:, **options)
|
@@ -12,8 +14,10 @@ module NETSNMP
|
|
12
14
|
private
|
13
15
|
|
14
16
|
def encode_headers_asn
|
15
|
-
[
|
16
|
-
|
17
|
+
[
|
18
|
+
OpenSSL::ASN1::OctetString.new(@engine_id || "").with_label(:engine_id),
|
19
|
+
OpenSSL::ASN1::OctetString.new(@context || "").with_label(:context)
|
20
|
+
]
|
17
21
|
end
|
18
22
|
end
|
19
23
|
end
|
@@ -8,6 +8,9 @@ module NETSNMP
|
|
8
8
|
# It also provides validation of the security options passed with a client is initialized in v3 mode.
|
9
9
|
class SecurityParameters
|
10
10
|
using StringExtensions
|
11
|
+
using ASNExtensions
|
12
|
+
|
13
|
+
prepend Loggable
|
11
14
|
|
12
15
|
IPAD = "\x36" * 64
|
13
16
|
OPAD = "\x5c" * 64
|
@@ -72,7 +75,10 @@ module NETSNMP
|
|
72
75
|
if encryption
|
73
76
|
encrypted_pdu, salt = encryption.encrypt(pdu.to_der, engine_boots: engine_boots,
|
74
77
|
engine_time: engine_time)
|
75
|
-
[
|
78
|
+
[
|
79
|
+
OpenSSL::ASN1::OctetString.new(encrypted_pdu).with_label(:encrypted_pdu),
|
80
|
+
OpenSSL::ASN1::OctetString.new(salt).with_label(:salt)
|
81
|
+
]
|
76
82
|
else
|
77
83
|
[pdu.to_asn, salt]
|
78
84
|
end
|
@@ -82,15 +88,16 @@ module NETSNMP
|
|
82
88
|
# @param [String] salt the salt from the incoming der
|
83
89
|
# @param [Integer] engine_time the reported engine time
|
84
90
|
# @param [Integer] engine_boots the reported engine boots
|
85
|
-
def decode(der, salt:, engine_time:, engine_boots:)
|
91
|
+
def decode(der, salt:, engine_time:, engine_boots:, security_level: @security_level)
|
86
92
|
asn = OpenSSL::ASN1.decode(der)
|
87
|
-
if
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
93
|
+
return asn if security_level < 3
|
94
|
+
|
95
|
+
return asn unless encryption
|
96
|
+
|
97
|
+
encrypted_pdu = asn.value
|
98
|
+
pdu_der = encryption.decrypt(encrypted_pdu, salt: salt, engine_time: engine_time, engine_boots: engine_boots)
|
99
|
+
log(level: 2) { "message has been decrypted" }
|
100
|
+
OpenSSL::ASN1.decode(pdu_der)
|
94
101
|
end
|
95
102
|
|
96
103
|
# @param [String] message the already encoded snmp v3 message
|
@@ -120,10 +127,11 @@ module NETSNMP
|
|
120
127
|
# @param [String] salt the incoming payload''s salt
|
121
128
|
#
|
122
129
|
# @raise [NETSNMP::Error] if the message's integration has been violated
|
123
|
-
def verify(stream, salt)
|
124
|
-
return if
|
130
|
+
def verify(stream, salt, security_level: @security_level)
|
131
|
+
return if security_level < 1
|
125
132
|
verisalt = sign(stream)
|
126
133
|
raise Error, "invalid message authentication salt" unless verisalt == salt
|
134
|
+
log(level: 2) { "message has been verified" }
|
127
135
|
end
|
128
136
|
|
129
137
|
def must_revalidate?
|
data/lib/netsnmp/session.rb
CHANGED
@@ -4,6 +4,8 @@ module NETSNMP
|
|
4
4
|
# Let's just remind that there is no session in snmp, this is just an abstraction.
|
5
5
|
#
|
6
6
|
class Session
|
7
|
+
prepend Loggable
|
8
|
+
|
7
9
|
TIMEOUT = 2
|
8
10
|
|
9
11
|
# @param [Hash] opts the options set
|
@@ -36,9 +38,16 @@ module NETSNMP
|
|
36
38
|
# @return [NETSNMP::PDU] the response pdu
|
37
39
|
#
|
38
40
|
def send(pdu)
|
41
|
+
log { "sending request..." }
|
42
|
+
log(level: 2) { pdu.to_hex }
|
39
43
|
encoded_request = pdu.to_der
|
44
|
+
log { Hexdump.dump(encoded_request) }
|
40
45
|
encoded_response = @transport.send(encoded_request)
|
41
|
-
|
46
|
+
log { "received response" }
|
47
|
+
log { Hexdump.dump(encoded_response) }
|
48
|
+
response_pdu = PDU.decode(encoded_response)
|
49
|
+
log(level: 2) { response_pdu.to_hex }
|
50
|
+
response_pdu
|
42
51
|
end
|
43
52
|
|
44
53
|
private
|
data/lib/netsnmp/v3_session.rb
CHANGED
@@ -8,6 +8,7 @@ module NETSNMP
|
|
8
8
|
@context = context
|
9
9
|
@security_parameters = opts.delete(:security_parameters)
|
10
10
|
super
|
11
|
+
@message_serializer = Message.new(**opts)
|
11
12
|
end
|
12
13
|
|
13
14
|
# @see {NETSNMP::Session#build_pdu}
|
@@ -20,10 +21,18 @@ module NETSNMP
|
|
20
21
|
|
21
22
|
# @see {NETSNMP::Session#send}
|
22
23
|
def send(pdu)
|
24
|
+
log { "sending request..." }
|
23
25
|
encoded_request = encode(pdu)
|
24
26
|
encoded_response = @transport.send(encoded_request)
|
25
|
-
|
26
|
-
|
27
|
+
response_pdu, *args = decode(encoded_response)
|
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
|
35
|
+
response_pdu
|
27
36
|
end
|
28
37
|
|
29
38
|
private
|
@@ -60,7 +69,8 @@ module NETSNMP
|
|
60
69
|
report_sec_params = SecurityParameters.new(security_level: 0,
|
61
70
|
username: @security_parameters.username)
|
62
71
|
pdu = ScopedPDU.build(:get, headers: [])
|
63
|
-
|
72
|
+
log { "sending probe..." }
|
73
|
+
encoded_report_pdu = @message_serializer.encode(pdu, security_parameters: report_sec_params)
|
64
74
|
|
65
75
|
encoded_response_pdu = @transport.send(encoded_report_pdu)
|
66
76
|
|
@@ -69,13 +79,13 @@ module NETSNMP
|
|
69
79
|
end
|
70
80
|
|
71
81
|
def encode(pdu)
|
72
|
-
|
73
|
-
|
74
|
-
|
82
|
+
@message_serializer.encode(pdu, security_parameters: @security_parameters,
|
83
|
+
engine_boots: @engine_boots,
|
84
|
+
engine_time: @engine_time)
|
75
85
|
end
|
76
86
|
|
77
87
|
def decode(stream, security_parameters: @security_parameters)
|
78
|
-
|
88
|
+
@message_serializer.decode(stream, security_parameters: security_parameters)
|
79
89
|
end
|
80
90
|
end
|
81
91
|
end
|
data/lib/netsnmp/varbind.rb
CHANGED
@@ -4,6 +4,8 @@ module NETSNMP
|
|
4
4
|
# Abstracts the PDU variable structure into a ruby object
|
5
5
|
#
|
6
6
|
class Varbind
|
7
|
+
using StringExtensions
|
8
|
+
|
7
9
|
attr_reader :oid, :value
|
8
10
|
|
9
11
|
def initialize(oid, value: nil, type: nil)
|
@@ -48,18 +50,15 @@ module NETSNMP
|
|
48
50
|
def convert_val(asn_value)
|
49
51
|
case asn_value
|
50
52
|
when OpenSSL::ASN1::OctetString
|
51
|
-
|
53
|
+
val = asn_value.value
|
54
|
+
|
52
55
|
# it's kind of common in snmp, some stuff can't be converted,
|
53
56
|
# like Hexa Strings. Parse them into a readable format a la netsnmp
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
Encoding::InvalidByteSequenceError
|
60
|
-
# hexdump me!
|
61
|
-
val.unpack("H*")[0].upcase.scan(/../).join(" ")
|
62
|
-
end
|
57
|
+
# https://github.com/net-snmp/net-snmp/blob/ed90aaaaea0d9cc6c5c5533f1863bae598d3b820/snmplib/mib.c#L650
|
58
|
+
is_hex_string = val.each_char.any? { |c| !c.match?(/[[:print:]]/) && !c.match?(/[[:space:]]/) }
|
59
|
+
|
60
|
+
val = HexString.new(val) if is_hex_string
|
61
|
+
val
|
63
62
|
when OpenSSL::ASN1::Primitive
|
64
63
|
val = asn_value.value
|
65
64
|
val = val.to_i if val.is_a?(OpenSSL::BN)
|
@@ -81,11 +80,11 @@ module NETSNMP
|
|
81
80
|
when :ipaddress then 0
|
82
81
|
when :counter32
|
83
82
|
asn_val = [value].pack("N*")
|
84
|
-
asn_val = asn_val[1..-1] while asn_val[0] == "\x00".b && asn_val[1].
|
83
|
+
asn_val = asn_val[1..-1] while asn_val[0] == "\x00".b && asn_val[1].unpack1("B") != "1"
|
85
84
|
1
|
86
85
|
when :gauge
|
87
86
|
asn_val = [value].pack("N*")
|
88
|
-
asn_val = asn_val[1..-1] while asn_val[0] == "\x00".b && asn_val[1].
|
87
|
+
asn_val = asn_val[1..-1] while asn_val[0] == "\x00".b && asn_val[1].unpack1("B") != "1"
|
89
88
|
2
|
90
89
|
when :timetick
|
91
90
|
return Timetick.new(value).to_asn
|
data/lib/netsnmp/version.rb
CHANGED
data/sig/loggable.rbs
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module NETSNMP
|
2
|
+
module Loggable
|
3
|
+
interface _Debugger
|
4
|
+
def <<: (string) -> void
|
5
|
+
end
|
6
|
+
|
7
|
+
DEBUG_LEVEL: Integer
|
8
|
+
DEBUG: _Debugger
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def initialize: (?debug: _DEBUGGER, ?debug_level: Integer, **untyped) -> void
|
13
|
+
|
14
|
+
def log: (?level: Integer) { () -> String } -> void
|
15
|
+
end
|
16
|
+
end
|
data/sig/message.rbs
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
module NETSNMP
|
2
|
-
|
3
|
-
|
2
|
+
class Message
|
3
|
+
prepend Loggable
|
4
4
|
|
5
|
-
def
|
5
|
+
def decode: (String stream, security_parameters: SecurityParameters) -> [ScopedPDU, String, Integer, Integer]
|
6
|
+
|
7
|
+
def encode: (ScopedPDU pdu, security_parameters: SecurityParameters, ?engine_boots: Integer, ?engine_time: Integer) -> String
|
6
8
|
end
|
7
9
|
end
|
data/sig/mib.rbs
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module NETSNMP
|
2
2
|
module MIB
|
3
|
+
type import = {ids: Array[{name: string}], name: string} | {ids: {name: string}, name: string}
|
4
|
+
|
5
|
+
|
3
6
|
MIBDIRS: Array[String]
|
4
7
|
PARSER: Parser
|
5
8
|
|
@@ -12,7 +15,7 @@ module NETSNMP
|
|
12
15
|
|
13
16
|
def self?.load: (String mod) -> void
|
14
17
|
|
15
|
-
def self?.load_imports: (
|
18
|
+
def self?.load_imports: ((Array[import] | import)? data) -> Hash[String, Array[String]]?
|
16
19
|
def self?.load_defaults: () -> void
|
17
20
|
end
|
18
21
|
end
|
data/sig/netsnmp.rbs
CHANGED
data/sig/pdu.rbs
CHANGED
data/sig/security_parameters.rbs
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module NETSNMP
|
2
2
|
class SecurityParameters
|
3
|
+
prepend Loggable
|
4
|
+
|
3
5
|
type security_level = :noauth | :auth_no_priv | :auth_priv | 0 | 1 | 3 | nil
|
4
6
|
|
5
7
|
type auth_protocol = :md5 | :sha
|
@@ -21,11 +23,11 @@ module NETSNMP
|
|
21
23
|
|
22
24
|
def encode: (_ToAsn, salt: OpenSSL::ASN1::ASN1Data, engine_time: Integer, engine_boots: Integer) -> [OpenSSL::ASN1::ASN1Data, OpenSSL::ASN1::ASN1Data]
|
23
25
|
|
24
|
-
def decode: (OpenSSL::ASN1::ASN1Data | String der, salt: OpenSSL::ASN1::ASN1Data | String, engine_time: Integer, engine_boots: Integer) -> OpenSSL::ASN1::ASN1Data
|
26
|
+
def decode: (OpenSSL::ASN1::ASN1Data | String der, salt: OpenSSL::ASN1::ASN1Data | String, engine_time: Integer, engine_boots: Integer, ?security_level: Integer?) -> OpenSSL::ASN1::ASN1Data
|
25
27
|
|
26
28
|
def sign: (String message) -> String?
|
27
29
|
|
28
|
-
def verify: (String stream, String salt) -> void
|
30
|
+
def verify: (String stream, String salt, ?security_level: Integer?) -> void
|
29
31
|
|
30
32
|
def must_revalidate?: () -> bool
|
31
33
|
|
data/sig/session.rbs
CHANGED
data/spec/client_spec.rb
CHANGED
@@ -67,6 +67,24 @@ RSpec.describe NETSNMP::Client do
|
|
67
67
|
WALK
|
68
68
|
end
|
69
69
|
let(:set_oid_result) { 43 }
|
70
|
+
|
71
|
+
context "when the returned value is a hex-string" do
|
72
|
+
let(:protocol_options) do
|
73
|
+
{
|
74
|
+
version: "2c",
|
75
|
+
community: "foreignformats/winxp1"
|
76
|
+
}
|
77
|
+
end
|
78
|
+
let(:hex_get_oid) { "1.3.6.1.2.1.25.3.7.1.3.10.1" }
|
79
|
+
let(:hex_get_result) { "\x01\x00\x00\x00" }
|
80
|
+
let(:hex_get_output) { "01 00 00 00" }
|
81
|
+
let(:value) { subject.get(oid: hex_get_oid) }
|
82
|
+
|
83
|
+
it "returns the string, which outputs the hex-representation" do
|
84
|
+
expect(value).to eq(hex_get_result)
|
85
|
+
expect(value.inspect).to include(hex_get_output)
|
86
|
+
end
|
87
|
+
end
|
70
88
|
end
|
71
89
|
end
|
72
90
|
|
data/spec/spec_helper.rb
CHANGED
data/spec/varbind_spec.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe NETSNMP::Varbind do
|
4
|
+
using NETSNMP::StringExtensions
|
5
|
+
|
4
6
|
describe "#to_der" do
|
5
7
|
it { expect(described_class.new(".1.3.6.1.2.1.1.1.0").to_der).to eq("0\f\006\b+\006\001\002\001\001\001\000\005\000".b) }
|
6
8
|
|
@@ -25,7 +27,7 @@ RSpec.describe NETSNMP::Varbind do
|
|
25
27
|
gauge = 127
|
26
28
|
varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :gauge, value: gauge)
|
27
29
|
value_str = varbind.to_der[12..-1]
|
28
|
-
header = value_str[0].
|
30
|
+
header = value_str[0].unpack1("B8")
|
29
31
|
|
30
32
|
# Class: Primitive Application
|
31
33
|
expect(header[0..1]).to eq("01")
|
@@ -43,7 +45,7 @@ RSpec.describe NETSNMP::Varbind do
|
|
43
45
|
gauge = 128
|
44
46
|
varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :gauge, value: gauge)
|
45
47
|
value_str = varbind.to_der[12..-1]
|
46
|
-
header = value_str[0].
|
48
|
+
header = value_str[0].unpack1("B8")
|
47
49
|
|
48
50
|
# Class: Primitive Application
|
49
51
|
expect(header[0..1]).to eq("01")
|
@@ -61,7 +63,7 @@ RSpec.describe NETSNMP::Varbind do
|
|
61
63
|
gauge = 805
|
62
64
|
varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :gauge, value: gauge)
|
63
65
|
value_str = varbind.to_der[12..-1]
|
64
|
-
header = value_str[0].
|
66
|
+
header = value_str[0].unpack1("B8")
|
65
67
|
|
66
68
|
# Class: Primitive Application
|
67
69
|
expect(header[0..1]).to eq("01")
|
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.4.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-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parslet
|
@@ -41,6 +41,8 @@ files:
|
|
41
41
|
- lib/netsnmp/encryption/des.rb
|
42
42
|
- lib/netsnmp/encryption/none.rb
|
43
43
|
- lib/netsnmp/errors.rb
|
44
|
+
- lib/netsnmp/extensions.rb
|
45
|
+
- lib/netsnmp/loggable.rb
|
44
46
|
- lib/netsnmp/message.rb
|
45
47
|
- lib/netsnmp/mib.rb
|
46
48
|
- lib/netsnmp/mib/parser.rb
|
@@ -54,6 +56,7 @@ files:
|
|
54
56
|
- lib/netsnmp/varbind.rb
|
55
57
|
- lib/netsnmp/version.rb
|
56
58
|
- sig/client.rbs
|
59
|
+
- sig/loggable.rbs
|
57
60
|
- sig/message.rbs
|
58
61
|
- sig/mib.rbs
|
59
62
|
- sig/mib/parser.rbs
|
@@ -101,21 +104,21 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
104
|
version: '0'
|
102
105
|
requirements:
|
103
106
|
- net-snmp
|
104
|
-
rubygems_version: 3.
|
107
|
+
rubygems_version: 3.2.3
|
105
108
|
signing_key:
|
106
109
|
specification_version: 4
|
107
110
|
summary: SNMP Client library
|
108
111
|
test_files:
|
109
|
-
- spec/timeticks_spec.rb
|
110
|
-
- spec/spec_helper.rb
|
111
|
-
- spec/session_spec.rb
|
112
112
|
- spec/client_spec.rb
|
113
|
+
- spec/handlers/celluloid_spec.rb
|
113
114
|
- spec/mib_spec.rb
|
114
115
|
- spec/oid_spec.rb
|
115
|
-
- spec/varbind_spec.rb
|
116
|
-
- spec/support/request_examples.rb
|
117
|
-
- spec/support/celluloid.rb
|
118
116
|
- spec/pdu_spec.rb
|
119
117
|
- spec/security_parameters_spec.rb
|
118
|
+
- spec/session_spec.rb
|
119
|
+
- spec/spec_helper.rb
|
120
|
+
- spec/support/celluloid.rb
|
121
|
+
- spec/support/request_examples.rb
|
122
|
+
- spec/timeticks_spec.rb
|
120
123
|
- spec/v3_session_spec.rb
|
121
|
-
- spec/
|
124
|
+
- spec/varbind_spec.rb
|