From 19452a62067d8aef552bfa6ca7bc6a5c08fd617d Mon Sep 17 00:00:00 2001 From: blackhedd Date: Fri, 15 Dec 2006 13:55:13 +0000 Subject: [PATCH] development on snmp --- lib/net/snmp.rb | 144 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 126 insertions(+), 18 deletions(-) diff --git a/lib/net/snmp.rb b/lib/net/snmp.rb index 7f3fb18..945db94 100644 --- a/lib/net/snmp.rb +++ b/lib/net/snmp.rb @@ -4,7 +4,7 @@ # #---------------------------------------------------------------------------- # -# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. # # Gmail: garbagecat10 # @@ -54,53 +54,161 @@ module Net class SnmpPdu class Error < Exception; end - attr_reader :version, :community, :pdu_type, :request_id, :variables + 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 + end #-- - # TODO, improve the error-trapping. - # We want to wrap up Ruby errors like array-ranges, which can appear if we get bad data. - # We should probably do the whole parse under a catch-all block. - def initialize ber_object + def parse ber_object begin parse_ber_object ber_object - rescue RuntimeError + rescue Error + # Pass through any SnmpPdu::Error instances + raise $! + rescue # Wrap any basic parsing error so it becomes a PDU-format error raise Error.new( "snmp-pdu format error" ) end end + private :parse def parse_ber_object ber_object - @version = ber_object[0].to_i - unless [0,2].include?(@version) - raise Error.new("unknown snmp-version: #{@version}") - end + version= ber_object[0].to_i - @community = ber_object[1].to_s + community= ber_object[1].to_s data = ber_object[2] - app_tag = data.ber_identifier & 31 - case app_tag + case (app_tag = data.ber_identifier & 31) when 0 - @pdu_type = :get_request + send :pdu_type=, :get_request parse_get_request data else raise Error.new( "unknown snmp-pdu type: #{app_tag}" ) end end + private :parse_ber_object #-- # Defined in RFC1157, pgh 4.1.2. def parse_get_request data - @request_id = data[0].to_i + send :request_id=, data[0].to_i # data[1] is error-status, always 0. # data[2] is error-index, always 0. - @variables = data[3].map {|v| + 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. - v[0] + unless v.is_a?(Net::BER::BerIdentifiedNull) + raise Error.new(" invalid variable-binding in get-request" ) + end + add_variable_binding n, nil } end + private :parse_get_request + + 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 + end + + def community= c + @community = c.to_s + end + + #-- + # Syntactic sugar + def add_variable_binding name, value + @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) + 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 end end