Skip to content

Commit eff2144

Browse files
committed
Support IPv4 mapped IPv6 addresses in IPv4 Range.
When an IPv4 scoped range is checked for the presence of an IPv6 address and the IPv6 address falls within the IPv4 mapped address block (::ffff:0:0/96) we will automatically convert the IPv6 address to its IPv4 equivalent before making the comparison. This can be helpful on hybrid dual-stack machines.
1 parent df32bee commit eff2144

2 files changed

Lines changed: 28 additions & 0 deletions

File tree

iptools/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ class IpRange (Sequence):
8484
False
8585
>>> 2130706433 in r
8686
True
87+
>>> # IPv4 mapped IPv6 addresses are valid in an IPv4 block
88+
>>> '::ffff:127.127.127.127' in r
89+
True
90+
>>> # but only if they are actually in the block :)
8791
>>> '::ffff:192.0.2.128' in r
8892
False
8993
>>> '::ffff:c000:0280' in r
@@ -241,6 +245,14 @@ def _cast(self, item):
241245
if type(item) not in [type(1), type(ipv4.MAX_IP), type(ipv6.MAX_IP)]:
242246
raise TypeError(
243247
"expected ip address, 32-bit integer or 128-bit integer")
248+
249+
if ipv4 == self._ipver and item > ipv4.MAX_IP:
250+
# casting an ipv6 in an ipv4 range
251+
# downcast to ipv4 iff address is in the IPv4 mapped block
252+
if item in IpRange(ipv6.IPV4_MAPPED):
253+
item = item & ipv4.MAX_IP
254+
#end if
255+
244256
return item
245257
#end _cast
246258

tests/iptools/iptools_test.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,22 @@ def testIPv6Range(self):
4545
self.assertTrue('::ffff:172.16.11.12' in fixture)
4646
self.assertFalse('209.19.170.129' in fixture)
4747
#end testIPv6Range
48+
49+
def testV4MappedAddressInIPv6Range(self):
50+
"""
51+
Given that the user has configured an IPv4 range
52+
When the server recieves a connection from a host in that range
53+
And the network stack presents that address in v4 mapped format
54+
Then the address should be recognized as being in the IPv4 range.
55+
"""
56+
fixture = iptools.IpRange('192.168.0.1/24')
57+
58+
self.assertTrue('192.168.0.12' in fixture)
59+
self.assertFalse('192.168.1.12' in fixture)
60+
61+
self.assertTrue('::ffff:192.168.0.12' in fixture)
62+
self.assertFalse('::ffff:192.168.1.12' in fixture)
63+
#end test6to4AddressInIPv6Range
4864
#end class IpRangeTests
4965

5066
# vim:se sw=4 ts=4 sts=4 et:

0 commit comments

Comments
 (0)