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.37 by root, Sun Apr 21 00:36:19 2019 UTC vs.
Revision 1.57 by root, Thu Apr 25 22:30:21 2019 UTC

8 8
9 my $ber = ber_decode $buf, $Convert::BER::XS::SNMP_PROFILE 9 my $ber = ber_decode $buf, $Convert::BER::XS::SNMP_PROFILE
10 or die "unable to decode SNMP message"; 10 or die "unable to decode SNMP message";
11 11
12 # The above results in a data structure consisting of 12 # The above results in a data structure consisting of
13 # (class, tag, flags, data) 13 # (class, tag, flags, data)
14 # tuples. Below is such a message, SNMPv1 trap 14 # tuples. Below is such a message, SNMPv1 trap
15 # with a Cisco mac change notification. 15 # with a Cisco mac change notification.
16 # Did you know that Cisco is in the news almost 16 # Did you know that Cisco is in the news almost
17 # every week because of some backdoor password 17 # every week because of some backdoor password
18 # or other extremely stupid security bug? 18 # or other extremely stupid security bug?
108 BER_CLASS BER_TAG BER_FLAGS BER_DATA 108 BER_CLASS BER_TAG BER_FLAGS BER_DATA
109 109
110=item C<:const_asn> 110=item C<:const_asn>
111 111
112ASN class values (these are C<0>, C<1>, C<2> and C<3>, respectively - 112ASN class values (these are C<0>, C<1>, C<2> and C<3>, respectively -
113exactly thw two topmost bits from the identifier octet shifted 6 bits to 113exactly the two topmost bits from the identifier octet shifted 6 bits to
114the right): 114the right):
115 115
116 ASN_UNIVERSAL ASN_APPLICATION ASN_CONTEXT ASN_PRIVATE 116 ASN_UNIVERSAL ASN_APPLICATION ASN_CONTEXT ASN_PRIVATE
117 117
118ASN tag values (some of which are aliases, such as C<ASN_OID>). Their 118ASN tag values (some of which are aliases, such as C<ASN_OID>). Their
296Also, since BER is self-delimited, this can be used to decode multiple BER 296Also, since BER is self-delimited, this can be used to decode multiple BER
297values joined together. 297values joined together.
298 298
299=item $bindata = ber_encode $tuple[, $profile] 299=item $bindata = ber_encode $tuple[, $profile]
300 300
301Encodes the BER tuple into a BER/DER data structure. AS with 301Encodes the BER tuple into a BER/DER data structure. As with
302Cyber_decode>, an optional profile can be given. 302Cyber_decode>, an optional profile can be given.
303 303
304The encoded data should be both BER and DER ("shortest form") compliant 304The encoded data should be both BER and DER ("shortest form") compliant
305unless the input says otherwise (e.g. it uses constructed strings). 305unless the input says otherwise (e.g. it uses constructed strings).
306 306
409use common::sense; 409use common::sense;
410 410
411use XSLoader (); 411use XSLoader ();
412use Exporter qw(import); 412use Exporter qw(import);
413 413
414use Carp ();
415
414our $VERSION; 416our $VERSION;
415 417
416BEGIN { 418BEGIN {
417 $VERSION = '1.0'; 419 $VERSION = 1.2;
418 XSLoader::load __PACKAGE__, $VERSION; 420 XSLoader::load __PACKAGE__, $VERSION;
419} 421}
420 422
421our %EXPORT_TAGS = ( 423our %EXPORT_TAGS = (
422 const_index => [qw( 424 const_index => [qw(
468 470
469$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_IPADDRESS , BER_TYPE_IPADDRESS); 471$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_IPADDRESS , BER_TYPE_IPADDRESS);
470$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER32 , BER_TYPE_INT); 472$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER32 , BER_TYPE_INT);
471$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_UNSIGNED32, BER_TYPE_INT); 473$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_UNSIGNED32, BER_TYPE_INT);
472$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_TIMETICKS , BER_TYPE_INT); 474$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_TIMETICKS , BER_TYPE_INT);
473$SNMP_PROFILE->set (ASN_APPLICATION, SNMP_OPAQUE , BER_TYPE_IPADDRESS); 475
476# decodes REAL values according to ECMA-63
477# this is pretty strict, except it doesn't catch -0.
478sub _decode_real_decimal {
479 my ($format, $val) = @_;
480
481 $val =~ y/,/./;
482
483 if ($format == 1) {
484 $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 } elsif ($format == 2) {
487 $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 } elsif ($format == 3) {
490 $val =~ /^ \ * [+-] (?: [0-9]+\.[0-9]* | [0-9]*\.[0-9]+ ) E [+-][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 } else {
493 Carp::croak "BER_TYPE_REAL illegal decimal numerical representation format $format";
494 }
495
496 $val
497}
498
499# this is a mess, but perl's support for floating point formatting is nearly nonexistant
500sub _encode_real_decimal {
501 my ($val, $nvdig) = @_;
502
503 $val = sprintf "%.*G", $nvdig + 1, $val;
504
505 if ($val =~ /E/) {
506 $val =~ s/E(?=[^+-])/E+/;
507 $val =~ s/E/.E/ if $val !~ /\./;
508 $val =~ s/^/+/ unless $val =~ /^-/;
509
510 return "\x03$val" # NR3
511 }
512
513 $val =~ /\./
514 ? "\x02$val" # NR2
515 : "\x01$val" # NR1
516}
474 517
475=head2 DEBUGGING 518=head2 DEBUGGING
476 519
477To aid debugging, you cna call the C<ber_dump> function to print a "nice" 520To aid debugging, you can call the C<ber_dump> function to print a "nice"
478representation to STDOUT. 521representation to STDOUT.
479 522
480=over 523=over
481 524
482=item ber_dump $tuple[, $profile[, $prefix]] 525=item ber_dump $tuple[, $profile[, $prefix]]
483 526
484In addition to specifying the BER C<$tuple> to dump, youc an also specify 527In addition to specifying the BER C<$tuple> to dump, you can also specify
485a C<$profile> and a C<$prefix> string that is printed in front of each line. 528a C<$profile> and a C<$prefix> string that is printed in front of each line.
486 529
487If C<$profile> is C<$Convert::BER::XS::SNMP_PROFILE>, then C<ber_dump> 530If C<$profile> is C<$Convert::BER::XS::SNMP_PROFILE>, then C<ber_dump>
488will try to improve its output for SNMP data. 531will try to improve its output for SNMP data.
489 532
496Example output: 539Example output:
497 540
498 SEQUENCE 541 SEQUENCE
499 | OCTET_STRING bytes 800063784300454045045400000001 542 | OCTET_STRING bytes 800063784300454045045400000001
500 | OCTET_STRING bytes 543 | OCTET_STRING bytes
501 | CONTEXT (7) bytes CONSTRUCTED 544 | CONTEXT (7) CONSTRUCTED
502 | | INTEGER int 1058588941 545 | | INTEGER int 1058588941
503 | | INTEGER int 0 546 | | INTEGER int 0
504 | | INTEGER int 0 547 | | INTEGER int 0
505 | | SEQUENCE 548 | | SEQUENCE
506 | | | SEQUENCE 549 | | | SEQUENCE
507 | | | | OID oid 1.3.6.1.2.1.1.3.0 550 | | | | OID oid 1.3.6.1.2.1.1.3.0
508 | | | | TIMETICKS int 638085796 551 | | | | TIMETICKS int 638085796
509 552
553=back
554
510=cut 555=cut
511 556
512# reverse enum, very slow and ugly hack 557# reverse enum, very slow and ugly hack
513sub _re { 558sub _re {
514 my ($export_tag, $value) = @_; 559 my ($export_tag, $value) = @_;
538 my $type = _re const_ber_type => $profile->get ($ber->[BER_CLASS], $ber->[BER_TAG]); 583 my $type = _re const_ber_type => $profile->get ($ber->[BER_CLASS], $ber->[BER_TAG]);
539 my $data = $ber->[BER_DATA]; 584 my $data = $ber->[BER_DATA];
540 585
541 if ($profile == $SNMP_PROFILE and $ber->[BER_CLASS] == ASN_APPLICATION) { 586 if ($profile == $SNMP_PROFILE and $ber->[BER_CLASS] == ASN_APPLICATION) {
542 $tag = _re const_snmp => $ber->[BER_TAG]; 587 $tag = _re const_snmp => $ber->[BER_TAG];
543 $asn = 1; 588 } elsif (!$asn) {
589 $tag = "$class ($tag)";
544 } 590 }
545
546 $asn or $tag = "$class ($tag)";
547 591
548 $class =~ s/^ASN_//; 592 $class =~ s/^ASN_//;
549 $tag =~ s/^(ASN_|SNMP_)//; 593 $tag =~ s/^(ASN_|SNMP_)//;
550 $type =~ s/^BER_TYPE_//; 594 $type =~ s/^BER_TYPE_//;
551 595
552 if ($ber->[BER_FLAGS]) { 596 if ($ber->[BER_FLAGS]) {
553 printf "$indent%-16.16s %-6.6s CONSTRUCTED\n", $tag, lc $type; 597 printf "$indent%-16.16s\n", $tag;
554 &_ber_dump ($_, $profile, "$indent| ") 598 &_ber_dump ($_, $profile, "$indent| ")
555 for @$data; 599 for @$data;
556 } else { 600 } else {
557 if ($data =~ y/\x20-\x7e//c > 10 or $data =~ /\x00./s) { 601 if ($data =~ y/\x20-\x7e//c / (length $data || 1) > 0.2 or $data =~ /\x00./s) {
558 # assume binary 602 # assume binary
559 $data = unpack "H*", $data; 603 $data = unpack "H*", $data;
560 substr $data, 40, 1e9, "..." if 40 < length $data;
561 } else { 604 } else {
562 $data =~ s/[^\x20-\x7e]/./g; 605 $data =~ s/[^\x20-\x7e]/./g;
563 $data = "\"$data\"" if $type =~ /string/i; 606 $data = "\"$data\"" if $tag =~ /string/i || !length $data;
564 substr $data, 40, 1e9, "..." if 40 < length $data;
565 } 607 }
608
609 substr $data, 40, 1e9, "..." if 40 < length $data;
566 610
567 printf "$indent%-16.16s %-6.6s %s\n", $tag, lc $type, $data; 611 printf "$indent%-16.16s %-6.6s %s\n", $tag, lc $type, $data;
568 } 612 }
569 } 613 }
570} 614}
640 684
641Returns the BER type mapped to the given C<$class>/C<$tag> combination. 685Returns the BER type mapped to the given C<$class>/C<$tag> combination.
642 686
643=back 687=back
644 688
645=head2 BER TYPES 689=head2 BER Types
646 690
647This lists the predefined BER types - you can map any C<CLASS>/C<TAG> 691This lists the predefined BER types. BER types are formatters used
648combination to any C<BER_TYPE_*>. 692internally to format and encode BER values. You can assign any C<BER_TYPE>
693to any C<CLASS>/C<TAG> combination tgo change how that tag is decoded or
694encoded.
649 695
650=over 696=over
651 697
652=item C<BER_TYPE_BYTES> 698=item C<BER_TYPE_BYTES>
653 699
730 776
731 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_IPADDRESS , BER_TYPE_IPADDRESS); 777 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_IPADDRESS , BER_TYPE_IPADDRESS);
732 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER32 , BER_TYPE_INT); 778 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER32 , BER_TYPE_INT);
733 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_UNSIGNED32, BER_TYPE_INT); 779 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_UNSIGNED32, BER_TYPE_INT);
734 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_TIMETICKS , BER_TYPE_INT); 780 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_TIMETICKS , BER_TYPE_INT);
735 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_OPAQUE , BER_TYPE_IPADDRESS); 781 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_OPAQUE , BER_TYPE_BYTES);
736 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER64 , BER_TYPE_INT); 782 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER64 , BER_TYPE_INT);
737 783
738=head2 LIMITATIONS/NOTES 784=head2 LIMITATIONS/NOTES
739 785
740This module can only en-/decode 64 bit signed and unsigned integers, and 786This module can only en-/decode 64 bit signed and unsigned
741only when your perl supports those. 787integers/tags/lengths, and only when your perl supports those. So no UUID
788OIDs for now (unless you map the C<OBJECT IDENTIFIER> tag to something
789other than C<BER_TYPE_OID>).
742 790
743This module does not generally care about ranges, i.e. it will happily 791This module does not generally care about ranges, i.e. it will happily
744de-/encode 64 bit integers into an C<ASN_INTEGER> value, or a negative 792de-/encode 64 bit integers into an C<SNMP_UNSIGNED32> value, or a negative
745number into an C<SNMP_COUNTER64>. 793number into an C<SNMP_COUNTER64>.
746 794
747OBJECT IDENTIFIEERs cannot have unlimited length, although the limit is 795OBJECT IDENTIFIEERs cannot have unlimited length, although the limit is
748much larger than e.g. the one imposed by SNMP or other protocols,a nd is 796much larger than e.g. the one imposed by SNMP or other protocols, and is
749about 4kB. 797about 4kB.
750
751Indefinite length encoding is not supported.
752 798
753Constructed strings are decoded just fine, but there should be a way to 799Constructed strings are decoded just fine, but there should be a way to
754join them for convenience. 800join them for convenience.
755 801
756REAL values are not supported and will currently croak. 802REAL values will always be encoded in decimal form and ssometimes is
757 803forced into a perl "NV" type, potentially losing precision.
758The encoder and decoder tend to accept more formats than should be
759strictly supported.
760
761This module has undergone little to no testing so far.
762 804
763=head2 ITHREADS SUPPORT 805=head2 ITHREADS SUPPORT
764 806
765This module is unlikely to work when the (officially discouraged) ithreads 807This module is unlikely to work in any other than the loading thread when
766are in use. 808the (officially discouraged) ithreads are in use.
767 809
768=head1 AUTHOR 810=head1 AUTHOR
769 811
770 Marc Lehmann <schmorp@schmorp.de> 812 Marc Lehmann <schmorp@schmorp.de>
771 http://software.schmorp.de/pkg/Convert-BER-XS 813 http://software.schmorp.de/pkg/Convert-BER-XS

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines