summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Poessinger <christian@poessinger.com>2019-09-22 19:13:07 +0200
committerChristian Poessinger <christian@poessinger.com>2019-09-22 19:13:07 +0200
commit79a655a12875f5f152abba2d17eb6a1033b59131 (patch)
tree5a75960039a0dd81608b5a38351a8c8314cabccf /src
parentc4d0b9ed4736911d341efdebf34997e6cee8c5a8 (diff)
parent2b9c84594a693c66b949183a25cc32dfcdee72e1 (diff)
downloadvyos-1x-79a655a12875f5f152abba2d17eb6a1033b59131.tar.gz
vyos-1x-79a655a12875f5f152abba2d17eb6a1033b59131.zip
Merge branch 'current' of github.com:vyos/vyos-1x into equuleus
* 'current' of github.com:vyos/vyos-1x: (49 commits) Jenkins: ease Pipeline vxlan: T1636: simplyfy code (don't delete intf addresses) ethernet: T1637: interfaces in a bond can be disabled ethernet: T1637: fix calling arp_cache_tmo property ethernet: T1637: do not overwrite interface description with interface name ethernet: T1637: support offloading functions Python/ifconfig: T1557: ethernet: add offloading interfaces Python/ifconfig: T1557: update comments Python/ifconfig: T1557: delete all assigned IP addresses on remove() ethernet: T1637: call remove() on interface deletion Python/ifconfig: T1557: use proper inheritance levels on remove() ethernet: T1637: remove debug pprint bridge: T1556: minor comment cleanup bonding: T1614: minor comment cleanup Python/ifconfig: T1557: unify '/sys/class/net/{}' path Python/ifconfig: T1557: vmxnet3/virtio_net do not support changing speed/duplex control Python/ifconfig: T1557: vmxnet3/virtio_net do not support changing flow control Python/ifconfig: T1557: query driver if it supports auto negotiation Python/ifconfig: T1557: call ethtool with full path Python/ifconfig: T1557: return stdout string for _cmd() ...
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/interface-bonding.py12
-rwxr-xr-xsrc/conf_mode/interface-bridge.py3
-rwxr-xr-xsrc/conf_mode/interface-ethernet.py382
-rwxr-xr-xsrc/conf_mode/interface-openvpn.py36
-rwxr-xr-xsrc/conf_mode/interface-vxlan.py16
-rwxr-xr-xsrc/conf_mode/interface-wireguard.py26
-rwxr-xr-xsrc/conf_mode/ipoe_server.py23
-rwxr-xr-xsrc/helpers/vyos-boot-config-loader.py153
-rwxr-xr-xsrc/services/vyos-hostsd2
9 files changed, 576 insertions, 77 deletions
diff --git a/src/conf_mode/interface-bonding.py b/src/conf_mode/interface-bonding.py
index f0a33beff..9049913e6 100755
--- a/src/conf_mode/interface-bonding.py
+++ b/src/conf_mode/interface-bonding.py
@@ -22,7 +22,7 @@ from copy import deepcopy
from sys import exit
from netifaces import interfaces
-from vyos.ifconfig import BondIf, EthernetIf
+from vyos.ifconfig import BondIf, VLANIf
from vyos.configdict import list_diff, vlan_to_dict
from vyos.config import Config
from vyos import ConfigError
@@ -82,7 +82,7 @@ def apply_vlan_config(vlan, config):
to a VLAN interface
"""
- if type(vlan) != type(EthernetIf("lo")):
+ if type(vlan) != type(VLANIf("lo")):
raise TypeError()
# update interface description used e.g. within SNMP
@@ -279,11 +279,6 @@ def verify(bond):
raise ConfigError('can not enslave interface {} which already ' \
'belongs to {}'.format(intf, tmp))
- # we can not add disabled slave interfaces to our bond
- if conf.exists('interfaces ethernet ' + intf + ' disable'):
- raise ConfigError('can not enslave disabled interface {}' \
- .format(intf))
-
# can not add interfaces with an assigned address to a bond
if conf.exists('interfaces ethernet ' + intf + ' address'):
raise ConfigError('can not enslave interface {} which has an address ' \
@@ -339,8 +334,7 @@ def apply(bond):
b = BondIf(bond['intf'])
if bond['deleted']:
- #
- # delete bonding interface
+ # delete interface
b.remove()
else:
# Some parameters can not be changed when the bond is up.
diff --git a/src/conf_mode/interface-bridge.py b/src/conf_mode/interface-bridge.py
index 401182a0d..62589c798 100755
--- a/src/conf_mode/interface-bridge.py
+++ b/src/conf_mode/interface-bridge.py
@@ -183,8 +183,7 @@ def apply(bridge):
br = BridgeIf(bridge['intf'])
if bridge['deleted']:
- # delete bridge interface
- # DHCP is stopped inside remove()
+ # delete interface
br.remove()
else:
# enable interface
diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interface-ethernet.py
new file mode 100755
index 000000000..f82105847
--- /dev/null
+++ b/src/conf_mode/interface-ethernet.py
@@ -0,0 +1,382 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2019 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
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+
+from copy import deepcopy
+from sys import exit
+
+from vyos.ifconfig import EthernetIf, VLANIf
+from vyos.configdict import list_diff, vlan_to_dict
+from vyos.config import Config
+from vyos import ConfigError
+
+default_config_data = {
+ 'address': [],
+ 'address_remove': [],
+ 'description': '',
+ 'deleted': False,
+ 'dhcp_client_id': '',
+ 'dhcp_hostname': '',
+ 'dhcpv6_prm_only': False,
+ 'dhcpv6_temporary': False,
+ 'disable': False,
+ 'disable_link_detect': 1,
+ 'duplex': 'auto',
+ 'flow_control': 'on',
+ 'hw_id': '',
+ 'ip_arp_cache_tmo': 30,
+ 'ip_proxy_arp': 0,
+ 'ip_proxy_arp_pvlan': 0,
+ 'intf': '',
+ 'mac': '',
+ 'mtu': 1500,
+ 'offload_gro': 'off',
+ 'offload_gso': 'off',
+ 'offload_sg': 'off',
+ 'offload_tso': 'off',
+ 'offload_ufo': 'off',
+ 'speed': 'auto',
+ 'vif_s': [],
+ 'vif_s_remove': [],
+ 'vif': [],
+ 'vif_remove': []
+}
+
+
+def apply_vlan_config(vlan, config):
+ """
+ Generic function to apply a VLAN configuration from a dictionary
+ to a VLAN interface
+ """
+
+ if type(vlan) != type(VLANIf("lo")):
+ raise TypeError()
+
+ # update interface description used e.g. within SNMP
+ vlan.ifalias = config['description']
+ # ignore link state changes
+ vlan.link_detect = config['disable_link_detect']
+ # Maximum Transmission Unit (MTU)
+ vlan.mtu = config['mtu']
+ # Change VLAN interface MAC address
+ if config['mac']:
+ vlan.mac = config['mac']
+
+ # enable/disable VLAN interface
+ if config['disable']:
+ vlan.state = 'down'
+ else:
+ vlan.state = 'up'
+
+ # Configure interface address(es)
+ # - not longer required addresses get removed first
+ # - newly addresses will be added second
+ for addr in config['address_remove']:
+ vlan.del_addr(addr)
+ for addr in config['address']:
+ vlan.add_addr(addr)
+
+
+def get_config():
+ eth = deepcopy(default_config_data)
+ conf = Config()
+
+ # determine tagNode instance
+ try:
+ eth['intf'] = os.environ['VYOS_TAGNODE_VALUE']
+ except KeyError as E:
+ print("Interface not specified")
+
+ # check if ethernet interface has been removed
+ cfg_base = 'interfaces ethernet ' + eth['intf']
+ if not conf.exists(cfg_base):
+ eth['deleted'] = True
+ # we can not bail out early as ethernet interface can not be removed
+ # Kernel will complain with: RTNETLINK answers: Operation not supported.
+ # Thus we need to remove individual settings
+ return eth
+
+ # set new configuration level
+ conf.set_level(cfg_base)
+
+ # retrieve configured interface addresses
+ if conf.exists('address'):
+ eth['address'] = conf.return_values('address')
+
+ # get interface addresses (currently effective) - to determine which
+ # address is no longer valid and needs to be removed
+ eff_addr = conf.return_effective_values('address')
+ eth['address_remove'] = list_diff(eff_addr, eth['address'])
+
+ # retrieve interface description
+ if conf.exists('description'):
+ eth['description'] = conf.return_value('description')
+
+ # get DHCP client identifier
+ if conf.exists('dhcp-options client-id'):
+ eth['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'):
+ eth['dhcp_hostname'] = conf.return_value('dhcp-options host-name')
+
+ # 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')
+
+ # DHCPv6 temporary IPv6 address
+ if conf.exists('dhcpv6-options temporary'):
+ eth['dhcpv6_temporary'] = conf.return_value('dhcpv6-options temporary')
+
+ # ignore link state changes
+ if conf.exists('disable-link-detect'):
+ eth['disable_link_detect'] = 2
+
+ # disable ethernet flow control (pause frames)
+ if conf.exists('disable-flow-control'):
+ eth['flow_control'] = 'off'
+
+ # retrieve real hardware address
+ if conf.exists('hw-id'):
+ eth['hw_id'] = conf.return_value('hw-id')
+
+ # disable interface
+ if conf.exists('disable'):
+ eth['disable'] = True
+
+ # interface duplex
+ if conf.exists('duplex'):
+ eth['duplex'] = conf.return_value('duplex')
+
+ # ARP cache entry timeout in seconds
+ if conf.exists('ip arp-cache-timeout'):
+ eth['ip_arp_cache_tmo'] = int(conf.return_value('ip arp-cache-timeout'))
+
+ # Enable proxy-arp on this interface
+ if conf.exists('ip enable-proxy-arp'):
+ eth['ip_proxy_arp'] = 1
+
+ # Enable private VLAN proxy ARP on this interface
+ if conf.exists('ip proxy-arp-pvlan'):
+ eth['ip_proxy_arp_pvlan'] = 1
+
+ # Media Access Control (MAC) address
+ if conf.exists('mac'):
+ eth['mac'] = conf.return_value('mac')
+
+ # Maximum Transmission Unit (MTU)
+ if conf.exists('mtu'):
+ eth['mtu'] = int(conf.return_value('mtu'))
+
+ # GRO (generic receive offload)
+ if conf.exists('offload-options generic-receive'):
+ eth['offload_gro'] = conf.return_value('offload-options generic-receive')
+
+ # GSO (generic segmentation offload)
+ if conf.exists('offload-options generic-segmentation'):
+ eth['offload_gso'] = conf.return_value('offload-options generic-segmentation')
+
+ # scatter-gather option
+ if conf.exists('offload-options scatter-gather'):
+ eth['offload_sg'] = conf.return_value('offload-options scatter-gather')
+
+ # TSO (TCP segmentation offloading)
+ if conf.exists('offload-options tcp-segmentation'):
+ eth['offload_tso'] = conf.return_value('offload-options tcp-segmentation')
+
+ # UDP fragmentation offloading
+ if conf.exists('offload-options udp-fragmentation'):
+ eth['offload_ufo'] = conf.return_value('offload-options udp-fragmentation')
+
+ # interface speed
+ if conf.exists('speed'):
+ eth['speed'] = conf.return_value('speed')
+
+ # re-set configuration level and retrieve vif-s interfaces
+ 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
+ eff_intf = conf.list_effective_nodes('vif-s')
+ act_intf = conf.list_nodes('vif-s')
+ eth['vif_s_remove'] = list_diff(eff_intf, act_intf)
+
+ if conf.exists('vif-s'):
+ for vif_s in conf.list_nodes('vif-s'):
+ # set config level to vif-s interface
+ 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
+ conf.set_level(cfg_base)
+ # Determine vif interfaces (currently effective) - to determine which
+ # vif interface is no longer present and needs to be removed
+ eff_intf = conf.list_effective_nodes('vif')
+ act_intf = conf.list_nodes('vif')
+ eth['vif_remove'] = list_diff(eff_intf, act_intf)
+
+ if conf.exists('vif'):
+ for vif in conf.list_nodes('vif'):
+ # set config level to vif interface
+ conf.set_level(cfg_base + ' vif ' + vif)
+ eth['vif'].append(vlan_to_dict(conf))
+
+ return eth
+
+
+def verify(eth):
+ if eth['deleted']:
+ return None
+
+ if eth['speed'] == 'auto':
+ if eth['duplex'] != 'auto':
+ raise ConfigError('If speed is hardcoded, duplex must be hardcoded, too')
+
+ if eth['duplex'] == 'auto':
+ if eth['speed'] != 'auto':
+ raise ConfigError('If duplex is hardcoded, speed must be hardcoded, too')
+
+ conf = Config()
+ # some options can not be changed when interface is enslaved to a bond
+ for bond in conf.list_nodes('interfaces bonding'):
+ if conf.exists('interfaces bonding ' + bond + ' member interface'):
+ bond_member = conf.return_values('interfaces bonding ' + bond + ' member interface')
+ if eth['name'] in bond_member:
+ if eth['address']:
+ raise ConfigError('Can not assign address to interface {} which is a member of {}').format(eth['intf'], bond)
+
+
+ return None
+
+def generate(eth):
+ return None
+
+def apply(eth):
+ e = EthernetIf(eth['intf'])
+ if eth['deleted']:
+ # delete interface
+ e.remove()
+ else:
+ # update interface description used e.g. within SNMP
+ e.ifalias = eth['description']
+
+ #
+ # missing DHCP/DHCPv6 options go here
+ #
+
+ # ignore link state changes
+ e.link_detect = eth['disable_link_detect']
+ # disable ethernet flow control (pause frames)
+ e.set_flow_control(eth['flow_control'])
+ # configure ARP cache timeout in milliseconds
+ e.arp_cache_tmo = eth['ip_arp_cache_tmo']
+ # Enable proxy-arp on this interface
+ e.proxy_arp = eth['ip_proxy_arp']
+ # Enable private VLAN proxy ARP on this interface
+ e.proxy_arp_pvlan = eth['ip_proxy_arp_pvlan']
+
+ # Change interface MAC address - re-set to real hardware address (hw-id)
+ # if custom mac is removed
+ if eth['mac']:
+ e.mac = eth['mac']
+ else:
+ e.mac = eth['hw_id']
+
+ # Maximum Transmission Unit (MTU)
+ e.mtu = eth['mtu']
+
+ # GRO (generic receive offload)
+ e.set_gro(eth['offload_gro'])
+
+ # GSO (generic segmentation offload)
+ e.set_gso(eth['offload_gso'])
+
+ # scatter-gather option
+ e.set_sg(eth['offload_sg'])
+
+ # TSO (TCP segmentation offloading)
+ e.set_tso(eth['offload_tso'])
+
+ # UDP fragmentation offloading
+ e.set_ufo(eth['offload_ufo'])
+
+ # Set physical interface speed and duplex
+ e.set_speed_duplex(eth['speed'], eth['duplex'])
+
+ # Configure interface address(es)
+ # - not longer required addresses get removed first
+ # - newly addresses will be added second
+ for addr in eth['address_remove']:
+ e.del_addr(addr)
+ for addr in eth['address']:
+ e.add_addr(addr)
+
+ # Enable/Disable interface
+ if eth['disable']:
+ e.state = 'down'
+ else:
+ e.state = 'up'
+
+ # remove no longer required service VLAN interfaces (vif-s)
+ for vif_s in eth['vif_s_remove']:
+ e.del_vlan(vif_s)
+
+ # create service VLAN interfaces (vif-s)
+ for vif_s in eth['vif_s']:
+ s_vlan = e.add_vlan(vif_s['id'], ethertype=vif_s['ethertype'])
+ apply_vlan_config(s_vlan, vif_s)
+
+ # remove no longer required client VLAN interfaces (vif-c)
+ # on lower service VLAN interface
+ for vif_c in vif_s['vif_c_remove']:
+ s_vlan.del_vlan(vif_c)
+
+ # create client VLAN interfaces (vif-c)
+ # on lower service VLAN interface
+ for vif_c in vif_s['vif_c']:
+ c_vlan = s_vlan.add_vlan(vif_c['id'])
+ apply_vlan_config(c_vlan, vif_c)
+
+ # remove no longer required VLAN interfaces (vif)
+ for vif in eth['vif_remove']:
+ e.del_vlan(vif)
+
+ # create VLAN interfaces (vif)
+ for vif in eth['vif']:
+ # QoS priority mapping can only be set during interface creation
+ # so we delete the interface first if required.
+ if vif['egress_qos_changed'] or vif['ingress_qos_changed']:
+ try:
+ # on system bootup the above condition is true but the interface
+ # does not exists, which throws an exception, but that's legal
+ e.del_vlan(vif['id'])
+ except:
+ pass
+
+ vlan = e.add_vlan(vif['id'], ingress_qos=vif['ingress_qos'], egress_qos=vif['egress_qos'])
+ apply_vlan_config(vlan, vif)
+
+ return None
+
+if __name__ == '__main__':
+ try:
+ c = get_config()
+ verify(c)
+ generate(c)
+ apply(c)
+ except ConfigError as e:
+ print(e)
+ exit(1)
diff --git a/src/conf_mode/interface-openvpn.py b/src/conf_mode/interface-openvpn.py
index 34c094862..35e7928c2 100755
--- a/src/conf_mode/interface-openvpn.py
+++ b/src/conf_mode/interface-openvpn.py
@@ -167,10 +167,18 @@ key {{ tls_key }}
crl-verify {{ tls_crl }}
{% endif %}
+{%- if tls_version_min %}
+tls-version-min {{tls_version_min}}
+{% endif %}
+
{%- if tls_dh %}
dh {{ tls_dh }}
{% endif %}
+{%- if tls_auth %}
+tls-auth {{tls_auth}}
+{% endif %}
+
{%- if 'active' in tls_role %}
tls-client
{%- elif 'passive' in tls_role %}
@@ -277,12 +285,14 @@ default_config_data = {
'server_topology': '',
'shared_secret_file': '',
'tls': False,
+ 'tls_auth': '',
'tls_ca_cert': '',
'tls_cert': '',
'tls_crl': '',
'tls_dh': '',
'tls_key': '',
'tls_role': '',
+ 'tls_version_min': '',
'type': 'tun',
'uid': user,
'gid': group,
@@ -532,6 +542,11 @@ def get_config():
if conf.exists('server reject-unconfigured-clients'):
openvpn['server_reject_unconfigured'] = True
+ # File containing TLS auth static key
+ if conf.exists('tls auth-file'):
+ openvpn['tls_auth'] = conf.return_value('tls auth-file')
+ openvpn['tls'] = True
+
# File containing certificate for Certificate Authority (CA)
if conf.exists('tls ca-cert-file'):
openvpn['tls_ca_cert'] = conf.return_value('tls ca-cert-file')
@@ -562,6 +577,10 @@ def get_config():
openvpn['tls_role'] = conf.return_value('tls role')
openvpn['tls'] = True
+ # Minimum required TLS version
+ if conf.exists('tls tls-version-min'):
+ openvpn['tls_version_min'] = conf.return_value('tls tls-version-min')
+
if conf.exists('shared-secret-key-file'):
openvpn['shared_secret_file'] = conf.return_value('shared-secret-key-file')
@@ -714,11 +733,17 @@ def verify(openvpn):
if not checkCertHeader('-----BEGIN CERTIFICATE-----', openvpn['tls_ca_cert']):
raise ConfigError('Specified ca-cert-file "{}" is invalid'.format(openvpn['tls_ca_cert']))
- if not checkCertHeader('-----BEGIN CERTIFICATE-----', openvpn['tls_cert']):
- raise ConfigError('Specified cert-file "{}" is invalid'.format(openvpn['tls_cert']))
+ if openvpn['tls_auth']:
+ if not checkCertHeader('-----BEGIN OpenVPN Static key V1-----', openvpn['tls_auth']):
+ raise ConfigError('Specified auth-file "{}" is invalid'.format(openvpn['tls_auth']))
+
+ if openvpn['tls_cert']:
+ if not checkCertHeader('-----BEGIN CERTIFICATE-----', openvpn['tls_cert']):
+ raise ConfigError('Specified cert-file "{}" is invalid'.format(openvpn['tls_cert']))
- if not checkCertHeader('-----BEGIN (?:RSA )?PRIVATE KEY-----', openvpn['tls_key']):
- raise ConfigError('Specified key-file "{}" is not valid'.format(openvpn['tls_key']))
+ if openvpn['tls_key']:
+ if not checkCertHeader('-----BEGIN (?:RSA )?PRIVATE KEY-----', openvpn['tls_key']):
+ raise ConfigError('Specified key-file "{}" is not valid'.format(openvpn['tls_key']))
if openvpn['tls_crl']:
if not checkCertHeader('-----BEGIN X509 CRL-----', openvpn['tls_crl']):
@@ -730,7 +755,8 @@ def verify(openvpn):
if openvpn['tls_role']:
if openvpn['mode'] in ['client', 'server']:
- raise ConfigError('Cannot specify "tls role" in client-server mode')
+ if not openvpn['tls_auth']:
+ raise ConfigError('Cannot specify "tls role" in client-server mode')
if openvpn['tls_role'] == 'active':
if openvpn['protocol'] == 'tcp-passive':
diff --git a/src/conf_mode/interface-vxlan.py b/src/conf_mode/interface-vxlan.py
index 59022238e..e97b4bf99 100755
--- a/src/conf_mode/interface-vxlan.py
+++ b/src/conf_mode/interface-vxlan.py
@@ -28,7 +28,6 @@ from netifaces import interfaces
default_config_data = {
'address': [],
- 'address_remove': [],
'deleted': False,
'description': '',
'disable': False,
@@ -43,7 +42,6 @@ default_config_data = {
# the IANA's selection of a standard destination port
}
-
def get_config():
vxlan = deepcopy(default_config_data)
conf = Config()
@@ -66,12 +64,6 @@ def get_config():
if conf.exists('address'):
vxlan['address'] = conf.return_values('address')
- # Determine interface addresses (currently effective) - to determine which
- # address is no longer valid and needs to be removed from the interface
- eff_addr = conf.return_effective_values('address')
- act_addr = conf.return_values('address')
- vxlan['address_remove'] = list_diff(eff_addr, act_addr)
-
# retrieve interface description
if conf.exists('description'):
vxlan['description'] = conf.return_value('description')
@@ -180,11 +172,9 @@ def apply(vxlan):
# Enable proxy-arp on this interface
v.proxy_arp = vxlan['ip_proxy_arp']
- # Configure interface address(es)
- # - not longer required addresses get removed first
- # - newly addresses will be added second
- for addr in vxlan['address_remove']:
- v.del_addr(addr)
+ # Configure interface address(es) - no need to implicitly delete the
+ # old addresses as they have already been removed by deleting the
+ # interface above
for addr in vxlan['address']:
v.add_addr(addr)
diff --git a/src/conf_mode/interface-wireguard.py b/src/conf_mode/interface-wireguard.py
index d51a7a08d..4ae3251fe 100755
--- a/src/conf_mode/interface-wireguard.py
+++ b/src/conf_mode/interface-wireguard.py
@@ -26,12 +26,16 @@ from vyos.config import Config
from vyos import ConfigError
from vyos.ifconfig import WireGuardIf
-ifname = str(os.environ['VYOS_TAGNODE_VALUE'])
-intfc = WireGuardIf(ifname)
+try:
+ ifname = str(os.environ['VYOS_TAGNODE_VALUE'])
+ intfc = WireGuardIf(ifname)
+except KeyError:
+ print("Interface not specified")
+ sys.exit(1)
kdir = r'/config/auth/wireguard'
-def check_kmod():
+def _check_kmod():
if not os.path.exists('/sys/module/wireguard'):
sl.syslog(sl.LOG_NOTICE, "loading wirguard kmod")
if os.system('sudo modprobe wireguard') != 0:
@@ -39,6 +43,19 @@ def check_kmod():
raise ConfigError("modprobe wireguard failed")
+def _migrate_default_keys():
+ if os.path.exists('{}/private.key'.format(kdir)) and not os.path.exists('{}/default/private.key'.format(kdir)):
+ sl.syslog(sl.LOG_NOTICE, "migrate keypair to default")
+ old_umask = os.umask(0o027)
+ location = '{}/default'.format(kdir)
+ subprocess.call(['sudo mkdir -p ' + location], shell=True)
+ subprocess.call(['sudo chgrp vyattacfg ' + location], shell=True)
+ subprocess.call(['sudo chmod 750 ' + location], shell=True)
+ os.rename('{}/private.key'.format(kdir),'{}/private.key'.format(location))
+ os.rename('{}/public.key'.format(kdir),'{}/public.key'.format(location))
+ os.umask(old_umask)
+
+
def get_config():
c = Config()
if not c.exists('interfaces wireguard'):
@@ -257,7 +274,8 @@ def apply(c):
if __name__ == '__main__':
try:
- check_kmod()
+ _check_kmod()
+ _migrate_default_keys()
c = get_config()
verify(c)
apply(c)
diff --git a/src/conf_mode/ipoe_server.py b/src/conf_mode/ipoe_server.py
index ca6b423e5..a60379760 100755
--- a/src/conf_mode/ipoe_server.py
+++ b/src/conf_mode/ipoe_server.py
@@ -41,7 +41,6 @@ ipoe_config = '''
### generated by ipoe.py ###
[modules]
log_syslog
-ippool
ipoe
shaper
ipv6pool
@@ -50,6 +49,7 @@ ipv6_dhcp
{% if auth['mech'] == 'radius' %}
radius
{% endif -%}
+ippool
{% if auth['mech'] == 'local' %}
chap-secrets
{% endif %}
@@ -65,7 +65,11 @@ level=5
[ipoe]
verbose=1
{% for intfc in interfaces %}
+{% if interfaces[intfc]['vlan_mon'] %}
+interface=re:{{intfc}}\.\d+,\
+{% else %}
interface={{intfc}},\
+{% endif %}
shared={{interfaces[intfc]['shared']}},\
mode={{interfaces[intfc]['mode']}},\
ifcfg={{interfaces[intfc]['ifcfg']}},\
@@ -83,8 +87,7 @@ password=csid
{%- for intfc in interfaces %}
{% if (interfaces[intfc]['shared'] == '0') and (interfaces[intfc]['vlan_mon']) %}
-vlan_mon={{interfaces[intfc]['vlan_mon']|join(',')}}
-interface=re:{{intfc}}\.(409[0-6]|40[0-8][0-9]|[1-3][0-9]{3}|[1-9][0-9]{0,2})
+vlan-mon={{intfc}},{{interfaces[intfc]['vlan_mon']|join(',')}}
{% endif %}
{% endfor %}
@@ -160,16 +163,24 @@ nas-identifier={{auth['radsettings']['nas-identifier']}}
tcp=127.0.0.1:2002
'''
-### pppoe chap secrets
+### chap secrets
chap_secrets_conf = '''
# username server password acceptable local IP addresses shaper
{% for aifc in auth['auth_if'] %}
{% for mac in auth['auth_if'][aifc] %}
{% if (auth['auth_if'][aifc][mac]['up']) and (auth['auth_if'][aifc][mac]['down']) %}
+{% if auth['auth_if'][aifc][mac]['vlan'] %}
+{{aifc}}.{{auth['auth_if'][aifc][mac]['vlan']}}\t*\t{{mac.lower()}}\t*\t{{auth['auth_if'][aifc][mac]['down']}}/{{auth['auth_if'][aifc][mac]['up']}}
+{% else %}
{{aifc}}\t*\t{{mac.lower()}}\t*\t{{auth['auth_if'][aifc][mac]['down']}}/{{auth['auth_if'][aifc][mac]['up']}}
+{% endif %}
+{% else %}
+{% if auth['auth_if'][aifc][mac]['vlan'] %}
+{{aifc}}.{{auth['auth_if'][aifc][mac]['vlan']}}\t*\t{{mac.lower()}}\t*
{% else %}
{{aifc}}\t*\t{{mac.lower()}}\t*
{% endif %}
+{% endif %}
{% endfor %}
{% endfor %}
'''
@@ -213,6 +224,7 @@ def accel_cmd(cmd=''):
### chap_secrets file if auth mode local
def gen_chap_secrets(c):
+
tmpl = jinja2.Template(chap_secrets_conf, trim_blocks=True)
chap_secrets_txt = tmpl.render(c)
old_umask = os.umask(0o077)
@@ -296,6 +308,9 @@ def get_config():
config_data['auth']['auth_if'][auth_int][mac] = {}
config_data['auth']['auth_if'][auth_int][mac]['up'] = None
config_data['auth']['auth_if'][auth_int][mac]['down'] = None
+ ## client vlan-id
+ if c.exists('authentication interface ' + auth_int + ' mac-address ' + mac + ' vlan-id'):
+ config_data['auth']['auth_if'][auth_int][mac]['vlan'] = c.return_value('authentication interface ' + auth_int + ' mac-address ' + mac + ' vlan-id')
if c.exists('authentication mode radius'):
for rsrv in c.list_nodes('authentication radius-server'):
config_data['auth']['radius'][rsrv] = {}
diff --git a/src/helpers/vyos-boot-config-loader.py b/src/helpers/vyos-boot-config-loader.py
index 06c95765f..7c81a4c3c 100755
--- a/src/helpers/vyos-boot-config-loader.py
+++ b/src/helpers/vyos-boot-config-loader.py
@@ -18,41 +18,72 @@
import os
import sys
+import pwd
+import grp
import subprocess
import traceback
+from datetime import datetime
+from vyos.defaults import directories
from vyos.configsession import ConfigSession, ConfigSessionError
from vyos.configtree import ConfigTree
STATUS_FILE = '/tmp/vyos-config-status'
TRACE_FILE = '/tmp/boot-config-trace'
-session = ConfigSession(os.getpid(), 'vyos-boot-config-loader')
-env = session.get_session_env()
+CFG_GROUP = 'vyattacfg'
-default_file_name = env['vyatta_sysconfdir'] + '/config.boot.default'
-
-if len(sys.argv) < 1:
- print("Must be called with argument.")
- sys.exit(1)
+if 'log' in directories:
+ LOG_DIR = directories['log']
else:
- file_name = sys.argv[1]
+ LOG_DIR = '/var/log/vyatta'
+
+LOG_FILE = LOG_DIR + '/vyos-boot-config-loader.log'
+
+try:
+ with open('/proc/cmdline', 'r') as f:
+ cmdline = f.read()
+ if 'vyos-debug' in cmdline:
+ os.environ['VYOS_DEBUG'] = 'yes'
+except Exception as e:
+ print('{0}'.format(e))
def write_config_status(status):
- with open(STATUS_FILE, 'w') as f:
- f.write('{0}\n'.format(status))
+ try:
+ with open(STATUS_FILE, 'w') as f:
+ f.write('{0}\n'.format(status))
+ except Exception as e:
+ print('{0}'.format(e))
def trace_to_file(trace_file_name):
- with open(trace_file_name, 'w') as trace_file:
- traceback.print_exc(file=trace_file)
+ try:
+ with open(trace_file_name, 'w') as trace_file:
+ traceback.print_exc(file=trace_file)
+ except Exception as e:
+ print('{0}'.format(e))
+
+def failsafe(config_file_name):
+ fail_msg = """
+ !!!!!
+ There were errors loading the configuration
+ Please examine the errors in
+ {0}
+ and correct
+ !!!!!
+ """.format(TRACE_FILE)
+
+ print(fail_msg, file=sys.stderr)
+
+ users = [x[0] for x in pwd.getpwall()]
+ if 'vyos' in users:
+ return
-def failsafe():
try:
- with open(default_file_name, 'r') as f:
+ with open(config_file_name, 'r') as f:
config_file = f.read()
except Exception as e:
print("Catastrophic: no default config file "
- "'{0}'".format(default_file_name))
+ "'{0}'".format(config_file_name))
sys.exit(1)
config = ConfigTree(config_file)
@@ -73,29 +104,73 @@ def failsafe():
except subprocess.CalledProcessError as e:
sys.exit("{0}".format(e))
- with open('/etc/motd', 'a+') as f:
- f.write('\n\n')
- f.write('!!!!!\n')
- f.write('There were errors loading the initial configuration;\n')
- f.write('please examine the errors in {0} and correct.'
- '\n'.format(TRACE_FILE))
- f.write('!!!!!\n\n')
+if __name__ == '__main__':
+ if len(sys.argv) < 2:
+ print("Must specify boot config file.")
+ sys.exit(1)
+ else:
+ file_name = sys.argv[1]
-try:
- with open(file_name, 'r') as f:
- config_file = f.read()
-except Exception as e:
- write_config_status(1)
- failsafe()
- trace_to_file(TRACE_FILE)
- sys.exit("{0}".format(e))
+ # Set user and group options, so that others will be able to commit
+ # Currently, the only caller does 'sg CFG_GROUP', but that may change
+ cfg_group = grp.getgrnam(CFG_GROUP)
+ os.setgid(cfg_group.gr_gid)
-try:
- session.load_config(file_name)
- session.commit()
- write_config_status(0)
-except ConfigSessionError as e:
- write_config_status(1)
- failsafe()
- trace_to_file(TRACE_FILE)
- sys.exit(1)
+ # Need to set file permissions to 775 so that every vyattacfg group
+ # member has write access to the running config
+ os.umask(0o002)
+
+ session = ConfigSession(os.getpid(), 'vyos-boot-config-loader')
+ env = session.get_session_env()
+
+ default_file_name = env['vyatta_sysconfdir'] + '/config.boot.default'
+
+ try:
+ with open(file_name, 'r') as f:
+ config_file = f.read()
+ except Exception:
+ write_config_status(1)
+ failsafe(default_file_name)
+ trace_to_file(TRACE_FILE)
+ sys.exit(1)
+
+ try:
+ time_begin_load = datetime.now()
+ load_out = session.load_config(file_name)
+ time_end_load = datetime.now()
+ time_begin_commit = datetime.now()
+ commit_out = session.commit()
+ time_end_commit = datetime.now()
+ write_config_status(0)
+ except ConfigSessionError:
+ # If here, there is no use doing session.discard, as we have no
+ # recoverable config environment, and will only throw an error
+ write_config_status(1)
+ failsafe(default_file_name)
+ trace_to_file(TRACE_FILE)
+ sys.exit(1)
+
+ time_elapsed_load = time_end_load - time_begin_load
+ time_elapsed_commit = time_end_commit - time_begin_commit
+
+ try:
+ if not os.path.exists(LOG_DIR):
+ os.mkdir(LOG_DIR)
+ with open(LOG_FILE, 'a') as f:
+ f.write('\n\n')
+ f.write('{0} Begin config load\n'
+ ''.format(time_begin_load))
+ f.write(load_out)
+ f.write('{0} End config load\n'
+ ''.format(time_end_load))
+ f.write('Elapsed time for config load: {0}\n'
+ ''.format(time_elapsed_load))
+ f.write('{0} Begin config commit\n'
+ ''.format(time_begin_commit))
+ f.write(commit_out)
+ f.write('{0} End config commit\n'
+ ''.format(time_end_commit))
+ f.write('Elapsed time for config commit: {0}\n'
+ ''.format(time_elapsed_commit))
+ except Exception as e:
+ print('{0}'.format(e))
diff --git a/src/services/vyos-hostsd b/src/services/vyos-hostsd
index 8f70eb4e9..e7ecd8573 100755
--- a/src/services/vyos-hostsd
+++ b/src/services/vyos-hostsd
@@ -43,7 +43,7 @@ hosts_tmpl_source = """
# Local host
127.0.0.1 localhost
-127.0.1.1 {{ host_name }}{% if domain_name %}.{{ domain_name }}{% endif %}
+127.0.1.1 {{ host_name }}{% if domain_name %}.{{ domain_name }} {{ host_name }}{% endif %}
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback