I'm working on adding anti-hammering code to SurfShop to be able to 
temporarily ban visitors if they enter certain "keywords" into the query 
string, or if they repeatedly hammer the cart.  I've also set it up to be able 
to permanently block foreign IP's of the store owner's choosing.  Each 
country's IPs are in separate text files and the temp IPs are in another, so 
there could be quite a few files.  The temporary IPs also have a date 
associated with them, so they can be deleted later on.

        I decided to go with Net::Netmask for CIDR blocks but it's 
excruciatingly slow - it adds 2+ seconds to each page load in the cart.  That's 
a deal breaker.  If I remove the Net::Netmask section, the delay drops to about 
1 second per page, but that's still visibly slower than without this sub.

        So I got the idea to keep track of the last 10?, 30?, 50? good IP 
addresses and not process those again after the first visit.  The first page 
view gets the delay, but subsequent page speeds are normal.  I've included my 
code below and I'm wondering what the problem is.  Did I code something wrong?  
Did I choose the wrong module?  Perhaps I'm looking at this incorrectly.  Is 
there a better way to do what I'm after?

        The lines in the IP text files can be in any of these formats:

23.254.251.87
60.1.33.
41.96.0.0/12
11.22.33.44  2018-01-23

Thanks,
Frank



sub banned_ip_check($current_ip) {
  return unless $current_ip;
  my @ips = read_last_visitor_ips();  ## Last X visitors.
  foreach my $ip (@ips) {
     chomp $ip;
     return if $ip eq $current_ip;    ## Only check the IP on first visit.
  }
  my $t2 = Time::Piece->new();  ## Today's date to compare with saved date.
  my @files = File::Find::Rule->file()
                       ->name('*.txt')
                       ->in("${data_dir}/banned_ips");
  foreach my $ip_file (@files) {
     open (my $ip_fh, '<', $ip_file) || SSLib::error("Xtras::banned_ip_check: 
Can't open $ip_file");
     while (my $line = <$ip_fh>) {
        chomp $line;
        my ($ip, $date) = split (/\s/, $line);
        my $process = 'yes';
        if ($date =~ m/\d+/) {
           $t1 = Time::Piece->strptime($date, "%Y-%m-%d");
           if (($t2 - $t1) > 2_600_000) { $process = 'no' }
        }
        my $long = length($ip);
        my $found;
        if ($ip =~ m|/\d{2}$|) {
           ## CIDR IP Addresses
           my $block = Net::Netmask->new($ip);
           $found = 'yes' if $block->match($current_ip);
        }
        if ($found || $process eq 'yes' && substr($current_ip, 0, $long) eq 
$ip) {  ## Match partial IP's, too.
           deny_entry($current_ip, 'IP address', $ip_file);
        }
     }
     close ($ip_fh);
  }
}

--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to