File Coverage

blib/lib/Net/sFlow.pm
Criterion Covered Total %
statement 384 1259 30.5
branch 1 322 0.3
condition 0 18 0.0
subroutine 128 157 81.5
pod 1 1 100.0
total 514 1757 29.2


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             #
3             # With many thanks to Tobias Engel for his help and support!
4             #
5             # Elisa Jasinska
6             # 12/19/2014
7             #
8             #
9             # Copyright (c) 2006 - 2015 AMS-IX B.V.
10             #
11             # This package is free software and is provided "as is" without express
12             # or implied warranty. It may be used, redistributed and/or modified
13             # under the terms of the Perl Artistic License (see
14             # http://www.perl.com/perl/misc/Artistic.html)
15             #
16             #
17             # sFlow v4 RFC 3176
18             # http://www.ietf.org/rfc/rfc3176.txt
19             #
20             # sFlow v5 Memo
21             # http://sflow.org/sflow_version_5.txt
22             #
23              
24              
25             package Net::sFlow;
26              
27              
28 1     1   498488 use strict;
  1         3  
  1         44  
29 1     1   5 use warnings;
  1         2  
  1         63  
30 1     1   6 use bytes;
  1         2  
  1         9  
31              
32 1     1   73 use Exporter 'import';
  1         4  
  1         105  
33             our $VERSION;
34             our @EXPORT_OK;
35             BEGIN {
36 1     1   3 $VERSION = '0.14';
37 1         130 @EXPORT_OK = qw(decode);
38             }
39              
40             # 64-bit integers
41             my $have_quad;
42             my $Q;
43             BEGIN {
44 1     1   4 eval {# die "no quad"; # uncomment to test BigInt version on 64bit systems.
45 1         2 $have_quad = pack( 'Q', 1 ); $Q = 'Q>'};
  1         2  
46 1 50       39 if ($@) {
47 0         0 require Math::BigInt;
48 0         0 $have_quad = 0;
49 0         0 $Q = '(a8)';
50             }
51             }
52              
53             # constants
54              
55 1     1   8 use constant SFLOWv4 => 4;
  1         2  
  1         72  
56 1     1   6 use constant SFLOWv5 => 5;
  1         3  
  1         82  
57              
58 1     1   6 use constant UNKNOWNIPVERSION => 0;
  1         2  
  1         62  
59 1     1   6 use constant IPv4 => 1;
  1         2  
  1         44  
60 1     1   6 use constant IPv6 => 2;
  1         11  
  1         50  
61              
62             # sFlow v4 constants
63              
64 1     1   5 use constant FLOWSAMPLE_SFLOWv4 => 1;
  1         3  
  1         55  
65 1     1   5 use constant COUNTERSAMPLE_SFLOWv4 => 2;
  1         8  
  1         67  
66              
67 1     1   6 use constant HEADERDATA_SFLOWv4 => 1;
  1         2  
  1         45  
68 1     1   18 use constant IPv4DATA_SFLOWv4 => 2;
  1         2  
  1         46  
69 1     1   5 use constant IPv6DATA_SFLOWv4 => 3;
  1         2  
  1         86  
70              
71 1     1   7 use constant SWITCHDATA_SFLOWv4 => 1;
  1         1  
  1         47  
72 1     1   6 use constant ROUTERDATA_SFLOWv4 => 2;
  1         1  
  1         56  
73 1     1   6 use constant GATEWAYDATA_SFLOWv4 => 3;
  1         1  
  1         44  
74 1     1   34 use constant USERDATA_SFLOWv4 => 4;
  1         1  
  1         67  
75 1     1   5 use constant URLDATA_SFLOWv4 => 5;
  1         2  
  1         56  
76              
77 1     1   6 use constant GENERICCOUNTER_SFLOWv4 => 1;
  1         2  
  1         46  
78 1     1   5 use constant ETHERNETCOUNTER_SFLOWv4 => 2;
  1         2  
  1         55  
79 1     1   5 use constant TOKENRINGCOUNTER_SFLOWv4 => 3;
  1         2  
  1         62  
80 1     1   6 use constant FDDICOUNTER_SFLOWv4 => 4;
  1         2  
  1         55  
81 1     1   6 use constant VGCOUNTER_SFLOWv4 => 5;
  1         1  
  1         58  
82 1     1   5 use constant WANCOUNTER_SFLOWv4 => 6;
  1         2  
  1         65  
83 1     1   6 use constant VLANCOUNTER_SFLOWv4 => 7;
  1         2  
  1         49  
84              
85             # sFlow v5 constants
86              
87 1     1   5 use constant FLOWSAMPLE_SFLOWv5 => 1;
  1         1  
  1         55  
88 1     1   5 use constant COUNTERSAMPLE_SFLOWv5 => 2;
  1         7  
  1         62  
89 1     1   6 use constant EXPANDEDFLOWSAMPLE_SFLOWv5 => 3;
  1         2  
  1         68  
90 1     1   5 use constant EXPANDEDCOUNTERSAMPLE_SFLOWv5 => 4;
  1         2  
  1         69  
91 1     1   6 use constant FOUNDRY_ACL_SFLOWv5 => 1991;
  1         1  
  1         62  
92              
93 1     1   5 use constant HEADERDATA_SFLOWv5 => 1;
  1         2  
  1         408  
94 1     1   8 use constant ETHERNETFRAMEDATA_SFLOWv5 => 2;
  1         2  
  1         71  
95 1     1   6 use constant IPv4DATA_SFLOWv5 => 3;
  1         2  
  1         48  
96 1     1   6 use constant IPv6DATA_SFLOWv5 => 4;
  1         2  
  1         57  
97 1     1   5 use constant SWITCHDATA_SFLOWv5 => 1001;
  1         2  
  1         54  
98 1     1   6 use constant ROUTERDATA_SFLOWv5 => 1002;
  1         2  
  1         45  
99 1     1   5 use constant GATEWAYDATA_SFLOWv5 => 1003;
  1         1  
  1         69  
100 1     1   25 use constant USERDATA_SFLOWv5 => 1004;
  1         3  
  1         53  
101 1     1   29 use constant URLDATA_SFLOWv5 => 1005;
  1         2  
  1         69  
102 1     1   5 use constant MPLSDATA_SFLOWv5 => 1006;
  1         2  
  1         73  
103 1     1   8 use constant NATDATA_SFLOWv5 => 1007;
  1         2  
  1         71  
104 1     1   7 use constant MPLSTUNNEL_SFLOWv5 => 1008;
  1         1  
  1         63  
105 1     1   6 use constant MPLSVC_SFLOWv5 => 1009;
  1         2  
  1         61  
106 1     1   6 use constant MPLSFEC_SFLOWv5 => 1010;
  1         2  
  1         55  
107 1     1   6 use constant MPLSLVPFEC_SFLOWv5 => 1011;
  1         2  
  1         55  
108 1     1   6 use constant VLANTUNNEL_SFLOWv5 => 1012;
  1         1  
  1         45  
109              
110 1     1   6 use constant GENERICCOUNTER_SFLOWv5 => 1;
  1         1  
  1         62  
111 1     1   5 use constant ETHERNETCOUNTER_SFLOWv5 => 2;
  1         2  
  1         52  
112 1     1   5 use constant TOKENRINGCOUNTER_SFLOWv5 => 3;
  1         2  
  1         181  
113 1     1   7 use constant VGCOUNTER_SFLOWv5 => 4;
  1         2  
  1         84  
114 1     1   7 use constant VLANCOUNTER_SFLOWv5 => 5;
  1         2  
  1         47  
115 1     1   5 use constant LAGCOUNTER_SFLOWv5 => 7;
  1         3  
  1         55  
116 1     1   5 use constant PROCESSORCOUNTER_SFLOWv5 => 1001;
  1         2  
  1         73  
117 1     1   23 use constant HTTPCOUNTER_SFLOWv5 => 2201;
  1         3  
  1         59  
118              
119             # ethernet header constants
120              
121 1     1   5 use constant ETH_TYPE_UNK => '0000';
  1         24  
  1         52  
122 1     1   6 use constant ETH_TYPE_XNS_IDP => '0600';
  1         13  
  1         67  
123 1     1   6 use constant ETH_TYPE_IP => '0800';
  1         2  
  1         45  
124 1     1   5 use constant ETH_TYPE_X25L3 => '0805';
  1         1  
  1         56  
125 1     1   5 use constant ETH_TYPE_ARP => '0806';
  1         2  
  1         67  
126 1     1   7 use constant ETH_TYPE_VINES_IP => '0bad';
  1         1  
  1         49  
127 1     1   6 use constant ETH_TYPE_VINES_ECHO => '0baf';
  1         2  
  1         56  
128 1     1   6 use constant ETH_TYPE_TRAIN => '1984';
  1         1  
  1         46  
129 1     1   4 use constant ETH_TYPE_CGMP => '2001';
  1         11  
  1         48  
130 1     1   5 use constant ETH_TYPE_CENTRINO_PROMISC => '2452';
  1         2  
  1         86  
131 1     1   6 use constant ETH_TYPE_3C_NBP_DGRAM => '3c07';
  1         2  
  1         51  
132 1     1   5 use constant ETH_TYPE_EPL_V1 => '3e3f';
  1         2  
  1         58  
133 1     1   5 use constant ETH_TYPE_DEC => '6000';
  1         11  
  1         85  
134 1     1   7 use constant ETH_TYPE_DNA_DL => '6001';
  1         3  
  1         55  
135 1     1   5 use constant ETH_TYPE_DNA_RC => '6002';
  1         2  
  1         75  
136 1     1   7 use constant ETH_TYPE_DNA_RT => '6003';
  1         1  
  1         58  
137 1     1   6 use constant ETH_TYPE_LAT => '6004';
  1         1  
  1         46  
138 1     1   5 use constant ETH_TYPE_DEC_DIAG => '6005';
  1         2  
  1         54  
139 1     1   13 use constant ETH_TYPE_DEC_CUST => '6006';
  1         3  
  1         46  
140 1     1   5 use constant ETH_TYPE_DEC_SCA => '6007';
  1         2  
  1         55  
141 1     1   5 use constant ETH_TYPE_ETHBRIDGE => '6558';
  1         2  
  1         56  
142 1     1   6 use constant ETH_TYPE_RAW_FR => '6559';
  1         2  
  1         56  
143 1     1   6 use constant ETH_TYPE_RARP => '8035';
  1         1  
  1         55  
144 1     1   6 use constant ETH_TYPE_DEC_LB => '8038';
  1         1  
  1         55  
145 1     1   7 use constant ETH_TYPE_DEC_LAST => '8041';
  1         2  
  1         68  
146 1     1   6 use constant ETH_TYPE_APPLETALK => '809b';
  1         2  
  1         59  
147 1     1   6 use constant ETH_TYPE_SNA => '80d5';
  1         2  
  1         66  
148 1     1   6 use constant ETH_TYPE_AARP => '80f3';
  1         2  
  1         108  
149 1     1   7 use constant ETH_TYPE_VLAN => '8100';
  1         3  
  1         55  
150 1     1   7 use constant ETH_TYPE_IPX => '8137';
  1         1  
  1         65  
151 1     1   6 use constant ETH_TYPE_SNMP => '814c';
  1         1  
  1         74  
152 1     1   6 use constant ETH_TYPE_WCP => '80ff';
  1         9  
  1         50  
153 1     1   6 use constant ETH_TYPE_STP => '8181';
  1         1  
  1         64  
154 1     1   6 use constant ETH_TYPE_ISMP => '81fd';
  1         2  
  1         63  
155 1     1   5 use constant ETH_TYPE_ISMP_TBFLOOD => '81ff';
  1         2  
  1         57  
156 1     1   5 use constant ETH_TYPE_IPv6 => '86dd';
  1         2  
  1         64  
157 1     1   7 use constant ETH_TYPE_WLCCP => '872d';
  1         2  
  1         47  
158 1     1   5 use constant ETH_TYPE_MAC_CONTROL => '8808';
  1         2  
  1         42  
159 1     1   6 use constant ETH_TYPE_SLOW_PROTOCOLS => '8809';
  1         2  
  1         103  
160 1     1   7 use constant ETH_TYPE_PPP => '880b';
  1         2  
  1         62  
161 1     1   6 use constant ETH_TYPE_COBRANET => '8819';
  1         3  
  1         45  
162 1     1   6 use constant ETH_TYPE_MPLS => '8847';
  1         64  
  1         62  
163 1     1   7 use constant ETH_TYPE_MPLS_MULTI => '8848';
  1         2  
  1         59  
164 1     1   6 use constant ETH_TYPE_FOUNDRY => '885a';
  1         1  
  1         58  
165 1     1   6 use constant ETH_TYPE_PPPOED => '8863';
  1         2  
  1         64  
166 1     1   5 use constant ETH_TYPE_PPPOES => '8864';
  1         2  
  1         53  
167 1     1   7 use constant ETH_TYPE_INTEL_ANS => '886d';
  1         1  
  1         44  
168 1     1   5 use constant ETH_TYPE_MS_NLB_HEARTBEAT => '886f';
  1         2  
  1         54  
169 1     1   6 use constant ETH_TYPE_CDMA2000_A10_UBS => '8881';
  1         1  
  1         43  
170 1     1   5 use constant ETH_TYPE_EAPOL => '888e';
  1         2  
  1         56  
171 1     1   15 use constant ETH_TYPE_PROFINET => '8892';
  1         2  
  1         56  
172 1     1   6 use constant ETH_TYPE_HYPERSCSI => '889a';
  1         2  
  1         56  
173 1     1   5 use constant ETH_TYPE_CSM_ENCAPS => '889b';
  1         2  
  1         78  
174 1     1   6 use constant ETH_TYPE_TELKONET => '88a1';
  1         2  
  1         58  
175 1     1   6 use constant ETH_TYPE_AOE => '88a2';
  1         2  
  1         44  
176 1     1   5 use constant ETH_TYPE_EPL_V2 => '88ab';
  1         2  
  1         54  
177 1     1   89 use constant ETH_TYPE_BRDWALK => '88ae';
  1         4  
  1         63  
178 1     1   6 use constant ETH_TYPE_IEEE802_OUI_EXTENDED => '88b7';
  1         2  
  1         97  
179 1     1   7 use constant ETH_TYPE_IEC61850_GOOSE => '88b8';
  1         2  
  1         50  
180 1     1   5 use constant ETH_TYPE_IEC61850_GSE => '88b9';
  1         2  
  1         43  
181 1     1   5 use constant ETH_TYPE_IEC61850_SV => '88ba';
  1         2  
  1         80  
182 1     1   6 use constant ETH_TYPE_TIPC => '88ca';
  1         2  
  1         58  
183 1     1   6 use constant ETH_TYPE_RSN_PREAUTH => '88c7';
  1         2  
  1         51  
184 1     1   5 use constant ETH_TYPE_LLDP => '88cc';
  1         2  
  1         59  
185 1     1   5 use constant ETH_TYPE_3GPP2 => '88d2';
  1         2  
  1         62  
186 1     1   5 use constant ETH_TYPE_MRP => '88e3';
  1         2  
  1         47  
