netsnmp 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,8 @@
1
+ module NETSNMP
2
+ Error = Class.new(StandardError)
3
+ ConnectionFailed = Class.new(Error)
4
+ AuthenticationFailed = Class.new(Error)
5
+
6
+ SendError = Class.new(Error)
7
+ ReceiveError = Class.new(Error)
8
+ 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
@@ -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
@@ -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