phihag / ipaddress

Python 3.3+'s ipaddress for older Python versions
Other
105 stars 53 forks source link

IPv6Network misrepresentation #46

Closed telmich closed 5 years ago

telmich commented 5 years ago

When creating an IPv6Network with python2 / ipaddress-1.0.22, the network representation is screwed up:

[17:21] line:~% virtualenv testp2ipaddress
Running virtualenv with interpreter /usr/bin/python2
New python executable in /home/nico/testp2ipaddress/bin/python2
Also creating executable in /home/nico/testp2ipaddress/bin/python
Installing setuptools, pkg_resources, pip, wheel...done.
[17:22] line:~% . ./testp2ipaddress/bin/activate
(testp2ipaddress) [17:23] line:~% pip install ipaddress
DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7.
Collecting ipaddress
  Using cached https://files.pythonhosted.org/packages/fc/d0/7fc3a811e011d4b388be48a0e381db8d990042df54aa4ef4599a31d39853/ipaddress-1.0.22-py2.py3-none-any.whl
Installing collected packages: ipaddress
Successfully installed ipaddress-1.0.22
(testp2ipaddress) [17:23] line:~% which python
/home/nico/testp2ipaddress/bin/python
(testp2ipaddress) [17:23] line:~% python
Python 2.7.13 (default, Sep 26 2018, 18:42:22)
[GCC 6.3.0 20170516] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import ipaddress
>>> ipaddress.ip_network("2001:db8:61::/64")
IPv6Network(u'3230:3031:3a64:6238:3a36:313a:3a2f:3634/128')
>>>

Expected result as seen in python3:

[17:28] line:~% python3
Python 3.5.3 (default, Sep 27 2018, 17:25:39)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ipaddress
>>> ipaddress.ip_network("2001:db8:61::/64")
IPv6Network('2001:db8:61::/64')
>>>
phihag commented 5 years ago

This is correct behavior. Your two inputs are not equal: In Python 2, string literals are byte strings by default, whereas in Python 3 (as well as many other programming languages), strings literals are character strings by default.

So Python 2's "2001:db8:61::/64" is really b"2001:db8:61::/64", and ipaddress.ip_network(b"2001:db8:61::/64") is IPv6Network(u'3230:3031:3a64:6238:3a36:313a:3a2f:3634/128'), both with this backport and in the standard library in Python 3.3+. This is because

>>> ipaddress.ip_address(u'3230:3031:3a64:6238:3a36:313a:3a2f:3634').packed
b'2001:db8:61::/64'

and if you pass in any representation of an address, you get the network with just that address.

To avoid this mistake, make sure to pass in character strings if you want ipaddress to construct from a character representation, for example by using ipaddress.ip_network(u"2001:db8:61::/64"). For more information, see the README.

Any other behavior would introduce very dangerous silent incompatibilities when switching between this ipaddress and the standard library one.

telmich commented 5 years ago

Thanks for the (very fast) clarification!