netsnmp 0.1.5 → 0.2.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.
@@ -0,0 +1,20 @@
1
+ module OpenSSL
2
+ module ASN1
3
+ class ASN1Data
4
+ end
5
+ class ObjectId < ASN1Data
6
+ end
7
+ class Primitive < ASN1Data
8
+ end
9
+ class Integer < ASN1Data
10
+ end
11
+ class OctetString < ASN1Data
12
+ end
13
+ class Sequence < ASN1Data
14
+ end
15
+ end
16
+ end
17
+
18
+ interface _ToAsn
19
+ def to_asn: () -> OpenSSL::ASN1::ASN1Data
20
+ end
@@ -0,0 +1,48 @@
1
+ module NETSNMP
2
+ type pdu_type = :get | :getnext | :set | :inform | :trap | :response
3
+
4
+ class PDU
5
+
6
+ # type pdu_options = {
7
+ # headers: [snmp_version?, String?],
8
+ # ?request_id: String,
9
+ # ?error_status: Integer,
10
+ # ?error_index: Integer,
11
+ # ?varbinds: Array[varbind_options]
12
+ # }
13
+
14
+ attr_reader varbinds: Array[Varbind]
15
+ attr_reader type: pdu_type
16
+ attr_reader version: snmp_version
17
+ attr_reader community: String
18
+ attr_reader request_id: Integer
19
+
20
+ def self.decode: (String der) -> PDU
21
+ | (OpenSSL::ASN1::ASN1Data der) -> PDU
22
+
23
+ def self.build: (pdu_type, **untyped) -> PDU
24
+
25
+
26
+ def to_asn: () -> OpenSSL::ASN1::ASN1Data
27
+
28
+ def to_der: () -> String
29
+
30
+ def add_varbind: (oid: oid, **varbind_options) -> void
31
+ alias << add_varbind
32
+
33
+ private
34
+
35
+ def initialize: (
36
+ type: Integer,
37
+ headers: [snmp_version?, String?],
38
+ ?request_id: Integer,
39
+ ?error_status: Integer,
40
+ ?error_index: Integer,
41
+ ?varbinds: Array[varbind_options]
42
+ ) -> untyped
43
+
44
+ def encode_headers_asn: () -> [OpenSSL::ASN1::Integer, OpenSSL::ASN1::OctetString]
45
+
46
+ def check_error_status: (Integer) -> void
47
+ end
48
+ end
@@ -0,0 +1,15 @@
1
+ module NETSNMP
2
+ class ScopedPDU < PDU
3
+ attr_reader engine_id: String
4
+
5
+ private
6
+
7
+ def initialize: (
8
+ type: Integer,
9
+ headers: [String?, String?],
10
+ **untyped
11
+ ) -> void
12
+
13
+ def encode_headers_asn: () -> [OpenSSL::ASN1::OctetString, OpenSSL::ASN1::OctetString]
14
+ end
15
+ end
@@ -0,0 +1,56 @@
1
+ module NETSNMP
2
+ class SecurityParameters
3
+ type security_level = :noauth | :auth_no_priv | :auth_priv | 0 | 1 | 3 | nil
4
+
5
+ type auth_protocol = :md5 | :sha
6
+ type priv_protocol = :des | :aes
7
+
8
+
9
+ @auth_protocol: auth_protocol?
10
+ @auth_password: String?
11
+ @priv_protocol: priv_protocol?
12
+ @priv_password: String?
13
+ @digest: _Authenticate?
14
+ @encryption: _Encrypt?
15
+
16
+ attr_reader security_level: security_level
17
+ attr_reader username: String
18
+ attr_reader engine_id: String
19
+
20
+ def engine_id=: (String id) -> void
21
+
22
+ def encode: (_ToAsn, salt: OpenSSL::ASN1::ASN1Data, engine_time: Integer, engine_boots: Integer) -> [OpenSSL::ASN1::ASN1Data, OpenSSL::ASN1::ASN1Data]
23
+
24
+ def decode: (OpenSSL::ASN1::ASN1Data | String der, salt: OpenSSL::ASN1::ASN1Data | String, engine_time: Integer, engine_boots: Integer) -> OpenSSL::ASN1::ASN1Data
25
+
26
+ def sign: (String message) -> String?
27
+
28
+ def verify: (String stream, String salt) -> void
29
+
30
+ def must_revalidate?: () -> bool
31
+
32
+ private
33
+
34
+ def initialize: (
35
+ username: String,
36
+ ?engine_id: String,
37
+ ?security_level: security_level?,
38
+ ?auth_protocol: auth_protocol?,
39
+ ?auth_password: String?,
40
+ ?priv_protocol: priv_protocol?,
41
+ ?priv_password: String?,
42
+ ) -> untyped
43
+
44
+ def auth_key: () -> String
45
+
46
+ def priv_key: () -> String
47
+
48
+ def check_parameters: () -> void
49
+
50
+ def localize_key: (String key) -> String
51
+
52
+ def passkey: (String password) -> String
53
+
54
+ def authorizable?: () -> bool
55
+ end
56
+ end
@@ -0,0 +1,36 @@
1
+ module NETSNMP
2
+ class Session
3
+ @transport: _Transport
4
+ @version: 0 | 1 | 3
5
+ @community: String?
6
+
7
+ def close: () -> void
8
+
9
+ def build_pdu: (pdu_type, *untyped) -> PDU
10
+
11
+ def send: (PDU) -> PDU
12
+
13
+ private
14
+
15
+ def initialize: (?version: snmp_version, ?community: String, **untyped) -> untyped
16
+
17
+ def validate: (?host: String?, ?port: Integer, ?proxy: _Transport, ?timeout: Integer, **untyped) -> void
18
+
19
+ class Transport
20
+ def initialize: (String host, Integer port, timeout: Integer) -> untyped
21
+ def close: () -> void
22
+ def send: (String payload) -> String
23
+ def write: (String) -> void
24
+ def recv: () -> void
25
+
26
+ private
27
+
28
+ def wait: (:wait_readable | :wait_writable) -> void
29
+ end
30
+ end
31
+
32
+ interface _Transport
33
+ def close: () -> void
34
+ def send: (String payload) -> String
35
+ end
36
+ end
@@ -0,0 +1,7 @@
1
+ module NETSNMP
2
+ class Timetick < Numeric
3
+ @ticks: Integer
4
+
5
+ def to_asn: () -> OpenSSL::ASN1::ASN1Data
6
+ end
7
+ end
@@ -0,0 +1,21 @@
1
+ module NETSNMP
2
+ class V3Session < Session
3
+
4
+ def build_pdu: (pdu_type, *untyped) -> ScopedPDU
5
+
6
+ def send: (ScopedPDU pdu) -> ScopedPDU
7
+ | (ScopedPDU pdu) -> [PDU, String, Integer, Integer]
8
+
9
+ private
10
+
11
+ def encode: (ScopedPDU) -> String
12
+
13
+ def initialize: (?context: String, **untyped) -> untyped
14
+
15
+ def security_parameters: () -> SecurityParameters
16
+
17
+ def probe_for_engine: () -> String
18
+
19
+ def decode: (String, ?security_parameters: SecurityParameters) -> [PDU, String, Integer, Integer]
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ module NETSNMP
2
+ type varbind_options = untyped
3
+
4
+ class Varbind
5
+
6
+ type varbind_value = OpenSSL::ASN1::OctetString | OpenSSL::ASN1::Primitive | OpenSSL::ASN1::ASN1Data | oid_value
7
+
8
+ attr_reader oid: String
9
+ attr_reader value: oid_value
10
+
11
+ def to_asn: () -> OpenSSL::ASN1::Sequence
12
+
13
+ def to_der: () -> String
14
+
15
+ def convert_val: (varbind_value) -> oid_value
16
+
17
+
18
+ def convert_to_asn: (oid_type, oid_value) -> OpenSSL::ASN1::ASN1Data
19
+
20
+ def convert_application_asn: (OpenSSL::ASN1::ASN1Data asn) -> oid_value
21
+
22
+ private
23
+
24
+ def initialize: (oid, ?value: varbind_value, ?type: oid_type) -> untyped
25
+
26
+ def unpack_32bit_integer: (String) -> Integer
27
+
28
+ def unpack_64bit_integer: (String) -> Integer
29
+ end
30
+ end
@@ -3,11 +3,11 @@
3
3
  require_relative "support/request_examples"
