#!/usr/bin/perl -w # # jgreylist-clean # John Simpson 2006-08-21 # # 2006-11-26 jms1 - adding optional check to remove non-revisited entries # (i.e. an IP connects exactly one time and then gives up, much like a # zombie PC without any kind of "retry" would do) after a given length # of time. Thanks to Ron Miller for the suggestion. # # 2006-11-29 jms1 - keeping count of entries deleted for $max_age and # $one_age, so i can get a feel for how many IPs are actually zombies. # also making the list of what's deleted optional, use "-v" if you want # to see the full list, or "-q" if you want to see nothing at all (i.e. # no totals.) # ############################################################################### # # Copyright (C) 2006 John Simpson. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # or visit http://www.gnu.org/licenses/gpl.txt # ############################################################################### require 5.003 ; use strict ; use Getopt::Std ; ############################################################################### # # configuration # directory where entries are stored. # should be the same as $greydir in the "jgreylist" script. my $greydir = "/var/qmail/jgreylist" ; # if a client doesn't connect at all for this number of seconds, their # file is removed and they become "unknown" again. my $max_age = 30 * 24 * 60 * 60 ; # if a client only connected exactly one time, their file is removed # after this number of seconds and they become "unknown" again. # if set to zero, this check is not done. my $one_age = 24 * 60 * 60 ; ############################################################################### # # global variables my $now = time() ; my $nrf = 0 ; my $nof = 0 ; my $nkf = 0 ; my $do_show = 1 ; my ( @ent ) ; our ( $opt_q , $opt_d , $opt_v ) ; $| = 1 ; ############################################################################### # # output functions sub vdebug(@) { return unless ( $do_show > 2 ) ; print @_ ; } sub debug(@) { return unless ( $do_show > 1 ) ; print @_ ; } sub show(@) { return unless ( $do_show > 0 ) ; print @_ ; } ############################################################################### # # recursive function to "do the deed" sub rrmdir($) ; sub rrmdir($) { my $d = shift ; my $ec = 0 ; my ( $dh , @df ) ; vdebug "$d \r" ; unless ( opendir ( $dh , "$d" ) ) { print "$d: opendir() failed: $!\n" ; return 0 ; } while ( my $f = readdir $dh ) { next if ( $f =~ /^\.\.?$/ ) ; push ( @df , $f ) ; } close $dh ; for my $f ( sort @df ) { if ( -d "$d/$f" ) { $ec += rrmdir ( "$d/$f" ) ; } elsif ( -f "$d/$f" ) { my @s = stat ( "$d/$f" ) ; if ( ( $now - $s[8] ) > $max_age ) { if ( unlink ( "$d/$f" ) ) { debug "$d/$f: removed\n" ; $nrf ++ ; } else { print "$d/$f: unlink(): $!\n" ; $ec ++ ; } } elsif ( $one_age && ( $s[8] == $s[9] ) && ( ( $now - $s[8] ) > $one_age ) ) { if ( unlink ( "$d/$f" ) ) { debug "$d/$f: removed\n" ; $nof ++ ; } else { print "$d/$f: unlink(): $!\n" ; $ec ++ ; } } else { $nkf ++ ; $ec ++ ; } } else { $ec ++ ; } } close $dh ; if ( 0 == $ec ) { if ( rmdir ( $d ) ) { debug "$d: removed\n" ; } else { print "$d: rmdir() failed: $!\n" ; $ec ++ ; } } return $ec ; } ############################################################################### ############################################################################### ############################################################################### # # the magic starts here getopts ( "qdv" ) ; if ( $opt_q ) { $do_show = 0 ; } if ( $opt_d ) { $do_show = 2 ; } if ( $opt_v ) { $do_show = 3 ; } opendir ( D , $greydir ) or die "opendir($greydir) failed: $!\n" ; while ( my $e = readdir D ) { next if ( $e =~ /^\.\.?$/ ) ; push ( @ent , $e ) ; } close D ; for my $e ( sort @ent ) { if ( -d "$greydir/$e" ) { rrmdir ( "$greydir/$e" ) ; } } show sprintf ( "Removed %8d max_age entries \n" , $nrf ) ; if ( $one_age ) { show sprintf ( "Removed %8d one-time entries\n" , $nof ) ; } show sprintf ( "Kept %8d entries\n" , $nkf ) ;