]>
Commit | Line | Data |
---|---|---|
1 | #!/usr/bin/perl | |
2 | ############################################################################### | |
3 | # # | |
4 | # IPFire.org - A linux based firewall # | |
5 | # Copyright (C) 2007-2012 IPFire Team <info@ipfire.org> # | |
6 | # # | |
7 | # This program is free software: you can redistribute it and/or modify # | |
8 | # it under the terms of the GNU General Public License as published by # | |
9 | # the Free Software Foundation, either version 3 of the License, or # | |
10 | # (at your option) any later version. # | |
11 | # # | |
12 | # This program is distributed in the hope that it will be useful, # | |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # | |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | |
15 | # GNU General Public License for more details. # | |
16 | # # | |
17 | # You should have received a copy of the GNU General Public License # | |
18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. # | |
19 | # # | |
20 | ############################################################################### | |
21 | ||
22 | use strict; | |
23 | ||
24 | use Net::IPv4Addr qw( :all ); | |
25 | use Switch; | |
26 | ||
27 | # enable only the following on debugging purpose | |
28 | #use warnings; | |
29 | #use CGI::Carp 'fatalsToBrowser'; | |
30 | ||
31 | require '/var/ipfire/general-functions.pl'; | |
32 | require "${General::swroot}/lang.pl"; | |
33 | require "${General::swroot}/header.pl"; | |
34 | ||
35 | my $colour_multicast = "#A0A0A0"; | |
36 | ||
37 | # sort arguments for connection tracking table | |
38 | # the sort field. eg. 1=src IP, 2=dst IP, 3=src port, 4=dst port | |
39 | my $SORT_FIELD = 0; | |
40 | # the sort order. (a)scending orr (d)escending | |
41 | my $SORT_ORDER = 0; | |
42 | # cgi query arguments | |
43 | my %cgiin; | |
44 | # debug mode | |
45 | my $debug = 0; | |
46 | ||
47 | # retrieve query arguments | |
48 | # note: let a-z A-Z and 0-9 pass as value only | |
49 | if (length ($ENV{'QUERY_STRING'}) > 0){ | |
50 | my $name; | |
51 | my $value; | |
52 | my $buffer = $ENV{'QUERY_STRING'}; | |
53 | my @pairs = split(/&/, $buffer); | |
54 | foreach my $pair (@pairs){ | |
55 | ($name, $value) = split(/=/, $pair); | |
56 | $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; # e.g. "%20" => " " | |
57 | $value =~ s/[^a-zA-Z0-9]*//g; # a-Z 0-9 will pass | |
58 | $cgiin{$name} = $value; | |
59 | } | |
60 | } | |
61 | ||
62 | &Header::showhttpheaders(); | |
63 | ||
64 | my @network=(); | |
65 | my @masklen=(); | |
66 | my @colour=(); | |
67 | ||
68 | my %netsettings=(); | |
69 | &General::readhash("${General::swroot}/ethernet/settings", \%netsettings); | |
70 | ||
71 | # output cgi query arrguments to browser on debug | |
72 | if ( $debug ){ | |
73 | &Header::openbox('100%', 'center', 'DEBUG'); | |
74 | my $debugCount = 0; | |
75 | foreach my $line (sort keys %cgiin) { | |
76 | print "$line = '$cgiin{$line}'<br />\n"; | |
77 | $debugCount++; | |
78 | } | |
79 | print " Count: $debugCount\n"; | |
80 | &Header::closebox(); | |
81 | } | |
82 | ||
83 | #workaround to suppress a warning when a variable is used only once | |
84 | my @dummy = ( ${Header::table1colour} ); | |
85 | undef (@dummy); | |
86 | ||
87 | # check sorting arguments | |
88 | if ( $cgiin{'sort_field'} ~~ [ '1','2','3','4','5','6','7','8','9' ] ) { | |
89 | $SORT_FIELD = $cgiin{'sort_field'}; | |
90 | ||
91 | if ( $cgiin{'sort_order'} ~~ [ 'a','d','A','D' ] ) { | |
92 | $SORT_ORDER = lc($cgiin{'sort_order'}); | |
93 | } | |
94 | } | |
95 | ||
96 | # Read and sort the connection tracking table | |
97 | # do sorting | |
98 | if ($SORT_FIELD and $SORT_ORDER) { | |
99 | # field sorting when sorting arguments are sane | |
100 | open(CONNTRACK, "/usr/local/bin/getconntracktable | /usr/local/bin/consort.sh $SORT_FIELD $SORT_ORDER |") or die "Unable to read conntrack table"; | |
101 | } else { | |
102 | # default sorting with no query arguments | |
103 | open(CONNTRACK, "/usr/local/bin/getconntracktable | sort -k 5,5 --numeric-sort --reverse |") or die "Unable to read conntrack table"; | |
104 | } | |
105 | my @conntrack = <CONNTRACK>; | |
106 | close(CONNTRACK); | |
107 | ||
108 | # Collect data for the @network array. | |
109 | ||
110 | # Add Firewall Localhost 127.0.0.1 | |
111 | push(@network, '127.0.0.1'); | |
112 | push(@masklen, '255.255.255.255'); | |
113 | push(@colour, ${Header::colourfw}); | |
114 | ||
115 | if (open(IP, "${General::swroot}/red/local-ipaddress")) { | |
116 | my $redip = <IP>; | |
117 | close(IP); | |
118 | ||
119 | chomp $redip; | |
120 | push(@network, $redip); | |
121 | push(@masklen, '255.255.255.255'); | |
122 | push(@colour, ${Header::colourfw}); | |
123 | } | |
124 | ||
125 | # Add STATIC RED aliases | |
126 | if ($netsettings{'RED_DEV'}) { | |
127 | my $aliasfile = "${General::swroot}/ethernet/aliases"; | |
128 | open(ALIASES, $aliasfile) or die 'Unable to open aliases file.'; | |
129 | my @aliases = <ALIASES>; | |
130 | close(ALIASES); | |
131 | ||
132 | # We have a RED eth iface | |
133 | if ($netsettings{'RED_TYPE'} eq 'STATIC') { | |
134 | # We have a STATIC RED eth iface | |
135 | foreach my $line (@aliases) { | |
136 | chomp($line); | |
137 | my @temp = split(/\,/,$line); | |
138 | if ($temp[0]) { | |
139 | push(@network, $temp[0]); | |
140 | push(@masklen, $netsettings{'RED_NETMASK'} ); | |
141 | push(@colour, ${Header::colourfw} ); | |
142 | } | |
143 | } | |
144 | } | |
145 | } | |
146 | ||
147 | # Add Green Firewall Interface | |
148 | push(@network, $netsettings{'GREEN_ADDRESS'}); | |
149 | push(@masklen, "255.255.255.255" ); | |
150 | push(@colour, ${Header::colourfw} ); | |
151 | ||
152 | # Add Green Network to Array | |
153 | push(@network, $netsettings{'GREEN_NETADDRESS'}); | |
154 | push(@masklen, $netsettings{'GREEN_NETMASK'} ); | |
155 | push(@colour, ${Header::colourgreen} ); | |
156 | ||
157 | # Add Green Routes to Array | |
158 | my @routes = `/sbin/route -n | /bin/grep $netsettings{'GREEN_DEV'}`; | |
159 | foreach my $route (@routes) { | |
160 | chomp($route); | |
161 | my @temp = split(/[\t ]+/, $route); | |
162 | push(@network, $temp[0]); | |
163 | push(@masklen, $temp[2]); | |
164 | push(@colour, ${Header::colourgreen} ); | |
165 | } | |
166 | ||
167 | # Add Blue Firewall Interface | |
168 | push(@network, $netsettings{'BLUE_ADDRESS'}); | |
169 | push(@masklen, "255.255.255.255" ); | |
170 | push(@colour, ${Header::colourfw} ); | |
171 | ||
172 | # Add Blue Network | |
173 | if ($netsettings{'BLUE_DEV'}) { | |
174 | push(@network, $netsettings{'BLUE_NETADDRESS'}); | |
175 | push(@masklen, $netsettings{'BLUE_NETMASK'} ); | |
176 | push(@colour, ${Header::colourblue} ); | |
177 | ||
178 | # Add Blue Routes to Array | |
179 | @routes = `/sbin/route -n | /bin/grep $netsettings{'BLUE_DEV'}`; | |
180 | foreach my $route (@routes) { | |
181 | chomp($route); | |
182 | my @temp = split(/[\t ]+/, $route); | |
183 | push(@network, $temp[0]); | |
184 | push(@masklen, $temp[2]); | |
185 | push(@colour, ${Header::colourblue} ); | |
186 | } | |
187 | } | |
188 | ||
189 | # Add Orange Firewall Interface | |
190 | push(@network, $netsettings{'ORANGE_ADDRESS'}); | |
191 | push(@masklen, "255.255.255.255" ); | |
192 | push(@colour, ${Header::colourfw} ); | |
193 | ||
194 | # Add Orange Network | |
195 | if ($netsettings{'ORANGE_DEV'}) { | |
196 | push(@network, $netsettings{'ORANGE_NETADDRESS'}); | |
197 | push(@masklen, $netsettings{'ORANGE_NETMASK'} ); | |
198 | push(@colour, ${Header::colourorange} ); | |
199 | # Add Orange Routes to Array | |
200 | @routes = `/sbin/route -n | /bin/grep $netsettings{'ORANGE_DEV'}`; | |
201 | foreach my $route (@routes) { | |
202 | chomp($route); | |
203 | my @temp = split(/[\t ]+/, $route); | |
204 | push(@network, $temp[0]); | |
205 | push(@masklen, $temp[2]); | |
206 | push(@colour, ${Header::colourorange} ); | |
207 | } | |
208 | } | |
209 | ||
210 | # Highlight multicast connections. | |
211 | push(@network, "224.0.0.0"); | |
212 | push(@masklen, "239.0.0.0"); | |
213 | push(@colour, $colour_multicast); | |
214 | ||
215 | # Add OpenVPN net and RED/BLUE/ORANGE entry (when appropriate) | |
216 | if (-e "${General::swroot}/ovpn/settings") { | |
217 | my %ovpnsettings = (); | |
218 | &General::readhash("${General::swroot}/ovpn/settings", \%ovpnsettings); | |
219 | my @tempovpnsubnet = split("\/",$ovpnsettings{'DOVPN_SUBNET'}); | |
220 | ||
221 | # add OpenVPN net | |
222 | push(@network, $tempovpnsubnet[0]); | |
223 | push(@masklen, $tempovpnsubnet[1]); | |
224 | push(@colour, ${Header::colourovpn} ); | |
225 | ||
226 | # add BLUE:port / proto | |
227 | if (($ovpnsettings{'ENABLED_BLUE'} eq 'on') && $netsettings{'BLUE_DEV'}) { | |
228 | push(@network, $netsettings{'BLUE_ADDRESS'} ); | |
229 | push(@masklen, '255.255.255.255' ); | |
230 | push(@colour, ${Header::colourovpn}); | |
231 | } | |
232 | ||
233 | # add ORANGE:port / proto | |
234 | if (($ovpnsettings{'ENABLED_ORANGE'} eq 'on') && $netsettings{'ORANGE_DEV'}) { | |
235 | push(@network, $netsettings{'ORANGE_ADDRESS'} ); | |
236 | push(@masklen, '255.255.255.255' ); | |
237 | push(@colour, ${Header::colourovpn} ); | |
238 | } | |
239 | } | |
240 | ||
241 | # Add OpenVPN net for custom OVPNs | |
242 | if (-e "${General::swroot}/ovpn/ccd.conf") { | |
243 | open(OVPNSUB, "${General::swroot}/ovpn/ccd.conf"); | |
244 | my @ovpnsub = <OVPNSUB>; | |
245 | close(OVPNSUB); | |
246 | ||
247 | foreach (@ovpnsub) { | |
248 | my ($network, $mask) = split '/', (split ',', $_)[2]; | |
249 | ||
250 | $mask = ipv4_cidr2msk($mask) unless &General::validip($mask); | |
251 | ||
252 | push(@network, $network); | |
253 | push(@masklen, $mask); | |
254 | push(@colour, ${Header::colourovpn}); | |
255 | } | |
256 | } | |
257 | ||
258 | open(IPSEC, "${General::swroot}/vpn/config"); | |
259 | my @ipsec = <IPSEC>; | |
260 | close(IPSEC); | |
261 | ||
262 | foreach my $line (@ipsec) { | |
263 | my @vpn = split(',', $line); | |
264 | ||
265 | my @subnets = split('|', $vpn[12]); | |
266 | for my $subnet (@subnets) { | |
267 | my ($network, $mask) = split("/", $subnet); | |
268 | ||
269 | if (!&General::validip($mask)) { | |
270 | $mask = ipv4_cidr2msk($mask); | |
271 | } | |
272 | ||
273 | push(@network, $network); | |
274 | push(@masklen, $mask); | |
275 | push(@colour, ${Header::colourvpn}); | |
276 | } | |
277 | } | |
278 | ||
279 | if (-e "${General::swroot}/ovpn/n2nconf") { | |
280 | open(OVPNN2N, "${General::swroot}/ovpn/ovpnconfig"); | |
281 | my @ovpnn2n = <OVPNN2N>; | |
282 | close(OVPNN2N); | |
283 | ||
284 | foreach my $line (@ovpnn2n) { | |
285 | my @ovpn = split(',', $line); | |
286 | next if ($ovpn[4] ne 'net'); | |
287 | ||
288 | my ($network, $mask) = split("/", $ovpn[12]); | |
289 | if (!&General::validip($mask)) { | |
290 | $mask = ipv4_cidr2msk($mask); | |
291 | } | |
292 | ||
293 | push(@network, $network); | |
294 | push(@masklen, $mask); | |
295 | push(@colour, ${Header::colourovpn}); | |
296 | } | |
297 | } | |
298 | ||
299 | # Show the page. | |
300 | &Header::openpage($Lang::tr{'connections'}, 1, ''); | |
301 | &Header::openbigbox('100%', 'left'); | |
302 | &Header::openbox('100%', 'left', $Lang::tr{'connection tracking'}); | |
303 | ||
304 | # Print legend. | |
305 | print <<END; | |
306 | <table style='width:100%'> | |
307 | <tr> | |
308 | <td style='text-align:center;'> | |
309 | <b>$Lang::tr{'legend'} :</b> | |
310 | </td> | |
311 | <td style='text-align:center; color:#FFFFFF; background-color:${Header::colourgreen}; font-weight:bold;'> | |
312 | <b>$Lang::tr{'lan'}</b> | |
313 | </td> | |
314 | <td style='text-align:center; color:#FFFFFF; background-color:${Header::colourred};'> | |
315 | <b>$Lang::tr{'internet'}</b> | |
316 | </td> | |
317 | <td style='text-align:center; color:#FFFFFF; background-color:${Header::colourorange};'> | |
318 | <b>$Lang::tr{'dmz'}</b> | |
319 | </td> | |
320 | <td style='text-align:center; color:#FFFFFF; background-color:${Header::colourblue};'> | |
321 | <b>$Lang::tr{'wireless'}</b> | |
322 | </td> | |
323 | <td style='text-align:center; color:#FFFFFF; background-color:${Header::colourfw};'> | |
324 | <b>IPFire</b> | |
325 | </td> | |
326 | <td style='text-align:center; color:#FFFFFF; background-color:${Header::colourvpn};'> | |
327 | <b>$Lang::tr{'vpn'}</b> | |
328 | </td> | |
329 | <td style='text-align:center; color:#FFFFFF; background-color:${Header::colourovpn};'> | |
330 | <b>$Lang::tr{'OpenVPN'}</b> | |
331 | </td> | |
332 | <td style='text-align:center; color:#FFFFFF; background-color:$colour_multicast;'> | |
333 | <b>Multicast</b> | |
334 | </td> | |
335 | </tr> | |
336 | </table> | |
337 | <br> | |
338 | END | |
339 | ||
340 | if ($SORT_FIELD and $SORT_ORDER) { | |
341 | my @sort_field_name = ( | |
342 | $Lang::tr{'source ip'}, | |
343 | $Lang::tr{'destination ip'}, | |
344 | $Lang::tr{'source port'}, | |
345 | $Lang::tr{'destination port'}, | |
346 | $Lang::tr{'protocol'}, | |
347 | $Lang::tr{'connection'}.' '.$Lang::tr{'status'}, | |
348 | $Lang::tr{'expires'}.' ('.$Lang::tr{'seconds'}.')', | |
349 | $Lang::tr{'download'}, | |
350 | $Lang::tr{'upload'} | |
351 | ); | |
352 | my $sort_order_name; | |
353 | if (lc($SORT_ORDER) eq "a") { | |
354 | $sort_order_name = $Lang::tr{'sort ascending'}; | |
355 | } else { | |
356 | $sort_order_name = $Lang::tr{'sort descending'}; | |
357 | } | |
358 | ||
359 | print <<END | |
360 | <div style="font-weight:bold;margin:10px;font-size: 70%"> | |
361 | $sort_order_name: $sort_field_name[$SORT_FIELD-1] | |
362 | </div> | |
363 | END | |
364 | ; | |
365 | } | |
366 | ||
367 | # Print table header. | |
368 | print <<END; | |
369 | <table style='width:100%'> | |
370 | <tr> | |
371 | <th style='text-align:center'> | |
372 | <a href="?sort_field=5&sort_order=d"><img style="width:10px" src="/images/up.gif" alt=""></a> | |
373 | <a href="?sort_field=5&sort_order=a"><img style="width:10px" src="/images/down.gif" alt=""></a> | |
374 | </th> | |
375 | <th style='text-align:center' colspan='2'> | |
376 | <a href="?sort_field=1&sort_order=d"><img style="width:10px" src="/images/up.gif" alt=""></a> | |
377 | <a href="?sort_field=1&sort_order=a"><img style="width:10px" src="/images/down.gif" alt=""></a> | |
378 | | |
379 | <a href="?sort_field=3&sort_order=d"><img style="width:10px" src="/images/up.gif" alt=""></a> | |
380 | <a href="?sort_field=3&sort_order=a"><img style="width:10px" src="/images/down.gif" alt=""></a> | |
381 | </th> | |
382 | <th style='text-align:center' colspan='2'> | |
383 | <a href="?sort_field=2&sort_order=d"><img style="width:10px" src="/images/up.gif" alt=""></a> | |
384 | <a href="?sort_field=2&sort_order=a"><img style="width:10px" src="/images/down.gif" alt=""></a> | |
385 | | |
386 | <a href="?sort_field=4&sort_order=d"><img style="width:10px" src="/images/up.gif" alt=""></a> | |
387 | <a href="?sort_field=4&sort_order=a"><img style="width:10px" src="/images/down.gif" alt=""></a> | |
388 | </th> | |
389 | <th style='text-align:center'> | |
390 | <a href="?sort_field=8&sort_order=d"><img style="width:10px" src="/images/up.gif" alt=""></a> | |
391 | <a href="?sort_field=8&sort_order=a"><img style="width:10px" src="/images/down.gif" alt=""></a> | |
392 | | |
393 | <a href="?sort_field=9&sort_order=d"><img style="width:10px" src="/images/up.gif" alt=""></a> | |
394 | <a href="?sort_field=9&sort_order=a"><img style="width:10px" src="/images/down.gif" alt=""></a> | |
395 | </th> | |
396 | <th style='text-align:center'> | |
397 | <a href="?sort_field=6&sort_order=d"><img style="width:10px" src="/images/up.gif" alt=""></a> | |
398 | <a href="?sort_field=6&sort_order=a"><img style="width:10px" src="/images/down.gif" alt=""></a> | |
399 | </th> | |
400 | <th style='text-align:center'> | |
401 | <a href="?sort_field=7&sort_order=d"><img style="width:10px" src="/images/up.gif" alt=""></a> | |
402 | <a href="?sort_field=7&sort_order=a"><img style="width:10px" src="/images/down.gif" alt=""></a> | |
403 | </th> | |
404 | </tr> | |
405 | <tr> | |
406 | <th style='text-align:center'> | |
407 | $Lang::tr{'protocol'} | |
408 | </th> | |
409 | <th style='text-align:center' colspan='2'> | |
410 | $Lang::tr{'source ip and port'} | |
411 | </th> | |
412 | <th style='text-align:center' colspan='2'> | |
413 | $Lang::tr{'dest ip and port'} | |
414 | </th> | |
415 | <th style='text-align:center'> | |
416 | $Lang::tr{'download'} / | |
417 | <br>$Lang::tr{'upload'} | |
418 | </th> | |
419 | <th style='text-align:center'> | |
420 | $Lang::tr{'connection'}<br>$Lang::tr{'status'} | |
421 | </th> | |
422 | <th style='text-align:center'> | |
423 | $Lang::tr{'expires'}<br>($Lang::tr{'seconds'}) | |
424 | </th> | |
425 | </tr> | |
426 | END | |
427 | ||
428 | foreach my $line (@conntrack) { | |
429 | my @conn = split(' ', $line); | |
430 | ||
431 | # The first bit is the l3 protocol. | |
432 | my $l3proto = $conn[0]; | |
433 | ||
434 | # Skip everything that is not IPv4. | |
435 | if ($l3proto ne 'ipv4') { | |
436 | next; | |
437 | } | |
438 | ||
439 | # L4 protocol (tcp, udp, ...). | |
440 | my $l4proto = $conn[2]; | |
441 | ||
442 | # Translate unknown protocols. | |
443 | if ($l4proto eq 'unknown') { | |
444 | my $l4protonum = $conn[3]; | |
445 | if ($l4protonum eq '2') { | |
446 | $l4proto = 'IGMP'; | |
447 | } elsif ($l4protonum eq '4') { | |
448 | $l4proto = 'IPv4 Encap'; | |
449 | } elsif ($l4protonum eq '33') { | |
450 | $l4proto = 'DCCP'; | |
451 | } elsif ($l4protonum eq '41') { | |
452 | $l4proto = 'IPv6 Encap'; | |
453 | } elsif ($l4protonum eq '50') { | |
454 | $l4proto = 'ESP'; | |
455 | } elsif ($l4protonum eq '51') { | |
456 | $l4proto = 'AH'; | |
457 | } elsif ($l4protonum eq '132') { | |
458 | $l4proto = 'SCTP'; | |
459 | } else { | |
460 | $l4proto = $l4protonum; | |
461 | } | |
462 | } else { | |
463 | $l4proto = uc($l4proto); | |
464 | } | |
465 | ||
466 | # Source and destination. | |
467 | my $sip; | |
468 | my $sip_ret; | |
469 | my $dip; | |
470 | my $dip_ret; | |
471 | my $sport; | |
472 | my $sport_ret; | |
473 | my $dport; | |
474 | my $dport_ret; | |
475 | my @packets; | |
476 | my @bytes; | |
477 | ||
478 | my $ttl = $conn[4]; | |
479 | my $state; | |
480 | if ($l4proto eq 'TCP') { | |
481 | $state = $conn[5]; | |
482 | } | |
483 | ||
484 | # Kick out everything that is not IPv4. | |
485 | foreach my $item (@conn) { | |
486 | my ($key, $val) = split('=', $item); | |
487 | ||
488 | switch ($key) { | |
489 | case "src" { | |
490 | if ($sip == "") { | |
491 | $sip = $val; | |
492 | } else { | |
493 | $dip_ret = $val; | |
494 | } | |
495 | } | |
496 | case "dst" { | |
497 | if ($dip == "") { | |
498 | $dip = $val; | |
499 | } else { | |
500 | $sip_ret = $val; | |
501 | } | |
502 | } | |
503 | case "sport" { | |
504 | if ($sport == "") { | |
505 | $sport = $val; | |
506 | } else { | |
507 | $dport_ret = $val; | |
508 | } | |
509 | } | |
510 | case "dport" { | |
511 | if ($dport == "") { | |
512 | $dport = $val; | |
513 | } else { | |
514 | $sport_ret = $val; | |
515 | } | |
516 | } | |
517 | case "packets" { | |
518 | push(@packets, $val); | |
519 | } | |
520 | case "bytes" { | |
521 | push(@bytes, $val); | |
522 | } | |
523 | } | |
524 | } | |
525 | ||
526 | my $sip_colour = ipcolour($sip); | |
527 | # use colour of destination network for DNAT | |
528 | my $dip_colour = $dip ne $dip_ret ? ipcolour($dip_ret) : ipcolour($dip); | |
529 | ||
530 | my $sserv = ''; | |
531 | if ($sport < 1024) { | |
532 | $sserv = uc(getservbyport($sport, lc($l4proto))); | |
533 | } | |
534 | ||
535 | my $dserv = ''; | |
536 | if ($dport < 1024) { | |
537 | $dserv = uc(getservbyport($dport, lc($l4proto))); | |
538 | } | |
539 | ||
540 | my $bytes_in = format_bytes($bytes[0]); | |
541 | my $bytes_out = format_bytes($bytes[1]); | |
542 | ||
543 | # Format TTL | |
544 | $ttl = format_time($ttl); | |
545 | ||
546 | my $sip_extra; | |
547 | if ($sip_ret && $sip ne $sip_ret) { | |
548 | $sip_extra = "<span style='color:#FFFFFF;'>></span> "; | |
549 | $sip_extra .= "<a href='/cgi-bin/ipinfo.cgi?ip=$sip_ret'>"; | |
550 | $sip_extra .= " <span style='color:#FFFFFF;'>$sip_ret</span>"; | |
551 | $sip_extra .= "</a>"; | |
552 | } | |
553 | ||
554 | my $dip_extra; | |
555 | if ($dip_ret && $dip ne $dip_ret) { | |
556 | $dip_extra = "<span style='color:#FFFFFF;'>></span> "; | |
557 | $dip_extra .= "<a href='/cgi-bin/ipinfo.cgi?ip=$dip_ret'>"; | |
558 | $dip_extra .= " <span style='color:#FFFFFF;'>$dip_ret</span>"; | |
559 | $dip_extra .= "</a>"; | |
560 | } | |
561 | ||
562 | ||
563 | my $sport_extra; | |
564 | if ($sport ne $sport_ret) { | |
565 | my $sserv_ret = ''; | |
566 | if ($sport_ret < 1024) { | |
567 | $sserv_ret = uc(getservbyport($sport_ret, lc($l4proto))); | |
568 | } | |
569 | ||
570 | $sport_extra = "<span style='color:#FFFFFF;'>></span> "; | |
571 | $sport_extra .= "<a href='http://isc.sans.org/port_details.php?port=$sport_ret' target='top' title='$sserv_ret'>"; | |
572 | $sport_extra .= " <span style='color:#FFFFFF;'>$sport_ret</span>"; | |
573 | $sport_extra .= "</a>"; | |
574 | } | |
575 | ||
576 | my $dport_extra; | |
577 | if ($dport ne $dport_ret) { | |
578 | my $dserv_ret = ''; | |
579 | if ($dport_ret < 1024) { | |
580 | $dserv_ret = uc(getservbyport($dport_ret, lc($l4proto))); | |
581 | } | |
582 | ||
583 | $dport_extra = "<span style='color:#FFFFFF;'>></span> "; | |
584 | $dport_extra .= "<a href='http://isc.sans.org/port_details.php?port=$dport_ret' target='top' title='$dserv_ret'>"; | |
585 | $dport_extra .= " <span style='color:#FFFFFF;'>$dport_ret</span>"; | |
586 | $dport_extra .= "</a>"; | |
587 | } | |
588 | ||
589 | print <<END; | |
590 | <tr> | |
591 | <td style='text-align:center'>$l4proto</td> | |
592 | <td style='text-align:center; background-color:$sip_colour;'> | |
593 | <a href='/cgi-bin/ipinfo.cgi?ip=$sip'> | |
594 | <span style='color:#FFFFFF;'>$sip</span> | |
595 | </a> | |
596 | $sip_extra | |
597 | </td> | |
598 | <td style='text-align:center; background-color:$sip_colour;'> | |
599 | <a href='http://isc.sans.org/port_details.php?port=$sport' target='top' title='$sserv'> | |
600 | <span style='color:#FFFFFF;'>$sport</span> | |
601 | </a> | |
602 | $sport_extra | |
603 | </td> | |
604 | <td style='text-align:center; background-color:$dip_colour;'> | |
605 | <a href='/cgi-bin/ipinfo.cgi?ip=$dip'> | |
606 | <span style='color:#FFFFFF;'>$dip</span> | |
607 | </a> | |
608 | $dip_extra | |
609 | </td> | |
610 | <td style='text-align:center; background-color:$dip_colour;'> | |
611 | <a href='http://isc.sans.org/port_details.php?port=$dport' target='top' title='$dserv'> | |
612 | <span style='color:#FFFFFF;'>$dport</span> | |
613 | </a> | |
614 | $dport_extra | |
615 | </td> | |
616 | <td style='text-align:center'> | |
617 | $bytes_in / $bytes_out | |
618 | </td> | |
619 | <td style='text-align:center'>$state</td> | |
620 | <td style='text-align:center'>$ttl</td> | |
621 | </tr> | |
622 | END | |
623 | } | |
624 | ||
625 | # Close the main table. | |
626 | print "</table>"; | |
627 | ||
628 | &Header::closebox(); | |
629 | &Header::closebigbox(); | |
630 | &Header::closepage(); | |
631 | ||
632 | sub format_bytes($) { | |
633 | my $bytes = shift; | |
634 | my @units = ("B", "k", "M", "G", "T"); | |
635 | ||
636 | foreach my $unit (@units) { | |
637 | if ($bytes < 1024) { | |
638 | return sprintf("%d%s", $bytes, $unit); | |
639 | } | |
640 | ||
641 | $bytes /= 1024; | |
642 | } | |
643 | ||
644 | return sprintf("%d%s", $bytes, $units[$#units]); | |
645 | } | |
646 | ||
647 | sub format_time($) { | |
648 | my $time = shift; | |
649 | ||
650 | my $seconds = $time % 60; | |
651 | my $minutes = $time / 60; | |
652 | ||
653 | my $hours = 0; | |
654 | if ($minutes >= 60) { | |
655 | $hours = $minutes / 60; | |
656 | $minutes %= 60; | |
657 | } | |
658 | ||
659 | return sprintf("%3d:%02d:%02d", $hours, $minutes, $seconds); | |
660 | } | |
661 | ||
662 | sub ipcolour($) { | |
663 | my $id = 0; | |
664 | my $colour = ${Header::colourred}; | |
665 | my ($ip) = $_[0]; | |
666 | my $found = 0; | |
667 | ||
668 | if ($ip) { | |
669 | foreach my $line (@network) { | |
670 | if ($network[$id] eq '') { | |
671 | $id++; | |
672 | } else { | |
673 | if (!$found && ipv4_in_network($network[$id], $masklen[$id], $ip) ) { | |
674 | $found = 1; | |
675 | $colour = $colour[$id]; | |
676 | } | |
677 | $id++; | |
678 | } | |
679 | } | |
680 | } | |
681 | ||
682 | return $colour; | |
683 | } | |
684 | ||
685 | 1; |