Version 24 of SNMP parser

Updated 2007-03-15 15:30:06

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