File Coverage

blib/lib/IPTables/Log/Set.pm
Criterion Covered Total %
statement 65 67 97.0
branch 10 16 62.5
condition n/a
subroutine 13 13 100.0
pod 5 5 100.0
total 93 101 92.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             #=======================================================================
4             # Set.pm / IPTables::Log::Set
5             # $Id: Set.pm 21 2010-12-17 21:07:37Z andys $
6             # $HeadURL: https://daedalus.dmz.dn7.org.uk/svn/IPTables-Log/trunk/IPTables-Log/lib/IPTables/Log/Set.pm $
7             # (c)2009 Andy Smith
8             #-----------------------------------------------------------------------
9             #:Description
10             # This class holds a set of IPTables::Log::Set::Record objects
11             #-----------------------------------------------------------------------
12             #:Synopsis
13             # NOTE: This class isn't designed to be created directly.
14             #
15             # use IPTables::Log;
16             # my $l = IPTables::Log->new;
17             # my $s = $l->create_set;
18             # my $r = $s->create_record({text => '...IN=eth0 OUT=eth1 MAC=00:...'});
19             # $r->parse;
20             # $s->add($r);
21             #=======================================================================
22              
23             # The pod (Perl Documentation) for this module is provided inline. For a
24             # better-formatted version, please run:-
25             # $ perldoc Set.pm
26              
27             =head1 NAME
28              
29             IPTables::Log::Set - Holds a set of IPTables::Log::Set::Record objects.
30              
31             =head1 SYNOPSIS
32              
33             Note that this class isn't designed to be created directly. You can create these objects via a C object.
34              
35             use IPTables::Log;
36             my $l = IPTables::Log->new;
37             my $s = $l->create_set;
38              
39             =head1 DEPENDENCIES
40              
41             =over 4
42              
43             =item * Class::Accessor - for accessor methods
44              
45             =item * Data::GUID - for GUID generation
46              
47             =item * NetAddr::IP - for the C and C methods (required by L)
48              
49             =back
50              
51             =cut
52              
53             # Set our package name
54             package IPTables::Log::Set;
55              
56             # Minimum version
57 3     3   53 use 5.010000;
  3         12  
  3         130  
58             # Use strict and warnings
59 3     3   17 use strict;
  3         7  
  3         89  
60 3     3   13 use warnings;
  3         4  
  3         67  
61              
62             # Use Carp for erroring
63 3     3   14 use Carp;
  3         5  
  3         166  
64             # Use Data::GUID for generating GUIDs
65 3     3   3172 use Data::GUID;
  3         95590  
  3         46  
66             # Use IPTables::Log::Set::Record for individual log entries
67 3     3   2933 use IPTables::Log::Set::Record;
  3         11  
  3         36  
68             # Use Data::Dumper
69 3     3   224 use Data::Dumper;
  3         7  
  3         315  
70              
71             # Inherit from Class::Accessor to simplify accessor method generation
72 3     3   19 use base qw(Class::Accessor);
  3         15  
  3         3064  
73             # Follow best practice
74             __PACKAGE__->follow_best_practice;
75             # Create log and guid as read-only accessor methods
76             __PACKAGE__->mk_ro_accessors( qw(log guid) );
77              
78             # Set version information
79             our $VERSION = '0.0005';
80              
81             =head1 CONSTRUCTORS
82              
83             =head2 Set->create
84              
85             Creates a new C object. This isn't the recommended way to do this, however. The proper way is to create an object via a L object with C.
86              
87             =cut
88              
89             sub create
90             {
91 2     2 1 4 my ($class, $args) = @_;
92              
93 2         19 my $self = __PACKAGE__->new($args);
94 2         30 $self->{records} = {};
95              
96             # Generate a GUID for the set
97 2         23 my $g = Data::GUID->new;
98 2         390878 $self->{guid} = $g->as_string;
99 2         163 $self->{no_header} = $args->{'no_header'};
100              
101 2         28 return $self;
102             }
103              
104             =head1 METHODS
105              
106             =head2 $set->create_record(I<{text => '...IN=eth0 OUT=eth1 MAC=00:...'}>))
107              
108             Creates a new L object. This is the B way to create C objects, as it ensures various settings are inherited from the C class.
109              
110             The text of the log entry can be passed here, or it can be passed with the C accessor method to the C object itself.
111              
112             =cut
113              
114             sub create_record
115             {
116 9     9 1 845 my ($self, $args) = @_;
117              
118             #$args->{log} = $self->get_log;
119              
120 9         49 my $record = IPTables::Log::Set::Record->create($args);
121              
122 9         19 return $record;
123             }
124              
125             =head2 $set->load_file($filename)
126              
127             Loads in logs from I<$filename>, discarding any which don't appear to be iptables/netfilter logs. A L object is then created for each entry, and the content is then parsed. Finally, each entry is then added to the set created with C.
128              
129             =cut
130              
131             sub load_file
132             {
133 1     1 1 375 my ($self, $filename) = @_;
134              
135             # Check we've been passed a filename
136 1 50       3 if(!$filename)
137             {
138 0         0 croak "No filename given to load_file().";
139             #$self->get_log->fatal("No filename given!");
140             }
141              
142             # Check that the file exists, and barf if not.
143 1 50       22 if(!-f $filename)
144             {
145 0         0 croak $filename." does not exist.";
146             #$self->get_log->fatal("Cannot find ".$self->get_log->fcolour('yellow', $filename));
147             }
148              
149             #$self->get_log->debug("Opening ".$self->get_log->fcolour('yellow', $filename)."...");
150             # Open the logfile
151 1 50       40 open(LOGFILE, $filename) || $self->get_log->fatal("Cannot open ".$self->get_log->fcolour('yellow', $filename));
152 1         46 my @logs = ;
153             #$self->get_log->debug("Finished reading in logs.");
154              
155             # It's a fair bet that if we don't have an IN= and an OUT= and it doesn't have a source of 'kernel', then it's not an iptables log.
156             # We'll discard those before even attempting to parse it.
157 1         4 foreach my $log (@logs)
158             {
159 8 50       133 if($log =~ /kernel.+IN=.+OUT=/)
160             {
161 8         17 chomp($log);
162             #$self->get_log->debug_nolf("Parsing iptables log entry... ");
163 8         38 my $record = $self->create_record({'text' => $log, 'no_header' => $self->{no_header}});
164 8         29 $record->parse;
165             #$self->get_log->debug("done.");
166 8         19 $self->add($record);
167 8         22 $self->get_log->debug("Added record with GUID ".$self->get_log->fcolour('yellow', $record->get_guid). " to set.");
168             #return 1;
169             }
170             else
171             {
172             #$self->get_log->debug("Log entry is not an iptables log entry, so skipping...");
173             }
174             }
175 1         18 return 1;
176             }
177              
178             =head2 $set->add($record)
179              
180             Adds a L object to a set created with C.
181              
182             =cut
183              
184             sub add
185             {
186 8     8 1 13 my ($self, $record) = @_;
187              
188 8 50       15 if($record)
189             {
190 8         20 my $guid = $record->get_guid;
191              
192 8         38 $self->{records}{$guid} = $record;
193             }
194             }
195              
196             =head2 $set->get_by('field')
197              
198             Returns a hash of record identifiers, indexed by I. Field can be one of I, I, I
199              
200             If you attempt to sort on a field that isn't present in all records in the set, get_by will only return records which have that field. For example, if you attempt to get_by('dpt'), any ICMP log messages will be silently excluded from the returned set.
201              
202             =cut
203              
204             sub get_by
205             {
206 19     19 1 10470 my ($self, $by) = @_;
207              
208             # Check that $by is set
209 19 50       63 if($by)
210             {
211             # Create a hash to hold the index values
212 19         88 my %indexes;
213 19         34 $indexes{by} = $by;
214              
215 19         23 foreach my $r (keys %{$self->{records}})
  19         84  
216             {
217             # Step through each record.
218 152         264 my $record = $self->{records}{$r};
219 152         643 my $value = $record->get($by);
220              
221             # If $value is blank, it means not all records have this field.
222             # For now, we'll refuse to add these.
223 152 100       313 if($value)
224             {
225 127 100       331 if(!$indexes{$by}{$record->get($by)})
226             {
227 49         174 $indexes{$by}{$record->get($by)} = [];
228             }
229 127         165 push (@{$indexes{$by}{$record->get($by)}}, $record);
  127         429  
230             }
231             }
232              
233 19         200 return %indexes;
234             }
235             }
236              
237             =head1 CAVEATS
238              
239             None.
240              
241             =head1 BUGS
242              
243             None that I'm aware of ;-)
244              
245             =head1 AUTHOR
246              
247             This module was written by B .
248              
249             =head1 COPYRIGHT
250              
251             $Id: Set.pm 21 2010-12-17 21:07:37Z andys $
252              
253             (c)2009 Andy Smith (L)
254              
255             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
256              
257             =cut
258              
259             1