Merge branch 'temp-stevee-ipblocklist-final' into next

This commit is contained in:
Peter Müller
2022-07-10 08:20:15 +00:00
29 changed files with 2114 additions and 2 deletions

View File

@@ -41,6 +41,7 @@ var/ipfire/ethernet/aliases
var/ipfire/ethernet/wireless
var/ipfire/firewall
var/ipfire/fwhosts
var/ipfire/ipblocklist/modified
var/ipfire/main/*
var/ipfire/ovpn
var/ipfire/ovpn/collectd.vpn
@@ -54,6 +55,7 @@ var/ipfire/*/settings
var/ipfire/time/
var/ipfire/urlfilter
var/ipfire/vpn
var/lib/ipblocklist
var/lib/suricata
var/log/ip-acct/*
var/log/rrd/*

View File

@@ -0,0 +1,386 @@
#!/usr/bin/perl -w
###############################################################################
# #
# IPFire.org - A linux based firewall #
# Copyright (C) 2007-2022 IPFire Team <info@ipfire.org> #
# #
# 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 2 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 <http://www.gnu.org/licenses/>. #
# #
###############################################################################
package IPblocklist;
require '/var/ipfire/general-functions.pl';
require "${General::swroot}/ipblocklist/sources";
# The directory where all ipblocklist related files and settings are stored.
our $settings_dir = "/var/ipfire/ipblocklist";
# Main settings file.
our $settings_file = "$settings_dir/settings";
# The file which keeps the time, when a blocklist last has been modified.
our $modified_file = "$settings_dir/modified";
# Location where the blocklists in ipset compatible format are stored.
our $blocklist_dir = "/var/lib/ipblocklist";
# File extension of the blocklist files.
my $blocklist_file_extension = ".conf";
# Hash which calls the correct parser functions.
my %parsers = (
'ip-or-net-list' => \&parse_ip_or_net_list,
'dshield' => \&parse_dshield
);
#
## Function to get all available blocklists.
#
sub get_blocklists () {
my @blocklists;
# Loop through the hash of blocklists.
foreach my $blocklist ( keys %IPblocklist::List::sources ) {
# Add the list to the array.
push(@blocklists, $blocklist);
}
# Sort and return the array.
return sort(@blocklists);
}
#
## Tiny function to get the full path and name of a given blocklist.
#
sub get_ipset_db_file($) {
my ($set) = @_;
# Generate the
my $file = "$blocklist_dir/$set$blocklist_file_extension";
# Return the file name.
return $file;
}
#
## The main download_and_create blocklist function.
##
## Uses LWP to download a given blocklist. The If-Modified-Since header is
## specified in the request so that only updated lists are downloaded (providing
## that the server supports this functionality).
##
## Once downloaded the list gets parsed, converted and stored in an ipset compatible
## format.
##
## Parameters:
## list The name of the blocklist
##
## Returns:
## nothing - On success
## not_modified - In case the servers responds with "Not modified" (304)
## dl_error - If the requested blocklist could not be downloaded.
## empty_list - The downloaded blocklist is empty, or the parser was not able to parse
## it correctly.
#
sub download_and_create_blocklist($) {
my ($list) = @_;
# Check if the given blockist is known and data available.
unless($IPblocklist::List::sources{$list}) {
# No valid data for this blocklist - exit and return "1".
return 1;
}
# The allowed maximum download size in bytes.
my $max_dl_bytes = 10_485_760;
# The amount of download attempts before giving up and
# logging an error.
my $max_dl_attempts = 5;
# Read proxysettings.
my %proxysettings=();
&General::readhash("${General::swroot}/proxy/settings", \%proxysettings);
# Load required perl module to handle the download.
use LWP::UserAgent;
# Create a user agent for downloading the blacklist
# Limit the download size for safety
my $ua = LWP::UserAgent->new (
ssl_opts => {
SSL_ca_file => '/etc/ssl/cert.pem',
verify_hostname => 1,
},
max_size => $max_dl_bytes,
);
# Set timeout to 10 seconds.
$ua->timeout(10);
# Check if an upstream proxy is configured.
if ($proxysettings{'UPSTREAM_PROXY'}) {
my $proxy_url;
$proxy_url = "http://";
# Check if the proxy requires authentication.
if (($proxysettings{'UPSTREAM_USER'}) && ($proxysettings{'UPSTREAM_PASSWORD'})) {
$proxy_url .= "$proxysettings{'UPSTREAM_USER'}\:$proxysettings{'UPSTREAM_PASSWORD'}\@";
}
# Add proxy server address and port.
$proxy_url .= $proxysettings{'UPSTREAM_PROXY'};
# Setup proxy settings.
$ua->proxy(['http', 'https'], $proxy_url);
}
# Gather the details, when a list got modified last time.
my %modified = ();
# Read-in data if the file exists.
&General::readhash($modified_file, \%modified ) if (-e $modified_file);
# Get the last modified time for this list.
my $last_modified = gmtime($modified{$list} || 0);
my $dl_attempt = 1;
my $response;
# Download and rety on failure loop.
while ($dl_attempt <= $max_dl_attempts) {
# Try to determine if there is a newer blocklist since last time and grab it.
$response = $ua->get($IPblocklist::List::sources{$list}{'url'}, 'If-Modified-Since' => $last_modified );
# Check if the download attempt was successfull.
if ($response->is_success) {
# We successfully grabbed the list - no more retries needed, break the loop.
# Further process the script code.
last;
# Exit, if the server responds with "Not modified (304).
} elsif ($response->code == 304) {
# Exit and return "not modified".
return "not_modified";
# Exit and log an erro
} elsif ($dl_attempt eq $max_dl_attempts) {
# Exit and return "dl_error".
return "dl_error";
}
# Increase download attempt counter.
$dl_attempt++;
}
# Update the timestamp for the new or modified list.
if($response->last_modified) {
$modified{$list} = $response->last_modified;
} else {
$modified{$list} = time();
}
# Write-back the modified timestamps.
&General::writehash($modified_file, \%modified);
# Parse and loop through the downloaded list.
my @blocklist = ();
# Get the responsible parser for the current list.
my $parser = $parsers{$IPblocklist::List::sources{$list}{'parser'}};
# Loop through the grabbed raw list.
foreach my $line (split /[\r\n]+/, $response->content) {
# Remove newlines.
chomp $line;
# Call the parser and obtain the addess or network.
my $address = &$parser($line);
# Skip the line if it does not contain an address.
next unless ($address and $address =~ m/\d+\.\d+\.\d+\.\d+/);
# Check if we got a single address.
if ($address =~ m|/32|) {
# Add /32 as prefix.
$address =~ s|/32||;
}
# Push the address/network to the blocklist array.
push(@blocklist, $address);
}
# Check if the content could be parsed correctly and the blocklist
# contains at least one item.
unless(@blocklist) {
# No entries - exit and return "empty_list".
return "empty_list";
}
# Get amount of entries in the blocklist array.
my $list_entries = scalar(@blocklist);
# Optain the filename for this blocklist to save.
my $file = &get_ipset_db_file($list);
# Open the file for writing.
open(FILE, ">", "$file") or die "Could not write to $file. $!\n";
# Write file header.
print FILE "#Autogenerated file. Any custom changes will be overwritten!\n\n";
# Calculate the hashsize for better list performance.
my $hashsize = &_calculate_hashsize($list_entries);
# Simply set the limit of list elements to the double of current list elements.
my $maxelem = $list_entries *2;
# Add "v4" suffix to the list name.
$list = "$list" . "v4";
# Write line to create the set.
#
# We safely can use hash:net as type because it supports single addresses and networks.
print FILE "create $list hash:net family inet hashsize $hashsize maxelem $maxelem -exist\n";
# Write line to flush the set itself during loading.
print FILE "flush $list\n";
# Loop through the array which contains the blocklist.
foreach my $entry (@blocklist) {
# Add the entry to the list.
print FILE "add $list $entry\n";
}
# Close the file handle.
close(FILE);
# Finished.
return;
}
#
## sub parse_ip_or_net_list( line )
##
## Parses an input line, looking for lines starting with an IP Address or
### Network specification.
##
## Parameters:
## line The line to parse
##
## Returns:
## Either an IP Address or a null string
#
sub parse_ip_or_net_list( $ ) {
my ($line) = @_;
# Grab the IP address or network.
$line =~ m|^(\d+\.\d+\.\d+\.\d+(?:/\d+)?)|;
# Return the grabbed address.
return $1;
}
#
## sub parse_dshield( line )
##
## Parses an input line removing comments.
##
## The format is:
## Start Addrs End Addrs Netmask Nb Attacks Network Name Country email
## We're only interested in the start address and netmask.
##
## Parameters:
## line The line to parse
##
## Returns:
## Either and IP Address or a null string
#
sub parse_dshield( $ ) {
my ($line) = @_;
# Skip coments.
return "" if ($line =~ m/^\s*#/);
$line =~ s/#.*$//;
# |Start addrs | |End Addrs | |Mask
$line =~ m|(\d+\.\d+\.\d+\.\d+(?:/\d+)?)\s+\d+\.\d+\.\d+\.\d+(?:/\d+)?\s+(\d+)|;
# Return nothing if no start address could be grabbed.
return unless ($1);
# Add /32 as prefix for single addresses and return it.
return "$1/32" unless ($2);
# Return the obtained network.
return "$1/$2";
}
#
## Helper function to proper calculate the hashsize.
#
sub _calculate_hashsize($) {
my ($list_entries) = @_;
my $hashsize = 1;
$hashsize <<= 1 while ($hashsize < $list_entries);
# Return the calculated hashsize.
return $hashsize;
}
#
## sub get_holdoff_rate(list)
##
## This function is used to get the holdoff rate in seconds for a desired provider,
## based on the configured rate limit in minutes (m), hours (h) or days (d) in the
## blacklist sources settings file.
##
#
sub get_holdoff_rate($) {
my ($list) = @_;
# Grab the configured lookup rate for the given list.
my $rate = $IPblocklist::List::sources{$list}{'rate'};
# Split the grabbed rate into value and unit.
my ($value, $unit) = (uc $rate) =~ m/(\d+)([DHM]?)/;
# Days
if ($unit eq 'D') {
$value *= 60 * 60 * 24;
# Minutes
} elsif ($unit eq 'M') {
$value *= 60;
# Everything else - assume hours.
} else {
$value *= 60 * 60;
}
# Sanity check - limit to range 5 min .. 1 week
# d h m s
$value = 5 * 60 if ($value < 5 * 60);
$value = 7 * 24 * 60 * 60 if ($value > 7 * 24 * 60 * 60);
return $value;
}
1;

View File

@@ -65,6 +65,9 @@ HOME=/
# Perform a surciata rules update every 12 hours.
@ 12h [ -f "/var/ipfire/red/active" ] && /usr/local/bin/update-ids-ruleset >/dev/null 2>&1
# Update Lists for IP-based blocking every 15 minutes.
@ 15 [ -f "/var/ipfire/red/active" ] && /usr/local/bin/update-ipblocklists >/dev/null 2>&1
# Retry sending spooled mails regularly
%hourly * /usr/sbin/dma -q

View File

@@ -26,6 +26,7 @@ require '/var/ipfire/general-functions.pl';
require "${General::swroot}/lang.pl";
require "/usr/lib/firewall/firewall-lib.pl";
require "${General::swroot}/location-functions.pl";
require "${General::swroot}/ipblocklist-functions.pl";
# Set to one to enable debugging mode.
my $DEBUG = 0;
@@ -73,6 +74,10 @@ my %confignatfw=();
my %locationsettings = (
"LOCATIONBLOCK_ENABLED" => "off"
);
my %blocklistsettings= (
"ENABLE" => "off",
);
my %ipset_loaded_sets = ();
my @ipset_used_sets = ();
@@ -82,6 +87,7 @@ my $configoutgoing = "${General::swroot}/firewall/outgoing";
my $locationfile = "${General::swroot}/firewall/locationblock";
my $configgrp = "${General::swroot}/fwhosts/customgroups";
my $netsettings = "${General::swroot}/ethernet/settings";
my $blocklistfile = "${General::swroot}/ipblocklist/settings";
&General::readhash("${General::swroot}/firewall/settings", \%fwdfwsettings);
&General::readhash("${General::swroot}/optionsfw/settings", \%fwoptions);
@@ -97,9 +103,18 @@ if (-e "$locationfile") {
&General::readhash("$locationfile", \%locationsettings);
}
# Check if the ipblocklist settings file exits.
if (-e "$blocklistfile") {
# Read-in settings file.
&General::readhash("$blocklistfile", \%blocklistsettings);
}
# Get all available locations.
my @locations = &Location::Functions::get_locations();
# Get all supported blocklists.
my @blocklists = &IPblocklist::get_blocklists();
# Name or the RED interface.
my $RED_DEV = &General::get_red_interface();
@@ -144,6 +159,9 @@ sub main {
# Load rules to block hostile networks.
&drop_hostile_networks();
# Handle ipblocklist.
&ipblocklist();
# Reload firewall policy.
run("/usr/sbin/firewall-policy");
@@ -708,6 +726,64 @@ sub drop_hostile_networks () {
run("$IPTABLES -A HOSTILE -o $RED_DEV -m set --match-set $HOSTILE_CCODE dst -j HOSTILE_DROP");
}
sub ipblocklist () {
# Flush the ipblocklist chains.
run("$IPTABLES -F BLOCKLISTIN");
run("$IPTABLES -F BLOCKLISTOUT");
# Check if the blocklist feature is enabled.
if($blocklistsettings{'ENABLE'} eq "on") {
# Loop through the array of private networks.
foreach my $private_network (@PRIVATE_NETWORKS) {
# Create firewall rules to never block private networks.
run("$IPTABLES -A BLOCKLISTIN -p ALL -i $RED_DEV -s $private_network -j RETURN");
run("$IPTABLES -A BLOCKLISTOUT -p ALL -o $RED_DEV -d $private_network -j RETURN");
}
}
# Loop through the array of blocklists.
foreach my $blocklist (@blocklists) {
# Check if the blocklist feature and the current processed blocklist is enabled.
if(($blocklistsettings{'ENABLE'} eq "on") && ($blocklistsettings{$blocklist}) && ($blocklistsettings{$blocklist} eq "on")) {
# Call function to load the blocklist.
&ipset_restore($blocklist);
# Call function to check if the corresponding iptables drop chain already has been created.
if(&firewall_chain_exists("${blocklist}_DROP")) {
# Create iptables chain.
run("$IPTABLES -N ${blocklist}_DROP");
} else {
# Flush the chain.
run("$IPTABLES -F ${blocklist}_DROP");
}
# Check if logging is enabled.
if($blocklistsettings{'LOGGING'} eq "on") {
# Create logging rule.
run("$IPTABLES -A ${blocklist}_DROP -j LOG -m limit --limit 10/second --log-prefix \"BLKLST_$blocklist\" ");
}
# Create Drop rule.
run("$IPTABLES -A ${blocklist}_DROP -j DROP");
# Add the rules to check against the set
run("$IPTABLES -A BLOCKLISTIN -p ALL -i $RED_DEV -m set --match-set $blocklist src -j ${blocklist}_DROP");
run("$IPTABLES -A BLOCKLISTOUT -p ALL -o $RED_DEV -m set --match-set $blocklist dst -j ${blocklist}_DROP");
# IP blocklist or the blocklist is disabled.
} else {
# Check if the blocklist related iptables drop chain exits.
unless(&firewall_chain_exists("${blocklist}_DROP")) {
# Flush the chain.
run("$IPTABLES -F ${blocklist}_DROP");
# Drop the chain.
run("$IPTABLES -X ${blocklist}_DROP");
}
}
}
}
sub get_protocols {
my $hash = shift;
my $key = shift;
@@ -921,6 +997,14 @@ sub firewall_is_in_subnet {
return 0;
}
sub firewall_chain_exists ($) {
my ($chain) = @_;
my $ret = &General::system("iptables", "--wait", "-n", "-L", "$chain");
return $ret;
}
sub ipset_get_sets () {
my @sets;
@@ -986,6 +1070,26 @@ sub ipset_restore ($) {
# If the set is not loaded, we have to rename it to proper use it.
run("$IPSET rename $loc_set $set");
}
# Check if the given set name is a blocklist.
} elsif ($set ~~ @blocklists) {
# IPblocklist sets contains v4 as setname extension.
my $set_name = "$set" . "v4";
# Get the database file for the given blocklist.
my $db_file = &IPblocklist::get_ipset_db_file($set);
# Call function to restore/load the set.
&ipset_call_restore($db_file);
# Check if the set is already loaded (has been used before).
if ($set ~~ @ipset_used_sets) {
# Swap the sets.
run("$IPSET swap $set_name $set");
} else {
# Rename the set to proper use it.
run("$IPSET rename $set_name $set");
}
}
# Store the restored set to the hash to prevent from loading it again.

140
config/ipblocklist/sources Normal file
View File

@@ -0,0 +1,140 @@
############################################################################
# #
# IP Address blocklists for IPFire #
# #
# This file contains a list of blocklist sources that will replace the one #
# internal to the updated if it is found at /var/ipfire/blocklist/sources. #
# The intention is to provide a common source of information for both the #
# updater and WUI. #
# #
# The chains created in the packet filter will be named by the top level #
# key and this will also be used in the log message to identify the reason #
# for the dropped packet. #
# #
# The fields are: #
# #
# name The blocklist's full name #
# url URL of the file containing the list #
# info URL giving information about the source #
# parser The parser function used to extract IP addresses from the #
# downloaded list #
# rate Minimum period between checks for updates. Can be specified in #
# days (d), hours (h) or minutes (m) #
# category Used for documentation on the WUI. Can be one of the following #
# 'application' Potentially unwanted applications #
# 'attacker' Generic source of malicious packets #
# 'c and c' Malware Command and Control source #
# 'composite' Composite of other lists #
# 'invalid' Invalid addresses on the public internet #
# 'scanner' Port scanner that is not initself malicious #
# disable Name of another list to disable if this one is enabled. Used #
# when the other list is a subset of this one. #
# #
# The info and category fields are purely for documentation. #
# #
############################################################################
package IPblocklist::List;
our %sources = ( 'EMERGING_FWRULE' => { 'name' => 'Emerging Threats Blocklist',
'url' => 'https://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt',
'info' => 'https://doc.emergingthreats.net/bin/view/Main/EmergingFirewallRules',
'parser' => 'ip-or-net-list',
'rate' => '1h',
'category' => 'composite',
'disable' => ['FEODO_RECOMMENDED', 'FEODO_IP', 'FEODO_AGGRESIVE', 'SPAMHAUS_DROP', 'DSHIELD'] },
'EMERGING_COMPROMISED' => { 'name' => 'Emerging Threats Compromised IPs',
'url' => 'https://rules.emergingthreats.net/blockrules/compromised-ips.txt',
'info' => 'https://doc.emergingthreats.net/bin/view/Main/CompromisedHost',
'parser' => 'ip-or-net-list',
'rate' => '1h',
'category' => 'attacker' },
'SPAMHAUS_DROP' => { 'name' => "Spamhaus Don't Route or Peer List",
'url' => 'https://www.spamhaus.org/drop/drop.txt',
'info' => 'https://www.spamhaus.org/drop/',
'parser' => 'ip-or-net-list',
'rate' => '12h',
'category' => 'reputation' },
'SPAMHAUS_EDROP' => { 'name' => "Spamhaus Extended Don't Route or Peer List",
'url' => 'https://www.spamhaus.org/drop/edrop.txt',
'info' => 'https://www.spamhaus.org/drop/',
'parser' => 'ip-or-net-list',
'rate' => '1h',
'category' => 'reputation' },
'DSHIELD' => { 'name' => 'Dshield.org Recommended Block List',
'url' => 'https://www.dshield.org/block.txt',
'info' => 'https://dshield.org/',
'parser' => 'dshield',
'rate' => '1h',
'category' => 'attacker' },
'FEODO_RECOMMENDED'=> {'name' => 'Feodo Trojan IP Blocklist (Recommended)',
'url' => 'https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt',
'info' => 'https://feodotracker.abuse.ch/blocklist',
'parser' => 'ip-or-net-list',
'rate' => '5m',
'category' => 'c and c' },
'FEODO_IP' => { 'name' => 'Feodo Trojan IP Blocklist',
'url' => 'https://feodotracker.abuse.ch/downloads/ipblocklist.txt',
'info' => 'https://feodotracker.abuse.ch/blocklist',
'parser' => 'ip-or-net-list',
'rate' => '5m',
'category' => 'c and c',
'disable' => 'FEODO_RECOMMENDED' },
'FEODO_AGGRESIVE' => { 'name' => 'Feodo Trojan IP Blocklist (Aggresive)',
'url' => 'https://feodotracker.abuse.ch/downloads/ipblocklist_aggressive.txt',
'info' => 'https://feodotracker.abuse.ch/blocklist',
'parser' => 'ip-or-net-list',
'rate' => '5m',
'category' => 'c and c',
'disable' => ['FEODO_IP', 'FEODO_RECOMMENDED'] },
'CIARMY' => { 'name' => 'The CINS Army List',
'url' => 'https://cinsscore.com/list/ci-badguys.txt',
'info' => 'https://cinsscore.com/#list',
'parser' => 'ip-or-net-list',
'rate' => '15m',
'category' => 'reputation' },
'TOR_ALL' => { 'name' => 'Known TOR Nodes',
'url' => 'https://www.dan.me.uk/torlist',
'info' => 'https://www.dan.me.uk/tornodes',
'parser' => 'ip-or-net-list',
'rate' => '1h',
'category' => 'application',
'disable' => 'TOR_EXIT' },
'TOR_EXIT' => { 'name' => 'Known TOR Exit Nodes',
'url' => 'https://www.dan.me.uk/torlist/?exit',
'info' => 'https://www.dan.me.uk/tornodes',
'parser' => 'ip-or-net-list',,
'rate' => '1h',
'category' => 'application' },
'ALIENVAULT' => { 'name' => 'AlienVault IP Reputation database',
'url' => 'https://reputation.alienvault.com/reputation.generic',
'info' => 'https://www.alienvault.com/resource-center/videos/what-is-ip-domain-reputation',
'parser' => 'ip-or-net-list',
'rate' => '1h',
'category' => 'reputation' },
'BOGON' => { 'name' => 'Bogus address list (Martian)',
'url' => 'https://www.team-cymru.org/Services/Bogons/bogon-bn-agg.txt',
'info' => 'https://www.team-cymru.com/bogon-reference.html',
'parser' => 'ip-or-net-list',
'rate' => '1d',
'category' => 'invalid' },
'BOGON_FULL' => { 'name' => 'Full Bogus Address List',
'url' => 'https://www.team-cymru.org/Services/Bogons/fullbogons-ipv4.txt',
'info' => 'https://www.team-cymru.com/bogon-reference.html',
'parser' => 'ip-or-net-list',
'rate' => '4h',
'category' => 'invalid',
'disable' => 'BOGON' },
'SHODAN' => { 'name' => 'ISC Shodan scanner blocklist',
'url' => 'https://isc.sans.edu/api/threatlist/shodan?tab',
'info' => 'https://isc.sans.edu',
'parser' => 'ip-or-net-list',
'rate' => '1d',
'category' => 'scanner' },
'BLOCKLIST_DE' => { 'name' => 'Blocklist.de all attacks list',
'url' => 'https://lists.blocklist.de/lists/all.txt',
'info' => 'https://www.blocklist.de',
'parser' => 'ip-or-net-list',
'rate' => '30m',
'category' => 'attacker' }
);

91
config/logwatch/ipblocklist Executable file
View File

@@ -0,0 +1,91 @@
###########################################################################
# ipblocklist script for Logwatch
# Analyzes the IPFire IP Blocklist log
#
#########################################################################
########################################################
## Copyright (c) 2008 Lars Skjærlund
## Covered under the included MIT/X-Consortium License:
## http://www.opensource.org/licenses/mit-license.php
## All modifications and contributions by other persons to
## this script are assumed to have been donated to the
## Logwatch project and thus assume the above copyright
## and licensing terms. If you want to make contributions
## under your own copyright or a different license this
## must be explicitly stated in the contribution and the
## Logwatch project reserves the right to not accept such
## contributions. If you have made significant
## contributions to this script and want to claim
## copyright please contact logwatch-devel@lists.sourceforge.net.
#########################################################
#########################################################################
# Files - all shown with default paths:
#
# /usr/share/logwatch/default.conf/logfiles/messages.conf
# /usr/share/logwatch/dist.conf/services/blocklist.conf
# /usr/share/logwatch/scripts/services/ipblocklist (this file)
#
# ... and of course
#
# /var/log/messages
#########################################################################
use Logwatch ':dates';
my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'};
my $SearchDate;
my %Updates;
my %Errors;
$SearchDate = TimeFilter("%b %e");
while (defined(my $ThisLine = <STDIN>))
{
next unless ($ThisLine =~ m/^\s*\w+\s+\w+\s+(..:..:..) .* ipblocklist: (.*)/);
my $text = $2;
if ($text =~ m/Successfully updated (\w+) blocklist/)
{
$Updates{$1}{updates}++;
}
elsif ($text !~ m/Skipping (\w+) blocklist - Too frequent update attempts!/ and
$text !~ m/Skipping (\w+) blocklist - It has not been modified!/ )
{
$Errors{$text}++;
}
}
#####################################################################
if (keys %Updates)
{
print "\nThe following block lists were updated:\n";
foreach my $Lists (sort keys %Updates)
{
print " $Lists: $Updates{$Lists}{updates} Time(s)\n";
}
}
if (keys %Errors)
{
print "\nThe following errors were detected:\n";
foreach my $Text (keys %Errors)
{
print " $Text: $Errors{$Text} Time(s)\n";
}
}
exit(0);
# vi: shiftwidth=3 tabstop=3 syntax=perl et
# Local Variables:
# mode: perl
# perl-indent-level: 3
# indent-tabs-mode: nil
# End:

View File

@@ -0,0 +1,34 @@
#########################################################################
# ids-update script for Logwatch
# Analyzes the IPFire IP Blocklist update log
#
# Version: 1.0.0
# Initial release
#
#########################################################################
#########################################################################
# This script is subject to the same copyright as Logwatch itself
#########################################################################
#########################################################################
# Files - all shown with default paths:
#
# /usr/share/logwatch/default.conf/logfiles/messages.conf
# /usr/share/logwatch/dist.conf/services/blocklist.conf (this file)
# /usr/share/logwatch/scripts/services/blocklist
#
# ... and of course
#
# /var/log/messages
#########################################################################
Title = "IP Blocklist"
# Which logfile group...
LogFile = messages
*applystddate
# vi: shiftwidth=3 tabstop=3 et

View File

@@ -21,6 +21,11 @@
'title' => "$Lang::tr{'intrusion detection system'}",
'enabled' => 1,
};
$subfirewall->{'50.ipblocklist'} = {'caption' => $Lang::tr{'ipblocklist'},
'uri' => '/cgi-bin/ipblocklist.cgi',
'title' => "$Lang::tr{'ipblocklist'}",
'enabled' => 1,
};
$subfirewall->{'60.locationblock'} = {
'caption' => $Lang::tr{'locationblock'},
'uri' => '/cgi-bin/location-block.cgi',

View File

@@ -43,6 +43,11 @@
'title' => "$Lang::tr{'ids logs'}",
'enabled' => 1
};
$sublogs->{'53.ipblocklist'} = {'caption' => $Lang::tr{'ipblocklist logs'},
'uri' => '/cgi-bin/logs.cgi/ipblocklists.dat',
'title' => "$Lang::tr{'ipblocklist logs'}",
'enabled' => 1
};
$sublogs->{'55.ovpnclients'} = {
'caption' => $Lang::tr{'ovpn rw connection log'},
'uri' => '/cgi-bin/logs.cgi/ovpnclients.dat',

View File

@@ -106,6 +106,7 @@ usr/local/bin/settime
usr/local/bin/timecheck
usr/local/bin/timezone-transition
usr/local/bin/update-ids-ruleset
usr/local/bin/update-ipblocklists
usr/local/bin/update-lang-cache
usr/local/bin/update-location-database
#usr/local/include
@@ -154,6 +155,7 @@ var/cache/ldconfig
var/cache/ldconfig/aux-cache
var/empty
#var/lib
var/lib/ipblocklist
#var/lib/misc
#var/local
var/lock

View File

@@ -104,6 +104,7 @@ usr/local/bin/settime
usr/local/bin/timecheck
usr/local/bin/timezone-transition
usr/local/bin/update-ids-ruleset
usr/local/bin/update-ipblocklists
usr/local/bin/update-lang-cache
usr/local/bin/update-location-database
#usr/local/include
@@ -152,6 +153,7 @@ var/cache/ldconfig
var/cache/ldconfig/aux-cache
var/empty
#var/lib
var/lib/ipblocklist
#var/lib/misc
#var/local
var/lock

View File

@@ -81,6 +81,9 @@ var/ipfire/graphs.pl
var/ipfire/header.pl
var/ipfire/location-functions.pl
var/ipfire/ids-functions.pl
var/ipfire/ipblocklist-functions.pl
var/ipfire/ipblocklist
#var/ipfire/ipblocklist/settings
var/ipfire/isdn
#var/ipfire/isdn/settings
var/ipfire/key

View File

@@ -0,0 +1 @@
var/ipfire/ipblocklist/sources

View File

@@ -195,6 +195,7 @@ usr/share/logwatch/default.conf/services/zz-sys.conf
usr/share/logwatch/dist.conf/logfiles
usr/share/logwatch/dist.conf/services
usr/share/logwatch/dist.conf/services/dialup.conf
usr/share/logwatch/dist.conf/services/ipblocklist.conf
#usr/share/logwatch/lib
usr/share/logwatch/lib/Logwatch.pm
#usr/share/logwatch/scripts
@@ -260,6 +261,7 @@ usr/share/logwatch/scripts/services/http
usr/share/logwatch/scripts/services/imapd
#usr/share/logwatch/scripts/services/in.qpopper
usr/share/logwatch/scripts/services/init
usr/share/logwatch/scripts/services/ipblocklist
usr/share/logwatch/scripts/services/ipop3d
usr/share/logwatch/scripts/services/iptables
usr/share/logwatch/scripts/services/kernel

View File

@@ -27,6 +27,7 @@ srv/web/ipfire/cgi-bin/hardwaregraphs.cgi
srv/web/ipfire/cgi-bin/hosts.cgi
srv/web/ipfire/cgi-bin/ids.cgi
srv/web/ipfire/cgi-bin/index.cgi
srv/web/ipfire/cgi-bin/ipblocklist.cgi
srv/web/ipfire/cgi-bin/ipinfo.cgi
srv/web/ipfire/cgi-bin/iptables.cgi
srv/web/ipfire/cgi-bin/location-block.cgi
@@ -38,9 +39,11 @@ srv/web/ipfire/cgi-bin/logs.cgi/firewalllogcountry.dat
srv/web/ipfire/cgi-bin/logs.cgi/firewalllogip.dat
srv/web/ipfire/cgi-bin/logs.cgi/firewalllogport.dat
srv/web/ipfire/cgi-bin/logs.cgi/ids.dat
srv/web/ipfire/cgi-bin/logs.cgi/ipblocklists.dat
srv/web/ipfire/cgi-bin/logs.cgi/log.dat
srv/web/ipfire/cgi-bin/logs.cgi/ovpnclients.dat
srv/web/ipfire/cgi-bin/logs.cgi/proxylog.dat
srv/web/ipfire/cgi-bin/logs.cgi/showrequestfromblocklist.dat
srv/web/ipfire/cgi-bin/logs.cgi/showrequestfromcountry.dat
srv/web/ipfire/cgi-bin/logs.cgi/showrequestfromip.dat
srv/web/ipfire/cgi-bin/logs.cgi/showrequestfromport.dat

View File

@@ -106,6 +106,7 @@ usr/local/bin/settime
usr/local/bin/timecheck
usr/local/bin/timezone-transition
usr/local/bin/update-ids-ruleset
usr/local/bin/update-ipblocklists
usr/local/bin/update-lang-cache
usr/local/bin/update-location-database
#usr/local/include
@@ -154,6 +155,7 @@ var/cache/ldconfig
var/cache/ldconfig/aux-cache
var/empty
#var/lib
var/lib/ipblocklist
#var/lib/misc
#var/local
var/lock

View File

@@ -143,6 +143,22 @@ if grep -q "ENABLED=on" /var/ipfire/vpn/settings; then
/etc/init.d/ipsec start
fi
# krb5 is now part of the core system, remove Pakfire metadata for it
if [ -e "/opt/pakfire/db/installed/meta-krb5" ] && [ -e "/opt/pakfire/db/meta/meta-krb5" ]; then
rm -vf \
/opt/pakfire/db/installed/meta-krb5 \
/opt/pakfire/db/meta/meta-krb5 \
/opt/pakfire/db/rootfiles/krb5
fi
# libtiff is now part of the core system, remove Pakfire metadata for it
if [ -e "/opt/pakfire/db/installed/meta-libtiff" ] && [ -e "/opt/pakfire/db/meta/meta-libtiff" ]; then
rm -vf \
/opt/pakfire/db/installed/meta-libtiff \
/opt/pakfire/db/meta/meta-libtiff \
/opt/pakfire/db/rootfiles/libtiff
fi
# This update needs a reboot...
touch /var/run/need_reboot

View File

@@ -0,0 +1,260 @@
#!/usr/bin/perl
###############################################################################
# #
# IPFire.org - A linux based firewall #
# #
# 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 <http://www.gnu.org/licenses/>. #
# #
# Copyright (C) 2018 - 2020 The IPFire Team #
# #
###############################################################################
use strict;
# enable the following only for debugging purposes
#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}/ipblocklist-functions.pl";
# Import blockist sources and settings file.
require "${General::swroot}/ipblocklist/sources";
###############################################################################
# Configuration variables
###############################################################################
my $settings = "${General::swroot}/ipblocklist/settings";
my %cgiparams = ('ACTION' => '');
###############################################################################
# Variables
###############################################################################
my $errormessage = '';
my $headline = "$Lang::tr{'error message'}";
my $updating = 0;
my %mainsettings;
my %color;
# Default settings - normally overwritten by settings file
my %settings = (
'DEBUG' => 0,
'LOGGING' => 'on',
'ENABLE' => 'off'
);
# Read all parameters
&Header::getcgihash( \%cgiparams);
&General::readhash( "${General::swroot}/main/settings", \%mainsettings );
&General::readhash( "/srv/web/ipfire/html/themes/".$mainsettings{'THEME'}."/include/colors.txt", \%color );
# Get list of supported blocklists.
my @blocklists = &IPblocklist::get_blocklists();
# Show Headers
&Header::showhttpheaders();
# Process actions
if ($cgiparams{'ACTION'} eq "$Lang::tr{'save'}") {
# Array to store if blocklists are missing on the system
# and needs to be downloaded first.
my @missing_blocklists = ();
# Loop through the array of supported blocklists.
foreach my $blocklist (@blocklists) {
# Skip the blocklist if it is not enabled.
next if($cgiparams{$blocklist} ne "on");
# Get the file name which keeps the converted blocklist.
my $ipset_db_file = &IPblocklist::get_ipset_db_file($blocklist);
# Check if the blocklist already has been downloaded.
if(-f "$ipset_db_file") {
# Blocklist already exits, we can skip it.
next;
} else {
# Blocklist not present, store in array to download it.
push(@missing_blocklists, $blocklist);
}
}
# Check if the red device is not active and blocklists are missing.
if ((not -e "${General::swroot}/red/active") && (@missing_blocklists)) {
# The system is offline, cannot download the missing blocklists.
# Store an error message.
$errormessage = "$Lang::tr{'system is offline'}";
} else {
# Loop over the array of missing blocklists.
foreach my $missing_blocklist (@missing_blocklists) {
# Call the download and convert function to get the missing blocklist.
my $status = &IPblocklist::download_and_create_blocklist($missing_blocklist);
# Check if there was an error during download.
if ($status eq "dl_error") {
$errormessage = "$Lang::tr{'ipblocklist could not download blocklist'} - $Lang::tr{'ipblocklist download error'}";
} elsif ($status eq "empty_list") {
$errormessage = "$Lang::tr{'ipblocklist could not download blocklist'} - $Lang::tr{'ipblocklist empty blocklist received'}";
}
}
}
# Check if there was an error.
unless($errormessage) {
# Write configuration hash.
&General::writehash($settings, \%cgiparams);
# Call function to mark a required reload of the firewall.
&General::firewall_config_changed();
# Display notice about a required reload of the firewall.
$headline = "$Lang::tr{'notice'}";
$errormessage = "$Lang::tr{'fw rules reload notice'}";
}
}
# Show site
&Header::openpage($Lang::tr{'ipblocklist'}, 1, '');
&Header::openbigbox('100%', 'left');
# Display error message if there was one.
&error() if ($errormessage);
# Read-in ipblocklist settings.
&General::readhash( $settings, \%settings ) if (-r $settings);
# Display configuration section.
&configsite();
# End of page
&Header::closebigbox();
&Header::closepage();
#------------------------------------------------------------------------------
# sub configsite()
#
# Displays configuration
#------------------------------------------------------------------------------
sub configsite {
# Find preselections
my $enable = 'checked';
&Header::openbox('100%', 'left', $Lang::tr{'settings'});
# Enable checkbox
$enable = ($settings{'ENABLE'} eq 'on') ? ' checked' : '';
print<<END;
<form method='post' action='$ENV{'SCRIPT_NAME'}'>
<table style='width:100%' border='0'>
<tr>
<td style='width:24em'>$Lang::tr{'ipblocklist use ipblocklists'}</td>
<td><input type='checkbox' name='ENABLE' id='ENABLE'$enable></td>
</tr>
</table><br>
END
# The following are only displayed if the blacklists are enabled
$enable = ($settings{'LOGGING'} eq 'on') ? ' checked' : '';
print <<END;
<div class='sources'>
<table style='width:100%' border='0'>
<tr>
<td style='width:24em'>$Lang::tr{'ipblocklist log'}</td>
<td><input type='checkbox' name="LOGGING" id="LOGGING"$enable></td>
</tr>
</table>
<br><br>
<h2>$Lang::tr{'ipblocklist blocklist settings'}</h2>
<table width='100%' cellspacing='1' class='tbl'>
<tr>
<th align='left'>$Lang::tr{'ipblocklist id'}</th>
<th align='left'>$Lang::tr{'ipblocklist name'}</th>
<th align='left'>$Lang::tr{'ipblocklist category'}</th>
<th align='center'>$Lang::tr{'ipblocklist enable'}</th>
</tr>
END
# Iterate through the list of sources
my $lines = 0;
foreach my $blocklist (@blocklists) {
# Display blocklist name or provide a link to the website if available.
my $website = "$blocklist";
if ($IPblocklist::List::sources{$blocklist}{info}) {
$website ="<a href='$IPblocklist::List::sources{$blocklist}{info}' target='_blank'>$blocklist</a>";
}
# Get the full name for the blocklist.
my $name = &CGI::escapeHTML( $IPblocklist::List::sources{$blocklist}{'name'} );
# Get category for this blocklist.
my $category = $Lang::tr{"ipblocklist category $IPblocklist::List::sources{$blocklist}{'category'}"};
# Determine if the blocklist is enabled.
my $enable = '';
$enable = 'checked' if ($settings{$blocklist} eq 'on');
# Set colour for the table columns.
my $col = ($lines++ % 2) ? "bgcolor='$color{'color20'}'" : "bgcolor='$color{'color22'}'";
print <<END;
<tr $col>
<td>$website</td>
<td>$name</td>
<td>$category</td>
<td align='center'><input type='checkbox' name="$blocklist" id="$blocklist"$enable></td>
</tr>
END
}
# The save button at the bottom of the table
print <<END;
</table>
</div>
<table style='width:100%;'>
<tr>
<td colspan='3' display:inline align='right'><input type='submit' name='ACTION' value='$Lang::tr{'save'}'></td>
</tr>
</table>
</form>
END
&Header::closebox();
}
#------------------------------------------------------------------------------
# sub error()
#
# Shows error messages
#------------------------------------------------------------------------------
sub error {
&Header::openbox('100%', 'left', $headline);
print "<class name='base'>$errormessage\n";
print "&nbsp;</class>\n";
&Header::closebox();
}

View File

@@ -0,0 +1,366 @@
#!/usr/bin/perl
#
# SmoothWall CGIs
#
# This code is distributed under the terms of the GPL
#
# JC HERITIER
# page inspired from the initial firewalllog.dat
#
# Modified for IPFire by Christian Schmidt
# and Michael Tremer (www.ipfire.org)
use strict;
# enable only the following on debugging purpose
#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}/ipblocklist-functions.pl";
require "${General::swroot}/ipblocklist/sources";
use POSIX();
my %cgiparams=();
my $errormessage = '';
my @shortmonths = ( 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug',
'Sep', 'Oct', 'Nov', 'Dec' );
my @longmonths = ( $Lang::tr{'january'}, $Lang::tr{'february'}, $Lang::tr{'march'},
$Lang::tr{'april'}, $Lang::tr{'may'}, $Lang::tr{'june'}, $Lang::tr{'july'}, $Lang::tr{'august'},
$Lang::tr{'september'}, $Lang::tr{'october'}, $Lang::tr{'november'},
$Lang::tr{'december'} );
my @now = localtime();
my $dow = $now[6];
my $doy = $now[7];
my $tdoy = $now[7];
my $year = $now[5]+1900;
$cgiparams{'DAY'} = $now[3];
$cgiparams{'MONTH'} = $now[4];
$cgiparams{'ACTION'} = '';
&Header::getcgihash(\%cgiparams);
my $start = -1;
if ($ENV{'QUERY_STRING'} && $cgiparams{'ACTION'} ne $Lang::tr{'update'})
{
my @temp = split(',',$ENV{'QUERY_STRING'});
$start = $temp[0];
$cgiparams{'MONTH'} = $temp[1];
$cgiparams{'DAY'} = $temp[2];
}
if (!($cgiparams{'MONTH'} =~ /^(0|1|2|3|4|5|6|7|8|9|10|11)$/) ||
!($cgiparams{'DAY'} =~ /^(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31)$/))
{
$cgiparams{'DAY'} = $now[3];
$cgiparams{'MONTH'} = $now[4];
}
elsif($cgiparams{'ACTION'} eq '>>')
{
my @temp_then=();
my @temp_now = localtime(time);
$temp_now[4] = $cgiparams{'MONTH'};
$temp_now[3] = $cgiparams{'DAY'};
@temp_then = localtime(POSIX::mktime(@temp_now) + 86400);
## Retrieve the same time on the next day -
## 86400 seconds in a day
$cgiparams{'MONTH'} = $temp_then[4];
$cgiparams{'DAY'} = $temp_then[3];
}
elsif($cgiparams{'ACTION'} eq '<<')
{
my @temp_then=();
my @temp_now = localtime(time);
$temp_now[4] = $cgiparams{'MONTH'};
$temp_now[3] = $cgiparams{'DAY'};
@temp_then = localtime(POSIX::mktime(@temp_now) - 86400);
## Retrieve the same time on the previous day -
## 86400 seconds in a day
$cgiparams{'MONTH'} = $temp_then[4];
$cgiparams{'DAY'} = $temp_then[3];
}
if (($cgiparams{'DAY'} ne $now[3]) || ($cgiparams{'MONTH'} ne $now[4]))
{
my @then = ();
if ( ( $cgiparams{'MONTH'} eq $now[4]) && ($cgiparams{'DAY'} > $now[3]) ||
( $cgiparams{'MONTH'} > $now[4] ) ) {
@then = localtime(POSIX::mktime( 0, 0, 0, $cgiparams{'DAY'}, $cgiparams{'MONTH'}, $year - 1901 ));
} else {
@then = localtime(POSIX::mktime( 0, 0, 0, $cgiparams{'DAY'}, $cgiparams{'MONTH'}, $year - 1900 ));
}
$tdoy = $then[7];
my $lastleap=($year-1)%4;
if ($tdoy>$doy) {
if ($lastleap == 0 && $tdoy < 60) {
$doy=$tdoy+366;
} else {
$doy=$doy+365;
}
}
}
my $datediff=0;
my $dowd=0;
my $multifile=0;
if ($tdoy ne $doy) {
$datediff=int(($doy-$tdoy)/7);
$dowd=($doy-$tdoy)%7;
if (($dow-$dowd)<1) {
$datediff=$datediff+1;
}
if (($dow-$dowd)==0) {
$multifile=1;
}
}
my $monthstr = $shortmonths[$cgiparams{'MONTH'}];
my $longmonthstr = $longmonths[$cgiparams{'MONTH'}];
my $day = $cgiparams{'DAY'};
my $daystr='';
if ($day <= 9) {
$daystr = " $day"; }
else {
$daystr = $day;
}
my %lists;
my %directions;
my %sources = ();
my %settings = ();
&General::readhash("${General::swroot}/ipblocklist/settings", \%settings);
# Get all available blocklists.
my @blocklists = &IPblocklist::get_blocklists();
foreach my $blocklist (@blocklists)
{
$lists{$blocklist} = {} if ($settings{$blocklist} eq 'on');
}
my $skip=0;
my $filestr='';
if ($datediff==0) {
$filestr="/var/log/messages";
} else {
$filestr="/var/log/messages.$datediff";
$filestr = "$filestr.gz" if -f "$filestr.gz";
}
if (!(open (FILE,($filestr =~ /.gz$/ ? "gzip -dc $filestr |" : $filestr)))) {
$errormessage = "$Lang::tr{'date not in logs'}: $filestr $Lang::tr{'could not be opened'}";
$skip=1;
# Note: This is in case the log does not exist for that date
}
my $lines = 0;
my $directions = 0;
if (!$skip)
{
while (<FILE>)
{
if (/^${monthstr} ${daystr} ..:..:.. [\w\-]+ kernel:.*BLKLST_(\w+)\s*IN=(\w*)/)
{
my $list = $1;
if ($2 =~ m/ppp|red/)
{
$lists{$list}{in}++;
$directions{in}++;
}
else
{
$lists{$list}{out}++;
$directions{out}++;
}
$lines++;
}
}
close (FILE);
}
if ($multifile) {
$datediff=$datediff-1;
if ($datediff==0) {
$filestr="/var/log/messages";
} else {
$filestr="/var/log/messages.$datediff";
$filestr = "$filestr.gz" if -f "$filestr.gz";
}
if (!(open (FILE,($filestr =~ /.gz$/ ? "gzip -dc $filestr |" : $filestr)))) {
$errormessage="$Lang::tr{'date not in logs'}: $filestr $Lang::tr{'could not be opened'}";
$skip=1;
}
if (!$skip) {
while (<FILE>) {
if (/^${monthstr} ${daystr} ..:..:.. [\w\-]+ kernel:.*BLKLST_(\w+)\s*IN=(\w+)/)
{
my $list = $1;
if ($2 =~ m/ppp|red/)
{
$lists{$list}{in}++;
$directions{in}++;
}
else
{
$lists{$list}{out}++;
$directions{out}++;
}
$lines++;
}
}
close (FILE);
}
}
my $MODNAME="fwlogs";
&Header::showhttpheaders();
&Header::openpage($Lang::tr{'ipblocklist logs'}, 1, '');
&Header::openbigbox('100%', 'left', '', $errormessage);
if ($errormessage) {
&Header::openbox('100%', 'left', $Lang::tr{'error messages'});
print "<font class='base'>$errormessage&nbsp;</font>\n";
&Header::closebox();
}
&Header::openbox('100%', 'left', "$Lang::tr{'settings'}");
print <<END
<form method='post' action='$ENV{'SCRIPT_NAME'}'>
<table width='100%'>
<tr>
<td width='10%' class='base'>$Lang::tr{'month'}:&nbsp;</td>
<td width='10%'>
<select name='MONTH'>
END
;
my $month;
for ($month = 0; $month < 12; $month++)
{
print "\t<option ";
if ($month == $cgiparams{'MONTH'}) {
print "selected='selected' ";
}
print "value='$month'>$longmonths[$month]</option>\n";
}
print <<END
</select>
</td>
<td width='10%' class='base' align='right'>&nbsp;$Lang::tr{'day'}:&nbsp;</td>
<td width='40%'>
<select name='DAY'>
END
;
for ($day = 1; $day <= 31; $day++)
{
print "\t<option ";
if ($day == $cgiparams{'DAY'}) {
print "selected='selected' ";
}
print "value='$day'>$day</option>\n";
}
print <<END
</select>
</td>
<td width='5%' align='center'><input type='submit' name='ACTION' title='$Lang::tr{'day before'}' value='&lt;&lt;' /></td>
<td width='5%' align='center'><input type='submit' name='ACTION' title='$Lang::tr{'day after'}' value='&gt;&gt;' /></td>
<td width='20%' align='right'><input type='submit' name='ACTION' value='$Lang::tr{'update'}' /></td>
</tr>
</table>
</form>
END
;
&Header::closebox();
&Header::openbox('100%', 'left', $Lang::tr{'firewall log'});
print "<p><b>$Lang::tr{'ipblocklist hits'} $longmonthstr $daystr: $lines</b></p>";
my %color = ();
my %mainsettings = ();
&General::readhash("${General::swroot}/main/settings", \%mainsettings);
&General::readhash("/srv/web/ipfire/html/themes/ipfire/include/colors.txt", \%color);
my @lists = sort keys (%lists);
print <<END
<table width='100%' class='tbl'>
<tr>
<th align='center' class='boldbase' rowspan='2'></th>
<th align='left' class='boldbase' rowspan='2'><b>$Lang::tr{'ipblocklist id'}</b></th>
<th align='left' class='boldbase' rowspan='2'><b>$Lang::tr{'ipblocklist category'}</b></th>
<th align='center' class='boldbase' colspan='2'><b>$Lang::tr{'ipblocklist input'}</b></th>
<th align='center' class='boldbase' colspan='2'><b>$Lang::tr{'ipblocklist output'}</b></th>
</tr>
<tr>
<th align='center' class='boldbase'>$Lang::tr{'count'}</th>
<th align='center' class='boldbase'>$Lang::tr{'percentage'}</th>
<th align='center' class='boldbase'>$Lang::tr{'count'}</th>
<th align='center' class='boldbase'>$Lang::tr{'percentage'}</th>
</tr>
END
;
$lines = 0;
my $lists = join ',', @lists;
foreach my $list (@lists)
{
my $col = ($lines++ % 2) ? "bgcolor='$color{'color20'}'" : "bgcolor='$color{'color22'}'";
my $category = exists( $IPblocklist::List::sources{$list}) ? $Lang::tr{"ipblocklist category $IPblocklist::List::sources{$list}{'category'}"} : '&nbsp;';
print "<tr>";
print "<td align='center' $col><form method='post' action='showrequestfromblocklist.dat'><input type='hidden' name='MONTH' value='$cgiparams{'MONTH'}'> <input type='hidden' name='DAY' value='$cgiparams{'DAY'}'> <input type='hidden' name='blocklist' value='$list'><input type='hidden' name='blocklists' value='$lists'> <input type='submit' value='$Lang::tr{'details'}'></form></td>";
if (exists($IPblocklist::List::sources{$list}) and $IPblocklist::List::sources{$list}{'info'})
{
print "<td $col><a href='$IPblocklist::List::sources{$list}{info}' target='_blank'>$list</a></td>";
}
else
{
print "<td $col>$list</td>";
}
print "<td $col>$category</td>";
foreach my $direction ('in', 'out')
{
my $count = $lists{$list}{$direction} || 0;
my $percent = $directions{$direction} > 0 ? $count * 100 / $directions{$direction} : 0;
$percent = sprintf("%.f", $percent);
print "<td align='center' class='boldbase' $col>$count</th>";
print "<td align='center' class='boldbase' $col>$percent%</th>";
}
print "</tr>";
}
print <<END
</table>
END
;
&Header::closebox();
&Header::closebigbox();
&Header::closepage();
sub checkversion {
#Automatic Updates is disabled
return "0","0";
}

View File

@@ -59,6 +59,7 @@ my %sections = (
'dhcp' => '(dhcpd: )',
'dma' => '(dma: |dma\[.*\]: |postfix/\w*\[\d*\]: )',
'guardian' => '(guardian\[.*\]: )',
'ipblocklist' => '(ipblocklist: )',
'ipfire' => '(ipfire: )',
'ipsec' => '(ipsec_[\w_]+: |pluto\[.*\]: |charon: |vpnwatch: )',
'kernel' => '(kernel: (?!DROP_))',
@@ -89,6 +90,7 @@ my %trsections = (
'dhcp' => "$Lang::tr{'dhcp server'}",
'dma' => 'Mail',
'guardian' => "$Lang::tr{'guardian'}",
'ipblocklist' => "$Lang::tr{'ipblocklist'}",
'ipfire' => 'IPFire',
'ipsec' => 'IPSec',
'kernel' => "$Lang::tr{'kernel'}",

View File

@@ -0,0 +1,414 @@
#!/usr/bin/perl
# SmoothWall CGIs
#
# This code is distributed under the terms of the GPL
#
# JC HERITIER
# page inspired from the initial firewalllog.dat
#
# Modified for IPFire by Christian Schmidt (www.ipfire.org)
# enable only the following on debugging purpose
#use warnings;
#use CGI::Carp 'fatalsToBrowser';
require '/var/ipfire/general-functions.pl';
require "${General::swroot}/lang.pl";
require "${General::swroot}/header.pl";
use POSIX();
#workaround to suppress a warning when a variable is used only once
my @dummy = ( ${Header::table2colour} );
undef (@dummy);
my %cgiparams=();
my %logsettings=();
my $errormessage = '';
my @shortmonths = ( 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug',
'Sep', 'Oct', 'Nov', 'Dec' );
my @longmonths = ( $Lang::tr{'january'}, $Lang::tr{'february'}, $Lang::tr{'march'},
$Lang::tr{'april'}, $Lang::tr{'may'}, $Lang::tr{'june'}, $Lang::tr{'july'}, $Lang::tr{'august'},
$Lang::tr{'september'}, $Lang::tr{'october'}, $Lang::tr{'november'},
$Lang::tr{'december'} );
my @now = localtime();
my $dow = $now[6];
my $doy = $now[7];
my $tdoy = $now[7];
my $year = $now[5]+1900;
$cgiparams{'DAY'} = $now[3];
$cgiparams{'MONTH'} = $now[4];
$cgiparams{'ACTION'} = '';
&Header::getcgihash(\%cgiparams);
$logsettings{'LOGVIEW_REVERSE'} = 'off';
&General::readhash("${General::swroot}/logging/settings", \%logsettings);
my $start = -1;
my @blocklists;
if ($ENV{'QUERY_STRING'} && $cgiparams{'ACTION'} ne $Lang::tr{'update'})
{
my @temp = split(',',$ENV{'QUERY_STRING'}, 5);
$start = shift @temp;
$cgiparams{'MONTH'} = shift @temp;
$cgiparams{'DAY'} = shift @temp;
$cgiparams{'blocklist'} = shift @temp;
$cgiparams{'blocklists'} = shift @temp;
}
if (!($cgiparams{'MONTH'} =~ /^(0|1|2|3|4|5|6|7|8|9|10|11)$/) ||
!($cgiparams{'DAY'} =~ /^(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31)$/))
{
$cgiparams{'DAY'} = $now[3];
$cgiparams{'MONTH'} = $now[4];
}
elsif($cgiparams{'ACTION'} eq '>>')
{
my @temp_then=();
my @temp_now = localtime(time);
$temp_now[4] = $cgiparams{'MONTH'};
$temp_now[3] = $cgiparams{'DAY'};
@temp_then = localtime(POSIX::mktime(@temp_now) + 86400);
## Retrieve the same time on the next day -
## 86400 seconds in a day
$cgiparams{'MONTH'} = $temp_then[4];
$cgiparams{'DAY'} = $temp_then[3];
}
elsif($cgiparams{'ACTION'} eq '<<')
{
my @temp_then=();
my @temp_now = localtime(time);
$temp_now[4] = $cgiparams{'MONTH'};
$temp_now[3] = $cgiparams{'DAY'};
@temp_then = localtime(POSIX::mktime(@temp_now) - 86400);
## Retrieve the same time on the previous day -
## 86400 seconds in a day
$cgiparams{'MONTH'} = $temp_then[4];
$cgiparams{'DAY'} = $temp_then[3];
}
if (($cgiparams{'DAY'} ne $now[3]) || ($cgiparams{'MONTH'} ne $now[4]))
{
my @then = ();
if ( ( $cgiparams{'MONTH'} eq $now[4]) && ($cgiparams{'DAY'} > $now[3]) ||
( $cgiparams{'MONTH'} > $now[4] ) ) {
@then = localtime(POSIX::mktime( 0, 0, 0, $cgiparams{'DAY'}, $cgiparams{'MONTH'}, $year - 1901 ));
} else {
@then = localtime(POSIX::mktime( 0, 0, 0, $cgiparams{'DAY'}, $cgiparams{'MONTH'}, $year - 1900 ));
}
$tdoy = $then[7];
my $lastleap=($year-1)%4;
if ($tdoy>$doy) {
if ($lastleap == 0 && $tdoy < 60) {
$doy=$tdoy+366;
} else {
$doy=$doy+365;
}
}
}
if ($cgiparams{'blocklists'})
{
@blocklists = split ',', $cgiparams{'blocklists'};
}
my $datediff=0;
my $dowd=0;
my $multifile=0;
if ($tdoy ne $doy) {
$datediff=int(($doy-$tdoy)/7);
$dowd=($doy-$tdoy)%7;
if (($dow-$dowd)<1) {
$datediff=$datediff+1;
}
if (($dow-$dowd)==0) {
$multifile=1;
}
}
my $monthstr = $shortmonths[$cgiparams{'MONTH'}];
my $longmonthstr = $longmonths[$cgiparams{'MONTH'}];
my $day = $cgiparams{'DAY'};
my $daystr='';
if ($day <= 9) {
$daystr = " $day"; }
else {
$daystr = $day;
}
my $skip=0;
my $filestr='';
if ($datediff==0) {
$filestr="/var/log/messages";
} else {
$filestr="/var/log/messages.$datediff";
$filestr = "$filestr.gz" if -f "$filestr.gz";
}
if (!(open (FILE,($filestr =~ /.gz$/ ? "gzip -dc $filestr |" : $filestr)))) {
$errormessage = "$Lang::tr{'date not in logs'}: $filestr $Lang::tr{'could not be opened'}";
$skip=1;
# Note: This is in case the log does not exist for that date
}
my $lines = 0;
my @log=();
my $blocklist = $cgiparams{blocklist};
if (!$skip)
{
while (<FILE>) {
if (/^${monthstr} ${daystr} ..:..:.. [\w\-]+ kernel:.*BLKLST_(\w+)\s?IN=.*/) {
if($1 eq $blocklist){
$log[$lines] = $_;
$lines++;
}
}
}
close (FILE);
}
$skip=0;
if ($multifile) {
$datediff=$datediff-1;
if ($datediff==0) {
$filestr="/var/log/messages";
} else {
$filestr="/var/log/messages.$datediff";
$filestr = "$filestr.gz" if -f "$filestr.gz";
}
if (!(open (FILE,($filestr =~ /.gz$/ ? "gzip -dc $filestr |" : $filestr)))) {
$errormessage="$Lang::tr{'date not in logs'}: $filestr $Lang::tr{'could not be opened'}";
$skip=1;
}
if (!$skip) {
while (<FILE>) {
if (/^${monthstr} ${daystr} ..:..:.. [\w\-]+ kernel:.*BLKLST_(\w+)\s?IN=.*/) {
if($1 eq $blocklist){
$log[$lines] = $_;
$lines++;
}
}
}
close (FILE);
}
}
&Header::showhttpheaders();
&Header::openpage($Lang::tr{'ipblocklist log list'}, 1, '');
&Header::openbigbox('100%', 'left', '', $errormessage);
if ($errormessage) {
&Header::openbox('100%', 'left', $Lang::tr{'error messages'});
print "<font class='base'>$errormessage&nbsp;</font>\n";
&Header::closebox();
}
&Header::openbox('100%', 'left', "$Lang::tr{'settings'}:");
print <<END
<form method='post' action='$ENV{'SCRIPT_NAME'}'>
<input type='hidden' name='blocklists' value='$cgiparams{blocklists}'>
<table width='100%'>
<tr>
<td width='10%' class='base'>$Lang::tr{'month'}:&nbsp;</td>
<td width='10%'>
<select name='MONTH'>
END
;
my $month;
for ($month = 0; $month < 12; $month++)
{
print "\t<option ";
if ($month == $cgiparams{'MONTH'}) {
print "selected='selected' "; }
print "value='$month'>$longmonths[$month]</option>\n";
}
print <<END
</select>
</td>
<td width='10%' class='base' align='right'>&nbsp;$Lang::tr{'day'}:&nbsp;</td>
<td width='40%'>
<select name='DAY'>
END
;
for ($day = 1; $day <= 31; $day++)
{
print "\t<option ";
if ($day == $cgiparams{'DAY'}) {
print "selected='selected' "; }
print "value='$day'>$day</option>\n";
}
print <<END
</select>
</td>
<td width='5%' align='center'><input type='submit' name='ACTION' title='$Lang::tr{'day before'}' value='&lt;&lt;' /></td>
<td width='5%' align='center'><input type='submit' name='ACTION' title='$Lang::tr{'day after'}' value='&gt;&gt;' /></td>
<td width='10%' align='center'><input type='submit' name='ACTION' value='$Lang::tr{'update'}' /></td>
<tr><td width='15%'>$Lang::tr{'ipblocklist id'}</td><td><select name='blocklist'>
END
;
foreach my $option (@blocklists)
{
my $selected = $option eq $cgiparams{blocklist} ? ' selected' : '';
print "<option value='$option'$selected>$option</option>";
}
print <<END
</select></td></tr>
</tr>
</table>
</form>
END
;
&Header::closebox();
&Header::openbox('100%', 'left', $Lang::tr{'ipblocklist log list'});
print "<p><b>$Lang::tr{'firewall hits'} $longmonthstr $daystr: $lines</b></p>";
if ($start == -1) {
$start = $lines - ${Header::viewsize};
}
if ($start >= $lines - ${Header::viewsize}) { $start = $lines - ${Header::viewsize}; };
if ($start < 0) { $start = 0; }
my $prev = $start - ${Header::viewsize};
my $next = $start + ${Header::viewsize};
if ($prev < 0) { $prev = 0; }
if ($next >= $lines) { $next = -1 }
if ($start == 0) { $prev = -1; }
if ($lines != 0) { &oldernewer(); }
print <<END
<table width='100%'>
<tr>
<td width='12%' align='center' class='boldbase'><b>$Lang::tr{'time'}</b></td>
<td width='6%' align='center' class='boldbase'><b>$Lang::tr{'iface'}</b></td>
<td width='6%' align='center' class='boldbase'><b>$Lang::tr{'proto'}</b></td>
<td width='18%' align='center' class='boldbase'><b>$Lang::tr{'source'}</b></td>
<td width='15%' align='center' class='boldbase'><b>$Lang::tr{'src port'}</b></td>
<td width='18%' align='center' class='boldbase'><b>$Lang::tr{'destination'}</b></td>
<td width='15%' align='center' class='boldbase'><b>$Lang::tr{'dst port'}</b></td>
</tr>
END
;
my @slice = splice(@log, $start, ${Header::viewsize});
if ($logsettings{'LOGVIEW_REVERSE'} eq 'on') { @slice = reverse @slice; }
$lines = 0;
foreach $_ (@slice) {
$a = $_;
# Check whether valid ipv4 or ipv6 address
if (($_ =~ /BLKLST_(\w+)\s?IN=/)) {
if($1 eq $blocklist) {
my $in = '-'; my $out = '-';
my $srcaddr = ''; my $dstaddr = '';
my $protostr = '';
my $srcport = ''; my $dstport = '';
# If ipv6 uses bridge, the use PHYSIN, otherwise use IN
if ($_ =~ /(^.* ..:..:..) [\w\-]+ kernel:.*(IN=.*)(PHYSIN=.*)$/) {}
elsif ($_ =~ /(^.* ..:..:..) [\w\-]+ kernel:.*(IN=.*)$/) {}
my $timestamp = $1; my $packet = $2;
$timestamp =~ /(...) (..) (..:..:..)/;
my $month = $1; my $day = $2; my $time = $3;
# If ipv6 uses bridge, the use PHYSIN and PHYSOUT, otherwise use IN and OUT
if ($a =~ /PHYSIN=(\w+)/) { $iface = $1; } elsif ($a =~ /IN=(\w+)/) { $iface = $1; }
if ($a =~ /PHYSOUT=(\w+)/) { $out = $1; } elsif ($a =~ /OUT=(\w+)/) { $out = $1; }
# Detect ipv4 and ipv6 addresses
if (($a =~ /SRC\=(([\d]{1,3})(\.([\d]{1,3})){3})/) or ($a =~ /SRC\=(([0-9a-fA-F]{0,4})(\:([0-9a-fA-F]{0,4})){2,7})/)) { $srcaddr = $1; }
if (($a =~ /DST\=(([\d]{1,3})(\.([\d]{1,3})){3})/) or ($a =~ /DST\=(([0-9a-fA-F]{0,4})(\:([0-9a-fA-F]{0,4})){2,7})/)) { $dstaddr = $1; }
if ($a =~ /PROTO\=(\w+)/) { $protostr = $1; }
my $protostrlc = lc($protostr);
if ($a =~ /SPT\=([\d\.]+)/){ $srcport = $1; }
if ($a =~ /DPT\=([\d\.]+)/){ $dstport = $1; }
if ($lines % 2) {
print "<tr bgcolor='${Header::table1colour}'>\n";
}
else {
print "<tr bgcolor='${Header::table2colour}'>\n";
}
print <<END
<td align='center'>$time</td>
<td align='center'>$iface</td>
<td align='center'>$protostr</td>
<td align='center'>
<table width='100%' cellpadding='0' cellspacing='0'><tr>
<td align='center'><a href='/cgi-bin/ipinfo.cgi?ip=$srcaddr'>$srcaddr</a></td>
</tr></table>
</td>
<td align='center'>$srcport</td>
<td align='center'>
<table width='100%' cellpadding='0' cellspacing='0'><tr>
<td align='center'><a href='/cgi-bin/ipinfo.cgi?ip=$dstaddr'>$dstaddr</a></td>
</tr></table>
</td>
<td align='center'>$dstport</td>
</tr>
END
;
$lines++;
}
}
}
print <<END
</table>
END
;
&oldernewer();
print"<table width='100%'><tr><td align='center'><a href='/cgi-bin/logs.cgi/ipblocklists.dat'><img src='/images/back.png' alt='$Lang::tr{'back'}' title='$Lang::tr{'back'}' /></a></td></tr></table>";
&Header::closebox();
&Header::closebigbox();
&Header::closepage();
sub oldernewer
{
print <<END
<table width='100%'>
<tr>
END
;
my $blocklists = join ',', @blocklists;
print "<td align='center' width='50%'>";
if ($prev != -1) {
print "<a href='/cgi-bin/logs.cgi/showrequestfromblocklist.dat?$prev,$cgiparams{'MONTH'},$cgiparams{'DAY'},$cgiparams{blocklist},$blocklists'>$Lang::tr{'older'}</a>";
}
else {
print "$Lang::tr{'older'}";
}
print "</td>\n";
print "<td align='center' width='50%'>";
if ($next != -1) {
print "<a href='/cgi-bin/logs.cgi/showrequestfromblocklist.dat?$next,$cgiparams{'MONTH'},$cgiparams{'DAY'},$cgiparams{blocklist},$blocklists'>$Lang::tr{'newer'}</a>";
}
else {
print "$Lang::tr{'newer'}";
}
print "</td>\n";
print <<END
</tr>
</table>
END
;
}

