ruby-net-ldap/lib/net/snmp.rb

269 lines
6.3 KiB
Ruby
Raw Normal View History

# -*- ruby encoding: utf-8 -*-
# :stopdoc:
2006-12-15 11:37:27 +01:00
module Net
class SNMP
VERSION = '0.2.2'
2006-12-15 11:37:27 +01:00
2010-02-12 17:42:29 +01:00
AsnSyntax = Net::BER.compile_syntax({
2006-12-15 11:37:27 +01:00
:application => {
:primitive => {
2006-12-21 17:04:25 +01:00
1 => :integer, # Counter32, (RFC2578 sec 2)
2 => :integer, # Gauge32 or Unsigned32, (RFC2578 sec 2)
3 => :integer # TimeTicks32, (RFC2578 sec 2)
2006-12-15 11:37:27 +01:00
},
:constructed => {
}
},
:context_specific => {
:primitive => {
},
:constructed => {
2006-12-15 17:15:06 +01:00
0 => :array, # GetRequest PDU (RFC1157 pgh 4.1.2)
1 => :array, # GetNextRequest PDU (RFC1157 pgh 4.1.3)
2 => :array # GetResponse PDU (RFC1157 pgh 4.1.4)
2006-12-15 11:37:27 +01:00
}
}
})
# SNMP 32-bit counter.
# Defined in RFC1155 (Structure of Mangement Information), section 6.
# A 32-bit counter is an ASN.1 application [1] implicit unsigned integer
# with a range from 0 to 2^^32 - 1.
class Counter32
def initialize value
@value = value
end
def to_ber
@value.to_ber_application(1)
end
end
# SNMP 32-bit gauge.
# Defined in RFC1155 (Structure of Mangement Information), section 6.
# A 32-bit counter is an ASN.1 application [2] implicit unsigned integer.
2006-12-21 17:04:25 +01:00
# This is also indistinguishable from Unsigned32. (Need to alias them.)
class Gauge32
def initialize value
@value = value
end
def to_ber
@value.to_ber_application(2)
end
end
# SNMP 32-bit timer-ticks.
# Defined in RFC1155 (Structure of Mangement Information), section 6.
# A 32-bit counter is an ASN.1 application [3] implicit unsigned integer.
class TimeTicks32
def initialize value
@value = value
end
def to_ber
@value.to_ber_application(3)
end
end
2006-12-15 11:37:27 +01:00
end
2006-12-15 12:22:41 +01:00
class SnmpPdu
class Error < StandardError; end
2006-12-15 12:22:41 +01:00
2006-12-15 14:55:13 +01:00
PduTypes = [
:get_request,
:get_next_request,
:get_response,
:set_request,
:trap
]
ErrorStatusCodes = { # Per RFC1157, pgh 4.1.1
0 => "noError",
1 => "tooBig",
2 => "noSuchName",
3 => "badValue",
4 => "readOnly",
5 => "genErr"
}
class << self
def parse ber_object
n = new
n.send :parse, ber_object
n
end
end
attr_reader :version, :community, :pdu_type, :variables, :error_status
attr_accessor :request_id, :error_index
def initialize args={}
@version = args[:version] || 0
@community = args[:community] || "public"
@pdu_type = args[:pdu_type] # leave nil unless specified; there's no reasonable default value.
@error_status = args[:error_status] || 0
@error_index = args[:error_index] || 0
2006-12-15 15:12:02 +01:00
@variables = args[:variables] || []
2006-12-15 14:55:13 +01:00
end
2006-12-15 12:22:41 +01:00
#--
2006-12-15 14:55:13 +01:00
def parse ber_object
2006-12-15 12:22:41 +01:00
begin
parse_ber_object ber_object
2006-12-15 14:55:13 +01:00
rescue Error
# Pass through any SnmpPdu::Error instances
raise $!
rescue
2006-12-15 12:22:41 +01:00
# Wrap any basic parsing error so it becomes a PDU-format error
raise Error.new( "snmp-pdu format error" )
end
end
2006-12-15 14:55:13 +01:00
private :parse
2006-12-15 12:22:41 +01:00
def parse_ber_object ber_object
2006-12-19 19:15:40 +01:00
send :version=, ber_object[0].to_i
send :community=, ber_object[1].to_s
2006-12-15 12:22:41 +01:00
data = ber_object[2]
2006-12-15 14:55:13 +01:00
case (app_tag = data.ber_identifier & 31)
2006-12-15 12:22:41 +01:00
when 0
2006-12-15 14:55:13 +01:00
send :pdu_type=, :get_request
2006-12-15 12:22:41 +01:00
parse_get_request data
2006-12-15 17:15:06 +01:00
when 1
send :pdu_type=, :get_next_request
# This PDU is identical to get-request except for the type.
parse_get_request data
when 2
send :pdu_type=, :get_response
# This PDU is identical to get-request except for the type,
2006-12-18 21:36:41 +01:00
# the error_status and error_index values are meaningful,
# and the fact that the variable bindings will be non-null.
2006-12-18 21:36:41 +01:00
parse_get_response data
2006-12-15 12:22:41 +01:00
else
raise Error.new( "unknown snmp-pdu type: #{app_tag}" )
end
end
2006-12-15 14:55:13 +01:00
private :parse_ber_object
2006-12-15 12:22:41 +01:00
#--
# Defined in RFC1157, pgh 4.1.2.
def parse_get_request data
2006-12-15 14:55:13 +01:00
send :request_id=, data[0].to_i
2006-12-18 21:36:41 +01:00
# data[1] is error_status, always zero.
# data[2] is error_index, always zero.
send :error_status=, 0
send :error_index=, 0
2006-12-15 14:55:13 +01:00
data[3].each {|n,v|
2006-12-15 12:22:41 +01:00
# A variable-binding, of which there may be several,
# consists of an OID and a BER null.
# We're ignoring the null, we might want to verify it instead.
2006-12-15 14:55:13 +01:00
unless v.is_a?(Net::BER::BerIdentifiedNull)
raise Error.new(" invalid variable-binding in get-request" )
end
add_variable_binding n, nil
2006-12-15 12:22:41 +01:00
}
end
2006-12-15 14:55:13 +01:00
private :parse_get_request
2006-12-18 21:36:41 +01:00
#--
# Defined in RFC1157, pgh 4.1.4
def parse_get_response data
send :request_id=, data[0].to_i
send :error_status=, data[1].to_i
send :error_index=, data[2].to_i
data[3].each {|n,v|
# A variable-binding, of which there may be several,
# consists of an OID and a BER null.
# We're ignoring the null, we might want to verify it instead.
add_variable_binding n, v
}
end
private :parse_get_response
2006-12-15 17:15:06 +01:00
2006-12-15 14:55:13 +01:00
def version= ver
unless [0,2].include?(ver)
raise Error.new("unknown snmp-version: #{ver}")
end
@version = ver
end
def pdu_type= t
unless PduTypes.include?(t)
raise Error.new("unknown pdu-type: #{t}")
end
@pdu_type = t
end
def error_status= es
unless ErrorStatusCodes.has_key?(es)
raise Error.new("unknown error-status: #{es}")
end
2006-12-15 19:37:09 +01:00
@error_status = es
2006-12-15 14:55:13 +01:00
end
def community= c
@community = c.to_s
end
#--
# Syntactic sugar
2006-12-15 17:15:06 +01:00
def add_variable_binding name, value=nil
2006-12-15 14:55:13 +01:00
@variables ||= []
@variables << [name, value]
end
def to_ber_string
[
version.to_ber,
community.to_ber,
pdu_to_ber_string
].to_ber_sequence
end
#--
# Helper method that returns a PDU payload in BER form,
# depending on the PDU type.
def pdu_to_ber_string
case pdu_type
when :get_request
[
request_id.to_ber,
error_status.to_ber,
error_index.to_ber,
[
@variables.map {|n,v|
[n.to_ber_oid, Net::BER::BerIdentifiedNull.new.to_ber].to_ber_sequence
}
].to_ber_sequence
].to_ber_contextspecific(0)
2006-12-15 17:15:06 +01:00
when :get_next_request
[
request_id.to_ber,
error_status.to_ber,
error_index.to_ber,
[
@variables.map {|n,v|
[n.to_ber_oid, Net::BER::BerIdentifiedNull.new.to_ber].to_ber_sequence
}
].to_ber_sequence
].to_ber_contextspecific(1)
2006-12-15 14:55:13 +01:00
when :get_response
[
request_id.to_ber,
error_status.to_ber,
error_index.to_ber,
[
@variables.map {|n,v|
[n.to_ber_oid, v.to_ber].to_ber_sequence
}
].to_ber_sequence
].to_ber_contextspecific(2)
else
raise Error.new( "unknown pdu-type: #{pdu_type}" )
end
end
private :pdu_to_ber_string
2006-12-15 12:22:41 +01:00
end
2006-12-15 11:37:27 +01:00
end
# :startdoc: