Description: Validate based on whether $ENV{REMOTE_ADDR} is present in a list of IP's or in the IP ranges listed in CIDR notation. Real-world application was within a subfunction, used to restrict signup for an email account.

use CGI; 
use Net::CIDR;

open ACL, "< /usr/local/atmail/ACL.txt";

my (@ACL, @CIDRs, $entry, $entry1, $offset, $offset1, $ip, $found);

# Create an array of the entries from the list file
    push(@ACL, $_);

# Push the CIDR's into an array and undef them (avoiding splice() prob
+lems with the foreach and offset) in @ACL so they can be easily remov
+ed later...
foreach $entry (@ACL){
        if ($entry =~ /(\d{1,3}\.){3}\d+\//){
        push(@CIDRs, $entry);
        undef $ACL[$offset];

# Anything left in the list that's not an IP gets whacked
foreach $entry1 (@ACL){
        if (!(Net::CIDR::cidrvalidate($entry1))){
                undef $ACL[$offset1];

# Iterate ACL, finishing up if the IP in the HTTP request can be found
+ in any of the CIDRs or if it matches the current IP in the list.
foreach $ip (@ACL){
    chomp $ip;
    if ($ENV{REMOTE_ADDR} eq "$ip" || Net::CIDR::cidrlookup($ENV{REMOT
+E_ADDR}, @CIDRs)){
        $found = 1;

# If your IP is allowed,  do nothing.  If not,  display error message.
if ($found){
print "Content-Type: text/html\n\n";
Replies are listed 'Best First'.
Re: CGI: Validate access based on IP - with CIDR support
by runrig (Abbot) on Feb 11, 2005 at 21:03 UTC
    You could also do this with Net::CIDR::Lite, which might be worthwhile if you have alot of cidr addresses. You can not currently serialize the Net::CIDR::Lite object (I've been thinking of adding store/retrieve or freeze/thaw methods), but if you could, then it might be better than reading in the file every time (patches welcome!). Of course, if your method works, and works well enough, then no need to go to the trouble of changing... :-)
      Thanks for the reply! I hear you about the freeze/thaw methods - good idea. I thought that Net::CIDR::Lite had no equivalent to Net::CIDR::cidrlookup() - or does it? That's why I went with Net::CIDR, anyway.

      Any other comments are most welcome! Thanks again :-)
        I thought that Net::CIDR::Lite had no equivalent to Net::CIDR::cidrlookup()

        The 'find' method would do that. You would add all ip's and cidr addresses to the object, then do find()'s to see if an ip is within any of those ip's or cidr ranges.