]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blame_incremental - html/cgi-bin/connections.cgi
core72: Add strongswan update.
[people/teissler/ipfire-2.x.git] / html / cgi-bin / connections.cgi
... / ...
CommitLineData
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
22use strict;
23
24use Net::IPv4Addr qw( :all );
25use Switch;
26
27# enable only the following on debugging purpose
28#use warnings;
29#use CGI::Carp 'fatalsToBrowser';
30
31require '/var/ipfire/general-functions.pl';
32require "${General::swroot}/lang.pl";
33require "${General::swroot}/header.pl";
34
35my $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
39my $SORT_FIELD = 0;
40# the sort order. (a)scending orr (d)escending
41my $SORT_ORDER = 0;
42# cgi query arguments
43my %cgiin;
44# debug mode
45my $debug = 0;
46
47# retrieve query arguments
48# note: let a-z A-Z and 0-9 pass as value only
49if (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
64my @network=();
65my @masklen=();
66my @colour=();
67
68my %netsettings=();
69&General::readhash("${General::swroot}/ethernet/settings", \%netsettings);
70
71# output cgi query arrguments to browser on debug
72if ( $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 "&nbsp;Count: $debugCount\n";
80 &Header::closebox();
81}
82
83#workaround to suppress a warning when a variable is used only once
84my @dummy = ( ${Header::table1colour} );
85undef (@dummy);
86
87# check sorting arguments
88if ( $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
98if ($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}
105my @conntrack = <CONNTRACK>;
106close(CONNTRACK);
107
108# Collect data for the @network array.
109
110# Add Firewall Localhost 127.0.0.1
111push(@network, '127.0.0.1');
112push(@masklen, '255.255.255.255');
113push(@colour, ${Header::colourfw});
114
115if (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
126if ($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
148push(@network, $netsettings{'GREEN_ADDRESS'});
149push(@masklen, "255.255.255.255" );
150push(@colour, ${Header::colourfw} );
151
152# Add Green Network to Array
153push(@network, $netsettings{'GREEN_NETADDRESS'});
154push(@masklen, $netsettings{'GREEN_NETMASK'} );
155push(@colour, ${Header::colourgreen} );
156
157# Add Green Routes to Array
158my @routes = `/sbin/route -n | /bin/grep $netsettings{'GREEN_DEV'}`;
159foreach 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
168push(@network, $netsettings{'BLUE_ADDRESS'});
169push(@masklen, "255.255.255.255" );
170push(@colour, ${Header::colourfw} );
171
172# Add Blue Network
173if ($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
190push(@network, $netsettings{'ORANGE_ADDRESS'});
191push(@masklen, "255.255.255.255" );
192push(@colour, ${Header::colourfw} );
193
194# Add Orange Network
195if ($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.
211push(@network, "224.0.0.0");
212push(@masklen, "239.0.0.0");
213push(@colour, $colour_multicast);
214
215# Add OpenVPN net and RED/BLUE/ORANGE entry (when appropriate)
216if (-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
241open(IPSEC, "${General::swroot}/vpn/config");
242my @ipsec = <IPSEC>;
243close(IPSEC);
244
245foreach my $line (@ipsec) {
246 my @vpn = split(',', $line);
247 my ($network, $mask) = split("/", $vpn[12]);
248
249 if (!&General::validip($mask)) {
250 $mask = ipv4_cidr2msk($mask);
251 }
252
253 push(@network, $network);
254 push(@masklen, $mask);
255 push(@colour, ${Header::colourvpn});
256}
257
258if (-e "${General::swroot}/ovpn/n2nconf") {
259 open(OVPNN2N, "${General::swroot}/ovpn/ovpnconfig");
260 my @ovpnn2n = <OVPNN2N>;
261 close(OVPNN2N);
262
263 foreach my $line (@ovpnn2n) {
264 my @ovpn = split(',', $line);
265 next if ($ovpn[4] ne 'net');
266
267 my ($network, $mask) = split("/", $ovpn[12]);
268 if (!&General::validip($mask)) {
269 $mask = ipv4_cidr2msk($mask);
270 }
271
272 push(@network, $network);
273 push(@masklen, $mask);
274 push(@colour, ${Header::colourovpn});
275 }
276}
277
278# Show the page.
279&Header::openpage($Lang::tr{'connections'}, 1, '');
280&Header::openbigbox('100%', 'left');
281&Header::openbox('100%', 'left', $Lang::tr{'connection tracking'});
282
283# Print legend.
284print <<END;
285 <table width='100%'>
286 <tr>
287 <td align='center'>
288 <b>$Lang::tr{'legend'} : </b>
289 </td>
290 <td align='center' bgcolor='${Header::colourgreen}'>
291 <b><font color='#FFFFFF'>$Lang::tr{'lan'}</font></b>
292 </td>
293 <td align='center' bgcolor='${Header::colourred}'>
294 <b><font color='#FFFFFF'>$Lang::tr{'internet'}</font></b>
295 </td>
296 <td align='center' bgcolor='${Header::colourorange}'>
297 <b><font color='#FFFFFF'>$Lang::tr{'dmz'}</font></b>
298 </td>
299 <td align='center' bgcolor='${Header::colourblue}'>
300 <b><font color='#FFFFFF'>$Lang::tr{'wireless'}</font></b>
301 </td>
302 <td align='center' bgcolor='${Header::colourfw}'>
303 <b><font color='#FFFFFF'>IPFire</font></b>
304 </td>
305 <td align='center' bgcolor='${Header::colourvpn}'>
306 <b><font color='#FFFFFF'>$Lang::tr{'vpn'}</font></b>
307 </td>
308 <td align='center' bgcolor='${Header::colourovpn}'>
309 <b><font color='#FFFFFF'>$Lang::tr{'OpenVPN'}</font></b>
310 </td>
311 <td align='center' bgcolor='$colour_multicast'>
312 <b><font color='#FFFFFF'>Multicast</font></b>
313 </td>
314 </tr>
315 </table>
316 <br>
317END
318
319if ($SORT_FIELD and $SORT_ORDER) {
320 my @sort_field_name = (
321 $Lang::tr{'source ip'},
322 $Lang::tr{'destination ip'},
323 $Lang::tr{'source port'},
324 $Lang::tr{'destination port'},
325 $Lang::tr{'protocol'},
326 $Lang::tr{'connection'}.' '.$Lang::tr{'status'},
327 $Lang::tr{'expires'}.' ('.$Lang::tr{'seconds'}.')',
328 $Lang::tr{'download'},
329 $Lang::tr{'upload'}
330 );
331 my $sort_order_name;
332 if (lc($SORT_ORDER) eq "a") {
333 $sort_order_name = $Lang::tr{'sort ascending'};
334 } else {
335 $sort_order_name = $Lang::tr{'sort descending'};
336 }
337
338print <<END
339 <div style="font-weight:bold;margin:10px;font-size: 70%">
340 $sort_order_name: $sort_field_name[$SORT_FIELD-1]
341 </div>
342END
343;
344}
345
346# Print table header.
347print <<END;
348 <table width='100%'>
349 <tr valign="top"">
350 <th align='center'>
351 <a href="?sort_field=5&sort_order=d"><img style="width:10px" src="/images/up.gif"></a>
352 <a href="?sort_field=5&sort_order=a"><img style="width:10px" src="/images/down.gif"></a>
353 </th>
354 <th align='center' colspan="2">
355 <a href="?sort_field=1&sort_order=d"><img style="width:10px" src="/images/up.gif"></a>
356 <a href="?sort_field=1&sort_order=a"><img style="width:10px" src="/images/down.gif"></a>
357 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
358 <a href="?sort_field=3&sort_order=d"><img style="width:10px" src="/images/up.gif"></a>
359 <a href="?sort_field=3&sort_order=a"><img style="width:10px" src="/images/down.gif"></a>
360 </th>
361 <th align='center' colspan="2">
362 <a href="?sort_field=2&sort_order=d"><img style="width:10px" src="/images/up.gif"></a>
363 <a href="?sort_field=2&sort_order=a"><img style="width:10px" src="/images/down.gif"></a>
364 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
365 <a href="?sort_field=4&sort_order=d"><img style="width:10px" src="/images/up.gif"></a>
366 <a href="?sort_field=4&sort_order=a"><img style="width:10px" src="/images/down.gif"></a>
367 </th>
368 <th align='center'>
369 <a href="?sort_field=8&sort_order=d"><img style="width:10px" src="/images/up.gif"></a>
370 <a href="?sort_field=8&sort_order=a"><img style="width:10px" src="/images/down.gif"></a>
371 &nbsp;&nbsp;&nbsp;&nbsp;
372 <a href="?sort_field=9&sort_order=d"><img style="width:10px" src="/images/up.gif"></a>
373 <a href="?sort_field=9&sort_order=a"><img style="width:10px" src="/images/down.gif"></a>
374 </th>
375 <th align='center'>
376 <a href="?sort_field=6&sort_order=d"><img style="width:10px" src="/images/up.gif"></a>
377 <a href="?sort_field=6&sort_order=a"><img style="width:10px" src="/images/down.gif"></a>
378 </th>
379 <th align='center'>
380 <a href="?sort_field=7&sort_order=d"><img style="width:10px" src="/images/up.gif"></a>
381 <a href="?sort_field=7&sort_order=a"><img style="width:10px" src="/images/down.gif"></a>
382 </th>
383 </tr>
384 <tr valign="top"">
385 <th align='center'>
386 $Lang::tr{'protocol'}
387 </th>
388 <th align='center' colspan="2">
389 $Lang::tr{'source ip and port'}
390 </th>
391 <th align='center' colspan="2">
392 $Lang::tr{'dest ip and port'}
393 </th>
394 <th align='center'>
395 $Lang::tr{'download'} /
396 <br>$Lang::tr{'upload'}
397 </th>
398 <th align='center'>
399 $Lang::tr{'connection'}<br>$Lang::tr{'status'}
400 </th>
401 <th align='center'>
402 $Lang::tr{'expires'}<br>($Lang::tr{'seconds'})
403 </th>
404 </tr>
405END
406
407foreach my $line (@conntrack) {
408 my @conn = split(' ', $line);
409
410 # The first bit is the l3 protocol.
411 my $l3proto = $conn[0];
412
413 # Skip everything that is not IPv4.
414 if ($l3proto ne 'ipv4') {
415 next;
416 }
417
418 # L4 protocol (tcp, udp, ...).
419 my $l4proto = $conn[2];
420
421 # Translate unknown protocols.
422 if ($l4proto eq 'unknown') {
423 my $l4protonum = $conn[3];
424 if ($l4protonum eq '2') {
425 $l4proto = 'IGMP';
426 } elsif ($l4protonum eq '4') {
427 $l4proto = 'IPv4 Encap';
428 } elsif ($l4protonum eq '33') {
429 $l4proto = 'DCCP';
430 } elsif ($l4protonum eq '41') {
431 $l4proto = 'IPv6 Encap';
432 } elsif ($l4protonum eq '50') {
433 $l4proto = 'ESP';
434 } elsif ($l4protonum eq '51') {
435 $l4proto = 'AH';
436 } elsif ($l4protonum eq '132') {
437 $l4proto = 'SCTP';
438 } else {
439 $l4proto = $l4protonum;
440 }
441 } else {
442 $l4proto = uc($l4proto);
443 }
444
445 # Source and destination.
446 my $sip;
447 my $sip_ret;
448 my $dip;
449 my $dip_ret;
450 my $sport;
451 my $sport_ret;
452 my $dport;
453 my $dport_ret;
454 my @packets;
455 my @bytes;
456
457 my $ttl = $conn[4];
458 my $state;
459 if ($l4proto eq 'TCP') {
460 $state = $conn[5];
461 }
462
463 # Kick out everything that is not IPv4.
464 foreach my $item (@conn) {
465 my ($key, $val) = split('=', $item);
466
467 switch ($key) {
468 case "src" {
469 if ($sip == "") {
470 $sip = $val;
471 } else {
472 $dip_ret = $val;
473 }
474 }
475 case "dst" {
476 if ($dip == "") {
477 $dip = $val;
478 } else {
479 $sip_ret = $val;
480 }
481 }
482 case "sport" {
483 if ($sport == "") {
484 $sport = $val;
485 } else {
486 $dport_ret = $val;
487 }
488 }
489 case "dport" {
490 if ($dport == "") {
491 $dport = $val;
492 } else {
493 $sport_ret = $val;
494 }
495 }
496 case "packets" {
497 push(@packets, $val);
498 }
499 case "bytes" {
500 push(@bytes, $val);
501 }
502 }
503 }
504
505 my $sip_colour = ipcolour($sip);
506 my $dip_colour = ipcolour($dip);
507
508 my $sserv = '';
509 if ($sport < 1024) {
510 $sserv = uc(getservbyport($sport, lc($l4proto)));
511 }
512
513 my $dserv = '';
514 if ($dport < 1024) {
515 $dserv = uc(getservbyport($dport, lc($l4proto)));
516 }
517
518 my $bytes_in = format_bytes($bytes[0]);
519 my $bytes_out = format_bytes($bytes[1]);
520
521 # Format TTL
522 $ttl = format_time($ttl);
523
524 my $sip_extra;
525 if ($sip ne $sip_ret) {
526 $sip_extra = "<font color='#FFFFFF'>&gt;</font> ";
527 $sip_extra .= "<a href='/cgi-bin/ipinfo.cgi?ip=$sip_ret'>";
528 $sip_extra .= " <font color='#FFFFFF'>$sip_ret</font>";
529 $sip_extra .= "</a>";
530 }
531
532 my $dip_extra;
533 if ($dip ne $dip_ret) {
534 $dip_extra = "<font color='#FFFFFF'>&gt;</font> ";
535 $dip_extra .= "<a href='/cgi-bin/ipinfo.cgi?ip=$dip_ret'>";
536 $dip_extra .= " <font color='#FFFFFF'>$dip_ret</font>";
537 $dip_extra .= "</a>";
538 }
539
540
541 my $sport_extra;
542 if ($sport ne $sport_ret) {
543 my $sserv_ret = '';
544 if ($sport_ret < 1024) {
545 $sserv_ret = uc(getservbyport($sport_ret, lc($l4proto)));
546 }
547
548 $sport_extra = "<font color='#FFFFFF'>&gt;</font> ";
549 $sport_extra .= "<a href='http://isc.sans.org/port_details.php?port=$sport_ret' target='top' title='$sserv_ret'>";
550 $sport_extra .= " <font color='#FFFFFF'>$sport_ret</font>";
551 $sport_extra .= "</a>";
552 }
553
554 my $dport_extra;
555 if ($dport ne $dport_ret) {
556 my $dserv_ret = '';
557 if ($dport_ret < 1024) {
558 $dserv_ret = uc(getservbyport($dport_ret, lc($l4proto)));
559 }
560
561 $dport_extra = "<font color='#FFFFFF'>&gt;</font> ";
562 $dport_extra .= "<a href='http://isc.sans.org/port_details.php?port=$dport_ret' target='top' title='$dserv_ret'>";
563 $dport_extra .= " <font color='#FFFFFF'>$dport_ret</font>";
564 $dport_extra .= "</a>";
565 }
566
567 print <<END;
568 <tr>
569 <td align='center'>$l4proto</td>
570 <td align='center' bgcolor='$sip_colour'>
571 <a href='/cgi-bin/ipinfo.cgi?ip=$sip'>
572 <font color='#FFFFFF'>$sip</font>
573 </a>
574 $sip_extra
575 </td>
576 <td align='center' bgcolor='$sip_colour'>
577 <a href='http://isc.sans.org/port_details.php?port=$sport' target='top' title='$sserv'>
578 <font color='#FFFFFF'>$sport</font>
579 </a>
580 $sport_extra
581 </td>
582 <td align='center' bgcolor='$dip_colour'>
583 <a href='/cgi-bin/ipinfo.cgi?ip=$dip'>
584 <font color='#FFFFFF'>$dip</font>
585 </a>
586 $dip_extra
587 </td>
588 <td align='center' bgcolor='$dip_colour'>
589 <a href='http://isc.sans.org/port_details.php?port=$dport' target='top' title='$dserv'>
590 <font color='#FFFFFF'>$dport</font>
591 </a>
592 $dport_extra
593 </td>
594 <td align='center'>
595 $bytes_in / $bytes_out
596 </td>
597 <td align='center'>$state</td>
598 <td align='center'>$ttl</td>
599 </tr>
600END
601}
602
603# Close the main table.
604print "</table>";
605
606&Header::closebox();
607&Header::closebigbox();
608&Header::closepage();
609
610sub format_bytes($) {
611 my $bytes = shift;
612 my @units = ("B", "k", "M", "G", "T");
613
614 foreach my $unit (@units) {
615 if ($bytes < 1024) {
616 return sprintf("%d%s", $bytes, $unit);
617 }
618
619 $bytes /= 1024;
620 }
621
622 return sprintf("%d%s", $bytes, $units[$#units]);
623}
624
625sub format_time($) {
626 my $time = shift;
627
628 my $seconds = $time % 60;
629 my $minutes = $time / 60;
630
631 my $hours = 0;
632 if ($minutes >= 60) {
633 $hours = $minutes / 60;
634 $minutes %= 60;
635 }
636
637 return sprintf("%3d:%02d:%02d", $hours, $minutes, $seconds);
638}
639
640sub ipcolour($) {
641 my $id = 0;
642 my $colour = ${Header::colourred};
643 my ($ip) = $_[0];
644 my $found = 0;
645
646 foreach my $line (@network) {
647 if ($network[$id] eq '') {
648 $id++;
649 } else {
650 if (!$found && ipv4_in_network($network[$id], $masklen[$id], $ip) ) {
651 $found = 1;
652 $colour = $colour[$id];
653 }
654 $id++;
655 }
656 }
657
658 return $colour;
659}
660
6611;