netsnmp 0.6.4 → 0.7.0

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