netsnmp 0.0.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 +7 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/.travis.yml +42 -0
- data/AUTHORS +1 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +201 -0
- data/README.md +162 -0
- data/Rakefile +26 -0
- data/lib/netsnmp.rb +16 -0
- data/lib/netsnmp/client.rb +131 -0
- data/lib/netsnmp/core.rb +12 -0
- data/lib/netsnmp/core/client.rb +15 -0
- data/lib/netsnmp/core/constants.rb +153 -0
- data/lib/netsnmp/core/inline.rb +20 -0
- data/lib/netsnmp/core/libc.rb +48 -0
- data/lib/netsnmp/core/libsnmp.rb +44 -0
- data/lib/netsnmp/core/structures.rb +167 -0
- data/lib/netsnmp/core/utilities.rb +13 -0
- data/lib/netsnmp/errors.rb +8 -0
- data/lib/netsnmp/handlers/celluloid.rb +27 -0
- data/lib/netsnmp/handlers/em.rb +56 -0
- data/lib/netsnmp/oid.rb +94 -0
- data/lib/netsnmp/pdu.rb +105 -0
- data/lib/netsnmp/session.rb +306 -0
- data/lib/netsnmp/varbind.rb +181 -0
- data/lib/netsnmp/version.rb +3 -0
- data/netsnmp.gemspec +36 -0
- data/spec/client_spec.rb +90 -0
- data/spec/core/libc_spec.rb +2 -0
- data/spec/core/libsnmp_spec.rb +32 -0
- data/spec/core/structures_spec.rb +54 -0
- data/spec/handlers/celluloid_spec.rb +29 -0
- data/spec/handlers/em_client_spec.rb +34 -0
- data/spec/oid_spec.rb +9 -0
- data/spec/pdu_spec.rb +29 -0
- data/spec/session_spec.rb +34 -0
- data/spec/spec_helper.rb +114 -0
- data/spec/support/Dockerfile +14 -0
- data/spec/support/celluloid.rb +22 -0
- data/spec/support/start_docker.sh +4 -0
- data/spec/support/stop_docker.sh +5 -0
- data/spec/varbind_spec.rb +54 -0
- metadata +187 -0
@@ -0,0 +1,167 @@
|
|
1
|
+
module NETSNMP::Core
|
2
|
+
# Maps to the relevant netsnmp C library structs.
|
3
|
+
module Structures
|
4
|
+
extend FFI::Library
|
5
|
+
typedef :u_long, :oid
|
6
|
+
|
7
|
+
callback(:snmp_callback, [ :int, :pointer, :int, :pointer, :pointer ], :int)
|
8
|
+
callback(:netsnmp_callback, [ :int, :pointer, :int, :pointer, :pointer ], :int)
|
9
|
+
|
10
|
+
class SessionList < FFI::Struct
|
11
|
+
layout(
|
12
|
+
:next, :pointer,
|
13
|
+
:session, :pointer,
|
14
|
+
:transport, :pointer,
|
15
|
+
:internal, :pointer
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
class Transport < FFI::Struct
|
20
|
+
layout(
|
21
|
+
:domain, :pointer,
|
22
|
+
:domain_length, :int,
|
23
|
+
:local, :pointer,
|
24
|
+
:local_length, :int,
|
25
|
+
:remote, :pointer,
|
26
|
+
:remote_length, :int,
|
27
|
+
:sock, :int,
|
28
|
+
:flags, :u_int,
|
29
|
+
:data, :pointer,
|
30
|
+
:data_length, :int,
|
31
|
+
:msgMaxSize, :size_t,
|
32
|
+
:base_transport, :pointer
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
class Session < FFI::Struct
|
37
|
+
layout(
|
38
|
+
:version, :long,
|
39
|
+
:retries, :int,
|
40
|
+
:timeout, :long,
|
41
|
+
:flags, :u_long,
|
42
|
+
:subsession, :pointer,
|
43
|
+
:next, :pointer,
|
44
|
+
:peername, :pointer,
|
45
|
+
:remote_port, :u_short,
|
46
|
+
:localname, :pointer,
|
47
|
+
:local_port, :u_short,
|
48
|
+
:authenticator, callback([ :pointer, :pointer, :pointer, :uint ], :pointer),
|
49
|
+
:callback, :netsnmp_callback,
|
50
|
+
:callback_magic, :pointer,
|
51
|
+
:s_errno, :int,
|
52
|
+
:s_snmp_errno, :int,
|
53
|
+
:sessid, :long,
|
54
|
+
:community, :pointer,
|
55
|
+
:community_len, :size_t,
|
56
|
+
:rcvMsgMaxSize, :size_t,
|
57
|
+
:sndMsgMaxSize, :size_t,
|
58
|
+
:isAuthoritative, :u_char,
|
59
|
+
:contextEngineID, :pointer,
|
60
|
+
:contextEngineIDLen, :size_t,
|
61
|
+
:engineBoots, :u_int,
|
62
|
+
:engineTime, :u_int,
|
63
|
+
:contextName, :pointer,
|
64
|
+
:contextNameLen, :size_t,
|
65
|
+
:securityEngineID, :pointer,
|
66
|
+
:securityEngineIDLen, :size_t,
|
67
|
+
:securityName, :pointer,
|
68
|
+
:securityNameLen, :size_t,
|
69
|
+
:securityAuthProto, :pointer,
|
70
|
+
:securityAuthProtoLen, :size_t,
|
71
|
+
:securityAuthKey, [:u_char, 32],
|
72
|
+
:securityAuthKeyLen, :size_t,
|
73
|
+
:securityAuthLocalKey, :pointer,
|
74
|
+
:securityAuthLocalKeyLen, :size_t,
|
75
|
+
:securityPrivProto, :pointer,
|
76
|
+
:securityPrivProtoLen, :size_t,
|
77
|
+
:securityPrivKey, [:u_char, 32],
|
78
|
+
:securityPrivKeyLen, :size_t,
|
79
|
+
:securityPrivLocalKey, :pointer,
|
80
|
+
:securityPrivLocalKeyLen, :size_t,
|
81
|
+
:securityModel, :int,
|
82
|
+
:securityLevel, :int,
|
83
|
+
:paramName, :pointer,
|
84
|
+
:securityInfo, :pointer,
|
85
|
+
:myvoid, :pointer
|
86
|
+
)
|
87
|
+
end
|
88
|
+
|
89
|
+
class Vardata < FFI::Union
|
90
|
+
layout(
|
91
|
+
:integer, :pointer,
|
92
|
+
:string, :pointer,
|
93
|
+
:objid, :pointer,
|
94
|
+
:bitstring, :pointer,
|
95
|
+
:counter64, :pointer,
|
96
|
+
:float, :pointer,
|
97
|
+
:double, :pointer
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
101
|
+
class VariableList < FFI::Struct
|
102
|
+
layout(
|
103
|
+
:next_variable, :pointer,#VariableList.typed_pointer,
|
104
|
+
:name, :pointer,
|
105
|
+
:name_length, :size_t,
|
106
|
+
:type, :u_char,
|
107
|
+
:val, Vardata,
|
108
|
+
:val_len, :size_t,
|
109
|
+
:name_loc, [:oid, Constants::MAX_OID_LEN],
|
110
|
+
:buf, [:u_char, 40],
|
111
|
+
:data, :pointer,
|
112
|
+
:dataFreeHook, callback([ :pointer ], :void),
|
113
|
+
:index, :int
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
class PDU < FFI::Struct
|
119
|
+
layout(
|
120
|
+
:version, :long,
|
121
|
+
:command, :int,
|
122
|
+
:reqid, :long,
|
123
|
+
:msgid, :long,
|
124
|
+
:transid, :long,
|
125
|
+
:sessid, :long,
|
126
|
+
:errstat, :long,
|
127
|
+
:errindex, :long,
|
128
|
+
:time, :u_long,
|
129
|
+
:flags, :u_long,
|
130
|
+
:securityModel, :int,
|
131
|
+
:securityLevel, :int,
|
132
|
+
:msgParseModel, :int,
|
133
|
+
:transport_data, :pointer,
|
134
|
+
:transport_data_length, :int,
|
135
|
+
:tDomain, :pointer,
|
136
|
+
:tDomainLen, :size_t,
|
137
|
+
:variables, :pointer,
|
138
|
+
:community, :pointer,
|
139
|
+
:community_len, :size_t,
|
140
|
+
:enterprise, :pointer,
|
141
|
+
:enterprise_length, :size_t,
|
142
|
+
:trap_type, :long,
|
143
|
+
:specific_type, :long,
|
144
|
+
:agent_addr, [:uchar, 4],
|
145
|
+
:contextEngineID, :pointer,
|
146
|
+
:contextEngineIDLen, :size_t,
|
147
|
+
:contextName, :pointer,
|
148
|
+
:contextNameLen, :size_t,
|
149
|
+
:securityEngineID, :pointer,
|
150
|
+
:securityEngineIDLen, :size_t,
|
151
|
+
:securityName, :pointer,
|
152
|
+
:securityNameLen, :size_t,
|
153
|
+
:priority, :int,
|
154
|
+
:range_subid, :int,
|
155
|
+
:securityStateRef, :pointer
|
156
|
+
)
|
157
|
+
end
|
158
|
+
|
159
|
+
class Counter64 < FFI::Struct
|
160
|
+
layout(
|
161
|
+
:high, :u_long,
|
162
|
+
:low, :u_long
|
163
|
+
)
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module NETSNMP::Core
|
2
|
+
|
3
|
+
def self.version
|
4
|
+
LibSNMP.netsnmp_get_version
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
# Do not support versions lower than 5.5, as they're mostly buggy.
|
9
|
+
if version < "5.5"
|
10
|
+
raise LoadError, "The netsnmp version #{version} is incompatible with this version of ffi-netsnmp-core"
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'netsnmp'
|
2
|
+
module NETSNMP
|
3
|
+
module Celluloid
|
4
|
+
class Client < ::NETSNMP::Client
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
@session = Celluloid::Session.new(*args)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
class Session < ::NETSNMP::Session
|
14
|
+
def wait_readable
|
15
|
+
return super unless ::Celluloid::IO.evented?
|
16
|
+
::Celluloid::IO.wait_readable(transport)
|
17
|
+
[[transport]]
|
18
|
+
end
|
19
|
+
|
20
|
+
def wait_writable
|
21
|
+
return super unless ::Celluloid::IO.evented?
|
22
|
+
::Celluloid::IO.wait_writable(transport)
|
23
|
+
[[],[transport]]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'netsnmp'
|
2
|
+
module NETSNMP
|
3
|
+
module EM
|
4
|
+
class Client < ::NETSNMP::Client
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
@session = EM::Session.new(*args)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
class Session < ::NETSNMP::Session
|
14
|
+
module Watcher
|
15
|
+
def initialize(client, deferable)
|
16
|
+
@client = client
|
17
|
+
@deferable = deferable
|
18
|
+
@is_watching = true
|
19
|
+
end
|
20
|
+
|
21
|
+
def notify_readable
|
22
|
+
detach
|
23
|
+
begin
|
24
|
+
operation = nil
|
25
|
+
@client.__send__ :async_read
|
26
|
+
result = @client.__send__ :handle_response
|
27
|
+
rescue => e
|
28
|
+
@deferable.fail(e)
|
29
|
+
else
|
30
|
+
@deferable.succeed(result)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def watching?
|
35
|
+
@is_watching
|
36
|
+
end
|
37
|
+
|
38
|
+
def unbind
|
39
|
+
@is_watching = false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def send(pdu)
|
44
|
+
if ::EM.reactor_running?
|
45
|
+
write(pdu)
|
46
|
+
deferable = ::EM::DefaultDeferrable.new
|
47
|
+
watch = ::EM.watch(transport.fileno, Watcher, self, deferable)
|
48
|
+
watch.notify_readable = true
|
49
|
+
::EM::Synchrony.sync deferable
|
50
|
+
else
|
51
|
+
super
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/netsnmp/oid.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
module NETSNMP
|
2
|
+
# Abstracts the OID structure
|
3
|
+
#
|
4
|
+
class OID
|
5
|
+
Error = Class.new(Error)
|
6
|
+
OIDREGEX = /^[\d\.]*$/
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
# @return [Integer] the default oid size in bytes
|
11
|
+
def default_size
|
12
|
+
@default_size ||= Core::Inline.oid_size
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param [FFI::Pointer] pointer the pointer to the beginning ot the memory octet
|
16
|
+
# @param [Integer] length the length of the oid
|
17
|
+
# @return [String] the oid code (ex: "1.2.4.56.3.4.5"...)
|
18
|
+
#
|
19
|
+
def read_pointer(pointer, length)
|
20
|
+
pointer.__send__(:"read_array_of_uint#{default_size * 8}", length).join('.')
|
21
|
+
end
|
22
|
+
|
23
|
+
# @see read_pointer
|
24
|
+
# @return [OID] an OID object initialized from a code read from memory
|
25
|
+
#
|
26
|
+
def from_pointer(pointer, length)
|
27
|
+
new(read_pointer(pointer, length))
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :code
|
33
|
+
|
34
|
+
# @param [String] code the oid code
|
35
|
+
#
|
36
|
+
def initialize(code)
|
37
|
+
@struct = FFI::MemoryPointer.new(OID::default_size * Core::Constants::MAX_OID_LEN)
|
38
|
+
@length_pointer = FFI::MemoryPointer.new(:size_t)
|
39
|
+
@length_pointer.write_int(Core::Constants::MAX_OID_LEN)
|
40
|
+
existing_oid = case code
|
41
|
+
when OIDREGEX then Core::LibSNMP.read_objid(code, @struct, @length_pointer)
|
42
|
+
else Core::LibSNMP.get_node(code, @struct, @length_pointer)
|
43
|
+
end
|
44
|
+
raise Error, "unsupported oid: #{code}" if existing_oid.zero?
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [String] the oid code
|
48
|
+
#
|
49
|
+
def code ; @code ||= OID.read_pointer(pointer, length) ; end
|
50
|
+
|
51
|
+
# @return [String] the pointer to the structure
|
52
|
+
#
|
53
|
+
def pointer ; @struct ; end
|
54
|
+
|
55
|
+
# @return [Integer] length of the oid
|
56
|
+
#
|
57
|
+
def length ; @length_pointer.read_int ; end
|
58
|
+
|
59
|
+
# @return [Integer] size of the oid
|
60
|
+
#
|
61
|
+
def size ; length * NETSNMP::OID.default_size ; end
|
62
|
+
|
63
|
+
def to_s ; code ; end
|
64
|
+
|
65
|
+
# @param [OID, String] child oid another oid
|
66
|
+
# @return [true, false] whether the given OID belongs to the sub-tree
|
67
|
+
#
|
68
|
+
def parent_of?(child_oid)
|
69
|
+
child_code = child_oid.is_a?(OID) ? child_oid.code : child_oid
|
70
|
+
child_code.start_with?(code)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# SNMP v3-relevant OIDs
|
75
|
+
|
76
|
+
class MD5OID < OID
|
77
|
+
def initialize ; super("1.3.6.1.6.3.10.1.1.2") ; end
|
78
|
+
end
|
79
|
+
class SHA1OID < OID
|
80
|
+
def initialize ; super("1.3.6.1.6.3.10.1.1.3") ; end
|
81
|
+
end
|
82
|
+
class NoAuthOID < OID
|
83
|
+
def initialize ; super("1.3.6.1.6.3.10.1.1.1") ; end
|
84
|
+
end
|
85
|
+
class AESOID < OID
|
86
|
+
def initialize ; super("1.3.6.1.6.3.10.1.2.4") ; end
|
87
|
+
end
|
88
|
+
class DESOID < OID
|
89
|
+
def initialize ; super("1.3.6.1.6.3.10.1.2.2") ; end
|
90
|
+
end
|
91
|
+
class NoPrivOID < OID
|
92
|
+
def initialize ; super("1.3.6.1.6.3.10.1.2.1") ; end
|
93
|
+
end
|
94
|
+
end
|
data/lib/netsnmp/pdu.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
module NETSNMP
|
3
|
+
# Abstracts the PDU base structure into a ruby object. It gives access to its varbinds.
|
4
|
+
#
|
5
|
+
class PDU
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
Error = Class.new(Error)
|
9
|
+
class << self
|
10
|
+
# factory method that abstracts initialization of the pdu types that the library supports.
|
11
|
+
#
|
12
|
+
# @param [Symbol] type the type of pdu structure to build
|
13
|
+
# @return [RequestPDU] a fully-formed request pdu
|
14
|
+
#
|
15
|
+
def build(type, *args)
|
16
|
+
case type
|
17
|
+
when :get then RequestPDU.new(Core::Constants::SNMP_MSG_GET, *args)
|
18
|
+
when :getnext then RequestPDU.new(Core::Constants::SNMP_MSG_GETNEXT, *args)
|
19
|
+
when :getbulk then RequestPDU.new(Core::Constants::SNMP_MSG_GETBULK, *args)
|
20
|
+
when :set then RequestPDU.new(Core::Constants::SNMP_MSG_SET, *args)
|
21
|
+
when :response then ResponsePDU.new(Core::Constants::SNMP_MSG_RESPONSE, *args)
|
22
|
+
else raise Error, "#{type} is not supported as type"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_reader :struct, :varbinds
|
28
|
+
|
29
|
+
def_delegators :@struct, :[], :[]=, :pointer
|
30
|
+
|
31
|
+
# @param [FFI::Pointer] the pointer to the initialized structure
|
32
|
+
#
|
33
|
+
def initialize(pointer)
|
34
|
+
@struct = Core::Structures::PDU.new(pointer)
|
35
|
+
@varbinds = []
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
# Abstracts the request PDU
|
42
|
+
# Main characteristic is that it has a write-only API, in that you can add varbinds to it.
|
43
|
+
#
|
44
|
+
class RequestPDU < PDU
|
45
|
+
def initialize(type)
|
46
|
+
pointer = Core::LibSNMP.snmp_pdu_create(type)
|
47
|
+
super(pointer)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Adds a request varbind to the pdu
|
51
|
+
#
|
52
|
+
# @param [OID] oid a valid oid
|
53
|
+
# @param [Hash] options additional request varbind options
|
54
|
+
# @option options [Object] :value the value for the oid
|
55
|
+
def add_varbind(oid, **options)
|
56
|
+
@varbinds << RequestVarbind.new(self, oid, options[:value], options)
|
57
|
+
end
|
58
|
+
alias_method :<<, :add_varbind
|
59
|
+
end
|
60
|
+
|
61
|
+
# Abstracts the response PDU
|
62
|
+
# Main characteristic is: it reads the values on initialization (because the response structure
|
63
|
+
# is at some point free'd). It is therefore a read-only entity
|
64
|
+
#
|
65
|
+
class ResponsePDU < PDU
|
66
|
+
|
67
|
+
# @param [FFI::Pointer] the pointer to the response pdu structure
|
68
|
+
#
|
69
|
+
# @note it loads the variable as well.
|
70
|
+
#
|
71
|
+
def initialize(pointer)
|
72
|
+
super
|
73
|
+
load_variables
|
74
|
+
end
|
75
|
+
|
76
|
+
# @return [String] the concatenation of the varbind values (usually, it's only one)
|
77
|
+
#
|
78
|
+
def value
|
79
|
+
case @varbinds.size
|
80
|
+
when 0 then nil
|
81
|
+
when 1 then @varbinds.first.value
|
82
|
+
else
|
83
|
+
# assume that they're all strings
|
84
|
+
@varbinds.map(&:value).join(' ')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# loads the C-level structure variables into ruby ResponseVarbind objects,
|
91
|
+
# and store them as state in {{@varbinds}}
|
92
|
+
def load_variables
|
93
|
+
variable = @struct[:variables]
|
94
|
+
unless variable.null?
|
95
|
+
@varbinds << ResponseVarbind.new(variable)
|
96
|
+
variable = Core::Structures::VariableList.new(variable)
|
97
|
+
while( !(variable = variable[:next_variable]).null? )
|
98
|
+
variable = Core::Structures::VariableList.new(variable)
|
99
|
+
@varbinds << ResponseVarbind.new(variable.pointer)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|