#!/usr/bin/perl ########################################################### # txt2rbl # # Converts local ip blacklist to DNS RBL zone file # # Available from: # See also: ########################################################### $SRCTXT="/etc/spamips"; $DSTDB="/var/named/db.example.com.rbl"; $ZONE='rbl.example.com'; $MESSAGE="per "; $ZONENS='ns.example.com'; $ZONEADMIN='hostmaster.example.com'; $TTL=86400; $SERIALNO=20000730; @WHITELIST=('127','192.168','10'); ########################################################### # to do: increment serial# for slave servers, # test zone file with nslint, # check for overlapping subnets, # warning msg if duplicate, ... ########################################################### # $Id: txt2db_ip,v 1.91 2007/10/19 15:10:17 $ ########################################################### $TMPDB="$DSTDB.tmp"; if ( ! -w $DSTDB ) { print " ERROR: $DSTDB not found or not writeable.\n"; exit; } elsif ( ! -s $SRCTXT ) { print " ERROR: empty source file: $SRCTXT. \n"; exit; } if ( -f $TMPDB ) { print " Lock ($TMPDB) found, sleeping 60 seconds.\n"; sleep 60; for ( $i=1 ; $i<5 ; $i++ ) { if ( -f $TMPDB ) { print " Lock ($TMPDB) found, sleeping another 60 seconds.\n"; sleep 60; } } if ( -f $TMPDB ) { print " Lock ($TMPDB) still found after 5 minutes, giving up.\n"; exec `logger " Lock ($TMPDB) still found after 5 minutes, giving up.\n"`; exit; } } sub Terminate() { close($SRCTXT); close($TMPDB); unlink($TMPDB); die("$_[0]"); } $SIG{ INT } = \&Terminate; $SIG{ KILL } = \&Terminate; $SIG{ TERM } = \&Terminate; $SIG{ QUIT } = \&Terminate; print "Updating $ZONE from $SRCTXT to $DSTDB...\n"; open(TMPDB,">$TMPDB") || die(" Cannot create $TMPDB\n"); print TMPDB <<"TAG"; \$TTL $TTL @ IN SOA $ZONENS. $ZONEADMIN. ( $SERIALNO 86400 43200 604800 $TTL ) IN NS ${ZONENS}. 2.0.0.127 A 127.0.0.2 2.0.0.127 TXT "$MESSAGE for testing" TAG open(SRCTXT, $SRCTXT)|| \&Terminate(" Cannot read $SRCTXT\n"); ADDRESS: foreach () { #### parse source file #### next ADDRESS if /(^#|^$|^\s)/; # ignore comments, nulls, start with space/tab next ADDRESS if /\s(HOLD|DISCARD|WARN|LOCAL)/; # skip local tags @line = split(/\s/, $_); # strip comments/tags $_ = $line[0]; chomp; #### validate IP syntax #### if ( /[^0-9\.]/ || /\.\./ || /^\./ || /\.$/ ) { #### illegal chars, sequential dots, leading/trailing dots print " REJECT: $_ is not a valid IP address format.\n"; next ADDRESS } #### test octects #### @ip = split(/\./, $_); if ( $ip[4] || $ip[0] == 0 || $ip[0] == 127 || $ip[0] == 255 || $ip[3] == 255 ) { # must be IPv4, not broadcast, and not localhost print " REJECT: $_ is not a valid IP host or subnet.\n"; next ADDRESS } for ( $octet = 0 ; $octet < 4 ; $octet++ ) { if ( $ip[$octet] < 0 || $ip[$octet] > 255 || $ip[$octet] =~ /^0[0-9]/ ) { print " REJECT: $_ contains an invalid octet.\n"; next ADDRESS } } #### check whitelist #### $checkip = $_; foreach $whitelisted ( @WHITELIST ) { chomp $whitelisted; if ( $checkip eq $whitelisted ) { print " REJECT: $checkip is whitelisted\n"; next ADDRESS } # perl bug, -w may generate "panic: pp_iter" } #### convert to DNS RR #### if ( ! $ip[3]) { $_ = "*.$ip[2].$ip[1].$ip[0]"; s/\.+/./; # delete sequential dots } else { $_ = "$ip[3].$ip[2].$ip[1].$ip[0]"; } #### cull duplicates #### $index{$_}++; } foreach (sort keys (%index) ) { #### A and TXT record #### printf TMPDB ("%-18s A 127.0.0.2\n", $_); printf TMPDB ("%-18s TXT \"$MESSAGE\"\n", $_); } close(SRCTXT); close(TMPDB); rename $TMPDB, $DSTDB; exec `/usr/bin/killall -1 named`;