View File

@@ -1585,6 +1585,33 @@
'ip basic info' => 'Basic IP information',
'ip info' => 'IP information',
'ip info for' => 'IP information for',
'ipblocklist' => 'IP Address Blocklists',
'ipblocklist blocklist settings' => 'Blocklist settings',
'ipblocklist category' => 'Category',
'ipblocklist category application' => 'Application',
'ipblocklist category attacker' => 'Attacker',
'ipblocklist category c and c' => 'Malware C&amp;C',
'ipblocklist category composite' => 'Composite',
'ipblocklist category invalid' => 'Invalid Address',
'ipblocklist category reputation' => 'Reputation',
'ipblocklist category scanner' => 'Scanner',
'ipblocklist could not download blocklist' => 'Could not download blocklist',
'ipblocklist disable mid' => 'because it is included in',
'ipblocklist disable post' => '',
'ipblocklist disable pre' => 'Disabling',
'ipblocklist download error' => 'A download error occurs.',
'ipblocklist empyt blocklist received' => 'An empty blocklist has been received.',
'ipblocklist enable' => 'Enable',
'ipblocklist entries' => 'Entries',
'ipblocklist hits' => 'Total number of blocklist hits for',
'ipblocklist id' => 'Blocklist',
'ipblocklist input' => 'Packets Dropped In',
'ipblocklist log list' => 'Firewall log (blocklist)',
'ipblocklist log' => 'Log dropped packets',
'ipblocklist logs' => 'IP Address Blocklist Logs',
'ipblocklist name' => 'Name',
'ipblocklist output' => 'Packets Dropped Out',
'ipblocklist use ipblocklists' => 'Enable IP Blocklists',
'ipfire has now rebooted' => 'IPFire is rebooting now.',
'ipfire has now shutdown' => 'IPFire is shutting down now.',
'ipfire side' => 'IPFire side:',

