[Dshield] script to automatically update iptables

Johannes B. Ullrich jullrich at sans.org
Thu May 2 19:13:10 GMT 2002

I put together a little perl script to grap our blocklist and
automatically setup iptables rules to block the networks listed.

It is attached below.

The script sets up its own chain, which you have to include in your
regular rules. For example something like this:

# first some trusted hosts which should never be blocked
iptables -A INPUT -s (trusted ip...) (restrictions... e.g. ports) -j

# call the blocklist
iptables -A INPUT -j BLOCKLIST

# remainder of your rules
iptables -A INPUT ....

You may want to setup a little log chain to mark everything dropped:
iptables -N LOGBLOCK
iptables -A LOGBLOCK -j LOG --log-level warning --log-prefix "filter:
iptables -A LOGBLOCK -j DROP

You have to change the value for the 'blocktarget' to point to
'LOGBLOCK' instead of 'DROP' to use this logging chain.

Let me know how it goes. The script insists on validating the file.
The script has to run as root to change the iptables rules.

------------------------ snip here ------------------------------------
#!/usr/bin/perl -T

#  (c) 2001 SANS Institute.
#      jullrich at 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 paramters you may want to change.

# a temporary directory. Preferable an empty directory that
# is owned by root and set to 700
my $tmpdir='/usr/tmp';

# only tested with gpg so far. you need to change this line if
# you are using pgp
my $gpg='/usr/bin/gpg -q --verify ';

# the signature...
my $signature='DShield.org \(Block List\) <blocklist\@dshield.org>';

# should point to your iptables binary.
my $iptables='/sbin/iptables';

# change this if you want to have the chain it creates called something
# else
my $blockchain='BLOCKLIST';

#  you may want to replace this with your own log & drop chain.
my $blocktarget='DROP';


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;


my $sig=$res->content;

# Writing content to tmp file.

my $filenum;

$filenum=rand() until ( ( ! -e "$tmpdir/$filenum" ) && ( ! -e "$tmpdir/$filenum.asc" )); 
open(F,"> $tmpdir/$filenum");
die ("Temporary file problem.\n") if ( ! -z "$tmpdir/$filenum");
print F $list;
close F;
open(F,"> $tmpdir/$filenum.asc");
die ("Temporary file problem.\n") if ( ! -z "$tmpdir/$filenum.asc");
print F $sig;
close F;
open (F,"$gpg $tmpdir/$filenum.asc 2>&1 |");
my $valid='N';
while (<F>) {
    $valid='Y' if ( /Good signature from "$signature"/ );
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("$iptables -F $blockchain");
print("$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.
exec("$iptables -I $blockchain -j RETURN");

open (F,"$tmpdir/$filenum");

my ($start, $end, $block, $attacks, $name, $country, $email);
while (<F>) {
    next if /^#/;
    ($start, $end, $block, $attacks, $name, $country, $email)=split("\t");
    if ( ( $start =~ /^[\d\.]+$/ ) && ( $block =~ /^\d+/ ) ) {  
	exec("$iptables -I -s $start/$block -j $blocktarget");

---------------------- end of script --------------------

jullrich at sans.org                    Join http://www.DShield.org
                          Distributed Intrusion Detection System

More information about the list mailing list