X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=html%2Fcgi-bin%2Fconnections.cgi;h=24702980c8f4eebe04a5921bd5f3677299cd69b9;hb=refs%2Fheads%2Fnext;hp=c27ff2ef761a70bebb550fd49e029ced97355cb9;hpb=cf45236b2aaa4ce095da053ac2d4bf9a08bc724a;p=ipfire-2.x.git diff --git a/html/cgi-bin/connections.cgi b/html/cgi-bin/connections.cgi index c27ff2ef76..badc1f395d 100644 --- a/html/cgi-bin/connections.cgi +++ b/html/cgi-bin/connections.cgi @@ -2,7 +2,7 @@ ############################################################################### # # # IPFire.org - A linux based firewall # -# Copyright (C) 2007-2012 IPFire Team # +# Copyright (C) 2007-2023 IPFire Team # # # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # @@ -20,244 +20,127 @@ ############################################################################### use strict; -use experimental 'smartmatch'; - -use Net::IPv4Addr qw( :all ); use Switch; # enable only the following on debugging purpose -#use warnings; -#use CGI::Carp 'fatalsToBrowser'; +use warnings; +use CGI::Carp 'fatalsToBrowser'; require '/var/ipfire/general-functions.pl'; require "${General::swroot}/lang.pl"; require "${General::swroot}/header.pl"; -require "${General::swroot}/geoip-functions.pl"; +require "${General::swroot}/ids-functions.pl"; +require "${General::swroot}/location-functions.pl"; my $colour_multicast = "#A0A0A0"; -# sort arguments for connection tracking table -# the sort field. eg. 1=src IP, 2=dst IP, 3=src port, 4=dst port -my $SORT_FIELD = 0; -# the sort order. (a)scending orr (d)escending -my $SORT_ORDER = 0; -# cgi query arguments -my %cgiin; -# debug mode -my $debug = 0; - -# retrieve query arguments -# note: let a-z A-Z and 0-9 pass as value only -if (length ($ENV{'QUERY_STRING'}) > 0){ - my $name; - my $value; - my $buffer = $ENV{'QUERY_STRING'}; - my @pairs = split(/&/, $buffer); - foreach my $pair (@pairs){ - ($name, $value) = split(/=/, $pair); - $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; # e.g. "%20" => " " - $value =~ s/[^a-zA-Z0-9]*//g; # a-Z 0-9 will pass - $cgiin{$name} = $value; - } -} +my %settings = (); +&General::readhash("/var/ipfire/ethernet/settings", \%settings); &Header::showhttpheaders(); -my @network=(); -my @masklen=(); -my @colour=(); +# Collect all known networks +my %networks = ( + # Localhost + "127.0.0.0/8" => ${Header::colourfw}, -my %netsettings=(); -&General::readhash("${General::swroot}/ethernet/settings", \%netsettings); + # Multicast + "224.0.0.0/3" => $colour_multicast, -# output cgi query arrguments to browser on debug -if ( $debug ){ - &Header::openbox('100%', 'center', 'DEBUG'); - my $debugCount = 0; - foreach my $line (sort keys %cgiin) { - print "$line = '$cgiin{$line}'
\n"; - $debugCount++; - } - print " Count: $debugCount\n"; - &Header::closebox(); -} + # GREEN + "$settings{'GREEN_ADDRESS'}/32" => ${Header::colourfw}, + "$settings{'GREEN_NETADDRESS'}/$settings{'GREEN_NETMASK'}" => ${Header::colourgreen}, -#workaround to suppress a warning when a variable is used only once -my @dummy = ( ${Header::table1colour} ); -undef (@dummy); + # BLUE + "$settings{'BLUE_ADDRESS'}/32" => ${Header::colourfw}, + "$settings{'BLUE_NETADDRESS'}/$settings{'BLUE_NETMASK'}" => ${Header::colourblue}, -# Init libloc database connection. -my $libloc_db_handle = &GeoIP::init(); + # ORANGE + "$settings{'ORANGE_ADDRESS'}/32" => ${Header::colourfw}, + "$settings{'ORANGE_NETADDRESS'}/$settings{'ORANGE_NETMASK'}" => ${Header::colourorange}, +); -# check sorting arguments -if ( $cgiin{'sort_field'} ~~ [ '1','2','3','4','5','6','7','8','9' ] ) { - $SORT_FIELD = $cgiin{'sort_field'}; - - if ( $cgiin{'sort_order'} ~~ [ 'a','d','A','D' ] ) { - $SORT_ORDER = lc($cgiin{'sort_order'}); - } +# RED Address +my $address = &IDS::get_red_address(); +if ($address) { + $networks{"${address}/32"} = ${Header::colourfw}; } -# Read and sort the connection tracking table -# do sorting -if ($SORT_FIELD and $SORT_ORDER) { - # field sorting when sorting arguments are sane - open(CONNTRACK, "/usr/local/bin/getconntracktable | /usr/local/bin/consort.sh $SORT_FIELD $SORT_ORDER |") or die "Unable to read conntrack table"; -} else { - # default sorting with no query arguments - open(CONNTRACK, "/usr/local/bin/getconntracktable | sort -k 5,5 --numeric-sort --reverse |") or die "Unable to read conntrack table"; +# Add all aliases +my @aliases = &IDS::get_aliases(); +for my $alias (@aliases) { + $networks{"${alias}/32"} = ${Header::colourfw}; } -my @conntrack = ; -close(CONNTRACK); -# Collect data for the @network array. +my %interfaces = ( + $settings{'GREEN_DEV'} => ${Header::colourgreen}, + $settings{'BLUE_DEV'} => ${Header::colourblue}, + $settings{'ORANGE_DEV'} => ${Header::colourorange}, -# Add Firewall Localhost 127.0.0.1 -push(@network, '127.0.0.1'); -push(@masklen, '255.255.255.255'); -push(@colour, ${Header::colourfw}); + # IPsec + "gre[0-9]+" => ${Header::colourvpn}, + "vti[0-9]+" => ${Header::colourvpn}, -if (open(IP, "${General::swroot}/red/local-ipaddress")) { - my $redip = ; - close(IP); + # OpenVPN + "tun[0-9]+" => ${Header::colourovpn}, +); - chomp $redip; - push(@network, $redip); - push(@masklen, '255.255.255.255'); - push(@colour, ${Header::colourfw}); -} +my @routes = &General::system_output("ip", "route", "show"); -# Add STATIC RED aliases -if ($netsettings{'RED_DEV'}) { - my $aliasfile = "${General::swroot}/ethernet/aliases"; - open(ALIASES, $aliasfile) or die 'Unable to open aliases file.'; - my @aliases = ; - close(ALIASES); - - # We have a RED eth iface - if ($netsettings{'RED_TYPE'} eq 'STATIC') { - # We have a STATIC RED eth iface - foreach my $line (@aliases) { - chomp($line); - my @temp = split(/\,/,$line); - if ($temp[0]) { - push(@network, $temp[0]); - push(@masklen, $netsettings{'RED_NETMASK'} ); - push(@colour, ${Header::colourfw} ); - } +# Find all routes +foreach my $intf (keys %interfaces) { + foreach my $route (grep(/dev ${intf}/, @routes)) { + if ($route =~ m/^(\d+\.\d+\.\d+\.\d+\/\d+)/) { + $networks{$1} = $interfaces{$intf}; } } } -# Add Green Firewall Interface -push(@network, $netsettings{'GREEN_ADDRESS'}); -push(@masklen, "255.255.255.255" ); -push(@colour, ${Header::colourfw} ); - -# Add Green Network to Array -push(@network, $netsettings{'GREEN_NETADDRESS'}); -push(@masklen, $netsettings{'GREEN_NETMASK'} ); -push(@colour, ${Header::colourgreen} ); - -# Add Green Routes to Array -my @routes = `/sbin/route -n | /bin/grep $netsettings{'GREEN_DEV'}`; -foreach my $route (@routes) { - chomp($route); - my @temp = split(/[\t ]+/, $route); - push(@network, $temp[0]); - push(@masklen, $temp[2]); - push(@colour, ${Header::colourgreen} ); -} +# Load the WireGuard client pool +if (-e "/var/ipfire/wireguard/settings") { + my %wgsettings = (); -# Add Blue Firewall Interface -push(@network, $netsettings{'BLUE_ADDRESS'}); -push(@masklen, "255.255.255.255" ); -push(@colour, ${Header::colourfw} ); - -# Add Blue Network -if ($netsettings{'BLUE_DEV'}) { - push(@network, $netsettings{'BLUE_NETADDRESS'}); - push(@masklen, $netsettings{'BLUE_NETMASK'} ); - push(@colour, ${Header::colourblue} ); - - # Add Blue Routes to Array - @routes = `/sbin/route -n | /bin/grep $netsettings{'BLUE_DEV'}`; - foreach my $route (@routes) { - chomp($route); - my @temp = split(/[\t ]+/, $route); - push(@network, $temp[0]); - push(@masklen, $temp[2]); - push(@colour, ${Header::colourblue} ); - } + &General::readhash("/var/ipfire/wireguard/settings", \%wgsettings); + + $networks{$wgsettings{'CLIENT_POOL'}} = ${Header::colourwg}; } -# Add Orange Firewall Interface -push(@network, $netsettings{'ORANGE_ADDRESS'}); -push(@masklen, "255.255.255.255" ); -push(@colour, ${Header::colourfw} ); - -# Add Orange Network -if ($netsettings{'ORANGE_DEV'}) { - push(@network, $netsettings{'ORANGE_NETADDRESS'}); - push(@masklen, $netsettings{'ORANGE_NETMASK'} ); - push(@colour, ${Header::colourorange} ); - # Add Orange Routes to Array - @routes = `/sbin/route -n | /bin/grep $netsettings{'ORANGE_DEV'}`; - foreach my $route (@routes) { - chomp($route); - my @temp = split(/[\t ]+/, $route); - push(@network, $temp[0]); - push(@masklen, $temp[2]); - push(@colour, ${Header::colourorange} ); +# Load routed WireGuard networks +if (-e "/var/ipfire/wireguard/peers") { + my %wgpeers = (); + + # Load all peers + &General::readhasharray("/var/ipfire/wireguard/peers", \%wgpeers); + + foreach my $key (keys %wgpeers) { + my $networks = $wgpeers{$key}[6]; + + # Split the string + my @networks = split(/\|/, $networks); + + foreach my $network (@networks) { + $networks[$network] = ${Header::colourwg}; + } } } -# Highlight multicast connections. -push(@network, "224.0.0.0"); -push(@masklen, "239.0.0.0"); -push(@colour, $colour_multicast); - # Add OpenVPN net and RED/BLUE/ORANGE entry (when appropriate) if (-e "${General::swroot}/ovpn/settings") { my %ovpnsettings = (); &General::readhash("${General::swroot}/ovpn/settings", \%ovpnsettings); - my @tempovpnsubnet = split("\/",$ovpnsettings{'DOVPN_SUBNET'}); - - # add OpenVPN net - push(@network, $tempovpnsubnet[0]); - push(@masklen, $tempovpnsubnet[1]); - push(@colour, ${Header::colourovpn} ); - - # add BLUE:port / proto - if (($ovpnsettings{'ENABLED_BLUE'} eq 'on') && $netsettings{'BLUE_DEV'}) { - push(@network, $netsettings{'BLUE_ADDRESS'} ); - push(@masklen, '255.255.255.255' ); - push(@colour, ${Header::colourovpn}); - } - # add ORANGE:port / proto - if (($ovpnsettings{'ENABLED_ORANGE'} eq 'on') && $netsettings{'ORANGE_DEV'}) { - push(@network, $netsettings{'ORANGE_ADDRESS'} ); - push(@masklen, '255.255.255.255' ); - push(@colour, ${Header::colourovpn} ); - } + $networks{$ovpnsettings{'DOVPN_SUBNET'}} = ${Header::colourovpn}; } # Add OpenVPN net for custom OVPNs if (-e "${General::swroot}/ovpn/ccd.conf") { - open(OVPNSUB, "${General::swroot}/ovpn/ccd.conf"); - my @ovpnsub = ; - close(OVPNSUB); - - foreach (@ovpnsub) { - my ($network, $mask) = split '/', (split ',', $_)[2]; - - $mask = ipv4_cidr2msk($mask) unless &General::validip($mask); + open(OVPNSUB, "${General::swroot}/ovpn/ccd.conf"); + foreach my $line () { + my @ovpn = split(',', $line); - push(@network, $network); - push(@masklen, $mask); - push(@colour, ${Header::colourovpn}); + $networks{$ovpn[3]} = ${Header::colourovpn}; } + close(OVPNSUB); } open(IPSEC, "${General::swroot}/vpn/config"); @@ -269,42 +152,25 @@ foreach my $line (@ipsec) { my @subnets = split(/\|/, $vpn[12]); for my $subnet (@subnets) { - my ($network, $mask) = split("/", $subnet); - - if (!&General::validip($mask)) { - $mask = ipv4_cidr2msk($mask); - } - - push(@network, $network); - push(@masklen, $mask); - push(@colour, ${Header::colourvpn}); + $networks{$subnet} = ${Header::colourvpn}; } } if (-e "${General::swroot}/ovpn/n2nconf") { open(OVPNN2N, "${General::swroot}/ovpn/ovpnconfig"); - my @ovpnn2n = ; - close(OVPNN2N); - - foreach my $line (@ovpnn2n) { + foreach my $line () { my @ovpn = split(',', $line); next if ($ovpn[4] ne 'net'); - my ($network, $mask) = split("/", $ovpn[12]); - if (!&General::validip($mask)) { - $mask = ipv4_cidr2msk($mask); - } - - push(@network, $network); - push(@masklen, $mask); - push(@colour, ${Header::colourovpn}); + $networks{$ovpn[12]} = ${Header::colourovpn}; } + close(OVPNN2N); } # Show the page. &Header::openpage($Lang::tr{'connections'}, 1, ''); &Header::openbigbox('100%', 'left'); -&Header::openbox('100%', 'left', $Lang::tr{'connection tracking'}); +&Header::opensection(); # Print legend. print < $Lang::tr{'vpn'} + + $Lang::tr{'wireguard'} + $Lang::tr{'OpenVPN'} @@ -342,103 +211,38 @@ print < END -if ($SORT_FIELD and $SORT_ORDER) { - my @sort_field_name = ( - $Lang::tr{'source ip'}, - $Lang::tr{'destination ip'}, - $Lang::tr{'source port'}, - $Lang::tr{'destination port'}, - $Lang::tr{'protocol'}, - $Lang::tr{'connection'}.' '.$Lang::tr{'status'}, - $Lang::tr{'expires'}.' ('.$Lang::tr{'seconds'}.')', - $Lang::tr{'download'}, - $Lang::tr{'upload'} - ); - my $sort_order_name; - if (lc($SORT_ORDER) eq "a") { - $sort_order_name = $Lang::tr{'sort ascending'}; - } else { - $sort_order_name = $Lang::tr{'sort descending'}; - } - -print < - $sort_order_name: $sort_field_name[$SORT_FIELD-1] - -END -; -} - -# Print table header. +# Print table header print < - - - - - - - - -          - - - -   - - - -        - - - -   - - - -      - - - - - - - - - - - - + - - - - + - - + - - END -foreach my $line (@conntrack) { +# Read and sort the connection tracking table +open(CONNTRACK, "/usr/local/bin/getconntracktable | sort -k 5,5 --numeric-sort --reverse |") + or die "Unable to read conntrack table"; + +foreach my $line () { my @conn = split(' ', $line); # The first bit is the l3 protocol. @@ -550,17 +354,18 @@ foreach my $line (@conntrack) { $dserv = uc(getservbyport($dport, lc($l4proto))); } - my $bytes_in = format_bytes($bytes[0]); - my $bytes_out = format_bytes($bytes[1]); + # Format bytes + my $bytes_in = &General::formatBytes($bytes[0]); + my $bytes_out = &General::formatBytes($bytes[1]); - # enumerate GeoIP information - my $srcccode = &GeoIP::lookup_country_code($libloc_db_handle, $sip_ret); - my $src_flag_icon = &GeoIP::get_flag_icon($srcccode); - my $dstccode = &GeoIP::lookup_country_code($libloc_db_handle, $dip_ret); - my $dst_flag_icon = &GeoIP::get_flag_icon($dstccode); + # enumerate location information + my $srcccode = &Location::Functions::lookup_country_code($sip_ret); + my $src_flag_icon = &Location::Functions::get_flag_icon($srcccode); + my $dstccode = &Location::Functions::lookup_country_code($dip_ret); + my $dst_flag_icon = &Location::Functions::get_flag_icon($dstccode); # Format TTL - $ttl = format_time($ttl); + $ttl = &General::format_time($ttl); my $sip_extra; if ($sip_ret && $sip ne $sip_ret) { @@ -578,7 +383,6 @@ foreach my $line (@conntrack) { $dip_extra .= ""; } - my $sport_extra; if ($sport ne $sport_ret) { my $sserv_ret = ''; @@ -587,7 +391,7 @@ foreach my $line (@conntrack) { } $sport_extra = "> "; - $sport_extra .= ""; + $sport_extra .= ""; $sport_extra .= " $sport_ret"; $sport_extra .= ""; } @@ -600,7 +404,7 @@ foreach my $line (@conntrack) { } $dport_extra = "> "; - $dport_extra .= ""; + $dport_extra .= ""; $dport_extra .= " $dport_ret"; $dport_extra .= ""; } @@ -615,7 +419,7 @@ foreach my $line (@conntrack) { $sip_extra - + @@ -647,64 +454,35 @@ foreach my $line (@conntrack) { END } +close(CONNTRACK); + # Close the main table. print "
+ $Lang::tr{'protocol'} + $Lang::tr{'source ip and port'} - $Lang::tr{'country'} - + $Lang::tr{'dest ip and port'} - $Lang::tr{'country'} - - $Lang::tr{'download'} / -
$Lang::tr{'upload'} +
+ $Lang::tr{'data transfer'} + $Lang::tr{'connection'}
$Lang::tr{'status'}
- $Lang::tr{'expires'}
($Lang::tr{'seconds'}) +
+ $Lang::tr{'expires'}
($Lang::tr{'hours:minutes:seconds'})
- + $sport $sport_extra @@ -630,7 +434,7 @@ foreach my $line (@conntrack) { $dip_extra - + $dport $dport_extra @@ -638,8 +442,11 @@ foreach my $line (@conntrack) { $dstccode - $bytes_in / $bytes_out + + > $bytes_in + + < $bytes_out $state $ttl
"; -&Header::closebox(); +&Header::closesection(); &Header::closebigbox(); &Header::closepage(); -sub format_bytes($) { - my $bytes = shift; - my @units = ("B", "k", "M", "G", "T"); - - foreach my $unit (@units) { - if ($bytes < 1024) { - return sprintf("%d%s", $bytes, $unit); - } - - $bytes /= 1024; - } - - return sprintf("%d%s", $bytes, $units[$#units]); -} - -sub format_time($) { - my $time = shift; - - my $seconds = $time % 60; - my $minutes = $time / 60; - - my $hours = 0; - if ($minutes >= 60) { - $hours = $minutes / 60; - $minutes %= 60; - } - - return sprintf("%3d:%02d:%02d", $hours, $minutes, $seconds); -} - sub ipcolour($) { - my $id = 0; - my $colour = ${Header::colourred}; - my ($ip) = $_[0]; - my $found = 0; - - if ($ip) { - foreach my $line (@network) { - if ($network[$id] eq '') { - $id++; - } else { - if (!$found && ipv4_in_network($network[$id], $masklen[$id], $ip) ) { - $found = 1; - $colour = $colour[$id]; + my $address = shift; + + # Sort all networks so we find the best match + my @networks = reverse sort { + &Network::get_prefix($a) <=> &Network::get_prefix($b) + } keys %networks; + + foreach my $network (@networks) { + if (defined $network) { + if (&Network::check_ip_address_and_netmask($network)) { + if (&Network::ip_address_in_network($address, $network)) { + return $networks{$network}; } - $id++; } } } - return $colour; + # If we don't know the network, the address must be from the RED network + return ${Header::colourred}; } 1;