#!/usr/bin/perl -Tw
# (c) 2001 SANS Institute.
# jullrich@sans.org
# distribution permitted.
#
# Script to retrieve block list from DShield.org, validate it \
# and generate iptables rules to apply it to firewall
#
use strict;
use LWP::UserAgent;
#
# A few parameters you may want to change.
#
my $debug=1;
# Better: change this to /root or another directory that is
# only read/writable by root
my $tmpdir='/usr/tmp';
#
# point to wherever you have gpg installed. Not tested with
# pgp, but may work anyway if you change the parameters
my $gpg='/usr/bin/gpg -q --verify ';
#
# for the current key.
my $signature='DShield.org \(Block List\) <blocklist\@dshield.org>';
#
# point to wherever you keep /sbin/iptables
my $iptables='/sbin/iptables';
#
# This is the name of the chain this script will create
my $blockchain='blocklist';
#
# change this to a different (action?) change if you would like more logging
# or such.
my $blocktarget='DROP';
# Use LWP routines to download the block list and gnupg signature
print "Retrieve block list...\n" if $debug;
my $ua = LWP::UserAgent->new;
$ua->agent("BlockListRetriever V 1.0");
my $req=HTTP::Request->new(GET => 'http://feeds.dshield.org/block.txt');
my $res=$ua->request($req);
die ("Request to retrieve block list failed.\n".$res->message."\n") unless ( $res->is_success) ;
my $list=$res->content;
print "Retrieve block list signature...\n" if $debug;
$req->uri('http://feeds.dshield.org/block.txt.asc');
$res=$ua->request($req);
my $sig=$res->content;
#
# Writing content to tmp file.
#
my $filenum;
$ENV{PATH}='';
$ENV{BASH_ENV}='';
# Make unused temp file name
$filenum=rand() until ( ( ! -e "$tmpdir/$filenum" ) && ( ! -e "$tmpdir/$filenum.asc" ));
# First write the block list to a temporary file
open(F,"> $tmpdir/$filenum");
die ("Temporary file problem ($tmpdir/$filenum).\n") if ( ! -z "$tmpdir/$filenum");
print F $list;
close F;
# Then write the signature to another temporary file
open(F,"> $tmpdir/$filenum.asc");
die ("Temporary file problem ($tmpdir/$filenum).\n") if ( ! -z "$tmpdir/$filenum.asc");
print F $sig;
close F;
# Verify gnupg signature
print "Check signature...\n" if $debug;
open (F,"$gpg $tmpdir/$filenum.asc 2>&1 |");
my $valid='N';
while (<F>) {
$valid='Y' if ( /Good signature from "$signature"/ );
}
# Abort if the signature doesn't check
die ("Signature not valid. Please verify manually or check if you have the right key\n") if ($valid eq 'N');
#
# Signature is valid.. Now we need to parse the block list.
#
# Clean out existing chain
print "Cleanup iptable '$blockchain'...\n" if $debug;
system("$iptables -F $blockchain");
system("$iptables -N $blockchain");
# Add default rule to return back to calling chain. As long as an
# IP is not on the list, this will allow it to pass.
system("$iptables -I $blockchain -j RETURN");
# The block list that we downloaded from http://feeds.dshield.org/block.txt
open (F,"$tmpdir/$filenum");
my ($start, $end, $block, $attacks, $name, $country, $email);
print "Populate $blockchain...\n" if $debug;
while (<F>) {
next if /^\s*(#|$)/;
($start, $end, $block, $attacks, $name, $country, $email)=split("\t");
# untaint
$start=~/^([\d\.]+)$/; $start = $1;
$block =~ /^(\d+)/; $block = $1;
if ( defined($start) && defined($block) ) {
system("$iptables -I $blockchain -s $start/$block -j $blocktarget");
}
}
print "Apparently... done.\n" if $debug;