4
4
 
5
5
  RSpec.describe NETSNMP::Client do
6
- let(:host) { "localhost" }
6
+ let(:host) { SNMPHOST }
7
7
 
8
8
  let(:device_options) do
9
9
  {
10
- peername: "localhost",
10
+ peername: SNMPHOST,
11
11
  port: SNMPPORT
12
12
  }
13
13
  end
@@ -31,14 +31,15 @@ RSpec.describe "with cellulloid", type: :celluloid do
31
31
  WALK
32
32
  end
33
33
 
34
+ before(:all) { Celluloid.boot }
34
35
  around(:each) do |example|
35
36
  within_io_actor { example.run }
36
37
  end
37
- let(:proxy) { CelluloidHelpers::Proxy.new("localhost", SNMPPORT) }
38
+ let(:proxy) { CelluloidHelpers::Proxy.new(SNMPHOST, SNMPPORT) }
38
39
  after(:each) { proxy.close }
39
40
 
40
41
  it_behaves_like "an snmp client" do
41
- subject { NETSNMP::Client.new(options) }
42
+ subject { NETSNMP::Client.new(**options) }
42
43
  let(:device_options) { { proxy: proxy } }
43
44
  let(:protocol_options) { user_options }
44
45
  let(:extra_options) { { version: 3, context: "a172334d7d97871b72241397f713fa12" } }
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe NETSNMP::Session do
4
- let(:host) { "localhost" }
4
+ let(:host) { SNMPHOST }
5
5
  let(:options) do
