Blame SOURCES/BZ_1816612_canonicalize-IP-address.patch

47b589
From c3a924203e8f0d3d6d6fc7882f006d60e7d8d985 Mon Sep 17 00:00:00 2001
47b589
From: Gris Ge <fge@redhat.com>
47b589
Date: Fri, 19 Jun 2020 10:14:25 +0800
47b589
Subject: [PATCH] ip: canonicalize IP address
47b589
47b589
Canonicalize these IP addresses:
47b589
    * `InterfaceIP.ADDRESS_IP`
47b589
    * `Route.DESTINATION`
47b589
    * `Route.NEXT_HOP_ADDRESS`
47b589
    * `RouteRule.IP_FROM`
47b589
    * `RouteRule.IP_TO`
47b589
47b589
Introduced two functions to `libnmstate/iplib.py`:
47b589
    * `canonicalize_ip_network()` returns address with prefix
47b589
    * `canonicalize_ip_address()` returns address without prefix
47b589
47b589
Unit test cases added.
47b589
47b589
Signed-off-by: Gris Ge <fge@redhat.com>
47b589
---
47b589
 libnmstate/ifaces/base_iface.py | 19 +++++++------------
47b589
 libnmstate/iplib.py             | 14 ++++++++++++++
47b589
 libnmstate/route.py             | 12 ++++++++++++
47b589
 libnmstate/route_rule.py        | 14 +++++++-------
47b589
 4 files changed, 40 insertions(+), 19 deletions(-)
47b589
47b589
diff --git a/libnmstate/ifaces/base_iface.py b/libnmstate/ifaces/base_iface.py
47b589
index 33da69d..56a1115 100644
47b589
--- a/libnmstate/ifaces/base_iface.py
47b589
+++ b/libnmstate/ifaces/base_iface.py
47b589
@@ -20,13 +20,12 @@
47b589
 from collections.abc import Mapping
47b589
 from copy import deepcopy
47b589
 import logging
47b589
-from ipaddress import ip_address
47b589
 from operator import itemgetter
47b589
 
47b589
 from libnmstate.error import NmstateInternalError
47b589
 from libnmstate.error import NmstateValueError
47b589
-from libnmstate.iplib import is_ipv6_address
47b589
 from libnmstate.iplib import is_ipv6_link_local_addr
47b589
+from libnmstate.iplib import canonicalize_ip_address
47b589
 from libnmstate.schema import Interface
47b589
 from libnmstate.schema import InterfaceIP
47b589
 from libnmstate.schema import InterfaceIPv6
47b589
@@ -44,7 +43,7 @@ class IPState:
47b589
         self._info = info
47b589
         self._remove_stack_if_disabled()
47b589
         self._sort_addresses()
47b589
-        self._canonicalize_ipv6_addr()
47b589
+        self._canonicalize_ip_addr()
47b589
         self._canonicalize_dynamic()
47b589
 
47b589
     def _canonicalize_dynamic(self):
47b589
@@ -61,15 +60,11 @@ class IPState:
47b589
             ):
47b589
                 self._info.pop(dhcp_option, None)
47b589
 
47b589
-    def _canonicalize_ipv6_addr(self):
47b589
-        """
47b589
-        Convert full IPv6 address to abbreviated address.
47b589
-        """
47b589
-        if self._family == Interface.IPV6:
47b589
-            for addr in self.addresses:
47b589
-                address = addr[InterfaceIP.ADDRESS_IP]
47b589
-                if is_ipv6_address(address):
47b589
-                    addr[InterfaceIP.ADDRESS_IP] = str(ip_address(address))
47b589
+    def _canonicalize_ip_addr(self):
47b589
+        for addr in self.addresses:
47b589
+            addr[InterfaceIP.ADDRESS_IP] = canonicalize_ip_address(
47b589
+                addr[InterfaceIP.ADDRESS_IP]
47b589
+            )
47b589
 
47b589
     def _sort_addresses(self):
47b589
         self.addresses.sort(key=itemgetter(InterfaceIP.ADDRESS_IP))
47b589
diff --git a/libnmstate/iplib.py b/libnmstate/iplib.py
47b589
index 57fffd7..183b81b 100644
47b589
--- a/libnmstate/iplib.py
47b589
+++ b/libnmstate/iplib.py
47b589
@@ -52,3 +52,17 @@ def ip_address_full_to_tuple(addr):
47b589
         raise NmstateValueError(f"Invalid IP address, error: {err}")
47b589
 
47b589
     return f"{net.network_address}", net.prefixlen
