mirror of
https://github.com/pfsense/pfsense.git
synced 2025-10-26 11:38:35 +00:00
Adding support for using IP ranges aliases. If you input an IP Range such as 192.168.0.1-192.168.0.254, it will instead turn that into a number of CIDR networks which will completely fill the range.
This commit is contained in:
parent
abfd0c9bcd
commit
ecd1f2d946
121
etc/inc/util.inc
121
etc/inc/util.inc
@ -181,6 +181,127 @@ function gen_subnet_mask($bits) {
|
||||
return long2ip(gen_subnet_mask_long($bits));
|
||||
}
|
||||
|
||||
/* Convert IP address to unsigned long int. */
|
||||
function ip2ulong($ip) {
|
||||
return sprintf("%u", ip2long($ip));
|
||||
}
|
||||
|
||||
/* Find out how many IPs are contained within a given IP range
|
||||
* e.g. 192.168.0.0 to 192.168.0.255 returns 256
|
||||
*/
|
||||
function ip_range_size($startip, $endip) {
|
||||
if (is_ipaddr($startip) && is_ipaddr($endip)) {
|
||||
// Operate as unsigned long because otherwise it wouldn't work
|
||||
// when crossing over from 127.255.255.255 / 128.0.0.0 barrier
|
||||
return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Find the smallest possible subnet mask which can contain a given number of IPs
|
||||
* e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
|
||||
*/
|
||||
function find_smallest_cidr($number) {
|
||||
$smallest = 1;
|
||||
for ($b=32; $b > 0; $b--) {
|
||||
$smallest = ($number <= pow(2,$b)) ? $b : $smallest;
|
||||
}
|
||||
return (32-$smallest);
|
||||
}
|
||||
|
||||
/* Return the previous IP address before the given address */
|
||||
function ip_before($ip) {
|
||||
return long2ip(ip2long($ip)-1);
|
||||
}
|
||||
|
||||
/* Return the next IP address after the given address */
|
||||
function ip_after($ip) {
|
||||
return long2ip(ip2long($ip)+1);
|
||||
}
|
||||
|
||||
/* Return true if the first IP is 'before' the second */
|
||||
function ip_less_than($ip1, $ip2) {
|
||||
// Compare as unsigned long because otherwise it wouldn't work when
|
||||
// crossing over from 127.255.255.255 / 128.0.0.0 barrier
|
||||
return ip2ulong($ip1) < ip2ulong($ip2);
|
||||
}
|
||||
|
||||
/* Return true if the first IP is 'after' the second */
|
||||
function ip_greater_than($ip1, $ip2) {
|
||||
// Compare as unsigned long because otherwise it wouldn't work
|
||||
// when crossing over from 127.255.255.255 / 128.0.0.0 barrier
|
||||
return ip2ulong($ip1) > ip2ulong($ip2);
|
||||
}
|
||||
|
||||
/* Convert a range of IPs to an array of subnets which can contain the range. */
|
||||
function ip_range_to_subnet_array($startip, $endip) {
|
||||
if (!is_ipaddr($startip) || !is_ipaddr($endip)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// Container for subnets within this range.
|
||||
$rangesubnets = array();
|
||||
|
||||
// Figure out what the smallest subnet is that holds the number of IPs in the given range.
|
||||
$cidr = find_smallest_cidr(ip_range_size($startip, $endip));
|
||||
|
||||
// Loop here to reduce subnet size and retest as needed. We need to make sure
|
||||
// that the target subnet is wholly contained between $startip and $endip.
|
||||
for ($cidr; $cidr <= 32; $cidr++) {
|
||||
// Find the network and broadcast addresses for the subnet being tested.
|
||||
$targetsub_min = gen_subnet($startip, $cidr);
|
||||
$targetsub_max = gen_subnet_max($startip, $cidr);
|
||||
|
||||
// Check best case where the range is exactly one subnet.
|
||||
if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
|
||||
// Hooray, the range is exactly this subnet!
|
||||
return array("{$startip}/{$cidr}");
|
||||
}
|
||||
|
||||
// These remaining scenarios will find a subnet that uses the largest
|
||||
// chunk possible of the range being tested, and leave the rest to be
|
||||
// tested recursively after the loop.
|
||||
|
||||
// Check if the subnet begins with $startip and ends before $endip
|
||||
if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if the subnet ends at $endip and starts after $startip
|
||||
if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if the subnet is between $startip and $endip
|
||||
if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Some logic that will recursivly search from $startip to the first IP before the start of the subnet we just found.
|
||||
// NOTE: This may never be hit, the way the above algo turned out, but is left for completeness.
|
||||
if ($startip != $targetsub_min) {
|
||||
$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array($startip, ip_before($targetsub_min)));
|
||||
}
|
||||
|
||||
// Add in the subnet we found before, to preserve ordering
|
||||
$rangesubnets[] = "{$targetsub_min}/{$cidr}";
|
||||
|
||||
// And some more logic that will search after the subnet we found to fill in to the end of the range.
|
||||
if ($endip != $targetsub_max) {
|
||||
$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
|
||||
}
|
||||
return $rangesubnets;
|
||||
}
|
||||
|
||||
function is_iprange($range) {
|
||||
if (substr_count($range, '-') != 1) {
|
||||
return false;
|
||||
}
|
||||
list($ip1, $ip2) = explode ('-', $range);
|
||||
return (is_ipaddr($ip1) && is_ipaddr($ip2));
|
||||
}
|
||||
|
||||
function is_numericint($arg) {
|
||||
return (preg_match("/[^0-9]/", $arg) ? false : true);
|
||||
}
|
||||
|
||||
@ -221,20 +221,25 @@ if ($_POST) {
|
||||
$wrongaliases = "";
|
||||
for($x=0; $x<4999; $x++) {
|
||||
if($_POST["address{$x}"] <> "") {
|
||||
$count = 0;
|
||||
if ($isfirst > 0)
|
||||
$address .= " ";
|
||||
$address .= $_POST["address{$x}"];
|
||||
if(($_POST['type'] == "network" || is_ipaddr($_POST["address{$x}"])) && $_POST["address_subnet{$x}"] <> "")
|
||||
$address .= "/" . $_POST["address_subnet{$x}"];
|
||||
|
||||
if($_POST["detail{$x}"] <> "") {
|
||||
$final_address_details .= $_POST["detail{$x}"];
|
||||
} else {
|
||||
$final_address_details .= "Entry added" . " ";
|
||||
$final_address_details .= date('r');
|
||||
}
|
||||
$final_address_details .= "||";
|
||||
$isfirst++;
|
||||
if (is_iprange($_POST["address{$x}"])) {
|
||||
list($startip, $endip) = explode('-', $_POST["address{$x}"]);
|
||||
$rangesubnets = ip_range_to_subnet_array($startip, $endip);
|
||||
$count = count($rangesubnets);
|
||||
$address .= implode($rangesubnets, ' ');
|
||||
} else {
|
||||
$address .= $_POST["address{$x}"];
|
||||
if(($_POST['type'] == "network" || is_ipaddr($_POST["address{$x}"])) && $_POST["address_subnet{$x}"] <> "")
|
||||
$address .= "/" . $_POST["address_subnet{$x}"];
|
||||
}
|
||||
if($_POST["detail{$x}"] <> "") {
|
||||
$final_address_details .= str_repeat($_POST["detail{$x}"] . "||", $count);
|
||||
} else {
|
||||
$final_address_details .= str_repeat("Entry added " . date('r') . "||", $count);
|
||||
}
|
||||
$isfirst += $count;
|
||||
|
||||
if (is_alias($_POST["address{$x}"])) {
|
||||
if (!alias_same_type($_POST["address{$x}"], $_POST['type']))
|
||||
@ -243,7 +248,9 @@ if ($_POST) {
|
||||
if (!is_port($_POST["address{$x}"]))
|
||||
$input_errors[] = $_POST["address{$x}"] . " is not a valid port or alias.";
|
||||
} else if ($_POST['type'] == "host" || $_POST['type'] == "network") {
|
||||
if (!is_ipaddr($_POST["address{$x}"]) && !is_hostname($_POST["address{$x}"]))
|
||||
if (!is_ipaddr($_POST["address{$x}"])
|
||||
&& !is_hostname($_POST["address{$x}"])
|
||||
&& !is_iprange($_POST["address{$x}"]))
|
||||
$input_errors[] = $_POST["address{$x}"] . " is not a valid {$_POST['type']} alias.";
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user