#!/usr/bin/perl ########################################################### # txt2rhsbl # # Converts local host/domain blacklist to DNS RHSBL zone file # # Available from: # See also: ########################################################### ## $SRCTXT="/etc/spamdomains"; ## sender RHSBL $SRCTXT="/etc/spamhosts"; ## client RHSBL $DSTDB="/var/named/db.example.com.rhsbl"; $ZONE='rhsbl.example.com'; $MESSAGE="per "; $ZONENS='ns.example.com'; $ZONEADMIN='hostmaster.example.com'; $TTL=86400; $SERIALNO=20000730; @WHITELIST=('localhost','example.com','yahoo.com','google.com'); ########################################################### # to do: increment serial# for slave servers, # test zone file with nslint, # warning msg if duplicate, ... ########################################################### # $Id: txt2db_client,v 1.22 2007/10/19 15:10:17 $ ########################################################### $TMPDB="$DSTDB.tmp"; if ( ! -w $DSTDB ) { print " ERROR: $DSTDB not found or not writeable.\n"; exit 1; } elsif ( ! -s $SRCTXT ) { print " ERROR: missing or empty $SRCTXT.\n"; exit 1; } 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 1; } } 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") || \&Terminate(" Cannot create $TMPDB\n"); #### write zone file header #### print TMPDB <<"TAG"; \$TTL $TTL @ IN SOA $ZONENS. $ZONEADMIN. ( $SERIALNO 86400 43200 604800 $TTL ) IN NS ${ZONENS}. example.tld A 127.0.0.2 example.tld TXT "$MESSAGE for testing" *.example.tld A 127.0.0.2 *.example.tld TXT "$MESSAGE for testing" example.com A 127.0.0.2 example.com TXT "$MESSAGE for testing" *.example.com A 127.0.0.2 *.example.com TXT "$MESSAGE for testing" example.net A 127.0.0.2 example.net TXT "$MESSAGE for testing" *.example.net A 127.0.0.2 *.example.net TXT "$MESSAGE for testing" example.org A 127.0.0.2 example.org TXT "$MESSAGE for testing" *.example.org A 127.0.0.2 *.example.org TXT "$MESSAGE for testing" TAG open(SRCTXT, $SRCTXT)|| \&Terminate(" Cannot read $SRCTXT\n"); DOMAIN: foreach () { #### parse source file #### next DOMAIN if /(^#|^$|^\s)/; # ignore comments, nulls, start with space/tab next DOMAIN if /\s(HOLD|DISCARD|WARN|LOCAL)/; # skip local tags @line = split(/\s/, $_); # strip comments/tags tr/A-Z/a-z/; # to lower case $_ = $line[0]; chomp; s/^\.+//; # strip leading dots s/\.+$//; # and trailing dots #### validate FQDN syntax #### if ( /[^a-z0-9-\.]/ || /\.-/ || /-\./ || /---/ || /\.\./ || /^-/ || /-$/ ) { #### illegal chars, sequential dots/dashes, leading/trailing dashes print " REJECT: $_ is not a valid host or domain name.\n"; next DOMAIN } #### check whitelist #### $checkdom = $_; foreach $whitelisted ( @WHITELIST ) { chomp $whitelisted; if ( $checkdom =~ /^$whitelisted$/ ) { print " REJECT: $checkdom is whitelisted.\n"; next DOMAIN } # perl bug, -w may generate "panic: pp_iter" } #### cull duplicates #### $index{$_}++; } foreach (sort keys (%index) ) { #### domain and subdomain A and TXT record #### printf TMPDB ("%-42s A 127.0.0.2\n", $_); printf TMPDB ("%-42s TXT \"$MESSAGE\"\n", $_); printf TMPDB ("*.%-40s A 127.0.0.2\n", $_); printf TMPDB ("*.%-40s TXT \"$MESSAGE\"\n", $_); } close(SRCTXT); close(TMPDB); rename $TMPDB, $DSTDB || \&Terminate(" Cannot write $DSTDB\n"); exec `/usr/bin/killall -1 named`;