line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::Traces::TSH; |
2
|
|
|
|
|
|
|
|
3
|
9
|
|
|
9
|
|
80088
|
use 5.6.1; |
|
9
|
|
|
|
|
31
|
|
|
9
|
|
|
|
|
382
|
|
4
|
9
|
|
|
9
|
|
46
|
use strict; |
|
9
|
|
|
|
|
19
|
|
|
9
|
|
|
|
|
357
|
|
5
|
9
|
|
|
9
|
|
50
|
use warnings; |
|
9
|
|
|
|
|
22
|
|
|
9
|
|
|
|
|
347
|
|
6
|
9
|
|
|
9
|
|
8088
|
use autouse 'Carp' => qw(carp croak confess); |
|
9
|
|
|
|
|
15324
|
|
|
9
|
|
|
|
|
50
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = 0.16; |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 NAME |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
Net::Traces::TSH - Analyze IP traffic traces in TSH format |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 SYNOPSIS |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
use Net::Traces::TSH qw(:traffic_analysis); |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# Display progress indicators |
19
|
|
|
|
|
|
|
# |
20
|
|
|
|
|
|
|
verbose; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# Process the trace in file some_trace.tsh |
23
|
|
|
|
|
|
|
# |
24
|
|
|
|
|
|
|
process_trace 'some_trace.tsh'; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# Then, write a summary of the trace contents to some_trace.csv, in |
27
|
|
|
|
|
|
|
# comma-separated values (CSV) format |
28
|
|
|
|
|
|
|
# |
29
|
|
|
|
|
|
|
write_trace_summary 'some_trace.csv'; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=cut |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
require Exporter; |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
our @ISA = qw( Exporter ); |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
our @EXPORT = qw( ); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# Exportable subroutine definitions |
40
|
|
|
|
|
|
|
# |
41
|
|
|
|
|
|
|
sub configure( % ); |
42
|
|
|
|
|
|
|
sub date_of( $ ); |
43
|
|
|
|
|
|
|
sub get_IP_address ( $ ); |
44
|
|
|
|
|
|
|
sub get_interfaces_href(); |
45
|
|
|
|
|
|
|
sub get_interfaces_list(); |
46
|
|
|
|
|
|
|
sub get_trace_summary_href(); |
47
|
|
|
|
|
|
|
sub process_trace( $ ); |
48
|
|
|
|
|
|
|
sub records_in( $ ); |
49
|
|
|
|
|
|
|
sub verbose(); |
50
|
|
|
|
|
|
|
sub write_interface_summaries( ; $); |
51
|
|
|
|
|
|
|
sub write_trace_summary( ; $ ); |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
our @EXPORT_OK = qw( |
54
|
|
|
|
|
|
|
configure |
55
|
|
|
|
|
|
|
date_of |
56
|
|
|
|
|
|
|
get_IP_address |
57
|
|
|
|
|
|
|
get_interfaces_href |
58
|
|
|
|
|
|
|
get_interfaces_list |
59
|
|
|
|
|
|
|
get_trace_summary_href |
60
|
|
|
|
|
|
|
numerically |
61
|
|
|
|
|
|
|
process_trace |
62
|
|
|
|
|
|
|
records_in |
63
|
|
|
|
|
|
|
verbose |
64
|
|
|
|
|
|
|
write_interface_summaries |
65
|
|
|
|
|
|
|
write_trace_summary |
66
|
|
|
|
|
|
|
); |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( |
69
|
|
|
|
|
|
|
traffic_analysis => [ qw( verbose |
70
|
|
|
|
|
|
|
process_trace |
71
|
|
|
|
|
|
|
write_interface_summaries |
72
|
|
|
|
|
|
|
write_trace_summary |
73
|
|
|
|
|
|
|
) |
74
|
|
|
|
|
|
|
], |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
trace_information => [ qw( date_of records_in ) ], |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
all => [@EXPORT_OK], |
79
|
|
|
|
|
|
|
); |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# Internal/utility subroutine definitions |
82
|
|
|
|
|
|
|
# |
83
|
|
|
|
|
|
|
sub progress( $ ); |
84
|
|
|
|
|
|
|
sub write_summary( *$ ; $ ); |
85
|
|
|
|
|
|
|
sub print_value( *$ ); |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
our %options; |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# Load the IANA protocol numbers from the __DATA__ section. If by any |
90
|
|
|
|
|
|
|
# chance we end up having duplicate keywords, something must have |
91
|
|
|
|
|
|
|
# corrupted the __DATA__ section, so abort. |
92
|
|
|
|
|
|
|
# |
93
|
|
|
|
|
|
|
my %iana_protocol_numbers; |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
INIT { |
96
|
9
|
|
|
9
|
|
67
|
while () { |
97
|
1260
|
|
|
|
|
1358
|
chomp; |
98
|
1260
|
|
|
|
|
2548
|
my ($k, $v) = split " ", $_, 2; |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# Sanity check |
101
|
|
|
|
|
|
|
# |
102
|
1260
|
50
|
|
|
|
2519
|
die "Duplicate IANA protocol keyword detected" |
103
|
|
|
|
|
|
|
if defined $iana_protocol_numbers{$k}; |
104
|
|
|
|
|
|
|
|
105
|
1260
|
|
|
|
|
6151
|
$iana_protocol_numbers{$k} = $v; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
# Default options, parameters and output |
109
|
|
|
|
|
|
|
# |
110
|
|
|
|
|
|
|
%options = ( |
111
|
|
|
|
|
|
|
# Do not display progress information |
112
|
9
|
|
|
|
|
726
|
Verbosity => 0, |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
'Link Capacity' => 0, # Bits per second |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# Filename to store TCP traffic in tcpdump format |
117
|
|
|
|
|
|
|
tcpdump => 0, |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# Filename to store TCP traffic in ns2 format |
120
|
|
|
|
|
|
|
ns2 => 0, |
121
|
|
|
|
|
|
|
); |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
# Used to sort the keys of a hash in numeric order instead of the |
125
|
|
|
|
|
|
|
# default alphabetical order. Borrowed from "Programming Perl 3/e" by |
126
|
|
|
|
|
|
|
# Wall, Christiansen and Orwant (p. 790). |
127
|
|
|
|
|
|
|
# |
128
|
1635
|
|
|
1635
|
0
|
2038
|
sub numerically { $a <=> $b; } |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=head1 INSTALLATION |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
C can be installed like any CPAN module. In |
133
|
|
|
|
|
|
|
particular, consider using Andreas Koenig's CPAN module for all your |
134
|
|
|
|
|
|
|
CPAN module installation needs. |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
To find out more about installing CPAN modules type |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
perldoc perlmodinstall |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
at the command prompt. |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
If you have already downloaded the C tarball, |
143
|
|
|
|
|
|
|
decompress and untar it, and proceed as follows: |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
perl Makefile.PL |
146
|
|
|
|
|
|
|
make |
147
|
|
|
|
|
|
|
make test |
148
|
|
|
|
|
|
|
make install |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=head1 DESCRIPTION |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
C can assist you in analyzing Internet Protocol (IP) |
153
|
|
|
|
|
|
|
packet traces in Time Sequenced Headers (TSH) format, a binary network |
154
|
|
|
|
|
|
|
trace format. Daily TSH traces are available from the L
|
155
|
|
|
|
|
|
|
site|"SEE ALSO">. Each 44-byte TSH record corresponds to an IP packet |
156
|
|
|
|
|
|
|
passing by a monitoring point. Although there are no explicit |
157
|
|
|
|
|
|
|
delimiters, each record is composed of three sections. |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=over |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=item Time and Interface |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
The first section uses 8 bytes to store the time (with microsecond |
164
|
|
|
|
|
|
|
granularity) and the interface number of the corresponding packet, as |
165
|
|
|
|
|
|
|
recorded by the (passive) monitor. |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=item IP |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
The next 20 bytes contain the standard IP packet header. IP options |
170
|
|
|
|
|
|
|
are not recorded. |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=item TCP |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
The third and last section contains the first 16 bytes of the standard |
175
|
|
|
|
|
|
|
TCP segment header. The TCP checksum, urgent pointer, and TCP options |
176
|
|
|
|
|
|
|
(if any) are not included in a TSH record. |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=back |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
If a record does not correspond to a TCP segment, it is not clear how |
181
|
|
|
|
|
|
|
to interpret the last section. As such, C makes no |
182
|
|
|
|
|
|
|
assumptions, and does not analyze the last section of a TSH record |
183
|
|
|
|
|
|
|
unless it corresponds to a TCP segment. In other words, |
184
|
|
|
|
|
|
|
C reports on protocols other than TCP based solely |
185
|
|
|
|
|
|
|
on the first two sections. |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
The following diagram illustrates a TSH record. |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
0 1 2 3 |
190
|
|
|
|
|
|
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 Section |
191
|
|
|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
192
|
|
|
|
|
|
|
0 | Timestamp (seconds) | Time |
193
|
|
|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
194
|
|
|
|
|
|
|
1 | Interface No.| Timestamp (microseconds) | |
195
|
|
|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
196
|
|
|
|
|
|
|
2 |Version| IHL |Type of Service| Total Length | IP |
197
|
|
|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
198
|
|
|
|
|
|
|
3 | Identification |Flags| Fragment Offset | |
199
|
|
|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
200
|
|
|
|
|
|
|
4 | Time to Live | Protocol | Header Checksum | |
201
|
|
|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
202
|
|
|
|
|
|
|
5 | Source Address | |
203
|
|
|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
204
|
|
|
|
|
|
|
6 | Destination Address | |
205
|
|
|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
206
|
|
|
|
|
|
|
7 | Source Port | Destination Port | TCP |
207
|
|
|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
208
|
|
|
|
|
|
|
8 | Sequence Number | |
209
|
|
|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
210
|
|
|
|
|
|
|
9 | Acknowledgment Number | |
211
|
|
|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
212
|
|
|
|
|
|
|
| Data | |C|E|U|A|P|R|S|F| | |
213
|
|
|
|
|
|
|
10 | Offset|RSRV-ed|W|C|R|C|S|S|Y|I| Window | |
214
|
|
|
|
|
|
|
| | |R|E|G|K|H|T|N|N| | |
215
|
|
|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
This diagram is an adaptation of the original TSH diagram (found on |
218
|
|
|
|
|
|
|
the L), which reflects the changes due |
219
|
|
|
|
|
|
|
to the addition of Explicit Congestion Notification (ECN) in the TCP |
220
|
|
|
|
|
|
|
header flags. Also, keep in mind that recent Internet Engineering |
221
|
|
|
|
|
|
|
Task Force (IETF) Requests for Comments (RFCs) have deprecated the IP |
222
|
|
|
|
|
|
|
header I field in favor of L
|
223
|
|
|
|
|
|
|
and Explicit Congestion Notification|"SEE ALSO">. |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
You can use C to L
|
226
|
|
|
|
|
|
|
information|"process_trace"> from a TSH packet trace, perform |
227
|
|
|
|
|
|
|
statistical analysis on Transport protocol, Differentiated Services |
228
|
|
|
|
|
|
|
(DiffServ) and ECN usage, and obtain packet and segment size |
229
|
|
|
|
|
|
|
distributions. The trace L |
230
|
|
|
|
|
|
|
are stored in comma separated values (CSV), a platform independent |
231
|
|
|
|
|
|
|
text format. |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=head2 Data Structures |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
A single TSH trace may contain records for packets observed on several |
236
|
|
|
|
|
|
|
different interfaces. For example, the daily TSH traces from the |
237
|
|
|
|
|
|
|
NLANR PMA repository typically contain records from two different |
238
|
|
|
|
|
|
|
interfaces. In such cases, incoming and outgoing traffic can be |
239
|
|
|
|
|
|
|
differentiated based on the interface number (despite the scrabbling of |
240
|
|
|
|
|
|
|
IP addresses to protect privacy). C users may be |
241
|
|
|
|
|
|
|
interested in collecting statistical information for each interface |
242
|
|
|
|
|
|
|
separately or aggregating across the entire trace. |
243
|
|
|
|
|
|
|
C uses two hashes to maintain these statistics: |
244
|
|
|
|
|
|
|
%Interfaces and %Trace. |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
B<%Interfaces> contains counts of several protocol particulars on a |
247
|
|
|
|
|
|
|
per-interface basis. For example, %Interfaces can tell you how many |
248
|
|
|
|
|
|
|
IP packets, TCP segments, and UDP datagrams were recorded in the trace |
249
|
|
|
|
|
|
|
for each interface. |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
B<%Trace> contains general information about the trace (date, number |
252
|
|
|
|
|
|
|
of records, duration, number of interfaces, etc.) as well as the |
253
|
|
|
|
|
|
|
aggregate data points across all interfaces. As such, %Trace will |
254
|
|
|
|
|
|
|
report the I number of UDP datagrams in the trace, the total |
255
|
|
|
|
|
|
|
number of TCP SYNs, and so on. |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
Both %Trace and %Interfaces are I by |
258
|
|
|
|
|
|
|
L. The recommended way to get the |
259
|
|
|
|
|
|
|
trace summary information, after processing a trace is to call |
260
|
|
|
|
|
|
|
L, which stores the |
261
|
|
|
|
|
|
|
contents of %Trace in a CSV-formated text file, as shown in |
262
|
|
|
|
|
|
|
L. Similarly, If you want summaries for the |
263
|
|
|
|
|
|
|
traffic on each interface, use |
264
|
|
|
|
|
|
|
L. |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
Neither %Trace nor %Interfaces are exported by default and are not |
267
|
|
|
|
|
|
|
meant to be accessed directly by user code. However, if you know what |
268
|
|
|
|
|
|
|
you are doing, you can get a reference to %Trace by calling |
269
|
|
|
|
|
|
|
L, and a reference to |
270
|
|
|
|
|
|
|
%Interfaces by calling L. |
271
|
|
|
|
|
|
|
If you choose to do so, the following subsections explain how you can |
272
|
|
|
|
|
|
|
access some of the information stored in %Trace. The %Interfaces |
273
|
|
|
|
|
|
|
structure is virtually the same only lacking the "general trace |
274
|
|
|
|
|
|
|
information" part. See also L
|
275
|
|
|
|
|
|
|
hashes|"Using the Net::Trace::TSH trace summary hashes">. |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=head3 General Trace Information |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
=over |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=item $Trace{filename} |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
The L. |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
=item $Trace{date} |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
The estimated date of the trace (see L). |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=item $Trace{summary} |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
The trace L. |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
=item $Trace{starts} |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
The first trace timestamp, in seconds, as it is recorded in the trace. |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
=item $Trace{ends} |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
The last trace timestamp, in seconds, after being "normalized". |
300
|
|
|
|
|
|
|
Essentially, the number of seconds since $Trace{starts}. |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
=item $Trace{records} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
L in the trace. |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
Similarly, if I<$if> is the interface number, |
307
|
|
|
|
|
|
|
C<$Interfaces{$if}{records}> contains the number or records |
308
|
|
|
|
|
|
|
corresponding to packets observed on interface I<$if>. |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=item $Trace{interfaces} |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
Number of interfaces recorded in the trace. |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=item $Trace{unidirectional} |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
True, if each interface carries unidirectional traffic. |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
False, if there is bidirectional traffic in at least one interface. |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
C if traffic directionality was not examined. |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=item $Trace{'Link Capacity'} |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
The L in bits per |
325
|
|
|
|
|
|
|
second (b/s). |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
=back |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=head3 Internet Protocol |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
=over |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=item $Trace{IP}{Total}{Packets} |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
=item $Trace{IP}{Total}{Bytes} |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
Number of IP packets and bytes, respectively, in the trace. The |
338
|
|
|
|
|
|
|
number of IP packets should equal the number of records in the trace. |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
As mentioned earlier, %Trace has virtually the same structure as |
341
|
|
|
|
|
|
|
%Interfaces. Therefore, if I<$if> is the interface number, |
342
|
|
|
|
|
|
|
C<$Interfaces{$if}{IP}{Total}{Packets}> and |
343
|
|
|
|
|
|
|
C<$Interfaces{$if}{IP}{Total}{Bytes}> contain the number of IP |
344
|
|
|
|
|
|
|
packets and bytes, respectively, observed on interface I<$if>. The |
345
|
|
|
|
|
|
|
same "rule" applies to all %Trace fields presented below. |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
=back |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=head4 Fragmentation |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
=over |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
=item $Trace{IP}{DF}{Packets} |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
=item $Trace{IP}{DF}{Bytes} |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
Number of IP packets and bytes, respectively, requesting no |
358
|
|
|
|
|
|
|
fragmentation ('Do not Fragment'). |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
=item $Trace{IP}{MF}{Packets} |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
=item $Trace{IP}{MF}{Bytes} |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
Number of IP packets and bytes, respectively, indicating that 'More |
365
|
|
|
|
|
|
|
Fragments' follow. |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
=back |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=head4 Differentiated Services |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=over |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=item $Trace{IP}{Normal}{Packets} |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=item $Trace{IP}{Normal}{Bytes} |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
Number of IP packets and bytes, respectively, requesting no particular |
378
|
|
|
|
|
|
|
treatment (best effort traffic). No DiffServ or ECN bits are set. |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
=item $Trace{IP}{'Class Selector'}{Packets} |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
=item $Trace{IP}{'Class Selector Bytes'} |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
Number of IP packets and bytes, respectively, with Class Selector bits |
385
|
|
|
|
|
|
|
set. |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
=item $Trace{IP}{'AF PHB Packets'} |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
=item $Trace{IP}{'AF PHB Bytes'} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
Number of IP packets and bytes, respectively, requesting Assured |
392
|
|
|
|
|
|
|
Forwarding Per-Hop Behavior (PHB). |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
=item $Trace{IP}{'EF PHB'}{Packets} |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
=item $Trace{IP}{'EF PHB'}{Bytes} |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
Number of IP packets and bytes, respectively, requesting Expedited |
399
|
|
|
|
|
|
|
Forwarding Per-Hop Behavior (PHB) |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=back |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
=head4 Explicit Congestion Notification |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
=over |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
=item $Trace{IP}{ECT}{Packets} |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
=item $Trace{IP}{ECT}{Bytes} |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
Number of IP packets and bytes, respectively, with either of the ECT |
412
|
|
|
|
|
|
|
bits set. These packets should be carrying traffic from ECN-aware |
413
|
|
|
|
|
|
|
hosts. |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
=item $Trace{IP}{CE}{Packets} |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
=item $Trace{IP}{CE}{Bytes} |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
Number of IP packets and bytes, respectively, with the CE bit set. |
420
|
|
|
|
|
|
|
These packets carry ECN-capable traffic that has been marked at an |
421
|
|
|
|
|
|
|
ECN-aware router. |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
=back |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
=head4 IP Options |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
=over |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
=item $Trace{IP}{'No IP Options'}{Packets} |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
=item $Trace{IP}{'No IP Options'}{Bytes} |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
Number of IP packets and bytes, respectively, carrying no IP header options. |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=item $Trace{IP}{'IP Options'}{Packets} |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
=item $Trace{IP}{'IP Options'}{Bytes} |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
Number of IP packets and bytes, respectively, carrying IP header options. |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
=back |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
The following diagram summarizes the %Trace data structure up to here. |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
Trace |
446
|
|
|
|
|
|
|
- filename |
447
|
|
|
|
|
|
|
- summary |
448
|
|
|
|
|
|
|
- date |
449
|
|
|
|
|
|
|
- starts |
450
|
|
|
|
|
|
|
- ends |
451
|
|
|
|
|
|
|
- records |
452
|
|
|
|
|
|
|
- interfaces |
453
|
|
|
|
|
|
|
- unidirectional |
454
|
|
|
|
|
|
|
- 'Link Capacity' |
455
|
|
|
|
|
|
|
- IP |
456
|
|
|
|
|
|
|
- Total |
457
|
|
|
|
|
|
|
- Packets |
458
|
|
|
|
|
|
|
- Bytes |
459
|
|
|
|
|
|
|
- DF |
460
|
|
|
|
|
|
|
- Packets |
461
|
|
|
|
|
|
|
- Bytes |
462
|
|
|
|
|
|
|
- MF |
463
|
|
|
|
|
|
|
- Packets |
464
|
|
|
|
|
|
|
- Bytes |
465
|
|
|
|
|
|
|
- Normal |
466
|
|
|
|
|
|
|
- Packets |
467
|
|
|
|
|
|
|
- Bytes |
468
|
|
|
|
|
|
|
- 'Class Selector' |
469
|
|
|
|
|
|
|
- Packets |
470
|
|
|
|
|
|
|
- Bytes |
471
|
|
|
|
|
|
|
- 'AF PHB' |
472
|
|
|
|
|
|
|
- Packets |
473
|
|
|
|
|
|
|
- Bytes |
474
|
|
|
|
|
|
|
- 'EF PHB' |
475
|
|
|
|
|
|
|
- Packets |
476
|
|
|
|
|
|
|
- Bytes |
477
|
|
|
|
|
|
|
- ECT |
478
|
|
|
|
|
|
|
- Packets |
479
|
|
|
|
|
|
|
- Bytes |
480
|
|
|
|
|
|
|
- CE |
481
|
|
|
|
|
|
|
- Packets |
482
|
|
|
|
|
|
|
- Bytes |
483
|
|
|
|
|
|
|
- 'No IP Options' |
484
|
|
|
|
|
|
|
- Packets |
485
|
|
|
|
|
|
|
- Bytes |
486
|
|
|
|
|
|
|
- 'IP Options' |
487
|
|
|
|
|
|
|
- Packets |
488
|
|
|
|
|
|
|
- Bytes |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
=head3 Transport Protocols |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
Besides the summary information about the trace itself and statistics |
493
|
|
|
|
|
|
|
about IP, %Trace maintains information about the transport protocols |
494
|
|
|
|
|
|
|
present in the trace. Based on the IP header, %Trace maintains the |
495
|
|
|
|
|
|
|
same statistics mentioned in the L
|
496
|
|
|
|
|
|
|
Protocol"> for all transport protocols with an IANA assigned number |
497
|
|
|
|
|
|
|
(including, of course, TCP and UDP). For example, |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
=over |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
=item $Trace{Transport}{TCP}{Total}{Packets} |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
=item $Trace{Transport}{TCP}{Total}{Bytes} |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
Number of TCP segments and the corresponding bytes (including the IP |
506
|
|
|
|
|
|
|
and TCP headers) in the trace. |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=item $Trace{Transport}{UDP}{Total}{Packets} |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
=item $Trace{Transport}{UDP}{Total}{Bytes} |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
Ditto, for UDP. |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=item $Trace{Transport}{ICMP}{DF}{Packets} |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
=item $Trace{Transport}{ICMP}{DF}{Bytes} |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
Number of ICMP packets and bytes, respectively, with the DF bit set. |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
=back |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
=head2 Using the Net::Trace::TSH trace summary hashes |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
The following example creates the trace summary file only if TCP |
525
|
|
|
|
|
|
|
accounts for more than 90% of the total IP traffic, in terms of bytes. |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
# Explicitly import process_trace(), write_trace_summary(), and |
528
|
|
|
|
|
|
|
# get_trace_summary_href(): |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
use Net::Traces::TSH qw( process_trace |
531
|
|
|
|
|
|
|
write_trace_summary |
532
|
|
|
|
|
|
|
get_trace_summary_href |
533
|
|
|
|
|
|
|
); |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
# Process a trace file... |
536
|
|
|
|
|
|
|
# |
537
|
|
|
|
|
|
|
process_trace "some.tsh"; |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
# Get a reference to %Trace |
540
|
|
|
|
|
|
|
# |
541
|
|
|
|
|
|
|
my $ts_href = get_trace_summary_href; |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
# ...and generate a summary only if the condition is met. |
544
|
|
|
|
|
|
|
# |
545
|
|
|
|
|
|
|
write_trace_summary |
546
|
|
|
|
|
|
|
if ( ( $ts_href->{Transport}{TCP}{Total}{Bytes} |
547
|
|
|
|
|
|
|
/ $ts_href->{IP}{Total}{Bytes} |
548
|
|
|
|
|
|
|
) > 0.9 |
549
|
|
|
|
|
|
|
); |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=cut |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
# Hash containing aggregate (across all interfaces) information about |
554
|
|
|
|
|
|
|
# the trace currently being processed. Daily TSH traces from NLANR |
555
|
|
|
|
|
|
|
# PMA usually contain records from two interfaces (incoming and |
556
|
|
|
|
|
|
|
# outgoing). |
557
|
|
|
|
|
|
|
# |
558
|
|
|
|
|
|
|
my %Trace; |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
# Hash containing per-interface information about the trace currently |
561
|
|
|
|
|
|
|
# being processed. |
562
|
|
|
|
|
|
|
# |
563
|
|
|
|
|
|
|
my %Interfaces; |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
# Make sure that all data points are accounted for and are in correct |
566
|
|
|
|
|
|
|
# order, thus saving some of hash key sorting operations. Moreover, |
567
|
|
|
|
|
|
|
# this allows us to use more descriptive, i.e. self-documenting hash |
568
|
|
|
|
|
|
|
# key names for the data hashes, %Trace and %Interfaces. |
569
|
|
|
|
|
|
|
# |
570
|
|
|
|
|
|
|
my @data_points = ( 'Total', 'DF', 'MF', 'ECT', 'CE', |
571
|
|
|
|
|
|
|
'Normal', 'Class Selector', 'AF PHB', 'EF PHB', |
572
|
|
|
|
|
|
|
'No IP Options', 'IP Options' |
573
|
|
|
|
|
|
|
); |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
=head1 FUNCTIONS |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
C does not export any functions by default. The |
578
|
|
|
|
|
|
|
following functions, listed in alphabetical order, are |
579
|
|
|
|
|
|
|
L. |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
=head2 configure |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
configure %OPTIONS |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
Used to specify verbosity, the link capacity, and the types of outputs |
586
|
|
|
|
|
|
|
requested. For example, |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
configure( |
589
|
|
|
|
|
|
|
# Display progress information, equivalent to calling verbose() |
590
|
|
|
|
|
|
|
# |
591
|
|
|
|
|
|
|
Verbosity => 1, # default is 0, no progress information |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
'Link Capacity' => 100_000_000, # bits per second |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
# Convert the TCP records in the TSH trace to tcpdump |
596
|
|
|
|
|
|
|
# format and store in 'trace.tcpdump'. |
597
|
|
|
|
|
|
|
# |
598
|
|
|
|
|
|
|
tcpdump => 'trace.tcpdump', |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
# Convert the TCP data-carrying segment records to binary |
601
|
|
|
|
|
|
|
# ns2 traffic trace format. Create one binary file per |
602
|
|
|
|
|
|
|
# interface and use 'trace.ns2' as the file prefix. |
603
|
|
|
|
|
|
|
# |
604
|
|
|
|
|
|
|
ns2 => 'trace.ns2', |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
); |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
=cut |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
sub configure ( % ) { |
611
|
7
|
|
|
7
|
1
|
8118
|
while ( defined ($_ = shift) ) { |
612
|
8
|
100
|
|
|
|
29
|
if ( defined $options{$_} ) { |
613
|
7
|
|
|
|
|
28
|
$options{$_} = shift; |
614
|
|
|
|
|
|
|
} |
615
|
|
|
|
|
|
|
else { |
616
|
1
|
|
|
|
|
3
|
$options{$_} = undef; |
617
|
1
|
|
|
|
|
2
|
shift; |
618
|
1
|
|
|
|
|
299
|
carp "Ignoring unknown configuration option '$_'..."; |
619
|
|
|
|
|
|
|
} |
620
|
|
|
|
|
|
|
} |
621
|
|
|
|
|
|
|
} |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
=head2 date_of |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
date_of FILENAME |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
TSH traces downloaded from the L
|
628
|
|
|
|
|
|
|
ALSO"> typically contain a timestamp as part of their filename. |
629
|
|
|
|
|
|
|
date_of() converts the timestamp to a human readable format. That is, |
630
|
|
|
|
|
|
|
if FILENAME contains a valid timestamp, date_of() returns the |
631
|
|
|
|
|
|
|
corresponding GMT date as a human readable string. For example, |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
date_of 'ODU-1073132115.tsh' |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
returns C. |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
If the FILENAME does not contain a timestamp, date_of() returns |
638
|
|
|
|
|
|
|
I. |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
Note that there is nothing special about FILENAME: It can be any |
641
|
|
|
|
|
|
|
string. The goal here is to get an idea of the period the trace was |
642
|
|
|
|
|
|
|
collected. |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
=cut |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
sub date_of( $ ) { |
647
|
24
|
100
|
100
|
24
|
1
|
2085
|
$_ = shift and /(\d{10})/ and return join ' ', scalar gmtime $1, 'GMT'; |
648
|
|
|
|
|
|
|
} |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
=head2 get_IP_address |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
get_IP_address INTEGER |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
Converts a 32-bit integer to an IP address in dotted decimal |
655
|
|
|
|
|
|
|
notation. For example, |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
get_IP_address(167772172) |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
returns C<10.0.0.12>. |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
=cut |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
sub get_IP_address ( $ ) { |
664
|
1690
|
|
|
1690
|
1
|
18787
|
return join '.', unpack('C4', pack('N', shift)); |
665
|
|
|
|
|
|
|
} |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
=head2 get_interfaces_href |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
get_interfaces_href |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
Returns a hash I to L<%Interfaces|"Data Structures">. |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
=cut |
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
sub get_interfaces_href() { |
676
|
|
|
|
|
|
|
|
677
|
4
|
|
|
4
|
1
|
32348
|
return \%Interfaces; |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
} |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
=head2 get_interfaces_list |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
get_interfaces_list |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
In list context returns a sorted list of all interfaces recorded in |
687
|
|
|
|
|
|
|
the trace. In scalar context returns the number of unique interfaces |
688
|
|
|
|
|
|
|
in the trace. |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
=cut |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
sub get_interfaces_list() { |
693
|
|
|
|
|
|
|
|
694
|
9
|
100
|
|
9
|
1
|
1618
|
return wantarray ? sort numerically keys %Interfaces |
695
|
|
|
|
|
|
|
: scalar keys %Interfaces; |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
} |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
=head2 get_trace_summary_href |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
get_trace_summary_href |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
Returns a hash I to L<%Trace|"Data Structures">. |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
=cut |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
sub get_trace_summary_href() { |
708
|
|
|
|
|
|
|
|
709
|
2
|
|
|
2
|
1
|
891
|
return \%Trace; |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
} |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
=head2 process_trace |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
process_trace FILENAME |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
In a void context, process_trace() examines the binary TSH trace stored |
718
|
|
|
|
|
|
|
in FILENAME, and populates L<%Trace and %Interfaces|"Data |
719
|
|
|
|
|
|
|
Structures">. |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
In a list context process_trace() in addition to collecting summary |
722
|
|
|
|
|
|
|
statistics, it extracts all TCP flows and TCP data-carrying segments |
723
|
|
|
|
|
|
|
from the trace, returning two hash references. For example, |
724
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
my ($senders_href, $segments_href) = process_trace 'trace.tsh'; |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
will process C and return two hash references: |
728
|
|
|
|
|
|
|
I<$senders_href> and I<$segments_href>. |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
I<$senders_href> is a reference to a hash which contains an entry for |
731
|
|
|
|
|
|
|
each TCP sender in the trace file. A TCP sender is identified by the |
732
|
|
|
|
|
|
|
ordered 4-tuple |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
(src, src port, dst, dst port) |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
where I and I are the L<32-bit integers|"get_IP_address"> |
737
|
|
|
|
|
|
|
corresponding to the IP addresses of the sending and receiving hosts, |
738
|
|
|
|
|
|
|
respectively. Similarly, I and I are the sending |
739
|
|
|
|
|
|
|
and receiving processes' port numbers. Senders are categorized on a |
740
|
|
|
|
|
|
|
per interface basis. For example, the following accesses the list of |
741
|
|
|
|
|
|
|
segments sent from 10.0.0.12:80 to 10.0.0.14:1080 (on interface 1): |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
$senders_href->{1}{167772172,80,167772174,1080} |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
Each hash entry is a list of timestamps extracted from the trace |
746
|
|
|
|
|
|
|
records and stored after being "normalized" (start of trace = 0.0 |
747
|
|
|
|
|
|
|
seconds, always). |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
In theory, records corresponding to packets transmitted on the same |
750
|
|
|
|
|
|
|
interface should have different timestamps. In practice, although it |
751
|
|
|
|
|
|
|
is not very likely that two data segments have the same timestamp, I |
752
|
|
|
|
|
|
|
encountered a few traces that did have duplicate timestamps. |
753
|
|
|
|
|
|
|
process_trace() checks for such cases and implements a timestamp |
754
|
|
|
|
|
|
|
"collision avoidance" algorithm. A timestamp collision threshold is |
755
|
|
|
|
|
|
|
defined and is currently set to 3. Trace processing is aborted if the |
756
|
|
|
|
|
|
|
number of records with the same timestamp exceeds this threshold. If |
757
|
|
|
|
|
|
|
you encounter such traces, it is not a bad idea to investigate why |
758
|
|
|
|
|
|
|
this is happening, as the trace may be corrupted. |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
The second returned value, I<$segments_href>, is another hash |
761
|
|
|
|
|
|
|
reference, which can be used to access any individual I
|
762
|
|
|
|
|
|
|
TCP segment> in the trace. Again, segments are categorized on a per |
763
|
|
|
|
|
|
|
interface basis. Three values are stored per segment: the total |
764
|
|
|
|
|
|
|
number of bytes (including IP and TCP headers, and application |
765
|
|
|
|
|
|
|
payload), the segment sequence number, and whether the segment was |
766
|
|
|
|
|
|
|
retransmitted or not. |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
For example, assuming the first record corresponds to a TCP segment, |
769
|
|
|
|
|
|
|
here is how you can print its packet size and the sequence number |
770
|
|
|
|
|
|
|
carried in the TCP header: |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
my $interface = 1; |
773
|
|
|
|
|
|
|
my $timestamp = 0.0; |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
print $segments_href->{$interface}{$timestamp}{bytes}; |
776
|
|
|
|
|
|
|
print $segments_href->{$interface}{$timestamp}{seq_num}; |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
You can also check whether a segment was retransmitted or not: |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
if ( segments_href->{$interface}{$timestamp}{retransmitted} ) { |
781
|
|
|
|
|
|
|
print "Segment was retransmitted by the TCP sender."; |
782
|
|
|
|
|
|
|
} |
783
|
|
|
|
|
|
|
else { |
784
|
|
|
|
|
|
|
print "Segment must have been acknowledged by the TCP receiver."; |
785
|
|
|
|
|
|
|
} |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
Note that process_trace() only initializes the "retransmitted" value |
788
|
|
|
|
|
|
|
to false (0). It is write_sojourn_times() that detects retransmitted |
789
|
|
|
|
|
|
|
segments and updates the "retransmitted" entry to I, if it is |
790
|
|
|
|
|
|
|
determined that the segment was retransmitted. |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
CAVEAT: write_sojourn_times() is not currently included in the stable, |
793
|
|
|
|
|
|
|
CPAN version of the module. L if you want to get |
794
|
|
|
|
|
|
|
a copy of the bleeding edge version. |
795
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
=head3 Using a TSH trace in ns2 simulations |
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
In addition to extracting %senders and %segments, C |
799
|
|
|
|
|
|
|
allows you to generate binary files suitable for driving L
|
800
|
|
|
|
|
|
|
simulations|"SEE ALSO">. For example, |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
configure(ns2 => 'some.tsh'); |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
process_trace 'some.tsh'; |
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
After the call to configure(), process_trace() will generate a binary |
807
|
|
|
|
|
|
|
file for each interface found in the trace. For example, assume that |
808
|
|
|
|
|
|
|
F has recorded traffic from two interfaces, 1 and 2. |
809
|
|
|
|
|
|
|
process_trace() will generate two binary files: |
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
some.tsh-if1.bin |
812
|
|
|
|
|
|
|
some.tsh-if2.bin |
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
Each of these files L in |
815
|
|
|
|
|
|
|
conjunction Application/Traffic/Trace. For example, the following ns2 |
816
|
|
|
|
|
|
|
script fragment illustrates how to attach F to a |
817
|
|
|
|
|
|
|
traffic source |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
# ... |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
# Initialize a trace file |
822
|
|
|
|
|
|
|
# |
823
|
|
|
|
|
|
|
set tfile [new Tracefile] |
824
|
|
|
|
|
|
|
$tfile filename some.tsh-2.bin |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
# Attach the tracefile |
827
|
|
|
|
|
|
|
# |
828
|
|
|
|
|
|
|
set trace [new Application/Traffic/Trace] |
829
|
|
|
|
|
|
|
$trace attach-tracefile $tfile |
830
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
# ... |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
Note that both F and F include |
834
|
|
|
|
|
|
|
only the I in the trace. If you want to |
835
|
|
|
|
|
|
|
convert the I TSH trace to Traffic/Trace files, see |
836
|
|
|
|
|
|
|
C. |
837
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
=head3 Converting TSH to F |
840
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
If you would like to extract the TCP traffic and store it in |
842
|
|
|
|
|
|
|
F format, use |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
configure(tcpdump => 'tcpdump_filename'); |
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
before calling process_trace(). process_trace() will generates a text |
847
|
|
|
|
|
|
|
file based on the trace records in a format similar to the modified |
848
|
|
|
|
|
|
|
output of F, as presented in I |
849
|
|
|
|
|
|
|
by W. R. Stevens (see pp. 230-231). |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
You can use such an output as input to other tools, present real |
852
|
|
|
|
|
|
|
traffic scenarios in a classroom, or simply "eyeball" the trace. For |
853
|
|
|
|
|
|
|
example, here are the first ten lines of the contents of such a file: |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
0.000000000 10.0.0.1.6699 > 10.0.0.2.55309: . ack 225051666 win 65463 |
856
|
|
|
|
|
|
|
0.000014000 10.0.0.3.80 > 10.0.0.4.14401: S 457330477:457330477(0) ack 810547499 win 34932 |
857
|
|
|
|
|
|
|
0.000014000 10.0.0.1.6699 > 10.0.0.2.55309: . 3069529864:3069531324(1460) ack 225051666 win 65463 |
858
|
|
|
|
|
|
|
0.000024000 10.0.0.5.12119 > 10.0.0.6.80: F 2073668891:2073668891(0) ack 183269290 win 64240 |
859
|
|
|
|
|
|
|
0.000034000 10.0.0.7.4725 > 10.0.0.8.445: S 3152140131:3152140131(0) win 16384 |
860
|
|
|
|
|
|
|
0.000067000 10.0.0.1.6699 > 10.0.0.2.55309: P 3069531324:3069531944(620) ack 225051666 win 65463 |
861
|
|
|
|
|
|
|
0.000072000 10.0.0.11.3381 > 10.0.0.12.445: S 1378088462:1378088462(0) win 16384 |
862
|
|
|
|
|
|
|
0.000083000 10.0.0.13.1653 > 10.0.0.1.6699: P 3272208349:3272208357(8) ack 501563814 win 32767 |
863
|
|
|
|
|
|
|
0.000093000 10.0.0.14.1320 > 10.0.0.15.445: S 3127123478:3127123478(0) win 64170 |
864
|
|
|
|
|
|
|
0.000095000 10.0.0.4.14401 > 10.0.0.3.80: R 810547499:810547499(0) ack 457330478 win 34932 |
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
Note that this output is similar to what F with options C<-n> |
867
|
|
|
|
|
|
|
and C<-S> would have produced. The only missing fields are related to |
868
|
|
|
|
|
|
|
the TCP options negotiated during connection setup. Unfortunately, |
869
|
|
|
|
|
|
|
L include only the first 16 bytes of the |
870
|
|
|
|
|
|
|
TCP header, making it impossible to record the options from the |
871
|
|
|
|
|
|
|
segment header. |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
=cut |
874
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
# A TSH record is 44 bytes long. |
876
|
|
|
|
|
|
|
# |
877
|
9
|
|
|
9
|
|
19223
|
use constant TSH_RECORD_LENGTH => 44; |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
853
|
|
878
|
|
|
|
|
|
|
|
879
|
|
|
|
|
|
|
# If more than so many records have the same timestamp, abort |
880
|
|
|
|
|
|
|
# processing. |
881
|
|
|
|
|
|
|
# |
882
|
9
|
|
|
9
|
|
59
|
use constant TIMESTAMP_COLLISION_THRESHOLD => 3; |
|
9
|
|
|
|
|
10
|
|
|
9
|
|
|
|
|
21124
|
|
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
sub process_trace( $ ) { |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
# Sanity checks |
887
|
|
|
|
|
|
|
# |
888
|
5
|
|
|
5
|
1
|
2275
|
my $trace = shift; |
889
|
5
|
50
|
|
|
|
25
|
croak 'No trace filename provided' unless $trace; |
890
|
|
|
|
|
|
|
|
891
|
5
|
|
|
|
|
22
|
my $records = records_in $trace; |
892
|
5
|
50
|
|
|
|
15
|
croak "Number of records in $trace not an integer. Is $trace corrupted?" |
893
|
|
|
|
|
|
|
unless $records; |
894
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
# Open trace file |
896
|
|
|
|
|
|
|
# |
897
|
5
|
50
|
|
|
|
188
|
open(INPUT, '<', $trace) |
898
|
|
|
|
|
|
|
or croak "Cannot open $trace for processing. $!"; |
899
|
|
|
|
|
|
|
|
900
|
5
|
|
|
|
|
15
|
binmode INPUT; # Needed for non-UNIX OSes; no harm in UNIX |
901
|
|
|
|
|
|
|
|
902
|
5
|
100
|
33
|
|
|
118
|
$options{tcpdump} and |
903
|
|
|
|
|
|
|
( open(TCPDUMP, '>', $options{tcpdump}) |
904
|
|
|
|
|
|
|
or croak "Cannot open $options{tcpdump}. $!" |
905
|
|
|
|
|
|
|
); |
906
|
|
|
|
|
|
|
|
907
|
5
|
|
|
|
|
91
|
my %ns2_fh; |
908
|
|
|
|
|
|
|
my %ns2_previous_timestamp; |
909
|
|
|
|
|
|
|
|
910
|
5
|
|
|
|
|
19
|
progress "Initializing data structures... "; |
911
|
|
|
|
|
|
|
|
912
|
5
|
|
|
|
|
192
|
%Trace = %Interfaces = (); |
913
|
|
|
|
|
|
|
|
914
|
5
|
|
|
|
|
12
|
$Trace{filename} = $trace; |
915
|
5
|
|
|
|
|
10
|
$Trace{records} = $records; |
916
|
5
|
|
|
|
|
10
|
$Trace{'Link Capacity'} = $options{'Link Capacity'}; |
917
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
# If process_trace() is called in a void context, we will not |
919
|
|
|
|
|
|
|
# examine traffic direction, thus undef $Trace{unidirectional}. |
920
|
|
|
|
|
|
|
# Otherwise, assume that traffic is unidirectional, until proven |
921
|
|
|
|
|
|
|
# otherwise. |
922
|
|
|
|
|
|
|
# |
923
|
5
|
100
|
|
|
|
16
|
$Trace{unidirectional} = defined wantarray ? 1 : undef; |
924
|
|
|
|
|
|
|
|
925
|
5
|
|
|
|
|
7
|
my (%senders, %segments); |
926
|
|
|
|
|
|
|
|
927
|
5
|
|
|
|
|
22
|
progress "Processing $Trace{filename}...\n"; |
928
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
# Read the trace file, record by record |
930
|
|
|
|
|
|
|
# |
931
|
5
|
|
|
|
|
9
|
my $record; |
932
|
|
|
|
|
|
|
|
933
|
5
|
|
|
|
|
112
|
while( read(INPUT, $record, TSH_RECORD_LENGTH) ) { |
934
|
|
|
|
|
|
|
# Extract the fields from the TSH record in a platform-independent way |
935
|
|
|
|
|
|
|
# |
936
|
5000
|
|
|
|
|
44924
|
my ($t_sec, |
937
|
|
|
|
|
|
|
$if, $t_usec, |
938
|
|
|
|
|
|
|
$version_ihl, $tos, $ip_len, |
939
|
|
|
|
|
|
|
$id, $flags_offset, |
940
|
|
|
|
|
|
|
$ttl, $protocol, $chk_sum, |
941
|
|
|
|
|
|
|
$src, |
942
|
|
|
|
|
|
|
$dst, |
943
|
|
|
|
|
|
|
$src_port, $dst_port, |
944
|
|
|
|
|
|
|
$seq_num, |
945
|
|
|
|
|
|
|
$ack_num, |
946
|
|
|
|
|
|
|
$data_offset, $tcp_flags, $win) = |
947
|
|
|
|
|
|
|
unpack( "# Time |
948
|
|
|
|
|
|
|
N # timestamp (seconds) |
949
|
|
|
|
|
|
|
C B24 # interface, timestamp (microseconds) |
950
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
# IP |
952
|
|
|
|
|
|
|
C C n # Version & IHL, Type of Service, Total Length |
953
|
|
|
|
|
|
|
n n # Identification, Flags & Fragment Offset |
954
|
|
|
|
|
|
|
B8 B8 n # TTL, Protocol, Header Checksum |
955
|
|
|
|
|
|
|
N # Source Address |
956
|
|
|
|
|
|
|
N # Destination Address |
957
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
# TCP |
959
|
|
|
|
|
|
|
n n # Source Port, Destination Port |
960
|
|
|
|
|
|
|
N # Sequence Number |
961
|
|
|
|
|
|
|
N # Acknowledgment Number |
962
|
|
|
|
|
|
|
C C n # Data Offset & Reserved bits, Flags, Window |
963
|
|
|
|
|
|
|
", $record |
964
|
|
|
|
|
|
|
); |
965
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
################################################################## |
967
|
|
|
|
|
|
|
# TIME |
968
|
|
|
|
|
|
|
################################################################## |
969
|
|
|
|
|
|
|
# Sanity: make absolutely sure that $t_sec is considered an |
970
|
|
|
|
|
|
|
# integer in the code below |
971
|
|
|
|
|
|
|
# |
972
|
5000
|
|
|
|
|
8507
|
$t_sec = int $t_sec; |
973
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
# Extract the microseconds part of the timestamp |
975
|
|
|
|
|
|
|
# |
976
|
5000
|
|
|
|
|
8681
|
$t_usec = oct("0b$t_usec") / 1_000_000; |
977
|
|
|
|
|
|
|
|
978
|
|
|
|
|
|
|
# Sanity check |
979
|
|
|
|
|
|
|
# |
980
|
5000
|
50
|
|
|
|
15137
|
croak 'Microseconds record field exceeds 1,000,000. Processing aborted' |
981
|
|
|
|
|
|
|
unless $t_usec < 1; |
982
|
|
|
|
|
|
|
|
983
|
5000
|
100
|
|
|
|
9219
|
unless ( defined $Trace{starts} ) { |
984
|
|
|
|
|
|
|
# Get the first timestamp in the trace, and use it to normalize |
985
|
|
|
|
|
|
|
# the rest of the timestamps in the trace. |
986
|
|
|
|
|
|
|
# |
987
|
5
|
|
|
|
|
13
|
$Trace{starts} = $t_sec + $t_usec; |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
# Identify the period the trace was collected |
990
|
|
|
|
|
|
|
# |
991
|
5
|
|
50
|
|
|
20
|
$Trace{date} = date_of $Trace{filename} || date_of $t_sec || 'Unknown'; |
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
# Timestamp of the last processed record. |
994
|
|
|
|
|
|
|
# |
995
|
5
|
|
|
|
|
13
|
$Trace{ends} = 0.0; |
996
|
|
|
|
|
|
|
} |
997
|
|
|
|
|
|
|
|
998
|
5000
|
|
|
|
|
7274
|
$Interfaces{$if}{records}++; |
999
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
# Combine the two parts of the timestamp ($t_sec and $t_usec) in |
1001
|
|
|
|
|
|
|
# one variable and normalize using the first timestamp in the trace |
1002
|
|
|
|
|
|
|
# |
1003
|
5000
|
|
|
|
|
6921
|
my $timestamp = $t_sec + $t_usec - $Trace{starts}; |
1004
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
# Convert the $protocol number to the corresponding protocol name |
1006
|
|
|
|
|
|
|
# |
1007
|
5000
|
|
100
|
|
|
12574
|
$protocol = $iana_protocol_numbers{oct "0b$protocol"} || 'Unknown'; |
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
# Sanity check: Timestamps must increase monotonically in a TSH |
1010
|
|
|
|
|
|
|
# trace. |
1011
|
|
|
|
|
|
|
# |
1012
|
5000
|
50
|
|
|
|
9868
|
if ( $Trace{ends} > $timestamp ) { |
1013
|
|
|
|
|
|
|
# If this is a TCP segment then this can play a big role if we |
1014
|
|
|
|
|
|
|
# are interested in extracting the segment time series, so it's |
1015
|
|
|
|
|
|
|
# better that we abort processing. |
1016
|
|
|
|
|
|
|
# |
1017
|
0
|
|
|
|
|
0
|
print "Timestamps do not increase monotonically (Prot $protocol)\n"; |
1018
|
|
|
|
|
|
|
|
1019
|
0
|
0
|
|
|
|
0
|
croak "Processing aborted for $Trace{filename}" if wantarray; |
1020
|
|
|
|
|
|
|
} |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
################################################################## |
1023
|
|
|
|
|
|
|
# IP |
1024
|
|
|
|
|
|
|
################################################################## |
1025
|
5000
|
|
|
|
|
7536
|
$Interfaces{$if}{IP}{Total}{Packets}++; |
1026
|
5000
|
|
|
|
|
7108
|
$Interfaces{$if}{IP}{Total}{Bytes} += $ip_len; |
1027
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
# Packet size distribution |
1029
|
|
|
|
|
|
|
# |
1030
|
5000
|
|
|
|
|
8616
|
$Interfaces{$if}{IP}{'Packet Size'}{$ip_len}++; |
1031
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
# Get the IP version |
1033
|
|
|
|
|
|
|
# |
1034
|
5000
|
|
|
|
|
6233
|
my $version = ($version_ihl & 0xf0) >> 4; |
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
# We shouldn't see anything other than IPv4. If we do, issue a |
1037
|
|
|
|
|
|
|
# warning. |
1038
|
|
|
|
|
|
|
# |
1039
|
5000
|
50
|
|
|
|
8696
|
carp "IPv$version packet detected" unless $version == 4; |
1040
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
# Get the IP header length (IHL) |
1042
|
|
|
|
|
|
|
# |
1043
|
5000
|
|
|
|
|
5463
|
my $ihl = ($version_ihl & 0xf) << 2; |
1044
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
################################################################## |
1046
|
|
|
|
|
|
|
# Transport protocols |
1047
|
|
|
|
|
|
|
################################################################## |
1048
|
5000
|
|
|
|
|
8864
|
$Interfaces{$if}{Transport}{$protocol}{Total}{Packets}++; |
1049
|
5000
|
|
|
|
|
8457
|
$Interfaces{$if}{Transport}{$protocol}{Total}{Bytes} += $ip_len; |
1050
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
# Packet size distribution |
1052
|
|
|
|
|
|
|
# |
1053
|
5000
|
|
|
|
|
8715
|
$Interfaces{$if}{Transport}{$protocol}{'Packet Size'}{$ip_len}++; |
1054
|
|
|
|
|
|
|
|
1055
|
|
|
|
|
|
|
################################################################## |
1056
|
|
|
|
|
|
|
# D(o not)F(ragment) bit |
1057
|
|
|
|
|
|
|
################################################################## |
1058
|
5000
|
100
|
|
|
|
9087
|
if ($flags_offset & 0x4000) { |
1059
|
4475
|
|
|
|
|
6205
|
$Interfaces{$if}{IP}{DF}{Packets}++; |
1060
|
4475
|
|
|
|
|
6253
|
$Interfaces{$if}{IP}{DF}{Bytes} += $ip_len; |
1061
|
|
|
|
|
|
|
|
1062
|
4475
|
|
|
|
|
6754
|
$Interfaces{$if}{Transport}{$protocol}{DF}{Packets}++; |
1063
|
4475
|
|
|
|
|
7716
|
$Interfaces{$if}{Transport}{$protocol}{DF}{Bytes} += $ip_len; |
1064
|
|
|
|
|
|
|
} |
1065
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
################################################################## |
1067
|
|
|
|
|
|
|
# M(ore)F(ragments) bit |
1068
|
|
|
|
|
|
|
################################################################## |
1069
|
5000
|
50
|
|
|
|
8905
|
if ($flags_offset & 0x2000) { |
1070
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{IP}{MF}{Packets}++; |
1071
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{IP}{MF}{Bytes} += $ip_len; |
1072
|
|
|
|
|
|
|
|
1073
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{Transport}{$protocol}{MF}{Packets}++; |
1074
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{Transport}{$protocol}{MF}{Bytes} += $ip_len; |
1075
|
|
|
|
|
|
|
} |
1076
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
################################################################## |
1078
|
|
|
|
|
|
|
# DiffServ |
1079
|
|
|
|
|
|
|
################################################################## |
1080
|
|
|
|
|
|
|
# |
1081
|
|
|
|
|
|
|
# Convert the ToS field and gather DiffServ statistics. |
1082
|
|
|
|
|
|
|
# |
1083
|
|
|
|
|
|
|
# Extract the Differentiated Services Code Point (DSCP) from ToS |
1084
|
|
|
|
|
|
|
# |
1085
|
5000
|
|
|
|
|
9226
|
my $dscp = $tos >> 2; |
1086
|
|
|
|
|
|
|
|
1087
|
5000
|
50
|
|
|
|
7376
|
if ( $dscp == 0 ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
# The usual suspect, the default value most of the time. This |
1089
|
|
|
|
|
|
|
# is compatible with RFC 791 (original ToS definition), RFC 1349 |
1090
|
|
|
|
|
|
|
# (updated ToS definition), RFC 2474 (DiffServ defines DSCP), |
1091
|
|
|
|
|
|
|
# RFC 2780: No DiffServ code point (DSCP) set |
1092
|
|
|
|
|
|
|
# |
1093
|
5000
|
|
|
|
|
13548
|
$Interfaces{$if}{IP}{Normal}{Packets}++; |
1094
|
5000
|
|
|
|
|
11141
|
$Interfaces{$if}{IP}{Normal}{Bytes} += $ip_len; |
1095
|
|
|
|
|
|
|
|
1096
|
5000
|
|
|
|
|
8065
|
$Interfaces{$if}{Transport}{$protocol}{Normal}{Packets}++; |
1097
|
5000
|
|
|
|
|
8670
|
$Interfaces{$if}{Transport}{$protocol}{Normal}{Bytes} += $ip_len; |
1098
|
|
|
|
|
|
|
} |
1099
|
|
|
|
|
|
|
elsif ( $dscp % 0b001000 == 0 ) { |
1100
|
|
|
|
|
|
|
# Class Selector Code points -- RFC 2474 |
1101
|
|
|
|
|
|
|
# |
1102
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{IP}{'Class Selector'}{Packets}++; |
1103
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{IP}{'Class Selector'}{Bytes} += $ip_len; |
1104
|
|
|
|
|
|
|
|
1105
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{Transport}{$protocol}{'Class Selector'}{Packets}++; |
1106
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{Transport}{$protocol}{'Class Selector'}{Bytes} |
1107
|
|
|
|
|
|
|
+=$ip_len; |
1108
|
|
|
|
|
|
|
} |
1109
|
|
|
|
|
|
|
elsif ( $dscp % 2 == 0 ) { |
1110
|
0
|
|
|
|
|
0
|
$dscp >>= 1; |
1111
|
0
|
0
|
0
|
|
|
0
|
if ( 0b00100 < $dscp and $dscp < 0b10100 ) { |
|
|
0
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
# Assured Forwarding (AF) PHB -- RFC 2597 |
1113
|
|
|
|
|
|
|
# |
1114
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{IP}{'AF PHB'}{Packets}++; |
1115
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{IP}{'AF PHB'}{Bytes} += $ip_len; |
1116
|
|
|
|
|
|
|
|
1117
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{Transport}{$protocol}{'AF PHB'}{Packets}++; |
1118
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{Transport}{$protocol}{'AF PHB'}{Bytes} += $ip_len; |
1119
|
|
|
|
|
|
|
} |
1120
|
|
|
|
|
|
|
elsif ( $dscp == 0b10111 ) { |
1121
|
|
|
|
|
|
|
# Expedited Forwarding (EF) PHB -- RFC 2598 |
1122
|
|
|
|
|
|
|
# |
1123
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{IP}{'EF PHB'}{Packets}++; |
1124
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{IP}{'EF PHB'}{Bytes} += $ip_len; |
1125
|
|
|
|
|
|
|
|
1126
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{Transport}{$protocol}{'EF PHB'}{Packets}++; |
1127
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{Transport}{$protocol}{'EF PHB'}{Bytes} += $ip_len; |
1128
|
|
|
|
|
|
|
} |
1129
|
|
|
|
|
|
|
} |
1130
|
|
|
|
|
|
|
|
1131
|
|
|
|
|
|
|
################################################################## |
1132
|
|
|
|
|
|
|
# ECN |
1133
|
|
|
|
|
|
|
################################################################## |
1134
|
|
|
|
|
|
|
# |
1135
|
|
|
|
|
|
|
# Extract ECN from ToS and gather ECN statistics |
1136
|
|
|
|
|
|
|
# |
1137
|
5000
|
|
|
|
|
5593
|
my $ecn = $tos & 0b11; |
1138
|
5000
|
50
|
|
|
|
8120
|
if ( $ecn ) { |
1139
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{IP}{ECT}{Packets}++; |
1140
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{IP}{ECT}{Bytes} += $ip_len; |
1141
|
|
|
|
|
|
|
|
1142
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{Transport}{$protocol}{ECT}{Packets}++; |
1143
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{Transport}{$protocol}{ECT}{Bytes} += $ip_len; |
1144
|
|
|
|
|
|
|
} |
1145
|
|
|
|
|
|
|
|
1146
|
5000
|
50
|
|
|
|
8534
|
if ( $ecn == 0b11 ) { |
1147
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{IP}{CE}{Packets}++; |
1148
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{IP}{CE}{Bytes} += $ip_len; |
1149
|
|
|
|
|
|
|
|
1150
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{Transport}{$protocol}{CE}{Packets}++; |
1151
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{Transport}{$protocol}{CE}{Bytes} += $ip_len; |
1152
|
|
|
|
|
|
|
} |
1153
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
################################################################## |
1155
|
|
|
|
|
|
|
# IP Options |
1156
|
|
|
|
|
|
|
################################################################## |
1157
|
5000
|
50
|
|
|
|
6886
|
if ( $ihl == 20 ) { |
|
|
0
|
|
|
|
|
|
1158
|
5000
|
|
|
|
|
7416
|
$Interfaces{$if}{IP}{'No IP Options'}{Packets}++; |
1159
|
5000
|
|
|
|
|
7385
|
$Interfaces{$if}{IP}{'No IP Options'}{Bytes} += $ip_len; |
1160
|
|
|
|
|
|
|
|
1161
|
5000
|
|
|
|
|
8049
|
$Interfaces{$if}{Transport}{$protocol}{'No IP Options'}{Packets}++; |
1162
|
5000
|
|
|
|
|
8451
|
$Interfaces{$if}{Transport}{$protocol}{'No IP Options'}{Bytes} += $ip_len; |
1163
|
|
|
|
|
|
|
} |
1164
|
|
|
|
|
|
|
elsif ( $ihl > 20 ) { |
1165
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{IP}{'IP Options'}{Packets}++; |
1166
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{IP}{'IP Options'}{Bytes} += $ip_len; |
1167
|
|
|
|
|
|
|
|
1168
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{Transport}{$protocol}{'IP Options'}{Packets}++; |
1169
|
0
|
|
|
|
|
0
|
$Interfaces{$if}{Transport}{$protocol}{'IP Options'}{Bytes} += $ip_len; |
1170
|
|
|
|
|
|
|
} |
1171
|
|
|
|
|
|
|
else { |
1172
|
|
|
|
|
|
|
# This is an extremely unlikely event, but just in case... |
1173
|
|
|
|
|
|
|
# |
1174
|
0
|
|
|
|
|
0
|
carp "IP header with only $ihl bytes detected"; |
1175
|
|
|
|
|
|
|
} |
1176
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
################################################################## |
1178
|
|
|
|
|
|
|
# TCP-related counts |
1179
|
|
|
|
|
|
|
################################################################## |
1180
|
5000
|
100
|
|
|
|
15294
|
if ( $protocol eq 'TCP' ) { |
1181
|
|
|
|
|
|
|
# Extract TCP header length from $data_offset, and right shift, |
1182
|
|
|
|
|
|
|
# since the TCP header length is expressed in 4-byte words. |
1183
|
|
|
|
|
|
|
# |
1184
|
4210
|
|
|
|
|
4834
|
my $tcp_hl = ( $data_offset & 0xf0 ) >> 2; |
1185
|
4210
|
|
|
|
|
4864
|
my $tcp_payload = $ip_len - $ihl - $tcp_hl; |
1186
|
|
|
|
|
|
|
|
1187
|
|
|
|
|
|
|
# TCP flags |
1188
|
|
|
|
|
|
|
# |
1189
|
4210
|
|
|
|
|
20160
|
my ($cwr, $ece, $urg, $ack, $psh, $rst, $syn, $fin) = |
1190
|
|
|
|
|
|
|
split '', unpack('B8', pack('C', $tcp_flags)); |
1191
|
|
|
|
|
|
|
|
1192
|
4210
|
100
|
|
|
|
9733
|
if ( $syn ) { |
1193
|
|
|
|
|
|
|
# Count the number of SYNs, SYN/ACKs and SYNs carrying a |
1194
|
|
|
|
|
|
|
# payload in the trace. |
1195
|
|
|
|
|
|
|
# |
1196
|
1365
|
|
|
|
|
3310
|
$Interfaces{$if}{Transport}{TCP}{SYN}{$tcp_hl}++; |
1197
|
1365
|
100
|
|
|
|
2430
|
$Interfaces{$if}{Transport}{TCP}{'SYN/ACK'}{$tcp_hl}++ |
1198
|
|
|
|
|
|
|
if $ack; |
1199
|
1365
|
50
|
|
|
|
2287
|
$Interfaces{$if}{Transport}{TCP}{'SYN/Payload'}++ |
1200
|
|
|
|
|
|
|
if $tcp_payload > 0; |
1201
|
|
|
|
|
|
|
|
1202
|
|
|
|
|
|
|
# Collect the receiver's advertised window (awnd), for all |
1203
|
|
|
|
|
|
|
# SYNs that have the standard TCP header. We will refer to |
1204
|
|
|
|
|
|
|
# that as the "hard count". For larger SYNs, we cannot say |
1205
|
|
|
|
|
|
|
# for sure what is the receiver's advertised window, but we |
1206
|
|
|
|
|
|
|
# can collect a count for comparison (rwnd). We will refer to |
1207
|
|
|
|
|
|
|
# this as the "soft count". |
1208
|
|
|
|
|
|
|
# |
1209
|
1365
|
|
|
|
|
2647
|
$Interfaces{$if}{Transport}{TCP}{rwnd}{$win}++; |
1210
|
1365
|
100
|
|
|
|
2698
|
$Interfaces{$if}{Transport}{TCP}{awnd}{$win}++ |
1211
|
|
|
|
|
|
|
if $tcp_hl == 20; |
1212
|
|
|
|
|
|
|
} |
1213
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
# Count the number of ACKs, pure ACKs, etc. |
1215
|
|
|
|
|
|
|
# |
1216
|
4210
|
100
|
|
|
|
7120
|
if ( $ack ) { |
1217
|
2880
|
50
|
|
|
|
5701
|
if ( $tcp_hl < 20 ) { |
1218
|
|
|
|
|
|
|
# Yet another extremely unlikely event, but just in case... |
1219
|
|
|
|
|
|
|
# |
1220
|
0
|
|
|
|
|
0
|
carp "TCP header with only $tcp_hl bytes detected and ignored"; |
1221
|
|
|
|
|
|
|
} |
1222
|
|
|
|
|
|
|
else { |
1223
|
2880
|
|
|
|
|
4742
|
$Interfaces{$if}{Transport}{TCP}{'Total ACKs'}++; |
1224
|
|
|
|
|
|
|
|
1225
|
2880
|
100
|
|
|
|
4316
|
if ( $tcp_hl == 20 ) { |
1226
|
2530
|
|
|
|
|
3903
|
$Interfaces{$if}{Transport}{TCP}{'Cumulative ACKs'}++; |
1227
|
|
|
|
|
|
|
|
1228
|
2530
|
100
|
|
|
|
5348
|
$Interfaces{$if}{Transport}{TCP}{'Pure ACKs'}++ |
1229
|
|
|
|
|
|
|
if $tcp_payload == 0; |
1230
|
|
|
|
|
|
|
} |
1231
|
|
|
|
|
|
|
else { |
1232
|
350
|
|
|
|
|
529
|
$Interfaces{$if}{Transport}{TCP}{'Options ACKs'}++; |
1233
|
350
|
|
|
|
|
695
|
$Interfaces{$if}{Transport}{TCP}{'ACK Option Size'}{$tcp_hl}++; |
1234
|
|
|
|
|
|
|
} |
1235
|
|
|
|
|
|
|
} |
1236
|
|
|
|
|
|
|
} |
1237
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
################################################################## |
1239
|
|
|
|
|
|
|
# Export %senders and %segments |
1240
|
|
|
|
|
|
|
################################################################## |
1241
|
|
|
|
|
|
|
# Determine if we should collect statistics about the %senders and |
1242
|
|
|
|
|
|
|
# the %segments. If process_trace() was called in a void context |
1243
|
|
|
|
|
|
|
# then we do not need to collect such data, which results in |
1244
|
|
|
|
|
|
|
# tremendous memory usage savings. |
1245
|
|
|
|
|
|
|
# |
1246
|
4210
|
100
|
|
|
|
7339
|
if ( $tcp_payload > 0 ) { |
1247
|
1860
|
50
|
|
|
|
3159
|
if ( wantarray ) { |
1248
|
|
|
|
|
|
|
# Add elements to the hashes ONLY if the segment carries |
1249
|
|
|
|
|
|
|
# some payload. This way, one can be more sure if a given |
1250
|
|
|
|
|
|
|
# segment was retransmitted or not, since ACKs are not |
1251
|
|
|
|
|
|
|
# guaranteed reliable delivery. |
1252
|
|
|
|
|
|
|
# |
1253
|
|
|
|
|
|
|
# Occasionally, we may get 2 or more TCP segments with the |
1254
|
|
|
|
|
|
|
# same $timestamp. We would like to keep them in the |
1255
|
|
|
|
|
|
|
# segments hash and be able to discriminate between the |
1256
|
|
|
|
|
|
|
# different segments, so we use the following (hash) |
1257
|
|
|
|
|
|
|
# collision avoidance mechanism. |
1258
|
|
|
|
|
|
|
# |
1259
|
0
|
|
|
|
|
0
|
my $collisions = 0; |
1260
|
|
|
|
|
|
|
|
1261
|
0
|
|
|
|
|
0
|
while ( exists $segments{$if}{$timestamp}{bytes} ) { |
1262
|
|
|
|
|
|
|
# Sanity check: If more than TIMESTAMP_COLLISION_THRESHOLD |
1263
|
|
|
|
|
|
|
# trace records have the same timestamp, it is better to |
1264
|
|
|
|
|
|
|
# abort processing. Theoretically there shouldn't be two |
1265
|
|
|
|
|
|
|
# segments with the same timestamp. |
1266
|
|
|
|
|
|
|
# |
1267
|
0
|
0
|
|
|
|
0
|
croak 'Too many duplicate timestamps: ', $collisions, |
1268
|
|
|
|
|
|
|
' trace records have the same timestamp. Processing aborted' |
1269
|
|
|
|
|
|
|
if $collisions++ == TIMESTAMP_COLLISION_THRESHOLD; |
1270
|
|
|
|
|
|
|
|
1271
|
0
|
|
|
|
|
0
|
carp "Duplicate timestamp $timestamp detected & replaced with ", |
1272
|
|
|
|
|
|
|
$timestamp .= "1"; |
1273
|
|
|
|
|
|
|
|
1274
|
0
|
|
|
|
|
0
|
$Trace{Transport}{TCP}{'Concurrent Segments'}++; |
1275
|
|
|
|
|
|
|
} |
1276
|
|
|
|
|
|
|
|
1277
|
|
|
|
|
|
|
# Store the total length of the segment (headers + |
1278
|
|
|
|
|
|
|
# application payload), and the sequence number it carries |
1279
|
|
|
|
|
|
|
# |
1280
|
0
|
|
|
|
|
0
|
$segments{$if}{$timestamp}{bytes} = $ip_len; |
1281
|
0
|
|
|
|
|
0
|
$segments{$if}{$timestamp}{seq_num} = $seq_num; |
1282
|
|
|
|
|
|
|
|
1283
|
|
|
|
|
|
|
# In addition, flag by default every segment as an original |
1284
|
|
|
|
|
|
|
# transmission. Detection of retransmitted segments is not |
1285
|
|
|
|
|
|
|
# done in process_trace(), but rather in |
1286
|
|
|
|
|
|
|
# write_sojourn_times() |
1287
|
|
|
|
|
|
|
# |
1288
|
0
|
|
|
|
|
0
|
$segments{$if}{$timestamp}{retransmitted} = undef; |
1289
|
|
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
# Add the packet timestamp to the respective sender list |
1291
|
|
|
|
|
|
|
# |
1292
|
0
|
|
|
|
|
0
|
push @{ $senders{$if}{"$src,$src_port,$dst,$dst_port"} }, |
|
0
|
|
|
|
|
0
|
|
1293
|
|
|
|
|
|
|
$timestamp; |
1294
|
|
|
|
|
|
|
|
1295
|
|
|
|
|
|
|
# Flag bidirectional traffic found in the *same* interface. |
1296
|
|
|
|
|
|
|
# If bidirectional traffic is present in the same interface, |
1297
|
|
|
|
|
|
|
# it is not clear (yet) how to isolate "incoming" from |
1298
|
|
|
|
|
|
|
# "outgoing" traffic. |
1299
|
|
|
|
|
|
|
# |
1300
|
0
|
0
|
0
|
|
|
0
|
$Trace{unidirectional} = 0 |
1301
|
|
|
|
|
|
|
if ( $Trace{unidirectional} and |
1302
|
|
|
|
|
|
|
exists $senders{$if}{"$dst,$dst_port,$src,$src_port"} |
1303
|
|
|
|
|
|
|
); |
1304
|
|
|
|
|
|
|
} |
1305
|
|
|
|
|
|
|
|
1306
|
|
|
|
|
|
|
################################################################## |
1307
|
|
|
|
|
|
|
# Export TSH to ns2 binary traffic trace format |
1308
|
|
|
|
|
|
|
################################################################## |
1309
|
|
|
|
|
|
|
# Generate an ns2 binary traffic trace. (TCP data-carrying |
1310
|
|
|
|
|
|
|
# segements only) |
1311
|
|
|
|
|
|
|
# |
1312
|
1860
|
100
|
|
|
|
3813
|
if ( $options{ns2} ) { |
1313
|
|
|
|
|
|
|
|
1314
|
372
|
100
|
|
|
|
809
|
unless ( defined $ns2_fh{$if}) { |
1315
|
2
|
50
|
|
|
|
142
|
open($ns2_fh{$if}, '>', "$options{ns2}-if$if.bin") |
1316
|
|
|
|
|
|
|
or croak "Cannot open $options{ns2}-if$if.bin. $!"; |
1317
|
2
|
|
|
|
|
6
|
binmode $ns2_fh{$if}; # Needed for non-UNIX OSes; no harm in UNIX |
1318
|
|
|
|
|
|
|
|
1319
|
2
|
|
|
|
|
6
|
$ns2_previous_timestamp{$if} = $timestamp; |
1320
|
|
|
|
|
|
|
} |
1321
|
|
|
|
|
|
|
|
1322
|
|
|
|
|
|
|
print |
1323
|
372
|
|
|
|
|
369
|
{ $ns2_fh{$if} } |
|
372
|
|
|
|
|
1422
|
|
1324
|
|
|
|
|
|
|
pack('NN', # two integers: interpacket time (usec), packet size (B) |
1325
|
|
|
|
|
|
|
sprintf("%.0f", ( $timestamp |
1326
|
|
|
|
|
|
|
- $ns2_previous_timestamp{$if} ) * 1_000_000 |
1327
|
|
|
|
|
|
|
), |
1328
|
|
|
|
|
|
|
$ip_len |
1329
|
|
|
|
|
|
|
); |
1330
|
|
|
|
|
|
|
|
1331
|
372
|
|
|
|
|
669
|
$ns2_previous_timestamp{$if} = $timestamp; |
1332
|
|
|
|
|
|
|
} |
1333
|
|
|
|
|
|
|
} |
1334
|
|
|
|
|
|
|
|
1335
|
|
|
|
|
|
|
################################################################## |
1336
|
|
|
|
|
|
|
# Export TSH to tcpdump format |
1337
|
|
|
|
|
|
|
################################################################## |
1338
|
|
|
|
|
|
|
# Print a tcpdump-like time line of the TSH trace (for TCP |
1339
|
|
|
|
|
|
|
# segments only) |
1340
|
|
|
|
|
|
|
# |
1341
|
4210
|
100
|
|
|
|
9182
|
if ( $options{tcpdump}) { |
1342
|
842
|
|
|
|
|
4139
|
printf TCPDUMP "%1.9f ", $timestamp; |
1343
|
842
|
100
|
100
|
|
|
1821
|
print TCPDUMP |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1344
|
|
|
|
|
|
|
get_IP_address $src, ".$src_port > ", |
1345
|
|
|
|
|
|
|
get_IP_address $dst, ".$dst_port: ", |
1346
|
|
|
|
|
|
|
|
1347
|
|
|
|
|
|
|
$syn ? 'S' : '', # SYN: Synchronize sequence numbers |
1348
|
|
|
|
|
|
|
$fin ? 'F' : '', # FIN: Sender is finished sending data |
1349
|
|
|
|
|
|
|
$psh ? 'P' : '', # PSH: Push data to receiving process ASAP |
1350
|
|
|
|
|
|
|
$rst ? 'R' : '', # RST: Reset Connection |
1351
|
|
|
|
|
|
|
$cwr ? 'C' : '', # ECN: Congestion Window Reduced bit |
1352
|
|
|
|
|
|
|
$ece ? 'E' : '', # ECN: ECN-capable Transport |
1353
|
|
|
|
|
|
|
|
1354
|
|
|
|
|
|
|
($syn + $fin + $psh + $rst + $cwr + $ece) ? ' ' : '. ', |
1355
|
|
|
|
|
|
|
|
1356
|
|
|
|
|
|
|
($tcp_payload or $syn or $fin or $rst) |
1357
|
|
|
|
|
|
|
? join('', "$seq_num:", $seq_num + $tcp_payload, "($tcp_payload) ") |
1358
|
|
|
|
|
|
|
: '', |
1359
|
|
|
|
|
|
|
|
1360
|
|
|
|
|
|
|
$ack ? "ack $ack_num " : '', |
1361
|
|
|
|
|
|
|
"win $win ", |
1362
|
|
|
|
|
|
|
$urg ? "urg 1\n": "\n", |
1363
|
|
|
|
|
|
|
} |
1364
|
|
|
|
|
|
|
} |
1365
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
# The following is used both for sanity checks and to store the |
1367
|
|
|
|
|
|
|
# the duration of the trace |
1368
|
|
|
|
|
|
|
# |
1369
|
5000
|
|
|
|
|
20791
|
$Trace{ends} = $Interfaces{$if}{ends} = $timestamp; |
1370
|
|
|
|
|
|
|
|
1371
|
|
|
|
|
|
|
} # end of while( read...) |
1372
|
|
|
|
|
|
|
|
1373
|
5
|
|
|
|
|
5761
|
close INPUT; |
1374
|
|
|
|
|
|
|
|
1375
|
5
|
100
|
33
|
|
|
129
|
close TCPDUMP and |
1376
|
|
|
|
|
|
|
progress "TCP activity stored in text format in $options{tcpdump}\n" |
1377
|
|
|
|
|
|
|
if $options{tcpdump}; |
1378
|
|
|
|
|
|
|
|
1379
|
5
|
50
|
33
|
|
|
55
|
carp $Trace{Transport}{TCP}{'Concurrent Segments'}, |
1380
|
|
|
|
|
|
|
' TCP segments had the same timestamp with another segment' |
1381
|
|
|
|
|
|
|
if $Trace{Transport}{TCP}{'Concurrent Segments'} and wantarray; |
1382
|
|
|
|
|
|
|
|
1383
|
|
|
|
|
|
|
# Since we keep track of statistics on a per-interface basis, we |
1384
|
|
|
|
|
|
|
# need to copy the data to %Trace for backwards compatibility. |
1385
|
|
|
|
|
|
|
# |
1386
|
5
|
|
|
|
|
27
|
my @interfaces = get_interfaces_list; |
1387
|
5
|
|
|
|
|
23
|
$Trace{interfaces} = scalar @interfaces; |
1388
|
|
|
|
|
|
|
|
1389
|
5
|
|
|
|
|
10
|
my $total_records = 0; |
1390
|
|
|
|
|
|
|
|
1391
|
5
|
|
|
|
|
19
|
foreach my $if ( @interfaces ) { |
1392
|
|
|
|
|
|
|
|
1393
|
10
|
|
|
|
|
27
|
$total_records += $Interfaces{$if}{records}; |
1394
|
|
|
|
|
|
|
|
1395
|
9
|
|
|
9
|
|
63
|
no warnings qw(uninitialized); |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
12159
|
|
1396
|
|
|
|
|
|
|
|
1397
|
10
|
|
|
|
|
12
|
my @transports = sort keys %{$Interfaces{$if}{Transport}}; |
|
10
|
|
|
|
|
74
|
|
1398
|
|
|
|
|
|
|
|
1399
|
10
|
|
|
|
|
25
|
foreach my $metric ('Packets', 'Bytes') { |
1400
|
20
|
|
|
|
|
40
|
foreach ( @data_points ) { |
1401
|
220
|
|
|
|
|
734
|
$Trace{IP}{$_}{$metric} += $Interfaces{$if}{IP}{$_}{$metric}; |
1402
|
|
|
|
|
|
|
|
1403
|
220
|
|
|
|
|
278
|
foreach my $protocol ( @transports ) { |
1404
|
770
|
|
|
|
|
2977
|
$Trace{Transport}{$protocol}{$_}{$metric} |
1405
|
|
|
|
|
|
|
+= $Interfaces{$if}{Transport}{$protocol}{$_}{$metric}; |
1406
|
|
|
|
|
|
|
} |
1407
|
|
|
|
|
|
|
} |
1408
|
|
|
|
|
|
|
} |
1409
|
|
|
|
|
|
|
|
1410
|
|
|
|
|
|
|
# ACKs |
1411
|
|
|
|
|
|
|
# |
1412
|
10
|
|
|
|
|
25
|
foreach ( 'Total ACKs', 'Cumulative ACKs', 'Pure ACKs', 'Options ACKs' ) { |
1413
|
40
|
|
|
|
|
123
|
$Trace{Transport}{TCP}{$_} += $Interfaces{$if}{Transport}{TCP}{$_}; |
1414
|
|
|
|
|
|
|
} |
1415
|
|
|
|
|
|
|
|
1416
|
|
|
|
|
|
|
# Advertised window |
1417
|
|
|
|
|
|
|
# |
1418
|
10
|
|
|
|
|
20
|
foreach ( keys %{$Interfaces{$if}{Transport}{TCP}{rwnd}} ) { |
|
10
|
|
|
|
|
69
|
|
1419
|
120
|
|
|
|
|
347
|
$Trace{Transport}{TCP}{rwnd}{$_} |
1420
|
|
|
|
|
|
|
+= $Interfaces{$if}{Transport}{TCP}{rwnd}{$_}; |
1421
|
|
|
|
|
|
|
|
1422
|
120
|
|
|
|
|
437
|
$Trace{Transport}{TCP}{awnd}{$_} |
1423
|
|
|
|
|
|
|
+= $Interfaces{$if}{Transport}{TCP}{awnd}{$_}; |
1424
|
|
|
|
|
|
|
} |
1425
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
# SYN and SYN/ACKs |
1427
|
|
|
|
|
|
|
# |
1428
|
10
|
|
|
|
|
25
|
foreach ( keys %{$Interfaces{$if}{Transport}{TCP}{SYN}} ) { |
|
10
|
|
|
|
|
219
|
|
1429
|
40
|
|
|
|
|
116
|
$Trace{Transport}{TCP}{SYN}{$_} |
1430
|
|
|
|
|
|
|
+= $Interfaces{$if}{Transport}{TCP}{SYN}{$_}; |
1431
|
|
|
|
|
|
|
|
1432
|
40
|
|
|
|
|
189
|
$Trace{Transport}{TCP}{'SYN/ACK'}{$_} |
1433
|
|
|
|
|
|
|
+= $Interfaces{$if}{Transport}{TCP}{'SYN/ACK'}{$_}; |
1434
|
|
|
|
|
|
|
|
1435
|
40
|
|
|
|
|
171
|
$Trace{Transport}{TCP}{'SYN/Payload'} |
1436
|
|
|
|
|
|
|
+= $Interfaces{$if}{Transport}{TCP}{'SYN/Payload'}; |
1437
|
|
|
|
|
|
|
} |
1438
|
|
|
|
|
|
|
|
1439
|
|
|
|
|
|
|
# TCP Options ACKs |
1440
|
|
|
|
|
|
|
# |
1441
|
10
|
|
|
|
|
28
|
while ( my ($k, $v) = each |
|
40
|
|
|
|
|
148
|
|
1442
|
|
|
|
|
|
|
%{$Interfaces{$if}{Transport}{TCP}{'ACK Option Size'}} ) { |
1443
|
30
|
|
|
|
|
80
|
$Trace{Transport}{TCP}{'ACK Option Size'}{$k} += $v; |
1444
|
|
|
|
|
|
|
} |
1445
|
|
|
|
|
|
|
|
1446
|
|
|
|
|
|
|
# Packet size distribution |
1447
|
|
|
|
|
|
|
# |
1448
|
10
|
|
|
|
|
19
|
while ( my ($k, $v) = each %{$Interfaces{$if}{IP}{'Packet Size'}} ) { |
|
730
|
|
|
|
|
2735
|
|
1449
|
720
|
|
|
|
|
1538
|
$Trace{IP}{'Packet Size'}{$k} += $v; |
1450
|
|
|
|
|
|
|
|
1451
|
720
|
|
|
|
|
1169
|
foreach ( @transports ) { |
1452
|
2575
|
|
|
|
|
8495
|
$Trace{Transport}{$_}{'Packet Size'}{$k} |
1453
|
|
|
|
|
|
|
+= $Interfaces{$if}{Transport}{$_}{'Packet Size'}{$k}; |
1454
|
|
|
|
|
|
|
} |
1455
|
|
|
|
|
|
|
} |
1456
|
|
|
|
|
|
|
} |
1457
|
|
|
|
|
|
|
|
1458
|
|
|
|
|
|
|
# Sanity checks |
1459
|
|
|
|
|
|
|
# |
1460
|
5
|
|
|
|
|
23
|
my $total_packets; |
1461
|
5
|
|
|
|
|
22
|
while ( ($_) = each %{$Trace{Transport}} ) { |
|
25
|
|
|
|
|
93
|
|
1462
|
20
|
|
|
|
|
50
|
$total_packets += $Trace{Transport}{$_}{Total}{Packets}; |
1463
|
|
|
|
|
|
|
} |
1464
|
|
|
|
|
|
|
|
1465
|
5
|
50
|
|
|
|
32
|
croak "Total number of packets is not equal to the number of trace records" |
1466
|
|
|
|
|
|
|
unless $Trace{records} == $total_packets; |
1467
|
|
|
|
|
|
|
|
1468
|
5
|
50
|
|
|
|
40
|
croak "The estimated number of records based on the file size does not equal the number of records observed across all interfaces" |
1469
|
|
|
|
|
|
|
unless $total_records == $Trace{records}; |
1470
|
|
|
|
|
|
|
|
1471
|
5
|
100
|
|
|
|
149
|
return (\%senders, \%segments) if defined wantarray; |
1472
|
|
|
|
|
|
|
} |
1473
|
|
|
|
|
|
|
|
1474
|
|
|
|
|
|
|
sub progress( $ ) { |
1475
|
17
|
50
|
|
17
|
0
|
79
|
print STDERR shift if $options{Verbosity}; |
1476
|
|
|
|
|
|
|
} |
1477
|
|
|
|
|
|
|
|
1478
|
|
|
|
|
|
|
=head2 records_in |
1479
|
|
|
|
|
|
|
|
1480
|
|
|
|
|
|
|
records_in FILENAME |
1481
|
|
|
|
|
|
|
|
1482
|
|
|
|
|
|
|
Estimates the number to records in FILENAME based on its file size. |
1483
|
|
|
|
|
|
|
It returns an integer corresponding to the "expected" number of |
1484
|
|
|
|
|
|
|
records in the trace, or I if the file size does not seem to |
1485
|
|
|
|
|
|
|
correspond to a legitimate TSH trace. |
1486
|
|
|
|
|
|
|
|
1487
|
|
|
|
|
|
|
=cut |
1488
|
|
|
|
|
|
|
|
1489
|
|
|
|
|
|
|
sub records_in( $ ) { |
1490
|
7
|
|
|
7
|
1
|
661
|
my $no_records = (-s shift) / TSH_RECORD_LENGTH; |
1491
|
|
|
|
|
|
|
|
1492
|
7
|
100
|
|
|
|
568
|
$no_records == int $no_records and return $no_records; |
1493
|
|
|
|
|
|
|
} |
1494
|
|
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
|
1496
|
|
|
|
|
|
|
=head2 verbose |
1497
|
|
|
|
|
|
|
|
1498
|
|
|
|
|
|
|
verbose |
1499
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
As you might expect, this function sets the verbosity level of the |
1501
|
|
|
|
|
|
|
module. By default C remains "silent". Call |
1502
|
|
|
|
|
|
|
verbose() to see trace processing progress indicators on standard |
1503
|
|
|
|
|
|
|
error. |
1504
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
As of version 0.13, verbose() is equivalent to |
1506
|
|
|
|
|
|
|
|
1507
|
|
|
|
|
|
|
configure(Verbosity => 1); |
1508
|
|
|
|
|
|
|
|
1509
|
|
|
|
|
|
|
=cut |
1510
|
|
|
|
|
|
|
|
1511
|
|
|
|
|
|
|
sub verbose () { |
1512
|
|
|
|
|
|
|
|
1513
|
1
|
|
|
1
|
1
|
177
|
$options{Verbosity} = 1; |
1514
|
|
|
|
|
|
|
|
1515
|
|
|
|
|
|
|
} |
1516
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
# Utility function to export the information stored in %Trace and |
1518
|
|
|
|
|
|
|
# %Interfaces in CSV format |
1519
|
|
|
|
|
|
|
# |
1520
|
|
|
|
|
|
|
sub write_summary( *$ ; $ ) { |
1521
|
3
|
|
|
3
|
0
|
11
|
my ( $FH, $href, $if ) = @_; |
1522
|
|
|
|
|
|
|
|
1523
|
3
|
50
|
33
|
|
|
39
|
confess "usage: write_summary(FILEHANDLE, HASH_REFERENCE)" |
1524
|
|
|
|
|
|
|
unless ref($FH) eq 'GLOB' and ref($href) eq 'HASH'; |
1525
|
|
|
|
|
|
|
|
1526
|
|
|
|
|
|
|
# Prepare to print general trace file information |
1527
|
|
|
|
|
|
|
# |
1528
|
3
|
|
|
|
|
165
|
print $FH <
|
1529
|
|
|
|
|
|
|
GENERAL TRACE INFORMATION |
1530
|
|
|
|
|
|
|
Filename,$Trace{filename},$Trace{date} |
1531
|
|
|
|
|
|
|
Duration,$Trace{ends} |
1532
|
|
|
|
|
|
|
Records,$Trace{records} |
1533
|
|
|
|
|
|
|
Interfaces,$Trace{interfaces} |
1534
|
|
|
|
|
|
|
GENERAL_INFO |
1535
|
|
|
|
|
|
|
|
1536
|
3
|
50
|
|
|
|
54
|
print $FH "Link Capacity,$Trace{'Link Capacity'}\n" |
1537
|
|
|
|
|
|
|
if $Trace{'Link Capacity'}; |
1538
|
|
|
|
|
|
|
|
1539
|
3
|
50
|
|
|
|
22
|
print $FH 'Duplicate timestamps,', |
1540
|
|
|
|
|
|
|
$Trace{Transport}{TCP}{'Concurrent Segments'}, "\n" |
1541
|
|
|
|
|
|
|
if $Trace{Transport}{TCP}{'Concurrent Segments'}; |
1542
|
|
|
|
|
|
|
|
1543
|
3
|
100
|
|
|
|
10
|
if ( defined $if ) { |
1544
|
2
|
|
|
|
|
15
|
print $FH <
|
1545
|
|
|
|
|
|
|
|
1546
|
|
|
|
|
|
|
INTERFACE INFORMATION |
1547
|
|
|
|
|
|
|
Interface Number,$if |
1548
|
|
|
|
|
|
|
Duration,$href->{ends} |
1549
|
|
|
|
|
|
|
Records,$href->{records} |
1550
|
|
|
|
|
|
|
|
1551
|
|
|
|
|
|
|
INTERFACE TRAFFIC DENSITY |
1552
|
|
|
|
|
|
|
,Pkts/s,Bytes/Pkt,b/s |
1553
|
|
|
|
|
|
|
INTERFACE_INFO |
1554
|
|
|
|
|
|
|
|
1555
|
2
|
|
|
|
|
34
|
printf $FH |
1556
|
|
|
|
|
|
|
"IP Total,%.0f,%.0f,%.0f\n", |
1557
|
|
|
|
|
|
|
$href->{IP}{Total}{Packets} / $href->{ends}, |
1558
|
|
|
|
|
|
|
$href->{IP}{Total}{Bytes} / $href->{IP}{Total}{Packets}, |
1559
|
|
|
|
|
|
|
$href->{IP}{Total}{Bytes} * 8 / $href->{ends}; |
1560
|
|
|
|
|
|
|
|
1561
|
2
|
50
|
|
|
|
14
|
if ( $href->{Transport}{TCP}{Total}{Packets}) { |
1562
|
2
|
|
|
|
|
18
|
printf $FH "TCP Total,%.0f,%.0f,%.0f", |
1563
|
|
|
|
|
|
|
$href->{Transport}{TCP}{Total}{Packets} / $href->{ends}, |
1564
|
|
|
|
|
|
|
( $href->{Transport}{TCP}{Total}{Bytes} |
1565
|
|
|
|
|
|
|
/ $href->{Transport}{TCP}{Total}{Packets} |
1566
|
|
|
|
|
|
|
), |
1567
|
|
|
|
|
|
|
( ( $href->{Transport}{TCP}{Total}{Bytes} * 8 ) |
1568
|
|
|
|
|
|
|
/ $href->{ends} |
1569
|
|
|
|
|
|
|
); |
1570
|
|
|
|
|
|
|
} |
1571
|
|
|
|
|
|
|
else { |
1572
|
0
|
|
|
|
|
0
|
print $FH "TCP Total,0,0,0"; |
1573
|
|
|
|
|
|
|
} |
1574
|
|
|
|
|
|
|
} |
1575
|
|
|
|
|
|
|
|
1576
|
3
|
|
|
|
|
14
|
my @transports = sort keys %{$href->{Transport}}; |
|
3
|
|
|
|
|
30
|
|
1577
|
|
|
|
|
|
|
|
1578
|
3
|
|
|
|
|
10
|
foreach my $metric ('Packets', 'Bytes') { |
1579
|
6
|
|
|
|
|
37
|
print $FH |
1580
|
|
|
|
|
|
|
"\n\nIP STATISTICS (", uc($metric), |
1581
|
|
|
|
|
|
|
")\n,,Fragmentation,,Explicit Congestion Notification,,", |
1582
|
|
|
|
|
|
|
"Differentiated Services,,,,IP Options\n,", |
1583
|
|
|
|
|
|
|
join( ',', @data_points), "\nIP"; |
1584
|
|
|
|
|
|
|
|
1585
|
|
|
|
|
|
|
# Some of the entries in the hashes below are naturally |
1586
|
|
|
|
|
|
|
# uninitialized. For example, a given trace may not have any |
1587
|
|
|
|
|
|
|
# packets the MF bit set. We take advantage of Perl's automatic |
1588
|
|
|
|
|
|
|
# conversion of uninitialized values to 0 (in a scalar/number |
1589
|
|
|
|
|
|
|
# context). However, with warnings on, this may cause a |
1590
|
|
|
|
|
|
|
# considerable number warnings re: uninitialized values possibly |
1591
|
|
|
|
|
|
|
# leading a novice user to believe that something REALLY BAD |
1592
|
|
|
|
|
|
|
# happened, which is not the case. So we disable these particular |
1593
|
|
|
|
|
|
|
# warnings for the rest of the block. This "practice is followed |
1594
|
|
|
|
|
|
|
# in the rest of the code below, as necessary. |
1595
|
|
|
|
|
|
|
# |
1596
|
9
|
|
|
9
|
|
62
|
no warnings qw(uninitialized); |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
1903
|
|
1597
|
|
|
|
|
|
|
|
1598
|
6
|
|
|
|
|
14
|
foreach ( @data_points ) { |
1599
|
66
|
|
|
|
|
249
|
printf $FH ",%d", $href->{IP}{$_}{$metric}; |
1600
|
|
|
|
|
|
|
} |
1601
|
|
|
|
|
|
|
|
1602
|
6
|
|
|
|
|
13
|
foreach my $protocol ( @transports ) { |
1603
|
22
|
|
|
|
|
38
|
print $FH "\n$protocol"; |
1604
|
|
|
|
|
|
|
|
1605
|
22
|
|
|
|
|
33
|
foreach ( @data_points ) { |
1606
|
242
|
|
|
|
|
1214
|
printf $FH ",%d", $href->{Transport}{$protocol}{$_}{$metric}; |
1607
|
|
|
|
|
|
|
} |
1608
|
|
|
|
|
|
|
} |
1609
|
|
|
|
|
|
|
} |
1610
|
|
|
|
|
|
|
|
1611
|
|
|
|
|
|
|
# Print distribution of ACKs |
1612
|
|
|
|
|
|
|
# |
1613
|
3
|
50
|
|
|
|
16
|
if ( $href->{Transport}{TCP}{'Total ACKs'} ) { |
1614
|
3
|
|
|
|
|
7
|
print $FH "\n\nTCP ACKNOWLEDGEMENTS\n"; |
1615
|
|
|
|
|
|
|
|
1616
|
3
|
|
|
|
|
7
|
foreach ( 'Total ACKs', 'Cumulative ACKs', 'Pure ACKs', 'Options ACKs' ) { |
1617
|
12
|
|
|
|
|
54
|
printf $FH "$_,%d\n", $href->{Transport}{TCP}{$_}; |
1618
|
|
|
|
|
|
|
} |
1619
|
|
|
|
|
|
|
} |
1620
|
|
|
|
|
|
|
|
1621
|
|
|
|
|
|
|
# Print the TCP Advertised window distribution |
1622
|
|
|
|
|
|
|
# |
1623
|
3
|
50
|
|
|
|
23
|
if ( $href->{Transport}{TCP}{rwnd} ) { |
1624
|
3
|
|
|
|
|
6
|
print $FH |
1625
|
|
|
|
|
|
|
"\nRECEIVER ADVERTISED WINDOW\nSize (Bytes),Soft Count,Hard Count\n"; |
1626
|
|
|
|
|
|
|
|
1627
|
9
|
|
|
9
|
|
46
|
no warnings qw(uninitialized); |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
1087
|
|
1628
|
|
|
|
|
|
|
|
1629
|
3
|
|
|
|
|
8
|
foreach ( sort numerically keys %{$href->{Transport}{TCP}{rwnd}} ) { |
|
3
|
|
|
|
|
58
|
|
1630
|
47
|
|
|
|
|
242
|
printf $FH "%d,%d,%d\n", $_, |
1631
|
|
|
|
|
|
|
|
1632
|
|
|
|
|
|
|
$href->{Transport}{TCP}{rwnd}{$_} |
1633
|
|
|
|
|
|
|
- $href->{Transport}{TCP}{awnd}{$_}, |
1634
|
|
|
|
|
|
|
|
1635
|
|
|
|
|
|
|
$href->{Transport}{TCP}{awnd}{$_}; |
1636
|
|
|
|
|
|
|
} |
1637
|
|
|
|
|
|
|
} |
1638
|
|
|
|
|
|
|
|
1639
|
|
|
|
|
|
|
# Print the TCP Options-carrying SYN size distribution |
1640
|
|
|
|
|
|
|
# |
1641
|
3
|
50
|
|
|
|
18
|
if ( $href->{Transport}{TCP}{SYN} ) { |
1642
|
3
|
|
|
|
|
7
|
print $FH |
1643
|
|
|
|
|
|
|
"\nTCP OPTIONS NEGOTIATION\n", |
1644
|
|
|
|
|
|
|
'TCP Header Length (Bytes),SYN,SYN/ACK'; |
1645
|
|
|
|
|
|
|
|
1646
|
9
|
|
|
9
|
|
127
|
no warnings qw(uninitialized); |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
1423
|
|
1647
|
|
|
|
|
|
|
|
1648
|
3
|
|
|
|
|
5
|
foreach ( sort numerically keys %{$href->{Transport}{TCP}{SYN}} ) { |
|
3
|
|
|
|
|
20
|
|
1649
|
14
|
|
|
|
|
81
|
print $FH "\n$_,", |
1650
|
|
|
|
|
|
|
$href->{Transport}{TCP}{SYN}{$_} |
1651
|
|
|
|
|
|
|
- $href->{Transport}{TCP}{'SYN/ACK'}{$_}, ',', |
1652
|
|
|
|
|
|
|
$href->{Transport}{TCP}{'SYN/ACK'}{$_}; |
1653
|
|
|
|
|
|
|
} |
1654
|
|
|
|
|
|
|
|
1655
|
3
|
|
|
|
|
13
|
print $FH "\nSYN/Payload,", $href->{Transport}{TCP}{'SYN/Payload'}; |
1656
|
|
|
|
|
|
|
} |
1657
|
|
|
|
|
|
|
|
1658
|
|
|
|
|
|
|
# Print the distribution of ACKs carrying TCP options |
1659
|
|
|
|
|
|
|
# |
1660
|
3
|
50
|
|
|
|
13
|
if ( $href->{Transport}{TCP}{'Options ACKs'}) { |
1661
|
3
|
|
|
|
|
90
|
print $FH "\n\nTCP OPTIONS ACK USAGE\nTCP Header Length (Bytes),Count"; |
1662
|
|
|
|
|
|
|
|
1663
|
9
|
|
|
9
|
|
50
|
no warnings qw(uninitialized); |
|
9
|
|
|
|
|
15
|
|
|
9
|
|
|
|
|
6160
|
|
1664
|
|
|
|
|
|
|
|
1665
|
3
|
|
|
|
|
5
|
foreach ( sort numerically keys |
|
3
|
|
|
|
|
16
|
|
1666
|
|
|
|
|
|
|
%{$href->{Transport}{TCP}{'ACK Option Size'}} ) |
1667
|
|
|
|
|
|
|
{ |
1668
|
10
|
|
|
|
|
37
|
print $FH "\n$_,", $href->{Transport}{TCP}{'ACK Option Size'}{$_}; |
1669
|
|
|
|
|
|
|
} |
1670
|
|
|
|
|
|
|
} |
1671
|
|
|
|
|
|
|
|
1672
|
|
|
|
|
|
|
# Print the packet size distribution |
1673
|
|
|
|
|
|
|
# |
1674
|
3
|
|
|
|
|
13
|
print $FH join ',', "\n\nPACKET SIZE DISTRIBUTION\nBytes,IP", @transports; |
1675
|
|
|
|
|
|
|
|
1676
|
3
|
|
|
|
|
5
|
foreach ( sort numerically keys %{$href->{IP}{'Packet Size'}} ) { |
|
3
|
|
|
|
|
71
|
|
1677
|
270
|
|
|
|
|
1102
|
print $FH "\n$_,$href->{IP}{'Packet Size'}{$_}"; |
1678
|
|
|
|
|
|
|
|
1679
|
270
|
|
|
|
|
331
|
foreach my $prt ( @transports ) { |
1680
|
1019
|
|
|
|
|
3717
|
print_value(\*$FH, $href->{Transport}{$prt}{'Packet Size'}{$_}); |
1681
|
|
|
|
|
|
|
} |
1682
|
|
|
|
|
|
|
} |
1683
|
|
|
|
|
|
|
|
1684
|
3
|
|
|
|
|
31
|
print $FH "\n"; |
1685
|
|
|
|
|
|
|
} |
1686
|
|
|
|
|
|
|
|
1687
|
|
|
|
|
|
|
=head2 write_interface_summaries |
1688
|
|
|
|
|
|
|
|
1689
|
|
|
|
|
|
|
write_interface_summaries |
1690
|
|
|
|
|
|
|
write_interface_summaries FILE_PREFIX |
1691
|
|
|
|
|
|
|
|
1692
|
|
|
|
|
|
|
Writes a CSV summary similar to what write_trace_summary() generates |
1693
|
|
|
|
|
|
|
for each interface in the trace (see L<%Interfaces|"Data |
1694
|
|
|
|
|
|
|
Structures">). Each summary file has a C<.if-X.csv> suffix, where X |
1695
|
|
|
|
|
|
|
is the number of the interface. If FILE_PREFIX is provided, |
1696
|
|
|
|
|
|
|
write_interface_summaries() will append to it this standard suffix |
1697
|
|
|
|
|
|
|
(indicative of the interface). |
1698
|
|
|
|
|
|
|
|
1699
|
|
|
|
|
|
|
=cut |
1700
|
|
|
|
|
|
|
|
1701
|
|
|
|
|
|
|
sub write_interface_summaries( ; $ ) { |
1702
|
|
|
|
|
|
|
|
1703
|
1
|
|
|
1
|
1
|
454
|
foreach my $if ( get_interfaces_list ) { |
1704
|
|
|
|
|
|
|
# Open the interface-specific summary |
1705
|
|
|
|
|
|
|
# |
1706
|
2
|
|
33
|
|
|
26
|
my $if_summary = shift || $Trace{filename}; |
1707
|
2
|
|
|
|
|
6
|
$if_summary .= ".if-$if.csv"; |
1708
|
|
|
|
|
|
|
|
1709
|
2
|
50
|
|
|
|
91672
|
open(LOG, '>', $if_summary) |
1710
|
|
|
|
|
|
|
or croak "Cannot open interface-specific summary. $!"; |
1711
|
|
|
|
|
|
|
|
1712
|
2
|
|
|
|
|
36
|
progress 'Generating interface-specific summary... '; |
1713
|
|
|
|
|
|
|
|
1714
|
2
|
|
|
|
|
25
|
write_summary( \*LOG, $Interfaces{$if}, $if ); |
1715
|
|
|
|
|
|
|
|
1716
|
2
|
|
|
|
|
182
|
close LOG; |
1717
|
|
|
|
|
|
|
|
1718
|
2
|
|
|
|
|
15
|
progress "see $if_summary\n"; |
1719
|
|
|
|
|
|
|
} |
1720
|
|
|
|
|
|
|
|
1721
|
|
|
|
|
|
|
} |
1722
|
|
|
|
|
|
|
|
1723
|
|
|
|
|
|
|
=head2 write_trace_summary |
1724
|
|
|
|
|
|
|
|
1725
|
|
|
|
|
|
|
write_trace_summary |
1726
|
|
|
|
|
|
|
write_trace_summary FILENAME |
1727
|
|
|
|
|
|
|
|
1728
|
|
|
|
|
|
|
Writes the contents of L<%Trace|"Data Structures"> to FILENAME |
1729
|
|
|
|
|
|
|
in comma separated values (CSV) format, a platform independent text |
1730
|
|
|
|
|
|
|
format, excellent for storing tabular data. CSV is both |
1731
|
|
|
|
|
|
|
human-readable and suitable for further analysis using Perl or direct |
1732
|
|
|
|
|
|
|
import to a spreadsheet application. Although not required, it is |
1733
|
|
|
|
|
|
|
recommended that FILENAME should have a I<.csv> suffix. |
1734
|
|
|
|
|
|
|
|
1735
|
|
|
|
|
|
|
If FILENAME is not specified, write_trace_summary() will create one |
1736
|
|
|
|
|
|
|
for you by appending the suffix I<.csv> to the L
|
1737
|
|
|
|
|
|
|
Trace Information"> of the trace being processed. |
1738
|
|
|
|
|
|
|
|
1739
|
|
|
|
|
|
|
If you want FILENAME to contain meaningful data you should call |
1740
|
|
|
|
|
|
|
write_trace_summary() I calling process_trace(). |
1741
|
|
|
|
|
|
|
|
1742
|
|
|
|
|
|
|
=cut |
1743
|
|
|
|
|
|
|
|
1744
|
|
|
|
|
|
|
sub write_trace_summary( ; $ ) { |
1745
|
|
|
|
|
|
|
|
1746
|
1
|
50
|
33
|
1
|
1
|
828
|
croak |
|
|
|
33
|
|
|
|
|
1747
|
|
|
|
|
|
|
'Important trace information was not found. Call process_trace() before ', |
1748
|
|
|
|
|
|
|
"calling write_trace_summary().\nTrace summary generation aborted" |
1749
|
|
|
|
|
|
|
unless ( $Trace{IP}{Total}{Bytes} |
1750
|
|
|
|
|
|
|
and $Trace{IP}{Total}{Packets} |
1751
|
|
|
|
|
|
|
and $Trace{ends} |
1752
|
|
|
|
|
|
|
); |
1753
|
|
|
|
|
|
|
|
1754
|
|
|
|
|
|
|
# Open the log file (expected to be .csv) |
1755
|
|
|
|
|
|
|
# |
1756
|
1
|
|
33
|
|
|
9
|
$Trace{summary} = shift || "$Trace{filename}.csv"; |
1757
|
|
|
|
|
|
|
|
1758
|
1
|
50
|
|
|
|
158
|
open(LOG, '>', $Trace{summary}) |
1759
|
|
|
|
|
|
|
or croak "Cannot write trace summary to $Trace{summary}. $!"; |
1760
|
|
|
|
|
|
|
|
1761
|
1
|
|
|
|
|
10
|
progress 'Generating trace summary... '; |
1762
|
|
|
|
|
|
|
|
1763
|
1
|
|
|
|
|
7
|
write_summary( \*LOG, \%Trace ); |
1764
|
|
|
|
|
|
|
|
1765
|
1
|
|
|
|
|
363
|
close LOG; |
1766
|
|
|
|
|
|
|
|
1767
|
1
|
|
|
|
|
15
|
progress "see $Trace{summary}\n"; |
1768
|
|
|
|
|
|
|
} |
1769
|
|
|
|
|
|
|
|
1770
|
|
|
|
|
|
|
sub print_value(*$) { |
1771
|
1019
|
|
|
1019
|
0
|
1247
|
my ($fh, $value) = @_; |
1772
|
1019
|
100
|
|
|
|
1158
|
print {$fh} $value ? ",$value" : ',0'; |
|
1019
|
|
|
|
|
4900
|
|
1773
|
|
|
|
|
|
|
} |
1774
|
|
|
|
|
|
|
|
1775
|
|
|
|
|
|
|
# Mandatory: the module must return "true" |
1776
|
|
|
|
|
|
|
# |
1777
|
|
|
|
|
|
|
|
1778
|
|
|
|
|
|
|
1; |
1779
|
|
|
|
|
|
|
|
1780
|
|
|
|
|
|
|
=head1 DEPENDENCIES |
1781
|
|
|
|
|
|
|
|
1782
|
|
|
|
|
|
|
Nothing non-standard: L, L and L. |
1783
|
|
|
|
|
|
|
|
1784
|
|
|
|
|
|
|
=head2 EXPORTS |
1785
|
|
|
|
|
|
|
|
1786
|
|
|
|
|
|
|
None by default. |
1787
|
|
|
|
|
|
|
|
1788
|
|
|
|
|
|
|
=head3 Exportable |
1789
|
|
|
|
|
|
|
|
1790
|
|
|
|
|
|
|
configure() date_of() get_IP_address() get_interfaces_href() |
1791
|
|
|
|
|
|
|
get_interfaces_list() get_trace_summary_href() numerically() |
1792
|
|
|
|
|
|
|
process_trace() records_in() verbose() write_trace_summary() |
1793
|
|
|
|
|
|
|
|
1794
|
|
|
|
|
|
|
In addition, the following export tags are defined: |
1795
|
|
|
|
|
|
|
|
1796
|
|
|
|
|
|
|
=over |
1797
|
|
|
|
|
|
|
|
1798
|
|
|
|
|
|
|
=item :traffic_analysis |
1799
|
|
|
|
|
|
|
|
1800
|
|
|
|
|
|
|
verbose() process_trace() write_interface_summaries() |
1801
|
|
|
|
|
|
|
write_trace_summary() |
1802
|
|
|
|
|
|
|
|
1803
|
|
|
|
|
|
|
=item :trace_information |
1804
|
|
|
|
|
|
|
|
1805
|
|
|
|
|
|
|
date_of() records_in() |
1806
|
|
|
|
|
|
|
|
1807
|
|
|
|
|
|
|
=back |
1808
|
|
|
|
|
|
|
|
1809
|
|
|
|
|
|
|
Finally, all exportable functions can be imported with |
1810
|
|
|
|
|
|
|
|
1811
|
|
|
|
|
|
|
use Net::Traces::TSH qw(:all); |
1812
|
|
|
|
|
|
|
|
1813
|
|
|
|
|
|
|
=head1 VERSION |
1814
|
|
|
|
|
|
|
|
1815
|
|
|
|
|
|
|
This is C version 0.16. |
1816
|
|
|
|
|
|
|
|
1817
|
|
|
|
|
|
|
=head1 SEE ALSO |
1818
|
|
|
|
|
|
|
|
1819
|
|
|
|
|
|
|
The NLANR MOAT Passive Measurement and Analysis (PMA) web site at |
1820
|
|
|
|
|
|
|
http://pma.nlanr.net/PMA provides more details on the process of |
1821
|
|
|
|
|
|
|
collecting packet traces. The site features a set of Perl programs |
1822
|
|
|
|
|
|
|
you can download, including several converters from other packet trace |
1823
|
|
|
|
|
|
|
formats to TSH. |
1824
|
|
|
|
|
|
|
|
1825
|
|
|
|
|
|
|
TSH trace files can be downloaded from the NLANR/PMA trace repository |
1826
|
|
|
|
|
|
|
at http://pma.nlanr.net/Traces . The site contains a variety of |
1827
|
|
|
|
|
|
|
traces gathered from several monitoring points at university campuses |
1828
|
|
|
|
|
|
|
and (Giga)PoPs connected to a variety of large and small networks. |
1829
|
|
|
|
|
|
|
|
1830
|
|
|
|
|
|
|
C version 0.11 was presented in YAPC::NA 2004. The |
1831
|
|
|
|
|
|
|
presentation slides are available at |
1832
|
|
|
|
|
|
|
http://www.cs.stonybrook.edu/~kostas/art/yapc . |
1833
|
|
|
|
|
|
|
|
1834
|
|
|
|
|
|
|
=head2 DiffServ |
1835
|
|
|
|
|
|
|
|
1836
|
|
|
|
|
|
|
If you are not familiar with Differentiated Services (DiffServ), good |
1837
|
|
|
|
|
|
|
starting points are the following RFCs: |
1838
|
|
|
|
|
|
|
|
1839
|
|
|
|
|
|
|
K. Nichols I, I
|
1840
|
|
|
|
|
|
|
Field (DS Field) in the IPv4 and IPv6 Headers>, RFC 2474. Available at |
1841
|
|
|
|
|
|
|
http://www.ietf.org/rfc/rfc2474.txt |
1842
|
|
|
|
|
|
|
|
1843
|
|
|
|
|
|
|
S. Blake I, I, |
1844
|
|
|
|
|
|
|
RFC 2475. Available at http://www.ietf.org/rfc/rfc2475.txt |
1845
|
|
|
|
|
|
|
|
1846
|
|
|
|
|
|
|
See also RFC 2597 and RFC 2598. |
1847
|
|
|
|
|
|
|
|
1848
|
|
|
|
|
|
|
=head2 ECN |
1849
|
|
|
|
|
|
|
|
1850
|
|
|
|
|
|
|
If you are not familiar Explicit Congestion Notification (ECN) make |
1851
|
|
|
|
|
|
|
sure to read |
1852
|
|
|
|
|
|
|
|
1853
|
|
|
|
|
|
|
K. K. Ramakrishnan I, I
|
1854
|
|
|
|
|
|
|
Notification (ECN) to IP>, RFC 3168. Available at |
1855
|
|
|
|
|
|
|
http://www.ietf.org/rfc/rfc3168.txt |
1856
|
|
|
|
|
|
|
|
1857
|
|
|
|
|
|
|
=head2 The ns2 network simulator |
1858
|
|
|
|
|
|
|
|
1859
|
|
|
|
|
|
|
C can convert TSH traces to binary files suitable to |
1860
|
|
|
|
|
|
|
drive simulations in ns2. More information about ns2 is available at |
1861
|
|
|
|
|
|
|
http://www.isi.edu/nsnam/ns . |
1862
|
|
|
|
|
|
|
|
1863
|
|
|
|
|
|
|
=head1 AUTHOR |
1864
|
|
|
|
|
|
|
|
1865
|
|
|
|
|
|
|
Kostas Pentikousis, kostas AT cpan DOT org. |
1866
|
|
|
|
|
|
|
|
1867
|
|
|
|
|
|
|
=head1 ACKNOWLEDGMENTS |
1868
|
|
|
|
|
|
|
|
1869
|
|
|
|
|
|
|
Professor Hussein Badr provided invaluable guidance while crafting the |
1870
|
|
|
|
|
|
|
main algorithms of this module. |
1871
|
|
|
|
|
|
|
|
1872
|
|
|
|
|
|
|
Many thanks to Wall, Christiansen and Orwant for writing I
|
1873
|
|
|
|
|
|
|
Perl 3/e>. It has been indispensable while developing this module. |
1874
|
|
|
|
|
|
|
|
1875
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
1876
|
|
|
|
|
|
|
|
1877
|
|
|
|
|
|
|
Copyright 2003, 2004 by Kostas Pentikousis. All Rights Reserved. |
1878
|
|
|
|
|
|
|
|
1879
|
|
|
|
|
|
|
This library is free software with ABSOLUTELY NO WARRANTY. You can |
1880
|
|
|
|
|
|
|
redistribute it and/or modify it under the same terms as Perl itself. |
1881
|
|
|
|
|
|
|
|
1882
|
|
|
|
|
|
|
=cut |
1883
|
|
|
|
|
|
|
|
1884
|
|
|
|
|
|
|
__DATA__ |