Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/snmp/pdu.rb
Views: 11766
#1# Copyright (c) 2004 David R. Halliday2# All rights reserved.3#4# This SNMP library is free software. Redistribution is permitted under the5# same terms and conditions as the standard Ruby distribution. See the6# COPYING file in the Ruby distribution for details.7#89require 'snmp/ber'10require 'snmp/varbind'1112include SNMP::BER1314module SNMP1516# Exceptions thrown during message/pdu decoding17class UnsupportedVersion < RuntimeError; end18class UnsupportedPduTag < RuntimeError; end19class InvalidPduTag < RuntimeError; end20class ParseError < RuntimeError; end21class InvalidErrorStatus < RuntimeError; end22class InvalidTrapVarbind < RuntimeError; end23class InvalidGenericTrap < RuntimeError; end2425SYS_UP_TIME_OID = ObjectId.new("1.3.6.1.2.1.1.3.0")26SNMP_TRAP_OID_OID = ObjectId.new("1.3.6.1.6.3.1.1.4.1.0")2728class Message29attr_reader :version30attr_reader :community31attr_reader :pdu3233class << self34def decode(data)35message_data, remainder = decode_sequence(data)36assert_no_remainder(remainder)37version, remainder = decode_version(message_data)38community, remainder = decode_octet_string(remainder)39pdu, remainder = decode_pdu(version, remainder)40assert_no_remainder(remainder)41Message.new(version, community, pdu)42end4344def decode_version(data)45version_data, remainder = decode_integer(data)46if version_data == SNMP_V147version = :SNMPv148elsif version_data == SNMP_V2C49version = :SNMPv2c50else51raise UnsupportedVersion, version_data.to_s52end53return version, remainder54end5556def decode_pdu(version, data)57pdu_tag, pdu_data, remainder = decode_tlv(data)58case pdu_tag59when GetRequest_PDU_TAG60pdu = PDU.decode(GetRequest, pdu_data)61when GetNextRequest_PDU_TAG62pdu = PDU.decode(GetNextRequest, pdu_data)63when Response_PDU_TAG64pdu = PDU.decode(Response, pdu_data)65when SetRequest_PDU_TAG66pdu = PDU.decode(SetRequest, pdu_data)67when SNMPv1_Trap_PDU_TAG68raise InvalidPduTag, "SNMPv1-trap not valid for #{version.to_s}" if version != :SNMPv169pdu = SNMPv1_Trap.decode(pdu_data)70when GetBulkRequest_PDU_TAG71raise InvalidPduTag, "get-bulk not valid for #{version.to_s}" if version != :SNMPv2c72pdu = PDU.decode(GetBulkRequest, pdu_data)73when InformRequest_PDU_TAG74raise InvalidPduTag, "inform not valid for #{version.to_s}" if version != :SNMPv2c75pdu = PDU.decode(InformRequest, pdu_data)76when SNMPv2_Trap_PDU_TAG77raise InvalidPduTag, "SNMPv2c-trap not valid for #{version.to_s}" if version != :SNMPv2c78pdu = PDU.decode(SNMPv2_Trap, pdu_data)79else80raise UnsupportedPduTag, pdu_tag.to_s81end82return pdu, remainder83end84end8586def initialize(version, community, pdu)87@version = version88@community = community89@pdu = pdu90end9192def response93Message.new(@version, @community, Response.from_pdu(@pdu))94end9596def encode_version(version)97if version == :SNMPv198encode_integer(SNMP_V1)99elsif version == :SNMPv2c100encode_integer(SNMP_V2C)101else102raise UnsupportedVersion, version.to_s103end104end105106def encode107data = encode_version(@version)108data << encode_octet_string(@community)109data << @pdu.encode110encode_sequence(data)111end112end113114class PDU115attr_accessor :request_id116attr_accessor :error_index117attr_accessor :varbind_list118119alias vb_list varbind_list120121def self.decode(pdu_class, pdu_data)122request_id, remainder = decode_integer(pdu_data)123error_status, remainder = decode_integer(remainder)124error_index, remainder = decode_integer(remainder)125varbind_list, remainder = VarBindList.decode(remainder)126assert_no_remainder(remainder)127pdu_class.new(request_id, varbind_list, error_status, error_index)128end129130ERROR_STATUS_NAME = {1310 => :noError,1321 => :tooBig,1332 => :noSuchName,1343 => :badValue,1354 => :readOnly,1365 => :genErr,1376 => :noAccess,1387 => :wrongType,1398 => :wrongLength,1409 => :wrongEncoding,14110 => :wrongValue,14211 => :noCreation,14312 => :inconsistentValue,14413 => :resourceUnavailable,14514 => :commitFailed,14615 => :undoFailed,14716 => :authorizationError,14817 => :notWritable,14918 => :inconsistentName150}151152ERROR_STATUS_CODE = ERROR_STATUS_NAME.invert153154def initialize(request_id, varbind_list, error_status=0, error_index=0)155@request_id = request_id156self.error_status = error_status157@error_index = error_index.to_int158@varbind_list = varbind_list159end160161def error_status=(status)162@error_status = ERROR_STATUS_CODE[status]163unless @error_status164if status.respond_to?(:to_int) && ERROR_STATUS_NAME[status.to_int]165@error_status = status166else167raise InvalidErrorStatus, status.to_s168end169end170end171172def error_status173ERROR_STATUS_NAME[@error_status]174end175176def encode_pdu(pdu_tag)177pdu_data = encode_integer(@request_id)178pdu_data << encode_integer(@error_status)179pdu_data << encode_integer(@error_index)180pdu_data << @varbind_list.encode181encode_tlv(pdu_tag, pdu_data)182end183184def each_varbind(&block)185@varbind_list.each(&block)186end187end188189class GetRequest < PDU190def encode191encode_pdu(GetRequest_PDU_TAG)192end193end194195class GetNextRequest < PDU196def encode197encode_pdu(GetNextRequest_PDU_TAG)198end199end200201class SetRequest < PDU202def encode203encode_pdu(SetRequest_PDU_TAG)204end205end206207class GetBulkRequest < PDU208alias max_repetitions error_index209alias max_repetitions= error_index=210211def encode212encode_pdu(GetBulkRequest_PDU_TAG)213end214215def non_repeaters=(number)216@error_status = number217end218219def non_repeaters220@error_status221end222end223224class Response < PDU225class << self226def from_pdu(request)227Response.new(request.request_id, request.varbind_list,228:noError, 0)229end230end231232def encode233encode_pdu(Response_PDU_TAG)234end235end236237##238# The PDU class for traps in SNMPv2c. Methods are provided for retrieving239# the values of the mandatory varbinds: the system uptime and the OID of the240# trap. The complete varbind list is available through the usual varbind_list241# method. The first two varbinds in this list will always be the uptime242# and trap OID varbinds.243#244class SNMPv2_Trap < PDU245def encode246encode_pdu(SNMPv2_Trap_PDU_TAG)247end248249##250# Returns the source IP address for the trap, usually derived from the251# source IP address of the packet that delivered the trap.252#253attr_accessor :source_ip254255##256# Returns the value of the mandatory sysUpTime varbind for this trap.257#258# Throws InvalidTrapVarbind if the sysUpTime varbind is not present.259#260def sys_up_time261varbind = @varbind_list[0]262if varbind && (varbind.name == SYS_UP_TIME_OID)263return varbind.value264else265raise InvalidTrapVarbind, "Expected sysUpTime.0, found " + varbind.to_s266end267end268269##270# Returns the value of the mandatory snmpTrapOID varbind for this trap.271#272# Throws InvalidTrapVarbind if the snmpTrapOID varbind is not present.273#274def trap_oid275varbind = @varbind_list[1]276if varbind && (varbind.name == SNMP_TRAP_OID_OID)277return varbind.value278else279raise InvalidTrapVarbind, "Expected snmpTrapOID.0, found " + varbind.to_s280end281end282end283284##285# The PDU class for SNMPv2 Inform notifications. This class is identical286# to SNMPv2_Trap.287#288class InformRequest < SNMPv2_Trap289def encode290encode_pdu(InformRequest_PDU_TAG)291end292end293294##295# The PDU class for traps in SNMPv1.296#297class SNMPv1_Trap298##299# Returns the source IP address for the trap, usually derived from the300# source IP address of the packet that delivered the trap.301#302attr_accessor :source_ip303304attr_accessor :enterprise305attr_accessor :agent_addr306attr_accessor :specific_trap307attr_accessor :timestamp308attr_accessor :varbind_list309310alias :vb_list :varbind_list311312def self.decode(pdu_data)313oid_data, remainder = decode_object_id(pdu_data)314enterprise = ObjectId.new(oid_data)315ip_data, remainder = decode_ip_address(remainder)316agent_addr = IpAddress.new(ip_data)317generic_trap, remainder = decode_integer(remainder)318specific_trap, remainder = decode_integer(remainder)319time_data, remainder = decode_timeticks(remainder)320timestamp = TimeTicks.new(time_data)321varbind_list, remainder = VarBindList.decode(remainder)322assert_no_remainder(remainder)323SNMPv1_Trap.new(enterprise, agent_addr, generic_trap, specific_trap,324timestamp, varbind_list)325end326327def initialize(enterprise, agent_addr, generic_trap, specific_trap, timestamp, varbind_list)328@enterprise = enterprise329@agent_addr = agent_addr330self.generic_trap = generic_trap331@specific_trap = specific_trap332@timestamp = timestamp333@varbind_list = varbind_list334end335336# Name map for all of the generic traps defined in RFC 1157.337GENERIC_TRAP_NAME = {3380 => :coldStart,3391 => :warmStart,3402 => :linkDown,3413 => :linkUp,3424 => :authenticationFailure,3435 => :egpNeighborLoss,3446 => :enterpriseSpecific345}346347# Code map for all of the generic traps defined in RFC 1157.348GENERIC_TRAP_CODE = GENERIC_TRAP_NAME.invert349350def generic_trap=(trap)351@generic_trap = GENERIC_TRAP_CODE[trap]352unless @generic_trap353if trap.respond_to?(:to_i) && GENERIC_TRAP_NAME[trap.to_i]354@generic_trap = trap355else356raise InvalidGenericTrap, trap.to_s357end358end359end360361def generic_trap362GENERIC_TRAP_NAME[@generic_trap]363end364365def encode366pdu_data = @enterprise.encode <<367@agent_addr.encode <<368encode_integer(@generic_trap) <<369encode_integer(@specific_trap) <<370@timestamp.encode <<371@varbind_list.encode372encode_tlv(SNMPv1_Trap_PDU_TAG, pdu_data)373end374375def each_varbind(&block)376@varbind_list.each(&block)377end378end379380end381382383