From e2f80e57d9895d207edf0ad92c299dc7862087d6 Mon Sep 17 00:00:00 2001 From: Thomas Mangin Date: Mon, 30 Mar 2020 22:31:29 +0100 Subject: validate: T2182: IPv6 are not normalised when compared Adding an already existing IP address on an interface would cause the 'ip addr add' command to fail. To prevent this, the code checks if the IP already exists on the interface. The code was not normalising the different ways of representing the IPv6 address (trailing 0, ::, etc.). --- python/vyos/validate.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'python') diff --git a/python/vyos/validate.py b/python/vyos/validate.py index 0e6d34e7e..b110a62fa 100644 --- a/python/vyos/validate.py +++ b/python/vyos/validate.py @@ -13,6 +13,7 @@ # You should have received a copy of the GNU Lesser General Public # License along with this library. If not, see . +import socket import netifaces import ipaddress @@ -83,6 +84,8 @@ def is_intf_addr_assigned(intf, addr): print(e) return False + addr_host, addr_mask = addr.split('/') + if addr_type in netifaces.ifaddresses(intf).keys(): # Check every IP address on this interface for a match for ip in netifaces.ifaddresses(intf)[addr_type]: @@ -92,23 +95,24 @@ def is_intf_addr_assigned(intf, addr): if r'/' in addr: prefixlen = '' if is_ipv6(addr): - # Note that currently expanded netmasks are not supported. That means - # 2001:db00::0/24 is a valid argument while 2001:db00::0/ffff:ff00:: not. - # see https://docs.python.org/3/library/ipaddress.html - bits = bin( int(ip['netmask'].replace(':',''), 16) ).count('1') - prefixlen = '/' + str(bits) - + # Note that currently expanded netmasks are not supported. That means + # 2001:db00::0/24 is a valid argument while 2001:db00::0/ffff:ff00:: not. + # see https://docs.python.org/3/library/ipaddress.html + bits = bin( int(ip['netmask'].replace(':',''), 16) ).count('1') + prefixlen = str(bits) else: - prefixlen = '/' + str(ipaddress.IPv4Network('0.0.0.0/' + ip['netmask']).prefixlen) + prefixlen = str(ipaddress.IPv4Network('0.0.0.0/' + ip['netmask']).prefixlen) - # construct temporary variable holding IPv6 address and netmask - # in CIDR notation - tmp = ip['addr'] + prefixlen - if addr == tmp: - return True + # the netmask are different + if prefixlen != addr_mask: + continue - elif ip['addr'] == addr: - return True + addr_af = socket.AF_INET if is_ipv4(addr_host) else socket.AF_INET6 + ip_af = socket.AF_INET if is_ipv4(ip['addr']) else socket.AF_INET6 + + # compare the binary representation of the IP + if socket.inet_pton(addr_af, addr_host) == socket.inet_pton(ip_af, ip['addr']): + return True return False -- cgit v1.2.3