[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 with the implicit tags definitions # format: # tag {type {implicit type} {decoding proc}} array set tags { 02 { INTEGER {} asnGetInteger} 04 { OCTETSTRING {} asnGetOctetString} 06 { {OBJECT IDENTIFIER} {} asnGetObjectIdentifier} 30 { SEQUENCE {} decodeSequence} 40 { NetworkAddress {} asnGetNetworkAddress} 43 { TimeTicks 02 asnGetInteger} A0 { GetRequest-PDU 30 decodeSequence} A1 { GetNextRequest-PDU 30 decodeSequence} A2 { GetResponse-PDU 30 decodeSequence} A3 { SetRequest-PDU 30 decodeSequence} A4 { Trap-PDU 30 decodeSequence} A6 { InformRequest-PDU 30 decodeSequence} A7 { SNMPv2-Trap-PDU 30 decodeSequence} } proc decodeBer {raw} { variable tags asnPeekByte raw tag set tag [format %02X $tag] if {[info exists tags($tag)] } { set tagInfo $tags($tag) set type [lindex $tagInfo 0] set implicitTag [lindex $tagInfo 1] if {$implicitTag ne {}} { # if we are handling an implicit type, retag the data asnRetag raw [expr "0x$implicitTag"] } [lindex $tagInfo end] raw res return [list $type $res] } else { dputs "Don't know how to handle: $tag" asnGetByte raw tag asnGetLength raw length asnGetBytes raw $length value return [list $tag [util::string2hex $value] ] } } 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 {data res} { upvar $data raw upvar $res result asnGetSequence raw sequence while {[string length $sequence] > 0 } { asnGetElement sequence element lappend result [decodeBer $element] } return } proc asnGetNetworkAddress {data res} { upvar $data raw upvar $res result asnGetByte raw dummy asnGetByte raw length asnGetBytes raw $length address foreach number [split $address ""] { lappend result [scan $number %c] } return } } 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 inmplicit types. ---- [Category Example] | [Category Networking] | [Category Package]