Skip to content
Snippets Groups Projects
blocklist.pl 11.9 KiB
Newer Older
virus2500's avatar
virus2500 committed
#!/usr/bin/perl
Virus2500's avatar
Virus2500 committed
use strict; 
use warnings;
use FindBin '$Bin';
virus2500's avatar
virus2500 committed
use Data::Validate::IP qw(is_ipv4 is_ipv6);
virus2500's avatar
virus2500 committed
use Getopt::Std;
no if ($] >= 5.018), 'warnings' => 'experimental::smartmatch';
virus2500's avatar
virus2500 committed
################################################################
virus2500's avatar
virus2500 committed
###### Script to parse a Blocklist list. Block new IP     ######
###### and unblock deleted entrys                         ######
###### Multiple list possible. IPV4 and IPV6 supported    ######
virus2500's avatar
virus2500 committed
################################################################

## config ##
my @listUrl     = ("http://lists.blocklist.de/lists/all.txt", "http://www.infiltrated.net/blacklisted");
my $tmpDir      = "/tmp";
my $logFile     = "/var/log/blocklist";
my $whiteList   = "$Bin/whitelist.txt";
my $blackList   = "$Bin/blacklist.txt";
virus2500's avatar
virus2500 committed

## binarys ##
## ! Notice ! Changing these values shouldn't be needed anymore
## I'll leave it here just in case none of the paths below match.
$ENV{'PATH'}    = '/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin';
my $iptables    = "iptables";
my $ipset       = "ipset";
my $grep        = "grep";
my $rm          = "rm";
my $wget        = "wget";
virus2500's avatar
virus2500 committed

## plain variables ##
my($row, $Blocklist, $line, $check, $checkLine, $result, $output, $url, $ipRegex, $message, %opt, $opt);
virus2500's avatar
virus2500 committed

my ($added, $count, $removed, $skipped);
$added = $count = $removed = $skipped = 0;
virus2500's avatar
virus2500 committed

## init arrays ##
my @fileArray = ();
my @ipsetArray = ();
Virus2500's avatar
Virus2500 committed
my @whiteListArray = ();
my @blackListArray = ();
virus2500's avatar
virus2500 committed
## init hashes for faster searching
Virus2500's avatar
Virus2500 committed
my %whiteListArray;
my $blackListArray;
virus2500's avatar
virus2500 committed
my %ipsetArray;
my %fileArray;

my $dateTime;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
my @months = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
my @days = qw(Sun Mon Tue Wed Thu Fri Sat Sun);

virus2500's avatar
virus2500 committed
&init();

############# init ##################
#### check if we got any options ####
#### and decide where to go      ####
#####################################

sub init {
    $opt = 'hc';
    getopts( "$opt", \%opt );
    usage() if $opt{h};
    cleanupAll() if $opt{c};
    # else start main subroutine
    main();
}
############## end init #############

############ usage ##################
#### Some info about this script ####
#####################################
sub usage() {
    print STDERR << "EOF";
    blocklist-with-ipset
    
virus2500's avatar
virus2500 committed
    This script downloads and parses Text files with IPs and blocks them. 
virus2500's avatar
virus2500 committed
    Just run ./blocklist.pl
    
    If you want to clean everything up run
    ./blocklist.pl -c
EOF
    exit;
}
virus2500's avatar
virus2500 committed
#****************************#
#*********** MAIN ***********#
#****************************#
virus2500's avatar
virus2500 committed
sub main {
    logging("Starting blocklist refresh");
    &iptablesCheck();
    &getWhiteListArray();
    &getBlackListArray();
    &getFileArray();
    &getIpsetArray();
    &addIpsToBlocklist();
    &remIpsFromBlocklist();
    &cleanup();

    exit;
}
virus2500's avatar
virus2500 committed
#***** END MAIN *****#


#****************************#
#******* Subroutines ********#
#****************************#



############# iptablesCheck ###############
## checks if all necessary               ##
## iptable/ipset Settings have been set  ##
###########################################

