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.43 by root, Sun Apr 21 01:58:14 2019 UTC vs.
Revision 1.60 by root, Thu Feb 6 11:51:40 2020 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.21;
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.
478# I don't have access to ISO 6093 (or BS 6727, or ANSI X.3-42)), so this is all guesswork.
479sub _decode_real_decimal {
480 my ($format, $val) = @_;
481
482 $val =~ y/,/./; # probably not in ISO-6093
483
484 if ($format == 1) {
485 $val =~ /^ \ * [+-]? [0-9]+ \z/x
486 or Carp::croak "BER_TYPE_REAL NR1 value not in NR1 format ($val) (X.690 8.5.8)";
487 } elsif ($format == 2) {
488 $val =~ /^ \ * [+-]? (?: [0-9]+\.[0-9]* | [0-9]*\.[0-9]+ ) \z/x
489 or Carp::croak "BER_TYPE_REAL NR2 value not in NR2 format ($val) (X.690 8.5.8)";
490 } elsif ($format == 3) {
491 $val =~ /^ \ * [+-] (?: [0-9]+\.[0-9]* | [0-9]*\.[0-9]+ ) [eE] [+-]? [0-9]+ \z/x
492 or Carp::croak "BER_TYPE_REAL NR3 value not in NR3 format ($val) (X.690 8.5.8)";
493 } else {
494 Carp::croak "BER_TYPE_REAL invalid decimal numerical representation format $format";
495 }
496
497 $val
498}
499
500# this is a mess, but perl's support for floating point formatting is nearly nonexistant
501sub _encode_real_decimal {
502 my ($val, $nvdig) = @_;
503
504 $val = sprintf "%.*G", $nvdig + 1, $val;
505
506 if ($val =~ /E/) {
507 $val =~ s/E(?=[^+-])/E+/;
508 $val =~ s/E/.E/ if $val !~ /\./;
509 $val =~ s/^/+/ unless $val =~ /^-/;
510
511 return "\x03$val" # NR3
512 }
513
514 $val =~ /\./
515 ? "\x02$val" # NR2
516 : "\x01$val" # NR1
517}
474 518
475=head2 DEBUGGING 519=head2 DEBUGGING
476 520
477To aid debugging, you cna call the C<ber_dump> function to print a "nice" 521To aid debugging, you can call the C<ber_dump> function to print a "nice"
478representation to STDOUT. 522representation to STDOUT.
479 523
480=over 524=over
481 525
482=item ber_dump $tuple[, $profile[, $prefix]] 526=item ber_dump $tuple[, $profile[, $prefix]]
483 527
484In addition to specifying the BER C<$tuple> to dump, youc an also specify 528In 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. 529a C<$profile> and a C<$prefix> string that is printed in front of each line.
486 530
487If C<$profile> is C<$Convert::BER::XS::SNMP_PROFILE>, then C<ber_dump> 531If C<$profile> is C<$Convert::BER::XS::SNMP_PROFILE>, then C<ber_dump>
488will try to improve its output for SNMP data. 532will try to improve its output for SNMP data.
489 533
496Example output: 540Example output:
497 541
498 SEQUENCE 542 SEQUENCE
499 | OCTET_STRING bytes 800063784300454045045400000001 543 | OCTET_STRING bytes 800063784300454045045400000001
500 | OCTET_STRING bytes 544 | OCTET_STRING bytes
501 | CONTEXT (7) bytes CONSTRUCTED 545 | CONTEXT (7) CONSTRUCTED
502 | | INTEGER int 1058588941 546 | | INTEGER int 1058588941
503 | | INTEGER int 0 547 | | INTEGER int 0
504 | | INTEGER int 0 548 | | INTEGER int 0
505 | | SEQUENCE 549 | | SEQUENCE
506 | | | SEQUENCE 550 | | | SEQUENCE
549 $class =~ s/^ASN_//; 593 $class =~ s/^ASN_//;
550 $tag =~ s/^(ASN_|SNMP_)//; 594 $tag =~ s/^(ASN_|SNMP_)//;
551 $type =~ s/^BER_TYPE_//; 595 $type =~ s/^BER_TYPE_//;
552 596
553 if ($ber->[BER_FLAGS]) { 597 if ($ber->[BER_FLAGS]) {
554 printf "$indent%-16.16s %-6.6s CONSTRUCTED\n", $tag, lc $type; 598 printf "$indent%-16.16s\n", $tag;
555 &_ber_dump ($_, $profile, "$indent| ") 599 &_ber_dump ($_, $profile, "$indent| ")
556 for @$data; 600 for @$data;
557 } else { 601 } else {
558 if ($data =~ y/\x20-\x7e//c / (length $data || 1) > 0.2 or $data =~ /\x00./s) { 602 if ($data =~ y/\x20-\x7e//c / (length $data || 1) > 0.2 or $data =~ /\x00./s) {
559 # assume binary 603 # assume binary
560 $data = unpack "H*", $data; 604 $data = unpack "H*", $data;
561 } else { 605 } else {
562 $data =~ s/[^\x20-\x7e]/./g; 606 $data =~ s/[^\x20-\x7e]/./g;
563 $data = "\"$data\"" if $type =~ /string/i || !length $data; 607 $data = "\"$data\"" if $tag =~ /string/i || !length $data;
564 } 608 }
565 609
566 substr $data, 40, 1e9, "..." if 40 < length $data; 610 substr $data, 40, 1e9, "..." if 40 < length $data;
567 611
568 printf "$indent%-16.16s %-6.6s %s\n", $tag, lc $type, $data; 612 printf "$indent%-16.16s %-6.6s %s\n", $tag, lc $type, $data;
641 685
642Returns the BER type mapped to the given C<$class>/C<$tag> combination. 686Returns the BER type mapped to the given C<$class>/C<$tag> combination.
643 687
644=back 688=back
645 689
646=head2 BER TYPES 690=head2 BER Types
647 691
648This lists the predefined BER types - you can map any C<CLASS>/C<TAG> 692This lists the predefined BER types. BER types are formatters used
649combination to any C<BER_TYPE_*>. 693internally to format and encode BER values. You can assign any C<BER_TYPE>
694to any C<CLASS>/C<TAG> combination tgo change how that tag is decoded or
695encoded.
650 696
651=over 697=over
652 698
653=item C<BER_TYPE_BYTES> 699=item C<BER_TYPE_BYTES>
654 700
731 777
732 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_IPADDRESS , BER_TYPE_IPADDRESS); 778 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_IPADDRESS , BER_TYPE_IPADDRESS);
733 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER32 , BER_TYPE_INT); 779 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER32 , BER_TYPE_INT);
734 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_UNSIGNED32, BER_TYPE_INT); 780 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_UNSIGNED32, BER_TYPE_INT);
735 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_TIMETICKS , BER_TYPE_INT); 781 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_TIMETICKS , BER_TYPE_INT);
736 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_OPAQUE , BER_TYPE_IPADDRESS); 782 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_OPAQUE , BER_TYPE_BYTES);
737 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER64 , BER_TYPE_INT); 783 $SNMP_PROFILE->set (ASN_APPLICATION, SNMP_COUNTER64 , BER_TYPE_INT);
738 784
739=head2 LIMITATIONS/NOTES 785=head2 LIMITATIONS/NOTES
740 786
741This module can only en-/decode 64 bit signed and unsigned integers, and 787This module can only en-/decode 64 bit signed and unsigned
742only when your perl supports those. So no UUID OIDs for now. 788integers/tags/lengths, and only when your perl supports those. So no UUID
789OIDs for now (unless you map the C<OBJECT IDENTIFIER> tag to something
790other than C<BER_TYPE_OID>).
743 791
744This module does not generally care about ranges, i.e. it will happily 792This module does not generally care about ranges, i.e. it will happily
745de-/encode 64 bit integers into an C<ASN_INTEGER> value, or a negative 793de-/encode 64 bit integers into an C<SNMP_UNSIGNED32> value, or a negative
746number into an C<SNMP_COUNTER64>. 794number into an C<SNMP_COUNTER64>.
747 795
748OBJECT IDENTIFIEERs cannot have unlimited length, although the limit is 796OBJECT IDENTIFIEERs cannot have unlimited length, although the limit is
749much larger than e.g. the one imposed by SNMP or other protocols,a nd is 797much larger than e.g. the one imposed by SNMP or other protocols, and is
750about 4kB. 798about 4kB.
751
752Indefinite length encoding is not supported.
753 799
754Constructed strings are decoded just fine, but there should be a way to 800Constructed strings are decoded just fine, but there should be a way to
755join them for convenience. 801join them for convenience.
756 802
757REAL values are not supported and will currently croak. 803REAL values will always be encoded in decimal form and ssometimes is
758 804forced into a perl "NV" type, potentially losing precision.
759The encoder and decoder tend to accept more formats than should be
760strictly supported.
761
762This module has undergone little to no testing so far.
763 805
764=head2 ITHREADS SUPPORT 806=head2 ITHREADS SUPPORT
765 807
766This module is unlikely to work when the (officially discouraged) ithreads 808This module is unlikely to work in any other than the loading thread when
767are in use. 809the (officially discouraged) ithreads are in use.
768 810
769=head1 AUTHOR 811=head1 AUTHOR
770 812
771 Marc Lehmann <schmorp@schmorp.de> 813 Marc Lehmann <schmorp@schmorp.de>
772 http://software.schmorp.de/pkg/Convert-BER-XS 814 http://software.schmorp.de/pkg/Convert-BER-XS

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines