netsnmp 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module NETSNMP
3
4
  module Encryption
4
5
  class AES
@@ -7,7 +8,7 @@ module NETSNMP
7
8
  @local = local
8
9
  end
9
10
 
10
- def encrypt(decrypted_data, engine_boots: , engine_time: )
11
+ def encrypt(decrypted_data, engine_boots:, engine_time:)
11
12
  cipher = OpenSSL::Cipher::AES128.new(:CFB)
12
13
 
13
14
  iv, salt = generate_encryption_key(engine_boots, engine_time)
@@ -24,12 +25,11 @@ module NETSNMP
24
25
  NETSNMP.debug { "encrypted:\n#{Hexdump.dump(encrypted_data)}" }
25
26
 
26
27
  [encrypted_data, salt]
27
-
28
28
  end
29
29
 
30
- def decrypt(encrypted_data, salt: , engine_boots: , engine_time: )
31
- raise Error, "invalid priv salt received" unless salt.length % 8 == 0
32
- raise Error, "invalid encrypted PDU received" unless encrypted_data.length % 8 == 0
30
+ def decrypt(encrypted_data, salt:, engine_boots:, engine_time:)
31
+ raise Error, "invalid priv salt received" unless (salt.length % 8).zero?
32
+ raise Error, "invalid encrypted PDU received" unless (encrypted_data.length % 8).zero?
33
33
 
34
34
  cipher = OpenSSL::Cipher::AES128.new(:CFB)
35
35
  cipher.padding = 0
@@ -40,13 +40,14 @@ module NETSNMP
40
40
  cipher.key = des_key
41
41
  cipher.iv = iv
42
42
  decrypted_data = cipher.update(encrypted_data) + cipher.final
43
- NETSNMP.debug {"decrypted:\n#{Hexdump.dump(decrypted_data)}" }
43
+ NETSNMP.debug { "decrypted:\n#{Hexdump.dump(decrypted_data)}" }
44
44
 
45
45
  hlen, bodylen = OpenSSL::ASN1.traverse(decrypted_data) { |_, _, x, y, *| break x, y }
46
- decrypted_data.byteslice(0, hlen+bodylen)
46
+ decrypted_data.byteslice(0, hlen + bodylen)
47
47
  end
48
48
 
49
49
  private
50
+
50
51
  # 8.1.1.1
51
52
  def generate_encryption_key(boots, time)
52
53
  salt = [0xff & (@local >> 56),
@@ -62,23 +63,22 @@ module NETSNMP
62
63
  iv = generate_decryption_key(boots, time, salt)
63
64
 
64
65
  [iv, salt]
65
- end
66
-
67
- def generate_decryption_key(boots, time, salt)
68
- [0xff & (boots >> 24),
69
- 0xff & (boots >> 16),
70
- 0xff & (boots >> 8),
71
- 0xff & boots,
72
- 0xff & (time >> 24),
73
- 0xff & (time >> 16),
74
- 0xff & (time >> 8),
75
- 0xff & time].pack("c*") + salt
76
- end
77
-
78
- def des_key
79
- @priv_key[0,16]
80
66
  end
81
67
 
68
+ def generate_decryption_key(boots, time, salt)
69
+ [0xff & (boots >> 24),
70
+ 0xff & (boots >> 16),
71
+ 0xff & (boots >> 8),
72
+ 0xff & boots,
73
+ 0xff & (time >> 24),
74
+ 0xff & (time >> 16),
75
+ 0xff & (time >> 8),
76
+ 0xff & time].pack("c*") + salt
77
+ end
78
+
79
+ def des_key
80
+ @priv_key[0, 16]
81
+ end
82
82
  end
83
83
  end
84
84
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module NETSNMP
3
4
  module Encryption
4
5
  using StringExtensions
@@ -9,8 +10,7 @@ module NETSNMP
9
10
  @local = local
10
11
  end
11
12
 
12
-
13
- def encrypt(decrypted_data, engine_boots: , engine_time: nil)
13
+ def encrypt(decrypted_data, engine_boots:, **)
14
14
  cipher = OpenSSL::Cipher::DES.new(:CBC)
15
15
 
16
16
  iv, salt = generate_encryption_key(engine_boots)
@@ -23,15 +23,14 @@ module NETSNMP
23
23
  decrypted_data << ("\x00" * (8 - diff))
24
24
  end
25
25
 
26
-
27
26
  encrypted_data = cipher.update(decrypted_data) + cipher.final
28
- NETSNMP.debug {"encrypted:\n#{Hexdump.dump(encrypted_data)}" }
27
+ NETSNMP.debug { "encrypted:\n#{Hexdump.dump(encrypted_data)}" }
29
28
  [encrypted_data, salt]
30
29
  end
31
30
 
32
- def decrypt(encrypted_data, salt: , engine_boots: nil, engine_time: nil)
33
- raise Error, "invalid priv salt received" unless salt.length % 8 == 0
34
- raise Error, "invalid encrypted PDU received" unless encrypted_data.length % 8 == 0
31
+ def decrypt(encrypted_data, salt:, **)
32
+ raise Error, "invalid priv salt received" unless (salt.length % 8).zero?
33
+ raise Error, "invalid encrypted PDU received" unless (encrypted_data.length % 8).zero?
35
34
 
36
35
  cipher = OpenSSL::Cipher::DES.new(:CBC)
37
36
  cipher.padding = 0
@@ -42,17 +41,17 @@ module NETSNMP
42
41
  cipher.key = des_key
43
42
  cipher.iv = iv
44
43
  decrypted_data = cipher.update(encrypted_data) + cipher.final
45
- NETSNMP.debug {"decrypted:\n#{Hexdump.dump(decrypted_data)}" }
44
+ NETSNMP.debug { "decrypted:\n#{Hexdump.dump(decrypted_data)}" }
46
45
 
47
46
  hlen, bodylen = OpenSSL::ASN1.traverse(decrypted_data) { |_, _, x, y, *| break x, y }
48
- decrypted_data.byteslice(0, hlen+bodylen)
47
+ decrypted_data.byteslice(0, hlen + bodylen)
49
48
  end
50
49
 
51
-
52
50
  private
51
+
53
52
  # 8.1.1.1
54
53
  def generate_encryption_key(boots)
55
- pre_iv = @priv_key[8,8]
54
+ pre_iv = @priv_key[8, 8]
56
55
  salt = [0xff & (boots >> 24),
57
56
  0xff & (boots >> 16),
58
57
  0xff & (boots >> 8),
@@ -61,19 +60,19 @@ module NETSNMP
61
60
  0xff & (@local >> 16),
62
61
  0xff & (@local >> 8),
63
62
  0xff & @local].pack("c*")
64
- @local = @local == 0xffffffff ? 0 : @local + 1
63
+ @local = @local == 0xffffffff ? 0 : @local + 1
65
64
 
66
- iv = pre_iv.xor(salt)
67
- [iv, salt]
68
- end
65
+ iv = pre_iv.xor(salt)
66
+ [iv, salt]
67
+ end
69
68
 
70
- def generate_decryption_key(salt)
71
- pre_iv = @priv_key[8,8]
72
- pre_iv.xor(salt)
73
- end
69
+ def generate_decryption_key(salt)
70
+ pre_iv = @priv_key[8, 8]
71
+ pre_iv.xor(salt)
72
+ end
74
73
 
75
- def des_key
76
- @priv_key[0,8]
74
+ def des_key
75
+ @priv_key[0, 8]
77
76
  end
78
77
  end
79
78
  end
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module NETSNMP
3
4
  module Encryption
4
5
  class None
5
-
6
- def initialize(*)
7
- end
6
+ def initialize(*); end
8
7
 
9
8
  def encrypt(pdu)
10
9
  pdu.send(:to_asn)
11
10
  end
11
+
12
12
  def decrypt(stream, *)
13
13
  stream
14
14
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module NETSNMP
3
4
  Error = Class.new(StandardError)
4
5
  ConnectionFailed = Class.new(Error)
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module NETSNMP
3
4
  # Factory for the SNMP v3 Message format
4
5
  module Message
5
- extend self
6
+ module_function
7
+
6
8
  AUTHNONE = OpenSSL::ASN1::OctetString.new("\x00" * 12)
7
9
  PRIVNONE = OpenSSL::ASN1::OctetString.new("")
8
10
  MSG_MAX_SIZE = OpenSSL::ASN1::Integer.new(65507)
9
- MSG_SECURITY_MODEL = OpenSSL::ASN1::Integer.new(3) # usmSecurityModel
11
+ MSG_SECURITY_MODEL = OpenSSL::ASN1::Integer.new(3) # usmSecurityModel
10
12
  MSG_VERSION = OpenSSL::ASN1::Integer.new(3)
11
13
  MSG_REPORTABLE = 4
12
14
 
@@ -15,25 +17,25 @@ module NETSNMP
15
17
  #
16
18
  # @return [NETSNMP::ScopedPDU] the decoded PDU
17
19
  #
18
- def decode(stream, security_parameters: )
20
+ def decode(stream, security_parameters:)
19
21
  asn_tree = OpenSSL::ASN1.decode(stream)
20
- version, headers, sec_params, pdu_payload = asn_tree.value
22
+ _version, _headers, sec_params, pdu_payload = asn_tree.value
21
23
 
22
24
  sec_params_asn = OpenSSL::ASN1.decode(sec_params.value).value
23
25
 
24
- engine_id, engine_boots, engine_time, username, auth_param, priv_param = sec_params_asn.map(&:value)
26
+ engine_id, engine_boots, engine_time, _username, auth_param, priv_param = sec_params_asn.map(&:value)
25
27
 
26
28
  # validate_authentication
27
29
  security_parameters.verify(stream.sub(auth_param, AUTHNONE.value), auth_param)
28
30
 
29
- engine_boots=engine_boots.to_i
30
- engine_time =engine_time.to_i
31
+ engine_boots = engine_boots.to_i
32
+ engine_time = engine_time.to_i
31
33
 
32
34
  encoded_pdu = security_parameters.decode(pdu_payload, salt: priv_param,
33
35
  engine_boots: engine_boots,
34
36
  engine_time: engine_time)
35
-
36
- pdu = ScopedPDU.decode(encoded_pdu)
37
+
38
+ pdu = ScopedPDU.decode(encoded_pdu)
37
39
  [pdu, engine_id, engine_boots, engine_time]
38
40
  end
39
41
 
@@ -42,33 +44,33 @@ module NETSNMP
42
44
  #
43
45
  # @return [String] the byte representation of an SNMP v3 Message
44
46
  #
45
- def encode(pdu, security_parameters: , engine_boots: 0, engine_time: 0)
46
- scoped_pdu, salt_param = security_parameters.encode(pdu, salt: PRIVNONE,
47
- engine_boots: engine_boots,
47
+ def encode(pdu, security_parameters:, engine_boots: 0, engine_time: 0)
48
+ scoped_pdu, salt_param = security_parameters.encode(pdu, salt: PRIVNONE,
49
+ engine_boots: engine_boots,
48
50
  engine_time: engine_time)
49
51
 
50
52
  sec_params = OpenSSL::ASN1::Sequence.new([
51
- OpenSSL::ASN1::OctetString.new(security_parameters.engine_id),
52
- OpenSSL::ASN1::Integer.new(engine_boots),
53
- OpenSSL::ASN1::Integer.new(engine_time),
54
- OpenSSL::ASN1::OctetString.new(security_parameters.username),
55
- AUTHNONE,
56
- salt_param
57
- ])
53
+ OpenSSL::ASN1::OctetString.new(security_parameters.engine_id),
54
+ OpenSSL::ASN1::Integer.new(engine_boots),
55
+ OpenSSL::ASN1::Integer.new(engine_time),
56
+ OpenSSL::ASN1::OctetString.new(security_parameters.username),
57
+ AUTHNONE,
58
+ salt_param
59
+ ])
58
60
  message_flags = MSG_REPORTABLE | security_parameters.security_level
59
61
  message_id = OpenSSL::ASN1::Integer.new(SecureRandom.random_number(2147483647))
60
62
  headers = OpenSSL::ASN1::Sequence.new([
61
- message_id, MSG_MAX_SIZE,
62
- OpenSSL::ASN1::OctetString.new( [String(message_flags)].pack("h*") ),
63
- MSG_SECURITY_MODEL
64
- ])
63
+ message_id, MSG_MAX_SIZE,
64
+ OpenSSL::ASN1::OctetString.new([String(message_flags)].pack("h*")),
65
+ MSG_SECURITY_MODEL
66
+ ])
65
67
 
66
- encoded = OpenSSL::ASN1::Sequence([
67
- MSG_VERSION,
68
- headers,
69
- OpenSSL::ASN1::OctetString.new(sec_params.to_der),
70
- scoped_pdu
71
- ]).to_der
68
+ encoded = OpenSSL::ASN1::Sequence([
69
+ MSG_VERSION,
70
+ headers,
71
+ OpenSSL::ASN1::OctetString.new(sec_params.to_der),
72
+ scoped_pdu
73
+ ]).to_der
72
74
  signature = security_parameters.sign(encoded)
73
75
  if signature
74
76
  auth_salt = OpenSSL::ASN1::OctetString.new(signature)
