--- Convert-BER-XS/XS.pm 2019/04/20 21:51:40 1.35 +++ Convert-BER-XS/XS.pm 2019/04/21 00:36:11 1.36 @@ -38,6 +38,9 @@ ] ], ... + # let's dump it, for debugging + + ber_dump $ber, $Convert::BER::XS::SNMP_PROFILE; # let's decode it a bit with some helper functions @@ -115,8 +118,8 @@ ASN tag values (some of which are aliases, such as C). Their numerical value corresponds exactly to the numbers used in BER/X.690. - ASN_BOOLEAN ASN_INTEGER ASN_BIT_STRING ASN_OCTET_STRING ASN_NULL ASN_OBJECT_IDENTIFIER - ASN_OBJECT_DESCRIPTOR ASN_OID ASN_EXTERNAL ASN_REAL ASN_SEQUENCE ASN_ENUMERATED + ASN_BOOLEAN ASN_INTEGER ASN_BIT_STRING ASN_OCTET_STRING ASN_NULL ASN_OID + ASN_OBJECT_IDENTIFIER ASN_OBJECT_DESCRIPTOR ASN_EXTERNAL ASN_REAL ASN_SEQUENCE ASN_ENUMERATED ASN_EMBEDDED_PDV ASN_UTF8_STRING ASN_RELATIVE_OID ASN_SET ASN_NUMERIC_STRING ASN_PRINTABLE_STRING ASN_TELETEX_STRING ASN_T61_STRING ASN_VIDEOTEX_STRING ASN_IA5_STRING ASN_ASCII_STRING ASN_UTC_TIME ASN_GENERALIZED_TIME ASN_GRAPHIC_STRING ASN_VISIBLE_STRING @@ -145,6 +148,7 @@ ber_decode ber-decode_prefix ber_is ber_is_seq ber_is_int ber_is_oid + ber_dump =item C<:encode> @@ -418,15 +422,16 @@ const_index => [qw( BER_CLASS BER_TAG BER_FLAGS BER_DATA )], - const_asn => [qw( - ASN_BOOLEAN ASN_INTEGER ASN_BIT_STRING ASN_OCTET_STRING ASN_NULL ASN_OBJECT_IDENTIFIER - ASN_OBJECT_DESCRIPTOR ASN_OID ASN_EXTERNAL ASN_REAL ASN_SEQUENCE ASN_ENUMERATED + const_asn_class => [qw( + ASN_UNIVERSAL ASN_APPLICATION ASN_CONTEXT ASN_PRIVATE + )], + const_asn_tag => [qw( + ASN_BOOLEAN ASN_INTEGER ASN_BIT_STRING ASN_OCTET_STRING ASN_NULL ASN_OID ASN_OBJECT_IDENTIFIER + ASN_OBJECT_DESCRIPTOR ASN_EXTERNAL ASN_REAL ASN_SEQUENCE ASN_ENUMERATED ASN_EMBEDDED_PDV ASN_UTF8_STRING ASN_RELATIVE_OID ASN_SET ASN_NUMERIC_STRING ASN_PRINTABLE_STRING ASN_TELETEX_STRING ASN_T61_STRING ASN_VIDEOTEX_STRING ASN_IA5_STRING ASN_ASCII_STRING ASN_UTC_TIME ASN_GENERALIZED_TIME ASN_GRAPHIC_STRING ASN_VISIBLE_STRING ASN_ISO646_STRING ASN_GENERAL_STRING ASN_UNIVERSAL_STRING ASN_CHARACTER_STRING ASN_BMP_STRING - - ASN_UNIVERSAL ASN_APPLICATION ASN_CONTEXT ASN_PRIVATE )], const_ber_type => [qw( BER_TYPE_BYTES BER_TYPE_UTF8 BER_TYPE_UCS2 BER_TYPE_UCS4 BER_TYPE_INT @@ -440,6 +445,7 @@ decode => [qw( ber_decode ber_decode_prefix ber_is ber_is_seq ber_is_int ber_is_oid + ber_dump )], encode => [qw( ber_encode @@ -449,8 +455,123 @@ our @EXPORT_OK = map @$_, values %EXPORT_TAGS; -$EXPORT_TAGS{all} = \@EXPORT_OK; -$EXPORT_TAGS{const} = [map @{ $EXPORT_TAGS{$_} }, qw(const_index const_asn)]; +$EXPORT_TAGS{all} = \@EXPORT_OK; +$EXPORT_TAGS{const_asn} = [map @{ $EXPORT_TAGS{$_} }, qw(const_asn_class const_asn_tag)]; +$EXPORT_TAGS{const} = [map @{ $EXPORT_TAGS{$_} }, qw(const_index const_asn)]; + +our $DEFAULT_PROFILE = new Convert::BER::XS::Profile; + +$DEFAULT_PROFILE->_set_default; + +# additional SNMP application types +our $SNMP_PROFILE = new Convert::BER::XS::Profile; + +$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_IPADDRESS , BER_TYPE_IPADDRESS); +$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER32 , BER_TYPE_INT); +$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_UNSIGNED32, BER_TYPE_INT); +$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_TIMETICKS , BER_TYPE_INT); +$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_OPAQUE , BER_TYPE_IPADDRESS); + +=head2 DEBUGGING + +To aid debugging, you cna call the C function to print a "nice" +representation to STDOUT. + +=over + +=item Convert::BER::XS::ber_dump $tuple[, $profile[, $prefix]] + +In addition to specifying the BER C<$tuple> to dump, youc an also specify +a C<$profile> and a C<$prefix> string that is printed in front of each line. + +If C<$profile> is C<$Convert::BER::XS::SNMP_PROFILE>, then C +will try to improve its output for SNMP data. + +The output usually contains three columns, the "human readable" tag, the +BER type used to decode it, and the data value. + +This function is somewhat slow and uses a number of heuristics and tricks, +so it really is only suitable for debug prints. + +Example output: + + SEQUENCE + | OCTET_STRING bytes 800063784300454045045400000001 + | OCTET_STRING bytes + | CONTEXT (7) bytes CONSTRUCTED + | | INTEGER int 1058588941 + | | INTEGER int 0 + | | INTEGER int 0 + | | SEQUENCE + | | | SEQUENCE + | | | | OID oid 1.3.6.1.2.1.1.3.0 + | | | | TIMETICKS int 638085796 + +=cut + +# reverse enum, very slow and ugly hack +sub _re { + my ($export_tag, $value) = @_; + + for my $symbol (@{ $EXPORT_TAGS{$export_tag} }) { + $value == eval $symbol + and return $symbol; + } + + "($value)" +} + +$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER64 , BER_TYPE_INT); + +sub _ber_dump { + my ($ber, $profile, $indent) = @_; + + if (my $seq = ber_is_seq $ber) { + printf "%sSEQUENCE\n", $indent; + &_ber_dump ($_, $profile, "$indent| ") + for @$seq; + } else { + my $asn = $ber->[BER_CLASS] == ASN_UNIVERSAL; + + my $class = _re const_asn_class => $ber->[BER_CLASS]; + my $tag = $asn ? _re const_asn_tag => $ber->[BER_TAG] : $ber->[BER_TAG]; + my $type = _re const_ber_type => $profile->get ($ber->[BER_CLASS], $ber->[BER_TAG]); + my $data = $ber->[BER_DATA]; + + if ($profile == $SNMP_PROFILE and $ber->[BER_CLASS] == ASN_APPLICATION) { + $tag = _re const_snmp => $ber->[BER_TAG]; + $asn = 1; + } + + $asn or $tag = "$class ($tag)"; + + $class =~ s/^ASN_//; + $tag =~ s/^(ASN_|SNMP_)//; + $type =~ s/^BER_TYPE_//; + + if ($ber->[BER_FLAGS]) { + printf "$indent%-16.16s %-6.6s CONSTRUCTED\n", $tag, lc $type; + &_ber_dump ($_, $profile, "$indent| ") + for @$data; + } else { + if ($data =~ y/\x20-\x7e//c > 10 or $data =~ /\x00./s) { + # assume binary + $data = unpack "H*", $data; + substr $data, 40, 1e9, "..." if 40 < length $data; + } else { + $data =~ s/[^\x20-\x7e]/./g; + $data = "\"$data\"" if $type =~ /string/i; + substr $data, 40, 1e9, "..." if 40 < length $data; + } + + printf "$indent%-16.16s %-6.6s %s\n", $tag, lc $type, $data; + } + } +} + +sub ber_dump($;$$) { + _ber_dump $_[0], $_[1] || $DEFAULT_PROFILE, $_[2]; +} =head1 PROFILES @@ -614,24 +735,6 @@ $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_OPAQUE , BER_TYPE_IPADDRESS); $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER64 , BER_TYPE_INT); -=cut - -our $DEFAULT_PROFILE = new Convert::BER::XS::Profile; - -$DEFAULT_PROFILE->_set_default; - -# additional SNMP application types -our $SNMP_PROFILE = new Convert::BER::XS::Profile; - -$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_IPADDRESS , BER_TYPE_IPADDRESS); -$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER32 , BER_TYPE_INT); -$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_UNSIGNED32, BER_TYPE_INT); -$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_TIMETICKS , BER_TYPE_INT); -$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_OPAQUE , BER_TYPE_IPADDRESS); -$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER64 , BER_TYPE_INT); - -1; - =head2 LIMITATIONS/NOTES This module can only en-/decode 64 bit signed and unsigned integers, and @@ -669,3 +772,5 @@ =cut +1; +