6
6
  {
7
7
  version: "2c",
@@ -9,6 +9,6 @@ RSpec.describe NETSNMP::Session do
9
9
  port: SNMPPORT
10
10
  }
11
11
  end
12
- subject { described_class.new(host, options) }
12
+ subject { described_class.new(host: host, **options) }
13
13
  after { subject.close }
14
14
  end
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "simplecov" if ENV["COVERAGE"]
4
- require "coveralls"
5
- Coveralls.wear!
3
+ if ENV.key?("CI")
4
+ require "simplecov"
5
+ SimpleCov.command_name "#{RUBY_ENGINE}-#{RUBY_VERSION}"
6
+ SimpleCov.coverage_dir "coverage/#{RUBY_ENGINE}-#{RUBY_VERSION}"
7
+ end
6
8
 
7
9
  if defined?(SimpleCov)
8
10
  SimpleCov.start do
@@ -17,7 +19,8 @@ Bundler.require(:default, :test)
17
19
 
18
20
  require "netsnmp"
19
21
 
20
- SNMPPORT = (ENV["SNMP_PORT"] || 1161).to_i
22
+ SNMPPORT = ENV.fetch("SNMP_PORT", 1161).to_i
23
+ SNMPHOST = ENV.fetch("SNMP_HOST", "localhost")
21
24
 
22
25
  # This file was generated by the `rspec --init` command. Conventionally, all
23
26
  # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
@@ -3,7 +3,7 @@
3
3
  RSpec.shared_examples "an snmp client" do
4
4
  let(:device_options) do
5
5
  {
6
- host: "localhost",
6
+ host: SNMPHOST,
7
7
  port: SNMPPORT
8
8
  }
9
9
  end
@@ -11,7 +11,7 @@ RSpec.shared_examples "an snmp client" do
11
11
  let(:extra_options) { {} }
12
12
  let(:options) { protocol_options.merge(device_options).merge(extra_options) }
13
13
 
14
- subject { described_class.new(options) }
14
+ subject { described_class.new(**options) }
15
15
 
