Skip to content

Commit

Permalink
Merge pull request #43 from mlocati/ip6-ip4-mapped
Browse files Browse the repository at this point in the history
Add support for IPv4-Mapped Addresses
  • Loading branch information
mlocati authored Jul 16, 2020
2 parents e79c9ac + 0278c8a commit 169aa5b
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 7 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,30 @@ echo \IPLib\Range\Type::getName($type);
// 'Unknown type'
```


### Converting IP addresses

This library supports converting IPv4 to/from IPv6 addresses using the [6to4 notation](https://tools.ietf.org/html/rfc3056) or the [IPv4-mapped notation](https://tools.ietf.org/html/rfc4291#section-2.5.5.2):

```php
$ipv4 = \IPLib\Factory::addressFromString('1.2.3.4');

// 6to4 notation
$ipv6 = $ipv4->toIPv6();
// This will print "2002:102:304::"
echo (string) $ipv6;
// This will print "1.2.3.4"
echo $ipv6->toIPv4();

// IPv4-mapped notation
$ipv6 = $ipv4->toIPv6IPv4Mapped();
// This will print "::ffff:1.2.3.4"
echo (string) $ipv6;
// This will print "1.2.3.4"
echo $ipv6_6to4->toIPv4();
```


### Converting IP ranges

This library supports IPv4/IPv6 ranges in pattern format (eg. `192.168.*.*`) and in CIDR/subnet format (eg. `192.168.0.0/16`), and it offers a way to convert between the two formats:
Expand Down
12 changes: 11 additions & 1 deletion src/Address/IPv4.php
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ public function getRangeType()
}

/**
* Create an IPv6 representation of this address.
* Create an IPv6 representation of this address (in 6to4 notation).
*
* @return \IPLib\Address\IPv6
*/
Expand All @@ -337,6 +337,16 @@ public function toIPv6()
return IPv6::fromString('2002:' . sprintf('%02x', $myBytes[0]) . sprintf('%02x', $myBytes[1]) . ':' . sprintf('%02x', $myBytes[2]) . sprintf('%02x', $myBytes[3]) . '::');
}

/**
* Create an IPv6 representation of this address (in IPv6 IPv4-mapped notation).
*
* @return \IPLib\Address\IPv6
*/
public function toIPv6IPv4Mapped()
{
return IPv6::fromBytes(array_merge(array(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff), $this->getBytes()));
}

/**
* {@inheritdoc}
*
Expand Down
10 changes: 7 additions & 3 deletions src/Address/IPv6.php
Original file line number Diff line number Diff line change
Expand Up @@ -420,12 +420,16 @@ public function getRangeType()
*/
public function toIPv4()
{
$result = null;
if (strpos($this->longAddress, '2002:') === 0) {
$result = IPv4::fromBytes(array_slice($this->getBytes(), 2, 4));
// 6to4
return IPv4::fromBytes(array_slice($this->getBytes(), 2, 4));
}
if (strpos($this->longAddress, '0000:0000:0000:0000:0000:ffff:') === 0) {
// IPv4-mapped IPv6 addresses
return IPv4::fromBytes(array_slice($this->getBytes(), -4));
}

return $result;
return null;
}

/**
Expand Down
34 changes: 31 additions & 3 deletions test/tests/Addresses/ConversionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

class ConversionTest extends TestCase
{
public function validAddressesProvider()
public function get6to4TestCases()
{
return array(
array('0.0.0.0'),
Expand All @@ -18,11 +18,11 @@ public function validAddressesProvider()
}

/**
* @dataProvider validAddressesProvider
* @dataProvider get6to4TestCases
*
* @param string $address
*/
public function testV4toV6toV4($address)
public function test6to4($address)
{
$ipV4 = Factory::addressFromString($address);
$this->assertNotNull($ipV4, "'{$address}' has been detected as an invalid IP, but it should be valid");
Expand All @@ -34,4 +34,32 @@ public function testV4toV6toV4($address)
$this->assertNotNull($ipV4, "'{$address}' has been converted to '" . $ipV6->toString() . "', but it coulnd't be converted back to IPv4");
$this->assertSame($address, $ipV4back->toString());
}

public function getIPv4MappedAddessTestCases()
{
return array(
array('0.0.0.0'),
array('127.0.0.1'),
array('10.20.30.40'),
array('255.255.255.255'),
);
}

/**
* @dataProvider getIPv4MappedAddessTestCases
*
* @param string $address
*/
public function testIPv4MappedAddress($address)
{
$ipV4 = Factory::addressFromString($address);
$this->assertNotNull($ipV4, "'{$address}' has been detected as an invalid IP, but it should be valid");
$this->assertInstanceOf('IPLib\Address\IPv4', $ipV4);
$ipV6 = $ipV4->toIPv6IPv4Mapped();
$this->assertNotNull($ipV6);
$this->assertInstanceOf('IPLib\Address\IPv6', $ipV6);
$ipV4back = $ipV6->toIPv4();
$this->assertNotNull($ipV4, "'{$address}' has been converted to '" . $ipV6->toString() . "', but it coulnd't be converted back to IPv4");
$this->assertSame($address, (string) $ipV4back->toString());
}
}

0 comments on commit 169aa5b

Please sign in to comment.