View File

@@ -51,7 +51,7 @@ $(TARGET) :
# Create all directories
for i in addon-lang auth backup ca captive certs connscheduler crls ddns dhcp dhcpc dns dnsforward \
ethernet extrahd/bin fwlogs fwhosts firewall isdn key langs logging mac main \
ethernet extrahd/bin fwlogs fwhosts firewall ipblocklist isdn key langs logging mac main \
menu.d modem optionsfw \
ovpn patches pakfire portfw ppp private proxy/advanced/cre \
proxy/calamaris/bin qos/bin red remote sensors suricata time \
@@ -65,7 +65,7 @@ $(TARGET) :
captive/settings captive/agb.txt captive/clients captive/voucher_out certs/index.txt certs/index.txt.attr ddns/config ddns/settings ddns/ipcache dhcp/settings \
dhcp/fixleases dhcp/advoptions dhcp/dhcpd.conf.local dns/settings dns/servers dnsforward/config ethernet/aliases ethernet/settings ethernet/known_nics ethernet/scanned_nics \
ethernet/wireless extrahd/scan extrahd/devices extrahd/partitions extrahd/settings firewall/settings firewall/config firewall/locationblock firewall/input firewall/outgoing \
fwhosts/customnetworks fwhosts/customhosts fwhosts/customgroups fwhosts/customservicegrp fwhosts/customlocationgrp fwlogs/ipsettings fwlogs/portsettings \
fwhosts/customnetworks fwhosts/customhosts fwhosts/customgroups fwhosts/customservicegrp fwhosts/customlocationgrp fwlogs/ipsettings fwlogs/portsettings ipblocklist/settings \
isdn/settings mac/settings main/hosts main/routing main/security main/settings optionsfw/settings \
ovpn/ccd.conf ovpn/ccdroute ovpn/ccdroute2 pakfire/settings portfw/config ppp/settings-1 ppp/settings-2 ppp/settings-3 ppp/settings-4 \
ppp/settings-5 ppp/settings proxy/settings proxy/squid.conf proxy/advanced/settings proxy/advanced/cre/enable remote/settings qos/settings qos/classes qos/subclasses qos/level7config qos/portconfig \