16
16
  describe "#get" do
17
17
  let(:value) { subject.get(oid: get_oid) }
@@ -7,19 +7,19 @@ RSpec.describe NETSNMP::V3Session do
7
7
  priv_protocol: :des, security_level: :auth_priv }
8
8
  end
9
9
  it "generates the security parameters handler" do
10
- sess = described_class.new(security_options.merge(host: "localhost", port: SNMPPORT))
10
+ sess = described_class.new(**security_options.merge(host: SNMPHOST, port: SNMPPORT))
11
11
  # not generated yet
12
12
  expect(sess.instance_variable_get(:@security_parameters)).to be_a(NETSNMP::SecurityParameters)
13
13
  end
14
14
 
15
15
  it "allows to pass a custom one" do
16
- sec_params = NETSNMP::SecurityParameters.new(security_options)
17
- sess = described_class.new(host: "localhost", port: SNMPPORT, security_parameters: sec_params)
16
+ sec_params = NETSNMP::SecurityParameters.new(**security_options)
17
+ sess = described_class.new(host: SNMPHOST, port: SNMPPORT, security_parameters: sec_params)
18
18
  # not generated yet
19
19
  expect(sess.instance_variable_get(:@security_parameters)).to be(sec_params)
20
20
  end
21
21
 
22
22
  it "fails if the pass object doesn't follow the expected api" do
23
- expect { described_class.new(host: "localhost", port: SNMPPORT, security_parameters: double) }.to raise_error(NETSNMP::Error)
23
+ expect { described_class.new(host: SNMPHOST, port: SNMPPORT, security_parameters: double) }.to raise_error(NETSNMP::Error)
24
24
  end
25
25
  end
@@ -9,27 +9,124 @@ RSpec.describe NETSNMP::Varbind do
9
9
  ipaddr = IPAddr.new("10.11.104.2")
10
10
  varbind = described_class.new(".1.3.6.1.4.1.2011.6.3.1.1.0", value: ipaddr)
11
11
  expect(varbind.to_der).to end_with("@\x04\n\vh\x02".b)
12
+ asn = varbind.to_asn.value.last
13
+ expect(varbind.convert_application_asn(asn)).to eq(ipaddr)
12
14
  end
13
15
  it "converts custom timeticks" do
14
16
  timetick = NETSNMP::Timetick.new(1) # yes, one timetick
15
17
  varbind = described_class.new(".1.3.6.1.2.1.1.3.0", value: timetick)
16
18
  expect(varbind.to_der).to end_with("\x04\x00\x00\x00\x01".b) # ends with an octet string rep of 1 timetick
19
+ asn = varbind.to_asn.value.last
20
+ expect(varbind.convert_application_asn(asn)).to eq(timetick)
17
21
  end
22
+
18
23
  context "when passed a type" do
24
+ it "converts gauge32 without a leading byte" do
25
+ gauge = 127
26
+ varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :gauge, value: gauge)
27
+ value_str = varbind.to_der[12..-1]
28
+ header = value_str[0].unpack("B8").first
29
+
30
+ # Class: Primitive Application
31
+ expect(header[0..1]).to eq("01")
32
+ expect(header[2]).to eq("0")
33
+ # Type: Integer
34
+ expect(header[3..-1].to_i(2)).to eq(2)
35
+ # Length & Value
36
+ expect(varbind.to_der).to end_with("\x01\x7F".b) # 2 Bytes
37
+
38
+ # Original Value
39
+ asn = varbind.to_asn.value.last
40
+ expect(varbind.convert_application_asn(asn)).to eq(gauge)
41
+ end
42
+ it "converts gauge32 with a leading byte" do
43
+ gauge = 128
44
+ varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :gauge, value: gauge)
45
+ value_str = varbind.to_der[12..-1]
46
+ header = value_str[0].unpack("B8").first
47
+
48
+ # Class: Primitive Application
49
+ expect(header[0..1]).to eq("01")
50
+ expect(header[2]).to eq("0")
51
+ # Type: Integer
52
+ expect(header[3..-1].to_i(2)).to eq(2)
53
+ # Length & Value
54
+ expect(varbind.to_der).to end_with("\x02\x00\x80".b) # 4 Bytes, all FF
55
+
56
+ # Original Value
57
+ asn = varbind.to_asn.value.last
58
+ expect(varbind.convert_application_asn(asn)).to eq(gauge)
59
+ end
19
60
  it "converts gauge32" do
