[interchange-cvs] interchange - pajamian modified 5 files

interchange-cvs at icdevgroup.org interchange-cvs at icdevgroup.org
Thu Jul 5 07:19:44 EDT 2007


User:      pajamian
Date:      2007-07-05 11:19:43 GMT
Modified:  .        UPGRADE WHATSNEW-5.5
Modified:  lib/Vend Dispatch.pm Session.pm Util.pm
Log:
This patch makes the following changes to sessions per IP limit protection:

* There are now seperate settings for the amount of time allowed to trigger a
	lockout and the amount of time a lockout lasts for.

* Lockouts are now triggered based on new sessions per time limit, which is
	different from the old critera of new sessions between pauses of length
	time.  This means that if RobotLimit is set to 100 and the other
	settings were left at thier defaults then a 24 hour lockout would be
	triggered if a given IP address had 100 new sessions in any given 60
	minute time period.

Settings used by this patch:

RobotLimit: Used to determine the number of new sessions required to trigger a
	lockout.  Default is 0 which disables this feature alltogether.

Limit robot_expire: Used to determine the amount of time a lockout will last
	in days once triggered.  Can be less than 1, for example 0.04 is
	slightly less than an hour.  Default is 1.

Limit ip_session_expire: Used to determine the length of time in minutes for
	RobotLimit sessions to build up in the counter file and trigger a
	lockout.  Default is 60 (1 hour).  This can also be set to fractional
	numbers, for example 0.5 will allow 30 seconds.

Also make note of the following:

