Forum Moderators: coopster

Message Too Old, No Replies

needed: script to convert IP range to regexp

         

bull

3:29 pm on May 5, 2005 (gmt 0)

10+ Year Member



If anyone had an idea to convert any IP range to a .htaccess readable RewriteCond line, I'd be very thankful. I already found a perl script at [info.ccone.at...] , but I do not understand it.

ironik

11:05 pm on May 5, 2005 (gmt 0)

10+ Year Member



This function should give you what you need, although it is untested. You'll need to pair it with a rewrite rule to tell it what to do when the IP range condition is met (re-direct, rewrite or whatever...)


<?php
/**
* Convert an 4 set IP range to a apache rewrite cond. Must be paired with
* a rewrite rule.
* @access public
* @param int Any number of integer parameters
* @return string an IP address condition
*/
function get_IP_range_rule()
{
$args = func_get_args();
$numArgs = func_num_args();

foreach ($args as $arg)
{
if (!is_numeric($arg))
{
return null;
}
}

$rule = 'RewriteCond %{REMOTE_ADDR} ^' . implode('\\.', $args);

if ($numArgs < 4)
{
$remainder = $numArgs % 4;
$rule .= '(\\.[0-9]{1,3}){,' . $numArgs . '}';
}

return $rule;
}

// Examples
$rule = get_IP_range_rule(127, 0);
echo $rule; // Outputs: RewriteCond %{REMOTE_ADDR} ^127\.0(\.[0-9]{1,3}){,2}

$rule2 = get_IP_range_rule(127, 0, 0, 1);
echo $rule2; // Outputs: RewriteCond %{REMOTE_ADDR} ^127\.0\.0\.1
?>

Let us know if that works

bull

10:24 am on May 6, 2005 (gmt 0)

10+ Year Member



mmh, this did not work as desired, as the ranges are not always whole IP blocks. I'll show you the code I currently have, and you'll see immediately the problem:

function ip2octets($ip)
{
$ip2 = long2ip($ip);
$octets = explode(".", $ip2);
return $octets;
}

//-----------------------

function ipRegex($ip_start, $ip_end, $ia_start, $ia_end)
{
$the_cond = "RewriteCond %{REMOTE_ADDR} ^";
$i = 0;

while($i < 3 && ($ia_start[$i] == $ia_end[$i]) )
{
$the_cond .= $ia_start[$i];
$the_cond .= "\\.";
$i++;
}

if($ia_start[$i] == 0 && $ia_end[$i] == 31)
{
$the_cond .= "([0-9]¦[1-2][0-9]¦3[0-2])";
}
else if($ia_start[$i] == 32 && $ia_end[$i] == 63)
{
$the_cond .= "(3[0-2]¦[4-5][0-9]¦6[0-3])";
}
else if($ia_start[$i] == 0 && $ia_end[$i] == 63)
{
$the_cond .= "([0-9]¦[1-5][0-9]¦6[0-3])";
}
else if($ia_start[$i] == 0 && $ia_end[$i] == 127)
{
$the_cond .= "([1-9]?[0-9]¦1[0-1][0-9]¦12[0-7])";
}
else if($ia_start[$i] == 63 && $ia_end[$i] == 127)
{
$the_cond .= "(6[3-9]¦[7-9][0-9]¦1[0-1][0-9]¦12[0-7])";
}
else if($ia_start[$i] == 128 && $ia_end[$i] == 191)
{
$the_cond .= "(12[8-9]¦1[3-8][0-9]¦19[0-1])";
}
else if($ia_start[$i] == 128 && $ia_end[$i] == 255)
{
$the_cond .= "(12[8-9]¦1[3-9][0-9]¦2[0-5][0-9])";
}
else if($ia_start[$i] == 192 && $ia_end[$i] == 255)
{
$the_cond .= "(19[2-9]¦2[0-5][0-9])";
}
else
{
// here is the problem
// a range e.g. from 111.222.5.0 to 111.222.111.255 is not covered by the above conds
}

$the_cond .= " [OR]\r\n";
return $the_cond;
}

//-----------------------------------------------------------

for($i = 0; $i < $rows; $i++)
{
$ra = mysql_fetch_row($cli);
$ipstart = $ra[0]; // as long
$ipend = $ra[1]; // as long
if($ipstart == $ipend) // single address
{
$ipascii = long2ip($ipstart);
$deny .= "deny from $ipascii\r\n";
}
else // ip range
{
print "# range " . long2ip ($ipstart) . " - " . long2ip ($ipend) . "\r\n";

$ia_start = ip2octets($ipstart);
$ia_end = ip2octets($ipend);
$j = 0;
while($j < 3 && ($ia_start[$j] == $ia_end[$j]) )
{ $j++; }

if($ia_start[$j] == 0 && $ia_end[$j] == 255) // whole block?
{
$deny .= "deny from ";
for($k = 0; $k < $j; $k++)
{ $deny .= $ia_start[$k] . "."; }
$deny .= "\r\n";
}
else // partial block!
{
$ipr = ipRegex($ipstart, $ipend, $ia_start, $ia_end);
$ipconds .= $ipr;
}
}
}

bull

10:28 am on May 6, 2005 (gmt 0)

10+ Year Member



The problem when to deny (it's all about denying "evil" IPs and ranges) a range like 111.222.5.0 to 111.222.111.255 . I'd have to check which boundaries (10, 100) are crossed and then count up, giving a bunch of "if" I'd like to avid for speed reasons.