[MJ] - Because [SNMP] uses [ASN].1 to encode packets, one can use [tcllib]'s [asn] package to decode the SNMP packets. The code below implements the ::asn::decodeBer command that will create a nested list of the parsed SNMP packet. ---- package require asn namespace eval asn { namespace eval util { proc string2hex {string} { binary scan $string H* t set res [regexp -inline -all {..} $t] return [join $res " "] } } array set dispatch { 02 decodeInteger 04 decodeOctetString 06 decodeOID 30 decodeSequence 40 decodeNetworkAddress 43 decodeTimeTicks A4 decodeTrap-PDU A6 decodeInformRequest-PDU A7 decodeSNMPv2-Trap-PDU } proc decodeBer {raw} { variable dispatch asnGetHexTag raw hex_tag if {[info exists dispatch($hex_tag)] } { set res [$dispatch($hex_tag) $raw] return $res } else { dputs "Don't know how to handle: $hex_tag" asnGetByte raw tag asnGetLength raw length asnGetBytes raw $length value return [list $hex_tag [util::string2hex $value] ] } } proc asnGetHexTag { data_var tag_var} { # no destructively get the tag upvar $data_var data $tag_var hex_tag set orig $data asnGetByte data tag set hex_tag [format %2.2X $tag] dputs "Part has tag $hex_tag" set data $orig } proc asnMorphTag { data_var tag } { upvar $data_var data asnGetByte data dummy set data $tag$data } proc asnGetElement { data_var element_var } { upvar $data_var data $element_var element dputs "Getting the first element from: [util::string2hex $data]" set orig $data asnGetByte data tag asnGetLength data length asnGetBytes data $length temp set remaining_length [string length $data] set element [string range $orig 0 end-$remaining_length] dputs "Element is: [util::string2hex $element]" return } proc decodeSequence {raw {type SEQUENCE}} { set data $raw asnGetSequence data sequence while {[string length $sequence] > 0 } { asnGetElement sequence element lappend result [decodeBer $element] } if {![info exists result] } { set result {}} return [list $type $result] } proc decodeTrap-PDU { raw } { # a trap PDU is an implicit sequence so morph it to that asnMorphTag raw "\x30" return [decodeSequence $raw Trap-PDU] } proc decodeSNMPv2-Trap-PDU { raw } { # an SNMPv2 trap PDU is an implicit sequence so morph it to that asnMorphTag raw "\x30" return [decodeSequence $raw SNMPv2-Trap-PDU] } proc decodeInformRequest-PDU { raw } { # an InformRequest PDU is an implicit sequence so morph it to that asnMorphTag raw "\x30" return [decodeSequence $raw InformRequest-PDU] } proc decodeTimeTicks { raw } { # a TimeTick is an implicit integer so morph it to that asnMorphTag raw "\x02" return [decodeInteger $raw TimeTicks] } proc decodeInteger {raw {type INTEGER}} { return [handleWithAsnLib $type asnGetInteger $raw] } proc decodeOID {raw} { return [handleWithAsnLib {OBJECT IDENTIFIER} asnGetObjectIdentifier $raw] } proc decodeOctetString {raw} { return [handleWithAsnLib OCTETSTRING asnGetOctetString $raw] } proc decodeNetworkAddress {raw} { asnGetByte raw dummy asnGetByte raw length asnGetBytes raw $length address foreach number [split $address ""] { lappend result [scan $number %c] } return [list IpAddress $result] } proc handleWithAsnLib {type libfunction raw} { dputs "Decoding $type: [util::string2hex $raw]" $libfunction raw result return [list $type $result] } } proc dputs {text} {} package provide ber 0.1 '''Sample output for a SNMPv1 trap PDU''' SEQUENCE {{INTEGER 0} {OCTETSTRING OS} {Trap-PDU {{{OBJECT IDENTIFIER} {1 3 6 1 4 1 8072 3 2 3}}\ {IpAddress {192 168 0 5}} {INTEGER 0} {INTEGER 0} {TimeTicks 7} {SEQUENCE {}}}}} ---- [Category Example] | [Category Networking] | [Category Package]