sub iptablesCheck {
    ## Do we have an BLOCKLIST/DROP Chain in iptables?
virus2500's avatar
virus2500 committed
    if (`$iptables -L -n | $grep BLOCKLIST` =~ m/Chain BLOCKLIST/) {
virus2500's avatar
virus2500 committed
    } else {
        $message = "Creating Chain BLOCKLIST";
        logging($message);
virus2500's avatar
virus2500 committed
        `$iptables -N BLOCKLIST`;
        `$iptables -A BLOCKLIST -m limit --limit 2/min -j LOG --log-prefix "Blocklist Dropped: " --log-level 4`;
        `$iptables -A BLOCKLIST -j DROP`;
    }

    ## Do we have an BLOCKLIST/DROP Chain in ip6tables?
    if (`$ip6tables -L -n | $grep BLOCKLIST` =~ m/Chain BLOCKLIST/) {
        # Do nothing...
    } else {
        $message = "Creating Chain BLOCKLIST";
        logging($message);
        `$ip6tables -N BLOCKLIST`;
        `$ip6tables -A BLOCKLIST -m limit --limit 2/min -j LOG --log-prefix "Blocklist Dropped: " --log-level 4`;
        `$ip6tables -A BLOCKLIST -j DROP`;
    }
virus2500's avatar
virus2500 committed
    ## Do we have an ipset list called blocklist?
virus2500's avatar
virus2500 committed
    if(`$ipset list -n | $grep blocklist` =~ m/blocklist/ && `$ipset list -n | $grep blocklist` =~ m/blocklist-v6/  ) {
virus2500's avatar
virus2500 committed
    } else {
        `$ipset create blocklist hash:ip hashsize 4096 maxelem 131050`;
        `$ipset create blocklist-v6 hash:ip hashsize 4096 family inet6 maxelem 131050`;
        $message = "Created ipset list blocklist";
        logging($message);
virus2500's avatar
virus2500 committed
    }
virus2500's avatar
virus2500 committed
        
    ## Is there an forwarded from INPUT to BLOCKLIST in iptables?
    if (`$iptables -L INPUT | $grep BLOCKLIST`=~ m/BLOCKLIST/ && `$iptables -L INPUT | $grep BLOCKLIST`=~ m/blocklist/) {
virus2500's avatar
virus2500 committed
    } else {
        `$iptables -I INPUT -m set --match-set blocklist src -j BLOCKLIST`;
        $message = "Creating forward to BLOCKLIST chain";
        logging($message);
virus2500's avatar
virus2500 committed
    }
    ## Is there an forwarded from INPUT to BLOCKLIST in ip6tables?
    if (`$ip6tables -L INPUT | $grep BLOCKLIST`=~ m/BLOCKLIST/ && `$ip6tables -L INPUT | $grep BLOCKLIST`=~ m/blocklist-v6/) {
        # Do nothing
    } else {
        `$ip6tables -I INPUT -m set --match-set blocklist-v6 src -j BLOCKLIST`;
        $message = "Creating forward to BLOCKLIST chain";
        logging($message);
    }

virus2500's avatar
virus2500 committed
}

######## END iptablesCheck ########


########## getFileArray #############
## downloads the Blocklist.txt and ##
## pushes it into an array         ##
#####################################
sub getFileArray {
virus2500's avatar
virus2500 committed
    foreach $url (@listUrl) {
        $count++;
        `$wget -q -O $tmpDir/Blocklist_$count $url && echo "Downloaded temp file to $tmpDir/Blocklist_$count" || echo "Can not download file.... stopping"`;
virus2500's avatar
virus2500 committed

virus2500's avatar
virus2500 committed
        open(INFO, "$tmpDir/Blocklist_$count") or die("Could not open file.");
        foreach $line (<INFO>) {
            push(@fileArray, $line);
        }
virus2500's avatar
virus2500 committed

virus2500's avatar
virus2500 committed
        close(INFO);
virus2500's avatar
virus2500 committed
    }
    chomp(@fileArray);
    %fileArray = map {$_ => 1 } @fileArray;
}
####### END getFileArray ##########

######### getIpsetArray ##########
## runs ipset list blocklist    ##
## and pushes it into           ##
## array ipsetList              ##
##################################

sub getIpsetArray {
    $output = `$ipset list blocklist`;
virus2500's avatar
virus2500 committed
    $output .= `$ipset list blocklist-v6`;
virus2500's avatar
virus2500 committed
    @ipsetArray = split("\n", $output);
    #remove the first 6 Elements of our Array using splice (ipset header info)
    splice @ipsetArray, 0, 6;
    %ipsetArray = map { $_ => 1} split("\n", $output);
}

##### END getIpsetArray #########

Virus2500's avatar
Virus2500 committed
######### getWhiteListArray ######
## puts all ips from our        ##
## $whitelist into              ##
## array whiteListArray         ##
##################################

sub getWhiteListArray {
    open(INFO, $whiteList) or die("Could not open Whitelist.");
    foreach $line (<INFO>) {
        push(@whiteListArray, $line);
    }

    close(INFO);
    chomp(@whiteListArray);
}
##### END getWhiteListArray #####

######### getBlackListArray ######
## puts all ips from our        ##
## $whitelist into              ##
## array blackListArray         ##
##################################

sub getBlackListArray {
    open(INFO, $blackList) or die("Could not open Blacklist.");
    foreach $line (<INFO>) {
        push(@blackListArray, $line);
    }

    close(INFO);
    chomp(@blackListArray);
}
##### END getBlackListArray #####

virus2500's avatar
virus2500 committed
######## addIpsToBlocklist ######
## adds IPs to our blocklist   ##
#################################

sub addIpsToBlocklist {
virus2500's avatar
virus2500 committed
    foreach $line (uniq(@blackListArray)) {
virus2500's avatar
virus2500 committed
        if ((exists $ipsetArray{"$line"}) ||    ($line ~~ @whiteListArray)) {
            $skipped++;
Virus2500's avatar
Virus2500 committed
        } else {
virus2500's avatar
virus2500 committed
            if (is_ipv4($line) || is_ipv6($line)) {
                if(is_ipv4($line)) {
                    $result = `$ipset add blocklist $line`;
                } else {
                    $result = `$ipset add blocklist-v6 $line`;
                }
                $added++;
                $message = "added $line";
                logging($message);
            } else {
Virus2500's avatar
Virus2500 committed
                $skipped++;
virus2500's avatar
virus2500 committed
            }
virus2500's avatar
virus2500 committed
        }
Virus2500's avatar
Virus2500 committed
    }
virus2500's avatar
virus2500 committed
    foreach $line (uniq(@fileArray)) { 
Virus2500's avatar
Virus2500 committed
        if ((exists $ipsetArray{"$line"}) || ($line ~~ @whiteListArray)) {
virus2500's avatar
virus2500 committed
            $skipped++;
        } else {
virus2500's avatar
virus2500 committed
            if (is_ipv4($line) || is_ipv6($line)) {
                if(is_ipv4($line)) {
                    $result = `$ipset add blocklist $line`;
                } else {
                    $result = `$ipset add blocklist-v6 $line`;
                }
virus2500's avatar
virus2500 committed
                $added++;
                $message = "added $line";
                logging($message);
virus2500's avatar
virus2500 committed
            } else {
                $skipped++;
            }
virus2500's avatar
virus2500 committed
        } 
    } 

virus2500's avatar
virus2500 committed
}
######## END addIpsToBlocklist ######

