ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-BER-XS/XS.pm
(Generate patch)

Comparing Convert-BER-XS/XS.pm (file contents):
Revision 1.57 by root, Thu Apr 25 22:30:21 2019 UTC vs.
Revision 1.63 by root, Wed Mar 3 05:30:23 2021 UTC

4 4
5=head1 SYNOPSIS 5=head1 SYNOPSIS
6 6
7 use Convert::BER::XS ':all'; 7 use Convert::BER::XS ':all';
8 8
9 # decode a binary BER data structure using the SNMP profile
9 my $ber = ber_decode $buf, $Convert::BER::XS::SNMP_PROFILE 10 my $ber = ber_decode $buf, $Convert::BER::XS::SNMP_PROFILE
10 or die "unable to decode SNMP message"; 11 or die "unable to decode SNMP message";
11 12
12 # The above results in a data structure consisting of 13 # The above results in a data structure consisting of
13 # (class, tag, flags, data) 14 # (class, tag, flags, data)
14 # tuples. Below is such a message, SNMPv1 trap 15 # tuples. Below is such a message, an SNMPv1 trap
15 # with a Cisco mac change notification. 16 # with a Cisco mac change notification.
16 # Did you know that Cisco is in the news almost 17 # (Did you know that Cisco is in the news almost
17 # every week because of some backdoor password 18 # every week because of some backdoor password
18 # or other extremely stupid security bug? 19 # or other extremely stupid security bug?)
19 20
20 [ ASN_UNIVERSAL, ASN_SEQUENCE, 1, 21 [ ASN_UNIVERSAL, ASN_SEQUENCE, 1,
21 [ 22 [
22 [ ASN_UNIVERSAL, ASN_INTEGER, 0, 0 ], # snmp version 1 23 [ ASN_UNIVERSAL, ASN_INTEGER, 0, 0 ], # snmp version 1
23 [ ASN_UNIVERSAL, 4, 0, "public" ], # community 24 [ ASN_UNIVERSAL, 4, 0, "public" ], # community
36 [ ASN_UNIVERSAL, ASN_OCTET_STRING, 0, "...data..." # the value 37 [ ASN_UNIVERSAL, ASN_OCTET_STRING, 0, "...data..." # the value
37 ] 38 ]
38 ] 39 ]
39 ], 40 ],
40 ... 41 ...
42
41 # let's dump it, for debugging 43 # let's dump the above structure, for debugging
42
43 ber_dump $ber, $Convert::BER::XS::SNMP_PROFILE; 44 ber_dump $ber, $Convert::BER::XS::SNMP_PROFILE;
44 45
45 # let's decode it a bit with some helper functions 46 # let's decode it a bit with some helper functions.
46 47 # first check whether it starts with a sequence
47 my $msg = ber_is_seq $ber 48 my $msg = ber_is_seq $ber
48 or die "SNMP message does not start with a sequence"; 49 or die "SNMP message does not start with a sequence";
49 50
51 # then check if its some kind of integer
50 ber_is $msg->[0], ASN_UNIVERSAL, ASN_INTEGER, 0 52 ber_is $msg->[0], ASN_UNIVERSAL, ASN_INTEGER, 0
51 or die "SNMP message does not start with snmp version\n"; 53 or die "SNMP message does not start with snmp version";
52 54
53 # message is SNMP v1 or v2c? 55 # message is SNMP v1 or v2c?
54 if ($msg->[0][BER_DATA] == 0 || $msg->[0][BER_DATA] == 1) { 56 if ($msg->[0][BER_DATA] == 0 || $msg->[0][BER_DATA] == 1) {
55 57
56 # message is v1 trap? 58 # message is v1 trap?
64 and (ber_is_int $trap->[3], 1) # mac changed msg 66 and (ber_is_int $trap->[3], 1) # mac changed msg
65 ) { 67 ) {
66 ... and so on 68 ... and so on
67 69
68 # finally, let's encode it again and hope it results in the same bit pattern 70 # finally, let's encode it again and hope it results in the same bit pattern
69
70 my $buf = ber_encode $ber, $Convert::BER::XS::SNMP_PROFILE; 71 my $buf = ber_encode $ber, $Convert::BER::XS::SNMP_PROFILE;
71 72
72=head1 DESCRIPTION 73=head1 DESCRIPTION
73
74WARNING: Before release 1.0, the API is not considered stable in any way.
75 74
76This module implements a I<very> low level BER/DER en-/decoder. 75This module implements a I<very> low level BER/DER en-/decoder.
77 76
78It is tuned for low memory and high speed, while still maintaining some 77It is tuned for low memory and high speed, while still maintaining some
79level of user-friendlyness. 78level of user-friendlyness.
175This works because BER values are tagged with a type and a namespace, 174This works because BER values are tagged with a type and a namespace,
176and also have a flag that says whether a value consists of subvalues (is 175and also have a flag that says whether a value consists of subvalues (is
177"constructed") or not (is "primitive"). 176"constructed") or not (is "primitive").
178 177
179Tags are simple integers, and ASN.1 defines a somewhat weird assortment 178Tags are simple integers, and ASN.1 defines a somewhat weird assortment
180of those - for example, you have one integers and 16(!) different 179of those - for example, you have one integer but 16(!) different
181string types, but there is no Unsigned32 type for example. Different 180string types, but there is no Unsigned32 type for example. Different
182applications work around this in different ways, for example, SNMP defines 181applications work around this in different ways, for example, SNMP defines
183application-specific Gauge32, Counter32 and Unsigned32, which are mapped 182application-specific Gauge32, Counter32 and Unsigned32, which are mapped
184to two different tags: you can distinguish between Counter32 and the 183to two different tags: you can distinguish between Counter32 and the
185others, but not between Gause32 and Unsigned32, without the ASN.1 schema. 184others, but not between Gause32 and Unsigned32, without the ASN.1 schema.
414use Carp (); 413use Carp ();
415 414
416our $VERSION; 415our $VERSION;
417 416
418BEGIN { 417BEGIN {
419 $VERSION = 1.2; 418 $VERSION = 1.21;
420 XSLoader::load __PACKAGE__, $VERSION; 419 XSLoader::load __PACKAGE__, $VERSION;
421} 420}
422 421
423our %EXPORT_TAGS = ( 422our %EXPORT_TAGS = (
424 const_index => [qw( 423 const_index => [qw(
468# additional SNMP application types 467# additional SNMP application types
469our $SNMP_PROFILE = new Convert::BER::XS::Profile; 468our $SNMP_PROFILE = new Convert::BER::XS::Profile;
470 469
471$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_IPADDRESS , BER_TYPE_IPADDRESS); 470$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_IPADDRESS , BER_TYPE_IPADDRESS);
472$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER32 , BER_TYPE_INT); 471$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER32 , BER_TYPE_INT);
472$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER64 , BER_TYPE_INT);
473$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_UNSIGNED32, BER_TYPE_INT); 473$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_UNSIGNED32, BER_TYPE_INT);
474$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_TIMETICKS , BER_TYPE_INT); 474$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_TIMETICKS , BER_TYPE_INT);
475 475
476# decodes REAL values according to ECMA-63 476# decodes REAL values according to ECMA-63
477# this is pretty strict, except it doesn't catch -0. 477# this is pretty strict, except it doesn't catch -0.
478# I don't have access to ISO 6093 (or BS 6727, or ANSI X.3-42)), so this is all guesswork.
478sub _decode_real_decimal { 479sub _decode_real_decimal {
479 my ($format, $val) = @_; 480 my ($format, $val) = @_;
480 481
481 $val =~ y/,/./; 482 $val =~ y/,/./; # probably not in ISO-6093
482 483
483 if ($format == 1) { 484 if ($format == 1) {
484 $val =~ /^ \ * [+-]? [0-9]+ \z/x 485 $val =~ /^ \ * [+-]? [0-9]+ \z/x
485 or Carp::croak "BER_TYPE_REAL NR1 value not in NR1 format ($val) (X.690 8.5.8, ECMA-63)"; 486 or Carp::croak "BER_TYPE_REAL NR1 value not in NR1 format ($val) (X.690 8.5.8)";
486 } elsif ($format == 2) { 487 } elsif ($format == 2) {
487 $val =~ /^ \ * [+-]? (?: [0-9]+\.[0-9]* | [0-9]*\.[0-9]+ ) \z/x 488 $val =~ /^ \ * [+-]? (?: [0-9]+\.[0-9]* | [0-9]*\.[0-9]+ ) \z/x
488 or Carp::croak "BER_TYPE_REAL NR2 value not in NR2 format ($val) (X.690 8.5.8, ECMA-63)"; 489 or Carp::croak "BER_TYPE_REAL NR2 value not in NR2 format ($val) (X.690 8.5.8)";
489 } elsif ($format == 3) { 490 } elsif ($format == 3) {
490 $val =~ /^ \ * [+-] (?: [0-9]+\.[0-9]* | [0-9]*\.[0-9]+ ) E [+-][0-9]+ \z/x 491 $val =~ /^ \ * [+-] (?: [0-9]+\.[0-9]* | [0-9]*\.[0-9]+ ) [eE] [+-]? [0-9]+ \z/x
491 or Carp::croak "BER_TYPE_REAL NR3 value not in NR3 format ($val) (X.690 8.5.8, ECMA-63)"; 492 or Carp::croak "BER_TYPE_REAL NR3 value not in NR3 format ($val) (X.690 8.5.8)";
492 } else { 493 } else {
493 Carp::croak "BER_TYPE_REAL illegal decimal numerical representation format $format"; 494 Carp::croak "BER_TYPE_REAL invalid decimal numerical representation format $format";
494 } 495 }
495 496
496 $val 497 $val
497} 498}
498 499
563 and return $symbol; 564 and return $symbol;
564 } 565 }
565 566
566 "($value)" 567 "($value)"
567} 568}
568
569$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER64 , BER_TYPE_INT);
570 569
571sub _ber_dump { 570sub _ber_dump {
572 my ($ber, $profile, $indent) = @_; 571 my ($ber, $profile, $indent) = @_;
573 572
574 if (my $seq = ber_is_seq $ber) { 573 if (my $seq = ber_is_seq $ber) {
649=item C<$Convert::BER::XS::SNMP_PROFILE> 648=item C<$Convert::BER::XS::SNMP_PROFILE>
650 649
651A profile with mappings for SNMP-specific application tags added. This is 650A profile with mappings for SNMP-specific application tags added. This is
652useful when de-/encoding SNMP data. 651useful when de-/encoding SNMP data.
653 652
653The L<Example Profile> section, below, shows how this profile is being
654constructed.
655
654Example: 656Example:
655 657
656 $ber = ber_decode $data, $Convert::BER::XS::SNMP_PROFILE; 658 $ber = ber_decode $data, $Convert::BER::XS::SNMP_PROFILE;
657 659
658=back 660=back
728dot, e.g. C<1.3.6.1.213>. 730dot, e.g. C<1.3.6.1.213>.
729 731
730=item C<BER_TYPE_RELOID> 732=item C<BER_TYPE_RELOID>
731 733
732Same as C<BER_TYPE_OID> but uses relative object identifier 734Same as C<BER_TYPE_OID> but uses relative object identifier
733encoding: ASN.1 has this hack of encoding the first two OID components 735encoding: ASN.1 uses some hack encoding of the first two OID components
734into a single integer in a weird attempt to save an insignificant amount 736into a single integer in a weird attempt to save an insignificant amount
735of space in an otherwise wasteful encoding, and relative OIDs are 737of space in an otherwise wasteful encoding, and relative OIDs are
736basically OIDs without this hack. The practical difference is that the 738basically OIDs without this hack. The practical difference is that the
737second component of an OID can only have the values 1..40, while relative 739second component of an OID can only have the values 1..40, while relative
738OIDs do not have this restriction. 740OIDs do not have this restriction.

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines