#!/usr/bin/perl ############################################################################### # # # IPFire.org - A linux based firewall # # Copyright (C) 2007-2020 IPFire Team # # Copyright (C) 2024 BPFire # # # # 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 # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program. If not, see . # # # ############################################################################### use strict; # enable only the following on debugging purpose #use warnings; #use CGI::Carp 'fatalsToBrowser'; use IO::Socket; require '/var/ipfire/general-functions.pl'; require "${General::swroot}/location-functions.pl"; require "${General::swroot}/lang.pl"; require "${General::swroot}/header.pl"; my %color = (); my %mainsettings = (); my %ddossettings=(); my %udpddossettings=(); my %dnsddossettings=(); my %checked=(); my $errormessage=''; my $counter = 0; my %tcp_ports=(); my %udp_ports=(); my $tcp_portfile = "${General::swroot}/ddos/tcp_ports"; my $udp_portfile = "${General::swroot}/ddos/udp_ports"; my $ddossettingfile = "${General::swroot}/ddos/settings"; my $udpddossettingfile = "${General::swroot}/ddos/udp-ddos-settings"; my $dnsddossettingfile = "${General::swroot}/ddos/dns-ddos-settings"; &get_tcp_ports(); &get_udp_ports(); # Read configuration file. &General::readhash("${General::swroot}/main/settings", \%mainsettings); &General::readhash("/srv/web/ipfire/html/themes/ipfire/include/colors.txt", \%color); &Header::showhttpheaders(); $ddossettings{'ENABLE_DDOS'} = 'off'; $udpddossettings{'ENABLE_UDP_DDOS'} = 'off'; $dnsddossettings{'ENABLE_DNS_DDOS'} = 'off'; $ddossettings{'ACTION'} = ''; $udpddossettings{'UDP_ACTION'} = ''; $udpddossettings{'DNS_ACTION'} = ''; &Header::getcgihash(\%ddossettings); if ($ddossettings{'ACTION'} eq $Lang::tr{'save'}) { # Loop through our locations array to prevent from # non existing countries or code. foreach my $p (values %tcp_ports) { # Check if blocking for this country should be enabled/disabled. if (exists $ddossettings{$p}) { $ddossettings{$p} = "on"; } else { $ddossettings{$p} = "off"; } } &General::writehash("$ddossettingfile", \%ddossettings); if ($ddossettings{'ENABLE_DDOS'} eq 'on') { &General::log($Lang::tr{'ddos is enabled'}); &General::system('/usr/bin/touch', "${General::swroot}/ddos/enableddos"); &General::system('/usr/local/bin/ddosctrl', 'start'); } else { &General::log($Lang::tr{'ddos is disabled'}); &General::system('/usr/local/bin/ddosctrl', 'stop'); unlink "${General::swroot}/ddos/enableddos"; } } &Header::getcgihash(\%udpddossettings); if ($udpddossettings{'UDP_ACTION'} eq $Lang::tr{'save'}) { # Loop through our locations array to prevent from # non existing countries or code. foreach my $p (values %udp_ports) { # Check if blocking for this country should be enabled/disabled. if (exists $udpddossettings{$p}) { $udpddossettings{$p} = "on"; } else { $udpddossettings{$p} = "off"; } } &General::writehash("$udpddossettingfile", \%udpddossettings); if ($udpddossettings{'ENABLE_UDP_DDOS'} eq 'on') { &General::log($Lang::tr{'ddos is enabled'}); &General::system('/usr/bin/touch', "${General::swroot}/ddos/enableddos"); &General::system('/usr/local/bin/ddosctrl', 'start'); } else { &General::log($Lang::tr{'ddos is disabled'}); &General::system('/usr/local/bin/ddosctrl', 'stop'); unlink "${General::swroot}/ddos/enableddos"; } } &Header::getcgihash(\%dnsddossettings); if ($udpddossettings{'DNS_ACTION'} eq $Lang::tr{'save'}) { &General::writehash("$dnsddossettingfile", \%dnsddossettings); if ($dnsddossettings{'ENABLE_DNS_DDOS'} eq 'on') { &General::log($Lang::tr{'ddos is enabled'}); &General::system('/usr/bin/touch', "${General::swroot}/ddos/enableddos"); &General::system('/usr/local/bin/ddosctrl', 'start'); } else { &General::log($Lang::tr{'ddos is disabled'}); &General::system('/usr/local/bin/ddosctrl', 'stop'); unlink "${General::swroot}/ddos/enableddos"; } } &Header::openpage($Lang::tr{'ebpf xdp ddos'}, 1, ''); &Header::openbigbox('100%', 'left', '', $errormessage); if ($errormessage) { &Header::openbox('100%', 'left', $Lang::tr{'error messages'}); print "$errormessage \n"; &Header::closebox(); } # Read configuration file. &General::readhash("$ddossettingfile", \%ddossettings); # Checkbox pre-selection. my $checked; if ($ddossettings{'ENABLE_DDOS'} eq "on") { $checked = "checked='checked'"; } # Print box to enable/disable locationblock. print"
\n"; &Header::openbox('100%', 'center', $Lang::tr{'xdp tcp'}); print < $Lang::tr{'xdp enable'} END &Header::closebox(); &Header::openbox('100%', 'center', $Lang::tr{'xdp tcp port'}); print < $Lang::tr{'port'} $Lang::tr{'service'}   $Lang::tr{'port'} $Lang::tr{'service'} END my $lines; my $lines2; my $col; # Sort output based on hash value port number for my $service ( sort { $tcp_ports{$a} cmp $tcp_ports{$b} } keys %tcp_ports ) { my $port = $tcp_ports{$service}; # Checkbox pre-selection. my $checked; if ($ddossettings{$port} eq "on") { $checked = "checked='checked'"; } # Colour lines. if ($lines % 2) { $col="bgcolor='$color{'color20'}'"; } else { $col="bgcolor='$color{'color22'}'"; } # Grouping elements. my $line_start; my $line_end; if ($lines2 % 2) { # Increase lines (background color by once. $lines++; # Add empty column in front. $line_start=" "; # When the line number can be diveded by "2", # we are going to close the line. $line_end=""; } else { # When the line number is not divideable by "2", # we are starting a new line. $line_start=""; $line_end; } print "$line_start\n"; print "$port\n"; print "$service$line_end\n"; $lines2++; } print < END &Header::closebox(); print "\n"; # # Read configuration file. &General::readhash("$dnsddossettingfile", \%dnsddossettings); # Checkbox pre-selection. my $dns_checked; if ($dnsddossettings{'ENABLE_DNS_DDOS'} eq "on") { $dns_checked = "checked='checked'"; } # Print box to enable/disable locationblock. print"
\n"; &Header::openbox('100%', 'center', $Lang::tr{'xdp dns'}); print < $Lang::tr{'xdp enable'} $Lang::tr{'xdp dns ratelimit'} END &Header::closebox(); print "\n"; # Read configuration file. &General::readhash("$udpddossettingfile", \%udpddossettings); # Checkbox pre-selection. my $udp_checked; if ($udpddossettings{'ENABLE_UDP_DDOS'} eq "on") { $udp_checked = "checked='checked'"; } # Print box to enable/disable locationblock. print"
\n"; &Header::openbox('100%', 'center', $Lang::tr{'xdp udp'}); print < $Lang::tr{'xdp enable'} $Lang::tr{'xdp udp ratelimit'} END &Header::closebox(); &Header::openbox('100%', 'center', $Lang::tr{'xdp udp port'}); print < $Lang::tr{'port'} $Lang::tr{'service'}   $Lang::tr{'port'} $Lang::tr{'service'} END my $udp_lines; my $udp_lines2; my $udp_col; # Sort output based on hash value port number for my $service ( sort { $udp_ports{$a} cmp $udp_ports{$b} } keys %udp_ports ) { my $port = $udp_ports{$service}; # Checkbox pre-selection. my $checked; if ($udpddossettings{$port} eq "on") { $checked = "checked='checked'"; } # Colour lines. if ($udp_lines % 2) { $col="bgcolor='$color{'color20'}'"; } else { $col="bgcolor='$color{'color22'}'"; } # Grouping elements. my $line_start; my $line_end; if ($udp_lines2 % 2) { # Increase lines (background color by once. $lines++; # Add empty column in front. $line_start=" "; # When the line number can be diveded by "2", # we are going to close the line. $line_end=""; } else { # When the line number is not divideable by "2", # we are starting a new line. $line_start=""; $line_end; } print "$line_start\n"; print "$port\n"; print "$service$line_end\n"; $udp_lines2++; } print < END &Header::closebox(); print "\n"; &Header::openbox('100%', 'center', $Lang::tr{'xdp status'}); print < $Lang::tr{'xdp interface'} $Lang::tr{'xdp prio'} $Lang::tr{'xdp program'} $Lang::tr{'xdp mode'} $Lang::tr{'xdp id'} $Lang::tr{'xdp tag'} $Lang::tr{'xdp action'} END &printxdp(); print "\n\n"; &Header::closebox(); &Header::closebigbox(); &Header::closepage(); sub get_tcp_ports() { my $fh; open($fh, '<', $tcp_portfile) or die "Unable to open file: $!"; while (my $line = <$fh>) { chomp $line; next if $line =~ /^\s*#/; # Skip comments my ($service, $port) = $line =~ /^(\w+)\s+(\d+)\/tcp/; if ($service && $port) { $tcp_ports{$service} = $port; } } close($fh); } sub get_udp_ports() { my $fh; open($fh, '<', $udp_portfile) or die "Unable to open file: $!"; while (my $line = <$fh>) { chomp $line; next if $line =~ /^\s*#/; # Skip comments my ($service, $port) = $line =~ /^(\w+)\s+(\d+)\/udp/; if ($service && $port) { $udp_ports{$service} = $port; } } close($fh); } sub printxdp() { # print active SSH logins (grep outpout of "who -s") my @output = &General::system_output("/usr/local/bin/ddosctrl", "status"); chomp(@output); # list active logins... foreach my $line (@output) { my $interface; my $prio; my $prog; my $mode; my $id; my $tag; my $action; #comment next below when having issue #next if $line !~ /^red0/; #next if $line !~ /^\s=>/; next if $line =~ /No XDP program loaded!/; if ($line =~ /^red0/) { my @arry = split(/\s+/, $line); $interface = $arry[0]; $prio = "N/A"; $prog = $arry[1]; $mode = $arry[2]; $id = $arry[3]; $tag = $arry[4]; $action = "N/A"; } elsif ($line =~ /^\s=>/) { my @arry = split(/\s+/, $line); $interface = "red0"; $prio = $arry[2]; $prog = $arry[3]; $mode = "N/A"; $id = $arry[4]; $tag = $arry[5]; $action = $arry[6]; } if ($line =~ /^red0/ or $line =~ /^\s=>/) { my $table_colour = ($id % 2) ? $color{'color20'} : $color{'color22'}; print < $interface $prio $prog $mode $id $tag $action END ; } } }