netsnmp 0.6.4 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3349a60dfb4bd19c4ae8b1f1f0ad76638ab3e384ed4d03419ddc71ab4770ada7
4
- data.tar.gz: 54c2d8c1414abff53cdd3687a69265447d24923ad3ee5dfd97f0e4395257696c
3
+ metadata.gz: dccc7490c2cbc05114eb97dbbf976a500939d3d4ac9d2fd7cc423c140201e809
4
+ data.tar.gz: 0b15cf923a202e51d27c000cce1187c4b63d68dd2dc1b354105a27ebb61846b0
5
5
  SHA512:
6
- metadata.gz: 48d7735ee7785d200a27318df71a8f60cc25fb7b9902c203471768b0f8da4333faf4a304eb8c23ff44f6a11c7e08e74c76afe7a993470c938d24af47576d34cf
7
- data.tar.gz: 557778f9e177cff84382ffcbae103d0245f6ece90f8169e41b3dffdbd7f6a505630d7ff9ace61980765824b2c5554ee5ca71f9d7bca0792933dc91dbed1abf02
6
+ metadata.gz: da6cc741eee319b0e07c4fd04f5bd55003bd761be7c5598695b4894c3d399e0519d81bbf7ef6c64d3dc355f3b512802372541ea10859aa96f701a29d88a604ad
7
+ data.tar.gz: a8b786a99c61cd722a789e06b6810545a54b18de47a08bf090f0251649fe20f22987294da9c54f8875783a29779817276b5368004adc52e80a6122b3cbbfcd9c
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # netsnmp
2
2
 