* When first implementing you should delete all the old counters with:
	rm -rf catroot/tmp/addr_ctr/*
...be careful with the above command, if mistyped it can seriously mess up
your filesystem.

* Shell command to view the contents of one of the binary new counter files:

	perl -e 'binmode STDIN;' -e '$/=undef;' -e '$_ = <STDIN>;' \
	-e 's/(.{4})/localtime(unpack("N",$1))."\n"/seg;' \
	-e 'print;' < 0_0_0_0

...where 0_0_0_0 is the filename of the binary counter.  The command will
show you a list of timestamps in human readable form.

Revision  Changes    Path
2.20      +7 -0      interchange/UPGRADE


rev 2.20, prev_rev 2.19
Index: UPGRADE
===================================================================
RCS file: /var/cvs/interchange/UPGRADE,v
retrieving revision 2.19
retrieving revision 2.20
diff -u -r2.19 -r2.20
--- UPGRADE	24 May 2007 19:56:38 -0000	2.19
+++ UPGRADE	5 Jul 2007 11:19:41 -0000	2.20
@@ -116,6 +116,13 @@
 need to remove any existing *Robot* directives from your interchange.cfg
 file and add "include robots.cfg" in their place.
 
+The session per IP counters have been changed to the new "timecard" round-robin
+style counters.  You will need to delete the old counter files from the
+tmp/addr_ctr directory with a command similar to the following:
+	rm -rf catroot/tmp/addr_ctr/*
+...be careful with the above command, if mistyped it can seriously mess up
+your filesystem.
+
 
 KNOWN ISSUES UPGRADING FROM 5.2.x
 



1.34      +5 -0      interchange/WHATSNEW-5.5


rev 1.34, prev_rev 1.33
Index: WHATSNEW-5.5
===================================================================
RCS file: /var/cvs/interchange/WHATSNEW-5.5,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -r1.33 -r1.34
--- WHATSNEW-5.5	4 May 2007 19:23:00 -0000	1.33
+++ WHATSNEW-5.5	5 Jul 2007 11:19:41 -0000	1.34
@@ -60,6 +60,11 @@
   from last_sequence_value() for returning even if we already know the key and
   even on an UPDATE which can cause problems.
 
+* New "timecard" round-robin style counters added with the timecard_stamp and
+  timecard_read subs in Util.pm.  These are now used for better control of the
+  session per IP lockouts (when RobotLimit is set).  See CVS log for more
+  details.
+
 UserDB
 ------
 



1.79      +20 -22    interchange/lib/Vend/Dispatch.pm


rev 1.79, prev_rev 1.78
Index: Dispatch.pm
===================================================================
RCS file: /var/cvs/interchange/lib/Vend/Dispatch.pm,v
retrieving revision 1.78
retrieving revision 1.79
diff -u -r1.78 -r1.79
--- Dispatch.pm	3 Jul 2007 05:48:37 -0000	1.78
+++ Dispatch.pm	5 Jul 2007 11:19:42 -0000	1.79
@@ -1,6 +1,6 @@
 # Vend::Dispatch - Handle Interchange page requests
 #
-# $Id: Dispatch.pm,v 1.78 2007/07/03 05:48:37 jon Exp $
+# $Id: Dispatch.pm,v 1.79 2007/07/05 11:19:42 pajamian Exp $
 #
 # Copyright (C) 2002-2006 Interchange Development Group
 # Copyright (C) 2002 Mike Heins <mike at perusion.net>
@@ -26,7 +26,7 @@
 package Vend::Dispatch;
 
 use vars qw($VERSION);
-$VERSION = substr(q$Revision: 1.78 $, 10);
+$VERSION = substr(q$Revision: 1.79 $, 10);
 
 use POSIX qw(strftime);
 use Vend::Util;
@@ -1368,34 +1368,32 @@
 				}
 			}
 		}
-    }
-	else {
-		if($Vend::Cfg->{RobotLimit}) {
-			if (Vend::Session::count_ip() > $Vend::Cfg->{RobotLimit}) {
-				my $msg;
-				# Here they can get it back if they pass expiration time
-				my $wait = $::Limit->{robot_expire} || 1;
-				$wait *= 24;
-				$msg = errmsg(<<EOF, $wait); 
+	} else {
+	    if (Vend::Session::count_ip()) {
+		my $msg;
+		# Here they can get it back if they pass expiration time
+		my $wait = $::Limit->{robot_expire} || 1;
+		$wait *= 24;
+		$msg = errmsg(<<EOF, $wait); 
 Too many new ID assignments for this IP address. Please wait at least %d hours
 before trying again. Only waiting that period will allow access. Terminating.
 EOF
-				$msg = get_locale_message(403, $msg);
-				do_lockout();
+		$msg = get_locale_message(403, $msg);
+		do_lockout();
 
-				::logError('Too many IDs, %d hour wait enforced.', $wait);
+		::logError('Too many IDs, %d hour wait enforced.', $wait);
 
-				$Vend::StatusLine = <<EOF;
+		$Vend::StatusLine = <<EOF;
 Status: 403 Forbidden
 Content-Type: text/plain
 EOF
-					response($msg);
-					close_cat();
-					return;
-			}
-		}
-		new_session();
-    }
+		response($msg);
+		close_cat();
+		return;
+	    }
+	    new_session();
+	}
+
 }
 
 #::logDebug("session name='$Vend::SessionName'\n");



2.29      +64 -18    interchange/lib/Vend/Session.pm


rev 2.29, prev_rev 2.28
Index: Session.pm
===================================================================
RCS file: /var/cvs/interchange/lib/Vend/Session.pm,v
retrieving revision 2.28
retrieving revision 2.29
diff -u -r2.28 -r2.29
--- Session.pm	30 Mar 2007 11:39:45 -0000	2.28
+++ Session.pm	5 Jul 2007 11:19:42 -0000	2.29
@@ -1,6 +1,6 @@
 # Vend::Session - Interchange session routines
 #
-# $Id: Session.pm,v 2.28 2007/03/30 11:39:45 pajamian Exp $
+# $Id: Session.pm,v 2.29 2007/07/05 11:19:42 pajamian Exp $
 # 
 # Copyright (C) 2002-2006 Interchange Development Group
 # Copyright (C) 1996-2002 Red Hat, Inc.
@@ -27,7 +27,7 @@
 require Exporter;
 
 use vars qw($VERSION);
-$VERSION = substr(q$Revision: 2.28 $, 10);
+$VERSION = substr(q$Revision: 2.29 $, 10);
 
 @ISA = qw(Exporter);
 
@@ -195,22 +195,68 @@
 }
 
 sub count_ip {
-	my $inc = shift;
-	my $ip = $CGI::remote_addr;
-	$ip =~ s/\W/_/g;
-	my $dir = "$Vend::Cfg->{ScratchDir}/addr_ctr";
-	my $fn = Vend::Util::get_filename($ip, 2, 1, $dir);
-	if(-f $fn) {
-		my $grace = $::Limit->{robot_expire} || 1;
-		my @st = stat(_);
-		my $mtime = (time() - $st[9]) / 86400;
-		if($mtime > $grace) {
-			::logDebug("ip $ip allowed back in due to '$mtime' > '$grace' days");
-			unlink $fn;
-		}
-	}
-	return Vend::CounterFile->new($fn)->inc() if $inc;
-	return Vend::CounterFile->new($fn)->value();
+        my ($inc) = @_;
+
+        # Immediate return if RobotLimit is not defined
+	my $index = $Vend::Cfg->{RobotLimit} or return 0;
+	$index *= -1;
+
+
+        my $ip = $CGI::remote_addr;
+        $ip =~ s/\W/_/g;
+
+        my $dir = "$Vend::Cfg->{ScratchDir}/addr_ctr";
+        my $fn = Vend::Util::get_filename($ip, 2, 1, $dir);
+
+
+        # Unlink the "counter" file if applicable.
+
+        if(-f $fn) {
+                my $grace = $::Limit->{ip_session_expire} || 60;
+                my @st = stat(_);
+                my $mtime = (time() - $st[9]) / 60;
+                if($mtime > $grace) {
+#::logDebug("ip $ip session limit expired due to '$mtime' > '$grace' minutes");
+                    unlink $fn;
+                }
+        }
+
+        my $lfn = $fn . '.lockout';
+
+
+        # Unlink the lockout file if applicable, otherwise lock.
+
+        if(-f $lfn) {
+                my $grace = $::Limit->{robot_expire} || 1;
+                my @st = stat(_);
+                my $mtime = (time() - $st[9]) / 86400;
+                if($mtime > $grace) {
+#::logDebug("ip $ip allowed back in due to '$mtime' > '$grace' days");
+                        unlink $lfn;
+                } else {
+                        return 1;
+                }
+        }
+
+
+        # Append a new timestamp to the counter file (if applicable)
+
+	timecard_stamp($fn) if $inc;
+
+
+	# Get timestamp from timecard file and see if it's expired yet.
+
+	my $rtime;
+	return 0 unless $rtime = timecard_read($fn, $index);
+	my $grace = $::Limit->{ip_session_expire} || 60;
+	return 0 if time - $rtime > $grace * 60;
+
+#::logDebug("ip $ip locked out due to too many new sessions in the last $grace minutes");
+	# Create the lockout file
+	open(FH, '>', $lfn) or die "Can't create $lfn: $!";
+	close FH;
+
+	return 1;
 }
 
 sub is_retired {



2.106     +54 -2     interchange/lib/Vend/Util.pm


rev 2.106, prev_rev 2.105
Index: Util.pm
===================================================================
RCS file: /var/cvs/interchange/lib/Vend/Util.pm,v
retrieving revision 2.105
retrieving revision 2.106
diff -u -r2.105 -r2.106
--- Util.pm	5 Jul 2007 10:01:25 -0000	2.105
+++ Util.pm	5 Jul 2007 11:19:42 -0000	2.106
@@ -1,6 +1,6 @@
 # Vend::Util - Interchange utility functions
 #
-# $Id: Util.pm,v 2.105 2007/07/05 10:01:25 racke Exp $
+# $Id: Util.pm,v 2.106 2007/07/05 11:19:42 pajamian Exp $
 # 
 # Copyright (C) 2002-2007 Interchange Development Group
 # Copyright (C) 1996-2002 Red Hat, Inc.
@@ -69,6 +69,8 @@
 	show_times
 	string_to_ref
 	tag_nitems
+	timecard_stamp
+	timecard_read
 	uneval
 	uneval_it
 	uneval_fast
@@ -88,7 +90,7 @@
 use Vend::File;
 use subs qw(logError logGlobal);
 use vars qw($VERSION @EXPORT @EXPORT_OK);
-$VERSION = substr(q$Revision: 2.105 $, 10);
+$VERSION = substr(q$Revision: 2.106 $, 10);
 
 my $Eval_routine;
 my $Eval_routine_file;
@@ -2193,6 +2195,56 @@
 	}
 	return \@out;
 }
+
+
+# Adds a timestamp to the end of a binary timecard file. You can specify the timestamp
+# as the second arg (unixtime) or just leave it out (or undefined) and it will be set
+# to the current time.
+sub timecard_stamp {
+	my ($filename,$timestamp) = @_;
+	$timestamp ||= time;
+
+	open(FH, '>>', $filename) or die "Can't open $filename for append: $!";
+	lockfile(\*FH, 1, 1);
+	binmode FH;
+	print FH pack('N',time);
+	unlockfile(\*FH);
+	close FH;
+}
+
+
+# Reads a timestamp from a binary timecard file.  If $index is negative indexes back from
+# the end of the file, otherwise indexes from the front of the file so that 0 is the first
+# (oldest) timestamp and -1 the last (most recent). Returns the timestamp or undefined if
+# the file doesn't exist or the index falls outside of the bounds of the timecard file.
+sub timecard_read {
+	my ($filename,$index) = @_;
+	$index *= 4;
+	my $limit = $index >= 0 ? $index + 4 : $index * -1;
+
+	if (-f $filename && (stat(_))[7] % 4) {
+	    # The file is corrupt, delete it and start over.
+	    ::logError("Counter file $filename found to be corrupt, deleting.");
+	    unlink($filename);
+	    return;
+	}
+	return unless (-f _ && (stat(_))[7] > $limit);
+
+	# The file exists and is big enough to cover the $index. Seek to the $index
+	# and return the timestamp from that position.
+
+	open (FH, '<', $filename) or die "Can't open $filename for read: $!";
+	lockfile(\*FH, 0, 1);
+	binmode FH;
+	seek(FH, $index, $index >= 0 ? 0 : 2) or die "Can't seek $filename to $index: $!";
+	my $rtime;
+	read(FH,$rtime,4) or die "Can't read from $filename: $!";
+	unlockfile(\*FH);
+	close FH;
+
+	return unpack('N',$rtime);
+}
+
 
 ### Provide stubs for former Vend::Util functions relocated to Vend::File
 *canonpath = \&Vend::File::canonpath;








More information about the interchange-cvs mailing list