File Coverage

blib/lib/Fsdb/Filter/tcpdump_to_db.pm
Criterion Covered Total %
statement 15 82 18.2
branch 0 20 0.0
condition n/a
subroutine 5 16 31.2
pod 5 5 100.0
total 25 123 20.3


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2              
3             #
4             # tcpdump_to_db.pm
5             # Copyright (C) 1999-2007 by John Heidemann
6             # $Id: 43409abf10f685dcc1abf480ced38d92f914c5c6 $
7             #
8             # This program is distributed under terms of the GNU general
9             # public license, version 2. See the file COPYING
10             # in $dblib for details.
11             #
12              
13              
14             package Fsdb::Filter::tcpdump_to_db;
15              
16             =head1 NAME
17              
18             tcpdump_to_db - convert tcpdump textual output to fsdb
19              
20             =head1 SYNOPSIS
21              
22             tcpdump_to_db [-T] < source.tcpdump > target.fsdb
23              
24             =head1 DESCRIPTION
25              
26             Converts a tcpdump textual data stream to Fsdb format.
27              
28             B
29             Awaiting enhancement... you're welcome to help.
30              
31              
32             =head1 OPTIONS
33              
34             =over 4
35              
36             =item B<-t> or B<--daytime>
37              
38             Adjust times relative to the first timestamp.
39             (Defaults on.)
40              
41             =back
42              
43              
44             =for comment
45             begin_standard_fsdb_options
46              
47             This module also supports the standard fsdb options:
48              
49             =over 4
50              
51             =item B<-d>
52              
53             Enable debugging output.
54              
55             =item B<-i> or B<--input> InputSource
56              
57             Read from InputSource, typically a file name, or C<-> for standard input,
58             or (if in Perl) a IO::Handle, Fsdb::IO or Fsdb::BoundedQueue objects.
59              
60             =item B<-o> or B<--output> OutputDestination
61              
62             Write to OutputDestination, typically a file name, or C<-> for standard output,
63             or (if in Perl) a IO::Handle, Fsdb::IO or Fsdb::BoundedQueue objects.
64              
65             =item B<--autorun> or B<--noautorun>
66              
67             By default, programs process automatically,
68             but Fsdb::Filter objects in Perl do not run until you invoke
69             the run() method.
70             The C<--(no)autorun> option controls that behavior within Perl.
71              
72             =item B<--help>
73              
74             Show help.
75              
76             =item B<--man>
77              
78             Show full manual.
79              
80             =back
81              
82             =for comment
83             end_standard_fsdb_options
84              
85              
86             =head1 SAMPLE USAGE
87              
88             =head2 Input:
89              
90             14:11:12.556781 dash.isi.edu.1023 > excalibur.usc.edu.ssh: S 2306448962:2306448962(0) win 32120 (DF)
91             14:11:12.561734 excalibur.usc.edu.ssh > dash.isi.edu.1023: S 1968320001:1968320001(0) ack 2306448963 win 4096
92             14:11:12.561875 dash.isi.edu.1023 > excalibur.usc.edu.ssh: . ack 1 win 32120 (DF)
93             14:11:18.746567 excalibur.usc.edu.ssh > dash.isi.edu.1023: P 316:328(12) ack 348 win 4096
94             14:11:18.755176 dash.isi.edu.1023 > excalibur.usc.edu.ssh: P 348:488(140) ack 328 win 32696 (DF) [tos 0x10]
95             14:11:18.847937 excalibur.usc.edu.ssh > dash.isi.edu.1023: P 328:468(140) ack 488 win 4096
96             14:11:18.860047 dash.isi.edu.1023 > excalibur.usc.edu.ssh: . ack 468 win 32696 (DF) [tos 0x10]
97             14:11:18.936255 dash.isi.edu.1023 > excalibur.usc.edu.ssh: P 488:516(28) ack 468 win 32696 (DF) [tos 0x10]
98              
99              
100             or a more modern form
101              
102             17:00:14.808855 IP 10.0.0.172.31738 > 10.1.0.50.telnet: Flags [S], seq 3236187954, win 21463, length 0
103              
104             =head2 Command:
105              
106             tcpdump_to_db
107              
108             =head2 Output:
109              
110             #fsdb time proto src dest flags start end len ack win
111             51072.556781 tcp dash.isi.edu.1023 excalibur.usc.edu.ssh S 2306448962 2306448962 0 - 32120
112             51072.561734 tcp excalibur.usc.edu.ssh dash.isi.edu.1023 S 1968320001 1968320001 0 2306448963 4096
113             51072.561875 tcp dash.isi.edu.1023 excalibur.usc.edu.ssh . - - - 1 32120
114             51078.746567 tcp excalibur.usc.edu.ssh dash.isi.edu.1023 P 316 328 12 348 4096
115             51078.755176 tcp dash.isi.edu.1023 excalibur.usc.edu.ssh P 348 488 140 328 32696
116             51078.847937 tcp excalibur.usc.edu.ssh dash.isi.edu.1023 P 328 468 140 488 4096
117             51078.860047 tcp dash.isi.edu.1023 excalibur.usc.edu.ssh . - - - 468 32696
118             51078.936255 tcp dash.isi.edu.1023 excalibur.usc.edu.ssh P 488 516 28 468 32696
119             # | tcpdump_to_db
120              
121              
122             =head1 SEE ALSO
123              
124             L.
125              
126              
127             =head1 CLASS FUNCTIONS
128              
129             =cut
130              
131             @ISA = qw(Fsdb::Filter);
132             $VERSION = 2.0;
133              
134 1     1   4292 use strict;
  1         2  
  1         29  