@@ -76,6 +78,5 @@ module NETSNMP
76
78
  end
77
79
  encoded
78
80
  end
79
-
80
81
  end
81
82
  end
data/lib/netsnmp/oid.rb CHANGED
@@ -1,19 +1,20 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module NETSNMP
3
4
  # Abstracts the OID structure
4
5
  #
5
6
  module OID
6
7
  OIDREGEX = /^[\d\.]*$/
7
8
 
8
- extend self
9
+ module_function
9
10
 
10
11
  def build(o)
11
12
  case o
12
13
  when OID then o
13
14
  when Array
14
- o.join('.')
15
+ o.join(".")
15
16
  when OIDREGEX
16
- o = o[1..-1] if o.start_with?('.')
17
+ o = o[1..-1] if o.start_with?(".")
17
18
  o
18
19
  # TODO: MIB to OID
19
20
  else raise Error, "can't convert #{o} to OID"
@@ -28,7 +29,7 @@ module NETSNMP
28
29
  # @return [true, false] whether the given OID belongs to the sub-tree
29
30
  #
30
31
  def parent?(parent_oid, child_oid)
31
- child_oid.match(%r/\A#{parent_oid}\./)
32
+ child_oid.match(/\A#{parent_oid}\./)
32
33
  end
33
34
  end
34
35
  end
data/lib/netsnmp/pdu.rb CHANGED
@@ -1,21 +1,21 @@
1
1
  # frozen_string_literal: true
2
- require 'forwardable'
2
+
3
+ require "forwardable"
3
4
  module NETSNMP
4
5
  # Abstracts the PDU base structure into a ruby object. It gives access to its varbinds.
5
6
  #
6
7
  class PDU
7
- MAXREQUESTID=2147483647
8
+ MAXREQUESTID = 2147483647
8
9
  class << self
9
-
10
10
  def decode(der)
11
11
  asn_tree = case der
12
- when String
13
- OpenSSL::ASN1.decode(der)
14
- when OpenSSL::ASN1::ASN1Data
15
- der
16
- else
17
- raise "#{der}: unexpected data"
18
- end
12
+ when String
13
+ OpenSSL::ASN1.decode(der)
14
+ when OpenSSL::ASN1::ASN1Data
15
+ der
16
+ else
17
+ raise "#{der}: unexpected data"
18
+ end
19
19
 
20
20
  *headers, request = asn_tree.value
21
21
 
@@ -25,34 +25,34 @@ module NETSNMP
25
25
 
26
26
  *request_headers, varbinds = request.value
27
27
 
28
- request_id, error_status, error_index = request_headers.map(&:value).map(&:to_i)
28
+ request_id, error_status, error_index = request_headers.map(&:value).map(&:to_i)
29
29
 
30
30
  varbs = varbinds.value.map do |varbind|
31
- oid_asn, val_asn = varbind.value
31
+ oid_asn, val_asn = varbind.value
32
32
  oid = oid_asn.value
33
33
  { oid: oid, value: val_asn }
34
34
  end
35
35
 
36
36
  new(type: type, headers: [version, community],
37
- error_status: error_status,
38
- error_index: error_index,
39
- request_id: request_id,
40
- varbinds: varbs)
37
+ error_status: error_status,
38
+ error_index: error_index,
39
+ request_id: request_id,
40
+ varbinds: varbs)
41
41
  end
42
42
 
43
43
  # factory method that abstracts initialization of the pdu types that the library supports.
44
- #
44
+ #
45
45
  # @param [Symbol] type the type of pdu structure to build
46
- #
46
+ #
47
47
  def build(type, **args)
48
48
  typ = case type
49
- when :get then 0
50
- when :getnext then 1
51
- # when :getbulk then 5
52
- when :set then 3
53
- when :response then 2
54
- else raise Error, "#{type} is not supported as type"
55
- end
49
+ when :get then 0
50
+ when :getnext then 1
51
+ # when :getbulk then 5
52
+ when :set then 3
53
+ when :response then 2
54
+ else raise Error, "#{type} is not supported as type"
55
+ end
56
56
  new(args.merge(type: typ))
57
57
  end
58
58
  end
@@ -61,11 +61,11 @@ module NETSNMP
61
61
 
62
62
  attr_reader :version, :community, :request_id
63
63
 
64
- def initialize(type: , headers: ,
65
- request_id: nil,
66
- error_status: 0,
67
- error_index: 0,
68
- varbinds: [])
64
+ def initialize(type:, headers:,
65
+ request_id: nil,
66
+ error_status: 0,
67
+ error_index: 0,
68
+ varbinds: [])
69
69
  @version, @community = headers
70
70
  @version = @version.to_i
71
71
  @error_status = error_status
@@ -79,70 +79,67 @@ module NETSNMP
79
79
  check_error_status(@error_status)
80
80
  end
81
81
 
82
-
83
82
  def to_der
84
83
  to_asn.to_der
85
84
  end
86
85
 
87
86
  # Adds a request varbind to the pdu
88
- #
87
+ #
89
88
  # @param [OID] oid a valid oid
90
89
  # @param [Hash] options additional request varbind options
91
90
  # @option options [Object] :value the value for the oid
92
- def add_varbind(oid: , **options)
91
+ def add_varbind(oid:, **options)
93
92
  @varbinds << Varbind.new(oid, **options)
94
93
  end
95
- alias_method :<<, :add_varbind
96
-
94
+ alias << add_varbind
97
95
 
98
96
  def to_asn
99
- request_id_asn = OpenSSL::ASN1::Integer.new( @request_id )
100
- error_asn = OpenSSL::ASN1::Integer.new( @error_status )
101
- error_index_asn = OpenSSL::ASN1::Integer.new( @error_index )
97
+ request_id_asn = OpenSSL::ASN1::Integer.new(@request_id)
98
+ error_asn = OpenSSL::ASN1::Integer.new(@error_status)
99
+ error_index_asn = OpenSSL::ASN1::Integer.new(@error_index)
102
100
 
103
- varbind_asns = OpenSSL::ASN1::Sequence.new( @varbinds.map(&:to_asn) )
101
+ varbind_asns = OpenSSL::ASN1::Sequence.new(@varbinds.map(&:to_asn))
104
102
 
105
- request_asn = OpenSSL::ASN1::ASN1Data.new( [request_id_asn,
106
- error_asn, error_index_asn,
107
- varbind_asns], @type,
108
- :CONTEXT_SPECIFIC )
103
+ request_asn = OpenSSL::ASN1::ASN1Data.new([request_id_asn,
104
+ error_asn, error_index_asn,
105
+ varbind_asns], @type,
106
+ :CONTEXT_SPECIFIC)
109
107
 
110
- OpenSSL::ASN1::Sequence.new( [ *encode_headers_asn, request_asn ] )
108
+ OpenSSL::ASN1::Sequence.new([*encode_headers_asn, request_asn])
111
109
  end
112
110
 
113
111
  private
114
112
 
115
113
  def encode_headers_asn
116
- [ OpenSSL::ASN1::Integer.new( @version ),
117
- OpenSSL::ASN1::OctetString.new( @community ) ]
114
+ [OpenSSL::ASN1::Integer.new(@version),
115
+ OpenSSL::ASN1::OctetString.new(@community)]
118
116
  end
119
117
 
120
-
121
118
  # http://www.tcpipguide.com/free/t_SNMPVersion2SNMPv2MessageFormats-5.htm#Table_219
122
119
  def check_error_status(status)
123
- return if status == 0
120
+ return if status.zero?
124
121
  message = case status
125
- when 1 then "Response-PDU too big"
126
- when 2 then "No such name"
127
- when 3 then "Bad value"
128
- when 4 then "Read Only"
129
- when 5 then "General Error"
130
- when 6 then "Access denied"
131
- when 7 then "Wrong type"
132
- when 8 then "Wrong length"
133
- when 9 then "Wrong encoding"
134
- when 10 then "Wrong value"
135
- when 11 then "No creation"
136
- when 12 then "Inconsistent value"
137
- when 13 then "Resource unavailable"
138
- when 14 then "Commit failed"
139
- when 15 then "Undo Failed"
140
- when 16 then "Authorization Error"
141
- when 17 then "Not Writable"
142
- when 18 then "Inconsistent Name"
143
- else
144
- "Unknown Error: (#{status})"
145
- end
122
+ when 1 then "Response-PDU too big"
123
+ when 2 then "No such name"
124
+ when 3 then "Bad value"
125
+ when 4 then "Read Only"
126
+ when 5 then "General Error"
127
+ when 6 then "Access denied"
128
+ when 7 then "Wrong type"
129
+ when 8 then "Wrong length"
130
+ when 9 then "Wrong encoding"
131
+ when 10 then "Wrong value"
132
+ when 11 then "No creation"
133
+ when 12 then "Inconsistent value"
134
+ when 13 then "Resource unavailable"
135
+ when 14 then "Commit failed"
136
+ when 15 then "Undo Failed"
137
+ when 16 then "Authorization Error"
138
+ when 17 then "Not Writable"
139
+ when 18 then "Inconsistent Name"
140
+ else
141
+ "Unknown Error: (#{status})"
142
+ end
146
143
  raise Error, message
147
144
  end
148
145
  end
@@ -1,19 +1,17 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module NETSNMP
3
4
  class ScopedPDU < PDU
4
-
5
-
6
5
  attr_reader :engine_id
7
6
 
8
- def initialize(type: , headers:, **options)
7
+ def initialize(type:, headers:, **options)
9
8
  @engine_id, @context = headers
10
9
  super(type: type, headers: [3, nil], **options)
11
10
  end
12
11
 
13
12
  def encode_headers_asn
14
- [ OpenSSL::ASN1::OctetString.new(@engine_id || ""),
15
- OpenSSL::ASN1::OctetString.new(@context || "") ]
16
- end
17
-
13
+ [OpenSSL::ASN1::OctetString.new(@engine_id || ""),
14
+ OpenSSL::ASN1::OctetString.new(@context || "")]
15
+ end
18
16
  end
19
17
  end