20
61
  gauge = 805
21
62
  varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :gauge, value: gauge)
22
- expect(varbind.to_der).to end_with("B\x02\x03%".b)
63
+ value_str = varbind.to_der[12..-1]
64
+ header = value_str[0].unpack("B8").first
65
+
66
+ # Class: Primitive Application
67
+ expect(header[0..1]).to eq("01")
68
+ expect(header[2]).to eq("0")
69
+ # Type: Integer
70
+ expect(header[3..-1].to_i(2)).to eq(2)
71
+ # Length & Value
72
+ expect(varbind.to_der).to end_with("\x02\x03%".b)
73
+
74
+ # Original Value
75
+ asn = varbind.to_asn.value.last
76
+ expect(varbind.convert_application_asn(asn)).to eq(gauge)
77
+ end
78
+ it "converts counter32 without a leading byte" do
79
+ counter = 127
80
+ varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :counter32, value: counter)
81
+ expect(varbind.to_der).to end_with("\x01\x7F".b)
82
+ asn = varbind.to_asn.value.last
83
+ expect(varbind.convert_application_asn(asn)).to eq(counter)
84
+ end
85
+ it "converts counter32 with a leading byte" do
86
+ counter = 128
87
+ varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :counter32, value: counter)
88
+ expect(varbind.to_der).to end_with("\x02\x00\x80".b)
89
+ asn = varbind.to_asn.value.last
90
+ expect(varbind.convert_application_asn(asn)).to eq(counter)
23
91
  end
24
92
  it "converts counter32" do
25
- gauge = 998932
26
- varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :counter32, value: gauge)
93
+ counter = 998932
94
+ varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :counter32, value: counter)
27
95
  expect(varbind.to_der).to end_with("\x0F>\x14".b)
96
+ asn = varbind.to_asn.value.last
97
+ expect(varbind.convert_application_asn(asn)).to eq(counter)
98
+ end
99
+ it "converts counter64" do
100
+ counter = 998932
101
+ varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :counter64, value: counter)
102
+ expect(varbind.to_der).to end_with("\x0F>\x14".b)
103
+ asn = varbind.to_asn.value.last
104
+ expect(varbind.convert_application_asn(asn)).to eq(counter)
105
+
106
+ counter = 4294967296
107
+ varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :counter64, value: counter)
108
+ expect(varbind.to_der).to end_with("\x01\x00\x00\x00\x00".b)
109
+ asn = varbind.to_asn.value.last
110
+ expect(varbind.convert_application_asn(asn)).to eq(counter)
111
+
112
+ counter = 309084502
113
+ varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :counter64, value: counter)
114
+ expect(varbind.to_der).to include("F\x04".b)
115
+ asn = varbind.to_asn.value.last
116
+ expect(varbind.convert_application_asn(asn)).to eq(counter)
117
+
118
+ counter = 2_613_579_752_238
119
+ varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :counter64, value: counter)
120
+ expect(varbind.to_der).to include("F\x06".b)
121
+ asn = varbind.to_asn.value.last
122
+ expect(varbind.convert_application_asn(asn)).to eq(counter)
28
123
  end
29
124
  it "converts integer ticks" do
30
125
  timetick = 1
31
126
  varbind = described_class.new(".1.3.6.1.2.1.1.3.0", type: :timetick, value: timetick)
32
127
  expect(varbind.to_der).to end_with("\x04\x00\x00\x00\x01".b)
128
+ asn = varbind.to_asn.value.last
129
+ expect(varbind.convert_application_asn(asn)).to eq(timetick)
33
130
  end
34
131
  end
35
132
  end