########## remIpsFromBlocklist ########
virus2500's avatar
virus2500 committed
## remove IPs from our blocklist     ##
#######################################
virus2500's avatar
virus2500 committed
sub remIpsFromBlocklist {
Virus2500's avatar
Virus2500 committed
    # remove Ips that are in our whiteList
    foreach $line (@whiteListArray) {
        if ((exists $ipsetArray{"$line"}) && ($line ~~ @whiteListArray)) {
virus2500's avatar
virus2500 committed
            if (is_ipv4($line) || is_ipv6($line)) {
                if(is_ipv4($line)) {
                    $result = `$ipset del blocklist $line`;
                } else {
                    $result = `$ipset del blocklist-v6 $line`;
                }
Virus2500's avatar
Virus2500 committed
                $message = "removed $line";
                logging($message);
                $removed++;
            } else {
virus2500's avatar
virus2500 committed
            $skipped++;
virus2500's avatar
virus2500 committed
    foreach $line (@ipsetArray) {
Virus2500's avatar
Virus2500 committed
        if ((exists $fileArray{"$line"}) || ($line ~~ @blackListArray)) {
virus2500's avatar
virus2500 committed
            $skipped++;     
virus2500's avatar
virus2500 committed
        } else {
virus2500's avatar
virus2500 committed
            if (is_ipv4($line) || is_ipv6($line)) {
                if(is_ipv4($line)) {
                    $result = `$ipset del blocklist $line`;
                } else {
                    $result = `$ipset del blocklist-v6 $line`;
                }
virus2500's avatar
virus2500 committed
                $message = "removed $line";
                logging($message);
                $removed++;
virus2500's avatar
virus2500 committed
            } else {
                $skipped++;
            }
        }
    }
}

######## END remIpsFromBlocklist ########


################## cleanup ###################
#### Cleanup: move tmp file to new place #####
##############################################
virus2500's avatar
virus2500 committed
sub cleanup {
virus2500's avatar
virus2500 committed
    for (1..$count) {
        $result = `$rm $tmpDir/Blocklist_$_ && echo "Deleted file $tmpDir/Blocklist_$_" || echo "Can\t delete file $tmpDir/Blocklist_$_"`;
    }
    $message = "We added $added, removed $removed, skipped $skipped Rules";
    logging($message);
virus2500's avatar
virus2500 committed
}
############### END cleanup ######################

virus2500's avatar
virus2500 committed
########### cleanupAll #################
#### Remove our Rules from iptables ####
#### and flush our ipset lists      ####
########################################

sub cleanupAll {
    if (`$iptables -n -L | $grep BLOCKLIST` =~ m/Chain BLOCKLIST/) {
        `$iptables -D INPUT -m set --match-set blocklist src -j BLOCKLIST`;
        `$iptables -F BLOCKLIST`;
        `$iptables -X BLOCKLIST`;
        `$ipset destroy blocklist`;
        `$ipset destroy blocklist-v6`;
    }
    if (`$ip6tables -n -L | $grep BLOCKLIST` =~ m/Chain BLOCKLIST/) {
        `$ip6tables -D INPUT -m set --match-set blocklist-v6 src -j BLOCKLIST`;
        `$ip6tables -F BLOCKLIST`;
        `$ip6tables -X BLOCKLIST`;
        `$ipset destroy blocklist`;
        `$ipset destroy blocklist-v6`;
    }

virus2500's avatar
virus2500 committed
    exit;
}

########################################

###### log #######
## log $message ##
##################
sub logging {
    my ($message) = @_;

    ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();

    open my $fh, ">>", $logFile
        or die "Can't open logfile: $!";
    $dateTime = sprintf("$months[$mon]  %02d %02d:%02d:%02d ", $mday,$hour,$min,$sec);
    print $fh "$dateTime $message\n";
    print "$message\n";

    close($fh);
}
#### end log #####
virus2500's avatar
virus2500 committed
############## uniq ###############
## Make sure we wont             ##
## add/remove the same ip twice  ##
###################################

virus2500's avatar
virus2500 committed
sub uniq { my %seen; grep !$seen{$_}++, @_ } # from http://stackoverflow.com/questions/13257095/remove-duplicate-values-for-a-key-in-hash

virus2500's avatar
virus2500 committed
#### end uniq ####

virus2500's avatar
virus2500 committed
######### EOF ###########