develooper Front page | perl.beginners | Postings from January 2018

Banning IP's with Net::Netmask

Thread Next
From:
SurfShop
Date:
January 23, 2018 22:38
Subject:
Banning IP's with Net::Netmask
Message ID:
0A604EB9-53F2-4088-9ABE-041D959FEA7E@surfshopcart.com
	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);
  }
}

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About