Skip to content
Extraits de code Groupes Projets
Valider c072a0e5 rédigé par Fabian Becker's avatar Fabian Becker
Parcourir les fichiers

Extend AnonymizeIP to properly mask IPv6 addresses.

maskLength is now interpreted as "mask level" (0-4) and determines the number of bits to be masked.

Level	IPv4	IPv6
0	0	0
1	8	64
2	16	80
3	24	104
4	32	n/a

fixes #3710
parent 1e313cdd
Branches
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
...@@ -235,7 +235,7 @@ class IP ...@@ -235,7 +235,7 @@ class IP
*/ */
public static function isIPv6($ip) public static function isIPv6($ip)
{ {
return strpos($ip, ':') !== false; return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
} }
/** /**
......
...@@ -12,6 +12,7 @@ namespace Piwik\Plugins\AnonymizeIP; ...@@ -12,6 +12,7 @@ namespace Piwik\Plugins\AnonymizeIP;
use Piwik\Config; use Piwik\Config;
use Piwik\Common; use Piwik\Common;
use Piwik\IP;
use Piwik\Version; use Piwik\Version;
/** /**
...@@ -51,22 +52,32 @@ class AnonymizeIP extends \Piwik\Plugin ...@@ -51,22 +52,32 @@ class AnonymizeIP extends \Piwik\Plugin
* @param int $maskLength Number of octets to reset * @param int $maskLength Number of octets to reset
* @return string * @return string
*/ */
static public function applyIPMask($ip, $maskLength) public static function applyIPMask($ip, $maskLength)
{ {
$i = Common::strlen($ip); // IPv4 or mapped IPv4 in IPv6
if ($maskLength > $i) { if(IP::isIPv4($ip)) {
$maskLength = $i; $i = Common::strlen($ip);
} if ($maskLength > $i) {
$maskLength = $i;
}
while ($maskLength-- > 0) { while ($maskLength-- > 0) {
$ip[--$i] = chr(0); $ip[--$i] = chr(0);
}
} else {
$masks = array(
'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
'ffff:ffff:ffff:ffff::',
'ffff:ffff:ffff:0000::',
'ffff:ff00:0000:0000::'
);
return $ip & current(unpack('a16', inet_pton($masks[$maskLength])));
} }
return $ip; return $ip;
} }
/** /**
* Hook on Tracker.Visit.setVisitorIp to anonymize visitor IP addresses * Hook on Tracker.Visit.setVisitorIp to anomymize visitor IP addresses
*/ */
public function setVisitorIpAddress(&$ip) public function setVisitorIpAddress(&$ip)
{ {
......
...@@ -33,6 +33,24 @@ class AnonymizeIPTest extends PHPUnit_Framework_TestCase ...@@ -33,6 +33,24 @@ class AnonymizeIPTest extends PHPUnit_Framework_TestCase
); );
} }
public function getipv6Addresses()
{
return array(
array('2001:db8:0:8d3:0:8a2e:70:7344', array(
"\x20\x01\x0d\xb8\x00\x00\x08\xd3\x00\x00\x8a\x2e\x00\x70\x73\x44",
"\x20\x01\x0d\xb8\x00\x00\x08\xd3\x00\x00\x00\x00\x00\x00\x00\x00", // mask 64 bits
"\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", // mask 80 bits
"\x20\x01\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mask 104 bits
)),
array('2001:6f8:900:724::2', array(
"\x20\x01\x06\xf8\x09\x00\x07\x24\x00\x00\x00\x00\x00\x00\x00\x02",
"\x20\x01\x06\xf8\x09\x00\x07\x24\x00\x00\x00\x00\x00\x00\x00\x00",
"\x20\x01\x06\xf8\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
"\x20\x01\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
))
);
}
/** /**
* @dataProvider getipv4Addresses * @dataProvider getipv4Addresses
* @group Plugins * @group Plugins
...@@ -55,8 +73,19 @@ class AnonymizeIPTest extends PHPUnit_Framework_TestCase ...@@ -55,8 +73,19 @@ class AnonymizeIPTest extends PHPUnit_Framework_TestCase
$this->assertEquals($res, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" . $expected[$maskLength], "Got " . bin2hex($res) . ", Expected " . bin2hex($expected[$maskLength])); $this->assertEquals($res, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" . $expected[$maskLength], "Got " . bin2hex($res) . ", Expected " . bin2hex($expected[$maskLength]));
} }
$this->assertEquals("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00\x00\x00\x00", AnonymizeIP::applyIPMask(IP::P2N('::ffff:' . $ip), 5)); $this->assertEquals("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00\x00\x00\x00", AnonymizeIP::applyIPMask(IP::P2N('::ffff:' . $ip), 5));
}
// edge case (bounds check) /**
$this->assertEquals("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", AnonymizeIP::applyIPMask(IP::P2N('2001::ffff:' . $ip), 17)); * @dataProvider getipv6Addresses
* @group Plugins
* @group AnonymizeIP
*/
public function testApplyIPMask6($ip, $expected)
{
// each IP is tested with 0 to 4 octets masked
for ($maskLength = 0; $maskLength < 4; $maskLength++) {
$res = AnonymizeIP::applyIPMask(IP::P2N($ip), $maskLength);
$this->assertEquals($expected[$maskLength], $res, "Got " . bin2hex($res) . ", Expected " . bin2hex($expected[$maskLength]) . ", Mask Level " . $maskLength);
}
} }
} }
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Veuillez vous inscrire ou vous pour commenter