3
- ![Tests](https://github.com/swisscom/ruby-netsnmp/workflows/Tests/badge.svg)
4
- [![Code Climate](https://codeclimate.com/github/swisscom/ruby-netsnmp/badges/gpa.svg)](https://codeclimate.com/github/swisscom/ruby-netsnmp)
5
- [![Docs](http://img.shields.io/badge/yard-docs-blue.svg)](https://www.rubydoc.info/github/swisscom/ruby-netsnmp/master)
3
+ [![Gem Version](https://badge.fury.io/rb/netsnmp.svg)](http://rubygems.org/gems/netsnmp)
4
+ ![Tests](https://github.com/HoneyryderChuck/ruby-netsnmp/workflows/Tests/badge.svg)
5
+ [![Code Climate](https://codeclimate.com/github/HoneyryderChuck/ruby-netsnmp/badges/gpa.svg)](https://codeclimate.com/github/HoneyryderChuck/ruby-netsnmp)
6
+ [![Docs](http://img.shields.io/badge/yard-docs-blue.svg)](https://www.rubydoc.info/github/HoneyryderChuck/ruby-netsnmp/master)
6
7
 
7
8
  The `netsnmp` gem provides a ruby native implementation of the SNMP protocol (v1/2c abd v3).
8
9
 
@@ -31,36 +32,14 @@ $ gem install netsnmp
31
32
  This gem provides:
32
33
 
33
34
  * 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.
35
+ * SNMPv3 USM supporting MD5/SHA1/SHA224/SHA256/SHA384/SHA512 auth and DES/AES128/AES192/AES256 privacy crypto algorithms.
35
36
  * Client/Manager API with simple interface for get, genext, set and walk.
36
- * Pure Ruby.
37
- * Support for concurrency and evented I/O.
38
-
39
- ## Why?
40
-
41
- If you look for snmp gems in ruby toolbox, you'll find a bunch.
42
- You may ask, why not just use one of them?
43
-
44
- Most of them only implement v1 and v2, so if your requirement is to use v3, you're left with only 2 choices: [net-snmp](https://github.com/mixtli/net-snmp) (unmantained since 2013) and its follow-up [net-snmp2](https://github.com/jbreeden/net-snmp2), which started as a fork to fix some bugs left unattended. Both libraries wrap the C netsnmp library using FFI, which leaves them vulnerable to the following bugs (experienced in both libraries):
45
-
46
- * Dependency of specific versions of netsnmp C package.
47
- * Memory Leaks.
48
- * Doesn't work reliable in ruby > 2.0.0-p576, crashing the VM.
49
- * Network I/O done by the library, thereby blocking the GVL, thereby making all snmp calls block the whole ruby VM.
50
- * This means, multi-threading is impossible.
51
- * This means, evented I/O is impossible.
52
-
53
- All of these issues are resolved here.
54
-
55
- ## Features
56
-
57
- * Client Interface, which supports SNMP v3, v2c, and v1
58
- * Supports get, getnext, set and walk calls
59
37
  * MIB support
60
38
  * Proxy IO object support (for eventmachine/celluloid-io)
61
- * Ruby >= 2.1 support (modern)
62
39
  * Pure Ruby (no FFI)
63
40
  * Easy PDU debugging
41
+ * Support for concurrency and evented I/O.
42
+
64
43
 
65
44
  ## Examples
66
45
 
@@ -126,7 +105,7 @@ The `NETSNMP::Timeticks` type is internal to this library, but it is a ruby `Num
126
105
 
127
106
  Counter32 and Counter64 types will map to plain integers.
128
107
 
129
- You can find usage examples [here](https://github.com/swisscom/ruby-netsnmp/blob/master/spec/varbind_spec.rb). If you need support to a missing type, you have the following options:
108
+ You can find usage examples [here](https://github.com/HoneyryderChuck/ruby-netsnmp/blob/master/spec/varbind_spec.rb). If you need support to a missing type, you have the following options:
130
109
 
131
110
  * Use the `:type` parameter in `#set` calls:
132
111
  ```ruby
@@ -3,18 +3,30 @@
3
3
  module NETSNMP
4
4
  module Encryption
5
5
  class AES
6
- def initialize(priv_key, local: 0)
6
+ def initialize(priv_key, cipher:, local: 0)
7
7
  @priv_key = priv_key
8
8
  @local = local
9
+ # https://www.rfc-editor.org/rfc/rfc3826
10
+ # https://snmp.com/snmpv3/snmpv3_aes256.shtml
11
+ # Note: AES Blumental is not supported and not widely used
12
+ @cipher = cipher
9
13
  end
10
14
 
11
15
  def encrypt(decrypted_data, engine_boots:, engine_time:)
12
- cipher = OpenSSL::Cipher.new("aes-128-cfb")
16
+ cipher = case @cipher
17
+ when :aes, :aes128 then OpenSSL::Cipher.new("aes-128-cfb")
18
+ when :aes192 then OpenSSL::Cipher.new("aes-192-cfb")
19
+ when :aes256 then OpenSSL::Cipher.new("aes-256-cfb")
20
+ end
13
21
 
14
22
  iv, salt = generate_encryption_key(engine_boots, engine_time)
15
23
 
16
24
  cipher.encrypt
17
- cipher.iv = iv
25
+ cipher.iv = case @cipher
26
+ when :aes, :aes128 then iv[0, 16]
27
+ when :aes192 then iv[0, 24]
28
+ when :aes256 then iv[0, 32]
29
+ end
18
30
  cipher.key = aes_key
19
31
 
20
32
  if (diff = decrypted_data.length % 8) != 0
@@ -29,14 +41,22 @@ module NETSNMP
29
41
  def decrypt(encrypted_data, salt:, engine_boots:, engine_time:)
30
42
  raise Error, "invalid priv salt received" unless !salt.empty? && (salt.length % 8).zero?
31
43
 
32
- cipher = OpenSSL::Cipher.new("aes-128-cfb")
44
+ cipher = case @cipher
45
+ when :aes, :aes128 then OpenSSL::Cipher.new("aes-128-cfb")
46
+ when :aes192 then OpenSSL::Cipher.new("aes-192-cfb")
47
+ when :aes256 then OpenSSL::Cipher.new("aes-256-cfb")
48
+ end
33
49
  cipher.padding = 0
34
50
 
35
51
  iv = generate_decryption_key(engine_boots, engine_time, salt)
36
52
 
37
53
  cipher.decrypt
38
54
  cipher.key = aes_key
39
- cipher.iv = iv
55
+ cipher.iv = case @cipher
56
+ when :aes, :aes128 then iv[0..16]
57
+ when :aes192 then iv[0..24]
58
+ when :aes256 then iv[0..32]
59
+ end
40
60
  decrypted_data = cipher.update(encrypted_data) + cipher.final
41
61
 
42
62
  hlen, bodylen = OpenSSL::ASN1.traverse(decrypted_data) { |_, _, x, y, *| break x, y }
@@ -58,6 +78,11 @@ module NETSNMP
58
78
  @local = @local == 0xffffffffffffffff ? 0 : @local + 1
59
79
 
60
80
  iv = generate_decryption_key(boots, time, salt)
81
+ iv = case @cipher
82
+ when :aes, :aes128 then iv[0, 16]
83
+ when :aes192 then iv[0, 24]
84
+ when :aes256 then iv[0, 32]
85
+ end
61
86
 
62
87
  [iv, salt]
63
88
  end
@@ -74,7 +99,11 @@ module NETSNMP
74
99
  end
75
100
 
76
101
  def aes_key
77
- @priv_key[0, 16]
102
+ case @cipher
103
+ when :aes, :aes128 then @priv_key[0, 16]
104
+ when :aes192 then @priv_key[0, 24]
105
+ when :aes256 then @priv_key[0, 32]
106
+ end
78
107
  end
79
108
  end
80
109
  end
@@ -136,7 +136,13 @@ module NETSNMP
136
136
 
137
137
  # The digest in the msgAuthenticationParameters field is replaced by the 12 zero octets.
138
138
  # 24 octets for sha256
139
- number_of_octets = auth_protocol == :sha256 ? 24 : 12
139
+ number_of_octets = case auth_protocol
140
+ when :sha512 then 48
141
+ when :sha384 then 32
142
+ when :sha256 then 24
143
+ when :sha224 then 16
144
+ else 12
145
+ end
140
146
 
141
147
  OpenSSL::ASN1::OctetString.new("\x00" * number_of_octets).with_label(:auth_mask)
142
148
  end
@@ -446,7 +446,7 @@ module NETSNMP::MIB
446
446
  spaced("STATUS") >> spaced { status } >>
447
447
  spaced("DESCRIPTION") >> spaced { text } >>
448
448
  spaced { refer_part }.maybe >>
449
- colon_colon_part >> curly(object_identifier)
449
+ colon_colon_part >> curly(object_identifier.as(:value))
450
450
  end
451
451
 
452
452
  rule(:units_part) do
@@ -557,7 +557,7 @@ module NETSNMP::MIB
557
557
 
558
558
  rule(:choice_clause) do
559
559
  # Ignoring choice syntax
560
- spaced { str("CHOICE").as(:type) } >> curly(match("[^\}]").repeat)
560
+ spaced { str("CHOICE").as(:type) } >> curly(match("[^}]").repeat)
561
561
  end
562
562
 
563
563
  rule(:syntax) do
@@ -689,11 +689,11 @@ module NETSNMP::MIB
689
689
  rule(:status) { lowercase_identifier }
690
690
 
691
691
  rule(:uppercase_identifier) do
692
- match("[A-Z]") >> match("[A-Za-z0-9\-]").repeat
692
+ match("[A-Z]") >> match("[A-Za-z0-9-]").repeat
693
693
  end
694
694
 
695
695
  rule(:lowercase_identifier) do
696
- match("[a-z]") >> match("[A-Za-z0-9\-]").repeat
696
+ match("[a-z]") >> match("[A-Za-z0-9-]").repeat
697
697
  end
698
698
 
699
699
  rule(:type_smi_and_sppi) do
data/lib/netsnmp/mib.rb CHANGED
@@ -15,9 +15,9 @@ module NETSNMP
15
15
  .flat_map { |dir| [dir, *Dir.glob(File.join(dir, "**", "*")).select(&File.method(:directory?))] }.uniq
16
16
  PARSER = Parser.new
17
17
  @parser_mutex = Mutex.new
18
+
18
19
  @modules_loaded = []
19
20
  @object_identifiers = {}
20
-
21
21
  # Translates na identifier, such as "sysDescr", into an OID
22
22
  def oid(identifier)
23
23
  prefix, *suffix = case identifier
@@ -98,7 +98,7 @@ module NETSNMP
98
98
  end
99
99
  end
100
100
 
101
- TYPES = ["OBJECT IDENTIFIER", "OBJECT-TYPE", "MODULE-IDENTITY"].freeze
101
+ TYPES = ["OBJECT IDENTIFIER", "OBJECT-TYPE", "MODULE-IDENTITY", "OBJECT-IDENTITY"].freeze
102
102
 
103
103
  STATIC_MIB_TO_OID = {
104
104
  "iso" => "1"
@@ -174,5 +174,11 @@ module NETSNMP
174
174
  load("SNMPv2-MIB")
175
175
  load("IF-MIB")
176
176
  end
177
+
178
+ def freeze
179
+ super
180
+ @modules_loaded.each(&:freeze).freeze
181
+ @object_identifiers.each_key(&:freeze).each_value(&:freeze).freeze
182
+ end
177
183
  end
178
184
  end
@@ -130,13 +130,25 @@ module NETSNMP
130
130
 
131
131
  key = auth_key.dup
132
132
 
133
- # SHA256 => https://datatracker.ietf.org/doc/html/rfc7860#section-4.2.2
134
- # The 24 first octets of HMAC are taken as the computed MAC value
135
- return OpenSSL::HMAC.digest("SHA256", key, message)[0, 24] if @auth_protocol == :sha256
133
+ case @auth_protocol
134
+ when :sha224
135
+ return OpenSSL::HMAC.digest("SHA224", key, message)[0, 16]
136
+ when :sha384
137
+ return OpenSSL::HMAC.digest("SHA384", key, message)[0, 32]
138
+ when :sha256
139
+ # The 24 first octets of HMAC are taken as the computed MAC value
140
+ # SHA256 => https://datatracker.ietf.org/doc/html/rfc7860#section-4.2.2
141
+ return OpenSSL::HMAC.digest("SHA256", key, message)[0, 24]
142
+ when :sha512
143
+ return OpenSSL::HMAC.digest("SHA512", key, message)[0, 48]
144
+ when :md5
145
+ # MD5 => https://datatracker.ietf.org/doc/html/rfc3414#section-6.3.2
146
+ key << ("\x00" * 48)
147
+ when :sha, :sha1
148
+ # SHA1 => https://datatracker.ietf.org/doc/html/rfc3414#section-7.3.2
149
+ key << ("\x00" * 44)
150
+ end
136
151
 
137
- # MD5 => https://datatracker.ietf.org/doc/html/rfc3414#section-6.3.2
138
- # SHA1 => https://datatracker.ietf.org/doc/html/rfc3414#section-7.3.2
139
- key << ("\x00" * (@auth_protocol == :md5 ? 48 : 44))
140
152
  k1 = key.xor(IPAD)
141
153
  k2 = key.xor(OPAD)
142
154
 
@@ -177,7 +189,20 @@ module NETSNMP
177
189
  end
178
190
 
179
191
  def priv_key
180
- @priv_key ||= localize_key(@priv_pass_key)
192
+ @priv_key ||= begin
193
+ key = localize_key(@priv_pass_key)
194
+ # AES-192, AES-256 require longer localized keys,
195
+ # which require adding of subsequent localized_priv_keys based on the previous until the length is satisfied
196
+ # The only hint to this is available in the python implementation called pysnmp
197
+ priv_key_size = case @priv_protocol
198
+ when :aes256 then 32
199
+ when :aes192 then 24
200
+ else 16
201
+ end
202
+
203
+ key += localize_key(passkey(key)) while key.size < priv_key_size
204
+ key
205
+ end
181
206
  end
182
207
 
183
208
  def localize_key(key)
@@ -205,15 +230,27 @@ module NETSNMP
205
230
  end
206
231
 
207
232
  dig = digest.digest
208
- dig = dig[0, 16] if @auth_protocol == :md5
233
+ dig_size = case @auth_protocol
234
+ when :sha512 then 64
235
+ when :sha384 then 48
236
+ when :sha256 then 32
237
+ when :sha224 then 28
238
+ when :sha1, :sha then 20
239
+ else 16
240
+ end
241
+
242
+ dig[0, dig_size]
209
243
  dig || ""
210
244
  end
211
245
 
212
246
  def digest
213
247
  @digest ||= case @auth_protocol
214
248
  when :md5 then OpenSSL::Digest.new("MD5")
215
- when :sha then OpenSSL::Digest.new("SHA1")
249
+ when :sha, :sha1 then OpenSSL::Digest.new("SHA1")
250
+ when :sha224 then OpenSSL::Digest.new("SHA224")
216
251
  when :sha256 then OpenSSL::Digest.new("SHA256")
252
+ when :sha384 then OpenSSL::Digest.new("SHA384")
253
+ when :sha512 then OpenSSL::Digest.new("SHA512")
217
254
  else
218
255
  raise Error, "unsupported auth protocol: #{@auth_protocol}"
219
256
  end
@@ -222,7 +259,7 @@ module NETSNMP
222
259
  def encryption
223
260
  @encryption ||= case @priv_protocol
224
261
  when :des then Encryption::DES.new(priv_key)
225
- when :aes then Encryption::AES.new(priv_key)
262
+ when :aes, :aes192, :aes256 then Encryption::AES.new(priv_key, cipher: @priv_protocol)
226
263
  end
227
264
  end
228
265
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NETSNMP
4
- VERSION = "0.6.4"
4
+ VERSION = "0.7.0"
5
5
  end
@@ -4,6 +4,7 @@ module NETSNMP
4
4
 
5
5
  @priv_key: String
6
6
  @local: Integer
7
+ @cipher: Symbol
7
8
 
8
9
  def encrypt: (String decrypted_data, engine_boots: Integer, engine_time: Integer) -> [String, String]
9
10
 
@@ -11,7 +12,7 @@ module NETSNMP
11
12
 
12
13
  private
13
14
 
14
- def initialize: (String priv_key, ?local: Integer) -> untyped
15
+ def initialize: (String priv_key, ?local: Integer, ?cipher: Symbol) -> untyped
15
16
 
16
17
  def generate_encryption_key: (Integer boots, Integer time) -> [String, String]
17
18
 
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.6.4
4
+ version: 0.7.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: 2022-05-10 00:00:00.000000000 Z
11
+ date: 2023-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parslet
@@ -73,24 +73,15 @@ files:
73
73
  - sig/timeticks.rbs
74
74
  - sig/v3_session.rbs
75
75
  - sig/varbind.rbs
76
- - spec/client_spec.rb
77
- - spec/handlers/celluloid_spec.rb
78
- - spec/mib_spec.rb
79
- - spec/oid_spec.rb
80
- - spec/pdu_spec.rb
81
- - spec/security_parameters_spec.rb
82
- - spec/session_spec.rb
83
- - spec/spec_helper.rb
84
- - spec/support/celluloid.rb
85
- - spec/support/request_examples.rb
86
- - spec/timeticks_spec.rb
87
- - spec/v3_session_spec.rb
88
- - spec/varbind_spec.rb
89
- homepage: ''
76
+ homepage: https://github.com/HoneyryderChuck/ruby-netsnmp
90
77
  licenses:
91
78
  - Apache-2.0
92
79
  metadata:
93
- allowed_push_host: https://rubygems.org/
80
+ bug_tracker_uri: https://github.com/HoneyryderChuck/ruby-netsnmp/issues
81
+ changelog_uri: https://github.com/HoneyryderChuck/ruby-netsnmp/blob/master/CHANGELOG.md
82
+ documentation_uri: https://www.rubydoc.info/github/HoneyryderChuck/ruby-netsnmp
83
+ source_code_uri: https://github.com/HoneyryderChuck/ruby-netsnmp
84
+ homepage_uri: https://github.com/HoneyryderChuck/ruby-netsnmp
94
85
  rubygems_mfa_required: 'true'
95
86
  post_install_message:
96
87
  rdoc_options: []
@@ -106,23 +97,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
97
  - - ">="
107
98
  - !ruby/object:Gem::Version
108
99
  version: '0'
109
- requirements:
110
- - net-snmp
111
- rubygems_version: 3.2.32
100
+ requirements: []
101
+ rubygems_version: 3.3.7
112
102
  signing_key:
113
103
  specification_version: 4
114
104
  summary: SNMP Client library
115
- test_files:
116
- - spec/client_spec.rb
117
- - spec/handlers/celluloid_spec.rb
118
- - spec/mib_spec.rb
119
- - spec/oid_spec.rb
120
- - spec/pdu_spec.rb
121
- - spec/security_parameters_spec.rb
122
- - spec/session_spec.rb
123
- - spec/spec_helper.rb
124
- - spec/support/celluloid.rb
125
- - spec/support/request_examples.rb
126
- - spec/timeticks_spec.rb
127
- - spec/v3_session_spec.rb
128
- - spec/varbind_spec.rb
105
+ test_files: []
data/spec/client_spec.rb DELETED
@@ -1,226 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "support/request_examples"
4
-
5
- RSpec.describe NETSNMP::Client do
6
- let(:host) { SNMPHOST }
7
-
8
- let(:device_options) do
9
- {
10
- peername: SNMPHOST,
11
- port: SNMPPORT
12
- }
13
- end
14
- describe "v1" do
15
- it_behaves_like "an snmp client" do
16
- let(:protocol_options) do
17
- {
18
- version: "1",
19
- community: "public"
20
- }
21
- end
22
- let(:get_oid) { "1.3.6.1.2.1.1.5.0" }
23
- let(:next_oid) { "1.3.6.1.2.1.1.6.0" }
24
- let(:walk_oid) { "1.3.6.1.2.1.1" }
25
- let(:set_oid) { "sysUpTime.0" } # sysUpTimeInstance
26
- let(:get_result) { "zeus.snmplabs.com (you can change this!)" }
27
- let(:next_result) { "San Francisco, California, United States" }
28
- let(:walk_result) do
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
- end
40
- let(:set_oid_result) { 43 }
41
- end
42
- end
43
- describe "v2" do
44
- it_behaves_like "an snmp client" do
45
- let(:protocol_options) do
46
- {
47
- version: "2c",
48
- community: "public"
49
- }
50
- end
51
- let(:get_oid) { "sysName.0" }
52
- let(:next_oid) { "1.3.6.1.2.1.1.6.0" }
53
- let(:walk_oid) { "system" }
54
- let(:set_oid) { "sysUpTime.0" }
55
- let(:get_result) { "zeus.snmplabs.com (you can change this!)" }
56
- let(:next_result) { "San Francisco, California, United States" }
57
- let(:walk_result) do
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
- end
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
88
- end
89
- end
90
-
91
- describe "v3" do
92
- let(:extra_options) { {} }
93
- let(:version_options) do
94
- {
95
- version: "3",
96
- context: "a172334d7d97871b72241397f713fa12"
97
- }
98
- end
99
- let(:get_oid) { "sysName.0" }
100
- let(:next_oid) { "1.3.6.1.2.1.1.6.0" }
101
- let(:set_oid) { "sysUpTime.0" } # sysUpTimeInstance
102
- let(:walk_oid) { "1.3.6.1.2.1.1.9.1.3" }
103
- let(:get_result) { "tt" }
104
- let(:next_result) { "KK12 (edit /etc/snmp/snmpd.conf)" }
105
- let(:walk_result) do
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
- end
117
- let(:set_oid_result) { 43 }
118
- context "with a no auth no priv policy" do
119
- let(:user_options) { { username: "unsafe", security_level: :noauth } }
120
- it_behaves_like "an snmp client" do
121
- let(:protocol_options) { version_options.merge(user_options).merge(extra_options) }
122
- # why is this here? that variation/notification community causes the simulagtor to go down
123
- # until I find the origin of the issue and patched it with an appropriated community, this
124
- # is here so that I test the set call at least once, although I'm sure it'll work always
125
- # for v3
126
- describe "#set" do
127
- let(:extra_options) { { context: "0886e1397d572377c17c15036a1e6c66" } }
128
- it "updates the value of the oid" do
129
- prev_value = subject.get(oid: set_oid)
130
- expect(prev_value).to be_a(Integer)
131
-
132
- # without type
133
- subject.set(oid: set_oid, value: set_oid_result)
134
- expect(subject.get(oid: set_oid)).to eq(set_oid_result)
135
-
136
- subject.set(oid: set_oid, value: prev_value)
137
- end
138
- end
139
- end
140
- end
141
- context "with an only auth policy" do
142
- context "speaking md5" do
143
- let(:user_options) do
144
- { username: "authmd5", security_level: :auth_no_priv,
145
- auth_password: "maplesyrup", auth_protocol: :md5 }
146
- end
147
- it_behaves_like "an snmp client" do
148
- let(:protocol_options) { version_options.merge(user_options).merge(extra_options) }
149
- end
150
- end
151
- context "speaking sha" do
152
- let(:user_options) do
153
- { username: "authsha", security_level: :auth_no_priv,
154
- auth_password: "maplesyrup", auth_protocol: :sha }
155
- end
156
- it_behaves_like "an snmp client" do
157
- let(:protocol_options) { version_options.merge(user_options).merge(extra_options) }
158
- end
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
169
- end
170
- context "with an auth priv policy" do
171
- context "auth in md5, encrypting in des" do
172
- let(:user_options) do
173
- { username: "authprivmd5des", auth_password: "maplesyrup",
174
- auth_protocol: :md5, priv_password: "maplesyrup",
175
- priv_protocol: :des }
176
- end
177
- it_behaves_like "an snmp client" do
178
- let(:protocol_options) { version_options.merge(user_options).merge(extra_options) }
179
- end
180
- end
181
- context "auth in sha, encrypting in des" do
182
- let(:user_options) do
183
- { username: "authprivshades", auth_password: "maplesyrup",
184
- auth_protocol: :sha, priv_password: "maplesyrup",
185
- priv_protocol: :des }
186
- end
187
- it_behaves_like "an snmp client" do
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
201
- end
202
- end
203
-
204
- context "auth in md5, encrypting in aes" do
205
- let(:user_options) do
206
- { username: "authprivmd5aes", auth_password: "maplesyrup",
207
- auth_protocol: :md5, priv_password: "maplesyrup",
208
- priv_protocol: :aes }
209
- end
210
- it_behaves_like "an snmp client" do
211
- let(:protocol_options) { version_options.merge(user_options).merge(extra_options) }
212
- end
213
- end
214
- context "auth in sha, encrypting in aes" do
215
- let(:user_options) do
216
- { username: "authprivshaaes", auth_password: "maplesyrup",
217
- auth_protocol: :sha, priv_password: "maplesyrup",
218
- priv_protocol: :aes }
219
- end
220
- it_behaves_like "an snmp client" do
221
- let(:protocol_options) { version_options.merge(user_options).merge(extra_options) }
222
- end
223
- end
224
- end
225
- end
226
- end
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "celluloid/io"
4
- require_relative "../support/request_examples"
5
- require_relative "../support/celluloid"
6
-
7
- RSpec.describe "with cellulloid", type: :celluloid do
8
- include CelluloidHelpers
9
- let(:user_options) do
10
- { username: "authprivmd5des", auth_password: "maplesyrup",
11
- auth_protocol: :md5, priv_password: "maplesyrup",
12
- priv_protocol: :des }
13
- end
14
-
15
- let(:get_oid) { "1.3.6.1.2.1.1.5.0" }
16
- let(:next_oid) { "1.3.6.1.2.1.1.6.0" }
17
- let(:set_oid) { "1.3.6.1.2.1.1.3.0" } # sysUpTimeInstance
18
- let(:walk_oid) { "1.3.6.1.2.1.1.9.1.3" }
19
- let(:get_result) { "tt" }
20
- let(:next_result) { "KK12 (edit /etc/snmp/snmpd.conf)" }
21
- let(:walk_result) do
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
- end
33
-
34
- before(:all) { Celluloid.boot }
35
- around(:each) do |example|
36
- within_io_actor { example.run }
37
- end
38
- let(:proxy) { CelluloidHelpers::Proxy.new(SNMPHOST, SNMPPORT) }
39
- after(:each) { proxy.close }
40
-
41
- it_behaves_like "an snmp client" do
42
- subject { NETSNMP::Client.new(**options) }
43
- let(:device_options) { { proxy: proxy } }
44
- let(:protocol_options) { user_options }
45
- let(:extra_options) { { version: 3, context: "a172334d7d97871b72241397f713fa12" } }
46
- end
47
- end
data/spec/mib_spec.rb DELETED
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe NETSNMP::MIB do
4
- describe ".oid" do
5
- it { expect(described_class.oid("1.2.3.4")).to eq("1.2.3.4") }
6
- it { expect(described_class.oid("ifTable")).to eq("1.3.6.1.2.1.2.2") }
7
- it { expect(described_class.oid("sysDescr.0")).to eq("1.3.6.1.2.1.1.1.0") }
8
- it { expect(described_class.oid("ifTable.1.23")).to eq("1.3.6.1.2.1.2.2.1.23") }
9
- it { expect(described_class.oid("IF-MIB::ifTable.1.23")).to eq("1.3.6.1.2.1.2.2.1.23") }
10
- it { expect(described_class.oid("IFMIB::ifTable.1.23")).to be_nil }
11
- it { expect(described_class.oid("IF-MIB::")).to be_nil }
12
- end
13
- end
data/spec/oid_spec.rb DELETED
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe NETSNMP::OID do
4
- # let(:code) { "SNMPv2-MIB::sysDescr.0" }
5
- let(:code) { "1.3.6.1.2.1.1.1.0" }
6
- subject { described_class.build(code) }
7
-
8
- describe ".build" do
9
- it { expect(described_class.build([1, 3, 6, 1, 2, 1, 1, 1, 0]).to_s).to eq(code) }
10
- it { expect(described_class.build(".#{code}").to_s).to eq(code) }
11
- it { expect { described_class.build("blablabla") }.to raise_error(NETSNMP::Error) }
12
- end
13
-
14
- describe ".to_asn" do
15
- it { expect(described_class.to_asn(subject).to_der).to eq("\x06\b+\x06\x01\x02\x01\x01\x01\x00".b) }
16
- end
17
- end
data/spec/pdu_spec.rb DELETED
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe NETSNMP::PDU do
4
- let(:get_request_oid) { ".1.3.6.1.2.1.1.1.0" }
5
- let(:encoded_get_pdu) do
6
- "0'\002\001\000\004\006public\240\032\002\002?*\002\001\000\002\001\0000\0160\f\006\b+\006\001\002\001\001\001\000\005\000"
7
- end
8
- let(:encoded_response_pdu) do
9
- "0+\002\001\000\004\006public\242\036\002\002'\017\002\001\000\002\001\0000\0220\020\006\b+\006\001\002\001\001\001\000\004\004test"
10
- end
11
-
12
- describe "#to_der" do
13
- let(:pdu_get) do
14
- described_class.build(:get, version: 0,
15
- community: "public",
16
- request_id: 16170)
17
- end
18
-
19
- context "v1" do
20
- before { pdu_get.add_varbind(oid: get_request_oid) }
21
- it { expect(pdu_get.to_der).to eq(encoded_get_pdu.b) }
22
- end
23
- end
24
-
25
- describe "#decoding pdus" do
26
- describe "v1" do
27
- let(:pdu_response) { described_class.decode(encoded_response_pdu) }
28
- it { expect(pdu_response.version).to be(0) }
29
- it { expect(pdu_response.community).to eq("public") }
30
- it { expect(pdu_response.request_id).to be(9999) }
31
-
32
- it { expect(pdu_response.varbinds.length).to be(1) }
33
- it { expect(pdu_response.varbinds[0].oid).to eq("1.3.6.1.2.1.1.1.0") }
34
- it { expect(pdu_response.varbinds[0].value).to eq("test") }
35
- end
36
- end
37
- end
@@ -1,90 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # FROM https://tools.ietf.org/html/rfc3414#appendix-A.2.1
4
- RSpec.describe NETSNMP::SecurityParameters do
5
- let(:engine_id) { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02".b }
6
- let(:password) { "maplesyrup" }
7
- describe "#passkey" do
8
- context "md5" do
9
- subject { described_class.new(security_level: :auth_no_priv, auth_protocol: :md5, username: "username", engine_id: engine_id, auth_password: "maplesyrup") }
10
- it { expect(subject.send(:passkey, password)).to eq("\x9f\xaf\x32\x83\x88\x4e\x92\x83\x4e\xbc\x98\x47\xd8\xed\xd9\x63".b) }
11
- end
12
- context "sha" do
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
- 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
- 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
23
- end
24
-
25
- describe "keys" do
26
- let(:md5_sec) do
27
- described_class.new(security_level: :auth_priv,
28
- auth_protocol: :md5,
29
- priv_protocol: :des,
30
- username: "username",
31
- auth_password: password,
32
- priv_password: password,
33
- engine_id: engine_id)
34
- end
35
- let(:sha_sec) do
36
- described_class.new(security_level: :auth_priv,
37
- auth_protocol: :sha,
38
- priv_protocol: :des,
39
- username: "username",
40
- auth_password: password,
41
- priv_password: password,
42
- engine_id: engine_id)
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
53
- it do
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)
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)
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)
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)
60
- end
61
- end
62
-
63
- context "#must_revalidate?" do
64
- let(:security_options) do
65
- { username: "authprivmd5des", auth_password: "maplesyrup",
66
- auth_protocol: :md5, priv_password: "maplesyrup",
67
- priv_protocol: :des, security_level: :auth_priv }
68
- end
69
- subject { described_class.new(**security_options) }
70
- context "for v3" do
71
- context "when initialized" do
72
- it { expect(subject.must_revalidate?).to be_truthy }
73
- end
74
- context "when given a new engine id" do
75
- before { subject.engine_id = "NEWENGINE" }
76
- it { expect(subject.must_revalidate?).to be_falsy }
77
- context "when limit surpasses" do
78
- before do
79
- subject.instance_variable_set(:@timeliness, Process.clock_gettime(Process::CLOCK_MONOTONIC, :second) - 150)
80
- end
81
- it { expect(subject.must_revalidate?).to be_truthy }
82
- context "when given a new engine id" do
83
- before { subject.engine_id = "UPDATEDENGINE" }
84
- it { expect(subject.must_revalidate?).to be_falsy }
85
- end
86
- end
87
- end
88
- end
89
- end
90
- end
data/spec/session_spec.rb DELETED
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe NETSNMP::Session do
4
- let(:host) { SNMPHOST }
5
- let(:options) do
6
- {
7
- version: "2c",
8
- context: "public",
9
- port: SNMPPORT
10
- }
11
- end
12
- subject { described_class.new(host: host, **options) }
13
- after { subject.close }
14
- end
data/spec/spec_helper.rb DELETED
@@ -1,67 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- GC.auto_compact = true if GC.respond_to?(:auto_compact=)
4
-
5
- if ENV.key?("CI")
6
- require "simplecov"
7
- SimpleCov.command_name "#{RUBY_ENGINE}-#{RUBY_VERSION}"
8
- SimpleCov.coverage_dir "coverage/#{RUBY_ENGINE}-#{RUBY_VERSION}"
9
- end
10
-
11
- if defined?(SimpleCov)
12
- SimpleCov.start do
13
- add_filter ".bundle"
14
- add_filter "/spec/"
15
- end
16
- end
17
-
18
- require "bundler/setup"
19
- Bundler.require(:default, :test)
20
-
21
- require "netsnmp"
22
-
23
- SNMPPORT = ENV.fetch("SNMP_PORT", 1161).to_i
24
- SNMPHOST = ENV.fetch("SNMP_HOST", "localhost")
25
-
26
- # This file was generated by the `rspec --init` command. Conventionally, all
27
- # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
28
- # The generated `.rspec` file contains `--require spec_helper` which will cause
29
- # this file to always be loaded, without a need to explicitly require it in any
30
- # files.
31
- #
32
- # Given that it is always loaded, you are encouraged to keep this file as
33
- # light-weight as possible. Requiring heavyweight dependencies from this file
34
- # will add to the boot time of your test suite on EVERY test run, even for an
35
- # individual file that may not need all of that loaded. Instead, consider making
36
- # a separate helper file that requires the additional dependencies and performs
37
- # the additional setup, and require it from the spec files that actually need
38
- # it.
39
- #
40
- # The `.rspec` file also contains a few flags that are not defaults but that
41
- # users commonly want.
42
- #
43
- # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
44
- RSpec.configure do |config|
45
- # rspec-expectations config goes here. You can use an alternate
46
- # assertion/expectation library such as wrong or the stdlib/minitest
47
- # assertions if you prefer.
48
- config.expect_with :rspec do |expectations|
49
- # This option will default to `true` in RSpec 4. It makes the `description`
50
- # and `failure_message` of custom matchers include text for helper methods
51
- # defined using `chain`, e.g.:
52
- # be_bigger_than(2).and_smaller_than(4).description
53
- # # => "be bigger than 2 and smaller than 4"
54
- # ...rather than:
55
- # # => "be bigger than 2"
56
- expectations.include_chain_clauses_in_custom_matcher_descriptions = true
57
- end
58
-
59
- # rspec-mocks config goes here. You can use an alternate test double
60
- # library (such as bogus or mocha) by changing the `mock_with` option here.
61
- config.mock_with :rspec do |mocks|
62
- # Prevents you from mocking or stubbing a method that does not exist on
63
- # a real object. This is generally recommended, and will default to
64
- # `true` in RSpec 4.
65
- mocks.verify_partial_doubles = true
66
- end
67
- end
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copied from celluloid-io spec helpers
4
- module CelluloidHelpers
5
- class WrapperActor
6
- include ::Celluloid::IO
7
- execute_block_on_receiver :wrap
8
-
9
- def wrap
10
- yield
11
- end
12
- end
13
-
14
- def with_wrapper_actor
15
- WrapperActor.new
16
- end
17
-
18
- def within_io_actor(&block)
19
- actor = WrapperActor.new
20
- actor.wrap(&block)
21
- ensure
22
- begin
23
- actor.terminate if actor.alive?
24
- rescue StandardError
25
- nil
26
- end
27
- end
28
-
29
- class Proxy
30
- MAXPDUSIZE = 0xffff + 1
31
-
32
- def initialize(host, port)
33
- @socket = Celluloid::IO::UDPSocket.new
34
- @socket.connect(host, port)
35
- @timeout = 2
36
- end
37
-
38
- def send(payload)
39
- @socket.send(payload, 0)
40
- recv
41
- end
42
-
43
- def recv(bytesize = MAXPDUSIZE)
44
- Celluloid.timeout(@timeout) do
45
- datagram, = @socket.recvfrom(bytesize)
46
- datagram
47
- end
48
- rescue Celluloid::TaskTimeout
49
- raise Timeout::Error, "Timeout after #{@timeout} seconds"
50
- end
51
-
52
- def close
53
- @socket.close
54
- end
55
- end
56
- end
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.shared_examples "an snmp client" do
4
- let(:device_options) do
5
- {
6
- host: SNMPHOST,
7
- port: SNMPPORT
8
- }
9
- end
10
- let(:protocol_options) { {} }
11
- let(:extra_options) { {} }
12
- let(:options) { protocol_options.merge(device_options).merge(extra_options) }
13
-
14
- subject { described_class.new(**options) }
15
-
16
- describe "#get" do
17
- let(:value) { subject.get(oid: get_oid) }
18
- it "fetches the varbinds for a given oid" do
19
- expect(value).to eq(get_result)
20
- end
21
- context "with multiple oids" do
22
- let(:value) { subject.get({ oid: get_oid }, oid: next_oid) }
23
- it "returns the values for both" do
24
- expect(value).to be_a(Array)
25
- expect(value).to include(get_result)
26
- expect(value).to include(next_result)
27
- end
28
- end
29
- end
30
-
31
- describe "#get_next" do
32
- let(:varbind) { subject.get_next(oid: get_oid) }
33
- it "fetches the varbinds for the next oid" do
34
- oid, value = varbind
35
- expect(value).to start_with(next_result)
36
- expect(oid).to eq(next_oid)
37
- end
38
- end
39
-
40
- describe "#walk" do
41
- let(:value) { subject.walk(oid: walk_oid) }
42
- it "fetches the varbinds for the next oid" do
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
54
- end
55
- end
56
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # from https://ask.wireshark.org/questions/14002/how-to-decode-timeticks-hundreds-seconds-to-readable-date-time
4
- RSpec.describe NETSNMP::Timetick do
5
- subject { described_class.new(1525917187) }
6
-
7
- describe "as an integer" do
8
- it { expect((1 + subject).to_i).to be(1525917188) }
9
- end
10
-
11
- describe "as an embedded string" do
12
- it { expect(subject.to_s).to eq("Timeticks: (1525917187) 176 days, 14:39:31.87") }
13
- end
14
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe NETSNMP::V3Session do
4
- let(:security_options) do
5
- { username: "authprivmd5des", auth_password: "maplesyrup",
6
- auth_protocol: :md5, priv_password: "maplesyrup",
7
- priv_protocol: :des, security_level: :auth_priv }
8
- end
9
- it "generates the security parameters handler" do
10
- sess = described_class.new(**security_options.merge(host: SNMPHOST, port: SNMPPORT))
11
- # not generated yet
12
- expect(sess.instance_variable_get(:@security_parameters)).to be_a(NETSNMP::SecurityParameters)
13
- end
14
-
15
- it "allows to pass a custom one" do
16
- sec_params = NETSNMP::SecurityParameters.new(**security_options)
17
- sess = described_class.new(host: SNMPHOST, port: SNMPPORT, security_parameters: sec_params)
18
- # not generated yet
19
- expect(sess.instance_variable_get(:@security_parameters)).to be(sec_params)
20
- end
21
-
22
- it "fails if the pass object doesn't follow the expected api" do
23
- expect { described_class.new(host: SNMPHOST, port: SNMPPORT, security_parameters: double) }.to raise_error(NETSNMP::Error)
24
- end
25
- end
data/spec/varbind_spec.rb DELETED
@@ -1,136 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe NETSNMP::Varbind do
4
- using NETSNMP::StringExtensions
5
-
6
- describe "#to_der" do
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) }
8
-
9
- context "application specific" do
10
- it "converts ip addresses" do
11
- ipaddr = IPAddr.new("10.11.104.2")
12
- varbind = described_class.new(".1.3.6.1.4.1.2011.6.3.1.1.0", value: ipaddr)
13
- expect(varbind.to_der).to end_with("@\x04\n\vh\x02".b)
14
- asn = varbind.to_asn.value.last
15
- expect(varbind.convert_application_asn(asn)).to eq(ipaddr)
16
- end
17
- it "converts custom timeticks" do
18
- timetick = NETSNMP::Timetick.new(1) # yes, one timetick
19
- varbind = described_class.new(".1.3.6.1.2.1.1.3.0", value: timetick)
20
- expect(varbind.to_der).to end_with("\x04\x00\x00\x00\x01".b) # ends with an octet string rep of 1 timetick
21
- asn = varbind.to_asn.value.last
22
- expect(varbind.convert_application_asn(asn)).to eq(timetick)
23
- end
24
-
25
- context "when passed a type" do
26
- it "converts gauge32 without a leading byte" do
27
- gauge = 127
28
- varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :gauge, value: gauge)
29
- value_str = varbind.to_der[12..-1]
30
- header = value_str[0].unpack1("B8")
31
-
32
- # Class: Primitive Application
33
- expect(header[0..1]).to eq("01")
34
- expect(header[2]).to eq("0")
35
- # Type: Integer
36
- expect(header[3..-1].to_i(2)).to eq(2)
37
- # Length & Value
38
- expect(varbind.to_der).to end_with("\x01\x7F".b) # 2 Bytes
39
-
40
- # Original Value
41
- asn = varbind.to_asn.value.last
42
- expect(varbind.convert_application_asn(asn)).to eq(gauge)
43
- end
44
- it "converts gauge32 with a leading byte" do
45
- gauge = 128
46
- varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :gauge, value: gauge)
47
- value_str = varbind.to_der[12..-1]
48
- header = value_str[0].unpack1("B8")
49
-
50
- # Class: Primitive Application
51
- expect(header[0..1]).to eq("01")
52
- expect(header[2]).to eq("0")
53
- # Type: Integer
54
- expect(header[3..-1].to_i(2)).to eq(2)
55
- # Length & Value
56
- expect(varbind.to_der).to end_with("\x02\x00\x80".b) # 4 Bytes, all FF
57
-
58
- # Original Value
59
- asn = varbind.to_asn.value.last
60
- expect(varbind.convert_application_asn(asn)).to eq(gauge)
61
- end
62
- it "converts gauge32" do
63
- gauge = 805
64
- varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :gauge, value: gauge)
65
- value_str = varbind.to_der[12..-1]
66
- header = value_str[0].unpack1("B8")
67
-
68
- # Class: Primitive Application
69
- expect(header[0..1]).to eq("01")
70
- expect(header[2]).to eq("0")
71
- # Type: Integer
72
- expect(header[3..-1].to_i(2)).to eq(2)
73
- # Length & Value
74
- expect(varbind.to_der).to end_with("\x02\x03%".b)
75
-
76
- # Original Value
77
- asn = varbind.to_asn.value.last
78
- expect(varbind.convert_application_asn(asn)).to eq(gauge)
79
- end
80
- it "converts counter32 without a leading byte" do
81
- counter = 127
82
- varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :counter32, value: counter)
83
- expect(varbind.to_der).to end_with("\x01\x7F".b)
84
- asn = varbind.to_asn.value.last
85
- expect(varbind.convert_application_asn(asn)).to eq(counter)
86
- end
87
- it "converts counter32 with a leading byte" do
88
- counter = 128
89
- varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :counter32, value: counter)
90
- expect(varbind.to_der).to end_with("\x02\x00\x80".b)
91
- asn = varbind.to_asn.value.last
92
- expect(varbind.convert_application_asn(asn)).to eq(counter)
93
- end
94
- it "converts counter32" do
95
- counter = 998932
96
- varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :counter32, value: counter)
97
- expect(varbind.to_der).to end_with("\x0F>\x14".b)
98
- asn = varbind.to_asn.value.last
99
- expect(varbind.convert_application_asn(asn)).to eq(counter)
100
- end
101
- it "converts counter64" do
102
- counter = 998932
103
- varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :counter64, value: counter)
104
- expect(varbind.to_der).to end_with("\x0F>\x14".b)
105
- asn = varbind.to_asn.value.last
106
- expect(varbind.convert_application_asn(asn)).to eq(counter)
107
-
108
- counter = 4294967296
109
- varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :counter64, value: counter)
110
- expect(varbind.to_der).to end_with("\x01\x00\x00\x00\x00".b)
111
- asn = varbind.to_asn.value.last
112
- expect(varbind.convert_application_asn(asn)).to eq(counter)
113
-
114
- counter = 309084502
115
- varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :counter64, value: counter)
116
- expect(varbind.to_der).to include("F\x04".b)
117
- asn = varbind.to_asn.value.last
118
- expect(varbind.convert_application_asn(asn)).to eq(counter)
119
-
120
- counter = 2_613_579_752_238
121
- varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :counter64, value: counter)
122
- expect(varbind.to_der).to include("F\x06".b)
123
- asn = varbind.to_asn.value.last
124
- expect(varbind.convert_application_asn(asn)).to eq(counter)
125
- end
126
- it "converts integer ticks" do
127
- timetick = 1
128
- varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :timetick, value: timetick)
129
- expect(varbind.to_der).to end_with("\x04\x00\x00\x00\x01".b)
130
- asn = varbind.to_asn.value.last
131
- expect(varbind.convert_application_asn(asn)).to eq(timetick)
132
- end
133
- end
134
- end
135
- end
136
- end