summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/dhcp_server.py12
-rwxr-xr-xsrc/conf_mode/dhcpv6_server.py2
-rwxr-xr-xsrc/conf_mode/dynamic_dns.py4
-rwxr-xr-xsrc/conf_mode/host_name.py2
-rwxr-xr-xsrc/conf_mode/interfaces-tunnel.py4
-rwxr-xr-xsrc/conf_mode/service_mdns-repeater.py12
-rwxr-xr-xsrc/conf_mode/snmp.py9
-rwxr-xr-xsrc/conf_mode/vpn_sstp.py2
-rw-r--r--src/etc/dhcp/dhclient-exit-hooks.d/01-vyos-cleanup12
-rw-r--r--src/etc/systemd/system/avahi-daemon.service.d/override.conf8
-rwxr-xr-xsrc/helpers/strip-private.py1
-rwxr-xr-xsrc/migration-scripts/interfaces/21-to-22141
-rwxr-xr-xsrc/migration-scripts/interfaces/22-to-23143
-rwxr-xr-xsrc/migration-scripts/interfaces/23-to-24379
-rwxr-xr-xsrc/migration-scripts/interfaces/24-to-25369
-rwxr-xr-xsrc/op_mode/show_ram.py64
-rwxr-xr-xsrc/op_mode/show_ram.sh33
-rwxr-xr-xsrc/op_mode/show_uptime.py50
-rwxr-xr-xsrc/services/vyos-hostsd2
19 files changed, 702 insertions, 547 deletions
diff --git a/src/conf_mode/dhcp_server.py b/src/conf_mode/dhcp_server.py
index 28f2a4ca5..a8cef5ebf 100755
--- a/src/conf_mode/dhcp_server.py
+++ b/src/conf_mode/dhcp_server.py
@@ -151,9 +151,15 @@ def verify(dhcp):
listen_ok = False
subnets = []
failover_ok = False
+ shared_networks = len(dhcp['shared_network_name'])
+ disabled_shared_networks = 0
+
# A shared-network requires a subnet definition
for network, network_config in dhcp['shared_network_name'].items():
+ if 'disable' in network_config:
+ disabled_shared_networks += 1
+
if 'subnet' not in network_config:
raise ConfigError(f'No subnets defined for {network}. At least one\n' \
'lease subnet must be configured.')
@@ -226,7 +232,7 @@ def verify(dhcp):
# There must be one subnet connected to a listen interface.
# This only counts if the network itself is not disabled!
if 'disable' not in network_config:
- if is_subnet_connected(subnet, primary=True):
+ if is_subnet_connected(subnet, primary=False):
listen_ok = True
# Subnets must be non overlapping
@@ -243,6 +249,10 @@ def verify(dhcp):
if net.overlaps(net2):
raise ConfigError('Conflicting subnet ranges: "{net}" overlaps "{net2}"!')
+ # Prevent 'disable' for shared-network if only one network is configured
+ if (shared_networks - disabled_shared_networks) < 1:
+ raise ConfigError(f'At least one shared network must be active!')
+
if 'failover' in dhcp:
if not failover_ok:
raise ConfigError('DHCP failover must be enabled for at least one subnet!')
diff --git a/src/conf_mode/dhcpv6_server.py b/src/conf_mode/dhcpv6_server.py
index 175300bb0..e6a2e4486 100755
--- a/src/conf_mode/dhcpv6_server.py
+++ b/src/conf_mode/dhcpv6_server.py
@@ -128,7 +128,7 @@ def verify(dhcpv6):
# Subnets must be unique
if subnet in subnets:
- raise ConfigError('DHCPv6 subnets must be unique! Subnet {0} defined multiple times!'.format(subnet['network']))
+ raise ConfigError(f'DHCPv6 subnets must be unique! Subnet {subnet} defined multiple times!')
subnets.append(subnet)
# DHCPv6 requires at least one configured address range or one static mapping
diff --git a/src/conf_mode/dynamic_dns.py b/src/conf_mode/dynamic_dns.py
index 646de6324..a31e5ed75 100755
--- a/src/conf_mode/dynamic_dns.py
+++ b/src/conf_mode/dynamic_dns.py
@@ -131,9 +131,7 @@ def generate(dyndns):
if not dyndns:
return None
- render(config_file, 'dynamic-dns/ddclient.conf.tmpl', dyndns,
- permission=0o644)
-
+ render(config_file, 'dynamic-dns/ddclient.conf.tmpl', dyndns)
return None
def apply(dyndns):
diff --git a/src/conf_mode/host_name.py b/src/conf_mode/host_name.py
index a7135911d..87bad0dc6 100755
--- a/src/conf_mode/host_name.py
+++ b/src/conf_mode/host_name.py
@@ -79,7 +79,7 @@ def get_config(config=None):
# system static-host-mapping
for hn in conf.list_nodes(['system', 'static-host-mapping', 'host-name']):
hosts['static_host_mapping'][hn] = {}
- hosts['static_host_mapping'][hn]['address'] = conf.return_value(['system', 'static-host-mapping', 'host-name', hn, 'inet'])
+ hosts['static_host_mapping'][hn]['address'] = conf.return_values(['system', 'static-host-mapping', 'host-name', hn, 'inet'])
hosts['static_host_mapping'][hn]['aliases'] = conf.return_values(['system', 'static-host-mapping', 'host-name', hn, 'alias'])
return hosts
diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py
index 51127127d..da8624202 100755
--- a/src/conf_mode/interfaces-tunnel.py
+++ b/src/conf_mode/interfaces-tunnel.py
@@ -98,7 +98,7 @@ def verify(tunnel):
# If tunnel source address any and key not set
if tunnel['encapsulation'] in ['gre'] and \
- tunnel['source_address'] == '0.0.0.0' and \
+ dict_search('source_address', tunnel) == '0.0.0.0' and \
dict_search('parameters.ip.key', tunnel) == None:
raise ConfigError('Tunnel parameters ip key must be set!')
@@ -111,7 +111,7 @@ def verify(tunnel):
# no match on encapsulation - bail out
if dict_search('linkinfo.info_kind', tunnel_cfg) != tunnel['encapsulation']:
continue
- new_source_address = tunnel['source_address']
+ new_source_address = dict_search('source_address', tunnel)
# Convert tunnel key to ip key, format "ip -j link show"
# 1 => 0.0.0.1, 999 => 0.0.3.231
orig_new_key = dict_search('parameters.ip.key', tunnel)
diff --git a/src/conf_mode/service_mdns-repeater.py b/src/conf_mode/service_mdns-repeater.py
index c920920ed..d31a0c49e 100755
--- a/src/conf_mode/service_mdns-repeater.py
+++ b/src/conf_mode/service_mdns-repeater.py
@@ -28,7 +28,7 @@ from vyos import ConfigError
from vyos import airbag
airbag.enable()
-config_file = r'/etc/default/mdns-repeater'
+config_file = '/run/avahi-daemon/avahi-daemon.conf'
vrrp_running_file = '/run/mdns_vrrp_active'
def get_config(config=None):
@@ -92,12 +92,12 @@ def generate(mdns):
if len(mdns['interface']) < 2:
return None
- render(config_file, 'mdns-repeater/mdns-repeater.tmpl', mdns)
+ render(config_file, 'mdns-repeater/avahi-daemon.tmpl', mdns)
return None
def apply(mdns):
if not mdns or 'disable' in mdns:
- call('systemctl stop mdns-repeater.service')
+ call('systemctl stop avahi-daemon.service')
if os.path.exists(config_file):
os.unlink(config_file)
@@ -106,16 +106,16 @@ def apply(mdns):
else:
if 'vrrp_disable' not in mdns and os.path.exists(vrrp_running_file):
os.unlink(vrrp_running_file)
-
+
if mdns['vrrp_exists'] and 'vrrp_disable' in mdns:
if not os.path.exists(vrrp_running_file):
os.mknod(vrrp_running_file) # vrrp script looks for this file to update mdns repeater
if len(mdns['interface']) < 2:
- call('systemctl stop mdns-repeater.service')
+ call('systemctl stop avahi-daemon.service')
return None
- call('systemctl restart mdns-repeater.service')
+ call('systemctl restart avahi-daemon.service')
return None
diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py
index 23e45a5b7..2a420b193 100755
--- a/src/conf_mode/snmp.py
+++ b/src/conf_mode/snmp.py
@@ -52,6 +52,7 @@ default_config_data = {
'communities': [],
'smux_peers': [],
'location' : '',
+ 'protocol' : 'udp',
'description' : '',
'contact' : '',
'route_table': 'False',
@@ -151,6 +152,9 @@ def get_config():
if conf.exists('location'):
snmp['location'] = conf.return_value('location')
+ if conf.exists('protocol'):
+ snmp['protocol'] = conf.return_value('protocol')
+
if conf.exists('smux-peer'):
snmp['smux_peers'] = conf.return_values('smux-peer')
@@ -404,13 +408,14 @@ def verify(snmp):
for listen in snmp['listen_address']:
addr = listen[0]
port = listen[1]
+ protocol = snmp['protocol']
if is_ipv4(addr):
# example: udp:127.0.0.1:161
- listen = 'udp:' + addr + ':' + port
+ listen = f'{protocol}:{addr}:{port}'
elif snmp['ipv6_enabled']:
# example: udp6:[::1]:161
- listen = 'udp6:' + '[' + addr + ']' + ':' + port
+ listen = f'{protocol}6:[{addr}]:{port}'
# We only wan't to configure addresses that exist on the system.
# Hint the user if they don't exist
diff --git a/src/conf_mode/vpn_sstp.py b/src/conf_mode/vpn_sstp.py
index d1a71a5ad..68139dc47 100755
--- a/src/conf_mode/vpn_sstp.py
+++ b/src/conf_mode/vpn_sstp.py
@@ -58,7 +58,7 @@ def verify(sstp):
verify_accel_ppp_base_service(sstp)
- if not sstp['client_ip_pool']:
+ if 'client_ip_pool' not in sstp and 'client_ipv6_pool' not in sstp:
raise ConfigError('Client IP subnet required')
#
diff --git a/src/etc/dhcp/dhclient-exit-hooks.d/01-vyos-cleanup b/src/etc/dhcp/dhclient-exit-hooks.d/01-vyos-cleanup
index 694d53b6b..fec792b64 100644
--- a/src/etc/dhcp/dhclient-exit-hooks.d/01-vyos-cleanup
+++ b/src/etc/dhcp/dhclient-exit-hooks.d/01-vyos-cleanup
@@ -15,10 +15,16 @@ if [[ $reason =~ (EXPIRE|FAIL|RELEASE|STOP) ]]; then
if_metric="$IF_METRIC"
- # try to delete default ip route
+ # try to delete default ip route
for router in $old_routers; do
- logmsg info "Deleting default route: via $router dev ${interface} ${if_metric:+metric $if_metric}"
- ip -4 route del default via $router dev ${interface} ${if_metric:+metric $if_metric}
+ # check if we are bound to a VRF
+ local vrf_name=$(basename /sys/class/net/${interface}/upper_* | sed -e 's/upper_//')
+ if [ "$vrf_name" != "*" ]; then
+ vrf="vrf $vrf_name"
+ fi
+
+ logmsg info "Deleting default route: via $router dev ${interface} ${if_metric:+metric $if_metric} ${vrf}"
+ ip -4 route del default via $router dev ${interface} ${if_metric:+metric $if_metric} ${vrf}
if_metric=$((if_metric+1))
done
diff --git a/src/etc/systemd/system/avahi-daemon.service.d/override.conf b/src/etc/systemd/system/avahi-daemon.service.d/override.conf
new file mode 100644
index 000000000..a9d2085f7
--- /dev/null
+++ b/src/etc/systemd/system/avahi-daemon.service.d/override.conf
@@ -0,0 +1,8 @@
+[Unit]
+After=
+After=vyos-router.service
+ConditionPathExists=/run/avahi-daemon/avahi-daemon.conf
+
+[Service]
+ExecStart=
+ExecStart=/usr/sbin/avahi-daemon --syslog --file /run/avahi-daemon/avahi-daemon.conf \ No newline at end of file
diff --git a/src/helpers/strip-private.py b/src/helpers/strip-private.py
index c74a379aa..e4e1fe11d 100755
--- a/src/helpers/strip-private.py
+++ b/src/helpers/strip-private.py
@@ -106,6 +106,7 @@ if __name__ == "__main__":
stripping_rules = [
# Strip passwords
(True, re.compile(r'password \S+'), 'password xxxxxx'),
+ (True, re.compile(r'cisco-authentication \S+'), 'cisco-authentication xxxxxx'),
# Strip public key information
(True, re.compile(r'public-keys \S+'), 'public-keys xxxx@xxx.xxx'),
(True, re.compile(r'type \'ssh-(rsa|dss)\''), 'type ssh-xxx'),
diff --git a/src/migration-scripts/interfaces/21-to-22 b/src/migration-scripts/interfaces/21-to-22
index 06e07572f..098102102 100755
--- a/src/migration-scripts/interfaces/21-to-22
+++ b/src/migration-scripts/interfaces/21-to-22
@@ -15,131 +15,32 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from sys import argv
-from sys import exit
from vyos.configtree import ConfigTree
-def migrate_ospf(config, path, interface):
- path = path + ['ospf']
- if config.exists(path):
- new_base = ['protocols', 'ospf', 'interface']
- config.set(new_base)
- config.set_tag(new_base)
- config.copy(path, new_base + [interface])
- config.delete(path)
+if (len(argv) < 1):
+ print("Must specify file name!")
+ exit(1)
- # if "ip ospf" was the only setting, we can clean out the empty
- # ip node afterwards
- if len(config.list_nodes(path[:-1])) == 0:
- config.delete(path[:-1])
+file_name = argv[1]
+with open(file_name, 'r') as f:
+ config_file = f.read()
-def migrate_ospfv3(config, path, interface):
- path = path + ['ospfv3']
- if config.exists(path):
- new_base = ['protocols', 'ospfv3', 'interface']
- config.set(new_base)
- config.set_tag(new_base)
- config.copy(path, new_base + [interface])
- config.delete(path)
+config = ConfigTree(config_file)
+base = ['interfaces', 'tunnel']
- # if "ipv6 ospfv3" was the only setting, we can clean out the empty
- # ip node afterwards
- if len(config.list_nodes(path[:-1])) == 0:
- config.delete(path[:-1])
+if not config.exists(base):
+ exit(0)
-def migrate_rip(config, path, interface):
- path = path + ['rip']
+for interface in config.list_nodes(base):
+ path = base + [interface, 'dhcp-interface']
if config.exists(path):
- new_base = ['protocols', 'rip', 'interface']
- config.set(new_base)
- config.set_tag(new_base)
- config.copy(path, new_base + [interface])
+ tmp = config.return_value(path)
config.delete(path)
-
- # if "ip rip" was the only setting, we can clean out the empty
- # ip node afterwards
- if len(config.list_nodes(path[:-1])) == 0:
- config.delete(path[:-1])
-
-def migrate_ripng(config, path, interface):
- path = path + ['ripng']
- if config.exists(path):
- new_base = ['protocols', 'ripng', 'interface']
- config.set(new_base)
- config.set_tag(new_base)
- config.copy(path, new_base + [interface])
- config.delete(path)
-
- # if "ipv6 ripng" was the only setting, we can clean out the empty
- # ip node afterwards
- if len(config.list_nodes(path[:-1])) == 0:
- config.delete(path[:-1])
-
-if __name__ == '__main__':
- if (len(argv) < 1):
- print("Must specify file name!")
- exit(1)
-
- file_name = argv[1]
- with open(file_name, 'r') as f:
- config_file = f.read()
-
- config = ConfigTree(config_file)
-
- #
- # Migrate "interface ethernet eth0 ip ospf" to "protocols ospf interface eth0"
- #
- for type in config.list_nodes(['interfaces']):
- for interface in config.list_nodes(['interfaces', type]):
- ip_base = ['interfaces', type, interface, 'ip']
- ipv6_base = ['interfaces', type, interface, 'ipv6']
- migrate_rip(config, ip_base, interface)
- migrate_ripng(config, ipv6_base, interface)
- migrate_ospf(config, ip_base, interface)
- migrate_ospfv3(config, ipv6_base, interface)
-
- vif_path = ['interfaces', type, interface, 'vif']
- if config.exists(vif_path):
- for vif in config.list_nodes(vif_path):
- vif_ip_base = vif_path + [vif, 'ip']
- vif_ipv6_base = vif_path + [vif, 'ipv6']
- ifname = f'{interface}.{vif}'
-
- migrate_rip(config, vif_ip_base, ifname)
- migrate_ripng(config, vif_ipv6_base, ifname)
- migrate_ospf(config, vif_ip_base, ifname)
- migrate_ospfv3(config, vif_ipv6_base, ifname)
-
-
- vif_s_path = ['interfaces', type, interface, 'vif-s']
- if config.exists(vif_s_path):
- for vif_s in config.list_nodes(vif_s_path):
- vif_s_ip_base = vif_s_path + [vif_s, 'ip']
- vif_s_ipv6_base = vif_s_path + [vif_s, 'ipv6']
-
- # vif-c interfaces MUST be migrated before their parent vif-s
- # interface as the migrate_*() functions delete the path!
- vif_c_path = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c']
- if config.exists(vif_c_path):
- for vif_c in config.list_nodes(vif_c_path):
- vif_c_ip_base = vif_c_path + [vif_c, 'ip']
- vif_c_ipv6_base = vif_c_path + [vif_c, 'ipv6']
- ifname = f'{interface}.{vif_s}.{vif_c}'
-
- migrate_rip(config, vif_c_ip_base, ifname)
- migrate_ripng(config, vif_c_ipv6_base, ifname)
- migrate_ospf(config, vif_c_ip_base, ifname)
- migrate_ospfv3(config, vif_c_ipv6_base, ifname)
-
-
- ifname = f'{interface}.{vif_s}'
- migrate_rip(config, vif_s_ip_base, ifname)
- migrate_ripng(config, vif_s_ipv6_base, ifname)
- migrate_ospf(config, vif_s_ip_base, ifname)
- migrate_ospfv3(config, vif_s_ipv6_base, ifname)
-
- try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+ config.set(base + [interface, 'source-interface'], value=tmp)
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ exit(1)
diff --git a/src/migration-scripts/interfaces/22-to-23 b/src/migration-scripts/interfaces/22-to-23
index d1ec2ad3e..06e07572f 100755
--- a/src/migration-scripts/interfaces/22-to-23
+++ b/src/migration-scripts/interfaces/22-to-23
@@ -14,47 +14,132 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# A VTI interface also requires an IPSec configuration - VyOS 1.2 supported
-# having a VTI interface in the CLI but no IPSec configuration - drop VTI
-# configuration if this is the case for VyOS 1.4
-
-import sys
+from sys import argv
+from sys import exit
from vyos.configtree import ConfigTree
+def migrate_ospf(config, path, interface):
+ path = path + ['ospf']
+ if config.exists(path):
+ new_base = ['protocols', 'ospf', 'interface']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.copy(path, new_base + [interface])
+ config.delete(path)
+
+ # if "ip ospf" was the only setting, we can clean out the empty
+ # ip node afterwards
+ if len(config.list_nodes(path[:-1])) == 0:
+ config.delete(path[:-1])
+
+def migrate_ospfv3(config, path, interface):
+ path = path + ['ospfv3']
+ if config.exists(path):
+ new_base = ['protocols', 'ospfv3', 'interface']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.copy(path, new_base + [interface])
+ config.delete(path)
+
+ # if "ipv6 ospfv3" was the only setting, we can clean out the empty
+ # ip node afterwards
+ if len(config.list_nodes(path[:-1])) == 0:
+ config.delete(path[:-1])
+
+def migrate_rip(config, path, interface):
+ path = path + ['rip']
+ if config.exists(path):
+ new_base = ['protocols', 'rip', 'interface']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.copy(path, new_base + [interface])
+ config.delete(path)
+
+ # if "ip rip" was the only setting, we can clean out the empty
+ # ip node afterwards
+ if len(config.list_nodes(path[:-1])) == 0:
+ config.delete(path[:-1])
+
+def migrate_ripng(config, path, interface):
+ path = path + ['ripng']
+ if config.exists(path):
+ new_base = ['protocols', 'ripng', 'interface']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.copy(path, new_base + [interface])
+ config.delete(path)
+
+ # if "ipv6 ripng" was the only setting, we can clean out the empty
+ # ip node afterwards
+ if len(config.list_nodes(path[:-1])) == 0:
+ config.delete(path[:-1])
+
if __name__ == '__main__':
- if (len(sys.argv) < 1):
+ if (len(argv) < 1):
print("Must specify file name!")
- sys.exit(1)
-
- file_name = sys.argv[1]
+ exit(1)
+ file_name = argv[1]
with open(file_name, 'r') as f:
config_file = f.read()
config = ConfigTree(config_file)
- base = ['interfaces', 'vti']
- if not config.exists(base):
- # Nothing to do
- sys.exit(0)
-
- ipsec_base = ['vpn', 'ipsec', 'site-to-site', 'peer']
- for interface in config.list_nodes(base):
- found = False
- if config.exists(ipsec_base):
- for peer in config.list_nodes(ipsec_base):
- if config.exists(ipsec_base + [peer, 'vti', 'bind']):
- tmp = config.return_value(ipsec_base + [peer, 'vti', 'bind'])
- if tmp == interface:
- # Interface was found and we no longer need to search
- # for it in our IPSec peers
- found = True
- break
- if not found:
- config.delete(base + [interface])
+
+ #
+ # Migrate "interface ethernet eth0 ip ospf" to "protocols ospf interface eth0"
+ #
+ for type in config.list_nodes(['interfaces']):
+ for interface in config.list_nodes(['interfaces', type]):
+ ip_base = ['interfaces', type, interface, 'ip']
+ ipv6_base = ['interfaces', type, interface, 'ipv6']
+ migrate_rip(config, ip_base, interface)
+ migrate_ripng(config, ipv6_base, interface)
+ migrate_ospf(config, ip_base, interface)
+ migrate_ospfv3(config, ipv6_base, interface)
+
+ vif_path = ['interfaces', type, interface, 'vif']
+ if config.exists(vif_path):
+ for vif in config.list_nodes(vif_path):
+ vif_ip_base = vif_path + [vif, 'ip']
+ vif_ipv6_base = vif_path + [vif, 'ipv6']
+ ifname = f'{interface}.{vif}'
+
+ migrate_rip(config, vif_ip_base, ifname)
+ migrate_ripng(config, vif_ipv6_base, ifname)
+ migrate_ospf(config, vif_ip_base, ifname)
+ migrate_ospfv3(config, vif_ipv6_base, ifname)
+
+
+ vif_s_path = ['interfaces', type, interface, 'vif-s']
+ if config.exists(vif_s_path):
+ for vif_s in config.list_nodes(vif_s_path):
+ vif_s_ip_base = vif_s_path + [vif_s, 'ip']
+ vif_s_ipv6_base = vif_s_path + [vif_s, 'ipv6']
+
+ # vif-c interfaces MUST be migrated before their parent vif-s
+ # interface as the migrate_*() functions delete the path!
+ vif_c_path = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c']
+ if config.exists(vif_c_path):
+ for vif_c in config.list_nodes(vif_c_path):
+ vif_c_ip_base = vif_c_path + [vif_c, 'ip']
+ vif_c_ipv6_base = vif_c_path + [vif_c, 'ipv6']
+ ifname = f'{interface}.{vif_s}.{vif_c}'
+
+ migrate_rip(config, vif_c_ip_base, ifname)
+ migrate_ripng(config, vif_c_ipv6_base, ifname)
+ migrate_ospf(config, vif_c_ip_base, ifname)
+ migrate_ospfv3(config, vif_c_ipv6_base, ifname)
+
+
+ ifname = f'{interface}.{vif_s}'
+ migrate_rip(config, vif_s_ip_base, ifname)
+ migrate_ripng(config, vif_s_ipv6_base, ifname)
+ migrate_ospf(config, vif_s_ip_base, ifname)
+ migrate_ospfv3(config, vif_s_ipv6_base, ifname)
try:
with open(file_name, 'w') as f:
f.write(config.to_string())
except OSError as e:
print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ exit(1)
diff --git a/src/migration-scripts/interfaces/23-to-24 b/src/migration-scripts/interfaces/23-to-24
index 93ce9215f..d1ec2ad3e 100755
--- a/src/migration-scripts/interfaces/23-to-24
+++ b/src/migration-scripts/interfaces/23-to-24
@@ -14,356 +14,47 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# Migrate Wireguard to store keys in CLI
-# Migrate EAPoL to PKI configuration
+# A VTI interface also requires an IPSec configuration - VyOS 1.2 supported
+# having a VTI interface in the CLI but no IPSec configuration - drop VTI
+# configuration if this is the case for VyOS 1.4
-import os
import sys
from vyos.configtree import ConfigTree
-from vyos.pki import load_certificate
-from vyos.pki import load_crl
-from vyos.pki import load_dh_parameters
-from vyos.pki import load_private_key
-from vyos.pki import encode_certificate
-from vyos.pki import encode_dh_parameters
-from vyos.pki import encode_private_key
-from vyos.util import run
-def wrapped_pem_to_config_value(pem):
- out = []
- for line in pem.strip().split("\n"):
- if not line or line.startswith("-----") or line[0] == '#':
- continue
- out.append(line)
- return "".join(out)
+if __name__ == '__main__':
+ if (len(sys.argv) < 1):
+ print("Must specify file name!")
+ sys.exit(1)
-def read_file_for_pki(config_auth_path):
- full_path = os.path.join(AUTH_DIR, config_auth_path)
- output = None
+ file_name = sys.argv[1]
- if os.path.isfile(full_path):
- if not os.access(full_path, os.R_OK):
- run(f'sudo chmod 644 {full_path}')
+ with open(file_name, 'r') as f:
+ config_file = f.read()
- with open(full_path, 'r') as f:
- output = f.read()
+ config = ConfigTree(config_file)
+ base = ['interfaces', 'vti']
+ if not config.exists(base):
+ # Nothing to do
+ sys.exit(0)
- return output
-
-if (len(sys.argv) < 1):
- print("Must specify file name!")
- sys.exit(1)
-
-file_name = sys.argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-AUTH_DIR = '/config/auth'
-pki_base = ['pki']
-
-# OpenVPN
-base = ['interfaces', 'openvpn']
-
-if config.exists(base):
- for interface in config.list_nodes(base):
- x509_base = base + [interface, 'tls']
- pki_name = f'openvpn_{interface}'
-
- if config.exists(base + [interface, 'shared-secret-key-file']):
- if not config.exists(pki_base + ['openvpn', 'shared-secret']):
- config.set(pki_base + ['openvpn', 'shared-secret'])
- config.set_tag(pki_base + ['openvpn', 'shared-secret'])
-
- key_file = config.return_value(base + [interface, 'shared-secret-key-file'])
- key = read_file_for_pki(key_file)
- key_pki_name = f'{pki_name}_shared'
-
- if key:
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
- config.set(base + [interface, 'shared-secret-key'], value=key_pki_name)
- else:
- print(f'Failed to migrate shared-secret-key on openvpn interface {interface}')
-
- config.delete(base + [interface, 'shared-secret-key-file'])
-
- if not config.exists(base + [interface, 'tls']):
- continue
-
- if config.exists(base + [interface, 'tls', 'auth-file']):
- if not config.exists(pki_base + ['openvpn', 'shared-secret']):
- config.set(pki_base + ['openvpn', 'shared-secret'])
- config.set_tag(pki_base + ['openvpn', 'shared-secret'])
-
- key_file = config.return_value(base + [interface, 'tls', 'auth-file'])
- key = read_file_for_pki(key_file)
- key_pki_name = f'{pki_name}_auth'
-
- if key:
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
- config.set(base + [interface, 'tls', 'auth-key'], value=key_pki_name)
- else:
- print(f'Failed to migrate auth-key on openvpn interface {interface}')
-
- config.delete(base + [interface, 'tls', 'auth-file'])
-
- if config.exists(base + [interface, 'tls', 'crypt-file']):
- if not config.exists(pki_base + ['openvpn', 'shared-secret']):
- config.set(pki_base + ['openvpn', 'shared-secret'])
- config.set_tag(pki_base + ['openvpn', 'shared-secret'])
-
- key_file = config.return_value(base + [interface, 'tls', 'crypt-file'])
- key = read_file_for_pki(key_file)
- key_pki_name = f'{pki_name}_crypt'
-
- if key:
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
- config.set(base + [interface, 'tls', 'crypt-key'], value=key_pki_name)
- else:
- print(f'Failed to migrate crypt-key on openvpn interface {interface}')
-
- config.delete(base + [interface, 'tls', 'crypt-file'])
-
- if config.exists(x509_base + ['ca-cert-file']):
- if not config.exists(pki_base + ['ca']):
- config.set(pki_base + ['ca'])
- config.set_tag(pki_base + ['ca'])
-
- cert_file = config.return_value(x509_base + ['ca-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['ca-certificate'], value=pki_name)
- else:
- print(f'Failed to migrate CA certificate on openvpn interface {interface}')
-
- config.delete(x509_base + ['ca-cert-file'])
-
- if config.exists(x509_base + ['crl-file']):
- if not config.exists(pki_base + ['ca']):
- config.set(pki_base + ['ca'])
- config.set_tag(pki_base + ['ca'])
-
- crl_file = config.return_value(x509_base + ['crl-file'])
- crl_path = os.path.join(AUTH_DIR, crl_file)
- crl = None
-
- if os.path.isfile(crl_path):
- if not os.access(crl_path, os.R_OK):
- run(f'sudo chmod 644 {crl_path}')
-
- with open(crl_path, 'r') as f:
- crl_data = f.read()
- crl = load_crl(crl_data, wrap_tags=False)
-
- if crl:
- crl_pem = encode_certificate(crl)
- config.set(pki_base + ['ca', pki_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
- else:
- print(f'Failed to migrate CRL on openvpn interface {interface}')
-
- config.delete(x509_base + ['crl-file'])
-
- if config.exists(x509_base + ['cert-file']):
- if not config.exists(pki_base + ['certificate']):
- config.set(pki_base + ['certificate'])
- config.set_tag(pki_base + ['certificate'])
-
- cert_file = config.return_value(x509_base + ['cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['certificate'], value=pki_name)
- else:
- print(f'Failed to migrate certificate on openvpn interface {interface}')
-
- config.delete(x509_base + ['cert-file'])
-
- if config.exists(x509_base + ['key-file']):
- key_file = config.return_value(x509_base + ['key-file'])
- key_path = os.path.join(AUTH_DIR, key_file)
- key = None
-
- if os.path.isfile(key_path):
- if not os.access(key_path, os.R_OK):
- run(f'sudo chmod 644 {key_path}')
-
- with open(key_path, 'r') as f:
- key_data = f.read()
- key = load_private_key(key_data, passphrase=None, wrap_tags=False)
-
- if key:
- key_pem = encode_private_key(key, passphrase=None)
- config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
- else:
- print(f'Failed to migrate private key on openvpn interface {interface}')
-
- config.delete(x509_base + ['key-file'])
-
- if config.exists(x509_base + ['dh-file']):
- if not config.exists(pki_base + ['dh']):
- config.set(pki_base + ['dh'])
- config.set_tag(pki_base + ['dh'])
-
- dh_file = config.return_value(x509_base + ['dh-file'])
- dh_path = os.path.join(AUTH_DIR, dh_file)
- dh = None
-
- if os.path.isfile(dh_path):
- if not os.access(dh_path, os.R_OK):
- run(f'sudo chmod 644 {dh_path}')
-
- with open(dh_path, 'r') as f:
- dh_data = f.read()
- dh = load_dh_parameters(dh_data, wrap_tags=False)
-
- if dh:
- dh_pem = encode_dh_parameters(dh)
- config.set(pki_base + ['dh', pki_name, 'parameters'], value=wrapped_pem_to_config_value(dh_pem))
- config.set(x509_base + ['dh-params'], value=pki_name)
- else:
- print(f'Failed to migrate DH parameters on openvpn interface {interface}')
-
- config.delete(x509_base + ['dh-file'])
-
-# Wireguard
-base = ['interfaces', 'wireguard']
-
-if config.exists(base):
- for interface in config.list_nodes(base):
- private_key_path = base + [interface, 'private-key']
-
- key_file = 'default'
- if config.exists(private_key_path):
- key_file = config.return_value(private_key_path)
-
- full_key_path = f'/config/auth/wireguard/{key_file}/private.key'
-
- if not os.path.exists(full_key_path):
- print(f'Could not find wireguard private key for migration on interface "{interface}"')
- continue
-
- with open(full_key_path, 'r') as f:
- key_data = f.read().strip()
- config.set(private_key_path, value=key_data)
-
- for peer in config.list_nodes(base + [interface, 'peer']):
- config.rename(base + [interface, 'peer', peer, 'pubkey'], 'public-key')
-
-# Ethernet EAPoL
-base = ['interfaces', 'ethernet']
-
-if config.exists(base):
+ ipsec_base = ['vpn', 'ipsec', 'site-to-site', 'peer']
for interface in config.list_nodes(base):
- if not config.exists(base + [interface, 'eapol']):
- continue
-
- x509_base = base + [interface, 'eapol']
- pki_name = f'eapol_{interface}'
-
- if config.exists(x509_base + ['ca-cert-file']):
- if not config.exists(pki_base + ['ca']):
- config.set(pki_base + ['ca'])
- config.set_tag(pki_base + ['ca'])
-
- cert_file = config.return_value(x509_base + ['ca-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['ca-certificate'], value=pki_name)
- else:
- print(f'Failed to migrate CA certificate on eapol config for interface {interface}')
-
- config.delete(x509_base + ['ca-cert-file'])
-
- if config.exists(x509_base + ['cert-file']):
- if not config.exists(pki_base + ['certificate']):
- config.set(pki_base + ['certificate'])
- config.set_tag(pki_base + ['certificate'])
-
- cert_file = config.return_value(x509_base + ['cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['certificate'], value=pki_name)
- else:
- print(f'Failed to migrate certificate on eapol config for interface {interface}')
-
- config.delete(x509_base + ['cert-file'])
-
- if config.exists(x509_base + ['key-file']):
- key_file = config.return_value(x509_base + ['key-file'])
- key_path = os.path.join(AUTH_DIR, key_file)
- key = None
-
- if os.path.isfile(key_path):
- if not os.access(key_path, os.R_OK):
- run(f'sudo chmod 644 {key_path}')
-
- with open(key_path, 'r') as f:
- key_data = f.read()
- key = load_private_key(key_data, passphrase=None, wrap_tags=False)
-
- if key:
- key_pem = encode_private_key(key, passphrase=None)
- config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
- else:
- print(f'Failed to migrate private key on eapol config for interface {interface}')
-
- config.delete(x509_base + ['key-file'])
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
+ found = False
+ if config.exists(ipsec_base):
+ for peer in config.list_nodes(ipsec_base):
+ if config.exists(ipsec_base + [peer, 'vti', 'bind']):
+ tmp = config.return_value(ipsec_base + [peer, 'vti', 'bind'])
+ if tmp == interface:
+ # Interface was found and we no longer need to search
+ # for it in our IPSec peers
+ found = True
+ break
+ if not found:
+ config.delete(base + [interface])
+
+ try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+ except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ sys.exit(1)
diff --git a/src/migration-scripts/interfaces/24-to-25 b/src/migration-scripts/interfaces/24-to-25
new file mode 100755
index 000000000..93ce9215f
--- /dev/null
+++ b/src/migration-scripts/interfaces/24-to-25
@@ -0,0 +1,369 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 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/>.
+
+# Migrate Wireguard to store keys in CLI
+# Migrate EAPoL to PKI configuration
+
+import os
+import sys
+from vyos.configtree import ConfigTree
+from vyos.pki import load_certificate
+from vyos.pki import load_crl
+from vyos.pki import load_dh_parameters
+from vyos.pki import load_private_key
+from vyos.pki import encode_certificate
+from vyos.pki import encode_dh_parameters
+from vyos.pki import encode_private_key
+from vyos.util import run
+
+def wrapped_pem_to_config_value(pem):
+ out = []
+ for line in pem.strip().split("\n"):
+ if not line or line.startswith("-----") or line[0] == '#':
+ continue
+ out.append(line)
+ return "".join(out)
+
+def read_file_for_pki(config_auth_path):
+ full_path = os.path.join(AUTH_DIR, config_auth_path)
+ output = None
+
+ if os.path.isfile(full_path):
+ if not os.access(full_path, os.R_OK):
+ run(f'sudo chmod 644 {full_path}')
+
+ with open(full_path, 'r') as f:
+ output = f.read()
+
+ return output
+
+if (len(sys.argv) < 1):
+ print("Must specify file name!")
+ sys.exit(1)
+
+file_name = sys.argv[1]
+
+with open(file_name, 'r') as f:
+ config_file = f.read()
+
+config = ConfigTree(config_file)
+
+AUTH_DIR = '/config/auth'
+pki_base = ['pki']
+
+# OpenVPN
+base = ['interfaces', 'openvpn']
+
+if config.exists(base):
+ for interface in config.list_nodes(base):
+ x509_base = base + [interface, 'tls']
+ pki_name = f'openvpn_{interface}'
+
+ if config.exists(base + [interface, 'shared-secret-key-file']):
+ if not config.exists(pki_base + ['openvpn', 'shared-secret']):
+ config.set(pki_base + ['openvpn', 'shared-secret'])
+ config.set_tag(pki_base + ['openvpn', 'shared-secret'])
+
+ key_file = config.return_value(base + [interface, 'shared-secret-key-file'])
+ key = read_file_for_pki(key_file)
+ key_pki_name = f'{pki_name}_shared'
+
+ if key:
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
+ config.set(base + [interface, 'shared-secret-key'], value=key_pki_name)
+ else:
+ print(f'Failed to migrate shared-secret-key on openvpn interface {interface}')
+
+ config.delete(base + [interface, 'shared-secret-key-file'])
+
+ if not config.exists(base + [interface, 'tls']):
+ continue
+
+ if config.exists(base + [interface, 'tls', 'auth-file']):
+ if not config.exists(pki_base + ['openvpn', 'shared-secret']):
+ config.set(pki_base + ['openvpn', 'shared-secret'])
+ config.set_tag(pki_base + ['openvpn', 'shared-secret'])
+
+ key_file = config.return_value(base + [interface, 'tls', 'auth-file'])
+ key = read_file_for_pki(key_file)
+ key_pki_name = f'{pki_name}_auth'
+
+ if key:
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
+ config.set(base + [interface, 'tls', 'auth-key'], value=key_pki_name)
+ else:
+ print(f'Failed to migrate auth-key on openvpn interface {interface}')
+
+ config.delete(base + [interface, 'tls', 'auth-file'])
+
+ if config.exists(base + [interface, 'tls', 'crypt-file']):
+ if not config.exists(pki_base + ['openvpn', 'shared-secret']):
+ config.set(pki_base + ['openvpn', 'shared-secret'])
+ config.set_tag(pki_base + ['openvpn', 'shared-secret'])
+
+ key_file = config.return_value(base + [interface, 'tls', 'crypt-file'])
+ key = read_file_for_pki(key_file)
+ key_pki_name = f'{pki_name}_crypt'
+
+ if key:
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
+ config.set(base + [interface, 'tls', 'crypt-key'], value=key_pki_name)
+ else:
+ print(f'Failed to migrate crypt-key on openvpn interface {interface}')
+
+ config.delete(base + [interface, 'tls', 'crypt-file'])
+
+ if config.exists(x509_base + ['ca-cert-file']):
+ if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ cert_file = config.return_value(x509_base + ['ca-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['ca-certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate CA certificate on openvpn interface {interface}')
+
+ config.delete(x509_base + ['ca-cert-file'])
+
+ if config.exists(x509_base + ['crl-file']):
+ if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ crl_file = config.return_value(x509_base + ['crl-file'])
+ crl_path = os.path.join(AUTH_DIR, crl_file)
+ crl = None
+
+ if os.path.isfile(crl_path):
+ if not os.access(crl_path, os.R_OK):
+ run(f'sudo chmod 644 {crl_path}')
+
+ with open(crl_path, 'r') as f:
+ crl_data = f.read()
+ crl = load_crl(crl_data, wrap_tags=False)
+
+ if crl:
+ crl_pem = encode_certificate(crl)
+ config.set(pki_base + ['ca', pki_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
+ else:
+ print(f'Failed to migrate CRL on openvpn interface {interface}')
+
+ config.delete(x509_base + ['crl-file'])
+
+ if config.exists(x509_base + ['cert-file']):
+ if not config.exists(pki_base + ['certificate']):
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
+
+ cert_file = config.return_value(x509_base + ['cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate certificate on openvpn interface {interface}')
+
+ config.delete(x509_base + ['cert-file'])
+
+ if config.exists(x509_base + ['key-file']):
+ key_file = config.return_value(x509_base + ['key-file'])
+ key_path = os.path.join(AUTH_DIR, key_file)
+ key = None
+
+ if os.path.isfile(key_path):
+ if not os.access(key_path, os.R_OK):
+ run(f'sudo chmod 644 {key_path}')
+
+ with open(key_path, 'r') as f:
+ key_data = f.read()
+ key = load_private_key(key_data, passphrase=None, wrap_tags=False)
+
+ if key:
+ key_pem = encode_private_key(key, passphrase=None)
+ config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+ else:
+ print(f'Failed to migrate private key on openvpn interface {interface}')
+
+ config.delete(x509_base + ['key-file'])
+
+ if config.exists(x509_base + ['dh-file']):
+ if not config.exists(pki_base + ['dh']):
+ config.set(pki_base + ['dh'])
+ config.set_tag(pki_base + ['dh'])
+
+ dh_file = config.return_value(x509_base + ['dh-file'])
+ dh_path = os.path.join(AUTH_DIR, dh_file)
+ dh = None
+
+ if os.path.isfile(dh_path):
+ if not os.access(dh_path, os.R_OK):
+ run(f'sudo chmod 644 {dh_path}')
+
+ with open(dh_path, 'r') as f:
+ dh_data = f.read()
+ dh = load_dh_parameters(dh_data, wrap_tags=False)
+
+ if dh:
+ dh_pem = encode_dh_parameters(dh)
+ config.set(pki_base + ['dh', pki_name, 'parameters'], value=wrapped_pem_to_config_value(dh_pem))
+ config.set(x509_base + ['dh-params'], value=pki_name)
+ else:
+ print(f'Failed to migrate DH parameters on openvpn interface {interface}')
+
+ config.delete(x509_base + ['dh-file'])
+
+# Wireguard
+base = ['interfaces', 'wireguard']
+
+if config.exists(base):
+ for interface in config.list_nodes(base):
+ private_key_path = base + [interface, 'private-key']
+
+ key_file = 'default'
+ if config.exists(private_key_path):
+ key_file = config.return_value(private_key_path)
+
+ full_key_path = f'/config/auth/wireguard/{key_file}/private.key'
+
+ if not os.path.exists(full_key_path):
+ print(f'Could not find wireguard private key for migration on interface "{interface}"')
+ continue
+
+ with open(full_key_path, 'r') as f:
+ key_data = f.read().strip()
+ config.set(private_key_path, value=key_data)
+
+ for peer in config.list_nodes(base + [interface, 'peer']):
+ config.rename(base + [interface, 'peer', peer, 'pubkey'], 'public-key')
+
+# Ethernet EAPoL
+base = ['interfaces', 'ethernet']
+
+if config.exists(base):
+ for interface in config.list_nodes(base):
+ if not config.exists(base + [interface, 'eapol']):
+ continue
+
+ x509_base = base + [interface, 'eapol']
+ pki_name = f'eapol_{interface}'
+
+ if config.exists(x509_base + ['ca-cert-file']):
+ if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ cert_file = config.return_value(x509_base + ['ca-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['ca-certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate CA certificate on eapol config for interface {interface}')
+
+ config.delete(x509_base + ['ca-cert-file'])
+
+ if config.exists(x509_base + ['cert-file']):
+ if not config.exists(pki_base + ['certificate']):
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
+
+ cert_file = config.return_value(x509_base + ['cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate certificate on eapol config for interface {interface}')
+
+ config.delete(x509_base + ['cert-file'])
+
+ if config.exists(x509_base + ['key-file']):
+ key_file = config.return_value(x509_base + ['key-file'])
+ key_path = os.path.join(AUTH_DIR, key_file)
+ key = None
+
+ if os.path.isfile(key_path):
+ if not os.access(key_path, os.R_OK):
+ run(f'sudo chmod 644 {key_path}')
+
+ with open(key_path, 'r') as f:
+ key_data = f.read()
+ key = load_private_key(key_data, passphrase=None, wrap_tags=False)
+
+ if key:
+ key_pem = encode_private_key(key, passphrase=None)
+ config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+ else:
+ print(f'Failed to migrate private key on eapol config for interface {interface}')
+
+ config.delete(x509_base + ['key-file'])
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ sys.exit(1)
diff --git a/src/op_mode/show_ram.py b/src/op_mode/show_ram.py
new file mode 100755
index 000000000..5818ec132
--- /dev/null
+++ b/src/op_mode/show_ram.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 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/>.
+#
+
+def get_system_memory():
+ from re import search as re_search
+
+ def find_value(keyword, mem_data):
+ regex = keyword + ':\s+(\d+)'
+ res = re_search(regex, mem_data).group(1)
+ return int(res)
+
+ with open("/proc/meminfo", "r") as f:
+ mem_data = f.read()
+
+ total = find_value('MemTotal', mem_data)
+ available = find_value('MemAvailable', mem_data)
+ buffers = find_value('Buffers', mem_data)
+ cached = find_value('Cached', mem_data)
+
+ used = total - available
+
+ res = {
+ "total": total,
+ "free": available,
+ "used": used,
+ "buffers": buffers,
+ "cached": cached
+ }
+
+ return res
+
+def get_system_memory_human():
+ from vyos.util import bytes_to_human
+
+ mem = get_system_memory()
+
+ for key in mem:
+ # The Linux kernel exposes memory values in kilobytes,
+ # so we need to normalize them
+ mem[key] = bytes_to_human(mem[key], initial_exponent=10)
+
+ return mem
+
+if __name__ == '__main__':
+ mem = get_system_memory_human()
+
+ print("Total: {}".format(mem["total"]))
+ print("Free: {}".format(mem["free"]))
+ print("Used: {}".format(mem["used"]))
+
diff --git a/src/op_mode/show_ram.sh b/src/op_mode/show_ram.sh
deleted file mode 100755
index b013e16f8..000000000
--- a/src/op_mode/show_ram.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/bash
-#
-# Module: vyos-show-ram.sh
-# Displays memory usage information in minimalistic format
-#
-# 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 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/>.
-
-MB_DIVISOR=1024
-
-TOTAL=$(cat /proc/meminfo | grep -E "^MemTotal:" | awk -F ' ' '{print $2}')
-FREE=$(cat /proc/meminfo | grep -E "^MemFree:" | awk -F ' ' '{print $2}')
-BUFFERS=$(cat /proc/meminfo | grep -E "^Buffers:" | awk -F ' ' '{print $2}')
-CACHED=$(cat /proc/meminfo | grep -E "^Cached:" | awk -F ' ' '{print $2}')
-
-DISPLAY_FREE=$(( ($FREE + $BUFFERS + $CACHED) / $MB_DIVISOR ))
-DISPLAY_TOTAL=$(( $TOTAL / $MB_DIVISOR ))
-DISPLAY_USED=$(( $DISPLAY_TOTAL - $DISPLAY_FREE ))
-
-echo "Total: $DISPLAY_TOTAL"
-echo "Free: $DISPLAY_FREE"
-echo "Used: $DISPLAY_USED"
diff --git a/src/op_mode/show_uptime.py b/src/op_mode/show_uptime.py
new file mode 100755
index 000000000..c3dea52e6
--- /dev/null
+++ b/src/op_mode/show_uptime.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 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 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/>.
+
+def get_uptime_seconds():
+ from re import search
+ from vyos.util import read_file
+
+ data = read_file("/proc/uptime")
+ seconds = search("([0-9\.]+)\s", data).group(1)
+
+ return int(float(seconds))
+
+def get_load_averages():
+ from re import search
+ from vyos.util import cmd
+
+ data = cmd("uptime")
+ matches = search(r"load average:\s*(?P<one>[0-9\.]+)\s*,\s*(?P<five>[0-9\.]+)\s*,\s*(?P<fifteen>[0-9\.]+)\s*", data)
+
+ res = {}
+ res[1] = float(matches["one"])
+ res[5] = float(matches["five"])
+ res[15] = float(matches["fifteen"])
+
+ return res
+
+if __name__ == '__main__':
+ from vyos.util import seconds_to_human
+
+ print("Uptime: {}\n".format(seconds_to_human(get_uptime_seconds())))
+
+ avgs = get_load_averages()
+
+ print("Load averages:")
+ print("1 minute: {:.02f}%".format(avgs[1]*100))
+ print("5 minutes: {:.02f}%".format(avgs[5]*100))
+ print("15 minutes: {:.02f}%".format(avgs[15]*100))
diff --git a/src/services/vyos-hostsd b/src/services/vyos-hostsd
index 4c4bb036e..f4b1d0fc2 100755
--- a/src/services/vyos-hostsd
+++ b/src/services/vyos-hostsd
@@ -317,7 +317,7 @@ hosts_add_schema = op_type_schema.extend({
'data': {
str: {
str: {
- 'address': str,
+ 'address': [str],
'aliases': [str]
}
}