Initial commit: Imported yaala 0.7.3.
[yaala.git] / lib / Yaala / Parser / Iptables.pm
1 package Yaala::Parser;
2
3 use strict;
4 use warnings;
5 use vars qw#%DATAFIELDS#;
6
7 use Exporter;
8 use Yaala::Data::Persistent qw#init#;
9 use Yaala::Parser::WebserverTools qw#%MONTH_NUMBERS#;
10
11 @Yaala::Parser::EXPORT_OK = qw(parse extra %DATAFIELDS);
12 @Yaala::Parser::ISA = ('Exporter');
13
14 our $LASTDATE = init ('$LASTDATE', 'scalar');
15                 
16 if (!$$LASTDATE) { $$LASTDATE = 0; }
17
18 %DATAFIELDS =
19 (
20         date            => 'key:date',
21         hour            => 'key:hour',
22         
23         source_ip       => 'key',
24         dest_ip         => 'key',
25         
26         incoming_dev    => 'key',
27         outgoing_dev    => 'key',
28
29         protocol        => 'key',
30
31         source_port     => 'key:numeric',
32         destination_port => 'key:numeric',
33
34         icmp_type       => 'key:numeric',
35
36         mac_address     => 'key',
37
38         tos             => 'key',
39         prec            => 'key',
40         ttl             => 'key:numeric',
41
42         packets         => 'agg',
43         size            => 'agg',
44         payload         => 'agg'
45 );
46
47
48 # This needs to be done at runtime, since Data uses Setup which relies on
49 # %DATAFIELDS to be defined  -octo
50 require Yaala::Data::Core;
51 import Yaala::Data::Core qw#store#;
52
53 my $VERSION = '$Id: Iptables.pm,v 1.4 2003/12/07 15:21:02 octo Exp octo $';
54 print STDERR $/, __FILE__, ": $VERSION" if ($::DEBUG);
55
56 return (1);
57
58 sub parse
59 {
60         my $line = shift;
61
62         if ($line =~ m/IN=(\S*) OUT=(\S*) /)
63         {
64                 my $in  = $1 ? $1 : '*unknown*';
65                 my $out = $2 ? $2 : '*unknown*';
66                 my $rest = $';
67
68                 my $mac = '*unknown*';
69                 my $src, $dst;
70                 my $len, $tos, $prec, $ttl, $id;
71
72                 my $ip_flags = '';
73                 my $frag = 0;
74                 my $opt;
75                 my $proto_name;
76                 my $proto_type = 'N/A';
77
78                 my $dport = 'N/A';
79                 my $sport = 'N/A';
80                 
81                 if ($rest =~ m/^SRC=([\d\.]+) DST=([\d\.]+) LEN=(\d+) TOS=(0x\S\S) PREC=(0x\S\S) TTL=(\d+) ID=(\d+) /)
82                 {
83                         $src = $1;
84                         $dst = $2;
85                         $len = $3;
86                         $tos = unpack ("%02h", $4);
87                         $prec = $5;
88                         $ttl = $6;
89                         $id = $7;
90                         $rest = $';
91
92                         # PPPTTTTM
93                         #    ^^^^
94                         # 00011110
95                         #    1   E
96                         $tos &= 0x1E;
97                         if ($tos == 0x00)
98                         {
99                                 $tos = 'Normal';
100                         }
101                         elsif ($tos == 0x10)
102                         {
103                                 $tos = 'Minimize Delay';
104                         }
105                         elsif ($tos == 0x08)
106                         {
107                                 $tos = 'Maximize Throughput';
108                         }
109                         elsif ($tos == 0x04)
110                         {
111                                 $tos = 'Maximize Reliability';
112                         }
113                         else
114                         {
115                                 $tos = sprintf ("Unknown (%02x)", $tos);
116                         }
117                 }
118                 else
119                 {
120                         return (0);
121                 }
122
123                 if ($rest =~ m/^((?:CE )?(?:DF )?(?:MF )?) (?:FRAG:(\d+) )?(?:OPT \(([0-9A-F]+)\) )?PROTO=(\S+) /)
124                 {
125                         $ip_flags = $1;
126                         $frag = defined ($2) ? $2 : 0;
127                         $opt  = defined ($3) ? $3 : 'none';
128                         $proto_name = $4;
129                         $rest = $';
130                 }
131                 else
132                 {
133                         return (0);
134                 }
135
136                 if (($proto eq 'TCP') or ($proto eq 'UDP'))
137                 {
138                         if ($rest =~ m/SPT=(\d+) DPT=(\d+) /)
139                         {
140                                 $sport = $1;
141                                 $dport = $2;
142                         }
143                 }
144                 
145                 if ($proto eq 'TCP')
146                 {
147                         if ($rest =~ m/RES=0x\S\S ((?:CWR )?(?:ECE )?(?:URG )?(?:ACK )?(?:PSH )?(?:RST )?(?:SYN )?(?:FIN )?)/)
148                         {
149                                 my $temp = $1;
150                                 $temp =~ s/ $//;
151                                 $proto_type = $temp ? $temp : '*none*';
152                         }
153                 }
154                 elsif ($proto eq 'ICMP')
155                 {
156                         my $type = -1;
157                         
158                         if ($rest =~ m/TYPE=(\d+) /)
159                         {
160                                 $type = $1;
161                         }
162
163                         if    ($type ==  0) { $proto_type = 'Echo Reply'; }
164                         elsif ($type ==  3) { $proto_type = 'Destination Unreachable'; }
165                         elsif ($type ==  4) { $proto_type = 'Source Quench'; }
166                         elsif ($type ==  5) { $proto_type = 'Redirect'; }
167                         elsif ($type ==  8) { $proto_type = 'Echo Request'; }
168                         elsif ($type == 11) { $proto_type = 'Time Exceeded'; }
169                         elsif ($type == 12) { $proto_type = 'Parameter Problem'; }
170                         elsif ($type == 13) { $proto_type = 'Timestamp Request'; }
171                         elsif ($type == 14) { $proto_type = 'Timestamp Reply'; }
172                         elsif ($type == 15) { $proto_type = 'Information Request'; }
173                         elsif ($type == 16) { $proto_type = 'Information Reply'; }
174                         elsif ($type == 17) { $proto_type = 'Address Mask Request'; }
175                         elsif ($type == 18) { $proto_type = 'Address Mask Reply'; }
176                         else { $proto_type = "Unknown type ($type)"; }
177                 }
178
179                         
180                         
181
182                 
183                 
184
185         if ($line =~ m/IN=\S* OUT=/)
186         {
187                 my ($month, $day, $hour, $minute, $second) = $line =~ m/^(\w{3}) (\d+) (\d\d):(\d\d):(\d\d)/;
188                 my $year = (localtime ())[5] + 1900;
189                 $month = $MONTH_NUMBERS{$month};
190
191                 {
192                         my $tmp = int (sprintf ("%04u%02u%02u%02u%02u%02u",
193                                         $year, $month, $day, $hour, $minute, $second));
194
195                         if ($tmp < $$LASTDATE)
196                         {
197                                 print STDERR $/, __FILE__, ": Skipping.. ($tmp < $$LASTDATE)" if ($::DEBUG & 0x0200);
198                                 return (undef);
199                         }
200                         else { $$LASTDATE = $tmp; }
201                 }
202                 
203                 my $date = sprintf ("%04u-%02u-%02u", $year, $month, $day);
204
205                 my %packet = ();
206                 while ($line =~ m/([A-Z]+)=(\S+)/g)
207                 {
208                         my $key = lc ($1);
209                         my $val = $2;
210
211                         if ($key eq 'len')
212                         {
213                                 if (defined ($packet{'size'}))
214                                 {
215                                         $packet{'payload'} = $val;
216                                 }
217                                 else
218                                 {
219                                         $packet{'size'} = $val;
220                                 }
221                         }
222                         else
223                         {
224                                 $packet{$key} = $val;
225                         }
226                 }
227
228                 my %data =
229                 (
230                         date            => $date,
231                         hour            => $hour,
232                         
233                         source_ip       => 'n/a',
234                         dest_ip         => 'n/a',
235                         
236                         incoming_dev    => '*none*',
237                         outgoing_dev    => '*none*',
238
239                         protocol        => '*unknown*',
240
241                         source_port     => 0,
242                         destination_port => 0,
243                         icmp_type       => 0,
244
245                         mac_address     => '*unknown*',
246
247                         tos             => '0x00',
248                         prec            => '0x00',
249                         ttl             => 0,
250
251                         packets         => 1,
252                         size            => 0,
253                         payload         => 0
254                 );
255
256                 $data{'source_ip'} = $packet{'src'} if (defined ($packet{'src'}));
257                 $data{'dest_ip'} = $packet{'dst'} if (defined ($packet{'dst'}));
258
259                 $data{'incoming_dev'} = $packet{'in'} if (defined ($packet{'in'}));
260                 $data{'outgoing_dev'} = $packet{'out'} if (defined ($packet{'out'}));
261
262                 $data{'protocol'} = $packet{'proto'} if (defined ($packet{'proto'}));
263
264                 $data{'source_port'} = $packet{'spt'} if (defined ($packet{'spt'}));
265                 $data{'destination_port'} = $packet{'dpt'} if (defined ($packet{'dpt'}));
266                 $data{'icmp_type'} = $packet{'type'} if (defined ($packet{'type'}));
267
268                 $data{'mac_address'} = $packet{'mac'} if (defined ($packet{'mac'}));
269
270                 $data{'tos'} = $packet{'tos'} if (defined ($packet{'tos'}));
271                 $data{'prec'} = $packet{'prec'} if (defined ($packet{'prec'}));
272                 $data{'ttl'} = $packet{'ttl'} if (defined ($packet{'ttl'}));
273
274                 $data{'size'} = $packet{'size'} if (defined ($packet{'size'}));
275                 $data{'payload'} = $packet{'payload'} if (defined ($packet{'payload'}));
276                 
277                 store (\%data);
278         }
279 }
280
281 sub extra
282 {
283 }