47b589
+
47b589
+
47b589
+def canonicalize_ip_network(address):
47b589
+    try:
47b589
+        return ipaddress.ip_network(address, strict=False).with_prefixlen
47b589
+    except ValueError as e:
47b589
+        raise NmstateValueError(f"Invalid IP network address: {e}")
47b589
+
47b589
+
47b589
+def canonicalize_ip_address(address):
47b589
+    try:
47b589
+        return ipaddress.ip_address(address).compressed
47b589
+    except ValueError as e:
47b589
+        raise NmstateValueError(f"Invalid IP address: {e}")
47b589
diff --git a/libnmstate/route.py b/libnmstate/route.py
47b589
index 6534182..a182f99 100644
47b589
--- a/libnmstate/route.py
47b589
+++ b/libnmstate/route.py
47b589
@@ -22,6 +22,8 @@ from collections import defaultdict
47b589
 from libnmstate.error import NmstateValueError
47b589
 from libnmstate.error import NmstateVerificationError
47b589
 from libnmstate.iplib import is_ipv6_address
47b589
+from libnmstate.iplib import canonicalize_ip_network
47b589
+from libnmstate.iplib import canonicalize_ip_address
47b589
 from libnmstate.prettystate import format_desired_current_state_diff
47b589
 from libnmstate.schema import Interface
47b589
 from libnmstate.schema import Route
47b589
@@ -44,6 +46,7 @@ class RouteEntry(StateEntry):
47b589
         # TODO: Convert IPv6 full address to abbreviated address
47b589
         self.complement_defaults()
47b589
         self._invalid_reason = None
47b589
+        self._canonicalize_ip_address()
47b589
 
47b589
     @property
47b589
     def is_ipv6(self):
47b589
@@ -148,6 +151,15 @@ class RouteEntry(StateEntry):
47b589
                 return False
47b589
         return True
47b589
 
47b589
+    def _canonicalize_ip_address(self):
47b589
+        if not self.absent:
47b589
+            if self.destination:
47b589
+                self.destination = canonicalize_ip_network(self.destination)
47b589
+            if self.next_hop_address:
47b589
+                self.next_hop_address = canonicalize_ip_address(
47b589
+                    self.next_hop_address
47b589
+                )
47b589
+
47b589
 
47b589
 class RouteState:
47b589
     def __init__(self, ifaces, des_route_state, cur_route_state):
47b589
diff --git a/libnmstate/route_rule.py b/libnmstate/route_rule.py
47b589
index 8b45367..f35d59c 100644
47b589
--- a/libnmstate/route_rule.py
47b589
+++ b/libnmstate/route_rule.py
47b589
@@ -6,7 +6,7 @@ from libnmstate.error import NmstateVerificationError
47b589
 from libnmstate.error import NmstateValueError
47b589
 from libnmstate.iplib import KERNEL_MAIN_ROUTE_TABLE_ID
47b589
 from libnmstate.iplib import is_ipv6_address
47b589
-from libnmstate.iplib import to_ip_address_full
47b589
+from libnmstate.iplib import canonicalize_ip_network
47b589
 from libnmstate.prettystate import format_desired_current_state_diff
47b589
 from libnmstate.schema import Interface
47b589
 from libnmstate.schema import RouteRule
47b589
@@ -23,7 +23,7 @@ class RouteRuleEntry(StateEntry):
47b589
         self.priority = route_rule.get(RouteRule.PRIORITY)
47b589
         self.route_table = route_rule.get(RouteRule.ROUTE_TABLE)
47b589
         self._complement_defaults()
47b589
-        self._append_prefix_length_for_host_only_ip()
47b589
+        self._canonicalize_ip_network()
47b589
 
47b589
     def _complement_defaults(self):
47b589
         if self.ip_from is None:
47b589
@@ -38,11 +38,11 @@ class RouteRuleEntry(StateEntry):
47b589
         ):
47b589
             self.route_table = KERNEL_MAIN_ROUTE_TABLE_ID
47b589
 
47b589
-    def _append_prefix_length_for_host_only_ip(self):
47b589
-        if self.ip_from and "/" not in self.ip_from:
47b589
-            self.ip_from = to_ip_address_full(self.ip_from)
47b589
-        if self.ip_to and "/" not in self.ip_to:
47b589
-            self.ip_to = to_ip_address_full(self.ip_to)
47b589
+    def _canonicalize_ip_network(self):
47b589
+        if self.ip_from:
47b589
+            self.ip_from = canonicalize_ip_network(self.ip_from)
47b589
+        if self.ip_to:
47b589
+            self.ip_to = canonicalize_ip_network(self.ip_to)
47b589
 
47b589
     def _keys(self):
47b589
         return (self.ip_from, self.ip_to, self.priority, self.route_table)
47b589
-- 
47b589
2.27.0
47b589