53
lfs/ipblocklist-sources Normal file
View File

@@ -0,0 +1,53 @@
###############################################################################
# #
# IPFire.org - A linux based firewall #
# Copyright (C) 2007-2022 IPFire development 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 #
# 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 <http://www.gnu.org/licenses/>. #
# #
###############################################################################
###############################################################################
# Definitions
###############################################################################
include Config
VER = ipfire
THISAPP = ipblocklist-sources
TARGET = $(DIR_INFO)/$(THISAPP)
###############################################################################
# Top-level Rules
###############################################################################
install : $(TARGET)
check :
download :
b2 :
###############################################################################
# Installation Details
###############################################################################
$(TARGET) :
@$(PREBUILD)
mkdir -p /var/ipfire/ipblocklist
install -v -m 0644 $(DIR_SRC)/config/ipblocklist/sources /var/ipfire/ipblocklist
@$(POSTBUILD)

View File

@@ -98,6 +98,9 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
cp -f $(DIR_SRC)/config/logwatch/dialup /usr/share/logwatch/scripts/services/dialup
cp -f $(DIR_SRC)/config/logwatch/dialup.conf /usr/share/logwatch/dist.conf/services/dialup.conf
cp -f $(DIR_SRC)/config/logwatch/ipblocklist /usr/share/logwatch/scripts/services/ipblocklist
cp -f $(DIR_SRC)/config/logwatch/ipblocklist.conf /usr/share/logwatch/dist.conf/services/ipblocklist.conf
-mkdir -p /var/cache/logwatch
chmod -v 777 /var/cache/logwatch
-mkdir -p /var/log/logwatch

