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.1 by root, Fri Apr 19 16:19:36 2019 UTC vs.
Revision 1.5 by root, Fri Apr 19 19:46:41 2019 UTC

1=head1 NAME 1=head1 NAME
2 2
3Convert::BER::XS - I<very> low level BER decoding 3Convert::BER::XS - I<very> low level BER en-/decoding
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 my $ber = ber_decode $buf 9 my $ber = ber_decode $buf
10 or die "unable to decode SNMP v1/v2c Message"; 10 or die "unable to decode SNMP v1/v2c Message";
11 11
12 # the above results in a data structure consisting of (class, tag,
13 # constructed, data) tuples. here is such a message, SNMPv1 trap
14 # with a cisoc mac change notification
15
16 [ ASN_UNIVERSAL, ASN_SEQUENCE, 1,
17 [
18 [ ASN_UNIVERSAL, ASN_INTEGER32, 0, 0 ], # snmp version 1
19 [ ASN_UNIVERSAL, 4, 0, "public" ], # community
20 [ ASN_CONTEXT, 4, 1, # CHOICE, constructed
21 [
22 [ ASN_UNIVERSAL, ASN_OBJECT_IDENTIFIER, 0, "1.3.6.1.4.1.9.9.215.2" ], # enterprise oid
23 [ ASN_APPLICATION, 0, 0, "\x0a\x00\x00\x01" ], # SNMP IpAddress, 10.0.0.1
24 [ ASN_UNIVERSAL, ASN_INTEGER32, 0, 6 ], # generic trap
25 [ ASN_UNIVERSAL, ASN_INTEGER32, 0, 1 ], # specific trap
26 [ ASN_APPLICATION, ASN_TIMETICKS, 0, 1817903850 ], # SNMP TimeTicks
27 [ ASN_UNIVERSAL, ASN_SEQUENCE, 1, # the varbindlist
28 [
29 [ ASN_UNIVERSAL, ASN_SEQUENCE, 1, # a single varbind, "key value" pair
30 [
31 [ ASN_UNIVERSAL, ASN_OBJECT_IDENTIFIER, 0, "1.3.6.1.4.1.9.9.215.1.1.8.1.2.1" ], # the oid
32 [ ASN_UNIVERSAL, ASN_OCTET_STRING, 0, "...data..." # the value
33 ]
34 ]
35 ],
36 ...
37
38 # let's decode it a bit with some helper functions
39
12 my $msg = ber_is_seq $ber 40 my $msg = ber_is_seq $ber
13 or die "SNMP message does not start with a sequence"; 41 or die "SNMP message does not start with a sequence";
14 42
15 ber_is $msg->[0], ASN_UNIVERSAL, ASN_INTEGER32, 0 43 ber_is $msg->[0], ASN_UNIVERSAL, ASN_INTEGER32, 0
16 or die "SNMP message does not start with snmp version\n"; 44 or die "SNMP message does not start with snmp version\n";
17 45
46 # message is SNMP v1 or v2c?
18 if ($msg->[0][BER_DATA] == 0 || $msg->[0][BER_DATA] == 1) { 47 if ($msg->[0][BER_DATA] == 0 || $msg->[0][BER_DATA] == 1) {
48
19 # message is SNMP v1 or v2c 49 # message is v1 trap?
20
21 if (ber_is $msg->[2], ASN_CONTEXT, 4, 1) { 50 if (ber_is $msg->[2], ASN_CONTEXT, 4, 1) {
22 # message is v1 trap
23 my $trap = $msg->[2][BER_DATA]; 51 my $trap = $msg->[2][BER_DATA];
24 52
25 # check whether trap is a cisco mac notification mac changed message 53 # check whether trap is a cisco mac notification mac changed message
26 if ( 54 if (
27 (ber_is_oid $trap->[0], "1.3.6.1.4.1.9.9.215.2") # cmnInterfaceObjects 55 (ber_is_oid $trap->[0], "1.3.6.1.4.1.9.9.215.2") # cmnInterfaceObjects
28 and (ber_is_i32 $trap->[2], 6) 56 and (ber_is_i32 $trap->[2], 6)
29 and (ber_is_i32 $trap->[3], 1) # mac changed msg 57 and (ber_is_i32 $trap->[3], 1) # mac changed msg
30 ) { 58 ) {
31 ... and so on 59 ... and so on
32 60
61 # finally, let's encode it again and hope it results in the same bit pattern
62
63 my $buf = ber_encode $ber;
64
33=head1 DESCRIPTION 65=head1 DESCRIPTION
34 66
35This module implements a I<very> low level BER/DER decoder, and in the 67This module implements a I<very> low level BER/DER en-/decoder.
36future, probably also an encoder (tell me if you want an encoder, this
37might speed up the process of getting one).
38 68
39If is tuned for low memory and high speed, while still maintaining some 69If is tuned for low memory and high speed, while still maintaining some
40level of user-friendlyness. 70level of user-friendlyness.
41 71
42Currently, not much is documented, as this is an initial release to 72Currently, not much is documented, as this is an initial release to
43reserve CPAN namespace, stay tuned for a few days. 73reserve CPAN namespace, stay tuned for a few days.
44 74
75=head2 ASN.1/BER/DER/... BASICS
76
77ASN.1 is a strange language that can be sed to describe protocols and
78data structures. It supports various mappings to JSON, XML, but most
79importantly, to a various binary encodings such as BER, that is the topic
80of this module, and is used in SNMP or LDAP for example.
81
82While ASN.1 defines a schema that is useful to interpret encoded data,
83the BER encoding is actually somehat self-describing: you might not know
84whether something is a string or a number or a sequence or something else,
85but you can nevertheless decode the overall structure, even if you end up
86with just a binary blob for the actual value.
87
88This works because BER values are tagged with a type and a namespace,
89and also have a flag that says whther a value consists of subvalues (is
90"constructed") or not (is "primitive").
91
92Tags are simple integers, and ASN.1 defines a somewhat weird assortment of
93those - for example, you have 32 bit signed integers and 16(!) different
94string types, but there is no unsigned32 type for example. Different
95applications work around this in different ways, for example, SNMP defines
96application-specific Gauge32, Counter32 and Unsigned32, which are mapped
97to two different tags: you can distinguish between Counter32 and the
98others, but not between Gause32 and Unsigned32, without the ASN.1 schema.
99
100Ugh.
101
102=head2 DECODED BER REPRESENTATION
103
104This module represents every BER value as a 4-element tuple (actually an
105array-reference):
106
107 [CLASS, TAG, CONSTRUCTED, DATA]
108
109I<CLASS> is something like a namespace for I<TAG>s - there is the
110C<ASN_UNIVERSAL> namespace which defines tags common to all ASN.1
111implementations, the C<ASN_APPLICATION> namespace which defines tags for
112specific applications (for example, the SNMP C<Unsigned32> type is in this
113namespace), a special-purpose context namespace (C<ASN_CONTEXT>, used e.g.
114for C<CHOICE>) and a private namespace (C<ASN_PRIVATE>).
115
116The meaning of the I<TAG> depends on the namespace, and defines a
117(partial) interpretation of the data value. For example, right now, SNMP
118application namespace knowledge ix hardcoded into this module, so it
119knows that SNMP C<Unsigned32> values need to be decoded into actual perl
120integers.
121
122The most common tags in the C<ASN_UNIVERSAL> namespace are
123C<ASN_INTEGER32>, C<ASN_BIT_STRING>, C<ASN_NULL>, C<ASN_OCTET_STRING>,
124C<ASN_OBJECT_IDENTIFIER>, C<ASN_SEQUENCE>, C<ASN_SET> and
125C<ASN_IA5_STRING>.
126
127The most common tags in SNMP's C<ASN_APPLICATION> namespace
128are C<SNMP_IPADDRESS>, C<SNMP_COUNTER32>, C<SNMP_UNSIGNED32>,
129C<SNMP_TIMETICKS>, C<SNMP_OPAQUE> and C<SNMP_COUNTER64>.
130
131The I<CONSTRUCTED> flag is really just a boolean - if it is false, the
132the value is "primitive" and contains no subvalues, kind of like a
133non-reference perl scalar. IF it is true, then the value is "constructed"
134which just means it contains a list of subvalues which this module will
135en-/decode as BER tuples themselves.
136
137The I<DATA> value is either a reference to an array of further tuples (if
138the value is I<CONSTRUCTED>), some decoded representation of the value,
139if this module knows how to decode it (e.g. for the integer types above)
140or a binary string with the raw octets if this module doesn't know how to
141interpret the namespace/tag.
142
143Thus, you can always decode a BER data structure and at worst you get a
144string in place of some nice decoded value.
145
146See the SYNOPSIS for an example of such an encoded tuple representation.
147
148=head2 RELATIONSHIP TO L<Convert::BER> and L<Convert::ASN1>
149
150This module is I<not> the XS version of L<Convert::BER>, but a different
151take at doing the same thing. I imagine this module would be a good base
152for speeding up either of these, or write a similar module, or write your
153own LDAP or SNMP module for example.
154
45=cut 155=cut
46 156
47package Convert::BER::XS; 157package Convert::BER::XS;
48 158
49use common::sense; 159use common::sense;
50 160
51use XSLoader (); 161use XSLoader ();
52use Exporter qw(import); 162use Exporter qw(import);
53 163
54our $VERSION = '0.0'; 164our $VERSION = 0.1;
55 165
56XSLoader::load __PACKAGE__, $VERSION; 166XSLoader::load __PACKAGE__, $VERSION;
57 167
58our %EXPORT_TAGS = ( 168our %EXPORT_TAGS = (
59 all => [qw( 169 const => [qw(
170 BER_CLASS BER_TAG BER_CONSTRUCTED BER_DATA
171
172 ASN_BOOLEAN ASN_INTEGER32 ASN_BIT_STRING ASN_OCTET_STRING ASN_NULL ASN_OBJECT_IDENTIFIER ASN_TAG_BER ASN_TAG_MASK
173 ASN_CONSTRUCTED ASN_UNIVERSAL ASN_APPLICATION ASN_CONTEXT ASN_PRIVATE ASN_CLASS_MASK ASN_CLASS_SHIFT
174 ASN_SEQUENCE
175
176 SNMP_IPADDRESS SNMP_COUNTER32 SNMP_UNSIGNED32 SNMP_TIMETICKS SNMP_OPAQUE SNMP_COUNTER64
177 )],
178 encode => [qw(
60 ber_decode 179 ber_decode
61 ber_is ber_is_seq ber_is_i32 ber_is_oid 180 ber_is ber_is_seq ber_is_i32 ber_is_oid
62 BER_CLASS BER_TAG BER_CONSTRUCTED BER_DATA 181 )],
63 ASN_BOOLEAN ASN_INTEGER32 ASN_BIT_STRING ASN_OCTET_STRING ASN_NULL ASN_OBJECT_IDENTIFIER ASN_TAG_BER ASN_TAG_MASK 182 decode => [qw(
64 ASN_CONSTRUCTED ASN_UNIVERSAL ASN_APPLICATION ASN_CONTEXT ASN_PRIVATE ASN_CLASS_MASK ASN_CLASS_SHIFT 183 ber_encode
65 ASN_SEQUENCE ASN_IPADDRESS ASN_COUNTER32 ASN_UNSIGNED32 ASN_TIMETICKS ASN_OPAQUE ASN_COUNTER64
66 )], 184 )],
67); 185);
68 186
69our @EXPORT_OK = map @$_, values %EXPORT_TAGS; 187our @EXPORT_OK = map @$_, values %EXPORT_TAGS;
70 188
189$EXPORT_TAGS{all} = \@EXPORT_OK;
190
711; 1911;
192
193=head2 BUGS / SHORTCOMINGs
194
195This module does have a number of SNMPisms hardcoded, such as the SNMP
196tags for Unsigned32 and so on. More configurability is needed, and, if
197ever implemented, will come in a form similar to how L<JSON::XS> and
198L<CBOR::XS> respresent things, namely with an object-oriented interface.
72 199
73=head1 AUTHOR 200=head1 AUTHOR
74 201
75 Marc Lehmann <schmorp@schmorp.de> 202 Marc Lehmann <schmorp@schmorp.de>
76 http://software.schmorp.de/pkg/Convert-BER-XS 203 http://software.schmorp.de/pkg/Convert-BER-XS

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines