From 822e171a0023c3f8f335cda08bcbf70b2d6d4070 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 28 Mar 2020 11:28:05 +0100 Subject: ipv6: T1831: migrate eui64 addressing to XML and python --- python/vyos/ifconfig/interface.py | 38 ++++++++++++++++++++++++++++++++++++-- python/vyos/util.py | 22 ++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) (limited to 'python') diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index a2d202466..8b41d6158 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -21,10 +21,10 @@ import time from copy import deepcopy from vyos.validate import * # should not * include -from vyos.config import Config # not used anymore +from vyos.util import mac2eui64 from vyos import ConfigError -from ipaddress import IPv4Network, IPv6Address +from ipaddress import IPv4Network, IPv6Address, IPv6Network from netifaces import ifaddresses, AF_INET, AF_INET6 from time import sleep from os.path import isfile @@ -393,6 +393,40 @@ class Interface(DHCP): """ return self.set_interface('ipv6_autoconf', autoconf) + def set_ipv6_eui64_address(self, prefix): + """ + Extended Unique Identifier (EUI), as per RFC2373, allows a host to + assign iteslf a unique IPv6 address based on a given IPv6 prefix. + + If prefix is passed address is assigned, if prefix is '' address is + removed from interface. + """ + # if prefix is an empty string convert it to None so mac2eui64 works + # as expected + if not prefix: + prefix = None + + eui64 = mac2eui64(self.get_mac(), prefix) + + if not prefix: + # if prefix is empty - thus removed - we need to walk through all + # interface IPv6 addresses and find the one with the calculated + # EUI-64 identifier. The address is then removed + for addr in self.get_addr(): + addr_wo_prefix = addr.split('/')[0] + if is_ipv6(addr_wo_prefix): + if eui64 in IPv6Address(addr_wo_prefix).exploded: + self.del_addr(addr) + + return None + + # calculate and add EUI-64 IPv6 address + if IPv6Network(prefix): + # we also need to take the subnet length into account + prefix = prefix.split('/')[1] + eui64 = f'{eui64}/{prefix}' + self.add_addr(eui64 ) + def set_ipv6_forwarding(self, forwarding): """ Configure IPv6 interface-specific Host/Router behaviour. diff --git a/python/vyos/util.py b/python/vyos/util.py index e8727c192..635b11ee5 100644 --- a/python/vyos/util.py +++ b/python/vyos/util.py @@ -207,3 +207,25 @@ def is_admin() -> bool: current_user = getuser() (_, _, _, admin_group_members) = getgrnam('sudo') return current_user in admin_group_members + + +def mac2eui64(mac, prefix=None): + ''' + Convert a MAC address to a EUI64 address or, with prefix provided, a full + IPv6 address. + Thankfully copied from https://gist.github.com/wido/f5e32576bb57b5cc6f934e177a37a0d3 + ''' + # http://tools.ietf.org/html/rfc4291#section-2.5.1 + eui64 = re.sub(r'[.:-]', '', mac).lower() + eui64 = eui64[0:6] + 'fffe' + eui64[6:] + eui64 = hex(int(eui64[0:2], 16) ^ 2)[2:].zfill(2) + eui64[2:] + + if prefix is None: + return ':'.join(re.findall(r'.{4}', eui64)) + else: + try: + net = ip_network(prefix, strict=False) + euil = int('0x{0}'.format(eui64), 16) + return str(net[euil]) + except: # pylint: disable=bare-except + return -- cgit v1.2.3