diff options
| -rw-r--r-- | interface-definitions/include/ipv6-address.xml.i | 12 | ||||
| -rw-r--r-- | python/vyos/ifconfig/interface.py | 38 | ||||
| -rw-r--r-- | python/vyos/util.py | 22 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces-bonding.py | 7 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces-bridge.py | 7 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces-ethernet.py | 8 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces-l2tpv3.py | 7 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces-openvpn.py | 7 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces-pseudo-ethernet.py | 7 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces-vxlan.py | 7 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces-wireless.py | 7 | 
11 files changed, 126 insertions, 3 deletions
| diff --git a/interface-definitions/include/ipv6-address.xml.i b/interface-definitions/include/ipv6-address.xml.i index 31629830e..507d5dcc1 100644 --- a/interface-definitions/include/ipv6-address.xml.i +++ b/interface-definitions/include/ipv6-address.xml.i @@ -6,5 +6,17 @@          <valueless/>        </properties>      </leafNode> +    <leafNode name="eui64"> +      <properties> +        <help>ssign IPv6 address using EUI-64 based on MAC address</help> +        <valueHelp> +          <format>ipv6net</format> +          <description>IPv6 address and prefix length</description> +        </valueHelp> +        <constraint> +          <validator name="ipv6-prefix"/> +        </constraint> +      </properties> +    </leafNode>    </children>  </node> 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 diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py index ab58b9159..cc119b91a 100755 --- a/src/conf_mode/interfaces-bonding.py +++ b/src/conf_mode/interfaces-bonding.py @@ -49,6 +49,7 @@ default_config_data = {      'ip_proxy_arp': 0,      'ip_proxy_arp_pvlan': 0,      'ipv6_autoconf': 0, +    'ipv6_eui64_prefix': '',      'ipv6_forwarding': 1,      'ipv6_dup_addr_detect': 1,      'intf': '', @@ -196,6 +197,10 @@ def get_config():      if conf.exists('ipv6 address autoconf'):          bond['ipv6_autoconf'] = 1 +    # Get prefix for IPv6 addressing based on MAC address (EUI-64) +    if conf.exists('ipv6 address eui64'): +        bond['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64') +      # Disable IPv6 forwarding on this interface      if conf.exists('ipv6 disable-forwarding'):          bond['ipv6_forwarding'] = 0 @@ -433,6 +438,8 @@ def apply(bond):          b.set_proxy_arp_pvlan(bond['ip_proxy_arp_pvlan'])          # IPv6 address autoconfiguration          b.set_ipv6_autoconf(bond['ipv6_autoconf']) +        # IPv6 EUI-based address +        b.set_ipv6_eui64_address(bond['ipv6_eui64_prefix'])          # IPv6 forwarding          b.set_ipv6_forwarding(bond['ipv6_forwarding'])          # IPv6 Duplicate Address Detection (DAD) tries diff --git a/src/conf_mode/interfaces-bridge.py b/src/conf_mode/interfaces-bridge.py index 1e143e30c..28e5957e4 100755 --- a/src/conf_mode/interfaces-bridge.py +++ b/src/conf_mode/interfaces-bridge.py @@ -47,6 +47,7 @@ default_config_data = {      'ip_enable_arp_announce': 0,      'ip_enable_arp_ignore': 0,      'ipv6_autoconf': 0, +    'ipv6_eui64_prefix': '',      'ipv6_forwarding': 1,      'ipv6_dup_addr_detect': 1,      'igmp_querier': 0, @@ -159,6 +160,10 @@ def get_config():      if conf.exists('ipv6 address autoconf'):          bridge['ipv6_autoconf'] = 1 +    # Get prefix for IPv6 addressing based on MAC address (EUI-64) +    if conf.exists('ipv6 address eui64'): +        bridge['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64') +      # Disable IPv6 forwarding on this interface      if conf.exists('ipv6 disable-forwarding'):          bridge['ipv6_forwarding'] = 0 @@ -275,6 +280,8 @@ def apply(bridge):          br.set_arp_ignore(bridge['ip_enable_arp_ignore'])          # IPv6 address autoconfiguration          br.set_ipv6_autoconf(bridge['ipv6_autoconf']) +        # IPv6 EUI-based address +        br.set_ipv6_eui64_address(bridge['ipv6_eui64_prefix'])          # IPv6 forwarding          br.set_ipv6_forwarding(bridge['ipv6_forwarding'])          # IPv6 Duplicate Address Detection (DAD) tries diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py index c7fabce60..286cab88e 100755 --- a/src/conf_mode/interfaces-ethernet.py +++ b/src/conf_mode/interfaces-ethernet.py @@ -49,6 +49,7 @@ default_config_data = {      'ip_proxy_arp': 0,      'ip_proxy_arp_pvlan': 0,      'ipv6_autoconf': 0, +    'ipv6_eui64_prefix': '',      'ipv6_forwarding': 1,      'ipv6_dup_addr_detect': 1,      'intf': '', @@ -174,6 +175,10 @@ def get_config():      if conf.exists('ipv6 address autoconf'):          eth['ipv6_autoconf'] = 1 +    # Get prefix for IPv6 addressing based on MAC address (EUI-64) +    if conf.exists('ipv6 address eui64'): +        eth['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64') +      # Disable IPv6 forwarding on this interface      if conf.exists('ipv6 disable-forwarding'):          eth['ipv6_forwarding'] = 0 @@ -341,9 +346,10 @@ def apply(eth):          e.set_proxy_arp(eth['ip_proxy_arp'])          # Enable private VLAN proxy ARP on this interface          e.set_proxy_arp_pvlan(eth['ip_proxy_arp_pvlan']) -        # Disable IPv6 forwarding on this interface          # IPv6 address autoconfiguration          e.set_ipv6_autoconf(eth['ipv6_autoconf']) +        # IPv6 EUI-based address +        e.set_ipv6_eui64_address(eth['ipv6_eui64_prefix'])          # IPv6 forwarding          e.set_ipv6_forwarding(eth['ipv6_forwarding'])          # IPv6 Duplicate Address Detection (DAD) tries diff --git a/src/conf_mode/interfaces-l2tpv3.py b/src/conf_mode/interfaces-l2tpv3.py index 18ae1f4d8..af1d3f482 100755 --- a/src/conf_mode/interfaces-l2tpv3.py +++ b/src/conf_mode/interfaces-l2tpv3.py @@ -34,6 +34,7 @@ default_config_data = {      'local_port': 5000,      'intf': '',      'ipv6_autoconf': 0, +    'ipv6_eui64_prefix': '',      'ipv6_forwarding': 1,      'ipv6_dup_addr_detect': 1,      'mtu': 1488, @@ -108,6 +109,10 @@ def get_config():      if conf.exists('ipv6 address autoconf'):          l2tpv3['ipv6_autoconf'] = 1 +    # Get prefix for IPv6 addressing based on MAC address (EUI-64) +    if conf.exists('ipv6 address eui64'): +        l2tpv3['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64') +      # Disable IPv6 forwarding on this interface      if conf.exists('ipv6 disable-forwarding'):          l2tpv3['ipv6_forwarding'] = 0 @@ -210,6 +215,8 @@ def apply(l2tpv3):          l.set_mtu(l2tpv3['mtu'])          # IPv6 address autoconfiguration          l.set_ipv6_autoconf(l2tpv3['ipv6_autoconf']) +        # IPv6 EUI-based address +        l.set_ipv6_eui64_address(l2tpv3['ipv6_eui64_prefix'])          # IPv6 forwarding          l.set_ipv6_forwarding(l2tpv3['ipv6_forwarding'])          # IPv6 Duplicate Address Detection (DAD) tries diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index a91cc2d73..17aa4697f 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.py @@ -295,6 +295,7 @@ default_config_data = {      'hash': '',      'intf': '',      'ipv6_autoconf': 0, +    'ipv6_eui64_prefix': '',      'ipv6_forwarding': 1,      'ipv6_dup_addr_detect': 1,      'ping_restart': '60', @@ -497,6 +498,10 @@ def get_config():      if conf.exists('ipv6 address autoconf'):          openvpn['ipv6_autoconf'] = 1 +    # Get prefix for IPv6 addressing based on MAC address (EUI-64) +    if conf.exists('ipv6 address eui64'): +        openvpn['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64') +      # Disable IPv6 forwarding on this interface      if conf.exists('ipv6 disable-forwarding'):          openvpn['ipv6_forwarding'] = 0 @@ -1056,6 +1061,8 @@ def apply(openvpn):          o.set_alias(openvpn['description'])          # IPv6 address autoconfiguration          o.set_ipv6_autoconf(openvpn['ipv6_autoconf']) +        # IPv6 EUI-based address +        o.set_ipv6_eui64_address(openvpn['ipv6_eui64_prefix'])          # IPv6 forwarding          o.set_ipv6_forwarding(openvpn['ipv6_forwarding'])          # IPv6 Duplicate Address Detection (DAD) tries diff --git a/src/conf_mode/interfaces-pseudo-ethernet.py b/src/conf_mode/interfaces-pseudo-ethernet.py index 4b1abc553..56d4fdfc3 100755 --- a/src/conf_mode/interfaces-pseudo-ethernet.py +++ b/src/conf_mode/interfaces-pseudo-ethernet.py @@ -46,6 +46,7 @@ default_config_data = {      'ip_proxy_arp': 0,      'ip_proxy_arp_pvlan': 0,      'ipv6_autoconf': 0, +    'ipv6_eui64_prefix': '',      'ipv6_forwarding': 1,      'ipv6_dup_addr_detect': 1,      'intf': '', @@ -152,6 +153,10 @@ def get_config():      if conf.exists('ipv6 address autoconf'):          peth['ipv6_autoconf'] = 1 +    # Get prefix for IPv6 addressing based on MAC address (EUI-64) +    if conf.exists('ipv6 address eui64'): +        peth['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64') +      # Disable IPv6 forwarding on this interface      if conf.exists('ipv6 disable-forwarding'):          peth['ipv6_forwarding'] = 0 @@ -313,6 +318,8 @@ def apply(peth):      p.set_proxy_arp_pvlan(peth['ip_proxy_arp_pvlan'])      # IPv6 address autoconfiguration      p.set_ipv6_autoconf(peth['ipv6_autoconf']) +    # IPv6 EUI-based address +    p.set_ipv6_eui64_address(peth['ipv6_eui64_prefix'])      # IPv6 forwarding      p.set_ipv6_forwarding(peth['ipv6_forwarding'])      # IPv6 Duplicate Address Detection (DAD) tries diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py index 294864bc1..3d2638c6f 100755 --- a/src/conf_mode/interfaces-vxlan.py +++ b/src/conf_mode/interfaces-vxlan.py @@ -38,6 +38,7 @@ default_config_data = {      'ip_enable_arp_ignore': 0,      'ip_proxy_arp': 0,      'ipv6_autoconf': 0, +    'ipv6_eui64_prefix': '',      'ipv6_forwarding': 1,      'ipv6_dup_addr_detect': 1,      'link': '', @@ -110,6 +111,10 @@ def get_config():      if conf.exists('ipv6 address autoconf'):          vxlan['ipv6_autoconf'] = 1 +    # Get prefix for IPv6 addressing based on MAC address (EUI-64) +    if conf.exists('ipv6 address eui64'): +        vxlan['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64') +      # Disable IPv6 forwarding on this interface      if conf.exists('ipv6 disable-forwarding'):          vxlan['ipv6_forwarding'] = 0 @@ -218,6 +223,8 @@ def apply(vxlan):          v.set_proxy_arp(vxlan['ip_proxy_arp'])          # IPv6 address autoconfiguration          v.set_ipv6_autoconf(vxlan['ipv6_autoconf']) +        # IPv6 EUI-based address +        v.set_ipv6_eui64_address(vxlan['ipv6_eui64_prefix'])          # IPv6 forwarding          v.set_ipv6_forwarding(vxlan['ipv6_forwarding'])          # IPv6 Duplicate Address Detection (DAD) tries diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py index d368cfa5d..2c67c39ae 100755 --- a/src/conf_mode/interfaces-wireless.py +++ b/src/conf_mode/interfaces-wireless.py @@ -828,6 +828,7 @@ default_config_data = {      'ip_enable_arp_announce': 0,      'ip_enable_arp_ignore': 0,      'ipv6_autoconf': 0, +    'ipv6_eui64_prefix': '',      'ipv6_forwarding': 1,      'ipv6_dup_addr_detect': 1,      'mac' : '', @@ -1143,6 +1144,10 @@ def get_config():      if conf.exists('ipv6 address autoconf'):          wifi['ipv6_autoconf'] = 1 +    # Get prefix for IPv6 addressing based on MAC address (EUI-64) +    if conf.exists('ipv6 address eui64'): +        wifi['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64') +      # ARP enable ignore      if conf.exists('ip enable-arp-ignore'):          wifi['ip_enable_arp_ignore'] = 1 @@ -1504,6 +1509,8 @@ def apply(wifi):          w.set_arp_ignore(wifi['ip_enable_arp_ignore'])          # IPv6 address autoconfiguration          w.set_ipv6_autoconf(wifi['ipv6_autoconf']) +        # IPv6 EUI-based address +        w.set_ipv6_eui64_address(wifi['ipv6_eui64_prefix'])          # IPv6 forwarding          w.set_ipv6_forwarding(wifi['ipv6_forwarding'])          # IPv6 Duplicate Address Detection (DAD) tries | 
