[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 41 decodeCounter 43 decodeTimeTicks A0 decodeGetRequest-PDU A1 decodeGetNextRequest-PDU A2 decodeGetResponse-PDU A3 decodeSetRequest-PDU 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 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 decodeGetRequest-PDU { raw } { # a GetResponse PDU is an implicit sequence so retag it to that asnRetag raw [expr {0x30}] return [decodeSequence $raw GetRequest-PDU] } proc decodeGetNextRequest-PDU { raw } { # a GetResponse PDU is an implicit sequence so retag it to that asnRetag raw [expr {0x30}] return [decodeSequence $raw GetNextRequest-PDU] } proc decodeGetResponse-PDU { raw } { # a GetResponse PDU is an implicit sequence so retag it to that asnRetag raw [expr {0x30}] return [decodeSequence $raw GetResponse-PDU] } proc decodeSetRequest-PDU { raw } { # a GetResponse PDU is an implicit sequence so retag it to that asnRetag raw [expr {0x30}] return [decodeSequence $raw SetRequest-PDU] } proc decodeTrap-PDU { raw } { # a trap PDU is an implicit sequence so retag it to that asnRetag raw [expr {0x30}] return [decodeSequence $raw Trap-PDU] } proc decodeSNMPv2-Trap-PDU { raw } { # an SNMPv2 trap PDU is an implicit sequence so retag it to that asnRetag raw [expr {0x30}] return [decodeSequence $raw SNMPv2-Trap-PDU] } proc decodeInformRequest-PDU { raw } { # an InformRequest PDU is an implicit sequence so retag it to that asnRetag raw [expr {0x30}] return [decodeSequence $raw InformRequest-PDU] } proc decodeTimeTicks { raw } { # a TimeTick is an implicit integer so retag it to that asnRetag raw [expr {0x02}] return [decodeInteger $raw TimeTicks] } proc decodeInteger {raw {type INTEGER}} { return [handleWithAsnLib $type asnGetInteger $raw] } proc decodeCounter {raw {type COUNTER}} { # a TimeTick is an implicit integer so retag it to that asnRetag raw [expr {0x02}] return [decodeInteger $raw COUNTER] } 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 usage for an SNMPv1 trap PDU''' package require base64 set trap [join {MIGXAgEABAZwdWJsaWOkgYkGCCsGAQQBgo17QATAqAAzAgEGAgID6EMBZDBtMBoGDCsFAQQBgo17?\ AQbOEAQKbG9jYWxob3N0IDBPBgwrBQEEAYKNewEGzhEEPyBzdShwYW1fdW5peClbMjUxMTVdOiBz?\ ZXNzaW9uIG9wZW5lZCBmb3IgdXNlciByb290IGJ5ICh1aWQ9NTAwKQ==} {}] ::asn::decodeBer [base64::decode $trap] gives: SEQUENCE {{INTEGER 0} {OCTETSTRING public} {Trap-PDU {{{OBJECT IDENTIFIER} {1 3 6 1 4 1 34555}}\ {IpAddress {192 168 0 51}} {INTEGER 6} {INTEGER 1000} {TimeTicks 100}\ {SEQUENCE {{SEQUENCE {{{OBJECT IDENTIFIER} {1 3 5 1 4 1 34555 1 6 10000}} {OCTETSTRING {localhost }}}}\ {SEQUENCE {{{OBJECT IDENTIFIER} {1 3 5 1 4 1 34555 1 6 10001}}\ {OCTETSTRING { su(pam_unix)[25115]: session opened for user root by (uid=500)}}}}}}}}} ---- [MJ] - 14-03-2007: Removed a lot of the redundancy when handling the implicit types. ---- [Category Example] | [Category Networking] | [Category Package]