commit 5050b79277d1f5944d786d63699feda013179c5b
Author: Phil Davis <phil.davis@inf.org>
Date:   Sun Jan 22 14:13:50 2017 +0545

    Always force compress when calling Net_IPv6
    
    (cherry picked from commit 587995fb57f91894d1f8eb6b296a9fe2fa111fac)

diff --git a/src/etc/inc/interfaces.inc b/src/etc/inc/interfaces.inc
index 7a08fc2a5b..cd2710f64b 100644
--- a/src/etc/inc/interfaces.inc
+++ b/src/etc/inc/interfaces.inc
@@ -3850,7 +3850,7 @@ function interface_6to4_configure($interface = "wan", $wancfg) {
 	foreach ($stfbrbinarr as $bin) {
 		$stfbrarr[] = dechex(bindec($bin));
 	}
-	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
+	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
 
 	/* convert the 128 bits for the broker address back into a valid IPv6 address */
 	$stflanarr = array();
@@ -3859,9 +3859,9 @@ function interface_6to4_configure($interface = "wan", $wancfg) {
 	foreach ($stflanbinarr as $bin) {
 		$stflanarr[] = dechex(bindec($bin));
 	}
-	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
+	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
 	$stflanarr[7] = 1;
-	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
+	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
 
 	/* setup the stf interface */
 	if (!is_module_loaded("if_stf")) {
diff --git a/src/etc/inc/ipsec.inc b/src/etc/inc/ipsec.inc
index faa4cabf22..2d02ff6d40 100644
--- a/src/etc/inc/ipsec.inc
+++ b/src/etc/inc/ipsec.inc
@@ -746,7 +746,7 @@ function ipsec_get_phase1($ikeid) {
 
 function ipsec_fixup_ip($ipaddr) {
 	if (is_ipaddrv6($ipaddr) || is_subnetv6($ipaddr)) {
-		return Net_IPv6::compress(Net_IPv6::uncompress($ipaddr));
+		return text_to_compressed_ip6($ipaddr);
 	} else {
 		return $ipaddr;
 	}
diff --git a/src/etc/inc/openvpn.inc b/src/etc/inc/openvpn.inc
index 2e80d70b83..ff3ab16676 100644
--- a/src/etc/inc/openvpn.inc
+++ b/src/etc/inc/openvpn.inc
@@ -1749,8 +1749,8 @@ function openvpn_get_interface_ipv6($ipv6, $prefix) {
 	// Is there a better way to do this math?
 	$ipv6_arr = explode(':', $basev6);
 	$last = hexdec(array_pop($ipv6_arr));
-	$ipv6_1 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 1)));
-	$ipv6_2 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 2)));
+	$ipv6_1 = text_to_compressed_ip6(implode(':', $ipv6_arr) . ':' . dechex($last + 1));
+	$ipv6_2 = text_to_compressed_ip6(implode(':', $ipv6_arr) . ':' . dechex($last + 2));
 	return array($ipv6_1, $ipv6_2);
 }
 
diff --git a/src/etc/inc/pfsense-utils.inc b/src/etc/inc/pfsense-utils.inc
index 1df790bf90..4e002b29e0 100644
--- a/src/etc/inc/pfsense-utils.inc
+++ b/src/etc/inc/pfsense-utils.inc
@@ -3135,7 +3135,7 @@ function convert_128bit_to_ipv6($ip6bin) {
 	foreach ($ip6binarr as $binpart) {
 		$ip6arr[] = dechex(bindec($binpart));
 	}
-	$ip6addr = Net_IPv6::compress(implode(":", $ip6arr));
+	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
 
 	return($ip6addr);
 }
@@ -3217,7 +3217,7 @@ function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
 		break;
 	}
 
-	return Net_IPv6::compress(substr($prefix, 0, $prefix_len) .
+	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
 	    substr($suffix, $prefix_len));
 }
 
diff --git a/src/etc/inc/util.inc b/src/etc/inc/util.inc
index 665806d202..3e8a9484f8 100644
--- a/src/etc/inc/util.inc
+++ b/src/etc/inc/util.inc
@@ -373,7 +373,7 @@ function gen_subnetv4($ipaddr, $bits) {
 /* same as gen_subnet() but accepts IPv6 only */
 function gen_subnetv6($ipaddr, $bits) {
 	if (is_ipaddrv6($ipaddr) && is_numericint($bits) && $bits <= 128) {
-		return Net_IPv6::compress(Net_IPv6::getNetmask($ipaddr, $bits));
+		return text_to_compressed_ip6(Net_IPv6::getNetmask($ipaddr, $bits));
 	}
 	return "";
 }
@@ -450,6 +450,21 @@ function ip2ulong($ip) {
 	return sprintf("%u", ip2long32($ip));
 }
 
+/*
+ * Convert textual IPv6 address string to compressed address
+ */
+function text_to_compressed_ip6($text) {
+	// Force re-compression by passing parameter 2 (force) true.
+	// This ensures that supposedly-compressed formats are uncompressed
+	// first then re-compressed into strictly correct form.
+	// e.g. 2001:0:0:4:0:0:0:1
+	// 2001::4:0:0:0:1 is a strictly-incorrect compression,
+	// but maybe the user entered it like that.
+	// The "force" parameter will ensure it is returned as:
+	// 2001:0:0:4::1
+	return Net_IPv6::compress($text, true);
+}
+
 /* 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
  */
diff --git a/src/usr/local/www/services_dhcpv6.php b/src/usr/local/www/services_dhcpv6.php
index 7f5780e4d1..d70961e7ee 100644
--- a/src/usr/local/www/services_dhcpv6.php
+++ b/src/usr/local/www/services_dhcpv6.php
@@ -259,9 +259,9 @@ if (isset($_POST['apply'])) {
 		$_POST['prefixrange_length']) {
 		$netmask = Net_IPv6::getNetmask($_POST['prefixrange_from'],
 			$_POST['prefixrange_length']);
-		$netmask = Net_IPv6::compress($netmask);
+		$netmask = text_to_compressed_ip6($netmask);
 
-		if ($netmask != Net_IPv6::compress(strtolower(
+		if ($netmask != text_to_compressed_ip6(strtolower(
 			$_POST['prefixrange_from']))) {
 			$input_errors[] = sprintf(gettext(
 				"Prefix Delegation From address is not a valid IPv6 Netmask for %s"),
@@ -270,9 +270,9 @@ if (isset($_POST['apply'])) {
 
 		$netmask = Net_IPv6::getNetmask($_POST['prefixrange_to'],
 			$_POST['prefixrange_length']);
-		$netmask = Net_IPv6::compress($netmask);
+		$netmask = text_to_compressed_ip6($netmask);
 
-		if ($netmask != Net_IPv6::compress(strtolower(
+		if ($netmask != text_to_compressed_ip6(strtolower(
 			$_POST['prefixrange_to']))) {
 			$input_errors[] = sprintf(gettext(
 				"Prefix Delegation To address is not a valid IPv6 Netmask for %s"),