View File

@@ -165,4 +165,8 @@ endif
-mkdir -pv /opt/pakfire/db/core
echo "$(CORE)" > /opt/pakfire/db/core/mine
# IPblocklist.
-mkdir -pv /var/lib/ipblocklist
chown nobody:nobody /var/lib/ipblocklist
@$(POSTBUILD)

View File

@@ -1439,6 +1439,7 @@ buildipfire() {
lfsmake2 hyperscan
lfsmake2 suricata
lfsmake2 ids-ruleset-sources
lfsmake2 ipblocklist-sources
lfsmake2 squid
lfsmake2 squidguard
lfsmake2 calamaris

View File

@@ -180,6 +180,14 @@ iptables_init() {
iptables -A HOSTILE_DROP -m limit --limit 10/second -j LOG --log-prefix "DROP_HOSTILE "
iptables -A HOSTILE_DROP -j DROP -m comment --comment "DROP_HOSTILE"
# IP Address Blocklist chains
iptables -N BLOCKLISTIN
iptables -N BLOCKLISTOUT
iptables -A INPUT ! -p icmp -j BLOCKLISTIN
iptables -A FORWARD ! -p icmp -j BLOCKLISTIN
iptables -A FORWARD ! -p icmp -j BLOCKLISTOUT
iptables -A OUTPUT ! -p icmp -j BLOCKLISTOUT
# IPS (Guardian) chains
iptables -N GUARDIAN
iptables -A INPUT -j GUARDIAN

View File

@@ -0,0 +1,173 @@
#!/usr/bin/perl
###############################################################################
# #
# IPFire.org - A linux based firewall #
# Copyright (C) 2007-2022 IPFire Team <info@ipfire.org> #
# #
# 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 <http://www.gnu.org/licenses/>. #
# #
###############################################################################
use strict;
use POSIX;
# Load perl module to talk to the kernel syslog.
use Sys::Syslog qw(:DEFAULT setlogsock);
require '/var/ipfire/general-functions.pl';
require "${General::swroot}/ipblocklist-functions.pl";
require "${General::swroot}/lang.pl";
# Hash to store the settings.
my %settings = ();
# The user and group name as which this script should be run.
my $run_as = 'nobody';
# Get user and group id of the user.
my ( $uid, $gid ) = ( getpwnam $run_as )[ 2, 3 ];
# Check if the script currently runs as root.
if ( $> == 0 ) {
# Drop privileges and switch to the specified user and group.
POSIX::setgid( $gid );
POSIX::setuid( $uid );
}
# Establish the connection to the syslog service.
openlog('ipblocklist', 'cons', 'user');
# Grab the configured providers.
&General::readhash("${General::swroot}/ipblocklist/settings", \%settings);
# Check if the blocklist feature is enabled.
unless ($settings{'ENABLE'} eq "on") {
# Exit.
exit 0;
}
# Check if the red device is active.
unless (-e "${General::swroot}/red/active") {
# Log to syslog.
&_log_to_syslog("<ERROR> Could not update any blocklist - The system is offline!");
# Exit.
exit 1;
}
# Get all available blocklists.
my @blocklists = &IPblocklist::get_blocklists();
# Array to store successfully update blocklists.
# They need to be reloaded.
my @updated_blocklists = ();
# Gather the details, when a list got modified last time.
my %modified = ();
# Read-in data if the file exists.
&General::readhash($IPblocklist::modified_file, \%modified ) if (-e $IPblocklist::modified_file);
# Loop through the array of blocklists.
foreach my $blocklist (@blocklists) {
# Skip if the blocklist is not enabled.
next if($settings{$blocklist} ne "on");
# Get current time.
my $time = time();
# Get time, when the blocklist has been downloaded last.
my $last_download_time = $modified{$blocklist};
# Get the holdoff rate in seconds for the current processed blocklist.
my $rate_time = &IPblocklist::get_holdoff_rate($blocklist);
# Calculate holdoff time.
my $holdoff_time = $last_download_time + $rate_time;
# Check if enough time has passed since the last download of the list.
if ($time <= $holdoff_time) {
# To frequent updates, log to syslog.
&_log_to_syslog("<INFO> Skipping $blocklist blocklist - Too frequent update attempts!");
# Skip this provider.
next;
}
# Try to download and update the blocklist.
my $return = &IPblocklist::download_and_create_blocklist($blocklist);
# Check if we got a return code.
if ($return) {
# Handle different return codes.
if ($return eq "not_modified") {
# Log notice to syslog.
&_log_to_syslog("<INFO> Skipping $blocklist blocklist - It has not been modified!");
} elsif ($return eq "dl_error") {
# Log error to the syslog.
&_log_to_syslog("<ERROR> Could not update $blocklist blocklist - Download error\!");
} else {
# Log error to syslog.
&_log_to_syslog("<ERROR> Could not update $blocklist blocklist - Unexpected error\!");
}
} else {
# Log successfull update.
&_log_to_syslog("<INFO> Successfully updated $blocklist blocklist.");
# Add the list to the array of updated blocklists.
push(@updated_blocklists, $blocklist);
}
}
# Check if a blocklist has been updated and therefore needs to be reloaded.
if (@updated_blocklists) {
# Loop through the array.
foreach my $updated_blocklist (@updated_blocklists) {
# Get the blocklist file.
my $ipset_db_file = &IPblocklist::get_ipset_db_file($updated_blocklist);
# Call safe system function to reload/update the blocklist.
&General::system("ipset", "restore", "-f", "$ipset_db_file");
# The set name contains a "v4" as suffix.
my $set_name = "$updated_blocklist" . "v4";
# Swap the sets to use the new one.
&General::system("ipset", "swap", "$set_name", "$updated_blocklist");
# Destroy the old blocklist.
&General::system("ipset", "destroy", "$set_name");
}
}
END {
# Close connection to syslog.
closelog();
}
#
# Tiny function to sent the error message to the syslog.
#
sub _log_to_syslog($) {
my ($message) = @_;
# The syslog function works best with an array based input,
# so generate one before passing the message details to syslog.
my @syslog = ("ERR", "$message");
# Send the log message.
syslog(@syslog);
}
1;