Merge "reject leading '0's in IPv4 addr to avoid ambiguity"

This commit is contained in:
Jenkins 2015-12-23 23:04:40 +00:00 committed by Gerrit Code Review
commit 6dc9a79579
2 changed files with 36 additions and 2 deletions
neutron
api/v2
tests/unit/api/v2

@ -211,7 +211,10 @@ def _validate_mac_address_or_none(data, valid_values=None):
def _validate_ip_address(data, valid_values=None):
msg = None
try:
netaddr.IPAddress(_validate_no_whitespace(data))
# netaddr.core.ZEROFILL is only applicable to IPv4.
# it will remove leading zeros from IPv4 address octets.
ip = netaddr.IPAddress(_validate_no_whitespace(data),
flags=netaddr.core.ZEROFILL)
# The followings are quick checks for IPv6 (has ':') and
# IPv4. (has 3 periods like 'xx.xx.xx.xx')
# NOTE(yamamoto): netaddr uses libraries provided by the underlying
@ -227,6 +230,13 @@ def _validate_ip_address(data, valid_values=None):
# >>>
if ':' not in data and data.count('.') != 3:
msg = _("'%s' is not a valid IP address") % data
# A leading '0' in IPv4 address may be interpreted as an octal number,
# e.g. 011 octal is 9 decimal. Since there is no standard saying
# whether IP address with leading '0's should be interpreted as octal
# or decimal, hence we reject leading '0's to avoid ambiguity.
if ip.version == 4 and str(ip) != data:
msg = _("'%(data)s' is not an accepted IP address, "
"'%(ip)s' is recommended") % {"data": data, "ip": ip}
except Exception:
msg = _("'%s' is not a valid IP address") % data
if msg:

@ -17,6 +17,7 @@ import string
import testtools
import mock
import netaddr
from neutron._i18n import _
from neutron.api.v2 import attributes
@ -270,6 +271,28 @@ class TestAttributes(base.BaseTestCase):
msg = attributes._validate_ip_address(ip_addr)
self.assertEqual("'%s' is not a valid IP address" % ip_addr, msg)
def test_validate_ip_address_with_leading_zero(self):
ip_addr = '1.1.1.01'
expected_msg = ("'%(data)s' is not an accepted IP address, "
"'%(ip)s' is recommended")
msg = attributes._validate_ip_address(ip_addr)
self.assertEqual(expected_msg % {"data": ip_addr, "ip": '1.1.1.1'},
msg)
ip_addr = '1.1.1.011'
msg = attributes._validate_ip_address(ip_addr)
self.assertEqual(expected_msg % {"data": ip_addr, "ip": '1.1.1.11'},
msg)
ip_addr = '1.1.1.09'
msg = attributes._validate_ip_address(ip_addr)
self.assertEqual(expected_msg % {"data": ip_addr, "ip": '1.1.1.9'},
msg)
ip_addr = "fe80:0:0:0:0:0:0:0001"
msg = attributes._validate_ip_address(ip_addr)
self.assertIsNone(msg)
def test_validate_ip_address_bsd(self):
# NOTE(yamamoto): On NetBSD and OS X, netaddr.IPAddress() accepts
# '1' * 59 as a valid address. The behaviour is inherited from
@ -279,7 +302,8 @@ class TestAttributes(base.BaseTestCase):
ip_addr = '1' * 59
with mock.patch('netaddr.IPAddress') as ip_address_cls:
msg = attributes._validate_ip_address(ip_addr)
ip_address_cls.assert_called_once_with(ip_addr)
ip_address_cls.assert_called_once_with(ip_addr,
flags=netaddr.core.ZEROFILL)
self.assertEqual("'%s' is not a valid IP address" % ip_addr, msg)
def test_validate_ip_pools(self):