Version 17 of SNMP parser

Updated 2007-03-14 17:05:20

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 {typeName implicitTag decodingProcedure}
     # if implicitTag is empty the means the tag represents a type 
     # for which a decode proc is available (last element of the list)
     # this should really be stored in a tree-like structure

     array set tags {  
         02 { INTEGER              {} asnGetInteger}
         04 { OCTETSTRING          {} asnGetOctetString}
         06 { {OBJECT IDENTIFIER}  {} asnGetObjectIdentifier}
         30 { SEQUENCE             {} decodeSequence}
         40 { NetworkAddress       {} asnGetNetworkAddress}
         43 { TimeTicks            02 {}}
         A0 { GetRequest-PDU       30 {}}
         A1 { GetNextRequest-PDU   30 {}}
         A2 { GetResponse-PDU      30 {}}
         A3 { SetRequest-PDU       30 {}}
         A4 { Trap-PDU             30 {}}
         A6 { InformRequest-PDU    30 {}}
         A7 { SNMPv2-Trap-PDU      30 {}}
     }

     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]
             while {$implicitTag ne {}} {
                 # if we are handling an implicit type, 
                # find the corresponding type it derived from that has a decode proc
                set tagInfo $tags($implicitTag)
                if {[lindex $tagInfo end] ne {}} {
                    asnRetag raw [expr "0x$implicitTag"]
                    break
                }
                set implicitTag [lindex $tagInfo 1]
             }
             [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