From 3288539a0b3be6b69efd2630b79133b918bb079b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Beraud?= Date: Wed, 3 Feb 2021 10:50:50 +0100 Subject: [PATCH] Add a ``strict`` flag allowing users to restrict validation of IPv4 format Add a ``strict`` flag allowing users to restrict validation to IP addresses in presentation format (``a.b.c.d``) as opposed to address format (``a.b.c.d``, ``a.b.c``, ``a.b``, ``a``). https://github.com/netaddr/netaddr/issues/186 https://man7.org/linux/man-pages/man3/inet_pton.3.html https://bugzilla.redhat.com/show_bug.cgi?id=1924436 Change-Id: I10fed16dad77ac17691a5d175c42b25916dc8bc4 Closes-Bug: #1914386 --- oslo_utils/netutils.py | 31 +++++++++++++- oslo_utils/tests/test_netutils.py | 41 ++++++++++++++++++- ...-from-text-to-binary-8c46ad2d9989e8c5.yaml | 6 +++ 3 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 releasenotes/notes/allow-to-convert-ipv4-address-from-text-to-binary-8c46ad2d9989e8c5.yaml diff --git a/oslo_utils/netutils.py b/oslo_utils/netutils.py index 492c7268..8912f17e 100644 --- a/oslo_utils/netutils.py +++ b/oslo_utils/netutils.py @@ -24,6 +24,7 @@ import socket from urllib import parse import netaddr +from netaddr.core import INET_PTON import netifaces from oslo_utils._i18n import _ @@ -81,17 +82,43 @@ def parse_host_port(address, default_port=None): return (host, None if port is None else int(port)) -def is_valid_ipv4(address): +def is_valid_ipv4(address, strict=None): """Verify that address represents a valid IPv4 address. :param address: Value to verify :type address: string + :param strict: flag allowing users to restrict validation + to IP addresses in presentation format (``a.b.c.d``) as opposed to + address format (``a.b.c.d``, ``a.b.c``, ``a.b``, ``a``). + :type flags: bool :returns: bool .. versionadded:: 1.1 + .. versionchanged:: 4.8.0 + Allow to restrict validation to IP addresses in presentation format + (``a.b.c.d``) as opposed to address format + (``a.b.c.d``, ``a.b.c``, ``a.b``, ``a``). """ + if strict is not None: + flag = INET_PTON if strict else 0 + try: + return netaddr.valid_ipv4(address, flags=flag) + except netaddr.AddrFormatError: + return False + + # non strict mode try: - return netaddr.valid_ipv4(address) + if netaddr.valid_ipv4(address, flags=INET_PTON): + return True + else: + if netaddr.valid_ipv4(address): + LOG.warn( + 'Converting in non strict mode is deprecated. ' + 'You should pass strict=False if you want to ' + 'preserve legacy behavior') + return True + else: + return False except netaddr.AddrFormatError: return False diff --git a/oslo_utils/tests/test_netutils.py b/oslo_utils/tests/test_netutils.py index 28bb1d9c..93fedf39 100644 --- a/oslo_utils/tests/test_netutils.py +++ b/oslo_utils/tests/test_netutils.py @@ -154,13 +154,52 @@ class NetworkUtilsTest(test_base.BaseTestCase): netutils.set_tcp_keepalive(mock_sock, False) self.assertEqual(1, len(mock_sock.mock_calls)) - def test_is_valid_ipv4(self): + @mock.patch.object(netutils, 'LOG', autospec=True) + def test_is_valid_ipv4(self, mock_log): + expected_log = 'Converting in non strict mode is deprecated. ' \ + 'You should pass strict=False if you want to preserve ' \ + 'legacy behavior' self.assertTrue(netutils.is_valid_ipv4('42.42.42.42')) self.assertFalse(netutils.is_valid_ipv4('-1.11.11.11')) self.assertFalse(netutils.is_valid_ipv4('')) + self.assertTrue(netutils.is_valid_ipv4('10')) + mock_log.warn.assert_called_with(expected_log) + mock_log.reset_mock() + self.assertTrue(netutils.is_valid_ipv4('10.10')) + mock_log.warn.assert_called_with(expected_log) + mock_log.reset_mock() + self.assertTrue(netutils.is_valid_ipv4('10.10.10')) + mock_log.warn.assert_called_with(expected_log) + mock_log.reset_mock() + self.assertTrue(netutils.is_valid_ipv4('10.10.10.10')) + mock_log.warn.assert_not_called() + mock_log.reset_mock() + self.assertFalse( + netutils.is_valid_ipv4('10', strict=True) + ) + self.assertFalse( + netutils.is_valid_ipv4('10.10', strict=True) + ) + self.assertFalse( + netutils.is_valid_ipv4('10.10.10', strict=True) + ) + mock_log.warn.assert_not_called() + mock_log.reset_mock() + self.assertTrue( + netutils.is_valid_ipv4('10', strict=False) + ) + self.assertTrue( + netutils.is_valid_ipv4('10.10', strict=False) + ) + self.assertTrue( + netutils.is_valid_ipv4('10.10.10', strict=False) + ) + mock_log.warn.assert_not_called() + mock_log.reset_mock() + def test_is_valid_ipv6(self): self.assertTrue(netutils.is_valid_ipv6('::1')) diff --git a/releasenotes/notes/allow-to-convert-ipv4-address-from-text-to-binary-8c46ad2d9989e8c5.yaml b/releasenotes/notes/allow-to-convert-ipv4-address-from-text-to-binary-8c46ad2d9989e8c5.yaml new file mode 100644 index 00000000..cca9c1b5 --- /dev/null +++ b/releasenotes/notes/allow-to-convert-ipv4-address-from-text-to-binary-8c46ad2d9989e8c5.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Add a ``strict`` flag to ``netutils.is_valid_ipv4`` to allowing users to + restrict validation to IP addresses in presentation format (``a.b.c.d``) + as opposed to address format (``a.b.c.d``, ``a.b.c``, ``a.b``, ``a``).