Version 14 of SNMP parser

Updated 2007-03-14 16:23:28

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}  06 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 {raw res} {
          upvar $raw data
         upvar $res result
          asnGetSequence data 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