187 1     1   5 use constant ETH_TYPE_LOOP => '9000';
  1         18  
  1         65  
188 1     1   6 use constant ETH_TYPE_RTMAC => '9021';
  1         2  
  1         49  
189 1     1   5 use constant ETH_TYPE_RTCFG => '9022';
  1         1  
  1         71  
190 1     1   5 use constant ETH_TYPE_LLT => 'cafe';
  1         2  
  1         94  
191 1     1   8 use constant ETH_TYPE_FCFT => 'fcfc';
  1         2  
  1         14800  
192              
193              
194              
195             #############################################################################
196             sub decode {
197             #############################################################################
198              
199 0     0 1   my $sFlowDatagramPacked = shift;
200 0           my %sFlowDatagram = ();
201 0           my @sFlowSamples = ();
202 0           my @errors = ();
203 0           my $error = undef;
204 0           my $subProcessed = undef;
205              
206 0           my $offset = 0;
207              
208             ($sFlowDatagram{sFlowVersion},
209 0           $sFlowDatagram{AgentIpVersion}) =
210             unpack('NN', $sFlowDatagramPacked);
211              
212 0           $offset += (2 * 4);
213              
214             ($subProcessed, $error) =
215             &_decodeIpAddress(
216             \$offset,
217             \$sFlowDatagramPacked,
218             \%sFlowDatagram,
219             undef,
220             \@sFlowSamples,
221             $sFlowDatagram{AgentIpVersion},
222 0           'AgentIp',
223             1,
224             );
225              
226 0 0         unless ($subProcessed) {
227 0           push @errors, $error;
228 0           %sFlowDatagram = ();
229 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
230             }
231              
232              
233             ####### sFlow V4 #######
234              
235 0 0         if ($sFlowDatagram{sFlowVersion} <= SFLOWv4) {
    0          
236              
237             (undef,
238             $sFlowDatagram{datagramSequenceNumber},
239             $sFlowDatagram{agentUptime},
240 0           $sFlowDatagram{samplesInPacket}) =
241             unpack("a$offset N3", $sFlowDatagramPacked);
242              
243 0           $offset += (3 * 4);
244              
245             # boundcheck for $sFlowDatagram{samplesInPacket}
246             # $sFlowDatagram{samplesInPacket} * 4
247             # cannot be longer than the number of $sFlowDatagramPacked byte - $offset
248              
249 0 0         if (length($sFlowDatagramPacked) - $offset <
    0          
250             $sFlowDatagram{samplesInPacket} * 4) {
251              
252             # error $sFlowDatagram{samplesInPacket} too big
253 0           $error = "ERROR: [sFlow.pm] Datagram: Samples in packet count too big "
254             . "- rest of the datagram skipped";
255              
256 0           push @errors, $error;
257 0           pop @sFlowSamples;
258 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
259              
260             } elsif ($sFlowDatagram{samplesInPacket} < 0) {
261              
262             # error $sFlowDatagram{samplesInPacket} too small
263 0           $error = "ERROR: [sFlow.pm] Datagram: Samples in packet count too small "
264             . "- rest of the datagram skipped";
265              
266 0           push @errors, $error;
267 0           pop @sFlowSamples;
268 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
269              
270             } else {
271              
272             # parse samples
273 0           for my $samplesCount (0 .. $sFlowDatagram{samplesInPacket} - 1) {
274              
275 0           my %sFlowSample = ();
276 0           push @sFlowSamples, \%sFlowSample;
277              
278             (undef,
279 0           $sFlowSample{sampleType}) =
280             unpack("a$offset N", $sFlowDatagramPacked);
281              
282 0           $offset += 4;
283              
284              
285             # FLOWSAMPLE
286 0 0         if ($sFlowSample{sampleType} == FLOWSAMPLE_SFLOWv4) {
    0          
287              
288             (undef,
289 0           $sFlowSample{sampleSequenceNumber}) =
290             unpack("a$offset N", $sFlowDatagramPacked);
291              
292 0           $offset += 4;
293              
294 0           my $sourceId = undef;
295              
296             (undef,
297             $sourceId,
298             $sFlowSample{samplingRate},
299             $sFlowSample{samplePool},
300             $sFlowSample{drops},
301             $sFlowSample{inputInterface},
302             $sFlowSample{outputInterface},
303 0           $sFlowSample{packetDataType}) =
304             unpack("a$offset N7", $sFlowDatagramPacked);
305              
306 0           $offset += 28;
307              
308 0           $sFlowSample{sourceIdType} = $sourceId >> 24;
309 0           $sFlowSample{sourceIdIndex} = $sourceId & 2 ** 24 - 1;
310              
311             # packet data type: header
312 0 0         if ($sFlowSample{packetDataType} == HEADERDATA_SFLOWv4) {
    0          
    0          
313              
314 0           ($subProcessed, $error) =
315             &_decodeHeaderData(
316             \$offset,
317             \$sFlowDatagramPacked,
318             \%sFlowDatagram,
319             \%sFlowSample,
320             \@sFlowSamples,
321             );
322              
323 0 0         unless ($subProcessed) {
324 0           push @errors, $error;
325             }
326             }
327              
328             # packet data type: IPv4
329             elsif ($sFlowSample{packetDataType} == IPv4DATA_SFLOWv4) {
330 0           &_decodeIPv4Data(\$offset, \$sFlowDatagramPacked, \%sFlowSample);
331             }
332              
333             # packet data type: IPv6
334             elsif ($sFlowSample{packetDataType} == IPv6DATA_SFLOWv4){
335 0           &_decodeIPv6Data(\$offset, \$sFlowDatagramPacked, \%sFlowSample);
336             }
337              
338             else {
339              
340 0           $error = "ERROR: [sFlow.pm] AgentIP: $sFlowDatagram{AgentIp}, "
341             . "Datagram: $sFlowDatagram{datagramSequenceNumber} - Unknown packet data type: "
342             . "$sFlowSample{packetDataType} - rest of the datagram skipped";
343              
344 0           push @errors, $error;
345 0           pop @sFlowSamples;
346 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
347             }
348              
349             (undef,
350 0           $sFlowSample{extendedDataInSample}) =
351             unpack("a$offset N", $sFlowDatagramPacked);
352              
353 0           $offset += 4;
354              
355             # boundcheck for $sFlowSample{extendedDataInSample}
356             # $sFlowSample{extendedDataInSample} * 4
357             # cannot be longer than the number of $sFlowDatagramPacked byte - $offset
358              
359 0 0         if (length($sFlowDatagramPacked) - $offset <
    0          
360             $sFlowSample{extendedDataInSample} * 4) {
361              
362             # error $sFlowSample{extendedDataInSample} too big
363 0           $error = "ERROR: [sFlow.pm] Datagram: Extended data in sample count too big "
364             . "- rest of the datagram skipped";
365              
366 0           push @errors, $error;
367 0           pop @sFlowSamples;
368 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
369              
370             } elsif ($sFlowSample{extendedDataInSample} < 0) {
371              
372             # error $sFlowSample{extendedDataInSample} too small
373 0           $error = "ERROR: [sFlow.pm] Datagram: Extended data in sample count too small "
374             . "- rest of the datagram skipped";
375              
376 0           push @errors, $error;
377 0           pop @sFlowSamples;
378 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
379              
380             } else {
381              
382 0           for my $extendedDataCount (0 .. $sFlowSample{extendedDataInSample} - 1){
383              
384 0           my $extendedDataType = undef;
385              
386 0           (undef, $extendedDataType) = unpack("a$offset N", $sFlowDatagramPacked);
387 0           $offset += 4;
388              
389             # extended data: switch
390 0 0         if ($extendedDataType == SWITCHDATA_SFLOWv4) {
    0          
    0          
    0          
    0          
391 0           &_decodeSwitchData(\$offset, \$sFlowDatagramPacked, \%sFlowSample);
392             }
393              
394             # extended data: router
395             elsif ($extendedDataType == ROUTERDATA_SFLOWv4) {
396              
397 0           ($subProcessed, $error) =
398             &_decodeRouterData(
399             \$offset,
400             \$sFlowDatagramPacked,
401             \%sFlowDatagram,
402             \%sFlowSample,
403             \@sFlowSamples,
404             );
405              
406 0 0         unless ($subProcessed) {
407 0           push @errors, $error;
408 0 0         pop @sFlowSamples unless $error =~ /rest of the datagram skipped/;
409 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
410             }
411              
412             }
413              
414             # extended data: gateway
415             elsif ($extendedDataType == GATEWAYDATA_SFLOWv4) {
416              
417 0           ($subProcessed, $error) =
418             &_decodeGatewayData(
419             \$offset,
420             \$sFlowDatagramPacked,
421             \%sFlowDatagram,
422             \%sFlowSample,
423             \@sFlowSamples,
424             );
425              
426 0 0         unless ($subProcessed) {
427 0           push @errors, $error;
428 0 0         pop @sFlowSamples unless $error =~ /rest of the datagram skipped/;
429 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
430             }
431              
432             }
433              
434             # extended data: user
435             elsif ($extendedDataType == USERDATA_SFLOWv4) {
436              
437 0           ($subProcessed, $error) =
438             &_decodeUserData(
439             \$offset,
440             \$sFlowDatagramPacked,
441             \%sFlowDatagram,
442             \%sFlowSample,
443             );
444              
445 0 0         unless ($subProcessed) {
446 0           push @errors, $error;
447 0 0         pop @sFlowSamples unless $error =~ /rest of the datagram skipped/;
448 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
449             }
450              
451             }
452              
453             # extended data: url
454             # added in v.3.
455             elsif ($extendedDataType == URLDATA_SFLOWv4) {
456              
457 0           ($subProcessed, $error) =
458             &_decodeUrlData(
459             \$offset,
460             \$sFlowDatagramPacked,
461             \%sFlowDatagram,
462             \%sFlowSample,
463             );
464              
465 0 0         unless ($subProcessed) {
466 0           push @errors, $error;
467 0 0         pop @sFlowSamples unless $error =~ /rest of the datagram skipped/;
468 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
469             }
470              
471             }
472              
473             else {
474              
475 0           $error = "ERROR: [sFlow.pm] AgentIP: $sFlowDatagram{AgentIp}, "
476             . "Datagram: $sFlowDatagram{datagramSequenceNumber} - Unknown extended data type: "
477             . "$extendedDataType - rest of the datagram skipped";
478              
479 0           push @errors, $error;
480 0           pop @sFlowSamples;
481 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
482             }
483              
484             }
485              
486             }
487              
488             }
489              
490             # COUNTERSAMPLE
491             elsif ($sFlowSample{sampleType} == COUNTERSAMPLE_SFLOWv4) {
492              
493 0           my $sourceId = undef;
494              
495             (undef,
496             $sFlowSample{sampleSequenceNumber},
497             $sourceId,
498             $sFlowSample{counterSamplingInterval},
499 0           $sFlowSample{countersVersion}) =
500             unpack("a$offset N4", $sFlowDatagramPacked);
501              
502 0           $offset += 16;
503              
504 0           $sFlowSample{sourceIdType} = $sourceId >> 24;
505 0           $sFlowSample{sourceIdIndex} = $sourceId & 2 ** 24 - 1;
506              
507             # counterstype: generic
508 0 0         if ($sFlowSample{countersVersion} == GENERICCOUNTER_SFLOWv4) {
    0          
    0          
    0          
    0          
    0          
    0          
509 0           &_decodeCounterGeneric(\$offset, \$sFlowDatagramPacked, \%sFlowSample);
510             }
511              
512             # counterstype: ethernet
513             elsif ($sFlowSample{countersVersion} == ETHERNETCOUNTER_SFLOWv4) {
514 0           &_decodeCounterGeneric(\$offset, \$sFlowDatagramPacked, \%sFlowSample);
515 0           &_decodeCounterEthernet(\$offset, \$sFlowDatagramPacked, \%sFlowSample);
516             }
517              
518             # counterstype: tokenring
519             elsif ($sFlowSample{countersVersion} == TOKENRINGCOUNTER_SFLOWv4) {
520 0           &_decodeCounterGeneric(\$offset, \$sFlowDatagramPacked, \%sFlowSample);
521 0           &_decodeCounterTokenring(\$offset, \$sFlowDatagramPacked, \%sFlowSample);
522             }
523              
524             # counterstype: fddi
525             elsif ($sFlowSample{countersVersion} == FDDICOUNTER_SFLOWv4) {
526 0           &_decodeCounterGeneric(\$offset, \$sFlowDatagramPacked, \%sFlowSample);
527             }
528              
529             # counterstype: vg
530             elsif ($sFlowSample{countersVersion} == VGCOUNTER_SFLOWv4) {
531 0           &_decodeCounterGeneric(\$offset, \$sFlowDatagramPacked, \%sFlowSample);
532 0           &_decodeCounterVg(\$offset, \$sFlowDatagramPacked, \%sFlowSample);
533             }
534              
535             # counterstype: wan
536             elsif ($sFlowSample{countersVersion} == WANCOUNTER_SFLOWv4) {
537 0           &_decodeCounterGeneric(\$offset, \$sFlowDatagramPacked, \%sFlowSample);
538             }
539              
540             # counterstype: vlan
541             elsif ($sFlowSample{countersVersion} == VLANCOUNTER_SFLOWv4) {
542 0           &_decodeCounterVlan(\$offset, \$sFlowDatagramPacked, \%sFlowSample);
543             }
544              
545             else {
546              
547 0           $error = "ERROR: [sFlow.pm] AgentIP: $sFlowDatagram{AgentIp}, "
548             . "Datagram: $sFlowDatagram{datagramSequenceNumber} - Unknown counters type: "
549             . "$sFlowSample{countersVersion} - rest of the datagram skipped";
550              
551 0           push @errors, $error;
552 0           pop @sFlowSamples;
553 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
554             }
555              
556             }
557              
558             else {
559              
560 0           $error = "ERROR: [sFlow.pm] AgentIP: $sFlowDatagram{AgentIp}, "
561             . "Datagram: $sFlowDatagram{datagramSequenceNumber} - Unknown sample type: "
562             . "$sFlowSample{sampleType} - rest of the datagram skipped";
563              
564 0           push @errors, $error;
565 0           pop @sFlowSamples;
566 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
567             }
568              
569             }
570              
571             }
572              
573             }
574              
575             ####### sFlow V5 #######
576              
577             elsif ($sFlowDatagram{sFlowVersion} >= SFLOWv5) {
578              
579             # v5 also provides a sub agent id
580             (undef,
581 0           $sFlowDatagram{subAgentId}) =
582             unpack("a$offset N", $sFlowDatagramPacked);
583              
584 0           $offset += 4;
585              
586             (undef,
587             $sFlowDatagram{datagramSequenceNumber},
588             $sFlowDatagram{agentUptime},
589 0           $sFlowDatagram{samplesInPacket}) =
590             unpack("a$offset N3", $sFlowDatagramPacked);
591              
592 0           $offset += 12;
593              
594             # boundcheck for $sFlowDatagram{samplesInPacket}
595             # $sFlowDatagram{samplesInPacket} * 4
596             # cannot be longer than the number of $sFlowDatagramPacked byte - $offset
597              
598 0 0         if (length($sFlowDatagramPacked) - $offset <
    0          
599             $sFlowDatagram{samplesInPacket} * 4) {
600              
601             # error $sFlowDatagram{samplesInPacket} too big
602 0           $error = "ERROR: [sFlow.pm] Datagram: Samples in packet count too big "
603             . "- rest of the datagram skipped";
604              
605 0           push @errors, $error;
606 0           pop @sFlowSamples;
607 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
608              
609             } elsif ($sFlowDatagram{samplesInPacket} < 0) {
610              
611             # error $sFlowDatagram{samplesInPacket} too small
612 0           $error = "ERROR: [sFlow.pm] Datagram: Samples in packet count too small "
613             . "- rest of the datagram skipped";
614              
615 0           push @errors, $error;
616 0           pop @sFlowSamples;
617 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
618              
619             } else {
620              
621             # parse samples
622 0           for my $samplesCount (0 .. $sFlowDatagram{samplesInPacket} - 1) {
623              
624 0           my %sFlowSample = ();
625 0           push @sFlowSamples, \%sFlowSample;
626              
627 0           my $sampleType = undef;
628              
629             (undef,
630             $sampleType,
631 0           $sFlowSample{sampleLength}) =
632             unpack("a$offset NN", $sFlowDatagramPacked);
633              
634 0           $offset += 8;
635              
636 0           $sFlowSample{sampleTypeEnterprise} = $sampleType >> 12;
637 0           $sFlowSample{sampleTypeFormat} = $sampleType & 2 ** 12 - 1;
638              
639 0           my $sourceId = undef;
640              
641 0 0 0       if ($sFlowSample{sampleTypeEnterprise} == 0
    0 0        
    0 0        
    0 0        
    0 0        
642             and $sFlowSample{sampleTypeFormat} == FLOWSAMPLE_SFLOWv5) {
643              
644             (undef,
645             $sFlowSample{sampleSequenceNumber},
646             $sourceId,
647             $sFlowSample{samplingRate},
648             $sFlowSample{samplePool},
649             $sFlowSample{drops},
650             $sFlowSample{inputInterface},
651             $sFlowSample{outputInterface},
652 0           $sFlowSample{flowRecordsCount}) =
653             unpack("a$offset N8", $sFlowDatagramPacked);
654              
655 0           $offset += 32;
656              
657 0           $sFlowSample{sourceIdType} = $sourceId >> 24;
658 0           $sFlowSample{sourceIdIndex} = $sourceId & 2 ** 24 - 1;
659              
660             # boundcheck for $sFlowSample{flowRecordsCount}
661             # $sFlowSample{flowRecordsCount} * 4
662             # cannot be longer than the number of $sFlowDatagramPacked byte - $offset
663              
664 0 0         if (length($sFlowDatagramPacked) - $offset <
    0          
665             $sFlowSample{flowRecordsCount} * 4) {
666              
667             # error $sFlowSample{flowRecordsCount} too big
668 0           $error = "ERROR: [sFlow.pm] Datagram: Flow records count too big "
669             . "for this packet length - rest of the datagram skipped";
670              
671 0           push @errors, $error;
672 0           pop @sFlowSamples;
673 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
674              
675             } elsif ($sFlowSample{flowRecordsCount} < 0) {
676              
677             # error $sFlowSample{flowRecordsCount} too small
678 0           $error = "ERROR: [sFlow.pm] Datagram: Flow records count too small "
679             . "- rest of the datagram skipped";
680              
681 0           push @errors, $error;
682 0           pop @sFlowSamples;
683 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
684              
685             } else {
686              
687 0           for my $flowRecords (0 .. $sFlowSample{flowRecordsCount} - 1) {
688              
689 0           ($subProcessed, $error) =
690             &_decodeFlowRecord(
691             \$offset,
692             \$sFlowDatagramPacked,
693             \%sFlowDatagram,
694             \%sFlowSample,
695             \@sFlowSamples,
696             \@errors,
697             );
698              
699 0 0         unless ($subProcessed) {
700 0           push @errors, $error;
701 0 0         pop @sFlowSamples unless $error =~ /rest of the datagram skipped/;
702 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
703             }
704              
705             }
706              
707             }
708              
709             }
710              
711             elsif ($sFlowSample{sampleTypeEnterprise} == 0
712             and $sFlowSample{sampleTypeFormat} == COUNTERSAMPLE_SFLOWv5) {
713              
714             (undef,
715             $sFlowSample{sampleSequenceNumber},
716             $sourceId,
717 0           $sFlowSample{counterRecordsCount}) =
718             unpack("a$offset N3", $sFlowDatagramPacked);
719              
720 0           $offset += 12;
721              
722 0           $sFlowSample{sourceIdType} = $sourceId >> 24;
723 0           $sFlowSample{sourceIdIndex} = $sourceId & 2 ** 24 - 1;
724              
725             # boundcheck for $sFlowSample{counterRecordsCount}
726             # $sFlowSample{counterRecordsCount} * 4
727             # cannot be longer than the number of $sFlowDatagramPacked byte - $offset
728              
729 0 0         if (length($sFlowDatagramPacked) - $offset <
    0          
730             $sFlowSample{counterRecordsCount} * 4) {
731              
732             # error $sFlowSample{counterRecordsCount} too big
733 0           $error = "ERROR: [sFlow.pm] Datagram: Counter records count too big "
734             . "- rest of the datagram skipped";
735              
736 0           push @errors, $error;
737 0           pop @sFlowSamples;
738 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
739              
740             } elsif ($sFlowSample{counterRecordsCount} < 0) {
741              
742             # error $sFlowSample{counterRecordsCount} too small
743 0           $error = "ERROR: [sFlow.pm] Datagram: Counter records count too small "
744             . "- rest of the datagram skipped";
745              
746 0           push @errors, $error;
747 0           pop @sFlowSamples;
748 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
749              
750             } else {
751              
752 0           for my $counterRecords (0 .. $sFlowSample{counterRecordsCount} - 1) {
753              
754 0           ($subProcessed, $error) =
755             &_decodeCounterRecord(
756             \$offset,
757             \$sFlowDatagramPacked,
758             \%sFlowDatagram,
759             \%sFlowSample,
760             \@sFlowSamples,
761             );
762              
763 0 0         unless ($subProcessed) {
764 0           push @errors, $error;
765 0 0         pop @sFlowSamples unless $error =~ /rest of the datagram skipped/;
766 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
767             }
768              
769             }
770              
771             }
772              
773             }
774              
775             elsif ($sFlowSample{sampleTypeEnterprise} == 0
776             and $sFlowSample{sampleTypeFormat} == EXPANDEDFLOWSAMPLE_SFLOWv5) {
777              
778             (undef,
779             $sFlowSample{sampleSequenceNumber},
780             $sFlowSample{sourceIdType},
781             $sFlowSample{sourceIdIndex},
782             $sFlowSample{samplingRate},
783             $sFlowSample{samplePool},
784             $sFlowSample{drops},
785             $sFlowSample{inputInterfaceFormat},
786             $sFlowSample{inputInterfaceValue},
787             $sFlowSample{outputInterfaceFormat},
788             $sFlowSample{outputInterfaceValue},
789 0           $sFlowSample{flowRecordsCount}) =
790             unpack("a$offset N11", $sFlowDatagramPacked);
791              
792 0           $offset += 44;
793              
794             # boundcheck for $sFlowSample{flowRecordsCount}
795             # $sFlowSample{flowRecordsCount} * 4
796             # cannot be longer than the number of $sFlowDatagramPacked byte - $offset
797              
798 0 0         if (length($sFlowDatagramPacked) - $offset <
    0          
799             $sFlowSample{flowRecordsCount} * 4) {
800              
801             # error $sFlowSample{flowRecordsCount} too big
802 0           $error = "ERROR: [sFlow.pm] Datagram: Flow records count too big "
803             . "for this packet length - rest of the datagram skipped";
804              
805 0           push @errors, $error;
806 0           pop @sFlowSamples;
807 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
808              
809             } elsif ($sFlowSample{flowRecordsCount} < 0) {
810              
811             # error $sFlowSample{flowRecordsCount} too small
812 0           $error = "ERROR: [sFlow.pm] Datagram: Flow records count too small"
813             . "- rest of the datagram skipped";
814              
815 0           push @errors, $error;
816 0           pop @sFlowSamples;
817 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
818              
819             } else {
820              
821 0           for my $flowRecords (0 .. $sFlowSample{flowRecordsCount} - 1) {
822              
823 0           ($subProcessed, $error) =
824             &_decodeFlowRecord(
825             \$offset,
826             \$sFlowDatagramPacked,
827             \%sFlowDatagram,
828             \%sFlowSample,
829             \@sFlowSamples,
830             \@errors,
831             );
832              
833 0 0         unless ($subProcessed) {
834 0           push @errors, $error;
835 0 0         pop @sFlowSamples unless $error =~ /rest of the datagram skipped/;
836 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
837             }
838              
839             }
840              
841             }
842              
843             }
844              
845             elsif ($sFlowSample{sampleTypeEnterprise} == 0
846             and $sFlowSample{sampleTypeFormat} == EXPANDEDCOUNTERSAMPLE_SFLOWv5) {
847              
848             (undef,
849             $sFlowSample{sampleSequenceNumber},
850             $sFlowSample{sourceIdType},
851             $sFlowSample{sourceIdIndex},
852 0           $sFlowSample{counterRecordsCount}) =
853             unpack("a$offset N4", $sFlowDatagramPacked);
854              
855 0           $offset += 16;
856              
857             # boundcheck for $sFlowSample{counterRecordsCount}
858             # $sFlowSample{counterRecordsCount} * 4
859             # cannot be longer than the number of $sFlowDatagramPacked byte - $offset
860              
861 0 0         if (length($sFlowDatagramPacked) - $offset <
    0          
862             $sFlowSample{counterRecordsCount} * 4) {
863              
864             # error $sFlowSample{counterRecordsCount} too big
865 0           $error = "ERROR: [sFlow.pm] Datagram: Counter records count too big "
866             . "- rest of the datagram skipped";
867              
868 0           push @errors, $error;
869 0           pop @sFlowSamples;
870 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
871              
872             } elsif ($sFlowSample{counterRecordsCount} < 0) {
873              
874             # error $sFlowSample{counterRecordsCount} too small
875 0           $error = "ERROR: [sFlow.pm] Datagram: Counter records count too small "
876             . "- rest of the datagram skipped";
877              
878 0           push @errors, $error;
879 0           pop @sFlowSamples;
880 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
881              
882             } else {
883              
884 0           for my $counterRecords (0 .. $sFlowSample{counterRecordsCount} - 1) {
885              
886 0           ($subProcessed, $error) =
887             &_decodeCounterRecord(
888             \$offset,
889             \$sFlowDatagramPacked,
890             \%sFlowDatagram,
891             \%sFlowSample,
892             \@sFlowSamples,
893             );
894              
895 0 0         unless ($subProcessed) {
896 0           push @errors, $error;
897 0 0         pop @sFlowSamples unless $error =~ /rest of the datagram skipped/;
898 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
899             }
900              
901             }
902              
903             }
904              
905             }
906              
907             elsif ($sFlowSample{sampleTypeEnterprise} == FOUNDRY_ACL_SFLOWv5
908             and $sFlowSample{sampleTypeFormat} == FLOWSAMPLE_SFLOWv5) {
909              
910             (undef,
911             $sFlowSample{FoundryFlags},
912 0           $sFlowSample{FoundryGroupID}) =
913             unpack("a$offset N2", $sFlowDatagramPacked);
914              
915 0           $offset += 8;
916              
917 0           $sFlowDatagram{samplesInPacket}++;
918 0           next;
919              
920             }
921              
922             else {
923              
924 0           $error = "ERROR: [sFlow.pm] AgentIP: $sFlowDatagram{AgentIp} Datagram: "
925             . "$sFlowDatagram{datagramSequenceNumber} - Unknown sample enterprise: "
926             . "$sFlowSample{sampleTypeEnterprise} or format: $sFlowSample{sampleTypeFormat} "
927             . "- rest of the datagram skipped";
928              
929 0           push @errors, $error;
930 0           pop @sFlowSamples;
931 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
932             }
933              
934             }
935              
936             }
937              
938             }
939              
940             else {
941              
942 0           $error = "ERROR: [sFlow.pm] AgentIP: $sFlowDatagram{AgentIp}, Datagram: "
943             . "$sFlowDatagram{datagramSequenceNumber} - Unknown sFlow Version: "
944             . "$sFlowDatagram{sFlowVersion}";
945              
946 0           push @errors, $error;
947 0           %sFlowDatagram = ();
948 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
949             }
950              
951 0           return (\%sFlowDatagram, \@sFlowSamples, \@errors);
952              
953             }
954              
955              
956             #### END sub decode() ######################################################
957              
958              
959              
960             #############################################################################
961             sub _bin2ip {
962             #############################################################################
963              
964             # _bin2ip is a copy of "to_dotquad" from NetPacket::IP.pm
965             # Copyright (c) 2001 Tim Potter.
966             # Copyright (c) 2001 Stephanie Wehner.
967              
968 0     0     my($net) = @_ ;
969 0           my($na, $nb, $nc, $nd);
970              
971 0           $na = $net >> 24 & 255;
972 0           $nb = $net >> 16 & 255;
973 0           $nc = $net >> 8 & 255;
974 0           $nd = $net & 255;
975              
976 0           return ("$na.$nb.$nc.$nd");
977             }
978              
979              
980             #############################################################################
981             sub _decodeIpAddress {
982             #############################################################################
983              
984 0     0     my $offsetref = shift;
985 0           my $sFlowDatagramPackedRef = shift;
986 0           my $sFlowDatagram = shift;
987 0           my $sFlowSample = shift;
988 0           my $sFlowSamples = shift;
989 0           my $IpVersion = shift;
990 0           my $keyName = shift;
991 0           my $DatagramOrSampleData = shift;
992              
993 0           my $error = undef;
994 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
995 0           my $offset = $$offsetref;
996              
997 0 0         if (defined($DatagramOrSampleData)) {
998              
999 0 0         if ($IpVersion == IPv4) {
    0          
1000              
1001             (undef,
1002 0           $sFlowDatagram->{$keyName}) =
1003             unpack("a$offset N", $sFlowDatagramPacked);
1004              
1005 0           $sFlowDatagram->{$keyName} = &_bin2ip($sFlowDatagram->{$keyName});
1006 0           $offset += 4;
1007             }
1008              
1009             elsif ($IpVersion == IPv6) {
1010              
1011 0           $sFlowDatagram->{$keyName} =
1012             join(':', unpack("x$offset H4H4H4H4H4H4H4H4", $sFlowDatagramPacked));
1013              
1014 0           $offset += 16;
1015             }
1016             }
1017              
1018             else {
1019              
1020 0 0         if ($IpVersion == IPv4) {
    0          
1021              
1022             (undef,
1023 0           $sFlowSample->{$keyName}) =
1024             unpack("a$offset N", $sFlowDatagramPacked);
1025              
1026 0           $sFlowSample->{$keyName} = &_bin2ip($sFlowSample->{$keyName});
1027 0           $offset += 4;
1028             }
1029              
1030             elsif ($IpVersion == IPv6) {
1031              
1032 0           $sFlowSample->{$keyName} =
1033             join(':', unpack("x$offset H4H4H4H4H4H4H4H4", $sFlowDatagramPacked));
1034              
1035 0           $offset += 16;
1036             }
1037             }
1038              
1039 0 0 0       if ($IpVersion != IPv4 and $IpVersion != IPv6) {
1040              
1041 0 0         if (defined($DatagramOrSampleData)) {
1042              
1043             # unknown ip version added in v5
1044 0 0         if ($IpVersion == UNKNOWNIPVERSION) {
1045              
1046 0           $error = "ERROR: [sFlow.pm] AgentIP: Unknown agent ip version: "
1047             . "$IpVersion - rest of the datagram skipped";
1048              
1049 0           return (undef, $error);
1050             }
1051              
1052             else {
1053              
1054 0           $error = "ERROR: [sFlow.pm] AgentIP: Unknown agent ip version: "
1055             . "$IpVersion - rest of the datagram skipped";
1056              
1057 0           return (undef, $error);
1058             }
1059              
1060             }
1061              
1062             else {
1063              
1064             # unknown ip version added in v5
1065 0 0         if ($IpVersion == UNKNOWNIPVERSION) {
1066              
1067 0           $error = "ERROR: [sFlow.pm] AgentIP: $sFlowDatagram->{AgentIp}, "
1068             . "Datagram: $sFlowDatagram->{datagramSequenceNumber}, Sample: "
1069             . "$sFlowSample->{sampleSequenceNumber} - Unknown ip version: "
1070             . "$IpVersion - rest of the datagram skipped";
1071              
1072 0           return (undef, $error);
1073             }
1074              
1075             else {
1076 0           $error = "ERROR: [sFlow.pm] AgentIP: $sFlowDatagram->{AgentIp}, "
1077             . "Datagram: $sFlowDatagram->{datagramSequenceNumber}, Sample: "
1078             . "$sFlowSample->{sampleSequenceNumber} - Unknown ip version: "
1079             . "$IpVersion - rest of the datagram skipped";
1080              
1081 0           return (undef, $error);
1082             }
1083              
1084             }
1085              
1086             }
1087              
1088 0           $$offsetref = $offset;
1089 0           return (1, undef);
1090             }
1091              
1092              
1093             #############################################################################
1094             sub _decodeFlowRecord {
1095             #############################################################################
1096              
1097 0     0     my $offsetref = shift;
1098 0           my $sFlowDatagramPackedRef = shift;
1099 0           my $sFlowDatagram = shift;
1100 0           my $sFlowSample = shift;
1101 0           my $sFlowSamples = shift;
1102 0           my $errors = shift;
1103              
1104 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
1105 0           my $offset = $$offsetref;
1106 0           my $flowType = undef;
1107 0           my $flowDataLength = undef;
1108 0           my $error = undef;
1109 0           my $subProcessed = undef;
1110              
1111             (undef,
1112 0           $flowType,
1113             $flowDataLength) =
1114             unpack("a$offset NN", $sFlowDatagramPacked);
1115              
1116 0           $offset += 8;
1117              
1118 0           my $flowTypeEnterprise = $flowType >> 12;
1119 0           my $flowTypeFormat = $flowType & 2 ** 12 - 1;
1120              
1121 0 0         if ($flowTypeEnterprise == 0) {
1122              
1123 0 0         if ($flowTypeFormat == HEADERDATA_SFLOWv5) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1124              
1125 0           ($subProcessed, $error) =
1126             &_decodeHeaderData(
1127             \$offset,
1128             $sFlowDatagramPackedRef,
1129             $sFlowDatagram,
1130             $sFlowSample,
1131             $sFlowSamples,
1132             );
1133              
1134 0 0         unless ($subProcessed) {
1135 0           push @{$errors}, $error;
  0            
1136             }
1137              
1138             }
1139              
1140             elsif ($flowTypeFormat == SWITCHDATA_SFLOWv5) {
1141 0           &_decodeSwitchData(\$offset, $sFlowDatagramPackedRef, $sFlowSample);
1142             }
1143              
1144             elsif ($flowTypeFormat == ETHERNETFRAMEDATA_SFLOWv5) {
1145 0           &_decodeEthernetFrameData(\$offset, $sFlowDatagramPackedRef, $sFlowSample);
1146             }
1147              
1148             elsif ($flowTypeFormat == IPv4DATA_SFLOWv5) {
1149 0           &_decodeIPv4Data(\$offset, $sFlowDatagramPackedRef, $sFlowSample);
1150             }
1151              
1152             elsif ($flowTypeFormat == IPv6DATA_SFLOWv5) {
1153 0           &_decodeIPv6Data(\$offset, $sFlowDatagramPackedRef, $sFlowSample);
1154             }
1155              
1156             elsif ($flowTypeFormat == ROUTERDATA_SFLOWv5) {
1157              
1158 0           ($subProcessed, $error) =
1159             &_decodeRouterData(
1160             \$offset,
1161             $sFlowDatagramPackedRef,
1162             $sFlowDatagram,
1163             $sFlowSample,
1164             $sFlowSamples,
1165             );
1166              
1167 0 0         unless ($subProcessed) {
1168 0           return (undef, $error);
1169             }
1170              
1171             }
1172              
1173             elsif ($flowTypeFormat == GATEWAYDATA_SFLOWv5) {
1174              
1175 0           ($subProcessed, $error) =
1176             &_decodeGatewayData(
1177             \$offset,
1178             $sFlowDatagramPackedRef,
1179             $sFlowDatagram,
1180             $sFlowSample,
1181             $sFlowSamples,
1182             );
1183              
1184 0 0         unless ($subProcessed) {
1185 0           return (undef, $error);
1186             }
1187              
1188             }
1189              
1190             elsif ($flowTypeFormat == USERDATA_SFLOWv5) {
1191              
1192 0           ($subProcessed, $error) =
1193             &_decodeUserData(
1194             \$offset,
1195             $sFlowDatagramPackedRef,
1196             $sFlowDatagram,
1197             $sFlowSample
1198             );
1199              
1200 0 0         unless ($subProcessed) {
1201 0           return (undef, $error);
1202             }
1203              
1204             }
1205              
1206             elsif ($flowTypeFormat == URLDATA_SFLOWv5) {
1207              
1208 0           ($subProcessed, $error) =
1209             &_decodeUrlData(
1210             \$offset,
1211             $sFlowDatagramPackedRef,
1212             $sFlowDatagram,
1213             $sFlowSample
1214             );
1215              
1216 0 0         unless ($subProcessed) {
1217 0           return (undef, $error);
1218             }
1219              
1220             }
1221              
1222             elsif ($flowTypeFormat == MPLSDATA_SFLOWv5) {
1223              
1224 0           ($subProcessed, $error) =
1225             &_decodeMplsData(
1226             \$offset,
1227             $sFlowDatagramPackedRef,
1228             $sFlowDatagram,
1229             $sFlowSample,
1230             $sFlowSamples,
1231             );
1232              
1233 0 0         unless ($subProcessed) {
1234 0           return (undef, $error);
1235             }
1236              
1237             }
1238              
1239             elsif ($flowTypeFormat == NATDATA_SFLOWv5) {
1240              
1241 0           ($subProcessed, $error) =
1242             &_decodeNatData(
1243             \$offset,
1244             $sFlowDatagramPackedRef,
1245             $sFlowDatagram,
1246             $sFlowSample,
1247             $sFlowSamples,
1248             );
1249              
1250 0 0         unless ($subProcessed) {
1251 0           return (undef, $error);
1252             }
1253              
1254             }
1255              
1256             elsif ($flowTypeFormat == MPLSTUNNEL_SFLOWv5) {
1257              
1258 0           ($subProcessed, $error) =
1259             &_decodeMplsTunnel(
1260             \$offset,
1261             $sFlowDatagramPackedRef,
1262             $sFlowSample
1263             );
1264              
1265 0 0         unless ($subProcessed) {
1266 0           return (undef, $error);
1267             }
1268              
1269             }
1270              
1271             elsif ($flowTypeFormat == MPLSVC_SFLOWv5) {
1272              
1273 0           ($subProcessed, $error) =
1274             &_decodeMplsVc(
1275             \$offset,
1276             $sFlowDatagramPackedRef,
1277             $sFlowSample
1278             );
1279              
1280 0 0         unless ($subProcessed) {
1281 0           return (undef, $error);
1282             }
1283              
1284             }
1285              
1286             elsif ($flowTypeFormat == MPLSFEC_SFLOWv5) {
1287              
1288 0           ($subProcessed, $error) =
1289             &_decodeMplsFec(
1290             \$offset,
1291             $sFlowDatagramPackedRef,
1292             $sFlowSample
1293             );
1294              
1295 0 0         unless ($subProcessed) {
1296 0           return (undef, $error);
1297             }
1298              
1299             }
1300              
1301             elsif ($flowTypeFormat == MPLSLVPFEC_SFLOWv5) {
1302 0           &_decodeMplsLpvFec(\$offset, $sFlowDatagramPackedRef, $sFlowSample);
1303             }
1304              
1305             elsif ($flowTypeFormat == VLANTUNNEL_SFLOWv5) {
1306              
1307 0           ($subProcessed, $error) =
1308             &_decodeVlanTunnel(
1309             \$offset,
1310             $sFlowDatagramPackedRef,
1311             $sFlowSample
1312             );
1313              
1314 0 0         unless ($subProcessed) {
1315 0           return (undef, $error);
1316             }
1317              
1318             }
1319              
1320             else {
1321              
1322 0           $error = "ERROR: [sFlow.pm] AgentIP: $sFlowDatagram->{AgentIp}, "
1323             . "Datagram: $sFlowDatagram->{datagramSequenceNumber}, Sample: "
1324             . "$sFlowSample->{sampleSequenceNumber} - Unknown Flowdata format: "
1325             . "$flowTypeFormat - rest of the datagram skipped";
1326              
1327 0           return (undef, $error);
1328             }
1329              
1330             }
1331              
1332             else {
1333              
1334 0           $error = "ERROR: [sFlow.pm] AgentIP: $sFlowDatagram->{AgentIp}, "
1335             . "Datagram: $sFlowDatagram->{datagramSequenceNumber} - Unknown Flowdata enterprise: "
1336             . "$flowTypeEnterprise - rest of the datagram skipped";
1337              
1338 0           return (undef, $error);
1339             }
1340              
1341 0           $$offsetref = $offset;
1342 0           return (1,undef);
1343             }
1344              
1345              
1346             #############################################################################
1347             sub _decodeCounterRecord {
1348             #############################################################################
1349              
1350 0     0     my $offsetref = shift;
1351 0           my $sFlowDatagramPackedRef = shift;
1352 0           my $sFlowDatagram = shift;
1353 0           my $sFlowSample = shift;
1354 0           my $sFlowSamples = shift;
1355              
1356 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
1357 0           my $offset = $$offsetref;
1358 0           my $counterType = undef;
1359 0           my $counterDataLength = undef;
1360 0           my $error = undef;
1361              
1362             (undef,
1363             $counterType,
1364 0           $sFlowSample->{counterDataLength}) =
1365             unpack("a$offset NN", $sFlowDatagramPacked);
1366              
1367 0           $offset += 8;
1368              
1369 0           my $counterTypeEnterprise = $counterType >> 12;
1370 0           my $counterTypeFormat = $counterType & 2 ** 12 - 1;
1371              
1372 0 0         if ($counterTypeEnterprise == 0) {
1373              
1374 0 0         if ($counterTypeFormat == GENERICCOUNTER_SFLOWv5) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1375 0           &_decodeCounterGeneric(\$offset, $sFlowDatagramPackedRef, $sFlowSample);
1376             }
1377              
1378             elsif ($counterTypeFormat == ETHERNETCOUNTER_SFLOWv5) {
1379 0           &_decodeCounterEthernet(\$offset, $sFlowDatagramPackedRef, $sFlowSample);
1380             }
1381              
1382             elsif ($counterTypeFormat == TOKENRINGCOUNTER_SFLOWv5) {
1383 0           &_decodeCounterTokenring(\$offset, $sFlowDatagramPackedRef, $sFlowSample);
1384             }
1385              
1386             elsif ($counterTypeFormat == VGCOUNTER_SFLOWv5) {
1387 0           &_decodeCounterVg(\$offset, $sFlowDatagramPackedRef, $sFlowSample);
1388             }
1389              
1390             elsif ($counterTypeFormat == VLANCOUNTER_SFLOWv5) {
1391 0           &_decodeCounterVlan(\$offset, $sFlowDatagramPackedRef, $sFlowSample);
1392             }
1393              
1394             elsif ($counterTypeFormat == LAGCOUNTER_SFLOWv5) {
1395 0           &_decodeCounterLag(\$offset, $sFlowDatagramPackedRef, $sFlowSample);
1396             }
1397              
1398             elsif ($counterTypeFormat == PROCESSORCOUNTER_SFLOWv5) {
1399 0           &_decodeCounterProcessor(\$offset, $sFlowDatagramPackedRef, $sFlowSample);
1400             }
1401              
1402             elsif ($counterTypeFormat == HTTPCOUNTER_SFLOWv5) {
1403 0           &_decodeCounterHTTP(\$offset, $sFlowDatagramPackedRef, $sFlowSample);
1404             }
1405              
1406             else {
1407              
1408 0           $error = "ERROR: [sFlow.pm] AgentIP: $sFlowDatagram->{AgentIp}, "
1409             . "Datagram: $sFlowDatagram->{datagramSequenceNumber} - Unknown counter data format: "
1410             . "$counterTypeFormat - rest of the datagram skipped";
1411 0           return (undef, $error);
1412             }
1413              
1414             }
1415              
1416             else {
1417              
1418 0           $error = "ERROR: [sFlow.pm] AgentIP: $sFlowDatagram->{AgentIp}, "
1419             . "Datagram: $sFlowDatagram->{datagramSequenceNumber} - Unknown counter data enterprise: "
1420             . "$counterTypeEnterprise - rest of the datagram skipped";
1421              
1422 0           return (undef, $error);
1423             }
1424              
1425 0           $$offsetref = $offset;
1426 0           return (1, undef);
1427              
1428             }
1429              
1430              
1431             #############################################################################
1432             sub _decodeHeaderData {
1433             #############################################################################
1434              
1435 0     0     my $offsetref = shift;
1436 0           my $sFlowDatagramPackedRef = shift;
1437 0           my $sFlowDatagram = shift;
1438 0           my $sFlowSample = shift;
1439 0           my $sFlowSamples = shift;
1440              
1441 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
1442 0           my $offset = $$offsetref;
1443 0           my $vlanTag = 0;
1444 0           my $error = undef;
1445              
1446 0           $sFlowSample->{HEADERDATA} = 'HEADERDATA';
1447              
1448 0 0         if ($sFlowDatagram->{sFlowVersion} == SFLOWv5) {
1449              
1450             (undef,
1451             $sFlowSample->{HeaderProtocol},
1452             $sFlowSample->{HeaderFrameLength},
1453             $sFlowSample->{HeaderStrippedLength},
1454 0           $sFlowSample->{HeaderSizeByte}) =
1455             unpack("a$offset N4", $sFlowDatagramPacked);
1456              
1457 0           $offset += 16;
1458              
1459             } else {
1460              
1461             (undef,
1462             $sFlowSample->{HeaderProtocol},
1463             $sFlowSample->{HeaderFrameLength},
1464 0           $sFlowSample->{HeaderSizeByte}) =
1465             unpack("a$offset N3", $sFlowDatagramPacked);
1466              
1467 0           $offset += 12;
1468              
1469             }
1470              
1471             # check if $sFlowSample->{HeaderSizeByte} has a reasonable value
1472             # it cannot be more than 256 Byte
1473              
1474 0 0         if ($sFlowSample->{HeaderSizeByte} > 256) {
    0          
1475              
1476             # error: header size byte too long
1477 0           $error = "ERROR: [sFlow.pm] HeaderData: Header data too long";
1478              
1479 0           return (undef, $error);
1480              
1481             } elsif ($sFlowSample->{HeaderSizeByte} < 0) {
1482              
1483             # error: header size byte too small
1484 0           $error = "ERROR: [sFlow.pm] HeaderData: Header data too small";
1485              
1486 0           return (undef, $error);
1487              
1488             } else {
1489              
1490             # header size in bits
1491             $sFlowSample->{HeaderSizeBit} =
1492 0           $sFlowSample->{HeaderSizeByte} * 8;
1493              
1494             $sFlowSample->{HeaderBin} =
1495 0           substr ($sFlowDatagramPacked, $offset, $sFlowSample->{HeaderSizeByte});
1496              
1497             # we have to cut off a $sFlowSample->{HeaderSizeByte} mod 4 == 0 number of bytes
1498 0           my $tmp = 4 - ($sFlowSample->{HeaderSizeByte} % 4);
1499 0 0         $tmp == 4 and $tmp = 0;
1500              
1501 0           $offset += ($sFlowSample->{HeaderSizeByte} + $tmp);
1502              
1503 0           my $ipdata = undef;
1504              
1505             ($sFlowSample->{HeaderEtherDestMac},
1506             $sFlowSample->{HeaderEtherSrcMac},
1507             $sFlowSample->{HeaderType},
1508             $ipdata) =
1509 0           unpack('a6a6H4a*', $sFlowSample->{HeaderBin});
1510              
1511             # analyze ether type
1512 0 0         if ($sFlowSample->{HeaderType} eq ETH_TYPE_VLAN) {
1513              
1514 0           (undef, $sFlowSample->{HeaderType}, $ipdata) = unpack('nH4a*', $ipdata);
1515             # add 4 bytes to ethernet header length because of vlan tag
1516             # this is done later on, if $vlanTag is set to 1
1517 0           $vlanTag = 1;
1518              
1519             }
1520              
1521 0 0         if ($sFlowSample->{HeaderType} eq ETH_TYPE_IP) {
    0          
    0          
1522              
1523 0           (undef, $sFlowSample->{HeaderDatalen}) = unpack('nn', $ipdata);
1524             # add ethernet header length
1525 0           $sFlowSample->{HeaderDatalen} += 14;
1526             }
1527              
1528             elsif ($sFlowSample->{HeaderType} eq ETH_TYPE_IPv6) {
1529              
1530 0           (undef, $sFlowSample->{HeaderDatalen}) = unpack('Nn', $ipdata);
1531             # add v6 header (not included in v6)
1532 0           $sFlowSample->{HeaderDatalen} += 40;
1533             # add ethernet header length
1534 0           $sFlowSample->{HeaderDatalen} += 14;
1535             }
1536              
1537             elsif ($sFlowSample->{HeaderType} eq ETH_TYPE_ARP) {
1538             # ARP
1539 0           $sFlowSample->{HeaderDatalen} = 64;
1540             }
1541              
1542             else {
1543             # unknown
1544 0           $sFlowSample->{HeaderDatalen} = 64;
1545             }
1546              
1547             # add vlan tag length
1548 0 0         if ($vlanTag == 1) {
1549 0           $sFlowSample->{HeaderDatalen} += 4;
1550             }
1551              
1552 0 0         if ($sFlowSample->{HeaderDatalen} < 64) {
1553 0           $sFlowSample->{HeaderDatalen} = 64;
1554             }
1555              
1556             }
1557              
1558 0           $$offsetref = $offset;
1559 0           return (1, undef);
1560              
1561             }
1562              
1563              
1564             #############################################################################
1565             sub _decodeEthernetFrameData {
1566             #############################################################################
1567              
1568 0     0     my $offsetref = shift;
1569 0           my $sFlowDatagramPackedRef = shift;
1570 0           my $sFlowSample = shift;
1571              
1572 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
1573 0           my $offset = $$offsetref;
1574              
1575 0           $sFlowSample->{ETHERNETFRAMEDATA} = 'ETHERNETFRAMEDATA';
1576              
1577             (undef,
1578             $sFlowSample->{EtherMacPacketlength},
1579             $sFlowSample->{EtherSrcMac},
1580             $sFlowSample->{EtherDestMac},
1581 0           $sFlowSample->{EtherPackettype}) =
1582             unpack("a$offset N(a6x2)2N", $sFlowDatagramPacked);
1583              
1584             # format MAC addresses as hex (ignore final 2 padding bytes)
1585 0           map { $_ = unpack 'H12' } ( @{$sFlowSample}{qw{EtherSrcMac EtherDestMac}} );
  0            
  0            
1586              
1587 0           $offset += 24;
1588 0           $$offsetref = $offset;
1589              
1590             }
1591              
1592              
1593             #############################################################################
1594             sub _decodeIPv4Data {
1595             #############################################################################
1596              
1597 0     0     my $offsetref = shift;
1598 0           my $sFlowDatagramPackedRef = shift;
1599 0           my $sFlowSample = shift;
1600              
1601 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
1602 0           my $offset = $$offsetref;
1603              
1604 0           $sFlowSample->{IPv4DATA} = 'IPv4DATA';
1605              
1606             (undef,
1607             $sFlowSample->{IPv4Packetlength},
1608             $sFlowSample->{IPv4NextHeaderProtocol},
1609             $sFlowSample->{IPv4srcIp},
1610             $sFlowSample->{IPv4destIp},
1611             $sFlowSample->{IPv4srcPort},
1612             $sFlowSample->{IPv4destPort},
1613             $sFlowSample->{IPv4tcpFlags},
1614 0           $sFlowSample->{IPv4tos}) =
1615             unpack("a$offset N2B32B32N4", $sFlowDatagramPacked);
1616              
1617 0           $sFlowSample->{IPv4srcIp} = &_bin2ip($sFlowSample->{IPv4srcIp});
1618 0           $sFlowSample->{IPv4destIp} = &_bin2ip($sFlowSample->{IPv4destIp});
1619              
1620 0           $offset += 32;
1621 0           $$offsetref = $offset;
1622              
1623             }
1624              
1625              
1626             #############################################################################
1627             sub _decodeIPv6Data {
1628             #############################################################################
1629              
1630 0     0     my $offsetref = shift;
1631 0           my $sFlowDatagramPackedRef = shift;
1632 0           my $sFlowSample = shift;
1633              
1634 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
1635 0           my $offset = $$offsetref;
1636              
1637 0           $sFlowSample->{IPv6DATA} = 'IPv6DATA';
1638              
1639             (
1640             $sFlowSample->{IPv6Packetlength},
1641             $sFlowSample->{IPv6NextHeaderProto},
1642             $sFlowSample->{IPv6srcIp},
1643             $sFlowSample->{IPv6destIp},
1644             $sFlowSample->{IPv6srcPort},
1645             $sFlowSample->{IPv6destPort},
1646             $sFlowSample->{IPv6tcpFlags},
1647             $sFlowSample->{IPv6Priority}
1648 0           ) = unpack("a$offset N2 a16 a16 N4", $sFlowDatagramPacked);
1649              
1650 0           $offset += 56;
1651 0           $$offsetref = $offset;
1652              
1653             }
1654              
1655              
1656             #############################################################################
1657             sub _decodeSwitchData {
1658             #############################################################################
1659              
1660 0     0     my $offsetref = shift;
1661 0           my $sFlowDatagramPackedRef = shift;
1662 0           my $sFlowSample = shift;
1663              
1664 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
1665 0           my $offset = $$offsetref;
1666              
1667 0           $sFlowSample->{SWITCHDATA} = 'SWITCHDATA';
1668              
1669             (undef,
1670             $sFlowSample->{SwitchSrcVlan},
1671             $sFlowSample->{SwitchSrcPriority},
1672             $sFlowSample->{SwitchDestVlan},
1673 0           $sFlowSample->{SwitchDestPriority}) =
1674             unpack("a$offset N4", $sFlowDatagramPacked);
1675              
1676 0           $offset += 16;
1677 0           $$offsetref = $offset;
1678              
1679             }
1680              
1681              
1682             #############################################################################
1683             sub _decodeRouterData {
1684             #############################################################################
1685              
1686 0     0     my $offsetref = shift;
1687 0           my $sFlowDatagramPackedRef = shift;
1688 0           my $sFlowDatagram = shift;
1689 0           my $sFlowSample = shift;
1690 0           my $sFlowSamples = shift;
1691              
1692 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
1693 0           my $offset = $$offsetref;
1694 0           my $subProcessed = undef;
1695 0           my $error = undef;
1696              
1697 0           $sFlowSample->{ROUTERDATA} = 'ROUTERDATA';
1698              
1699             (undef,
1700 0           $sFlowSample->{RouterIpVersionNextHopRouter}) =
1701             unpack("a$offset N", $sFlowDatagramPacked);
1702              
1703 0           $offset += 4;
1704              
1705             ($subProcessed, $error) =
1706             &_decodeIpAddress(
1707             \$offset,
1708             $sFlowDatagramPackedRef,
1709             $sFlowDatagram,
1710             $sFlowSample,
1711             $sFlowSamples,
1712             $sFlowSample->{RouterIpVersionNextHopRouter},
1713 0           'RouterIpAddressNextHopRouter',
1714             undef
1715             );
1716              
1717 0 0         unless ($subProcessed) {
1718 0           return (undef, $error);
1719             }
1720              
1721             (undef,
1722             $sFlowSample->{RouterSrcMask},
1723 0           $sFlowSample->{RouterDestMask}) =
1724             unpack("a$offset NN", $sFlowDatagramPacked);
1725              
1726 0           $offset += 8;
1727              
1728 0           $$offsetref = $offset;
1729 0           return (1, undef);
1730              
1731             }
1732              
1733              
1734             #############################################################################
1735             sub _decodeGatewayData {
1736             #############################################################################
1737              
1738 0     0     my $offsetref = shift;
1739 0           my $sFlowDatagramPackedRef = shift;
1740 0           my $sFlowDatagram = shift;
1741 0           my $sFlowSample = shift;
1742 0           my $sFlowSamples = shift;
1743              
1744 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
1745 0           my $offset = $$offsetref;
1746 0           my $subProcessed = undef;
1747 0           my $error = undef;
1748              
1749 0           $sFlowSample->{GATEWAYDATA} = 'GATEWAYDATA';
1750              
1751 0 0         if ($sFlowDatagram->{sFlowVersion} == SFLOWv5) {
1752              
1753             (undef,
1754 0           $sFlowSample->{GatewayIpVersionNextHopRouter}) =
1755             unpack("a$offset N", $sFlowDatagramPacked);
1756              
1757 0           $offset += 4;
1758              
1759             ($subProcessed, $error) =
1760             &_decodeIpAddress(
1761             \$offset,
1762             $sFlowDatagramPackedRef,
1763             $sFlowDatagram,
1764             $sFlowSample,
1765             $sFlowSamples,
1766             $sFlowSample->{GatewayIpVersionNextHopRouter},
1767 0           'GatewayIpAddressNextHopRouter',
1768             undef,
1769             );
1770              
1771 0 0         unless ($subProcessed) {
1772 0           return (undef, $error);
1773             }
1774             }
1775              
1776             (undef,
1777             $sFlowSample->{GatewayAsRouter},
1778             $sFlowSample->{GatewayAsSource},
1779             $sFlowSample->{GatewayAsSourcePeer},
1780 0           $sFlowSample->{GatewayDestAsPathsCount}) =
1781             unpack("a$offset N4", $sFlowDatagramPacked);
1782              
1783 0           $offset += 16;
1784              
1785             # boundcheck for $sFlowSample->{GatewayDestAsPathsCount}
1786             # $sFlowSample->{GatewayDestAsPathsCount} * 4 (that will be the min)
1787             # cannot be longer than the number of $sFlowDatagramPacked byte - $offset
1788              
1789 0 0         if (length($sFlowDatagramPacked) - $offset <
    0          
1790             $sFlowSample->{GatewayDestAsPathsCount} * 4) {
1791              
1792             # error $sFlowSample->{GatewayDestAsPaths} too big
1793 0           $error = "ERROR: [sFlow.pm] GatewayDestAsPaths: Gateway destination AS paths count too big "
1794             . "- rest of the datagram skipped";
1795              
1796 0           return (undef, $error);
1797              
1798             } elsif ($sFlowSample->{GatewayDestAsPathsCount} < 0) {
1799              
1800             # error $sFlowSample->{GatewayDestAsPaths} too small
1801 0           $error = "ERROR: [sFlow.pm] GatewayDestAsPaths: Gateway destination AS paths count too small "
1802             . "- rest of the datagram skipped";
1803              
1804 0           return (undef, $error);
1805              
1806             } else {
1807              
1808             # array containing the single paths
1809 0           my @sFlowAsPaths = ();
1810              
1811             # reference to this array in extended data
1812 0           $sFlowSample->{GatewayDestAsPaths} = \@sFlowAsPaths;
1813              
1814 0           for my $destAsPathCount (0 .. $sFlowSample->{GatewayDestAsPathsCount} - 1) {
1815              
1816             # single path hash
1817 0           my %sFlowAsPath = ();
1818              
1819             # reference to this single path hash in the paths array
1820 0           push @sFlowAsPaths, \%sFlowAsPath;
1821              
1822 0 0         if ($sFlowDatagram->{sFlowVersion} >= SFLOWv4) {
1823              
1824             (undef,
1825             $sFlowAsPath{asPathSegmentType},
1826 0           $sFlowAsPath{lengthAsList}) =
1827             unpack("a$offset NN", $sFlowDatagramPacked);
1828              
1829 0           $offset += 8;
1830              
1831             } else {
1832              
1833 0           $sFlowAsPath{lengthAsList} = 1;
1834              
1835             }
1836              
1837             # boundcheck for $sFlowAsPath{lengthAsList}
1838             # $sFlowAsPath{lengthAsList} * 4
1839             # cannot be longer than the number of $sFlowDatagramPacked byte - $offset
1840              
1841 0 0         if (length($sFlowDatagramPacked) - $offset <
    0          
1842             $sFlowAsPath{lengthAsList} * 4) {
1843              
1844             # error $sFlowAsPath{lengthAsList} too big
1845 0           $error = "ERROR: [sFlow.pm] AsPath: Length AS list too big "
1846             . "- rest of the datagram skipped";
1847              
1848 0           return (undef, $error);
1849              
1850             } elsif ($sFlowAsPath{lengthAsList} < 0) {
1851              
1852             # error $sFlowAsPath{lengthAsList} too small
1853 0           $error = "ERROR: [sFlow.pm] AsPath: Length AS list too small "
1854             . "- rest of the datagram skipped";
1855              
1856 0           return (undef, $error);
1857              
1858             } else {
1859              
1860             # array containing the as numbers of a path
1861 0           my @sFlowAsNumber = ();
1862              
1863             # referece to this array in path hash
1864 0           $sFlowAsPath{AsPath} = \@sFlowAsNumber;
1865              
1866 0           for my $asListLength (0 .. $sFlowAsPath{lengthAsList} - 1) {
1867              
1868             (undef,
1869 0           my $asNumber) =
1870             unpack("a$offset N", $sFlowDatagramPacked);
1871              
1872             # push as number to array
1873 0           push @sFlowAsNumber, $asNumber;
1874 0           $offset += 4;
1875             }
1876              
1877             }
1878              
1879             }
1880              
1881             }
1882              
1883             # communities and localpref added in v.4.
1884 0 0         if ($sFlowDatagram->{sFlowVersion} >= SFLOWv4) {
1885              
1886             (undef,
1887 0           $sFlowSample->{GatewayLengthCommunitiesList}) =
1888             unpack("a$offset N", $sFlowDatagramPacked);
1889              
1890 0           $offset += 4;
1891              
1892             # boundcheck for $sFlowSample->{GatewayLengthCommunitiesList}
1893             # $sFlowSample->{GatewayLengthCommunitiesList} * 4
1894             # cannot be longer than the number of $sFlowDatagramPacked byte - $offset
1895              
1896 0 0         if (length($sFlowDatagramPacked) - $offset <
    0          
1897             $sFlowSample->{GatewayLengthCommunitiesList} * 4) {
1898              
1899             # error $sFlowSample->{GatewayLengthCommunitiesList} too big
1900 0           $error = "ERROR: [sFlow.pm] GatewayCommunitiesList: Gateway communities list count too big "
1901             . "- rest of the datagram skipped";
1902              
1903 0           return (undef, $error);
1904              
1905             # $sFlowSample->{GatewayLengthCommunitiesList} might very well be 0
1906             } elsif ($sFlowSample->{GatewayLengthCommunitiesList} < 0) {
1907              
1908             # error $sFlowSample->{GatewayLengthCommunitiesList} too small
1909 0           $error = "ERROR: [sFlow.pm] GatewayCommunitiesList: Gateway communities list count too small "
1910             . "- rest of the datagram skipped";
1911              
1912 0           return (undef, $error);
1913              
1914             } else {
1915              
1916 0           my @sFlowCommunities = ();
1917 0           $sFlowSample->{GatewayCommunities} = \@sFlowCommunities;
1918              
1919 0           for my $commLength (0 .. $sFlowSample->{GatewayLengthCommunitiesList} - 1) {
1920              
1921             (undef,
1922 0           my $community) =
1923             unpack("a$offset N", $sFlowDatagramPacked);
1924              
1925 0           $community = ($community >> 16) . ':' . ($community & 65535);
1926              
1927 0           push @sFlowCommunities, $community;
1928 0           $offset += 4;
1929             }
1930              
1931             }
1932              
1933             (undef,
1934 0           $sFlowSample->{localPref}) =
1935             unpack("a$offset N", $sFlowDatagramPacked);
1936              
1937 0           $offset += 4;
1938              
1939             }
1940              
1941 0           $$offsetref = $offset;
1942 0           return (1, undef);
1943              
1944             }
1945              
1946              
1947             #############################################################################
1948             sub _decodeUserData {
1949             #############################################################################
1950              
1951 0     0     my $offsetref = shift;
1952 0           my $sFlowDatagramPackedRef = shift;
1953 0           my $sFlowDatagram = shift;
1954 0           my $sFlowSample = shift;
1955              
1956 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
1957 0           my $offset = $$offsetref;
1958 0           my $error = undef;
1959              
1960 0           $sFlowSample->{USERDATA} = 'USERDATA';
1961              
1962 0 0         if ($sFlowDatagram->{sFlowVersion} == SFLOWv5) {
1963              
1964             (undef,
1965 0           $sFlowSample->{UserSrcCharset}) =
1966             unpack("a$offset N", $sFlowDatagramPacked);
1967              
1968 0           $offset += 4;
1969             }
1970              
1971             (undef,
1972 0           $sFlowSample->{UserLengthSrcString}) =
1973             unpack("a$offset N", $sFlowDatagramPacked);
1974              
1975 0           $offset += 4;
1976              
1977 0 0         if ($sFlowSample->{UserLengthSrcString} > length($sFlowDatagramPacked) - $offset) {
    0          
1978              
1979 0           $error = "ERROR: [sFlow.pm] UserData: UserLengthSrcString too big "
1980             . "- rest of the datagram skipped";
1981              
1982 0           return (undef, $error);
1983              
1984             } elsif ($sFlowSample->{UserLengthSrcString} < 0) {
1985              
1986 0           $error = "ERROR: [sFlow.pm] UserData: UserLengthSrcString too small "
1987             . "- rest of the datagram skipped";
1988              
1989 0           return (undef, $error);
1990              
1991             } else {
1992              
1993             (undef,
1994 0           $sFlowSample->{UserSrcString}) =
1995             unpack("a$offset A$sFlowSample->{UserLengthSrcString}", $sFlowDatagramPacked);
1996              
1997             # we have to cut off a $sFlowSample->{UserLengthSrcString} mod 4 == 0 number of bytes
1998 0           my $tmp = 4 - ($sFlowSample->{UserLengthSrcString} % 4);
1999 0 0         $tmp == 4 and $tmp = 0;
2000              
2001 0           $offset += ($sFlowSample->{UserLengthSrcString} + $tmp);
2002              
2003             }
2004              
2005 0 0         if ($sFlowDatagram->{sFlowVersion} == SFLOWv5) {
2006              
2007             (undef,
2008 0           $sFlowSample->{UserDestCharset}) =
2009             unpack("a$offset N", $sFlowDatagramPacked);
2010              
2011 0           $offset += 4;
2012             }
2013              
2014             (undef,
2015 0           $sFlowSample->{UserLengthDestString}) =
2016             unpack("a$offset N", $sFlowDatagramPacked);
2017              
2018 0           $offset += 4;
2019              
2020 0 0         if ($sFlowSample->{UserLengthDestString} > length($sFlowDatagramPacked) - $offset) {
    0          
2021              
2022 0           $error = "ERROR: [sFlow.pm] UserData: UserLengthDestString too big "
2023             . "- rest of the datagram skipped";
2024              
2025 0           return (undef, $error);
2026              
2027             } elsif ($sFlowSample->{UserLengthDestString} < 0) {
2028              
2029 0           $error = "ERROR: [sFlow.pm] UserData: UserLengthDestString too small "
2030             . "- rest of the datagram skipped";
2031              
2032 0           return (undef, $error);
2033              
2034             } else {
2035              
2036             (undef,
2037 0           $sFlowSample->{UserDestString}) =
2038             unpack("a$offset A$sFlowSample->{UserLengthDestString}", $sFlowDatagramPacked);
2039              
2040             # we have to cut off a $sFlowSample->{UserLengthDestString} mod 4 == 0 number of bytes
2041 0           my $tmp = 4 - ($sFlowSample->{UserLengthDestString} % 4);
2042 0 0         $tmp == 4 and $tmp = 0;
2043              
2044 0           $offset += ($sFlowSample->{UserLengthDestString} + $tmp);
2045              
2046             }
2047              
2048 0           $$offsetref = $offset;
2049 0           return (1, undef);
2050              
2051             }
2052              
2053              
2054             #############################################################################
2055             sub _decodeUrlData {
2056             #############################################################################
2057              
2058 0     0     my $offsetref = shift;
2059 0           my $sFlowDatagramPackedRef = shift;
2060 0           my $sFlowDatagram = shift;
2061 0           my $sFlowSample = shift;
2062              
2063 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
2064 0           my $offset = $$offsetref;
2065 0           my $error = undef;
2066              
2067 0           $sFlowSample->{URLDATA} = 'URLDATA';
2068              
2069             (undef,
2070             $sFlowSample->{UrlDirection},
2071 0           $sFlowSample->{UrlLength}) =
2072             unpack("a$offset NN", $sFlowDatagramPacked);
2073              
2074 0           $offset += 8;
2075              
2076 0 0         if ($sFlowSample->{UrlLength} > length($sFlowDatagramPacked) - $offset) {
    0          
2077              
2078 0           $error = "ERROR: [sFlow.pm] UrlData: UrlLength too big "
2079             . "- rest of the datagram skipped";
2080              
2081 0           return (undef, $error);
2082              
2083             } elsif ($sFlowSample->{UrlLength} < 0) {
2084              
2085 0           $error = "ERROR: [sFlow.pm] UrlData: UrlLength too small "
2086             . "- rest of the datagram skipped";
2087              
2088 0           return (undef, $error);
2089              
2090             } else {
2091              
2092             (undef,
2093 0           $sFlowSample->{Url}) =
2094             unpack("a$offset A$sFlowSample->{UrlLength}", $sFlowDatagramPacked);
2095              
2096             # we have to cut off a $sFlowSample->{UrlLength} mod 4 == 0 number of bytes
2097 0           my $tmp = 4 - ($sFlowSample->{UrlLength} % 4);
2098 0 0         $tmp == 4 and $tmp = 0;
2099              
2100 0           $offset += ($sFlowSample->{UrlLength} + $tmp);
2101              
2102 0 0         if ($sFlowDatagram->{sFlowVersion} == SFLOWv5) {
2103              
2104             (undef,
2105 0           $sFlowSample->{UrlHostLength}) =
2106             unpack("a$offset N", $sFlowDatagramPacked);
2107              
2108 0           $offset += 4;
2109              
2110 0 0         if ($sFlowSample->{UrlHostLength} > length($sFlowDatagramPacked) - $offset) {
    0          
2111              
2112 0           $error = "ERROR: [sFlow.pm] UrlData: UrlHostLength too big "
2113             . "- rest of the datagram skipped";
2114              
2115 0           return (undef, $error);
2116              
2117             } elsif ($sFlowSample->{UrlHostLength} < 0) {
2118              
2119 0           $error = "ERROR: [sFlow.pm] UrlData: UrlHostLength too small "
2120             . "- rest of the datagram skipped";
2121              
2122 0           return (undef, $error);
2123              
2124             } else {
2125              
2126             (undef,
2127 0           $sFlowSample->{UrlHost}) =
2128             unpack("a$offset A$sFlowSample->{UrlHostLength}", $sFlowDatagramPacked);
2129              
2130             # we have to cut off a $sFlowSample->{UrlHostLength} mod 4 == 0 number of bytes
2131 0           my $tmp = 4 - ($sFlowSample->{UrlHostLength} % 4);
2132 0 0         $tmp == 4 and $tmp = 0;
2133              
2134 0           $offset += ($sFlowSample->{UrlHostLength} + $tmp);
2135              
2136             }
2137              
2138             }
2139              
2140             }
2141              
2142 0           $$offsetref = $offset;
2143 0           return (1, undef);
2144              
2145             }
2146              
2147              
2148             #############################################################################
2149             sub _decodeMplsData {
2150             #############################################################################
2151              
2152 0     0     my $offsetref = shift;
2153 0           my $sFlowDatagramPackedRef = shift;
2154 0           my $sFlowDatagram = shift;
2155 0           my $sFlowSample = shift;
2156 0           my $sFlowSamples = shift;
2157              
2158 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
2159 0           my $offset = $$offsetref;
2160 0           my $subProcessed = undef;
2161 0           my $error = undef;
2162              
2163 0           $sFlowSample->{MPLSDATA} = 'MPLSDATA';
2164              
2165             (undef,
2166 0           $sFlowSample->{MplsIpVersionNextHopRouter}) =
2167             unpack("a$offset N", $sFlowDatagramPacked);
2168              
2169 0           $offset += 4;
2170              
2171             ($subProcessed, $error) =
2172             &_decodeIpAddress(
2173             \$offset,
2174             $sFlowDatagramPackedRef,
2175             $sFlowDatagram,
2176             $sFlowSample,
2177             $sFlowSamples,
2178             $sFlowSample->{MplsIpVersionNextHopRouter},
2179 0           'MplsIpVersionNextHopRouter',
2180             undef,
2181             );
2182              
2183 0 0         unless ($subProcessed) {
2184 0           return (undef, $error);
2185             }
2186              
2187             (undef,
2188 0           $sFlowSample->{MplsInLabelStackCount}) =
2189             unpack("a$offset N", $sFlowDatagramPacked);
2190              
2191 0           $offset += 4;
2192              
2193             # boundcheck for $sFlowSample->{MplsInLabelStackCount}
2194             # $sFlowSample->{MplsInLabelStackCount} * 4
2195             # cannot be longer than the number of $sFlowDatagramPacked byte - $offset
2196              
2197 0 0         if (length($sFlowDatagramPacked) - $offset <
    0          
2198             $sFlowSample->{MplsInLabelStackCount} * 4) {
2199              
2200             # error $sFlowSample->{MplsInLabelStack} too big
2201 0           $error = "ERROR: [sFlow.pm] MplsInLabel: Mpls in label stack count too big "
2202             . "- rest of the datagram skipped";
2203              
2204 0           return (undef, $error);
2205              
2206             } elsif ($sFlowSample->{MplsInLabelStackCount} < 0) {
2207              
2208             # error $sFlowSample->{MplsInLabelStack} too small
2209 0           $error = "ERROR: [sFlow.pm] MplsInLabel: Mpls in label stack count too small "
2210             . "- rest of the datagram skipped";
2211              
2212 0           return (undef, $error);
2213              
2214             } else {
2215              
2216 0           my @MplsInLabelStack = ();
2217 0           $sFlowSample->{MplsInLabelStack} = \@MplsInLabelStack;
2218              
2219 0           for my $MplsInLabelStackCount (0 .. $sFlowSample->{MplsInLabelStackCount} - 1) {
2220              
2221 0           (undef, my $MplsInLabel) = unpack("a$offset N", $sFlowDatagramPacked);
2222 0           push @MplsInLabelStack, $MplsInLabel;
2223 0           $offset += 4;
2224             }
2225              
2226             }
2227              
2228             (undef,
2229 0           $sFlowSample->{MplsOutLabelStackCount}) =
2230             unpack("a$offset N", $sFlowDatagramPacked);
2231              
2232 0           $offset += 4;
2233              
2234             # boundcheck for $sFlowSample->{MplsOutLabelStackCount}
2235             # $sFlowSample->{MplsOutLabelStackCount} * 4
2236             # cannot be longer than the number of $sFlowDatagramPacked byte - $offset
2237              
2238 0 0         if (length($sFlowDatagramPacked) - $offset <
    0          
2239             $sFlowSample->{MplsOutLabelStackCount} * 4) {
2240              
2241             # error $sFlowSample->{MplsOutLabelStack} too big
2242 0           $error = "ERROR: [sFlow.pm] MplsOutLabel: Mpls out label stack count too big "
2243             . "- rest of the datagram skipped";
2244              
2245 0           return (undef, $error);
2246              
2247             } elsif ($sFlowSample->{MplsOutLabelStackCount} < 0) {
2248              
2249             # error $sFlowSample->{MplsOutLabelStack} too small
2250 0           $error = "ERROR: [sFlow.pm] MplsOutLabel: Mpls out label stack count too small "
2251             . "- rest of the datagram skipped";
2252              
2253 0           return (undef, $error);
2254              
2255             } else {
2256              
2257 0           my @MplsOutLabelStack = ();
2258 0           $sFlowSample->{MplsOutLabelStack} = \@MplsOutLabelStack;
2259              
2260 0           for my $MplsOutLabelStackCount (0 .. $sFlowSample->{MplsOutLabelStackCount} - 1) {
2261              
2262 0           (undef, my $MplsOutLabel) = unpack("a$offset N", $sFlowDatagramPacked);
2263 0           push @MplsOutLabelStack, $MplsOutLabel;
2264 0           $offset += 4;
2265             }
2266              
2267             }
2268              
2269 0           $$offsetref = $offset;
2270 0           return (1, undef);
2271              
2272             }
2273              
2274              
2275             #############################################################################
2276             sub _decodeNatData {
2277             #############################################################################
2278              
2279 0     0     my $offsetref = shift;
2280 0           my $sFlowDatagramPackedRef = shift;
2281 0           my $sFlowDatagram = shift;
2282 0           my $sFlowSample = shift;
2283 0           my $sFlowSamples = shift;
2284              
2285 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
2286 0           my $offset = $$offsetref;
2287 0           my $subProcessed = undef;
2288 0           my $error = undef;
2289              
2290 0           $sFlowSample->{NATDATA} = 'NATDATA';
2291              
2292             (undef,
2293 0           $sFlowSample->{NatIpVersionSrcAddress}) =
2294             unpack("a$offset N", $sFlowDatagramPacked);
2295              
2296 0           $offset += 4;
2297              
2298             ($subProcessed, $error) =
2299             &_decodeIpAddress(
2300             \$offset,
2301             $sFlowDatagramPackedRef,
2302             $sFlowDatagram,
2303             $sFlowSample,
2304             $sFlowSamples,
2305             $sFlowSample->{NatIpVersionSrcAddress},
2306 0           'NatSrcAddress',
2307             undef,
2308             );
2309              
2310 0 0         unless ($subProcessed) {
2311 0           return (undef, $error);
2312             }
2313              
2314             (undef,
2315 0           $sFlowSample->{NatIpVersionDestAddress}) =
2316             unpack("a$offset N", $sFlowDatagramPacked);
2317              
2318 0           $offset += 4;
2319              
2320             ($subProcessed, $error) =
2321             &_decodeIpAddress(
2322             \$offset,
2323             $sFlowDatagramPackedRef,
2324             $sFlowDatagram,
2325             $sFlowSample,
2326             $sFlowSamples,
2327             $sFlowSample->{NatIpVersionDestAddress},
2328 0           'NatDestAddress',
2329             undef,
2330             );
2331              
2332 0 0         unless ($subProcessed) {
2333 0           return (undef, $error);
2334             }
2335              
2336 0           $$offsetref = $offset;
2337 0           return (1, undef);
2338             }
2339              
2340              
2341             #############################################################################
2342             sub _decodeMplsTunnel {
2343             #############################################################################
2344              
2345 0     0     my $offsetref = shift;
2346 0           my $sFlowDatagramPackedRef = shift;
2347 0           my $sFlowSample = shift;
2348              
2349 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
2350 0           my $offset = $$offsetref;
2351 0           my $error = undef;
2352              
2353 0           $sFlowSample->{MPLSTUNNEL} = 'MPLSTUNNEL';
2354              
2355             (undef,
2356 0           $sFlowSample->{MplsTunnelNameLength}) =
2357             unpack("a$offset N", $sFlowDatagramPacked);
2358              
2359 0           $offset += 4;
2360              
2361 0 0         if ($sFlowSample->{MplsTunnelNameLength} > length($sFlowDatagramPacked) - $offset) {
    0          
2362              
2363             # error $sFlowSample->{MplsTunnelLength} too big
2364 0           $error = "ERROR: [sFlow.pm] MplsTunnel: MplsTunnelNameLength too big "
2365             . "- rest of the datagram skipped";
2366              
2367 0           return (undef, $error);
2368              
2369             } elsif ($sFlowSample->{MplsTunnelNameLength} < 0) {
2370              
2371             # error $sFlowSample->{MplsTunnelLength} too small
2372 0           $error = "ERROR: [sFlow.pm] MplsTunnel: MplsTunnelNameLength too small "
2373             . "- rest of the datagram skipped";
2374              
2375 0           return (undef, $error);
2376              
2377             } else {
2378              
2379             (undef,
2380 0           $sFlowSample->{MplsTunnelName}) =
2381             unpack("a$offset A$sFlowSample->{MplsTunnelNameLength}", $sFlowDatagramPacked);
2382              
2383             # we have to cut off a $sFlowSample->{MplsTunnelLength} mod 4 == 0 number of bytes
2384 0           my $tmp = 4 - ($sFlowSample->{MplsTunnelNameLength} % 4);
2385 0 0         $tmp == 4 and $tmp = 0;
2386              
2387 0           $offset += ($sFlowSample->{MplsTunnelNameLength} + $tmp);
2388              
2389             (undef,
2390             $sFlowSample->{MplsTunnelId},
2391 0           $sFlowSample->{MplsTunnelCosValue}) =
2392             unpack("a$offset NN", $sFlowDatagramPacked);
2393              
2394 0           $offset += 8;
2395              
2396             }
2397              
2398 0           $$offsetref = $offset;
2399 0           return (1, undef);
2400              
2401             }
2402              
2403              
2404             #############################################################################
2405             sub _decodeMplsVc {
2406             #############################################################################
2407              
2408 0     0     my $offsetref = shift;
2409 0           my $sFlowDatagramPackedRef = shift;
2410 0           my $sFlowSample = shift;
2411              
2412 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
2413 0           my $offset = $$offsetref;
2414 0           my $error = undef;
2415              
2416 0           $sFlowSample->{MPLSVC} = 'MPLSVC';
2417              
2418             (undef,
2419 0           $sFlowSample->{MplsVcInstanceNameLength}) =
2420             unpack("a$offset N", $sFlowDatagramPacked);
2421              
2422 0           $offset += 4;
2423              
2424 0 0         if ($sFlowSample->{MplsVcInstanceNameLength} > length($sFlowDatagramPacked) - $offset) {
    0          
2425              
2426             # error $sFlowSample->{MplsVcInstanceNameLength} too big
2427 0           $error = "ERROR: [sFlow.pm] MplsVc: MplsVcInstanceNameLength too big "
2428             . "- rest of the datagram skipped";
2429              
2430 0           return (undef, $error);
2431              
2432             } elsif ($sFlowSample->{MplsVcInstanceNameLength} < 0) {
2433              
2434             # error $sFlowSample->{MplsVcInstanceNameLength} too small
2435 0           $error = "ERROR: [sFlow.pm] MplsVc: MplsVcInstanceNameLength too small "
2436             . "- rest of the datagram skipped";
2437              
2438 0           return (undef, $error);
2439              
2440             } else {
2441              
2442             (undef,
2443 0           $sFlowSample->{MplsVcInstanceName}) =
2444             unpack("a$offset A$sFlowSample->{MplsVcInstanceNameLength}", $sFlowDatagramPacked);
2445              
2446             # we have to cut off a $sFlowSample->{MplsVcInstanceNameLength} mod 4 == 0 number of bytes
2447 0           my $tmp = 4 - ($sFlowSample->{MplsVcInstanceNameLength} % 4);
2448 0 0         $tmp == 4 and $tmp = 0;
2449              
2450 0           $offset += ($sFlowSample->{MplsVcInstanceNameLength} + $tmp);
2451              
2452             (undef,
2453             $sFlowSample->{MplsVcId},
2454 0           $sFlowSample->{MplsVcLabelCosValue}) =
2455             unpack("a$offset NN", $sFlowDatagramPacked);
2456              
2457 0           $offset += 8;
2458              
2459             }
2460              
2461 0           $$offsetref = $offset;
2462 0           return (1, undef);
2463              
2464             }
2465              
2466              
2467             #############################################################################
2468             sub _decodeMplsFec {
2469             #############################################################################
2470              
2471 0     0     my $offsetref = shift;
2472 0           my $sFlowDatagramPackedRef = shift;
2473 0           my $sFlowSample = shift;
2474              
2475 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
2476 0           my $offset = $$offsetref;
2477 0           my $error = undef;
2478              
2479 0           $sFlowSample->{MPLSFEC} = 'MPLSFEC';
2480              
2481             (undef,
2482 0           $sFlowSample->{MplsFtnDescrLength}) =
2483             unpack("a$offset N", $sFlowDatagramPacked);
2484              
2485 0           $offset += 4;
2486              
2487 0 0         if ($sFlowSample->{MplsFtnDescrLength} > length($sFlowDatagramPacked) - $offset) {
    0          
2488              
2489             # error $sFlowSample->{{MplsFtnDescrLength} too big
2490 0           $error = "ERROR: [sFlow.pm] MplsFec: MplsFtnDescrLength too big "
2491             . "- rest of the datagram skipped";
2492              
2493 0           return (undef, $error);
2494              
2495             } elsif ($sFlowSample->{MplsFtnDescrLength} < 0) {
2496              
2497             # error $sFlowSample->{{MplsFtnDescrLength} too small
2498 0           $error = "ERROR: [sFlow.pm] MplsFec: MplsFtnDescrLength too small "
2499             . "- rest of the datagram skipped";
2500              
2501 0           return (undef, $error);
2502              
2503             } else {
2504              
2505             (undef,
2506 0           $sFlowSample->{MplsFtnDescr}) =
2507             unpack("a$offset A$sFlowSample->{MplsFtnDescrLength}", $sFlowDatagramPacked);
2508              
2509             # we have to cut off a $sFlowSample->{MplsFtrDescrLength} mod 4 == 0 number of bytes
2510 0           my $tmp = 4 - ($sFlowSample->{MplsFtrDescrLength} % 4);
2511 0 0         $tmp == 4 and $tmp = 0;
2512              
2513 0           $offset += ($sFlowSample->{MplsFtrDescrLength} + $tmp);
2514              
2515 0           (undef, $sFlowSample->{MplsFtnMask}) = unpack("a$offset N", $sFlowDatagramPacked);
2516 0           $offset += 4;
2517              
2518             }
2519              
2520 0           $$offsetref = $offset;
2521 0           return (1, undef);
2522              
2523             }
2524              
2525              
2526             #############################################################################
2527             sub _decodeMplsLpvFec {
2528             #############################################################################
2529              
2530 0     0     my $offsetref = shift;
2531 0           my $sFlowDatagramPackedRef = shift;
2532 0           my $sFlowSample = shift;
2533              
2534 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
2535 0           my $offset = $$offsetref;
2536              
2537 0           $sFlowSample->{MPLSLPVFEC} = 'MPLSLPVFEC';
2538              
2539             (undef,
2540 0           $sFlowSample->{MplsFecAddrPrefixLength}) =
2541             unpack("a$offset N", $sFlowDatagramPacked);
2542              
2543 0           $offset += 4;
2544              
2545 0           $$offsetref = $offset;
2546             }
2547              
2548              
2549             #############################################################################
2550             sub _decodeVlanTunnel {
2551             #############################################################################
2552              
2553 0     0     my $offsetref = shift;
2554 0           my $sFlowDatagramPackedRef = shift;
2555 0           my $sFlowSample = shift;
2556              
2557 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
2558 0           my $offset = $$offsetref;
2559 0           my $error = undef;
2560              
2561 0           $sFlowSample->{VLANTUNNEL} = 'VLANTUNNEL';
2562              
2563             (undef,
2564 0           $sFlowSample->{VlanTunnelLayerStackCount}) =
2565             unpack("a$offset N", $sFlowDatagramPacked);
2566              
2567 0           $offset += 4;
2568              
2569             # boundcheck for $sFlowSample->{VlanTunnelLayerStackCount}
2570             # $sFlowSample->{VlanTunnelLayerStackCount} * 4
2571             # cannot be longer than the number of $sFlowDatagramPacked byte - $offset
2572              
2573 0 0         if (length($sFlowDatagramPacked) - $offset <
    0          
2574             $sFlowSample->{VlanTunnelLayerStackCount} * 4) {
2575              
2576             # error $sFlowSample->{VlanTunnelLayerStackCount} too big
2577 0           $error = "ERROR: [sFlow.pm] VlanTunnel: Vlan tunnel stack count too big "
2578             . "- rest of the datagram skipped";
2579              
2580 0           return (undef, $error);
2581              
2582             } elsif ($sFlowSample->{VlanTunnelLayerStackCount} < 0) {
2583              
2584             # error $sFlowSample->{VlanTunnelLayerStackCount} too small
2585 0           $error = "ERROR: [sFlow.pm] VlanTunnel: Vlan tunnel stack count too small "
2586             . "- rest of the datagram skipped";
2587              
2588 0           return (undef, $error);
2589              
2590             } else {
2591              
2592 0           my @VlanTunnelLayerStack = ();
2593 0           $sFlowSample->{VlanTunnelLayerStack} = \@VlanTunnelLayerStack;
2594              
2595 0           for my $VlanTunnelLayerCount (0 .. $sFlowSample->{VlanTunnelLayerStackCount} - 1) {
2596              
2597 0           (undef, my $VlanTunnelLayer) = unpack("a$offset N", $sFlowDatagramPacked);
2598 0           push @VlanTunnelLayerStack, $VlanTunnelLayer;
2599 0           $offset += 4;
2600             }
2601              
2602             }
2603              
2604 0           $$offsetref = $offset;
2605 0           return (1, undef);
2606              
2607             }
2608              
2609              
2610             #############################################################################
2611             sub _decodeCounterGeneric {
2612             #############################################################################
2613              
2614 0     0     my $offsetref = shift;
2615 0           my $sFlowDatagramPackedRef = shift;
2616 0           my $sFlowSample = shift;
2617              
2618 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
2619 0           my $offset = $$offsetref;
2620 0           my $ifStatus = undef;
2621              
2622 0           $sFlowSample->{COUNTERGENERIC} = 'COUNTERGENERIC';
2623              
2624             (undef,
2625             $sFlowSample->{ifIndex},
2626             $sFlowSample->{ifType},
2627             $sFlowSample->{ifSpeed}, # $Q
2628             $sFlowSample->{ifDirection},
2629             $ifStatus,
2630             $sFlowSample->{ifInOctets}, # $Q
2631             $sFlowSample->{ifInUcastPkts},
2632             $sFlowSample->{ifInMulticastPkts},
2633             $sFlowSample->{ifInBroadcastPkts},
2634             $sFlowSample->{ifInDiscards},
2635             $sFlowSample->{ifInErrors},
2636             $sFlowSample->{ifInUnknownProtos},
2637             $sFlowSample->{ifOutOctets}, # $Q
2638             $sFlowSample->{ifOutUcastPkts},
2639             $sFlowSample->{ifOutMulticastPkts},
2640             $sFlowSample->{ifOutBroadcastPkts},
2641             $sFlowSample->{ifOutDiscards},
2642             $sFlowSample->{ifOutErrors},
2643 0           $sFlowSample->{ifPromiscuousMode}) =
2644             unpack("a$offset N2${Q}N2${Q}N6${Q}N6", $sFlowDatagramPacked);
2645              
2646 0           $offset += 88;
2647              
2648 0 0         unless ($have_quad) {
2649 0           my $hex_val;
2650 0           $hex_val = unpack('H*', $sFlowSample->{ifSpeed});
2651 0           $sFlowSample->{ifSpeed} = Math::BigInt->from_hex("0x$hex_val");
2652              
2653 0           $hex_val = unpack('H*', $sFlowSample->{ifInOctets});
2654 0           $sFlowSample->{ifInOctets} = Math::BigInt->from_hex("0x$hex_val");
2655              
2656 0           $hex_val = unpack('H*', $sFlowSample->{ifOutOctets});
2657 0           $sFlowSample->{ifOutOctets} = Math::BigInt->from_hex("0x$hex_val");
2658             }
2659              
2660             # seperate the 32bit status
2661 0           $sFlowSample->{ifAdminStatus} = $ifStatus & 0x1;
2662 0           $sFlowSample->{ifOperStatus} = ($ifStatus >> 1) & 0x1;
2663              
2664 0           $$offsetref = $offset;
2665             }
2666              
2667              
2668             #############################################################################
2669             sub _decodeCounterEthernet {
2670             #############################################################################
2671              
2672 0     0     my $offsetref = shift;
2673 0           my $sFlowDatagramPackedRef = shift;
2674 0           my $sFlowSample = shift;
2675              
2676 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
2677 0           my $offset = $$offsetref;
2678              
2679 0           $sFlowSample->{COUNTERETHERNET} = 'COUNTERETHERNET';
2680              
2681             (undef,
2682             $sFlowSample->{dot3StatsAlignmentErrors},
2683             $sFlowSample->{dot3StatsFCSErrors},
2684             $sFlowSample->{dot3StatsSingleCollisionFrames},
2685             $sFlowSample->{dot3StatsMultipleCollisionFrames},
2686             $sFlowSample->{dot3StatsSQETestErrors},
2687             $sFlowSample->{dot3StatsDeferredTransmissions},
2688             $sFlowSample->{dot3StatsLateCollisions},
2689             $sFlowSample->{dot3StatsExcessiveCollisions},
2690             $sFlowSample->{dot3StatsInternalMacTransmitErrors},
2691             $sFlowSample->{dot3StatsCarrierSenseErrors},
2692             $sFlowSample->{dot3StatsFrameTooLongs},
2693             $sFlowSample->{dot3StatsInternalMacReceiveErrors},
2694 0           $sFlowSample->{dot3StatsSymbolErrors}) =
2695             unpack("a$offset N13", $sFlowDatagramPacked);
2696              
2697 0           $offset += 52;
2698 0           $$offsetref = $offset;
2699             }
2700              
2701              
2702             #############################################################################
2703             sub _decodeCounterTokenring {
2704             #############################################################################
2705              
2706 0     0     my $offsetref = shift;
2707 0           my $sFlowDatagramPackedRef = shift;
2708 0           my $sFlowSample = shift;
2709              
2710 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
2711 0           my $offset = $$offsetref;
2712              
2713 0           $sFlowSample->{COUNTERTOKENRING} = 'COUNTERTOKENRING';
2714              
2715             (undef,
2716             $sFlowSample->{dot5StatsLineErrors},
2717             $sFlowSample->{dot5StatsBurstErrors},
2718             $sFlowSample->{dot5StatsACErrors},
2719             $sFlowSample->{dot5StatsAbortTransErrors},
2720             $sFlowSample->{dot5StatsInternalErrors},
2721             $sFlowSample->{dot5StatsLostFrameErrors},
2722             $sFlowSample->{dot5StatsReceiveCongestions},
2723             $sFlowSample->{dot5StatsFrameCopiedErrors},
2724             $sFlowSample->{dot5StatsTokenErrors},
2725             $sFlowSample->{dot5StatsSoftErrors},
2726             $sFlowSample->{dot5StatsHardErrors},
2727             $sFlowSample->{dot5StatsSignalLoss},
2728             $sFlowSample->{dot5StatsTransmitBeacons},
2729             $sFlowSample->{dot5StatsRecoverys},
2730             $sFlowSample->{dot5StatsLobeWires},
2731             $sFlowSample->{dot5StatsRemoves},
2732             $sFlowSample->{dot5StatsSingles},
2733 0           $sFlowSample->{dot5StatsFreqErrors}) =
2734             unpack("a$offset N18", $sFlowDatagramPacked);
2735              
2736 0           $offset += 72;
2737 0           $$offsetref = $offset;
2738             }
2739              
2740              
2741             #############################################################################
2742             sub _decodeCounterVg {
2743             #############################################################################
2744              
2745 0     0     my $offsetref = shift;
2746 0           my $sFlowDatagramPackedRef = shift;
2747 0           my $sFlowSample = shift;
2748              
2749 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
2750 0           my $offset = $$offsetref;
2751              
2752 0           $sFlowSample->{COUNTERVG} = 'COUNTERVG';
2753              
2754             (undef,
2755             $sFlowSample->{dot12InHighPriorityFrames},
2756             $sFlowSample->{dot12InHighPriorityOctets}, # $Q
2757             $sFlowSample->{dot12InNormPriorityFrames},
2758             $sFlowSample->{dot12InNormPriorityOctets}, # $Q
2759             $sFlowSample->{dot12InIPMErrors},
2760             $sFlowSample->{dot12InOversizeFrameErrors},
2761             $sFlowSample->{dot12InDataErrors},
2762             $sFlowSample->{dot12InNullAddressedFrames},
2763             $sFlowSample->{dot12OutHighPriorityFrames},
2764             $sFlowSample->{dot12OutHighPriorityOctets}, # $Q
2765             $sFlowSample->{dot12TransitionIntoTrainings},
2766             $sFlowSample->{dot12HCInHighPriorityOctets}, # $Q
2767             $sFlowSample->{dot12HCInNormPriorityOctets}, # $Q
2768             $sFlowSample->{dot12HCOutHighPriorityOctets}, # $Q
2769 0           ) =
2770             unpack("a$offset N${Q}N${Q}N5${Q}N${Q}3", $sFlowDatagramPacked);
2771              
2772 0           $offset += 80;
2773              
2774 0 0         unless ($have_quad) {
2775 0           my $hex_val;
2776 0           $hex_val = unpack( 'H*', $sFlowSample->{dot12InHighPriorityOctets} );
2777             $sFlowSample->{dot12InHighPriorityOctets}
2778 0           = Math::BigInt->from_hex("0x$hex_val");
2779              
2780 0           $hex_val = unpack( 'H*', $sFlowSample->{dot12InNormPriorityOctets} );
2781             $sFlowSample->{dot12InNormPriorityOctets}
2782 0           = Math::BigInt->from_hex("0x$hex_val");
2783              
2784 0           $hex_val = unpack( 'H*', $sFlowSample->{dot12OutHighPriorityOctets} );
2785             $sFlowSample->{dot12OutHighPriorityOctets}
2786 0           = Math::BigInt->from_hex("0x$hex_val");
2787              
2788 0           $hex_val = unpack( 'H*', $sFlowSample->{dot12HCInHighPriorityOctets} );
2789             $sFlowSample->{dot12HCInHighPriorityOctets}
2790 0           = Math::BigInt->from_hex("0x$hex_val");
2791              
2792 0           $hex_val = unpack( 'H*', $sFlowSample->{dot12HCInNormPriorityOctets} );
2793             $sFlowSample->{dot12HCInNormPriorityOctets}
2794 0           = Math::BigInt->from_hex("0x$hex_val");
2795              
2796 0           $hex_val = unpack( 'H*', $sFlowSample->{dot12HCOutHighPriorityOctets} );
2797             $sFlowSample->{dot12HCOutHighPriorityOctets}
2798 0           = Math::BigInt->from_hex("0x$hex_val");
2799             }
2800              
2801 0           $$offsetref = $offset;
2802             }
2803              
2804              
2805             #############################################################################
2806             sub _decodeCounterVlan {
2807             #############################################################################
2808              
2809 0     0     my $offsetref = shift;
2810 0           my $sFlowDatagramPackedRef = shift;
2811 0           my $sFlowSample = shift;
2812              
2813 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
2814 0           my $offset = $$offsetref;
2815              
2816 0           $sFlowSample->{COUNTERVLAN} = 'COUNTERVLAN';
2817              
2818             (undef,
2819             $sFlowSample->{vlan_id},
2820             $sFlowSample->{octets}, # $Q
2821             $sFlowSample->{ucastPkts},
2822             $sFlowSample->{multicastPkts},
2823             $sFlowSample->{broadcastPkts},
2824 0           $sFlowSample->{discards}) =
2825             unpack("a$offset N${Q}N4", $sFlowDatagramPacked);
2826              
2827 0           $offset += 28;
2828              
2829 0 0         unless ($have_quad) {
2830 0           my $hex_val;
2831 0           $hex_val = unpack( 'H*', $sFlowSample->{octets} );
2832 0           $sFlowSample->{octets} = Math::BigInt->from_hex("0x$hex_val");
2833             }
2834 0           $$offsetref = $offset;
2835             }
2836              
2837              
2838             #############################################################################
2839             sub _decodeCounterLag {
2840             #############################################################################
2841              
2842 0     0     my $offsetref = shift;
2843 0           my $sFlowDatagramPackedRef = shift;
2844 0           my $sFlowSample = shift;
2845              
2846 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
2847 0           my $offset = $$offsetref;
2848              
2849 0           $sFlowSample->{COUNTERLAG} = 'COUNTERLAG';
2850              
2851             (undef,
2852             $sFlowSample->{dot3adAggPortActorSystemID},
2853             $sFlowSample->{dot3adAggPortPartnerOperSystemID},
2854             $sFlowSample->{dot3adAggPortAttachedAggID},
2855             $sFlowSample->{dot3adAggPortActorAdminState},
2856             $sFlowSample->{dot3adAggPortActorOperState},
2857             $sFlowSample->{dot3adAggPortPartnerAdminState},
2858             $sFlowSample->{dot3adAggPortPartnerOperState},
2859             $sFlowSample->{dot3adAggPortStatsLACPDUsRx},
2860             $sFlowSample->{dot3adAggPortStatsMarkerPDUsRx},
2861             $sFlowSample->{dot3adAggPortStatsMarkerResponsePDUsRx},
2862             $sFlowSample->{dot3adAggPortStatsUnknownRx},
2863             $sFlowSample->{dot3adAggPortStatsIllegalRx},
2864             $sFlowSample->{dot3adAggPortStatsLACPDUsTx},
2865             $sFlowSample->{dot3adAggPortStatsMarkerPDUsTx},
2866 0           $sFlowSample->{dot3adAggPortStatsMarkerResponsePDUsTx}) =
2867             unpack("a$offset (a6x2)2NC4N8", $sFlowDatagramPacked);
2868              
2869 0           $offset += 56;
2870              
2871             # format MAC addresses as hex (ignore final 2 padding bytes)
2872 0           map { $_ = unpack 'H12' } ( @{$sFlowSample}{qw{dot3adAggPortActorSystemID dot3adAggPortPartnerOperSystemID}} );
  0            
  0            
2873              
2874 0           $$offsetref = $offset;
2875             }
2876              
2877             #############################################################################
2878             sub _decodeCounterHTTP {
2879             #############################################################################
2880              
2881 0     0     my $offsetref = shift;
2882 0           my $sFlowDatagramPackedRef = shift;
2883 0           my $sFlowSample = shift;
2884              
2885 0           my $offset = $$offsetref;
2886              
2887 0           $sFlowSample->{COUNTERHTTP} = 'COUNTERHTTP';
2888             (undef,
2889             $sFlowSample->{methodOptionCount},
2890             $sFlowSample->{methodGetCount},
2891             $sFlowSample->{methodHeadCount},
2892             $sFlowSample->{methodPostCount},
2893             $sFlowSample->{methodPutCount},
2894             $sFlowSample->{methodDeleteCount},
2895             $sFlowSample->{methodTraceCount},
2896             $sFlowSample->{methodConnectCount},
2897             $sFlowSample->{methodOtherCount},
2898             $sFlowSample->{status1xxCount},
2899             $sFlowSample->{status2xxCount},
2900             $sFlowSample->{status3xxCount},
2901             $sFlowSample->{status4xxCount},
2902             $sFlowSample->{status5xxCount},
2903             $sFlowSample->{statusOtherCount},
2904 0           ) = unpack("a$offset N15", $$sFlowDatagramPackedRef);
2905              
2906 0           $offset += 60;
2907 0           $$offsetref = $offset;
2908             }
2909              
2910              
2911             #############################################################################
2912             sub _decodeCounterProcessor {
2913             #############################################################################
2914              
2915 0     0     my $offsetref = shift;
2916 0           my $sFlowDatagramPackedRef = shift;
2917 0           my $sFlowSample = shift;
2918              
2919 0           my $sFlowDatagramPacked = $$sFlowDatagramPackedRef;
2920 0           my $offset = $$offsetref;
2921 0           my $memoryTotal1 = undef;
2922 0           my $memoryTotal2 = undef;
2923 0           my $memoryFree1 = undef;
2924 0           my $memoryFree2 = undef;
2925              
2926 0           $sFlowSample->{COUNTERPROCESSOR} = 'COUNTERPROCESSOR';
2927              
2928             (undef,
2929             $sFlowSample->{cpu5s},
2930             $sFlowSample->{cpu1m},
2931             $sFlowSample->{cpu5m},
2932             $sFlowSample->{memoryTotal}, # $Q
2933             $sFlowSample->{memoryFree}, # $Q
2934 0           ) =
2935             unpack("a$offset N3${Q}2", $sFlowDatagramPacked);
2936              
2937 0           $offset += 28;
2938              
2939 0 0         unless ($have_quad) {
2940 0           my $hex_val;
2941 0           $hex_val = unpack( 'H*', $sFlowSample->{memoryTotal} );
2942 0           $sFlowSample->{memoryTotal} = Math::BigInt->from_hex("0x$hex_val");
2943              
2944 0           $hex_val = unpack( 'H*', $sFlowSample->{memoryFree} );
2945 0           $sFlowSample->{memoryFree} = Math::BigInt->from_hex("0x$hex_val");
2946             }
2947              
2948 0           $$offsetref = $offset;
2949             }
2950              
2951              
2952             1;
2953              
2954              
2955             __END__