fishbot_v2 has asked for the wisdom of the Perl Monks concerning the following question:

Long time listener, first time caller. I've been struggling with this on and off for several days, and I know when I've been beaten.

I want to parse SNMP trap PDUs from BER/DER encoded ASN1 into a nested hash. I'd prefer to use Convert::ASN1, because I use it similarly and successfully with LDAP in the same application.

Try as I might, I cannot get Convert::ASN1 to parse the trapPDU ASN1 ABNF.

There are a number of issues, the big one being that the Convert::ASN1 docs don't describe the coverage of ASN1 ABNFs. It's difficult to determine what's supported, and what isn't. It's possible that the support simply isn't complete enough to describe SNMP traps.

I can parse the outer SNMP envelope:

my $desc = q( SNMPMessage ::= SEQUENCE { version INTEGER, community OCTET STRING, pdu ANY } ); my $asn = Convert::ASN1->new(); $asn->prepare($desc) or die $asn->error; my $snmp_message = $asn->find("SNMPMessage");

That gets me as far as:

$VAR1 = { 'community' => 'public', 'version' => 0, 'pdu' => <binary whatnot>, };

But from here things get tricky. I've tried using the ABNF directly from the RFC, but it needs a bunch of massaging before Convert::ASN1 will ->prepare() it. I massage until it compiles, but then simply end up with 'decode errors'.

I can go on with everything I've tried, but my main question is just: has anyone managed to get Convert::ASN1 to work with SNMP? Or is this hopeless? Should I just try to use a basic BER/DER decoder and try to build a parser manually? (that's what SNMP does, it seems)

Replies are listed 'Best First'.
Re: Getting Convert::ASN1 to parse SNMP traps
by fishbot_v2 (Chaplain) on Aug 03, 2006 at 12:49 UTC

    Update: I gave up on Convert::ASN1, and switched down to Convert::BER. The structure of SNMP traps is relatively straightforward, and I was able to cobble a BER parser together quite quickly - borrowing a bit from Mon:SNMP to get started.

    If anyone someday supersearches for this, and attempts the same, I suggest reading this bug report before beginning, as it outlines some essentially required modifications. In particular, if you actually want to get the values sent (update: by values, I mean the VarBindList values), you need to attempt to decode them...

    my $ret; for my $type ( qw{ STRING BOOLEAN INTEGER REAL } ) { return $ret if defined( $ber->decode( $type => \$ret )); } return $ber->buffer();

    ...though, of course, the encoding type is normally based on the identifying OID, so if you have a list of all the OIDs you might receive and their types, you can be more efficient about it. It also seems to me that BER is rich enough that you should be able to probe for the type of the next token, but I haven't found an obvious method for this yet.