135 1     1   5 use Pod::Usage;
  1         2  
  1         92  
136 1     1   6 use Carp;
  1         2  
  1         50  
137              
138 1     1   5 use Fsdb::Filter;
  1         2  
  1         17  
139 1     1   5 use Fsdb::IO::Writer;
  1         2  
  1         735  
140              
141              
142             =head2 new
143              
144             $filter = new Fsdb::Filter::tcpdump_to_db(@arguments);
145              
146             Create a new tcpdump_to_db object, taking command-line arguments.
147              
148             =cut
149              
150             sub new ($@) {
151 0     0 1   my $class = shift @_;
152 0           my $self = $class->SUPER::new(@_);
153 0           bless $self, $class;
154 0           $self->set_defaults;
155 0           $self->parse_options(@_);
156 0           $self->SUPER::post_new();
157 0           return $self;
158             }
159              
160              
161             =head2 set_defaults
162              
163             $filter->set_defaults();
164              
165             Internal: set up defaults.
166              
167             =cut
168              
169             sub set_defaults ($) {
170 0     0 1   my($self) = @_;
171 0           $self->SUPER::set_defaults();
172             }
173              
174             =head2 parse_options
175              
176             $filter->parse_options(@ARGV);
177              
178             Internal: parse command-line arguments.
179              
180             =cut
181              
182             sub parse_options ($@) {
183 0     0 1   my $self = shift @_;
184              
185 0           my(@argv) = @_;
186             $self->get_options(
187             \@argv,
188 0     0     'help|?' => sub { pod2usage(1); },
189 0     0     'man' => sub { pod2usage(-verbose => 2); },
190             'autorun!' => \$self->{_autorun},
191             'd|debug+' => \$self->{_debug},
192 0     0     'i|input=s' => sub { $self->parse_io_option('input', @_); },
193             't|daytime!' => \$self->{_daytime},
194 0     0     'T' => sub { $self->{_daytime} = undef; },
195             'log!' => \$self->{_logprog},
196 0     0     'o|output=s' => sub { $self->parse_io_option('output', @_); },
197 0 0         ) or pod2usage(2);
198 0           push (@{$self->{_argv}}, @argv);
  0            
199             }
200              
201             =head2 setup
202              
203             $filter->setup();
204              
205             Internal: setup, parse headers.
206              
207             =cut
208              
209             sub setup ($) {
210 0     0 1   my($self) = @_;
211              
212 0           $self->finish_fh_io_option('input');
213              
214 0           $self->finish_io_option('output', -cols => [qw(time proto src dest flags start end len ack win)]);
215             }
216              
217             =head2 _conv_time
218              
219             $daytime = $self->_conv_time($raw);
220              
221             Convert tcpdump h:mm:ss.SS format to absolute seconds.
222              
223             =cut
224              
225             sub _conv_time {
226 0     0     my($self, $raw) = @_;
227 0           my($h, $m, $s, $f) = ($raw =~ /^\s*(\d+):(\d+):(\d+)\.(\d+)\s*$/);
228 0 0         die "$0: input doesn't look like an ascii formatted tcpdump. Giving up.\n"
229             if (!defined($h));
230 0           my $S = (($h * 60) + $m) * 60 + $s;
231 0 0         if ($self->{_daytime}) {
232 0 0         if (!defined($self->{_time_origin_S})) {
233 0           $self->{_time_origin_S} = $S;
234 0           $self->{_time_origin_f} = $f;
235             };
236 0           $S -= $self->{_time_origin_S};
237 0           $f -= $self->{_time_origin_f};
238 0           while ($f < 0) {
239 0           $S -= 1;
240 0           $f += 1000000;
241             };
242 0           $f = sprintf("%06d", $f);
243             };
244 0           return "$S.$f";
245             }
246              
247              
248             =head2 run
249              
250             $filter->run();
251              
252             Internal: run over each rows.
253              
254             =cut
255             sub run ($) {
256 0     0 1   my($self) = @_;
257              
258 0           my $read_fh = $self->{_in};
259 0           my $write_fastpath_sub = $self->{_out}->fastpath_sub();
260 0           my $empty = $self->{_out}->{_empty};
261              
262 0           for (;;) {
263 0           my $line = $read_fh->getline;
264 0 0         last if (!defined($line));
265              
266 0 0         next if ($line !~ /^\d/);
267 0           my(@F) = split(' ', $line);
268 0           my($proto, $raw_time, $src, $dummy, $dest, $flags, $ack, $win, $start, $end, $len) = ($empty) x 20;
269 0           $raw_time = shift @F;
270             # xxx: should support other protos!
271             # Currently silently fails on them.
272 0           $proto = 'tcp';
273 0           $src = shift @F;
274             # The src field may have "truncated-ip" instead of the src.
275             # If the entry is truncated then silently ignore it.
276 0 0         next if ($src =~ /truncated/);
277            
278 0           $dummy = shift @F;
279 0           $dest = shift @F;
280 0           $dest =~ s/:$//;
281 0           $flags = shift @F;
282 0 0         if ($F[0] =~ /^\d/) {
283 0           ($start, $end, $len) = ($F[0] =~ /^\s*(\d+):(\d+)\((\d+)\)\s*$/);
284 0           shift @F;
285             };
286 0 0         if ($F[0] eq 'ack') {
287 0           shift @F;
288 0           $ack = shift @F;
289             };
290 0 0         if ($F[0] eq 'win') {
291 0           shift @F;
292 0           $win = shift @F;
293             };
294              
295 0           my @outf = ($self->_conv_time($raw_time), $proto, $src, $dest, $flags, $start, $end, $len, $ack, $win);
296 0           &{$write_fastpath_sub}(\@outf);
  0            
297             };
298             }
299              
300              
301             =head1 AUTHOR and COPYRIGHT
302              
303             Copyright (C) 1991-2008 by John Heidemann
304              
305             This program is distributed under terms of the GNU general
306             public license, version 2. See the file COPYING
307             with the distribution for details.
308              
309             =cut
310              
311             1;