diff options
28 files changed, 269 insertions, 159 deletions
| diff --git a/data/templates/dhcp-client/override.conf.j2 b/data/templates/dhcp-client/override.conf.j2 index 03fd71bf1..d09320270 100644 --- a/data/templates/dhcp-client/override.conf.j2 +++ b/data/templates/dhcp-client/override.conf.j2 @@ -10,6 +10,6 @@ ConditionPathExists={{ isc_dhclient_dir }}/dhclient_%i.conf  ExecStart=  ExecStart={{ vrf_command }}/sbin/dhclient -4 {{ dhclient_options }} {{ ifname }}  ExecStop= -ExecStop=/sbin/dhclient -4 -r {{ dhclient_options }} {{ ifname }} +ExecStop={{ vrf_command }}/sbin/dhclient -4 -r {{ dhclient_options }} {{ ifname }}  WorkingDirectory={{ isc_dhclient_dir }}  PIDFile={{ isc_dhclient_dir }}/dhclient_%i.pid diff --git a/data/templates/frr/bgpd.frr.j2 b/data/templates/frr/bgpd.frr.j2 index 4535758da..7fa974254 100644 --- a/data/templates/frr/bgpd.frr.j2 +++ b/data/templates/frr/bgpd.frr.j2 @@ -349,6 +349,9 @@ router bgp {{ system_as }} {{ 'vrf ' ~ vrf if vrf is vyos_defined }}  {%         if afi_config.label.vpn.export is vyos_defined %}    label vpn export {{ afi_config.label.vpn.export }}  {%         endif %} +{%         if afi_config.label.vpn.allocation_mode.per_nexthop is vyos_defined %} +  label vpn export allocation-mode per-nexthop +{%         endif %}  {%         if afi_config.local_install is vyos_defined %}  {%             for interface in afi_config.local_install.interface %}    local-install {{ interface }} diff --git a/data/templates/openvpn/server.conf.j2 b/data/templates/openvpn/server.conf.j2 index a9bd45370..f76fbbe79 100644 --- a/data/templates/openvpn/server.conf.j2 +++ b/data/templates/openvpn/server.conf.j2 @@ -185,7 +185,7 @@ tls-version-min {{ tls.tls_version_min }}  {%     endif %}  {%     if tls.dh_params is vyos_defined %}  dh /run/openvpn/{{ ifname }}_dh.pem -{%     elif mode is vyos_defined('server') and tls.private_key is vyos_defined %} +{%     else %}  dh none  {%     endif %}  {%     if tls.auth_key is vyos_defined %} @@ -201,9 +201,9 @@ tls-client  tls-server  {%     endif %} -{%     if peer_fingerprint is vyos_defined %} +{%     if tls.peer_fingerprint is vyos_defined %}  <peer-fingerprint> -{%         for fp in peer_fingerprint %} +{%         for fp in tls.peer_fingerprint %}  {{ fp }}  {%         endfor %}  </peer-fingerprint> diff --git a/data/vyos-firewall-init.conf b/data/vyos-firewall-init.conf index 11a5bc7bf..36d92fe93 100644 --- a/data/vyos-firewall-init.conf +++ b/data/vyos-firewall-init.conf @@ -20,7 +20,7 @@ table raw {      }      chain PREROUTING { -        type filter hook prerouting priority -200; policy accept; +        type filter hook prerouting priority -300; policy accept;          counter jump VYOS_CT_IGNORE          counter jump VYOS_CT_TIMEOUT          counter jump VYOS_CT_PREROUTING_HOOK @@ -29,7 +29,7 @@ table raw {      }      chain OUTPUT { -        type filter hook output priority -200; policy accept; +        type filter hook output priority -300; policy accept;          counter jump VYOS_CT_IGNORE          counter jump VYOS_CT_TIMEOUT          counter jump VYOS_CT_OUTPUT_HOOK diff --git a/debian/vyos-1x.links b/debian/vyos-1x.links new file mode 100644 index 000000000..0e2d1b841 --- /dev/null +++ b/debian/vyos-1x.links @@ -0,0 +1 @@ +/etc/netplug/linkup.d/vyos-python-helper /etc/netplug/linkdown.d/vyos-python-helper diff --git a/debian/vyos-1x.preinst b/debian/vyos-1x.preinst index 92037a915..e355ffa84 100644 --- a/debian/vyos-1x.preinst +++ b/debian/vyos-1x.preinst @@ -8,3 +8,5 @@ dpkg-divert --package vyos-1x --add --no-rename /etc/rsyslog.conf  dpkg-divert --package vyos-1x --add --no-rename /etc/skel/.bashrc  dpkg-divert --package vyos-1x --add --no-rename /etc/skel/.profile  dpkg-divert --package vyos-1x --add --no-rename /etc/sysctl.d/80-vpp.conf +dpkg-divert --package vyos-1x --add --no-rename /etc/netplug/netplugd.conf +dpkg-divert --package vyos-1x --add --no-rename /etc/netplug/netplug diff --git a/interface-definitions/include/bgp/afi-label.xml.i b/interface-definitions/include/bgp/afi-label.xml.i index 9535d19e8..2c5eed18b 100644 --- a/interface-definitions/include/bgp/afi-label.xml.i +++ b/interface-definitions/include/bgp/afi-label.xml.i @@ -29,6 +29,19 @@              </constraint>            </properties>          </leafNode> +        <node name="allocation-mode"> +          <properties> +            <help>Label allocation mode</help> +          </properties> +          <children> +            <leafNode name="per-nexthop"> +              <properties> +                <help>Allocate a label per connected next-hop in the VRF</help> +                <valueless/> +              </properties> +            </leafNode> +          </children> +        </node>        </children>      </node>    </children> diff --git a/interface-definitions/include/interface/per-client-thread.xml.i b/interface-definitions/include/interface/per-client-thread.xml.i new file mode 100644 index 000000000..2fd19b5ce --- /dev/null +++ b/interface-definitions/include/interface/per-client-thread.xml.i @@ -0,0 +1,8 @@ +<!-- include start from interface/per-client-thread.xml.i --> +<leafNode name="per-client-thread"> +  <properties> +    <help>Process traffic from each client in a dedicated thread</help> +    <valueless/> +  </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/radius-server-key.xml.i b/interface-definitions/include/radius-server-key.xml.i index c6301646b..dd5cdb0c6 100644 --- a/interface-definitions/include/radius-server-key.xml.i +++ b/interface-definitions/include/radius-server-key.xml.i @@ -2,6 +2,14 @@  <leafNode name="key">    <properties>      <help>Shared secret key</help> +    <valueHelp> +      <format>txt</format> +      <description>Password string (key)</description> +    </valueHelp> +    <constraint> +      <regex>[[:ascii:]]{1,128}</regex> +    </constraint> +    <constraintErrorMessage>Password must be less then 128 characters</constraintErrorMessage>    </properties>  </leafNode>  <!-- include end --> diff --git a/interface-definitions/interfaces-wireguard.xml.in b/interface-definitions/interfaces-wireguard.xml.in index dd1e8e511..3c79cef28 100644 --- a/interface-definitions/interfaces-wireguard.xml.in +++ b/interface-definitions/interfaces-wireguard.xml.in @@ -59,6 +59,7 @@              </properties>              <children>                #include <include/generic-disable-node.xml.i> +              #include <include/generic-description.xml.i>                <leafNode name="public-key">                  <properties>                    <help>base64 encoded public key</help> @@ -119,6 +120,7 @@              </children>            </tagNode>            #include <include/interface/redirect.xml.i> +          #include <include/interface/per-client-thread.xml.i>            #include <include/interface/vrf.xml.i>          </children>        </tagNode> diff --git a/interface-definitions/interfaces-wireless.xml.in b/interface-definitions/interfaces-wireless.xml.in index a9538d577..421d46c6e 100644 --- a/interface-definitions/interfaces-wireless.xml.in +++ b/interface-definitions/interfaces-wireless.xml.in @@ -778,6 +778,7 @@              </properties>              <defaultValue>monitor</defaultValue>            </leafNode> +          #include <include/interface/per-client-thread.xml.i>            #include <include/interface/redirect.xml.i>            #include <include/interface/vif.xml.i>            #include <include/interface/vif-s.xml.i> diff --git a/interface-definitions/system-login.xml.in b/interface-definitions/system-login.xml.in index d772c7821..71db8b1d6 100644 --- a/interface-definitions/system-login.xml.in +++ b/interface-definitions/system-login.xml.in @@ -184,6 +184,13 @@                <leafNode name="home-directory">                  <properties>                    <help>Home directory</help> +                  <valueHelp> +                    <format>txt</format> +                    <description>Path to home directory</description> +                  </valueHelp> +                  <constraint> +                    <regex>\/$|(\/[a-zA-Z_0-9-.]+)+</regex> +                  </constraint>                  </properties>                </leafNode>              </children> diff --git a/op-mode-definitions/monitor-log.xml.in b/op-mode-definitions/monitor-log.xml.in index ee52a7eb8..52b5b85d4 100644 --- a/op-mode-definitions/monitor-log.xml.in +++ b/op-mode-definitions/monitor-log.xml.in @@ -36,6 +36,12 @@              </properties>              <command>journalctl --no-hostname --follow --boot --unit conntrackd.service</command>            </leafNode> +          <leafNode name="console-server"> +            <properties> +              <help>Monitor last lines of console server log</help> +            </properties> +            <command>journalctl --no-hostname --follow --boot --unit conserver-server.service</command> +          </leafNode>            <node name="dhcp">              <properties>                <help>Monitor last lines of Dynamic Host Control Protocol log</help> diff --git a/op-mode-definitions/show-log.xml.in b/op-mode-definitions/show-log.xml.in index 925a780ac..747622db6 100644 --- a/op-mode-definitions/show-log.xml.in +++ b/op-mode-definitions/show-log.xml.in @@ -50,6 +50,12 @@              </properties>              <command>journalctl --no-hostname --boot --unit conntrackd.service</command>            </leafNode> +          <leafNode name="console-server"> +            <properties> +              <help>Show log for console server</help> +            </properties> +            <command>journalctl --no-hostname --boot --unit conserver-server.service</command> +          </leafNode>            <node name="ids">              <properties>                <help>Show log for for Intrusion Detection System</help> diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index cc6149428..ddac387e7 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -1,4 +1,4 @@ -# Copyright 2019-2022 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2019-2023 VyOS maintainers and contributors <maintainers@vyos.io>  #  # This library is free software; you can redistribute it and/or  # modify it under the terms of the GNU Lesser General Public @@ -224,6 +224,10 @@ class Interface(Control):              'validate': lambda link: assert_range(link,0,3),              'location': '/proc/sys/net/ipv4/conf/{ifname}/link_filter',          }, +        'per_client_thread': { +            'validate': assert_boolean, +            'location': '/sys/class/net/{ifname}/threaded', +        },      }      _sysfs_get = { @@ -275,6 +279,10 @@ class Interface(Control):          'link_detect': {              'location': '/proc/sys/net/ipv4/conf/{ifname}/link_filter',          }, +        'per_client_thread': { +            'validate': assert_boolean, +            'location': '/sys/class/net/{ifname}/threaded', +        },      }      @classmethod @@ -1386,6 +1394,30 @@ class Interface(Control):                                   f'egress redirect dev {target_if}')              if err: print('tc filter add for redirect failed') +    def set_per_client_thread(self, enable): +        """ +        Per-device control to enable/disable the threaded mode for all the napi +        instances of the given network device, without the need for a device up/down. + +        User sets it to 1 or 0 to enable or disable threaded mode. + +        Example: +        >>> from vyos.ifconfig import Interface +        >>> Interface('wg1').set_per_client_thread(1) +        """ +        # In the case of a "virtual" interface like wireguard, the sysfs +        # node is only created once there is a peer configured. We can now +        # add a verify() code-path for this or make this dynamic without +        # nagging the user +        tmp = self._sysfs_get['per_client_thread']['location'] +        if not os.path.exists(tmp): +            return None + +        tmp = self.get_interface('per_client_thread') +        if tmp == enable: +            return None +        self.set_interface('per_client_thread', enable) +      def update(self, config):          """ General helper function which works on a dictionary retrived by          get_config_dict(). It's main intention is to consolidate the scattered @@ -1601,6 +1633,11 @@ class Interface(Control):          # configure interface mirror or redirection target          self.set_mirror_redirect() +        # enable/disable NAPI threading mode +        tmp = dict_search('per_client_thread', config) +        value = '1' if (tmp != None) else '0' +        self.set_per_client_thread(value) +          # Enable/Disable of an interface must always be done at the end of the          # derived class to make use of the ref-counting set_admin_state()          # function. We will only enable the interface if 'up' was called as diff --git a/python/vyos/ifconfig/wireguard.py b/python/vyos/ifconfig/wireguard.py index fe5e9c519..4aac103ec 100644 --- a/python/vyos/ifconfig/wireguard.py +++ b/python/vyos/ifconfig/wireguard.py @@ -1,4 +1,4 @@ -# Copyright 2019-2022 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2019-2023 VyOS maintainers and contributors <maintainers@vyos.io>  #  # This library is free software; you can redistribute it and/or  # modify it under the terms of the GNU Lesser General Public @@ -25,6 +25,7 @@ from hurry.filesize import alternative  from vyos.ifconfig import Interface  from vyos.ifconfig import Operational  from vyos.template import is_ipv6 +from vyos.base import Warning  class WireGuardOperational(Operational):      def _dump(self): @@ -184,7 +185,6 @@ class WireGuardIf(Interface):          base_cmd += f' private-key {tmp_file.name}'          base_cmd = base_cmd.format(**config) -          if 'peer' in config:              for peer, peer_config in config['peer'].items():                  # T4702: No need to configure this peer when it was explicitly diff --git a/smoketest/scripts/cli/test_interfaces_wireguard.py b/smoketest/scripts/cli/test_interfaces_wireguard.py index f84ce159d..48c7cb6a1 100755 --- a/smoketest/scripts/cli/test_interfaces_wireguard.py +++ b/smoketest/scripts/cli/test_interfaces_wireguard.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2020-2021 VyOS maintainers and contributors +# Copyright (C) 2020-2023 VyOS maintainers and contributors  #  # This program is free software; you can redistribute it and/or modify  # it under the terms of the GNU General Public License version 2 or later as @@ -19,6 +19,7 @@ import unittest  from base_vyostest_shim import VyOSUnitTestSHIM  from vyos.configsession import ConfigSessionError +from vyos.utils.file import read_file  base_path = ['interfaces', 'wireguard'] @@ -35,7 +36,7 @@ class WireGuardInterfaceTest(VyOSUnitTestSHIM.TestCase):          self.cli_delete(base_path)          self.cli_commit() -    def test_wireguard_peer(self): +    def test_01_wireguard_peer(self):          # Create WireGuard interfaces with associated peers          for intf in self._interfaces:              peer = 'foo-' + intf @@ -62,7 +63,7 @@ class WireGuardInterfaceTest(VyOSUnitTestSHIM.TestCase):              self.assertTrue(os.path.isdir(f'/sys/class/net/{intf}')) -    def test_wireguard_add_remove_peer(self): +    def test_02_wireguard_add_remove_peer(self):          # T2939: Create WireGuard interfaces with associated peers.          # Remove one of the configured peers.          # T4774: Test prevention of duplicate peer public keys @@ -100,10 +101,9 @@ class WireGuardInterfaceTest(VyOSUnitTestSHIM.TestCase):          self.cli_delete(base_path + [interface, 'peer', 'PEER01'])          self.cli_commit() -    def test_wireguard_same_public_key(self): -        # T2939: Create WireGuard interfaces with associated peers. -        # Remove one of the configured peers. -        # T4774: Test prevention of duplicate peer public keys +    def test_03_wireguard_same_public_key(self): +        # T5413: Test prevention of equality interface public key and peer's +        #        public key          interface = 'wg0'          port = '12345'          privkey = 'OOjcXGfgQlAuM6q8Z9aAYduCua7pxf7UKYvIqoUPoGQ=' @@ -129,5 +129,28 @@ class WireGuardInterfaceTest(VyOSUnitTestSHIM.TestCase):          self.assertTrue(os.path.isdir(f'/sys/class/net/{interface}')) +    def test_04_wireguard_threaded(self): +        # T5409: Test adding threaded option on interface. +        #        Test prevention for adding threaded +        #        if no enabled peer is configured. +        interface = 'wg0' +        port = '12345' +        privkey = 'OOjcXGfgQlAuM6q8Z9aAYduCua7pxf7UKYvIqoUPoGQ=' +        pubkey = 'ebFx/1G0ti8tvuZd94sEIosAZZIznX+dBAKG/8DFm0I=' + +        self.cli_set(base_path + [interface, 'address', '172.16.0.1/24']) +        self.cli_set(base_path + [interface, 'private-key', privkey]) + +        self.cli_set(base_path + [interface, 'peer', 'PEER01', 'port', port]) +        self.cli_set(base_path + [interface, 'peer', 'PEER01', 'public-key', pubkey]) +        self.cli_set(base_path + [interface, 'peer', 'PEER01', 'allowed-ips', '10.205.212.10/32']) +        self.cli_set(base_path + [interface, 'peer', 'PEER01', 'address', '192.0.2.1']) +        self.cli_set(base_path + [interface, 'per-client-thread']) + +        # Commit peers +        self.cli_commit() +        tmp = read_file(f'/sys/class/net/{interface}/threaded') +        self.assertTrue(tmp, "1") +  if __name__ == '__main__':      unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 5b247a413..77952d8d9 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -868,6 +868,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):              self.cli_set(base_path + ['address-family', afi, 'export', 'vpn'])              self.cli_set(base_path + ['address-family', afi, 'import', 'vpn'])              self.cli_set(base_path + ['address-family', afi, 'label', 'vpn', 'export', label]) +            self.cli_set(base_path + ['address-family', afi, 'label', 'vpn', 'allocation-mode', 'per-nexthop'])              self.cli_set(base_path + ['address-family', afi, 'rd', 'vpn', 'export', rd])              self.cli_set(base_path + ['address-family', afi, 'route-map', 'vpn', 'export', route_map_out])              self.cli_set(base_path + ['address-family', afi, 'route-map', 'vpn', 'import', route_map_in]) @@ -887,6 +888,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):              self.assertIn(f'  export vpn', afi_config)              self.assertIn(f'  import vpn', afi_config)              self.assertIn(f'  label vpn export {label}', afi_config) +            self.assertIn(f'  label vpn export allocation-mode per-nexthop', afi_config)              self.assertIn(f'  rd vpn export {rd}', afi_config)              self.assertIn(f'  route-map vpn export {route_map_out}', afi_config)              self.assertIn(f'  route-map vpn import {route_map_in}', afi_config) diff --git a/src/conf_mode/dhcp_server.py b/src/conf_mode/dhcp_server.py index 280057f04..c4c72aae9 100755 --- a/src/conf_mode/dhcp_server.py +++ b/src/conf_mode/dhcp_server.py @@ -296,6 +296,10 @@ def generate(dhcp):      render(config_file, 'dhcp-server/dhcpd.conf.j2', dhcp,             formater=lambda _: _.replace(""", '"')) +    # Clean up configuration test file +    if os.path.exists(tmp_file): +        os.unlink(tmp_file) +      return None  def apply(dhcp): diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index 26b217d98..1d0feb56f 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.py @@ -166,17 +166,23 @@ def verify_pki(openvpn):              raise ConfigError(f'Invalid shared-secret on openvpn interface {interface}')      if tls: -        if 'ca_certificate' not in tls: -            raise ConfigError(f'Must specify "tls ca-certificate" on openvpn interface {interface}') - -        for ca_name in tls['ca_certificate']: -            if ca_name not in pki['ca']: -                raise ConfigError(f'Invalid CA certificate on openvpn interface {interface}') +        if (mode in ['server', 'client']) and ('ca_certificate' not in tls): +            raise ConfigError(f'Must specify "tls ca-certificate" on openvpn interface {interface},\ +              it is required in server and client modes') +        else: +            if ('ca_certificate' not in tls) and ('peer_fingerprint' not in tls): +                raise ConfigError('Either "tls ca-certificate" or "tls peer-fingerprint" is required\ +                  on openvpn interface {interface} in site-to-site mode') -        if len(tls['ca_certificate']) > 1: -            sorted_chain = sort_ca_chain(tls['ca_certificate'], pki['ca']) -            if not verify_ca_chain(sorted_chain, pki['ca']): -                raise ConfigError(f'CA certificates are not a valid chain') +        if 'ca_certificate' in tls: +            for ca_name in tls['ca_certificate']: +                if ca_name not in pki['ca']: +                    raise ConfigError(f'Invalid CA certificate on openvpn interface {interface}') + +            if len(tls['ca_certificate']) > 1: +                sorted_chain = sort_ca_chain(tls['ca_certificate'], pki['ca']) +                if not verify_ca_chain(sorted_chain, pki['ca']): +                    raise ConfigError(f'CA certificates are not a valid chain')          if mode != 'client' and 'auth_key' not in tls:              if 'certificate' not in tls: diff --git a/src/conf_mode/interfaces-wireguard.py b/src/conf_mode/interfaces-wireguard.py index 446399255..122d9589a 100755 --- a/src/conf_mode/interfaces-wireguard.py +++ b/src/conf_mode/interfaces-wireguard.py @@ -90,7 +90,6 @@ def verify(wireguard):      # run checks on individual configured WireGuard peer      public_keys = [] -      for tmp in wireguard['peer']:          peer = wireguard['peer'][tmp] @@ -107,8 +106,9 @@ def verify(wireguard):          if peer['public_key'] in public_keys:              raise ConfigError(f'Duplicate public-key defined on peer "{tmp}"') -        if 'disable' not in peer and is_wireguard_key_pair(wireguard['private_key'], peer['public_key']): -            raise ConfigError(f'Peer "{tmp}" has the same public key as the interface "{wireguard["ifname"]}"') +        if 'disable' not in peer: +            if is_wireguard_key_pair(wireguard['private_key'], peer['public_key']): +                raise ConfigError(f'Peer "{tmp}" has the same public key as the interface "{wireguard["ifname"]}"')          public_keys.append(peer['public_key']) diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py index e49ad25ac..29ab9713f 100755 --- a/src/conf_mode/interfaces-wireless.py +++ b/src/conf_mode/interfaces-wireless.py @@ -116,7 +116,7 @@ def verify(wifi):          raise ConfigError('You must specify a WiFi mode')      if 'ssid' not in wifi and wifi['type'] != 'monitor': -        raise ConfigError('SSID must be configured') +        raise ConfigError('SSID must be configured unless type is set to "monitor"!')      if wifi['type'] == 'access-point':          if 'country_code' not in wifi: diff --git a/src/etc/netplug/linkdown.d/dhclient b/src/etc/netplug/linkdown.d/dhclient deleted file mode 100755 index 555ff9134..000000000 --- a/src/etc/netplug/linkdown.d/dhclient +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/perl -# -# Module: dhclient -# -# **** License **** -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -# General Public License for more details. -# -# A copy of the GNU General Public License is available as -# `/usr/share/common-licenses/GPL' in the Debian GNU/Linux distribution -# or on the World Wide Web at `http://www.gnu.org/copyleft/gpl.html'. -# You can also obtain it by writing to the Free Software Foundation, -# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, -# MA 02110-1301, USA. -# -# This code was originally developed by Vyatta, Inc. -# Portions created by Vyatta are Copyright (C) 2008 Vyatta, Inc. -# All Rights Reserved. -# -# Author: Mohit Mehta -# Date: November 2008 -# Description: Script to release lease on link down -# -# **** End License **** -# - -use lib "/opt/vyatta/share/perl5/"; -use Vyatta::Config; -use Vyatta::Misc; - -use strict; -use warnings; - -sub stop_dhclient { -    my $intf = shift; -    my $dhcp_daemon = '/sbin/dhclient'; -    my ($intf_config_file, $intf_process_id_file, $intf_leases_file) = Vyatta::Misc::generate_dhclient_intf_files($intf); -    my $release_cmd = "sudo $dhcp_daemon -q -cf $intf_config_file -pf $intf_process_id_file -lf $intf_leases_file -r $intf 2> /dev/null;"; -    $release_cmd .= "sudo rm -f $intf_process_id_file 2> /dev/null"; -    system ($release_cmd); -} - - -# -# main -# - -my $dev=shift; - -# only do this if interface is configured to use dhcp for getting IP address -if (Vyatta::Misc::is_dhcp_enabled($dev, "outside_cli")) { -   # do a dhcp lease release for interface -   stop_dhclient($dev); -} - -exit 0; - -# end of file - diff --git a/src/etc/netplug/linkup.d/dhclient b/src/etc/netplug/linkup.d/dhclient deleted file mode 100755 index 8e50715fd..000000000 --- a/src/etc/netplug/linkup.d/dhclient +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/perl -# -# Module: dhclient -# -# **** License **** -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -# General Public License for more details. -# -# A copy of the GNU General Public License is available as -# `/usr/share/common-licenses/GPL' in the Debian GNU/Linux distribution -# or on the World Wide Web at `http://www.gnu.org/copyleft/gpl.html'. -# You can also obtain it by writing to the Free Software Foundation, -# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, -# MA 02110-1301, USA. -# -# This code was originally developed by Vyatta, Inc. -# Portions created by Vyatta are Copyright (C) 2008 Vyatta, Inc. -# All Rights Reserved. -# -# Author: Mohit Mehta -# Date: November 2008 -# Description: Script to renew lease on link up -# -# **** End License **** -# - -use lib "/opt/vyatta/share/perl5/"; -use Vyatta::Config; -use Vyatta::Misc; - -use strict; -use warnings; - -sub run_dhclient { -    my $intf = shift; -    my $dhcp_daemon = '/sbin/dhclient'; -    my ($intf_config_file, $intf_process_id_file, $intf_leases_file) = Vyatta::Misc::generate_dhclient_intf_files($intf); -    my $cmd = "sudo $dhcp_daemon -pf $intf_process_id_file -x $intf 2> /dev/null; sudo rm -f $intf_process_id_file 2> /dev/null;"; -    $cmd .= "sudo $dhcp_daemon -q -nw -cf $intf_config_file -pf $intf_process_id_file  -lf $intf_leases_file $intf 2> /dev/null &"; -    system ($cmd); -} - -# -# main -# - -my $dev=shift; - -# only do this if interface is configured to use dhcp for getting IP address -if (Vyatta::Misc::is_dhcp_enabled($dev, "outside_cli")) { -   # do a dhcp lease renew for interface -   run_dhclient($dev); -} - -exit 0; - -# end of file - diff --git a/src/etc/netplug/linkup.d/vyos-python-helper b/src/etc/netplug/linkup.d/vyos-python-helper new file mode 100755 index 000000000..9c59c58ad --- /dev/null +++ b/src/etc/netplug/linkup.d/vyos-python-helper @@ -0,0 +1,4 @@ +#!/bin/sh +PYTHON3=$(which python3) +# Call the real python script and forward commandline arguments +$PYTHON3 /etc/netplug/vyos-netplug-dhcp-client "${@:1}" diff --git a/src/etc/netplug/netplug b/src/etc/netplug/netplug new file mode 100755 index 000000000..60b65e8c9 --- /dev/null +++ b/src/etc/netplug/netplug @@ -0,0 +1,41 @@ +#!/bin/sh +# +# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library.  If not, see <http://www.gnu.org/licenses/>. + +dev="$1" +action="$2" + +case "$action" in +in) +   run-parts --arg $dev --arg in /etc/netplug/linkup.d +    ;; +out) +   run-parts --arg $dev --arg out /etc/netplug/linkdown.d +    ;; + +# probe loads and initialises the driver for the interface and brings the +# interface into the "up" state, so that it can generate netlink(7) events. +# This interferes with "admin down" for an interface. Thus, commented out. An +# "admin up" is treated as a "link up" and thus, "link up" action is executed. +# To execute "link down" action on "admin down", run appropriate script in +# /etc/netplug/linkdown.d +#probe) +#    ;; + +*) +    exit 1 +    ;; +esac diff --git a/src/etc/netplug/netplugd.conf b/src/etc/netplug/netplugd.conf new file mode 100644 index 000000000..ab4d826d6 --- /dev/null +++ b/src/etc/netplug/netplugd.conf @@ -0,0 +1,3 @@ +eth* +br* +bond* diff --git a/src/etc/netplug/vyos-netplug-dhcp-client b/src/etc/netplug/vyos-netplug-dhcp-client new file mode 100755 index 000000000..55d15a163 --- /dev/null +++ b/src/etc/netplug/vyos-netplug-dhcp-client @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# +# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library.  If not, see <http://www.gnu.org/licenses/>. + +import sys + +from time import sleep + +from vyos.configquery import ConfigTreeQuery +from vyos.ifconfig import Section +from vyos.utils.boot import boot_configuration_complete +from vyos.utils.commit import commit_in_progress +from vyos.utils.process import call +from vyos import airbag +airbag.enable() + +if len(sys.argv) < 3: +    airbag.noteworthy("Must specify both interface and link status!") +    sys.exit(1) + +if not boot_configuration_complete(): +    airbag.noteworthy("System bootup not yet finished...") +    sys.exit(1) + +while commit_in_progress(): +    sleep(1) + +interface = sys.argv[1] +in_out = sys.argv[2] +config = ConfigTreeQuery() + +interface_path = ['interfaces'] + Section.get_config_path(interface).split() + +for _, interface_config in config.get_config_dict(interface_path).items(): +    # Bail out early if we do not have an IP address configured +    if 'address' not in interface_config: +        continue +    # Bail out early if interface ist administrative down +    if 'disable' in interface_config: +        continue +    systemd_action = 'start' +    if in_out == 'out': +        systemd_action = 'stop' +    # Start/Stop DHCP service +    if 'dhcp' in interface_config['address']: +        call(f'systemctl {systemd_action} dhclient@{interface}.service') +    # Start/Stop DHCPv6 service +    if 'dhcpv6' in interface_config['address']: +        call(f'systemctl {systemd_action} dhcp6c@{interface}.service') | 
