def _validate_ip_address(data, valid_values=None):
try:
netaddr.IPAddress(_validate_no_whitespace(data))
+ # 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
+ # platform to convert addresses. For example, inet_aton(3).
+ # Some platforms, including NetBSD and OS X, have inet_aton
+ # implementation which accepts more varying forms of addresses than
+ # we want to accept here. The following check is to reject such
+ # addresses. For Example:
+ # >>> netaddr.IPAddress('1' * 59)
+ # IPAddress('199.28.113.199')
+ # >>> netaddr.IPAddress(str(int('1' * 59) & 0xffffffff))
+ # IPAddress('199.28.113.199')
+ # >>>
+ if ':' not in data and data.count('.') != 3:
+ raise ValueError()
except Exception:
msg = _("'%s' is not a valid IP address") % data
LOG.debug(msg)
import string
import testtools
+import mock
+
from neutron.api.v2 import attributes
from neutron.common import exceptions as n_exc
from neutron.tests import base
msg = attributes._validate_ip_address(ip_addr)
self.assertEqual("'%s' is not a valid IP address" % ip_addr, msg)
+ # Depending on platform to run UTs, this case might or might not be
+ # an equivalent to test_validate_ip_address_bsd.
+ ip_addr = '1' * 59
+ msg = attributes._validate_ip_address(ip_addr)
+ self.assertEqual("'%s' is not a valid IP address" % ip_addr, msg)
+
ip_addr = '1.1.1.1 has whitespace'
msg = attributes._validate_ip_address(ip_addr)
self.assertEqual("'%s' is not a valid IP address" % ip_addr, msg)
msg = attributes._validate_ip_address(ip_addr)
self.assertEqual("'%s' is not a valid IP address" % ip_addr, 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
+ # libc behaviour there. This test ensures that our validator reject
+ # such addresses on such platforms by mocking netaddr to emulate
+ # the behaviour.
+ 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)
+ self.assertEqual("'%s' is not a valid IP address" % ip_addr, msg)
+
def test_validate_ip_pools(self):
pools = [[{'end': '10.0.0.254'}],
[{'start': '10.0.0.254'}],