package ONO::Apps::Admin::Screen::Info::Security;
################################################################################
# COPYRIGHT / LICENSE #
################################################################################
#
# This file is part of the ONO Software Project.
#
# Copyright (C) 2000-2025 Jos KIRPS [ www.kirps.com | jos_AT_kirps_DOT_com ]
# and The Joopita Project [ www.joopita.org | contact_AT_joopita_DOT_com ]
#
# This file, as well as other parts of the ONO Software Project or related
# elements, are FREE SOFTWARE available under the ARTISTIC LICENSE 2.0.
#
# 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.
#
# For the full license, see /ono/osr/license/LICENSE.txt, or write to
# jos_AT_kirps_DOT_com or contact_AT_joopita_DOT_com.
#
################################################################################
# END OF COPYRIGHT / LICENSE, HERE COMES THE CODE ... #
################################################################################
use strict;
use ONO::IO;
use ONO::Lib::Basic;
use ONO::ToolBox::Security;
use ONO::Lib::DateTime::ToolBox;
###############################################################################
# ONO
###############################################################################
sub screen {
my (
$self,
$db,
$community,
$lang,
$BLK_ref,
$vars_ref,
$sql_ref,
$ono_ref,
) = @_;
#: The ONO Admin security screen, where admins may track and block evil
#: IPs and attackers.
my %BLK = %$BLK_ref;
my %vars = %$vars_ref;
my %sql = %$sql_ref;
my ($TITLE,$SUBTITLE,$SCREEN,$LEFT,$RIGHT,$TOOLS);
$TITLE = "ONO Security";
$SUBTITLE = "Accesses & Firewall [ $ENV{'REMOTE_ADDR'} ]";
my (
$sec,$min,$hour,
$mday,$mon,$year,
$wday,$yday,$timestamp
) = ONO::Lib::DateTime::ToolBox->get;
my (@IPTABLES,%RULES,%FRIENDLY,%CUSTOM);
$vars{'firewall_block_ip'} =~ s~[^0-9\.]~~g;
if (ONO::Lib::Basic->valid_ip_range($vars{'firewall_block_ip'}) && !&protected_range("",$vars{'firewall_block_ip'})) {
ONO::IO->mkpath("etc/security/iptables_rules_backup");
ONO::IO->append("etc/security/iptables_rules.txt","$vars{'firewall_block_ip'}:block:\n");
ONO::IO->append("etc/security/iptables_rules_backup/$year$mon$mday$hour.txt","$vars{'firewall_block_ip'}:block:\n");
ONO::IO->store("etc/security/iptables_rules_refresh.txt","$vars{'username'}");
$SCREEN .= qq~<div class="box_green mb10">
IP '$vars{'firewall_block_ip'}' has been added to the blocking list, firewall will take action soon...
</div>
~;
}
# foreach my $line (sort ONO::IO->list("var/log/security/iptables_rules_current.txt")) {
# $line =~ s~(\n|\r|\t)~~g;
# @IPTABLES = (@IPTABLES,$line);
# }
foreach my $line (ONO::IO->list("etc/security/friendly_ips.txt")) {
$line =~ s~(\n|\r|\t|\ )~~g;
if ($line =~ /[0-9]/) {
$FRIENDLY{$line}++;
}
}
if ($ENV{'REQUEST_URI'} =~ m~/firewall:(.*?):(.*?)/~) {
my ($mode,$ip) = ($1,$2);
if (!&protected_range("",$ip)) {
if ($mode eq "block") {
if (ONO::Lib::Basic->valid_ip_range($ip)) {
ONO::IO->append("etc/security/iptables_rules.txt","$ip:$mode:\n");
ONO::IO->append("etc/security/iptables_rules_backup/$year$mon$mday$hour.txt","$ip:$mode:\n");
ONO::IO->store("etc/security/iptables_rules_refresh.txt","$vars{'username'}");
}
} else {
my ($DATA,%used,$found);
foreach my $line (sort ONO::IO->list("etc/security/iptables_rules.txt")) {
my @lp = split(/:/,$line);
if ($lp[0] eq $ip) {
$found++;
}
if ($lp[0] ne $ip && !$used{$line}) {
$used{$line}++;
$DATA .= $line;
}
}
if ($mode =~ /^(trust|warn)$/) {
$DATA .= "$ip:$mode:\n";
ONO::IO->mkpath("etc/security/iptables_rules_backup");
if ($found) {
ONO::IO->store("etc/security/iptables_rules.txt",$DATA);
ONO::IO->store("etc/security/iptables_rules_backup/$year$mon$mday$hour.txt",$DATA);
} else {
if (ONO::Lib::Basic->valid_ip_range($ip)) {
ONO::IO->append("etc/security/iptables_rules.txt","$ip:$mode:\n");
ONO::IO->append("etc/security/iptables_rules_backup/$year$mon$mday$hour.txt","$ip:$mode:\n");
}
}
ONO::IO->store("etc/security/iptables_rules_refresh.txt","$vars{'username'}");
}
if ($mode =~ /^(flush)$/) {
ONO::IO->mkpath("etc/security/iptables_rules_backup");
ONO::IO->store("etc/security/iptables_rules.txt",$DATA);
ONO::IO->store("etc/security/iptables_rules_backup/$year$mon$mday$hour.txt",$DATA);
ONO::IO->store("etc/security/iptables_rules_refresh.txt","$vars{'username'}");
}
}
}
}
if ($ENV{'REQUEST_URI'} !~ /optimize/) {
foreach my $line (ONO::IO->list("etc/security/iptables_rules.txt")) {
my @lp = split(/:/,$line);
$RULES{$lp[0]} = $lp[1];
}
foreach my $line (ONO::IO->list("etc/security/iptables_rules_custom.txt")) {
my @lp = split(/:/,$line);
$CUSTOM{$lp[0]} = $lp[1];
}
}
if (($ENV{'REQUEST_URI'} =~ m~/info_security/(.*?)/~ && $ENV{'REQUEST_URI'} !~ m~/firewall:~) || $vars{'secmode'}) {
my $uri = $1;
if ($uri =~ /-/) {
$uri =~ m~^(.*?)-(.*?)$~;
my $ip = $1;
my $ip32 = $2;
# if (&check_firewall_block("",$ip,\@IPTABLES)) {
# $SCREEN = "IS BLOCKED";
# }
foreach my $line (ONO::IO->list("var/log/security/report_agents.txt")) {
$line =~ s~(\n|\r|\t)~~g;
my @lp = split(/=/,$line);
if ($ip32 eq $lp[0]) {
$SCREEN .= qq~<div>$lp[0] - $lp[1]</div>~;
}
}
$SCREEN .= qq~<div class="inline w100">
<a href="/ono/admin/?/info_security/firewall:trust:$ip/" class="button_green mt10">trust</a>
<a href="/ono/admin/?/info_security/firewall:warn:$ip/" class="button_yellow mt10">warn</a>
<a href="/ono/admin/?/info_security/firewall:block:$ip/" class="button_red mt10">block</a>
</div>
<div class="inline w100">
<a href="/ono/admin/?/info_security/apacheaccesslog/$ip32/" class="button button_orange mt10">check access.log</a>
</div>
<div class="inline w100">
<a href="https://www.abuseipdb.com/check/$ip32" target="_blank" class="button_yellow mt10">AbuseIPDB: $ip32</a>
</div>
<div class="inline w100">
<a href="https://www.killall.net/webmaster/botverifier.php?ip=$ip32" target="_blank" class="button_yellow mt10">VerifyBot: $ip32</a>
</div>
~;
} else {
if ($uri eq "auth" || $vars{'secmode'} eq "auth") {
my (@LISTS,@NUMS,@SORTED1,@SORTED2,%TRIPLETS24,%TRIPLETS16,%TMP);
# include custom rules
foreach my $line (ONO::IO->list("etc/security/iptables_rules_custom.txt")) {
my @lp = split(/:/,$line);
$RULES{$lp[0]} = $lp[1];
}
# check TMPs
foreach my $line (ONO::IO->list("etc/security/iptables_rules_tmp.txt")) {
my @lp = split(/:/,$line);
if ($lp[1] eq "block") {
$TMP{$lp[0]} = $lp[1];
}
}
foreach my $line (ONO::IO->list("var/log/security/report_ips_auth.txt")) {
$line =~ s~(\n|\r|\t)~~g;
if ($line =~ m~^auth_ip_(.*?)=(.*?)$~) {
my $ip = $1;
my $num = $2;
# $ip =~ m~^(.*?)\.(.*?)\.(.*?)\.(.*?)$~;
# my $ip_1 = $1;
# my $ip_2 = $2;
# my $ip_3 = $3;
# my $ip_4 = $4;
my @ips = split(/\./,$ip);
my $ip_1 = $ips[0];
my $ip_2 = $ips[1];
my $ip_3 = $ips[2];
my $ip_4 = $ips[3];
$TRIPLETS24{"$ip_1\.$ip_2\.$ip_3"}++;
$TRIPLETS16{"$ip_1\.$ip_2"}++;
my ($BG,$BG2,$BUT,$BUT3,$SORT);
if ($RULES{$ip} eq "block") {
$BG = " bg_red";
} else {
$BUT = qq~<a href="/ono/admin/?/info_security/firewall:block:$ip/"><img class="block16" src="/ono/osr/images/icons/ono/32x32/remove.png" alt=""></a>~;
if ($RULES{"$ip_1.$ip_2.$ip_3"} || $RULES{"$ip_1.$ip_2"} || $RULES{"$ip_1"}) {
$BG = " bg_red";
} else {
$BUT3 = qq~<a href="/ono/admin/?/info_security/firewall:block:$ip_1.$ip_2.$ip_3/" class="button_red small" style="padding:0px 3px 0px 3px">3</a>~;
}
if ($TMP{$ip}) {
$BG2 = " bg_blue";
}
}
if ($vars{'order'} eq "ip") {
$SORT = qq~<!--sort:$ip-->~;
}
my $LINE = qq~ $SORT
<tr class="bt bb row$BG$BG2">
<td>$BUT3</td>
<td class="w100">$ip</td>
<td class="tar col9">$num</td>
<td class="pad10_2"><a href="https://www.abuseipdb.com/check/$ip" class="col9" target="_blank">[?]</a></td>
<td>$BUT</td>
</tr>
~;
if ($num > 1) {
if (!$BG) {
$NUMS[0]++;
}
$NUMS[1]++;
$LISTS[1] .= $LINE;
if ($vars{'order'} eq "ip") {
@SORTED1 = (@SORTED1,$LINE);
}
}
if (!$BG) {
$NUMS[2]++;
$LISTS[2] .= $LINE;
if ($vars{'order'} eq "ip") {
@SORTED2 = (@SORTED2,$LINE);
}
}
}
}
if ($vars{'order'} eq "ip") {
$LISTS[1] = "";
$LISTS[2] = "";
foreach my $LINE (sort @SORTED1) {
$LISTS[1] .= $LINE;
}
foreach my $LINE (sort @SORTED2) {
$LISTS[2] .= $LINE;
}
}
my ($TRIS16,$TRIS24);
foreach my $TRIPLET (sort keys %TRIPLETS24) {
if ($TRIPLETS24{$TRIPLET} > 2) {
my $BG;
if ($RULES{$TRIPLET} eq "block") {
$BG = " bg_red";
} else {
my @ipp = split(/\./,$TRIPLET);
if ($RULES{"$ipp[0]\.$ipp[1]\.$ipp[2]"} || $RULES{"$ipp[0]\.$ipp[1]"} || $RULES{"$ipp[0]"}) {
$BG = " bg_red";
}
}
$TRIS24 .= qq~<tr class="bt bb$BG">
<td class="pad5_2 w100">$TRIPLET</td>
<td class="pad5_2 tar col9">$TRIPLETS24{$TRIPLET}</td>
<td class="pad10_2"><a href="https://www.abuseipdb.com/check/$TRIPLET.1" class="col9" target="_blank">[?]</a></td>
<td><a href="/ono/admin/?/info_security/firewall:block:$TRIPLET/"><img class="block16" src="/ono/osr/images/icons/ono/32x32/remove.png" alt=""></a></td>
</tr>
~;
}
}
foreach my $TRIPLET (sort keys %TRIPLETS16) {
if ($TRIPLETS16{$TRIPLET} > 7) {
my $BG;
if ($RULES{$TRIPLET} eq "block") {
$BG = " bg_red";
} else {
my @ipp = split(/\./,$TRIPLET);
if ($RULES{"$ipp[0]\.$ipp[1]"} || $RULES{"$ipp[0]"}) {
$BG = " bg_red";
}
}
$TRIS16 .= qq~<tr class="bt bb$BG">
<td class="pad5_2 w100">$TRIPLET</td>
<td class="pad5_2 tar col9">$TRIPLETS16{$TRIPLET}</td>
<td class="pad10_2"><a href="https://www.abuseipdb.com/check/$TRIPLET.1.1" class="col9" target="_blank">[?]</a></td>
<td><a href="/ono/admin/?/info_security/firewall:block:$TRIPLET/"><img class="block16" src="/ono/osr/images/icons/ono/32x32/remove.png" alt=""></a></td>
</tr>
~;
}
}
$SCREEN .= qq~<div class="inline w100">
<div class="w25 fl">
<div class="pad10_2">
<div class="box_paper">
<div class="fr">$NUMS[0]/$NUMS[1]</div>
<h3>All IPs > 1</h3>
<table class="default_table bt bb">
$LISTS[1]
</table>
</div>
</div>
</div>
<div class="w25 fl">
<div class="pad10_2">
<div class="box_paper">
<div class="fr">$NUMS[2]</div>
<h3>Unmarked IPs</h3>
<table class="default_table bt bb">
$LISTS[2]
</table>
</div>
</div>
</div>
<div class="w25 fl">
<div class="pad10_2">
<div class="box_paper mb10">
<$vars{'form'}>
<input type="hidden" name="secmode" value="auth">
<table class="wide_table">
<tr>
<td class="p0 w100"><input type="text" name="firewall_block_ip" value="" class="w100 query" maxlength="16" placeholder="0.0.0.0"></td>
<td class="p0"><input type="submit" name="firewall_block_ip_button" value="block" class="button_red button_right"></td>
</tr>
</table>
</form>
<div class="inline">
<a href="/ono/admin/?/info_security/auth/&order=ip" class="button_yellow mt10">order by IP</a>
</div>
</div>
<div class="box_paper mb10">
<h3>Top /24</h3>
<table class="wide_table bt bb">
$TRIS24
</table>
</div>
<div class="box_paper">
<h3>Top /16</h3>
<table class="wide_table bt bb">
$TRIS16
</table>
</div>
</div>
</div>
</div>
~;
}
if ($uri eq "images") {
my (%IMG,%IMG2,%IP24,%IP32,%IP24i,%IP32i);
foreach my $opt ("var/log/security/apache_access_log.txt","var/log/security/apache_access_log_previous.txt") {
foreach my $line (ONO::IO->list($opt)) {
my $img;
if ($line =~ /\.(jpg|jpeg|png)/ && $line !~ m~ /ono/~) {
$line =~ m~(GET|HEAD) (.*?) HTTP~;
$img = $2;
if ($line =~ /^(.*?) (.*?)\.(.*?)\.(.*?)\.(.*?) \[/) {
my $domain = $1;
my $ip24 = "$2.$3.$4";
my $ip32 = "$2.$3.$4.$5";
$IMG{"$domain$img"}++;
$IP24{$ip24}++;
$IP32{$ip32}++;
if (length $IMG2{"$domain$img"} < 256) {
$IMG2{"$domain$img"} .= "$ip32, ";
}
if (length $IP24i{$ip24} < 256) {
$IP24i{$ip24} .= "$domain$img, ";
}
if (length $IP32i{$ip32} < 256) {
$IP32i{$ip32} .= "$domain$img, ";
}
}
}
}
}
my ($count,$count24,$count32);
$SCREEN .= qq~<div class="box_paper mb10">
<h3>Top images</h3>
<table class="default_table">
~;
foreach my $img (reverse sort { $IMG{$a} <=> $IMG{$b} } keys %IMG) {
if ($count < 20) {
$count++;
my $img_show = $img;
$img_show =~ s~^(.*?)/~<span class="bold">$1</span>/~;
my ($IPS,%used);
foreach my $ip (split(/,/,$IMG2{$img})) {
if ($ip =~ /[0-9]/ && !$used{$ip}) {
$used{$ip}++;
$IPS .= qq~<a href="https://www.abuseipdb.com/check/$ip" target="_blank">$ip</a>, ~;
}
}
$IPS =~ s~, $~~;
$SCREEN .= qq~ <tr class="vtop">
<td class="pad10_2 tar col6">$IMG{$img}x</td>
<td><a href="https://$img" target="_blank" class="col6">$img_show</a><div class="small ml20">$IPS</div></td>
</tr>
~;
}
}
$SCREEN .= qq~ </table>
</div>
<div class="box_paper mb10">
<h3>Top IPs</h3>
<table class="default_table">
~;
foreach my $ip (reverse sort { $IP32{$a} <=> $IP32{$b} } keys %IP32) {
if ($count32 < 20) {
$count32++;
$SCREEN .= qq~ <tr class="vtop">
<td class="tar">$IP32{$ip}x</td>
<td class="pad10_2"><a href="https://www.abuseipdb.com/check/$ip" target="_blank">$ip</a></td>
<td class="col6">$IP32i{$ip}</td>
</td>
~;
}
}
$SCREEN .= qq~ </table>
</div>
<div class="box_paper mb10">
<h3>Top /24 IP ranges</h3>
<table class="default_table">
~;
foreach my $ip (reverse sort { $IP24{$a} <=> $IP24{$b} } keys %IP24) {
if ($count24 < 20) {
$count24++;
$SCREEN .= qq~ <tr class="vtop">
<td class="tar">$IP24{$ip}x</td>
<td class="pad10_2"><a href="https://www.abuseipdb.com/check/$ip.1" target="_blank">$ip</a></td>
<td class="col6">$IP24i{$ip}</td>
</td>
~;
}
}
$SCREEN .= qq~ </table>
</div>
~;
}
if ($uri eq "optimizeautofix" || $vars{'secmode'} eq "optimizeautofix") {
$SCREEN .= qq~<div class="lightred bold mb10">Trying to optimize the database...</div>~;
my ($DATA,%USED);
foreach my $line (ONO::IO->list("etc/security/iptables_rules_custom.txt")) {
if ($line =~ /[0-9]/ && $line =~ s~:block:~~) {
$line =~ s~(\n|\r|\t)~~g;
$USED{$line}++;
}
}
foreach my $line (reverse sort ONO::IO->list("etc/security/iptables_rules.txt")) {
my $IP = $line;
$IP =~ s~:(.*)$~~g;
$IP =~ s~(\n|\r|\t)~~g;
if ($IP =~ /^(.*?)\.(.*?)\.(.*?)\.(.*?)$/) {
if ($USED{"$1"} || $USED{"$1\.$2"} || $USED{"$1\.$2\.$3"} || $USED{"$1\.$2\.$3\.$4"} || $USED{$IP}) {
$SCREEN .= qq~<div class="lightred">$IP removed...</div>~;
} else {
$DATA .= $line;
}
} else {
if ($IP =~ /^(.*?)\.(.*?)\.(.*?)$/) {
if ($USED{"$1"} || $USED{"$1\.$2"} || $USED{"$1\.$2\.$3"} || $USED{$IP}) {
$SCREEN .= qq~<div class="lightred">$IP removed...</div>~;
} else {
$DATA .= $line;
}
} else {
if ($IP =~ /^(.*?)\.(.*?)$/) {
if ($USED{"$1"} || $USED{"$1\.$2"} || $USED{$IP}) {
$SCREEN .= qq~<div class="lightred">$IP removed...</div>~;
} else {
$DATA .= $line;
}
} else {
$DATA .= $line;
}
}
}
$USED{$IP}++;
}
ONO::IO->store("etc/security/iptables_rules.txt",$DATA);
$SCREEN .= qq~<div class="lightred mt10 mb20">done...</div>~;
}
if ($uri eq "optimize" || $vars{'secmode'} eq "optimize" || $uri eq "optimizeautofix" || $vars{'secmode'} eq "optimizeautofix") {
my ($custom,$blocked) = (0,0);
my (%CUSTOM,%BLOCKED,%USED);
foreach my $line (ONO::IO->list("etc/security/iptables_rules_custom.txt")) {
if ($line =~ /[0-9]/ && $line =~ s~:block:~~) {
$line =~ s~(\n|\r|\t)~~g;
$CUSTOM{$line}++;
$custom++;
}
}
$SCREEN .= qq~<div><span class="bold">$custom</span> blocked IP addresses in /etc/security/iptables_rules_custom.txt</div>~;
foreach my $IP (sort keys %CUSTOM) {
if ($IP =~ /^(.*?)\.(.*?)\.(.*?)\.(.*?)$/) {
if ($CUSTOM{"$1"} || $CUSTOM{"$1\.$2"} || $CUSTOM{"$1\.$2\.$3"}) {
$SCREEN .= qq~<div class="lightred">$IP seems to be redundant (please fix manually)</div>~;
}
} else {
if ($IP =~ /^(.*?)\.(.*?)\.(.*?)$/) {
if ($CUSTOM{"$1"} || $CUSTOM{"$1\.$2"}) {
$SCREEN .= qq~<div class="lightred">$IP seems to be redundant (please fix manually)</div>~;
}
} else {
if ($IP =~ /^(.*?)\.(.*?)$/) {
if ($CUSTOM{"$1"}) {
$SCREEN .= qq~<div class="lightred">$IP seems to be redundant (please fix manually)</div>~;
}
}
}
}
}
foreach my $line (ONO::IO->list("etc/security/iptables_rules.txt")) {
if ($line =~ /[0-9]/ && $line =~ s~:block:~~) {
$line =~ s~(\n|\r|\t)~~g;
$BLOCKED{$line}++;
$blocked++;
}
}
$SCREEN .= qq~<div class="mt20"><span class="bold">$blocked</span> blocked IP addresses in /etc/security/iptables_rules.txt</div>~;
foreach my $IP (sort keys %BLOCKED) {
if ($BLOCKED{$IP} > 1) {
$SCREEN .= qq~<div class="lightred">$IP seems to be listed more than once</div>~;
}
if ($IP =~ /^(.*?)\.(.*?)\.(.*?)\.(.*?)$/) {
if ($CUSTOM{"$1"} || $CUSTOM{"$1\.$2"} || $CUSTOM{"$1\.$2\.$3"} || $CUSTOM{"$1\.$2\.$3\.$4"} || $BLOCKED{"$1"} || $BLOCKED{"$1\.$2"} || $BLOCKED{"$1\.$2\.$3"}) {
$SCREEN .= qq~<div class="lightred">$IP seems to be redundant</div>~;
}
} else {
if ($IP =~ /^(.*?)\.(.*?)\.(.*?)$/) {
if ($CUSTOM{"$1"} || $CUSTOM{"$1\.$2"} || $CUSTOM{"$1\.$2\.3"} || $BLOCKED{"$1"} || $BLOCKED{"$1\.$2"}) {
$SCREEN .= qq~<div class="lightred">$IP seems to be redundant</div>~;
}
} else {
if ($IP =~ /^(.*?)\.(.*?)$/) {
if ($CUSTOM{"$1"} || $CUSTOM{"$1\.$2"} || $BLOCKED{"$1"}) {
$SCREEN .= qq~<div class="lightred">$IP seems to be redundant</div>~;
}
}
}
}
}
if ($uri eq "optimizeautofix" || $vars{'secmode'} eq "optimizeautofix") {
$SCREEN .= qq~<div class="inline"><a href="/ono/admin/?/info_security/optimize/" class="button_green mt10">reload</a></div>~;
} else {
$SCREEN .= qq~<div class="inline"><a href="/ono/admin/?/info_security/optimizeautofix/" class="button_blue mt10">auto-fix</a></div>~;
}
}
if ($uri eq "apacheaccesslog" || $uri eq "apacheaccesslogevilagents" || $vars{'secmode'} eq "apacheaccesslog") {
my ($LINES,$total,$counter,$MORE);
# foreach my $line (sort ONO::IO->list("var/log/security/iptables_rules_current.txt")) {
# $line =~ s~(\n|\r|\t)~~g;
# @IPTABLES = (@IPTABLES,$line);
# }
if ($ENV{'REQUEST_URI'} =~ m~/apacheaccesslog/(.*?)/~) {
$vars{'query1'} = $1;
$MORE .= qq~<a href="/ono/admin/?/info_security/$1-$1/" class="button_orange ml20">IP '$1' details</a>~;
}
foreach my $opt ("var/log/security/apache_access_log.txt","var/log/security/apache_access_log_previous.txt") {
if ($counter < 200) {
foreach my $line (reverse ONO::IO->list($opt)) {
if ($line !~ m~/ono/admin/\?/info_security~) {
$total++;
if ($counter < 200 && (!$vars{'query1'} || $line =~ /$vars{'query1'}/i) && (!$vars{'query2'} || $line =~ /$vars{'query2'}/i) && (!$vars{'query3'} || $line =~ /$vars{'query3'}/i)) {
if ($uri ne "apacheaccesslogevilagents" || $line =~ m~"-" "-"~ || $line =~ m~(aiohttp|analytic|blex|curl|python|scanner)~i || ONO::IO->devstation) {
$counter++;
$line =~ m~^(.*?) (.*?) (.*)$~;
my $site = $1;
my $ip = $2;
if ($ip =~ /\./ && !$FRIENDLY{$ip}) {
my ($BG,$STYLE);
# if (&check_firewall_block("",$ip,\@IPTABLES)) {
# $BG = " bg_red";
# }
my $ICO = "PAGE";
my $BG = " bg_yellow";
if ($line =~ m~\.(jpg|jpeg|png|gif|ico|svg)( |\?)~) {
$BG = " bg_blue";
$ICO = qq~IMG~;
}
if ($line =~ m~\.(mp3)( |\?)~) {
$BG = " bg_blue";
$ICO = qq~AUDIO~;
}
if ($line =~ m~\.(pdf)( |\?)~) {
$BG = " bg_blue";
$ICO = qq~PDF~;
}
if ($line =~ m~\.(css|js|txt)( |\?)~) {
$BG = " bg_fabric trans50";
$ICO = qq~CSS/JS~;
}
if ($line =~ m~/ono/osr/~) {
$BG = " bg_fabric trans50";
$ICO = qq~OSR~;
}
if ($line =~ /(copyright|privacy|terms|disclaimer|legal)/) {
$BG = " bg_red";
}
my ($url,$url_view);
if ($line =~ m~"(GET|HEAD) (.*?) HTTP/(.*?)"~) {
$url = $2;
$url_view = ": $2";
}
$line =~ s~^(.*?) ~<span class="bold"><a href="http://$site$url" target="_blank">$site$url_view</a></span><br>~;
$LINES .= qq~<tr class="vtop bt bb row$BG" style="$STYLE">
<td><a href="/ono/admin/?/info_security/apacheaccesslog/$ip/" class="col6">$ip</a></td>
<td class="col9">[<a href="https://www.abuseipdb.com/check/$ip" target="_blank" class="col9">?</a>]</td>
<td>$ICO</td>
<td class="p5"><a href="/ono/admin/?/info_security/firewall:block:$ip/"><img class="block16" src="/ono/osr/images/icons/ono/32x32/delete.png" alt=""></a></td>
<td class="lh125">$line</td>
</tr>
~;
}
}
}
}
}
}
}
$SCREEN .= qq~<$vars{'form'}>
<input type="hidden" name="secmode" value="apacheaccesslog">
<div class="box_paper mb10">
<table class="wide_table">
<tr>
<td class="bold">$counter</td>
<td>of</td>
<td class="bold">$total</td>
<td>lines</td>
<td class="w100">$MORE</td>
<td><input type="text" name="query1" value="$vars{'query1'}" style="width:100px"></td>
<td><input type="text" name="query2" value="$vars{'query2'}" style="width:100px"></td>
<td><input type="text" name="query3" value="$vars{'query3'}" style="width:100px"></td>
<td>$BLK{'submit_search'}</td>
</tr>
</table>
</div>
</form>
<div class="box_paper"><table class="wide_table bt bb">$LINES</table></div>~;
}
if ($uri eq "firewall") {
my @RULES;
foreach my $line (sort ONO::IO->list("var/log/security/iptables_rules_current.txt")) {
$line =~ s~(\n|\r|\t)~~g;
my $ip = $line;
$ip =~ s~/(.*)$~~;
$ip =~ s~\.0$~~;
$ip =~ s~\.0$~~;
$ip =~ s~\.0$~~;
if ($line =~ s~/~ / ~g) {
$line =~ s~\.0~<span class="col9">\.0</span>~g;
$line = qq~<div class="bold">$line</div>~;
} else {
$line = qq~<div class="ml20">$line <span class="small col9">[<a href="https://www.abuseipdb.com/check/$line" target="_blank" class="col9">?</a>]</span></div>~;
}
$RULES[0] .= qq~ <tr class="bt bb row">
<td class="pad10_2 w100">$line</td>
<td class="pad10_2">
<a href="/ono/admin/?/info_security/firewall:flush:$ip/">
<img class="block24" src="/ono/osr/images/icons/ono/32x32/delete_inv.png" alt="">
</a>
</td>
</tr>
~;
}
my (%TOP16,%TOP24);
foreach my $opt ("1:iptables_rules","2:iptables_rules_custom") {
my @op = split(/:/,$opt);
foreach my $line (sort ONO::IO->list("etc/security/$op[1].txt")) {
my @lp = split(/:/,$line);
if ($lp[0] && $lp[1]) {
my $ip = $lp[0];
my $status = $lp[1];
my $BG;
if ($status eq "trust") {
$BG = " bg_green";
}
if ($status eq "warn") {
$BG = " bg_yellow";
}
if ($status eq "block") {
$BG = " bg_red";
}
my $BUT;
if ($op[0] == 1) {
$BUT = qq~<a href="/ono/admin/?/info_security/firewall:flush:$ip/">
<img class="block24" src="/ono/osr/images/icons/ono/32x32/delete_inv.png" alt="">
</a>
~;
}
$RULES[$op[0]] .= qq~ <tr class="bt bb row$BG">
<td class="pad10_2 w100">$ip</td>
<td class="pad10_2">$BUT</td>
</tr>
~;
if ($status eq "block" && $ip =~ /^(.*?)\.(.*?)\.(.*?)\.(.*?)$/) {
$TOP24{"$1.$2.$3"}++;
$TOP16{"$1.$2"}++;
} else {
if ($status eq "block" && $ip =~ /^(.*?)\.(.*?)\.(.*?)$/) {
$TOP16{"$1.$2"}++;
}
}
}
}
}
my ($limit24,$limit16) = (2,7);
if ($vars{'limit24'}) {
$limit24 = $vars{'limit24'};
}
if ($vars{'limit16'}) {
$limit16 = $vars{'limit16'};
}
foreach my $TOP (reverse sort { $TOP24{$a} <=> $TOP24{$b} } keys %TOP24) {
if ($TOP24{$TOP} > $limit24) {
$RULES[3] .= qq~ <tr>
<td class="w100">$TOP <span class="small"><a href="https://www.abuseipdb.com/check/$TOP.1" class="col9" target="_blank">[?]</a></span></td>
<td class="bold tar">$TOP24{$TOP}</td>
<td><a href="/ono/admin/?/info_security/firewall:block:$TOP/"><img class="block16 ml5" src="/ono/osr/images/icons/ono/32x32/delete.png" alt=""></a></td>
</tr>
~;
}
}
foreach my $TOP (reverse sort { $TOP16{$a} <=> $TOP16{$b} } keys %TOP16) {
if ($TOP16{$TOP} > $limit16) {
$RULES[4] .= qq~ <tr>
<td class="w100">$TOP <span class="small"><a href="https://www.abuseipdb.com/check/$TOP.1.1" class="col9" target="_blank">[?]</a></span></td>
<td class="bold tar">$TOP16{$TOP}</td>
<td><a href="/ono/admin/?/info_security/firewall:block:$TOP/"><img class="block16 ml5" src="/ono/osr/images/icons/ono/32x32/delete.png" alt=""></a></td>
</tr>
~;
}
}
$SCREEN .= qq~<div class="inline w100">
<div class="w25 fl w100_800 fn_800">
<div class="p5">
<div class="box_paper">
<h3>Current Firewall List</h3>
<h4>iptables command</h4>
<table class="wide_table bt bb">
$RULES[0]
</table>
</div>
</div>
</div>
<div class="w25 fl w100_800 fn_800">
<div class="p5">
<div class="box_paper">
<h3>Current Rules</h3>
<h4>/etc/security/iptables_rules.txt</h4>
<table class="wide_table bt bb">
$RULES[1]
</table>
</div>
</div>
</div>
<div class="w25 fl w100_800 fn_800">
<div class="p5">
<div class="box_paper">
<h3>Current Custom Rules</h3>
<h4>/etc/security/iptables_rules_custom.txt</h4>
<table class="wide_table bt bb">
$RULES[2]
</table>
</div>
</div>
</div>
<div class="w25 fl w100_800 fn_800">
<div class="p5">
<div class="box_paper mb10">
<a href="/ono/admin/?/info_security/firewall/&limit24=2" class="button_yellow fr">limit:2</a>
<h3>Top /24 Ranges</h3>
<h4>calculated</h4>
<table class="wide_table bt bb">
$RULES[3]
</table>
</div>
<div class="box_paper mb10">
<a href="/ono/admin/?/info_security/firewall/&limit16=4" class="button_yellow fr">limit:4</a>
<h3>Top /16 Ranges</h3>
<h4>calculated</h4>
<table class="wide_table bt bb">
$RULES[4]
</table>
</div>
</div>
</div>
</div>
~;
}
}
} else {
my ($LIST_ref) = ONO::ToolBox::Security->apache_log_ip_analytics(\%RULES,\%vars,\%CUSTOM);
my @LIST = @$LIST_ref;
foreach my $opt (8,16,24,32) {
$LIST[$opt] = qq~<div class="w25 fl w100_1000 fn_1000">
<div class="p5">
<div class="box_paper">
<table class="wide_table bt bb">
<tr class="bt bb">
<td class="w100 bold col6">IP/range</td>
<td class="tar bold col6">hits</td>
<td></td>
<td></td>
<td></td>
</tr>
$LIST[$opt]
</table>
</div>
</div>
</div>
~;
}
$SCREEN .= qq~<div class="pad5_2">
<div class="box_fabric mb5">
<div class="inline w100">
<div class="fl">
<table class="default_table">
<tr>
<td>
<a href="/ono/admin/?/info_security/firewall/" class="button_orange">firewall</a>
<a href="/ono/admin/?/info_security/optimize/" class="button_yellow ml20">optimize</a>
<a href="/ono/admin/?/info_security/" class="button button_left ml20">all</a>
<a href="/ono/admin/?/info_security/&filter=undef" class="button button_dark button_middle">undef</a>
<a href="/ono/admin/?/info_security/&filter=trust" class="button button_green button_middle">trusted</a>
<a href="/ono/admin/?/info_security/&filter=warn" class="button button_yellow button_middle">warnings</a>
<a href="/ono/admin/?/info_security/&filter=block" class="button button_red button_right">blocked</a>
<a href="/ono/admin/?/info_security/apacheaccesslog/" class="button_green button_left ml20">access.log</a>
<a href="/ono/admin/?/info_security/images/" class="button_yellow button_middle">img</a>
<a href="/ono/admin/?/info_security/apacheaccesslogevilagents/" class="button_orange button_middle">evil agents</a>
<a href="/ono/admin/?/info_security/auth/" class="button_red button_right">auth</a>
</td>
</tr>
</table>
</div>
<div class="fr">
<$vars{'form'}>
<table class="default_table">
<tr>
<td class="p0"><input type="text" name="firewall_block_ip" value="" class="query" style="width:200px" maxlength="16" placeholder="0.0.0.0"></td>
<td class="p0"><input type="submit" name="firewall_block_ip_button" value="block" class="button_red button_right"></td>
</tr>
</table>
</form>
</div>
</div>
</div>
</div>
<div class="inline w100">
$LIST[8]
$LIST[16]
$LIST[24]
$LIST[32]
</div>
~;
}
# $RIGHT .= qq~SEC2~;
return ($TITLE,$SUBTITLE,$SCREEN,$LEFT,$RIGHT,$TOOLS);
}
sub check_firewall_block {
my (
$self,
$IP,
$IPTABLES_ref,
) = @_;
#: Check firewall block status
my $res = 0;
my @ips = split(/\./,$IP);
my $ip_length = @ips;
my @IPTABLES = @$IPTABLES_ref;
foreach my $test (@IPTABLES) {
my @tp = split(/\//,$test);
if ($test eq $IP || ($tp[1] eq "32" && $tp[0] eq $IP)) {
$res = 1;
}
if ($ip_length == 3) {
if ($tp[1] eq "24" && $tp[0] eq "$IP.0") {
$res = 1;
}
if ($tp[1] eq "16" && $tp[0] eq "$IP.0") {
$res = 1;
}
if ($tp[1] eq "8" && $tp[0] eq "$IP.0") {
$res = 1;
}
}
if ($ip_length == 2) {
if ($tp[1] eq "16" && $tp[0] eq "$IP.0.0") {
$res = 1;
}
if ($tp[1] eq "8" && $tp[0] eq "$IP.0.0") {
$res = 1;
}
}
if ($ip_length == 1) {
if ($tp[1] eq "8" && $tp[0] eq "$IP.0.0.0") {
$res = 1;
}
}
}
return $res;
}
sub protected_range {
#: Protect some ranges known to be used by friendly bots from being blocked
#: by mistake.
my $protected = 0;
if ($_[1] =~ m~^(66\.249)$~) {
$protected++;
}
if ($_[1] =~ m~^(13\.66|40\.77|157\.55)$~) {
$protected++;
}
return $protected;
}
###############################################################################
# end of script
###############################################################################
1;
__END__