summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Jenkinsfile1
-rw-r--r--interface-definitions/interfaces-bonding.xml22
-rw-r--r--interface-definitions/interfaces-bridge.xml7
-rw-r--r--interface-definitions/interfaces-dummy.xml2
-rw-r--r--interface-definitions/interfaces-ethernet.xml30
-rw-r--r--interface-definitions/interfaces-loopback.xml2
-rw-r--r--interface-definitions/interfaces-openvpn.xml2
-rw-r--r--interface-definitions/interfaces-vxlan.xml2
-rw-r--r--interface-definitions/interfaces-wireguard.xml2
-rw-r--r--python/vyos/configdict.py9
-rw-r--r--python/vyos/ifconfig.py141
-rwxr-xr-xsrc/conf_mode/interfaces-bonding.py (renamed from src/conf_mode/interface-bonding.py)84
-rwxr-xr-xsrc/conf_mode/interfaces-bridge.py (renamed from src/conf_mode/interface-bridge.py)55
-rwxr-xr-xsrc/conf_mode/interfaces-dummy.py (renamed from src/conf_mode/interface-dummy.py)0
-rwxr-xr-xsrc/conf_mode/interfaces-ethernet.py (renamed from src/conf_mode/interface-ethernet.py)84
-rwxr-xr-xsrc/conf_mode/interfaces-loopback.py (renamed from src/conf_mode/interface-loopback.py)0
-rwxr-xr-xsrc/conf_mode/interfaces-openvpn.py (renamed from src/conf_mode/interface-openvpn.py)18
-rwxr-xr-xsrc/conf_mode/interfaces-vxlan.py (renamed from src/conf_mode/interface-vxlan.py)0
-rwxr-xr-xsrc/conf_mode/interfaces-wireguard.py (renamed from src/conf_mode/interface-wireguard.py)2
-rwxr-xr-xsrc/conf_mode/snmp.py2
-rwxr-xr-xsrc/conf_mode/ssh.py3
21 files changed, 386 insertions, 82 deletions
diff --git a/Jenkinsfile b/Jenkinsfile
index bcce16dd0..7b6dc49e3 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -74,6 +74,7 @@ pipeline {
docker {
args '--sysctl net.ipv6.conf.lo.disable_ipv6=0 -e GOSU_UID=1006 -e GOSU_GID=1006'
image 'vyos/vyos-build:current'
+ alwaysPull true
}
}
options {
diff --git a/interface-definitions/interfaces-bonding.xml b/interface-definitions/interfaces-bonding.xml
index 88dbab6ab..c71482d9c 100644
--- a/interface-definitions/interfaces-bonding.xml
+++ b/interface-definitions/interfaces-bonding.xml
@@ -2,7 +2,7 @@
<interfaceDefinition>
<node name="interfaces">
<children>
- <tagNode name="bonding" owner="${vyos_conf_scripts_dir}/interface-bonding.py">
+ <tagNode name="bonding" owner="${vyos_conf_scripts_dir}/interfaces-bonding.py">
<properties>
<help>Bonding interface name</help>
<priority>315</priority>
@@ -101,6 +101,11 @@
<help>DHCP client host name (overrides the system host name)</help>
</properties>
</leafNode>
+ <leafNode name="vendor-class-id">
+ <properties>
+ <help>DHCP client vendor type</help>
+ </properties>
+ </leafNode>
</children>
</node>
<node name="dhcpv6-options">
@@ -339,6 +344,11 @@
<help>DHCP client host name (overrides the system host name)</help>
</properties>
</leafNode>
+ <leafNode name="vendor-class-id">
+ <properties>
+ <help>DHCP client vendor type</help>
+ </properties>
+ </leafNode>
</children>
</node>
<node name="dhcpv6-options">
@@ -480,6 +490,11 @@
<help>DHCP client host name (overrides the system host name)</help>
</properties>
</leafNode>
+ <leafNode name="vendor-class-id">
+ <properties>
+ <help>DHCP client vendor type</help>
+ </properties>
+ </leafNode>
</children>
</node>
<node name="dhcpv6-options">
@@ -605,6 +620,11 @@
<help>DHCP client host name (overrides the system host name)</help>
</properties>
</leafNode>
+ <leafNode name="vendor-class-id">
+ <properties>
+ <help>DHCP client vendor type</help>
+ </properties>
+ </leafNode>
</children>
</node>
<node name="dhcpv6-options">
diff --git a/interface-definitions/interfaces-bridge.xml b/interface-definitions/interfaces-bridge.xml
index 4b82972dc..40505d7de 100644
--- a/interface-definitions/interfaces-bridge.xml
+++ b/interface-definitions/interfaces-bridge.xml
@@ -2,7 +2,7 @@
<interfaceDefinition>
<node name="interfaces">
<children>
- <tagNode name="bridge" owner="${vyos_conf_scripts_dir}/interface-bridge.py">
+ <tagNode name="bridge" owner="${vyos_conf_scripts_dir}/interfaces-bridge.py">
<properties>
<help>Bridge interface name</help>
<priority>470</priority>
@@ -85,6 +85,11 @@
<help>DHCP client host name (overrides the system host name)</help>
</properties>
</leafNode>
+ <leafNode name="vendor-class-id">
+ <properties>
+ <help>DHCP client vendor type</help>
+ </properties>
+ </leafNode>
</children>
</node>
<node name="dhcpv6-options">
diff --git a/interface-definitions/interfaces-dummy.xml b/interface-definitions/interfaces-dummy.xml
index c9860fe3b..3bc4330e4 100644
--- a/interface-definitions/interfaces-dummy.xml
+++ b/interface-definitions/interfaces-dummy.xml
@@ -2,7 +2,7 @@
<interfaceDefinition>
<node name="interfaces">
<children>
- <tagNode name="dummy" owner="${vyos_conf_scripts_dir}/interface-dummy.py">
+ <tagNode name="dummy" owner="${vyos_conf_scripts_dir}/interfaces-dummy.py">
<properties>
<help>Dummy interface name</help>
<priority>300</priority>
diff --git a/interface-definitions/interfaces-ethernet.xml b/interface-definitions/interfaces-ethernet.xml
index e4a56b216..f51bb3d87 100644
--- a/interface-definitions/interfaces-ethernet.xml
+++ b/interface-definitions/interfaces-ethernet.xml
@@ -2,7 +2,7 @@
<interfaceDefinition>
<node name="interfaces">
<children>
- <tagNode name="ethernet" owner="${vyos_conf_scripts_dir}/interface-ethernet.py">
+ <tagNode name="ethernet" owner="${vyos_conf_scripts_dir}/interfaces-ethernet.py">
<properties>
<help>Ethernet interface name</help>
<priority>318</priority>
@@ -70,7 +70,12 @@
</leafNode>
<leafNode name="host-name">
<properties>
- <help>DHCP client host name (overrides the system host name)</help>
+ <help>DHCP client host name (overrides system host name)</help>
+ </properties>
+ </leafNode>
+ <leafNode name="vendor-class-id">
+ <properties>
+ <help>DHCP client vendor type</help>
</properties>
</leafNode>
</children>
@@ -454,7 +459,12 @@
</leafNode>
<leafNode name="host-name">
<properties>
- <help>DHCP client host name (overrides the system host name)</help>
+ <help>DHCP client host name (overrides system host name)</help>
+ </properties>
+ </leafNode>
+ <leafNode name="vendor-class-id">
+ <properties>
+ <help>DHCP client vendor type</help>
</properties>
</leafNode>
</children>
@@ -615,7 +625,12 @@
</leafNode>
<leafNode name="host-name">
<properties>
- <help>DHCP client host name (overrides the system host name)</help>
+ <help>DHCP client host name (overrides system host name)</help>
+ </properties>
+ </leafNode>
+ <leafNode name="vendor-class-id">
+ <properties>
+ <help>DHCP client vendor type</help>
</properties>
</leafNode>
</children>
@@ -760,7 +775,12 @@
</leafNode>
<leafNode name="host-name">
<properties>
- <help>DHCP client host name (overrides the system host name)</help>
+ <help>DHCP client host name (overrides system host name)</help>
+ </properties>
+ </leafNode>
+ <leafNode name="vendor-class-id">
+ <properties>
+ <help>DHCP client vendor type</help>
</properties>
</leafNode>
</children>
diff --git a/interface-definitions/interfaces-loopback.xml b/interface-definitions/interfaces-loopback.xml
index 267731b1c..0f003bc64 100644
--- a/interface-definitions/interfaces-loopback.xml
+++ b/interface-definitions/interfaces-loopback.xml
@@ -2,7 +2,7 @@
<interfaceDefinition>
<node name="interfaces">
<children>
- <tagNode name="loopback" owner="${vyos_conf_scripts_dir}/interface-loopback.py">
+ <tagNode name="loopback" owner="${vyos_conf_scripts_dir}/interfaces-loopback.py">
<properties>
<help>Loopback interface</help>
<priority>300</priority>
diff --git a/interface-definitions/interfaces-openvpn.xml b/interface-definitions/interfaces-openvpn.xml
index 365d80558..42c953fdc 100644
--- a/interface-definitions/interfaces-openvpn.xml
+++ b/interface-definitions/interfaces-openvpn.xml
@@ -2,7 +2,7 @@
<interfaceDefinition>
<node name="interfaces">
<children>
- <tagNode name="openvpn" owner="${vyos_conf_scripts_dir}/interface-openvpn.py">
+ <tagNode name="openvpn" owner="${vyos_conf_scripts_dir}/interfaces-openvpn.py">
<properties>
<help>OpenVPN tunnel interface name</help>
<priority>460</priority>
diff --git a/interface-definitions/interfaces-vxlan.xml b/interface-definitions/interfaces-vxlan.xml
index b06c2860c..f93711741 100644
--- a/interface-definitions/interfaces-vxlan.xml
+++ b/interface-definitions/interfaces-vxlan.xml
@@ -2,7 +2,7 @@
<interfaceDefinition>
<node name="interfaces">
<children>
- <tagNode name="vxlan" owner="${vyos_conf_scripts_dir}/interface-vxlan.py">
+ <tagNode name="vxlan" owner="${vyos_conf_scripts_dir}/interfaces-vxlan.py">
<properties>
<help>Virtual extensible LAN interface (VXLAN)</help>
<priority>460</priority>
diff --git a/interface-definitions/interfaces-wireguard.xml b/interface-definitions/interfaces-wireguard.xml
index f2a7cc316..0c32a3bc1 100644
--- a/interface-definitions/interfaces-wireguard.xml
+++ b/interface-definitions/interfaces-wireguard.xml
@@ -2,7 +2,7 @@
<interfaceDefinition>
<node name="interfaces">
<children>
- <tagNode name="wireguard" owner="${vyos_conf_scripts_dir}/interface-wireguard.py">
+ <tagNode name="wireguard" owner="${vyos_conf_scripts_dir}/interfaces-wireguard.py">
<properties>
<help>WireGuard interface name</help>
<priority>459</priority>
diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py
index 1c9cf6897..983906923 100644
--- a/python/vyos/configdict.py
+++ b/python/vyos/configdict.py
@@ -112,6 +112,7 @@ def vlan_to_dict(conf):
'description': '',
'dhcp_client_id': '',
'dhcp_hostname': '',
+ 'dhcp_vendor_class_id': '',
'dhcpv6_prm_only': False,
'dhcpv6_temporary': False,
'disable': False,
@@ -145,13 +146,17 @@ def vlan_to_dict(conf):
if conf.exists('dhcp-options host-name'):
vlan['dhcp_hostname'] = conf.return_value('dhcp-options host-name')
+ # DHCP client vendor identifier
+ if conf.exists('dhcp-options vendor-class-id'):
+ vlan['dhcp_vendor_class_id'] = conf.return_value('dhcp-options vendor-class-id')
+
# DHCPv6 only acquire config parameters, no address
if conf.exists('dhcpv6-options parameters-only'):
- vlan['dhcpv6_prm_only'] = conf.return_value('dhcpv6-options parameters-only')
+ vlan['dhcpv6_prm_only'] = True
# DHCPv6 temporary IPv6 address
if conf.exists('dhcpv6-options temporary'):
- vlan['dhcpv6_temporary'] = conf.return_value('dhcpv6-options temporary')
+ vlan['dhcpv6_temporary'] = True
# ignore link state changes
if conf.exists('disable-link-detect'):
diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py
index 4ac605b54..0692f77f3 100644
--- a/python/vyos/ifconfig.py
+++ b/python/vyos/ifconfig.py
@@ -23,13 +23,26 @@ from netifaces import ifaddresses, AF_INET, AF_INET6
from subprocess import Popen, PIPE, STDOUT
from time import sleep
+dhclient_base = r'/var/lib/dhcp/dhclient_'
dhcp_cfg = """
# generated by ifconfig.py
option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;
+timeout 60;
+retry 300;
+
interface "{{ intf }}" {
send host-name "{{ hostname }}";
- request subnet-mask, broadcast-address, routers, domain-name-servers, rfc3442-classless-static-routes, domain-name, interface-mtu;
+ {% if client_id -%}
+ send dhcp-client-identifier "{{ client_id }}";
+ {% endif -%}
+ {% if vendor_class_id -%}
+ send vendor-class-identifier "{{ vendor_class_id }}";
+ {% endif -%}
+ request subnet-mask, broadcast-address, routers, domain-name-servers,
+ rfc3442-classless-static-routes, domain-name, interface-mtu;
+ require subnet-mask;
}
+
"""
dhcpv6_cfg = """
@@ -37,10 +50,8 @@ dhcpv6_cfg = """
interface "{{ intf }}" {
request routers, domain-name-servers, domain-name;
}
-"""
-
-dhclient_base = r'/var/lib/dhcp/dhclient_'
+"""
class Interface:
def __init__(self, ifname, type=None):
@@ -78,6 +89,21 @@ class Interface:
self._dhcpv6_pid_file = dhclient_base + self._ifname + '.v6pid'
self._dhcpv6_lease_file = dhclient_base + self._ifname + '.v6leases'
+ # DHCP options
+ self._dhcp_options = {
+ 'intf' : self._ifname,
+ 'hostname' : '',
+ 'client_id' : '',
+ 'vendor_class_id' : ''
+ }
+
+ # DHCPv6 options
+ self._dhcpv6_options = {
+ 'intf' : self._ifname,
+ 'dhcpv6_prm_only' : False,
+ 'dhcpv6_temporary' : False
+ }
+
def _debug_msg(self, msg):
if os.path.isfile('/tmp/vyos.ifconfig.debug'):
print('DEBUG/{:<6} {}'.format(self._ifname, msg))
@@ -293,21 +319,7 @@ class Interface:
# Assemble command executed on system. Unfortunately there is no way
# to up/down an interface via sysfs
cmd = 'ip link set dev {} {}'.format(self._ifname, state)
- tmp = self._cmd(cmd)
-
- # better safe then sorry - wait until the interface is really up
- # but only for a given period of time to avoid potential deadlocks!
- cnt = 0
- while self.get_state() != state:
- cnt += 1
- if cnt == 50:
- print('Interface {} could not be brought up in time ...'.format(self._ifname))
- break
-
- # sleep 250ms
- sleep(0.250)
-
- return tmp
+ return self._cmd(cmd)
def set_proxy_arp(self, enable):
"""
@@ -449,6 +461,37 @@ class Interface:
cmd = 'ip addr del "{}" dev "{}"'.format(addr, self._ifname)
return self._cmd(cmd)
+
+ def get_dhcp_options(self):
+ """
+ Return dictionary with supported DHCP options.
+
+ Dictionary should be altered and send back via set_dhcp_options()
+ so those options are applied when DHCP is run.
+ """
+ return self._dhcp_options
+
+ def set_dhcp_options(self, options):
+ """
+ Store new DHCP options used by next run of DHCP client.
+ """
+ self._dhcp_options = options
+
+ def get_dhcpv6_options(self):
+ """
+ Return dictionary with supported DHCPv6 options.
+
+ Dictionary should be altered and send back via set_dhcp_options()
+ so those options are applied when DHCP is run.
+ """
+ return self._dhcpv6_options
+
+ def set_dhcpv6_options(self, options):
+ """
+ Store new DHCP options used by next run of DHCP client.
+ """
+ self._dhcpv6_options = options
+
# replace dhcpv4/v6 with systemd.networkd?
def _set_dhcp(self):
"""
@@ -461,15 +504,13 @@ class Interface:
>>> j = Interface('eth0')
>>> j.set_dhcp()
"""
- dhcp = {
- 'hostname': 'vyos',
- 'intf': self._ifname
- }
- # read configured system hostname.
- # maybe change to vyos hostd client ???
- with open('/etc/hostname', 'r') as f:
- dhcp['hostname'] = f.read().rstrip('\n')
+ dhcp = self.get_dhcp_options()
+ if not dhcp['hostname']:
+ # read configured system hostname.
+ # maybe change to vyos hostd client ???
+ with open('/etc/hostname', 'r') as f:
+ dhcp['hostname'] = f.read().rstrip('\n')
# render DHCP configuration
tmpl = jinja2.Template(dhcp_cfg)
@@ -545,9 +586,14 @@ class Interface:
>>> j = Interface('eth0')
>>> j.set_dhcpv6()
"""
- dhcpv6 = {
- 'intf': self._ifname
- }
+ dhcpv6 = self.get_dhcpv6_options()
+ import pprint
+ pprint.pprint(dhcpv6)
+
+ # better save then sorry .. should be checked in interface script
+ # but if you missed it we are safe!
+ if dhcpv6['dhcpv6_prm_only'] and dhcpv6['dhcpv6_temporary']:
+ raise Exception('DHCPv6 temporary and parameters-only options are mutually exclusive!')
# render DHCP configuration
tmpl = jinja2.Template(dhcpv6_cfg)
@@ -563,16 +609,24 @@ class Interface:
sleep(5)
# no longer accept router announcements on this interface
- cmd = 'sysctl -q -w net.ipv6.conf.{}.accept_ra=0'.format(self._ifname)
- self._cmd(cmd)
+ self._write_sysfs('/proc/sys/net/ipv6/conf/{}/accept_ra'
+ .format(self._ifname), 0)
# assemble command-line to start DHCPv6 client (dhclient)
cmd = 'start-stop-daemon --start --quiet --pidfile ' + \
self._dhcpv6_pid_file
cmd += ' --exec /sbin/dhclient --'
# now pass arguments to dhclient binary
- cmd += ' -6 -nw -cf {} -pf {} -lf {} {}'.format(
- self._dhcpv6_cfg_file, self._dhcpv6_pid_file, self._dhcpv6_lease_file, self._ifname)
+ cmd += ' -6 -nw -cf {} -pf {} -lf {}'.format(
+ self._dhcpv6_cfg_file, self._dhcpv6_pid_file, self._dhcpv6_lease_file)
+
+ # add optional arguments
+ if dhcpv6['dhcpv6_prm_only']:
+ cmd += ' -S'
+ if dhcpv6['dhcpv6_temporary']:
+ cmd += ' -T'
+
+ cmd += ' {}'.format(self._ifname)
return self._cmd(cmd)
@@ -600,8 +654,8 @@ class Interface:
self._cmd(cmd)
# accept router announcements on this interface
- cmd = 'sysctl -q -w net.ipv6.conf.{}.accept_ra=1'.format(self._ifname)
- self._cmd(cmd)
+ self._write_sysfs('/proc/sys/net/ipv6/conf/{}/accept_ra'
+ .format(self._ifname), 1)
# cleanup old config file
if os.path.isfile(self._dhcpv6_cfg_file):
@@ -1338,15 +1392,16 @@ class WireGuardIf(Interface):
def __init__(self, ifname):
super().__init__(ifname, type='wireguard')
+
self.config = {
'port': 0,
- 'private-key': None,
- 'pubkey': None,
- 'psk': '/dev/null',
- 'allowed-ips': [],
- 'fwmark': 0x00,
- 'endpoint': None,
- 'keepalive': 0
+ 'private-key': None,
+ 'pubkey': None,
+ 'psk': '/dev/null',
+ 'allowed-ips': [],
+ 'fwmark': 0x00,
+ 'endpoint': None,
+ 'keepalive': 0
}
def update(self):
diff --git a/src/conf_mode/interface-bonding.py b/src/conf_mode/interfaces-bonding.py
index 4d5009c73..8a0f9f84d 100755
--- a/src/conf_mode/interface-bonding.py
+++ b/src/conf_mode/interfaces-bonding.py
@@ -34,6 +34,7 @@ default_config_data = {
'deleted': False,
'dhcp_client_id': '',
'dhcp_hostname': '',
+ 'dhcp_vendor_class_id': '',
'dhcpv6_prm_only': False,
'dhcpv6_temporary': False,
'disable': False,
@@ -83,6 +84,33 @@ def apply_vlan_config(vlan, config):
if type(vlan) != type(VLANIf("lo")):
raise TypeError()
+ # get DHCP config dictionary and update values
+ opt = vlan.get_dhcp_options()
+
+ if config['dhcp_client_id']:
+ opt['client_id'] = config['dhcp_client_id']
+
+ if config['dhcp_hostname']:
+ opt['hostname'] = config['dhcp_hostname']
+
+ if config['dhcp_vendor_class_id']:
+ opt['vendor_class_id'] = config['dhcp_vendor_class_id']
+
+ # store DHCP config dictionary - used later on when addresses are aquired
+ vlan.set_dhcp_options(opt)
+
+ # get DHCPv6 config dictionary and update values
+ opt = vlan.get_dhcpv6_options()
+
+ if config['dhcpv6_prm_only']:
+ opt['dhcpv6_prm_only'] = True
+
+ if config['dhcpv6_temporary']:
+ opt['dhcpv6_temporary'] = True
+
+ # store DHCPv6 config dictionary - used later on when addresses are aquired
+ vlan.set_dhcpv6_options(opt)
+
# update interface description used e.g. within SNMP
vlan.set_alias(config['description'])
# ignore link state changes
@@ -164,13 +192,17 @@ def get_config():
if conf.exists('dhcp-options host-name'):
bond['dhcp_hostname'] = conf.return_value('dhcp-options host-name')
+ # DHCP client vendor identifier
+ if conf.exists('dhcp-options vendor-class-id'):
+ bond['dhcp_vendor_class_id'] = conf.return_value('dhcp-options vendor-class-id')
+
# DHCPv6 only acquire config parameters, no address
if conf.exists('dhcpv6-options parameters-only'):
- bond['dhcpv6_prm_only'] = conf.return_value('dhcpv6-options parameters-only')
+ bond['dhcpv6_prm_only'] = True
# DHCPv6 temporary IPv6 address
if conf.exists('dhcpv6-options temporary'):
- bond['dhcpv6_temporary'] = conf.return_value('dhcpv6-options temporary')
+ bond['dhcpv6_temporary'] = True
# ignore link state changes
if conf.exists('disable-link-detect'):
@@ -216,7 +248,7 @@ def get_config():
if conf.exists('primary'):
bond['primary'] = conf.return_value('primary')
- # re-set configuration level and retrieve vif-s interfaces
+ # re-set configuration level to parse new nodes
conf.set_level(cfg_base)
# get vif-s interfaces (currently effective) - to determine which vif-s
# interface is no longer present and needs to be removed
@@ -230,7 +262,7 @@ def get_config():
conf.set_level(cfg_base + ' vif-s ' + vif_s)
bond['vif_s'].append(vlan_to_dict(conf))
- # re-set configuration level and retrieve vif-s interfaces
+ # re-set configuration level to parse new nodes
conf.set_level(cfg_base)
# Determine vif interfaces (currently effective) - to determine which
# vif interface is no longer present and needs to be removed
@@ -260,6 +292,21 @@ def verify(bond):
raise ConfigError('Interface "{}" is not part of the bond' \
.format(bond['primary']))
+
+ # DHCPv6 parameters-only and temporary address are mutually exclusive
+ for vif_s in bond['vif_s']:
+ if vif_s['dhcpv6_prm_only'] and vif_s['dhcpv6_temporary']:
+ raise ConfigError('DHCPv6 temporary and parameters-only options are mutually exclusive!')
+
+ for vif_c in vif_s['vif_c']:
+ if vif_c['dhcpv6_prm_only'] and vif_c['dhcpv6_temporary']:
+ raise ConfigError('DHCPv6 temporary and parameters-only options are mutually exclusive!')
+
+ for vif in bond['vif']:
+ if vif['dhcpv6_prm_only'] and vif['dhcpv6_temporary']:
+ raise ConfigError('DHCPv6 temporary and parameters-only options are mutually exclusive!')
+
+
for vif_s in bond['vif_s']:
for vif in bond['vif']:
if vif['id'] == vif_s['id']:
@@ -368,9 +415,32 @@ def apply(bond):
# update interface description used e.g. within SNMP
b.set_alias(bond['description'])
- #
- # missing DHCP/DHCPv6 options go here
- #
+ # get DHCP config dictionary and update values
+ opt = b.get_dhcp_options()
+
+ if bond['dhcp_client_id']:
+ opt['client_id'] = bond['dhcp_client_id']
+
+ if bond['dhcp_hostname']:
+ opt['hostname'] = bond['dhcp_hostname']
+
+ if bond['dhcp_vendor_class_id']:
+ opt['vendor_class_id'] = bond['dhcp_vendor_class_id']
+
+ # store DHCP config dictionary - used later on when addresses are aquired
+ b.set_dhcp_options(opt)
+
+ # get DHCPv6 config dictionary and update values
+ opt = b.get_dhcpv6_options()
+
+ if bond['dhcpv6_prm_only']:
+ opt['dhcpv6_prm_only'] = True
+
+ if bond['dhcpv6_temporary']:
+ opt['dhcpv6_temporary'] = True
+
+ # store DHCPv6 config dictionary - used later on when addresses are aquired
+ b.set_dhcpv6_options(opt)
# ignore link state changes
b.set_link_detect(bond['disable_link_detect'])
diff --git a/src/conf_mode/interface-bridge.py b/src/conf_mode/interfaces-bridge.py
index 37b5c4979..70bf4f528 100755
--- a/src/conf_mode/interface-bridge.py
+++ b/src/conf_mode/interfaces-bridge.py
@@ -32,6 +32,11 @@ default_config_data = {
'arp_cache_tmo': 30,
'description': '',
'deleted': False,
+ 'dhcp_client_id': '',
+ 'dhcp_hostname': '',
+ 'dhcp_vendor_class_id': '',
+ 'dhcpv6_prm_only': False,
+ 'dhcpv6_temporary': False,
'disable': False,
'disable_link_detect': 1,
'forwarding_delay': 14,
@@ -81,6 +86,26 @@ def get_config():
if conf.exists('description'):
bridge['description'] = conf.return_value('description')
+ # get DHCP client identifier
+ if conf.exists('dhcp-options client-id'):
+ bridge['dhcp_client_id'] = conf.return_value('dhcp-options client-id')
+
+ # DHCP client host name (overrides the system host name)
+ if conf.exists('dhcp-options host-name'):
+ bridge['dhcp_hostname'] = conf.return_value('dhcp-options host-name')
+
+ # DHCP client vendor identifier
+ if conf.exists('dhcp-options vendor-class-id'):
+ bridge['dhcp_vendor_class_id'] = conf.return_value('dhcp-options vendor-class-id')
+
+ # DHCPv6 only acquire config parameters, no address
+ if conf.exists('dhcpv6-options parameters-only'):
+ bridge['dhcpv6_prm_only'] = True
+
+ # DHCPv6 temporary IPv6 address
+ if conf.exists('dhcpv6-options temporary'):
+ bridge['dhcpv6_temporary'] = True
+
# Disable this bridge interface
if conf.exists('disable'):
bridge['disable'] = True
@@ -149,6 +174,9 @@ def get_config():
return bridge
def verify(bridge):
+ if bridge['dhcpv6_prm_only'] and bridge['dhcpv6_temporary']:
+ raise ConfigError('DHCPv6 temporary and parameters-only options are mutually exclusive!')
+
conf = Config()
for br in conf.list_nodes('interfaces bridge'):
# it makes no sense to verify ourself in this case
@@ -203,6 +231,33 @@ def apply(bridge):
# update interface description used e.g. within SNMP
br.set_alias(bridge['description'])
+ # get DHCP config dictionary and update values
+ opt = br.get_dhcp_options()
+
+ if bridge['dhcp_client_id']:
+ opt['client_id'] = bridge['dhcp_client_id']
+
+ if bridge['dhcp_hostname']:
+ opt['hostname'] = bridge['dhcp_hostname']
+
+ if bridge['dhcp_vendor_class_id']:
+ opt['vendor_class_id'] = bridge['dhcp_vendor_class_id']
+
+ # store DHCPv6 config dictionary - used later on when addresses are aquired
+ br.set_dhcp_options(opt)
+
+ # get DHCPv6 config dictionary and update values
+ opt = br.get_dhcpv6_options()
+
+ if bridge['dhcpv6_prm_only']:
+ opt['dhcpv6_prm_only'] = True
+
+ if bridge['dhcpv6_temporary']:
+ opt['dhcpv6_temporary'] = True
+
+ # store DHCPv6 config dictionary - used later on when addresses are aquired
+ br.set_dhcpv6_options(opt)
+
# Change interface MAC address
if bridge['mac']:
br.set_mac(bridge['mac'])
diff --git a/src/conf_mode/interface-dummy.py b/src/conf_mode/interfaces-dummy.py
index eb0145f65..eb0145f65 100755
--- a/src/conf_mode/interface-dummy.py
+++ b/src/conf_mode/interfaces-dummy.py
diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interfaces-ethernet.py
index 317da5772..cd40aff3e 100755
--- a/src/conf_mode/interface-ethernet.py
+++ b/src/conf_mode/interfaces-ethernet.py
@@ -31,6 +31,7 @@ default_config_data = {
'deleted': False,
'dhcp_client_id': '',
'dhcp_hostname': '',
+ 'dhcp_vendor_class_id': '',
'dhcpv6_prm_only': False,
'dhcpv6_temporary': False,
'disable': False,
@@ -66,6 +67,33 @@ def apply_vlan_config(vlan, config):
if type(vlan) != type(VLANIf("lo")):
raise TypeError()
+ # get DHCP config dictionary and update values
+ opt = vlan.get_dhcp_options()
+
+ if config['dhcp_client_id']:
+ opt['client_id'] = config['dhcp_client_id']
+
+ if config['dhcp_hostname']:
+ opt['hostname'] = config['dhcp_hostname']
+
+ if config['dhcp_vendor_class_id']:
+ opt['vendor_class_id'] = config['dhcp_vendor_class_id']
+
+ # store DHCP config dictionary - used later on when addresses are aquired
+ vlan.set_dhcp_options(opt)
+
+ # get DHCPv6 config dictionary and update values
+ opt = vlan.get_dhcpv6_options()
+
+ if config['dhcpv6_prm_only']:
+ opt['dhcpv6_prm_only'] = True
+
+ if config['dhcpv6_temporary']:
+ opt['dhcpv6_temporary'] = True
+
+ # store DHCPv6 config dictionary - used later on when addresses are aquired
+ vlan.set_dhcpv6_options(opt)
+
# update interface description used e.g. within SNMP
vlan.set_alias(config['description'])
# ignore link state changes
@@ -134,13 +162,17 @@ def get_config():
if conf.exists('dhcp-options host-name'):
eth['dhcp_hostname'] = conf.return_value('dhcp-options host-name')
+ # DHCP client vendor identifier
+ if conf.exists('dhcp-options vendor-class-id'):
+ eth['dhcp_vendor_class_id'] = conf.return_value('dhcp-options vendor-class-id')
+
# DHCPv6 only acquire config parameters, no address
if conf.exists('dhcpv6-options parameters-only'):
- eth['dhcpv6_prm_only'] = conf.return_value('dhcpv6-options parameters-only')
+ eth['dhcpv6_prm_only'] = True
# DHCPv6 temporary IPv6 address
if conf.exists('dhcpv6-options temporary'):
- eth['dhcpv6_temporary'] = conf.return_value('dhcpv6-options temporary')
+ eth['dhcpv6_temporary'] = True
# ignore link state changes
if conf.exists('disable-link-detect'):
@@ -206,7 +238,7 @@ def get_config():
if conf.exists('speed'):
eth['speed'] = conf.return_value('speed')
- # re-set configuration level and retrieve vif-s interfaces
+ # re-set configuration level to parse new nodes
conf.set_level(cfg_base)
# get vif-s interfaces (currently effective) - to determine which vif-s
# interface is no longer present and needs to be removed
@@ -220,7 +252,7 @@ def get_config():
conf.set_level(cfg_base + ' vif-s ' + vif_s)
eth['vif_s'].append(vlan_to_dict(conf))
- # re-set configuration level and retrieve vif-s interfaces
+ # re-set configuration level to parse new nodes
conf.set_level(cfg_base)
# Determine vif interfaces (currently effective) - to determine which
# vif interface is no longer present and needs to be removed
@@ -249,6 +281,9 @@ def verify(eth):
if eth['speed'] != 'auto':
raise ConfigError('If duplex is hardcoded, speed must be hardcoded, too')
+ if eth['dhcpv6_prm_only'] and eth['dhcpv6_temporary']:
+ raise ConfigError('DHCPv6 temporary and parameters-only options are mutually exclusive!')
+
conf = Config()
# some options can not be changed when interface is enslaved to a bond
for bond in conf.list_nodes('interfaces bonding'):
@@ -258,6 +293,18 @@ def verify(eth):
if eth['address']:
raise ConfigError('Can not assign address to interface {} which is a member of {}').format(eth['intf'], bond)
+ # DHCPv6 parameters-only and temporary address are mutually exclusive
+ for vif_s in eth['vif_s']:
+ if vif_s['dhcpv6_prm_only'] and vif_s['dhcpv6_temporary']:
+ raise ConfigError('DHCPv6 temporary and parameters-only options are mutually exclusive!')
+
+ for vif_c in vif_s['vif_c']:
+ if vif_c['dhcpv6_prm_only'] and vif_c['dhcpv6_temporary']:
+ raise ConfigError('DHCPv6 temporary and parameters-only options are mutually exclusive!')
+
+ for vif in eth['vif']:
+ if vif['dhcpv6_prm_only'] and vif['dhcpv6_temporary']:
+ raise ConfigError('DHCPv6 temporary and parameters-only options are mutually exclusive!')
return None
@@ -273,9 +320,32 @@ def apply(eth):
# update interface description used e.g. within SNMP
e.set_alias(eth['description'])
- #
- # missing DHCP/DHCPv6 options go here
- #
+ # get DHCP config dictionary and update values
+ opt = e.get_dhcp_options()
+
+ if eth['dhcp_client_id']:
+ opt['client_id'] = eth['dhcp_client_id']
+
+ if eth['dhcp_hostname']:
+ opt['hostname'] = eth['dhcp_hostname']
+
+ if eth['dhcp_vendor_class_id']:
+ opt['vendor_class_id'] = eth['dhcp_vendor_class_id']
+
+ # store DHCP config dictionary - used later on when addresses are aquired
+ e.set_dhcp_options(opt)
+
+ # get DHCPv6 config dictionary and update values
+ opt = e.get_dhcpv6_options()
+
+ if eth['dhcpv6_prm_only']:
+ opt['dhcpv6_prm_only'] = True
+
+ if eth['dhcpv6_temporary']:
+ opt['dhcpv6_temporary'] = True
+
+ # store DHCPv6 config dictionary - used later on when addresses are aquired
+ e.set_dhcpv6_options(opt)
# ignore link state changes
e.set_link_detect(eth['disable_link_detect'])
diff --git a/src/conf_mode/interface-loopback.py b/src/conf_mode/interfaces-loopback.py
index 10722d137..10722d137 100755
--- a/src/conf_mode/interface-loopback.py
+++ b/src/conf_mode/interfaces-loopback.py
diff --git a/src/conf_mode/interface-openvpn.py b/src/conf_mode/interfaces-openvpn.py
index 5345bf7a2..cdd133904 100755
--- a/src/conf_mode/interface-openvpn.py
+++ b/src/conf_mode/interfaces-openvpn.py
@@ -16,11 +16,11 @@
import os
import re
-import sys
-import stat
-import jinja2
+from jinja2 import Template
from copy import deepcopy
+from sys import exit
+from stat import S_IRUSR,S_IRWXU,S_IRGRP,S_IXGRP,S_IROTH,S_IXOTH
from grp import getgrnam
from ipaddress import ip_address,ip_network,IPv4Interface
from netifaces import interfaces
@@ -331,12 +331,12 @@ def openvpn_mkdir(directory):
os.mkdir(directory)
# fix permissions - corresponds to mode 755
- os.chmod(directory, stat.S_IRWXU|stat.S_IRGRP|stat.S_IXGRP|stat.S_IROTH|stat.S_IXOTH)
+ os.chmod(directory, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
uid = getpwnam(user).pw_uid
gid = getgrnam(group).gr_gid
os.chown(directory, uid, gid)
-def fixup_permission(filename, permission=stat.S_IRUSR):
+def fixup_permission(filename, permission=S_IRUSR):
"""
Check if the given file exists and change ownershit to root/vyattacfg
and appripriate file access permissions - default is user and group readable
@@ -737,7 +737,7 @@ def verify(openvpn):
if openvpn['shared_secret_file']:
if openvpn['encryption'] in ['aes128gcm', 'aes192gcm', 'aes256gcm']:
raise ConfigError('GCM encryption with shared-secret-key-file is not supported')
-
+
if not checkCertHeader('-----BEGIN OpenVPN Static key V1-----', openvpn['shared_secret_file']):
raise ConfigError('Specified shared-secret-key-file "{}" is not valid'.format(openvpn['shared_secret_file']))
@@ -851,13 +851,13 @@ def generate(openvpn):
# Generate client specific configuration
for client in openvpn['client']:
client_file = directory + '/ccd/' + interface + '/' + client['name']
- tmpl = jinja2.Template(client_tmpl)
+ tmpl = Template(client_tmpl)
client_text = tmpl.render(client)
with open(client_file, 'w') as f:
f.write(client_text)
os.chown(client_file, uid, gid)
- tmpl = jinja2.Template(config_tmpl)
+ tmpl = Template(config_tmpl)
config_text = tmpl.render(openvpn)
# we need to support quoting of raw parameters from OpenVPN CLI
@@ -957,4 +957,4 @@ if __name__ == '__main__':
apply(c)
except ConfigError as e:
print(e)
- sys.exit(1)
+ exit(1)
diff --git a/src/conf_mode/interface-vxlan.py b/src/conf_mode/interfaces-vxlan.py
index 1097ae4d0..1097ae4d0 100755
--- a/src/conf_mode/interface-vxlan.py
+++ b/src/conf_mode/interfaces-vxlan.py
diff --git a/src/conf_mode/interface-wireguard.py b/src/conf_mode/interfaces-wireguard.py
index 0dcce6b1c..7a684bafa 100755
--- a/src/conf_mode/interface-wireguard.py
+++ b/src/conf_mode/interfaces-wireguard.py
@@ -190,6 +190,8 @@ def verify(c):
raise ConfigError("ERROR: allowed-ips required for peer " + p)
if not c['peer'][p]['pubkey']:
raise ConfigError("peer pubkey required for peer " + p)
+ if not c['peer'][p]['endpoint']:
+ raise ConfigError("peer endpoint required for peer " + p)
def apply(c):
diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py
index 0ddab2129..cba1fe319 100755
--- a/src/conf_mode/snmp.py
+++ b/src/conf_mode/snmp.py
@@ -224,7 +224,7 @@ init_config_tmpl = """
SNMPDRUN=yes
# snmpd options (use syslog, close stdin/out/err).
-SNMPDOPTS='-LSed -u snmp -g snmp -p /run/snmpd.pid'
+SNMPDOPTS='-LSed -u snmp -g snmp -I -ipCidrRouteTable,inetCidrRouteTable -p /run/snmpd.pid'
"""
default_config_data = {
diff --git a/src/conf_mode/ssh.py b/src/conf_mode/ssh.py
index 2a5cba99a..e3b11b537 100755
--- a/src/conf_mode/ssh.py
+++ b/src/conf_mode/ssh.py
@@ -267,7 +267,8 @@ def apply(ssh):
else:
# SSH access is removed in the commit
os.system("sudo systemctl stop ssh.service")
- os.unlink(config_file)
+ if os.path.isfile(config_file):
+ os.unlink(config_file)
return None