summaryrefslogtreecommitdiffstats
path: root/etc/inc/util.inc
diff options
context:
space:
mode:
authorjim-p <jim@pingle.org>2010-03-07 16:37:02 -0500
committerjim-p <jim@pingle.org>2010-03-07 16:37:02 -0500
commitecd1f2d946abe16193e0ea62dbbdd6c87aa9b985 (patch)
treee94638d481a7a7932080a3d7053cf8351125b681 /etc/inc/util.inc
parentabfd0c9bcdf4b31d64983ea557de018afbcd720d (diff)
downloadpfsense-ecd1f2d946abe16193e0ea62dbbdd6c87aa9b985.zip
pfsense-ecd1f2d946abe16193e0ea62dbbdd6c87aa9b985.tar.gz
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.
Diffstat (limited to 'etc/inc/util.inc')
-rw-r--r--etc/inc/util.inc121
1 files changed, 121 insertions, 0 deletions
diff --git a/etc/inc/util.inc b/etc/inc/util.inc
index c289f37..7ae1eb8 100644
--- a/etc/inc/util.inc
+++ b/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);
}
OpenPOWER on IntegriCloud