summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarcus Hoff <marcus.hoff@ring2.dk>2020-09-26 13:19:37 +0200
committerMarcus Hoff <marcus.hoff@ring2.dk>2020-09-26 13:19:37 +0200
commit1141bee72677b25d18436975625d2d298be503ff (patch)
tree4b6dc8fe1a8ced931e1ba08c58a348abfcd85a6b /src
parent45b30adfaaec7065f768d04085138a75a76ed376 (diff)
parent374724be64728101c262fcac1579beece63ee651 (diff)
downloadvyos-1x-1141bee72677b25d18436975625d2d298be503ff.tar.gz
vyos-1x-1141bee72677b25d18436975625d2d298be503ff.zip
Merge remote-tracking branch 'upstream/current' into current
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/dns_forwarding.py176
-rwxr-xr-xsrc/conf_mode/interfaces-bonding.py30
-rwxr-xr-xsrc/conf_mode/interfaces-bridge.py35
-rwxr-xr-xsrc/conf_mode/interfaces-ethernet.py11
-rwxr-xr-xsrc/conf_mode/interfaces-geneve.py13
-rwxr-xr-xsrc/conf_mode/interfaces-l2tpv3.py12
-rwxr-xr-xsrc/conf_mode/interfaces-macsec.py32
-rwxr-xr-xsrc/conf_mode/interfaces-openvpn.py11
-rwxr-xr-xsrc/conf_mode/interfaces-pppoe.py2
-rwxr-xr-xsrc/conf_mode/interfaces-pseudo-ethernet.py36
-rwxr-xr-xsrc/conf_mode/interfaces-tunnel.py9
-rwxr-xr-xsrc/conf_mode/interfaces-vxlan.py16
-rwxr-xr-xsrc/conf_mode/interfaces-wireguard.py2
-rwxr-xr-xsrc/conf_mode/interfaces-wireless.py11
-rwxr-xr-xsrc/conf_mode/snmp.py2
-rwxr-xr-xsrc/migration-scripts/interfaces/12-to-1371
-rwxr-xr-xsrc/migration-scripts/system/10-to-1161
-rwxr-xr-xsrc/migration-scripts/system/11-to-1278
-rwxr-xr-xsrc/migration-scripts/system/12-to-1385
-rwxr-xr-xsrc/migration-scripts/system/13-to-1456
-rwxr-xr-xsrc/migration-scripts/system/14-to-1521
-rwxr-xr-xsrc/migration-scripts/system/15-to-1634
-rwxr-xr-xsrc/migration-scripts/system/16-to-1743
-rwxr-xr-xsrc/migration-scripts/system/17-to-18123
-rwxr-xr-xsrc/migration-scripts/system/18-to-19105
-rwxr-xr-xsrc/migration-scripts/system/9-to-1036
-rwxr-xr-xsrc/services/vyos-hostsd21
-rwxr-xr-xsrc/utils/vyos-hostsd-client6
28 files changed, 598 insertions, 540 deletions
diff --git a/src/conf_mode/dns_forwarding.py b/src/conf_mode/dns_forwarding.py
index 53bc37882..5101c1e79 100755
--- a/src/conf_mode/dns_forwarding.py
+++ b/src/conf_mode/dns_forwarding.py
@@ -17,14 +17,17 @@
import os
from sys import exit
-from copy import deepcopy
from vyos.config import Config
+from vyos.configdict import dict_merge
from vyos.hostsd_client import Client as hostsd_client
-from vyos import ConfigError
-from vyos.util import call, chown
+from vyos.util import call
+from vyos.util import chown
+from vyos.util import vyos_dict_search
from vyos.template import render
+from vyos.xml import defaults
+from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -35,136 +38,84 @@ pdns_rec_hostsd_lua_conf_file = f'{pdns_rec_run_dir}/recursor.vyos-hostsd.conf.l
pdns_rec_hostsd_zones_file = f'{pdns_rec_run_dir}/recursor.forward-zones.conf'
pdns_rec_config_file = f'{pdns_rec_run_dir}/recursor.conf'
-default_config_data = {
- 'allow_from': [],
- 'cache_size': 10000,
- 'export_hosts_file': 'yes',
- 'listen_address': [],
- 'name_servers': [],
- 'negative_ttl': 3600,
- 'system': False,
- 'domains': {},
- 'dnssec': 'process-no-validate',
- 'dhcp_interfaces': []
-}
-
hostsd_tag = 'static'
-def get_config(conf):
- dns = deepcopy(default_config_data)
+def get_config(config=None):
+ if config:
+ conf = config
+ else:
+ conf = Config()
base = ['service', 'dns', 'forwarding']
-
if not conf.exists(base):
return None
- conf.set_level(base)
-
- if conf.exists(['allow-from']):
- dns['allow_from'] = conf.return_values(['allow-from'])
-
- if conf.exists(['cache-size']):
- cache_size = conf.return_value(['cache-size'])
- dns['cache_size'] = cache_size
-
- if conf.exists('negative-ttl'):
- negative_ttl = conf.return_value(['negative-ttl'])
- dns['negative_ttl'] = negative_ttl
-
- if conf.exists(['domain']):
- for domain in conf.list_nodes(['domain']):
- conf.set_level(base + ['domain', domain])
- entry = {
- 'nslist': bracketize_ipv6_addrs(conf.return_values(['server'])),
- 'addNTA': conf.exists(['addnta']),
- 'recursion-desired': conf.exists(['recursion-desired'])
- }
- dns['domains'][domain] = entry
-
- conf.set_level(base)
+ dns = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
+ # We have gathered the dict representation of the CLI, but there are default
+ # options which we need to update into the dictionary retrived.
+ default_values = defaults(base)
+ dns = dict_merge(default_values, dns)
- if conf.exists(['ignore-hosts-file']):
- dns['export_hosts_file'] = "no"
+ # some additions to the default dictionary
+ if 'system' in dns:
+ base_nameservers = ['system', 'name-server']
+ if conf.exists(base_nameservers):
+ dns.update({'system_name_server': conf.return_values(base_nameservers)})
- if conf.exists(['name-server']):
- dns['name_servers'] = bracketize_ipv6_addrs(
- conf.return_values(['name-server']))
-
- if conf.exists(['system']):
- dns['system'] = True
-
- if conf.exists(['listen-address']):
- dns['listen_address'] = conf.return_values(['listen-address'])
-
- if conf.exists(['dnssec']):
- dns['dnssec'] = conf.return_value(['dnssec'])
-
- if conf.exists(['dhcp']):
- dns['dhcp_interfaces'] = conf.return_values(['dhcp'])
+ base_nameservers_dhcp = ['system', 'name-servers-dhcp']
+ if conf.exists(base_nameservers_dhcp):
+ dns.update({'system_name_server_dhcp': conf.return_values(base_nameservers_dhcp)})
return dns
-def bracketize_ipv6_addrs(addrs):
- """Wraps each IPv6 addr in addrs in [], leaving IPv4 addrs untouched."""
- return ['[{0}]'.format(a) if a.count(':') > 1 else a for a in addrs]
-
-def verify(conf, dns):
+def verify(dns):
# bail out early - looks like removal from running config
- if dns is None:
+ if not dns:
return None
- if not dns['listen_address']:
- raise ConfigError(
- "Error: DNS forwarding requires a listen-address")
-
- if not dns['allow_from']:
- raise ConfigError(
- "Error: DNS forwarding requires an allow-from network")
-
- if dns['domains']:
- for domain in dns['domains']:
- if not dns['domains'][domain]['nslist']:
- raise ConfigError((
- f'Error: No server configured for domain {domain}'))
-
- no_system_nameservers = False
- conf.set_level([])
- if dns['system'] and not (
- conf.exists(['system', 'name-server']) or
- conf.exists(['system', 'name-servers-dhcp']) ):
- no_system_nameservers = True
- print(("DNS forwarding warning: No 'system name-server' or "
- "'system name-servers-dhcp' set\n"))
-
- if (no_system_nameservers or not dns['system']) and not (
- dns['name_servers'] or dns['dhcp_interfaces']):
- print(("DNS forwarding warning: No 'dhcp', 'name-server' or 'system' "
- "nameservers set. Forwarding will operate as a recursor.\n"))
+ if 'listen_address' not in dns:
+ raise ConfigError('DNS forwarding requires a listen-address')
+
+ if 'allow_from' not in dns:
+ raise ConfigError('DNS forwarding requires an allow-from network')
+
+ # we can not use vyos_dict_search() when testing for domain servers
+ # as a domain will contains dot's which is out dictionary delimiter.
+ if 'domain' in dns:
+ for domain in dns['domain']:
+ if 'server' not in dns['domain'][domain]:
+ raise ConfigError(f'No server configured for domain {domain}!')
+
+ if 'system' in dns:
+ if not ('system_name_server' in dns or 'system_name_server_dhcp' in dns):
+ print("Warning: No 'system name-server' or 'system " \
+ "name-servers-dhcp' configured")
return None
def generate(dns):
# bail out early - looks like removal from running config
- if dns is None:
+ if not dns:
return None
render(pdns_rec_config_file, 'dns-forwarding/recursor.conf.tmpl',
- dns, user=pdns_rec_user, group=pdns_rec_group)
+ dns, trim_blocks=True, user=pdns_rec_user, group=pdns_rec_group)
render(pdns_rec_lua_conf_file, 'dns-forwarding/recursor.conf.lua.tmpl',
- dns, user=pdns_rec_user, group=pdns_rec_group)
+ dns, trim_blocks=True, user=pdns_rec_user, group=pdns_rec_group)
# if vyos-hostsd didn't create its files yet, create them (empty)
- for f in [pdns_rec_hostsd_lua_conf_file, pdns_rec_hostsd_zones_file]:
- with open(f, 'a'):
+ for file in [pdns_rec_hostsd_lua_conf_file, pdns_rec_hostsd_zones_file]:
+ with open(file, 'a'):
pass
- chown(f, user=pdns_rec_user, group=pdns_rec_group)
+ chown(file, user=pdns_rec_user, group=pdns_rec_group)
return None
def apply(dns):
- if dns is None:
+ if not dns:
# DNS forwarding is removed in the commit
- call("systemctl stop pdns-recursor.service")
+ call('systemctl stop pdns-recursor.service')
+
if os.path.isfile(pdns_rec_config_file):
os.unlink(pdns_rec_config_file)
else:
@@ -174,8 +125,8 @@ def apply(dns):
# add static nameservers to hostsd so they can be joined with other
# sources
hc.delete_name_servers([hostsd_tag])
- if dns['name_servers']:
- hc.add_name_servers({hostsd_tag: dns['name_servers']})
+ if 'name_server' in dns:
+ hc.add_name_servers({hostsd_tag: dns['name_server']})
# delete all nameserver tags
hc.delete_name_server_tags_recursor(hc.get_name_server_tags_recursor())
@@ -184,32 +135,33 @@ def apply(dns):
# our own tag (static)
hc.add_name_server_tags_recursor([hostsd_tag])
- if dns['system']:
+ if 'system' in dns:
hc.add_name_server_tags_recursor(['system'])
else:
hc.delete_name_server_tags_recursor(['system'])
# add dhcp nameserver tags for configured interfaces
- for intf in dns['dhcp_interfaces']:
- hc.add_name_server_tags_recursor(['dhcp-' + intf, 'dhcpv6-' + intf ])
+ if 'system_name_server_dhcp' in dns:
+ for interface in dns['system_name_server_dhcp']:
+ hc.add_name_server_tags_recursor(['dhcp-' + interface,
+ 'dhcpv6-' + interface ])
# hostsd will generate the forward-zones file
# the list and keys() are required as get returns a dict, not list
hc.delete_forward_zones(list(hc.get_forward_zones().keys()))
- if dns['domains']:
- hc.add_forward_zones(dns['domains'])
+ if 'domain' in dns:
+ hc.add_forward_zones(dns['domain'])
# call hostsd to generate forward-zones and its lua-config-file
hc.apply()
### finally (re)start pdns-recursor
- call("systemctl restart pdns-recursor.service")
+ call('systemctl restart pdns-recursor.service')
if __name__ == '__main__':
try:
- conf = Config()
- c = get_config(conf)
- verify(conf, c)
+ c = get_config()
+ verify(c)
generate(c)
apply(c)
except ConfigError as e:
diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py
index a9679b47c..9763620ac 100755
--- a/src/conf_mode/interfaces-bonding.py
+++ b/src/conf_mode/interfaces-bonding.py
@@ -22,15 +22,18 @@ from netifaces import interfaces
from vyos.config import Config
from vyos.configdict import get_interface_dict
from vyos.configdict import leaf_node_changed
+from vyos.configdict import is_member
+from vyos.configdict import is_source_interface
from vyos.configverify import verify_address
from vyos.configverify import verify_bridge_delete
from vyos.configverify import verify_dhcpv6
from vyos.configverify import verify_source_interface
+from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_vlan_config
from vyos.configverify import verify_vrf
from vyos.ifconfig import BondIf
from vyos.ifconfig import Section
-from vyos.validate import is_member
+from vyos.util import vyos_dict_search
from vyos.validate import has_address_configured
from vyos import ConfigError
from vyos import airbag
@@ -98,18 +101,21 @@ def get_config(config=None):
# also present the interfaces to be removed from the bond as dictionary
bond['member'].update({'interface_remove': tmp})
- if 'member' in bond and 'interface' in bond['member']:
+ if vyos_dict_search('member.interface', bond):
for interface, interface_config in bond['member']['interface'].items():
- # Check if we are a member of another bond device
+ # Check if member interface is already member of another bridge
tmp = is_member(conf, interface, 'bridge')
- if tmp:
- interface_config.update({'is_bridge_member' : tmp})
+ if tmp: interface_config.update({'is_bridge_member' : tmp})
- # Check if we are a member of a bond device
+ # Check if member interface is already member of a bond
tmp = is_member(conf, interface, 'bonding')
if tmp and tmp != bond['ifname']:
interface_config.update({'is_bond_member' : tmp})
+ # Check if member interface is used as source-interface on another interface
+ tmp = is_source_interface(conf, interface)
+ if tmp: interface_config.update({'is_source_interface' : tmp})
+
# bond members must not have an assigned address
tmp = has_address_configured(conf, interface)
if tmp: interface_config.update({'has_address' : ''})
@@ -136,6 +142,7 @@ def verify(bond):
raise ConfigError('Option primary - mode dependency failed, not'
'supported in mode {mode}!'.format(**bond))
+ verify_mtu_ipv6(bond)
verify_address(bond)
verify_dhcpv6(bond)
verify_vrf(bond)
@@ -144,10 +151,9 @@ def verify(bond):
verify_vlan_config(bond)
bond_name = bond['ifname']
- if 'member' in bond:
- member = bond.get('member')
- for interface, interface_config in member.get('interface', {}).items():
- error_msg = f'Can not add interface "{interface}" to bond "{bond_name}", '
+ if vyos_dict_search('member.interface', bond):
+ for interface, interface_config in bond['member']['interface'].items():
+ error_msg = f'Can not add interface "{interface}" to bond, '
if interface == 'lo':
raise ConfigError('Loopback interface "lo" can not be added to a bond')
@@ -163,6 +169,10 @@ def verify(bond):
tmp = interface_config['is_bond_member']
raise ConfigError(error_msg + f'it is already a member of bond "{tmp}"!')
+ if 'is_source_interface' in interface_config:
+ tmp = interface_config['is_source_interface']
+ raise ConfigError(error_msg + f'it is the source-interface of "{tmp}"!')
+
if 'has_address' in interface_config:
raise ConfigError(error_msg + 'it has an address assigned!')
diff --git a/src/conf_mode/interfaces-bridge.py b/src/conf_mode/interfaces-bridge.py
index 47c8c05f9..485decb17 100755
--- a/src/conf_mode/interfaces-bridge.py
+++ b/src/conf_mode/interfaces-bridge.py
@@ -22,13 +22,16 @@ from netifaces import interfaces
from vyos.config import Config
from vyos.configdict import get_interface_dict
from vyos.configdict import node_changed
+from vyos.configdict import is_member
+from vyos.configdict import is_source_interface
from vyos.configverify import verify_dhcpv6
from vyos.configverify import verify_vrf
from vyos.ifconfig import BridgeIf
-from vyos.validate import is_member, has_address_configured
+from vyos.validate import has_address_configured
from vyos.xml import defaults
from vyos.util import cmd
+from vyos.util import vyos_dict_search
from vyos import ConfigError
from vyos import airbag
@@ -54,8 +57,8 @@ def get_config(config=None):
else:
bridge.update({'member': {'interface_remove': tmp }})
- if 'member' in bridge and 'interface' in bridge['member']:
- # XXX TT2665 we need a copy of the dict keys for iteration, else we will get:
+ if vyos_dict_search('member.interface', bridge):
+ # XXX: T2665: we need a copy of the dict keys for iteration, else we will get:
# RuntimeError: dictionary changed size during iteration
for interface in list(bridge['member']['interface']):
for key in ['cost', 'priority']:
@@ -69,20 +72,22 @@ def get_config(config=None):
for interface, interface_config in bridge['member']['interface'].items():
interface_config.update(default_member_values)
- # Check if we are a member of another bridge device
+ # Check if member interface is already member of another bridge
tmp = is_member(conf, interface, 'bridge')
if tmp and tmp != bridge['ifname']:
interface_config.update({'is_bridge_member' : tmp})
- # Check if we are a member of a bond device
+ # Check if member interface is already member of a bond
tmp = is_member(conf, interface, 'bonding')
- if tmp:
- interface_config.update({'is_bond_member' : tmp})
+ if tmp: interface_config.update({'is_bond_member' : tmp})
+
+ # Check if member interface is used as source-interface on another interface
+ tmp = is_source_interface(conf, interface)
+ if tmp: interface_config.update({'is_source_interface' : tmp})
# Bridge members must not have an assigned address
tmp = has_address_configured(conf, interface)
- if tmp:
- interface_config.update({'has_address' : ''})
+ if tmp: interface_config.update({'has_address' : ''})
return bridge
@@ -93,11 +98,9 @@ def verify(bridge):
verify_dhcpv6(bridge)
verify_vrf(bridge)
- if 'member' in bridge:
- member = bridge.get('member')
- bridge_name = bridge['ifname']
- for interface, interface_config in member.get('interface', {}).items():
- error_msg = f'Can not add interface "{interface}" to bridge "{bridge_name}", '
+ if vyos_dict_search('member.interface', bridge):
+ for interface, interface_config in bridge['member']['interface'].items():
+ error_msg = f'Can not add interface "{interface}" to bridge, '
if interface == 'lo':
raise ConfigError('Loopback interface "lo" can not be added to a bridge')
@@ -113,6 +116,10 @@ def verify(bridge):
tmp = interface_config['is_bond_member']
raise ConfigError(error_msg + f'it is already a member of bond "{tmp}"!')
+ if 'is_source_interface' in interface_config:
+ tmp = interface_config['is_source_interface']
+ raise ConfigError(error_msg + f'it is the source-interface of "{tmp}"!')
+
if 'has_address' in interface_config:
raise ConfigError(error_msg + 'it has an address assigned!')
diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py
index a8df64cce..1f622c003 100755
--- a/src/conf_mode/interfaces-ethernet.py
+++ b/src/conf_mode/interfaces-ethernet.py
@@ -20,11 +20,13 @@ from sys import exit
from vyos.config import Config
from vyos.configdict import get_interface_dict
-from vyos.configverify import verify_interface_exists
-from vyos.configverify import verify_dhcpv6
from vyos.configverify import verify_address
-from vyos.configverify import verify_vrf
+from vyos.configverify import verify_dhcpv6
+from vyos.configverify import verify_interface_exists
+from vyos.configverify import verify_mtu
+from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_vlan_config
+from vyos.configverify import verify_vrf
from vyos.ifconfig import EthernetIf
from vyos import ConfigError
from vyos import airbag
@@ -41,6 +43,7 @@ def get_config(config=None):
conf = Config()
base = ['interfaces', 'ethernet']
ethernet = get_interface_dict(conf, base)
+
return ethernet
def verify(ethernet):
@@ -57,6 +60,8 @@ def verify(ethernet):
if ethernet.get('speed', None) != 'auto':
raise ConfigError('If duplex is hardcoded, speed must be hardcoded, too')
+ verify_mtu(ethernet)
+ verify_mtu_ipv6(ethernet)
verify_dhcpv6(ethernet)
verify_address(ethernet)
verify_vrf(ethernet)
diff --git a/src/conf_mode/interfaces-geneve.py b/src/conf_mode/interfaces-geneve.py
index cc2cf025a..979a5612e 100755
--- a/src/conf_mode/interfaces-geneve.py
+++ b/src/conf_mode/interfaces-geneve.py
@@ -17,12 +17,12 @@
import os
from sys import exit
-from copy import deepcopy
from netifaces import interfaces
from vyos.config import Config
from vyos.configdict import get_interface_dict
from vyos.configverify import verify_address
+from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_bridge_delete
from vyos.ifconfig import GeneveIf
from vyos import ConfigError
@@ -48,6 +48,7 @@ def verify(geneve):
verify_bridge_delete(geneve)
return None
+ verify_mtu_ipv6(geneve)
verify_address(geneve)
if 'remote' not in geneve:
@@ -62,7 +63,6 @@ def verify(geneve):
def generate(geneve):
return None
-
def apply(geneve):
# Check if GENEVE interface already exists
if geneve['ifname'] in interfaces():
@@ -72,10 +72,11 @@ def apply(geneve):
g.remove()
if 'deleted' not in geneve:
- # GENEVE interface needs to be created on-block
- # instead of passing a ton of arguments, I just use a dict
- # that is managed by vyos.ifconfig
- conf = deepcopy(GeneveIf.get_config())
+ # This is a special type of interface which needs additional parameters
+ # when created using iproute2. Instead of passing a ton of arguments,
+ # use a dictionary provided by the interface class which holds all the
+ # options necessary.
+ conf = GeneveIf.get_config()
# Assign GENEVE instance configuration parameters to config dict
conf['vni'] = geneve['vni']
diff --git a/src/conf_mode/interfaces-l2tpv3.py b/src/conf_mode/interfaces-l2tpv3.py
index 144cee5fe..1118143e4 100755
--- a/src/conf_mode/interfaces-l2tpv3.py
+++ b/src/conf_mode/interfaces-l2tpv3.py
@@ -17,7 +17,6 @@
import os
from sys import exit
-from copy import deepcopy
from netifaces import interfaces
from vyos.config import Config
@@ -25,6 +24,7 @@ from vyos.configdict import get_interface_dict
from vyos.configdict import leaf_node_changed
from vyos.configverify import verify_address
from vyos.configverify import verify_bridge_delete
+from vyos.configverify import verify_mtu_ipv6
from vyos.ifconfig import L2TPv3If
from vyos.util import check_kmod
from vyos.validate import is_addr_assigned
@@ -81,6 +81,7 @@ def verify(l2tpv3):
raise ConfigError('L2TPv3 local-ip address '
'"{local_ip}" is not configured!'.format(**l2tpv3))
+ verify_mtu_ipv6(l2tpv3)
verify_address(l2tpv3)
return None
@@ -88,10 +89,11 @@ def generate(l2tpv3):
return None
def apply(l2tpv3):
- # L2TPv3 interface needs to be created/deleted on-block, instead of
- # passing a ton of arguments, I just use a dict that is managed by
- # vyos.ifconfig
- conf = deepcopy(L2TPv3If.get_config())
+ # This is a special type of interface which needs additional parameters
+ # when created using iproute2. Instead of passing a ton of arguments,
+ # use a dictionary provided by the interface class which holds all the
+ # options necessary.
+ conf = L2TPv3If.get_config()
# Check if L2TPv3 interface already exists
if l2tpv3['ifname'] in interfaces():
diff --git a/src/conf_mode/interfaces-macsec.py b/src/conf_mode/interfaces-macsec.py
index 2866ccc0a..0a20a121b 100755
--- a/src/conf_mode/interfaces-macsec.py
+++ b/src/conf_mode/interfaces-macsec.py
@@ -16,17 +16,18 @@
import os
-from copy import deepcopy
from sys import exit
from vyos.config import Config
from vyos.configdict import get_interface_dict
from vyos.ifconfig import MACsecIf
+from vyos.ifconfig import Interface
from vyos.template import render
from vyos.util import call
from vyos.configverify import verify_vrf
from vyos.configverify import verify_address
from vyos.configverify import verify_bridge_delete
+from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_source_interface
from vyos import ConfigError
from vyos import airbag
@@ -47,6 +48,14 @@ def get_config(config=None):
base = ['interfaces', 'macsec']
macsec = get_interface_dict(conf, base)
+ # MACsec is "special" the default MTU is 1460 - update accordingly
+ # as the config_level is already st in get_interface_dict() - we can use []
+ tmp = conf.get_config_dict([], key_mangling=('-', '_'), get_first_key=True)
+ if 'mtu' not in tmp:
+ # base MTU for MACsec is 1468 bytes, but we leave room for 802.1ad and
+ # 802.1q VLAN tags, thus the limit is 1460 bytes.
+ macsec['mtu'] = '1460'
+
# Check if interface has been removed
if 'deleted' in macsec:
source_interface = conf.return_effective_value(
@@ -63,6 +72,7 @@ def verify(macsec):
verify_source_interface(macsec)
verify_vrf(macsec)
+ verify_mtu_ipv6(macsec)
verify_address(macsec)
if not (('security' in macsec) and
@@ -80,6 +90,15 @@ def verify(macsec):
raise ConfigError('Missing mandatory MACsec security '
'keys as encryption is enabled!')
+ if 'source_interface' in macsec:
+ # MACsec adds a 40 byte overhead (32 byte MACsec + 8 bytes VLAN 802.1ad
+ # and 802.1q) - we need to check the underlaying MTU if our configured
+ # MTU is at least 40 bytes less then the MTU of our physical interface.
+ lower_mtu = Interface(macsec['source_interface']).get_mtu()
+ if lower_mtu < (int(macsec['mtu']) + 40):
+ raise ConfigError('MACsec overhead does not fit into underlaying device MTU,\n' \
+ f'{underlay_mtu} bytes is too small!')
+
return None
@@ -102,12 +121,11 @@ def apply(macsec):
os.unlink(wpa_suppl_conf.format(**macsec))
else:
- # MACsec interfaces require a configuration when they are added using
- # iproute2. This static method will provide the configuration
- # dictionary used by this class.
-
- # XXX: subject of removal after completing T2653
- conf = deepcopy(MACsecIf.get_config())
+ # This is a special type of interface which needs additional parameters
+ # when created using iproute2. Instead of passing a ton of arguments,
+ # use a dictionary provided by the interface class which holds all the
+ # options necessary.
+ conf = MACsecIf.get_config()
conf['source_interface'] = macsec['source_interface']
conf['security_cipher'] = macsec['security']['cipher']
diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py
index 958b305dd..518dbdc0e 100755
--- a/src/conf_mode/interfaces-openvpn.py
+++ b/src/conf_mode/interfaces-openvpn.py
@@ -26,10 +26,11 @@ from shutil import rmtree
from vyos.config import Config
from vyos.configdict import list_diff
+from vyos.configdict import is_member
from vyos.ifconfig import VTunIf
from vyos.template import render
from vyos.util import call, chown, chmod_600, chmod_755
-from vyos.validate import is_addr_assigned, is_member, is_ipv4
+from vyos.validate import is_addr_assigned, is_ipv4
from vyos import ConfigError
from vyos import airbag
@@ -256,7 +257,10 @@ def get_config(config=None):
if conf.exists('encryption ncp-ciphers'):
_ncp_ciphers = []
for enc in conf.return_values('encryption ncp-ciphers'):
- if enc == 'des':
+ if enc == 'none':
+ _ncp_ciphers.append('none')
+ _ncp_ciphers.append('NONE')
+ elif enc == 'des':
_ncp_ciphers.append('des-cbc')
_ncp_ciphers.append('DES-CBC')
elif enc == '3des':
@@ -943,6 +947,9 @@ def verify(openvpn):
else:
print('Diffie-Hellman prime file is unspecified, assuming ECDH')
+ if openvpn['encryption'] == 'none':
+ print('Warning: "encryption none" was specified. NO encryption will be performed and tunnelled data WILL be transmitted in clear text over the network!')
+
#
# Auth user/pass
#
diff --git a/src/conf_mode/interfaces-pppoe.py b/src/conf_mode/interfaces-pppoe.py
index 1b4b9e4ee..ee3b142c8 100755
--- a/src/conf_mode/interfaces-pppoe.py
+++ b/src/conf_mode/interfaces-pppoe.py
@@ -24,6 +24,7 @@ from vyos.config import Config
from vyos.configdict import get_interface_dict
from vyos.configverify import verify_source_interface
from vyos.configverify import verify_vrf
+from vyos.configverify import verify_mtu_ipv6
from vyos.template import render
from vyos.util import call
from vyos import ConfigError
@@ -57,6 +58,7 @@ def verify(pppoe):
verify_source_interface(pppoe)
verify_vrf(pppoe)
+ verify_mtu_ipv6(pppoe)
if {'connect_on_demand', 'vrf'} <= set(pppoe):
raise ConfigError('On-demand dialing and VRF can not be used at the same time')
diff --git a/src/conf_mode/interfaces-pseudo-ethernet.py b/src/conf_mode/interfaces-pseudo-ethernet.py
index 59edca1cc..ddbef56ac 100755
--- a/src/conf_mode/interfaces-pseudo-ethernet.py
+++ b/src/conf_mode/interfaces-pseudo-ethernet.py
@@ -14,9 +14,6 @@
# 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.config import Config
@@ -28,7 +25,6 @@ from vyos.configverify import verify_bridge_delete
from vyos.configverify import verify_source_interface
from vyos.configverify import verify_vlan_config
from vyos.ifconfig import MACVLANIf
-from vyos.validate import is_member
from vyos import ConfigError
from vyos import airbag
@@ -47,19 +43,7 @@ def get_config(config=None):
peth = get_interface_dict(conf, base)
mode = leaf_node_changed(conf, ['mode'])
- if mode:
- peth.update({'mode_old' : mode})
-
- # Check if source-interface is member of a bridge device
- if 'source_interface' in peth:
- bridge = is_member(conf, peth['source_interface'], 'bridge')
- if bridge:
- peth.update({'source_interface_is_bridge_member' : bridge})
-
- # Check if we are a member of a bond device
- bond = is_member(conf, peth['source_interface'], 'bonding')
- if bond:
- peth.update({'source_interface_is_bond_member' : bond})
+ if mode: peth.update({'mode_old' : mode})
return peth
@@ -72,16 +56,6 @@ def verify(peth):
verify_vrf(peth)
verify_address(peth)
- if 'source_interface_is_bridge_member' in peth:
- raise ConfigError(
- 'Source interface "{source_interface}" can not be used as it is already a '
- 'member of bridge "{source_interface_is_bridge_member}"!'.format(**peth))
-
- if 'source_interface_is_bond_member' in peth:
- raise ConfigError(
- 'Source interface "{source_interface}" can not be used as it is already a '
- 'member of bond "{source_interface_is_bond_member}"!'.format(**peth))
-
# use common function to verify VLAN configuration
verify_vlan_config(peth)
return None
@@ -101,9 +75,11 @@ def apply(peth):
if 'mode_old' in peth:
MACVLANIf(peth['ifname']).remove()
- # MACVLAN interface needs to be created on-block instead of passing a ton
- # of arguments, I just use a dict that is managed by vyos.ifconfig
- conf = deepcopy(MACVLANIf.get_config())
+ # This is a special type of interface which needs additional parameters
+ # when created using iproute2. Instead of passing a ton of arguments,
+ # use a dictionary provided by the interface class which holds all the
+ # options necessary.
+ conf = MACVLANIf.get_config()
# Assign MACVLAN instance configuration parameters to config dict
conf['source_interface'] = peth['source_interface']
diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py
index 11d8d6edc..f1d885b15 100755
--- a/src/conf_mode/interfaces-tunnel.py
+++ b/src/conf_mode/interfaces-tunnel.py
@@ -22,10 +22,11 @@ from copy import deepcopy
from netifaces import interfaces
from vyos.config import Config
+from vyos.configdict import is_member
from vyos.ifconfig import Interface, GREIf, GRETapIf, IPIPIf, IP6GREIf, IPIP6If, IP6IP6If, SitIf, Sit6RDIf
from vyos.ifconfig.afi import IP4, IP6
from vyos.configdict import list_diff
-from vyos.validate import is_ipv4, is_ipv6, is_member
+from vyos.validate import is_ipv4, is_ipv6
from vyos import ConfigError
from vyos.dicts import FixedDict
@@ -170,8 +171,8 @@ class ConfigurationState(object):
"""
>>> conf.get_values('addresses', 'address')
will place a list of the new IP present in 'interface dummy dum1 address'
- into the dictionnary entry "-add" (here 'addresses-add') using
- Config.return_values and will add the the one which were removed in into
+ into the dictionnary entry "-add" (here 'addresses-add') using
+ Config.return_values and will add the the one which were removed in into
the entry "-del" (here addresses-del')
"""
add_name = f'{name}-add'
@@ -263,7 +264,7 @@ class ConfigurationState(object):
d = d[lpath[-1]]
# XXX: it should have provided me the content and not the key
self._conf.set_level(l)
- return d
+ return d
def to_api(self):
"""
diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py
index bea3aa25b..002f40aef 100755
--- a/src/conf_mode/interfaces-vxlan.py
+++ b/src/conf_mode/interfaces-vxlan.py
@@ -17,13 +17,13 @@
import os
from sys import exit
-from copy import deepcopy
from netifaces import interfaces
from vyos.config import Config
from vyos.configdict import get_interface_dict
from vyos.configverify import verify_address
from vyos.configverify import verify_bridge_delete
+from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_source_interface
from vyos.ifconfig import VXLANIf, Interface
from vyos import ConfigError
@@ -73,11 +73,12 @@ def verify(vxlan):
if 'source_interface' in vxlan:
# VXLAN adds a 50 byte overhead - we need to check the underlaying MTU
# if our configured MTU is at least 50 bytes less
- underlay_mtu = int(Interface(vxlan['source_interface']).get_mtu())
- if underlay_mtu < (int(vxlan['mtu']) + 50):
+ lower_mtu = Interface(vxlan['source_interface']).get_mtu()
+ if lower_mtu < (int(vxlan['mtu']) + 50):
raise ConfigError('VXLAN has a 50 byte overhead, underlaying device ' \
f'MTU is to small ({underlay_mtu} bytes)')
+ verify_mtu_ipv6(vxlan)
verify_address(vxlan)
return None
@@ -95,10 +96,11 @@ def apply(vxlan):
v.remove()
if 'deleted' not in vxlan:
- # VXLAN interface needs to be created on-block
- # instead of passing a ton of arguments, I just use a dict
- # that is managed by vyos.ifconfig
- conf = deepcopy(VXLANIf.get_config())
+ # This is a special type of interface which needs additional parameters
+ # when created using iproute2. Instead of passing a ton of arguments,
+ # use a dictionary provided by the interface class which holds all the
+ # options necessary.
+ conf = VXLANIf.get_config()
# Assign VXLAN instance configuration parameters to config dict
for tmp in ['vni', 'group', 'source_address', 'source_interface', 'remote', 'port']:
diff --git a/src/conf_mode/interfaces-wireguard.py b/src/conf_mode/interfaces-wireguard.py
index e7c22da1a..d5800264f 100755
--- a/src/conf_mode/interfaces-wireguard.py
+++ b/src/conf_mode/interfaces-wireguard.py
@@ -27,6 +27,7 @@ from vyos.configdict import leaf_node_changed
from vyos.configverify import verify_vrf
from vyos.configverify import verify_address
from vyos.configverify import verify_bridge_delete
+from vyos.configverify import verify_mtu_ipv6
from vyos.ifconfig import WireGuardIf
from vyos.util import check_kmod
from vyos import ConfigError
@@ -71,6 +72,7 @@ def verify(wireguard):
verify_bridge_delete(wireguard)
return None
+ verify_mtu_ipv6(wireguard)
verify_address(wireguard)
verify_vrf(wireguard)
diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py
index c6c843e7b..f8520aecf 100755
--- a/src/conf_mode/interfaces-wireless.py
+++ b/src/conf_mode/interfaces-wireless.py
@@ -18,7 +18,6 @@ import os
from sys import exit
from re import findall
-from copy import deepcopy
from netaddr import EUI, mac_unix_expanded
from vyos.config import Config
@@ -233,13 +232,15 @@ def apply(wifi):
if 'deleted' in wifi:
WiFiIf(interface).remove()
else:
- # WiFi interface needs to be created on-block (e.g. mode or physical
- # interface) instead of passing a ton of arguments, I just use a dict
- # that is managed by vyos.ifconfig
- conf = deepcopy(WiFiIf.get_config())
+ # This is a special type of interface which needs additional parameters
+ # when created using iproute2. Instead of passing a ton of arguments,
+ # use a dictionary provided by the interface class which holds all the
+ # options necessary.
+ conf = WiFiIf.get_config()
# Assign WiFi instance configuration parameters to config dict
conf['phy'] = wifi['physical_device']
+ conf['wds'] = 'on' if 'wds' in wifi else 'off'
# Finally create the new interface
w = WiFiIf(interface, **conf)
diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py
index e9806ef47..117bf0274 100755
--- a/src/conf_mode/snmp.py
+++ b/src/conf_mode/snmp.py
@@ -22,7 +22,7 @@ from vyos.config import Config
from vyos.configverify import verify_vrf
from vyos.snmpv3_hashgen import plaintext_to_md5, plaintext_to_sha1, random
from vyos.template import render
-from vyos.util import call
+from vyos.util import call, chmod_755
from vyos.validate import is_ipv4, is_addr_assigned
from vyos.version import get_version_data
from vyos import ConfigError, airbag
diff --git a/src/migration-scripts/interfaces/12-to-13 b/src/migration-scripts/interfaces/12-to-13
new file mode 100755
index 000000000..f866ca9a6
--- /dev/null
+++ b/src/migration-scripts/interfaces/12-to-13
@@ -0,0 +1,71 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2020 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/>.
+
+# - T2903: Change vif-s ethertype from numeric number to literal
+# - 0x88a8 -> 802.1ad
+# - 0x8100 -> 802.1q
+# - T2905: Change WWAN "ondemand" node to "connect-on-demand" to have identical
+# CLI nodes for both types of dialer interfaces
+
+from sys import exit, argv
+from vyos.configtree import ConfigTree
+
+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)
+
+ #
+ # T2903
+ #
+ for type in config.list_nodes(['interfaces']):
+ for interface in config.list_nodes(['interfaces', type]):
+ if not config.exists(['interfaces', type, interface, 'vif-s']):
+ continue
+
+ for vif_s in config.list_nodes(['interfaces', type, interface, 'vif-s']):
+ base_path = ['interfaces', type, interface, 'vif-s', vif_s]
+ if config.exists(base_path + ['ethertype']):
+ protocol = '802.1ad'
+ tmp = config.return_value(base_path + ['ethertype'])
+ if tmp == '0x8100':
+ protocol = '802.1q'
+
+ config.set(base_path + ['protocol'], value=protocol)
+ config.delete(base_path + ['ethertype'])
+
+ #
+ # T2905
+ #
+ wwan_base = ['interfaces', 'wirelessmodem']
+ if config.exists(wwan_base):
+ for interface in config.list_nodes(wwan_base):
+ if config.exists(wwan_base + [interface, 'ondemand']):
+ config.rename(wwan_base + [interface, 'ondemand'], 'connect-on-demand')
+
+ 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/system/10-to-11 b/src/migration-scripts/system/10-to-11
index 1a0233c7d..3c49f0d95 100755
--- a/src/migration-scripts/system/10-to-11
+++ b/src/migration-scripts/system/10-to-11
@@ -1,9 +1,7 @@
#!/usr/bin/env python3
-# Unclutter RADIUS configuration
-#
-# Move radius-server top level tag nodes to a regular node which allows us
-# to specify additional general features for the RADIUS client.
+# Operator accounts have been deprecated due to a security issue. Those accounts
+# will be converted to regular admin accounts.
import sys
from vyos.configtree import ConfigTree
@@ -18,54 +16,21 @@ with open(file_name, 'r') as f:
config_file = f.read()
config = ConfigTree(config_file)
-cfg_base = ['system', 'login']
-if not (config.exists(cfg_base + ['radius-server']) or config.exists(cfg_base + ['radius-source-address'])):
- # Nothing to do
+base_level = ['system', 'login', 'user']
+
+if not config.exists(base_level):
+ # Nothing to do, which shouldn't happen anyway
+ # only if you wipe the config and reboot.
sys.exit(0)
else:
- #
- # Migrate "system login radius-source-address" to "system login radius"
- #
- if config.exists(cfg_base + ['radius-source-address']):
- address = config.return_value(cfg_base + ['radius-source-address'])
- # delete old configuration node
- config.delete(cfg_base + ['radius-source-address'])
- # write new configuration node
- config.set(cfg_base + ['radius', 'source-address'], value=address)
-
- #
- # Migrate "system login radius-server" tag node to new
- # "system login radius server" tag node and also rename the "secret" node to "key"
- #
- for server in config.list_nodes(cfg_base + ['radius-server']):
- base_server = cfg_base + ['radius-server', server]
- # "key" node is mandatory
- key = config.return_value(base_server + ['secret'])
- config.set(cfg_base + ['radius', 'server', server, 'key'], value=key)
-
- # "port" is optional
- if config.exists(base_server + ['port']):
- port = config.return_value(base_server + ['port'])
- config.set(cfg_base + ['radius', 'server', server, 'port'], value=port)
-
- # "timeout is optional"
- if config.exists(base_server + ['timeout']):
- timeout = config.return_value(base_server + ['timeout'])
- config.set(cfg_base + ['radius', 'server', server, 'timeout'], value=timeout)
-
- # format as tag node
- config.set_tag(cfg_base + ['radius', 'server'])
-
- # delete old configuration node
- config.delete(base_server)
-
- # delete top level tag node
- if config.exists(cfg_base + ['radius-server']):
- config.delete(cfg_base + ['radius-server'])
+ for user in config.list_nodes(base_level):
+ if config.exists(base_level + [user, 'level']):
+ if config.return_value(base_level + [user, 'level']) == 'operator':
+ config.set(base_level + [user, 'level'], value="admin", replace=True)
try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
+ open(file_name,'w').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/system/11-to-12 b/src/migration-scripts/system/11-to-12
index 0c92a0746..1a0233c7d 100755
--- a/src/migration-scripts/system/11-to-12
+++ b/src/migration-scripts/system/11-to-12
@@ -1,47 +1,71 @@
#!/usr/bin/env python3
-# converts 'set system syslog host <address>:<port>'
-# to 'set system syslog host <address> port <port>'
+# Unclutter RADIUS configuration
+#
+# Move radius-server top level tag nodes to a regular node which allows us
+# to specify additional general features for the RADIUS client.
import sys
-import re
-
from vyos.configtree import ConfigTree
if (len(sys.argv) < 1):
- print("Must specify file name!")
- sys.exit(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_file = f.read()
config = ConfigTree(config_file)
-cbase = ['system', 'syslog', 'host']
-
-if not config.exists(cbase):
+cfg_base = ['system', 'login']
+if not (config.exists(cfg_base + ['radius-server']) or config.exists(cfg_base + ['radius-source-address'])):
+ # Nothing to do
sys.exit(0)
+else:
+ #
+ # Migrate "system login radius-source-address" to "system login radius"
+ #
+ if config.exists(cfg_base + ['radius-source-address']):
+ address = config.return_value(cfg_base + ['radius-source-address'])
+ # delete old configuration node
+ config.delete(cfg_base + ['radius-source-address'])
+ # write new configuration node
+ config.set(cfg_base + ['radius', 'source-address'], value=address)
+
+ #
+ # Migrate "system login radius-server" tag node to new
+ # "system login radius server" tag node and also rename the "secret" node to "key"
+ #
+ for server in config.list_nodes(cfg_base + ['radius-server']):
+ base_server = cfg_base + ['radius-server', server]
+ # "key" node is mandatory
+ key = config.return_value(base_server + ['secret'])
+ config.set(cfg_base + ['radius', 'server', server, 'key'], value=key)
+
+ # "port" is optional
+ if config.exists(base_server + ['port']):
+ port = config.return_value(base_server + ['port'])
+ config.set(cfg_base + ['radius', 'server', server, 'port'], value=port)
+
+ # "timeout is optional"
+ if config.exists(base_server + ['timeout']):
+ timeout = config.return_value(base_server + ['timeout'])
+ config.set(cfg_base + ['radius', 'server', server, 'timeout'], value=timeout)
+
+ # format as tag node
+ config.set_tag(cfg_base + ['radius', 'server'])
+
+ # delete old configuration node
+ config.delete(base_server)
-for host in config.list_nodes(cbase):
- if re.search(':[0-9]{1,5}$',host):
- h = re.search('^[a-zA-Z\-0-9\.]+', host).group(0)
- p = re.sub(':', '', re.search(':[0-9]+$', host).group(0))
- config.set(cbase + [h])
- config.set(cbase + [h, 'port'], value=p)
- for fac in config.list_nodes(cbase + [host, 'facility']):
- config.set(cbase + [h, 'facility', fac])
- config.set_tag(cbase + [h, 'facility'])
- if config.exists(cbase + [host, 'facility', fac, 'protocol']):
- proto = config.return_value(cbase + [host, 'facility', fac, 'protocol'])
- config.set(cbase + [h, 'facility', fac, 'protocol'], value=proto)
- if config.exists(cbase + [host, 'facility', fac, 'level']):
- lvl = config.return_value(cbase + [host, 'facility', fac, 'level'])
- config.set(cbase + [h, 'facility', fac, 'level'], value=lvl)
- config.delete(cbase + [host])
+ # delete top level tag node
+ if config.exists(cfg_base + ['radius-server']):
+ config.delete(cfg_base + ['radius-server'])
try:
- open(file_name,'w').write(config.to_string())
+ 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/system/12-to-13 b/src/migration-scripts/system/12-to-13
index 5b068f4fc..36311a19d 100755
--- a/src/migration-scripts/system/12-to-13
+++ b/src/migration-scripts/system/12-to-13
@@ -1,70 +1,47 @@
#!/usr/bin/env python3
-# Fixup non existent time-zones. Some systems have time-zone set to: Los*
-# (Los_Angeles), Den* (Denver), New* (New_York) ... but those are no real IANA
-# assigned time zones. In the past they have been silently remapped.
-#
-# Time to clean it up!
-#
-# Migrate all configured timezones to real IANA assigned timezones!
+# converts 'set system syslog host <address>:<port>'
+# to 'set system syslog host <address> port <port>'
-import re
import sys
+import re
from vyos.configtree import ConfigTree
-from vyos.util import cmd
-
if (len(sys.argv) < 1):
- print("Must specify file name!")
- sys.exit(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_file = f.read()
config = ConfigTree(config_file)
-tz_base = ['system', 'time-zone']
-if not config.exists(tz_base):
- # Nothing to do
- sys.exit(0)
-else:
- tz = config.return_value(tz_base)
+cbase = ['system', 'syslog', 'host']
- # retrieve all valid timezones
- try:
- tz_datas = cmd('find /usr/share/zoneinfo/posix -type f -or -type l | sed -e s:/usr/share/zoneinfo/posix/::')
- except OSError:
- tz_datas = ''
- tz_data = tz_datas.split('\n')
-
- if re.match(r'[Ll][Oo][Ss].+', tz):
- tz = 'America/Los_Angeles'
- elif re.match(r'[Dd][Ee][Nn].+', tz):
- tz = 'America/Denver'
- elif re.match(r'[Hh][Oo][Nn][Oo].+', tz):
- tz = 'Pacific/Honolulu'
- elif re.match(r'[Nn][Ee][Ww].+', tz):
- tz = 'America/New_York'
- elif re.match(r'[Cc][Hh][Ii][Cc]*.+', tz):
- tz = 'America/Chicago'
- elif re.match(r'[Aa][Nn][Cc].+', tz):
- tz = 'America/Anchorage'
- elif re.match(r'[Pp][Hh][Oo].+', tz):
- tz = 'America/Phoenix'
- elif re.match(r'GMT(.+)?', tz):
- tz = 'Etc/' + tz
- elif tz not in tz_data:
- # assign default UTC timezone
- tz = 'UTC'
-
- # replace timezone data is required
- config.set(tz_base, value=tz)
+if not config.exists(cbase):
+ sys.exit(0)
- 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)
+for host in config.list_nodes(cbase):
+ if re.search(':[0-9]{1,5}$',host):
+ h = re.search('^[a-zA-Z\-0-9\.]+', host).group(0)
+ p = re.sub(':', '', re.search(':[0-9]+$', host).group(0))
+ config.set(cbase + [h])
+ config.set(cbase + [h, 'port'], value=p)
+ for fac in config.list_nodes(cbase + [host, 'facility']):
+ config.set(cbase + [h, 'facility', fac])
+ config.set_tag(cbase + [h, 'facility'])
+ if config.exists(cbase + [host, 'facility', fac, 'protocol']):
+ proto = config.return_value(cbase + [host, 'facility', fac, 'protocol'])
+ config.set(cbase + [h, 'facility', fac, 'protocol'], value=proto)
+ if config.exists(cbase + [host, 'facility', fac, 'level']):
+ lvl = config.return_value(cbase + [host, 'facility', fac, 'level'])
+ config.set(cbase + [h, 'facility', fac, 'level'], value=lvl)
+ config.delete(cbase + [host])
+
+try:
+ open(file_name,'w').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/system/13-to-14 b/src/migration-scripts/system/13-to-14
index c055dad1f..5b068f4fc 100755
--- a/src/migration-scripts/system/13-to-14
+++ b/src/migration-scripts/system/13-to-14
@@ -1,15 +1,19 @@
#!/usr/bin/env python3
+
+# Fixup non existent time-zones. Some systems have time-zone set to: Los*
+# (Los_Angeles), Den* (Denver), New* (New_York) ... but those are no real IANA
+# assigned time zones. In the past they have been silently remapped.
+#
+# Time to clean it up!
#
-# Delete 'system ipv6 blacklist' option as the IPv6 module can no longer be
-# blacklisted as it is required by e.g. WireGuard and thus will always be
-# loaded.
+# Migrate all configured timezones to real IANA assigned timezones!
-import os
+import re
import sys
-ipv6_blacklist_file = '/etc/modprobe.d/vyatta_blacklist_ipv6.conf'
-
from vyos.configtree import ConfigTree
+from vyos.util import cmd
+
if (len(sys.argv) < 1):
print("Must specify file name!")
@@ -21,16 +25,42 @@ with open(file_name, 'r') as f:
config_file = f.read()
config = ConfigTree(config_file)
-ip_base = ['system', 'ipv6']
-if not config.exists(ip_base):
+tz_base = ['system', 'time-zone']
+if not config.exists(tz_base):
# Nothing to do
sys.exit(0)
else:
- # delete 'system ipv6 blacklist' node
- if config.exists(ip_base + ['blacklist']):
- config.delete(ip_base + ['blacklist'])
- if os.path.isfile(ipv6_blacklist_file):
- os.unlink(ipv6_blacklist_file)
+ tz = config.return_value(tz_base)
+
+ # retrieve all valid timezones
+ try:
+ tz_datas = cmd('find /usr/share/zoneinfo/posix -type f -or -type l | sed -e s:/usr/share/zoneinfo/posix/::')
+ except OSError:
+ tz_datas = ''
+ tz_data = tz_datas.split('\n')
+
+ if re.match(r'[Ll][Oo][Ss].+', tz):
+ tz = 'America/Los_Angeles'
+ elif re.match(r'[Dd][Ee][Nn].+', tz):
+ tz = 'America/Denver'
+ elif re.match(r'[Hh][Oo][Nn][Oo].+', tz):
+ tz = 'Pacific/Honolulu'
+ elif re.match(r'[Nn][Ee][Ww].+', tz):
+ tz = 'America/New_York'
+ elif re.match(r'[Cc][Hh][Ii][Cc]*.+', tz):
+ tz = 'America/Chicago'
+ elif re.match(r'[Aa][Nn][Cc].+', tz):
+ tz = 'America/Anchorage'
+ elif re.match(r'[Pp][Hh][Oo].+', tz):
+ tz = 'America/Phoenix'
+ elif re.match(r'GMT(.+)?', tz):
+ tz = 'Etc/' + tz
+ elif tz not in tz_data:
+ # assign default UTC timezone
+ tz = 'UTC'
+
+ # replace timezone data is required
+ config.set(tz_base, value=tz)
try:
with open(file_name, 'w') as f:
diff --git a/src/migration-scripts/system/14-to-15 b/src/migration-scripts/system/14-to-15
index 2491e3d0d..c055dad1f 100755
--- a/src/migration-scripts/system/14-to-15
+++ b/src/migration-scripts/system/14-to-15
@@ -1,10 +1,14 @@
#!/usr/bin/env python3
#
-# Make 'system options reboot-on-panic' valueless
+# Delete 'system ipv6 blacklist' option as the IPv6 module can no longer be
+# blacklisted as it is required by e.g. WireGuard and thus will always be
+# loaded.
import os
import sys
+ipv6_blacklist_file = '/etc/modprobe.d/vyatta_blacklist_ipv6.conf'
+
from vyos.configtree import ConfigTree
if (len(sys.argv) < 1):
@@ -17,17 +21,16 @@ with open(file_name, 'r') as f:
config_file = f.read()
config = ConfigTree(config_file)
-base = ['system', 'options']
-if not config.exists(base):
+ip_base = ['system', 'ipv6']
+if not config.exists(ip_base):
# Nothing to do
sys.exit(0)
else:
- if config.exists(base + ['reboot-on-panic']):
- reboot = config.return_value(base + ['reboot-on-panic'])
- config.delete(base + ['reboot-on-panic'])
- # create new valueless node if action was true
- if reboot == "true":
- config.set(base + ['reboot-on-panic'])
+ # delete 'system ipv6 blacklist' node
+ if config.exists(ip_base + ['blacklist']):
+ config.delete(ip_base + ['blacklist'])
+ if os.path.isfile(ipv6_blacklist_file):
+ os.unlink(ipv6_blacklist_file)
try:
with open(file_name, 'w') as f:
diff --git a/src/migration-scripts/system/15-to-16 b/src/migration-scripts/system/15-to-16
index e70893d55..2491e3d0d 100755
--- a/src/migration-scripts/system/15-to-16
+++ b/src/migration-scripts/system/15-to-16
@@ -1,24 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 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/>.
-
-# * remove "system login user <user> group" node, Why should be add a user to a
-# 3rd party group when the system is fully managed by CLI?
-# * remove "system login user <user> level" node
-# This is the only privilege level left and also the default, what is the
-# sense in keeping this orphaned node?
+# Make 'system options reboot-on-panic' valueless
import os
import sys
@@ -35,17 +17,17 @@ with open(file_name, 'r') as f:
config_file = f.read()
config = ConfigTree(config_file)
-base = ['system', 'login', 'user']
+base = ['system', 'options']
if not config.exists(base):
# Nothing to do
sys.exit(0)
else:
- for user in config.list_nodes(base):
- if config.exists(base + [user, 'group']):
- config.delete(base + [user, 'group'])
-
- if config.exists(base + [user, 'level']):
- config.delete(base + [user, 'level'])
+ if config.exists(base + ['reboot-on-panic']):
+ reboot = config.return_value(base + ['reboot-on-panic'])
+ config.delete(base + ['reboot-on-panic'])
+ # create new valueless node if action was true
+ if reboot == "true":
+ config.set(base + ['reboot-on-panic'])
try:
with open(file_name, 'w') as f:
diff --git a/src/migration-scripts/system/16-to-17 b/src/migration-scripts/system/16-to-17
index 8f762c0e2..e70893d55 100755
--- a/src/migration-scripts/system/16-to-17
+++ b/src/migration-scripts/system/16-to-17
@@ -14,8 +14,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# remove "system console netconsole"
-# remove "system console device <device> modem"
+# * remove "system login user <user> group" node, Why should be add a user to a
+# 3rd party group when the system is fully managed by CLI?
+# * remove "system login user <user> level" node
+# This is the only privilege level left and also the default, what is the
+# sense in keeping this orphaned node?
import os
import sys
@@ -32,41 +35,17 @@ with open(file_name, 'r') as f:
config_file = f.read()
config = ConfigTree(config_file)
-base = ['system', 'console']
+base = ['system', 'login', 'user']
if not config.exists(base):
# Nothing to do
sys.exit(0)
else:
- # remove "system console netconsole" (T2561)
- if config.exists(base + ['netconsole']):
- config.delete(base + ['netconsole'])
+ for user in config.list_nodes(base):
+ if config.exists(base + [user, 'group']):
+ config.delete(base + [user, 'group'])
- if config.exists(base + ['device']):
- for device in config.list_nodes(base + ['device']):
- dev_path = base + ['device', device]
- # remove "system console device <device> modem" (T2570)
- if config.exists(dev_path + ['modem']):
- config.delete(dev_path + ['modem'])
-
- # Only continue on USB based serial consoles
- if not 'ttyUSB' in device:
- continue
-
- # A serial console has been configured but it does no longer
- # exist on the system - cleanup
- if not os.path.exists(f'/dev/{device}'):
- config.delete(dev_path)
- continue
-
- # migrate from ttyUSB device to new device in /dev/serial/by-bus
- for root, dirs, files in os.walk('/dev/serial/by-bus'):
- for usb_device in files:
- device_file = os.path.realpath(os.path.join(root, usb_device))
- # migrate to new USB device names (T2529)
- if os.path.basename(device_file) == device:
- config.copy(dev_path, base + ['device', usb_device])
- # Delete old USB node from config
- config.delete(dev_path)
+ if config.exists(base + [user, 'level']):
+ config.delete(base + [user, 'level'])
try:
with open(file_name, 'w') as f:
diff --git a/src/migration-scripts/system/17-to-18 b/src/migration-scripts/system/17-to-18
index dd2abce00..8f762c0e2 100755
--- a/src/migration-scripts/system/17-to-18
+++ b/src/migration-scripts/system/17-to-18
@@ -13,93 +13,64 @@
#
# 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 disable-dhcp-nameservers (boolean) to name-servers-dhcp <interface>
-# if disable-dhcp-nameservers is set, just remove it
-# else retrieve all interface names that have configured dhcp(v6) address and
-# add them to the new name-servers-dhcp node
+# remove "system console netconsole"
+# remove "system console device <device> modem"
+
+import os
+import sys
-from sys import argv, exit
-from vyos.ifconfig import Interface
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if (len(sys.argv) < 1):
print("Must specify file name!")
- exit(1)
+ sys.exit(1)
-file_name = argv[1]
+file_name = sys.argv[1]
with open(file_name, 'r') as f:
config_file = f.read()
config = ConfigTree(config_file)
-
-base = ['system']
+base = ['system', 'console']
if not config.exists(base):
# Nothing to do
- exit(0)
-
-if config.exists(base + ['disable-dhcp-nameservers']):
- config.delete(base + ['disable-dhcp-nameservers'])
+ sys.exit(0)
else:
- dhcp_interfaces = []
-
- # go through all interfaces searching for 'address dhcp(v6)?'
- for sect in Interface.sections():
- sect_base = ['interfaces', sect]
-
- if not config.exists(sect_base):
- continue
-
- for intf in config.list_nodes(sect_base):
- intf_base = sect_base + [intf]
-
- # try without vlans
- if config.exists(intf_base + ['address']):
- for addr in config.return_values(intf_base + ['address']):
- if addr in ['dhcp', 'dhcpv6']:
- dhcp_interfaces.append(intf)
-
- # try vif
- if config.exists(intf_base + ['vif']):
- for vif in config.list_nodes(intf_base + ['vif']):
- vif_base = intf_base + ['vif', vif]
- if config.exists(vif_base + ['address']):
- for addr in config.return_values(vif_base + ['address']):
- if addr in ['dhcp', 'dhcpv6']:
- dhcp_interfaces.append(f'{intf}.{vif}')
-
- # try vif-s
- if config.exists(intf_base + ['vif-s']):
- for vif_s in config.list_nodes(intf_base + ['vif-s']):
- vif_s_base = intf_base + ['vif-s', vif_s]
- if config.exists(vif_s_base + ['address']):
- for addr in config.return_values(vif_s_base + ['address']):
- if addr in ['dhcp', 'dhcpv6']:
- dhcp_interfaces.append(f'{intf}.{vif_s}')
-
- # try vif-c
- if config.exists(intf_base + ['vif-c', vif_c]):
- for vif_c in config.list_nodes(vif_s_base + ['vif-c', vif_c]):
- vif_c_base = vif_s_base + ['vif-c', vif_c]
- if config.exists(vif_c_base + ['address']):
- for addr in config.return_values(vif_c_base + ['address']):
- if addr in ['dhcp', 'dhcpv6']:
- dhcp_interfaces.append(f'{intf}.{vif_s}.{vif_c}')
-
- # set new config nodes
- for intf in dhcp_interfaces:
- config.set(base + ['name-servers-dhcp'], value=intf, replace=False)
-
- # delete old node
- config.delete(base + ['disable-dhcp-nameservers'])
-
-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)
-
-exit(0)
+ # remove "system console netconsole" (T2561)
+ if config.exists(base + ['netconsole']):
+ config.delete(base + ['netconsole'])
+
+ if config.exists(base + ['device']):
+ for device in config.list_nodes(base + ['device']):
+ dev_path = base + ['device', device]
+ # remove "system console device <device> modem" (T2570)
+ if config.exists(dev_path + ['modem']):
+ config.delete(dev_path + ['modem'])
+
+ # Only continue on USB based serial consoles
+ if not 'ttyUSB' in device:
+ continue
+
+ # A serial console has been configured but it does no longer
+ # exist on the system - cleanup
+ if not os.path.exists(f'/dev/{device}'):
+ config.delete(dev_path)
+ continue
+
+ # migrate from ttyUSB device to new device in /dev/serial/by-bus
+ for root, dirs, files in os.walk('/dev/serial/by-bus'):
+ for usb_device in files:
+ device_file = os.path.realpath(os.path.join(root, usb_device))
+ # migrate to new USB device names (T2529)
+ if os.path.basename(device_file) == device:
+ config.copy(dev_path, base + ['device', usb_device])
+ # Delete old USB node from config
+ config.delete(dev_path)
+
+ 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/system/18-to-19 b/src/migration-scripts/system/18-to-19
new file mode 100755
index 000000000..dd2abce00
--- /dev/null
+++ b/src/migration-scripts/system/18-to-19
@@ -0,0 +1,105 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2020 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 disable-dhcp-nameservers (boolean) to name-servers-dhcp <interface>
+# if disable-dhcp-nameservers is set, just remove it
+# else retrieve all interface names that have configured dhcp(v6) address and
+# add them to the new name-servers-dhcp node
+
+from sys import argv, exit
+from vyos.ifconfig import Interface
+from vyos.configtree import ConfigTree
+
+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)
+
+base = ['system']
+if not config.exists(base):
+ # Nothing to do
+ exit(0)
+
+if config.exists(base + ['disable-dhcp-nameservers']):
+ config.delete(base + ['disable-dhcp-nameservers'])
+else:
+ dhcp_interfaces = []
+
+ # go through all interfaces searching for 'address dhcp(v6)?'
+ for sect in Interface.sections():
+ sect_base = ['interfaces', sect]
+
+ if not config.exists(sect_base):
+ continue
+
+ for intf in config.list_nodes(sect_base):
+ intf_base = sect_base + [intf]
+
+ # try without vlans
+ if config.exists(intf_base + ['address']):
+ for addr in config.return_values(intf_base + ['address']):
+ if addr in ['dhcp', 'dhcpv6']:
+ dhcp_interfaces.append(intf)
+
+ # try vif
+ if config.exists(intf_base + ['vif']):
+ for vif in config.list_nodes(intf_base + ['vif']):
+ vif_base = intf_base + ['vif', vif]
+ if config.exists(vif_base + ['address']):
+ for addr in config.return_values(vif_base + ['address']):
+ if addr in ['dhcp', 'dhcpv6']:
+ dhcp_interfaces.append(f'{intf}.{vif}')
+
+ # try vif-s
+ if config.exists(intf_base + ['vif-s']):
+ for vif_s in config.list_nodes(intf_base + ['vif-s']):
+ vif_s_base = intf_base + ['vif-s', vif_s]
+ if config.exists(vif_s_base + ['address']):
+ for addr in config.return_values(vif_s_base + ['address']):
+ if addr in ['dhcp', 'dhcpv6']:
+ dhcp_interfaces.append(f'{intf}.{vif_s}')
+
+ # try vif-c
+ if config.exists(intf_base + ['vif-c', vif_c]):
+ for vif_c in config.list_nodes(vif_s_base + ['vif-c', vif_c]):
+ vif_c_base = vif_s_base + ['vif-c', vif_c]
+ if config.exists(vif_c_base + ['address']):
+ for addr in config.return_values(vif_c_base + ['address']):
+ if addr in ['dhcp', 'dhcpv6']:
+ dhcp_interfaces.append(f'{intf}.{vif_s}.{vif_c}')
+
+ # set new config nodes
+ for intf in dhcp_interfaces:
+ config.set(base + ['name-servers-dhcp'], value=intf, replace=False)
+
+ # delete old node
+ config.delete(base + ['disable-dhcp-nameservers'])
+
+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)
+
+exit(0)
diff --git a/src/migration-scripts/system/9-to-10 b/src/migration-scripts/system/9-to-10
deleted file mode 100755
index 3c49f0d95..000000000
--- a/src/migration-scripts/system/9-to-10
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/env python3
-
-# Operator accounts have been deprecated due to a security issue. Those accounts
-# will be converted to regular admin accounts.
-
-import sys
-from vyos.configtree import ConfigTree
-
-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)
-base_level = ['system', 'login', 'user']
-
-if not config.exists(base_level):
- # Nothing to do, which shouldn't happen anyway
- # only if you wipe the config and reboot.
- sys.exit(0)
-else:
- for user in config.list_nodes(base_level):
- if config.exists(base_level + [user, 'level']):
- if config.return_value(base_level + [user, 'level']) == 'operator':
- config.set(base_level + [user, 'level'], value="admin", replace=True)
-
- try:
- open(file_name,'w').write(config.to_string())
-
- except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- sys.exit(1)
diff --git a/src/services/vyos-hostsd b/src/services/vyos-hostsd
index 0079f7e5c..59dbeda17 100755
--- a/src/services/vyos-hostsd
+++ b/src/services/vyos-hostsd
@@ -107,16 +107,17 @@
#
### forward_zones
## Additional zones added to pdns-recursor forward-zones-file.
-## If recursion-desired is true, '+' will be prepended to the zone line.
-## If addNTA is true, a NTA will be added via lua-config-file.
+## If recursion_desired is true, '+' will be prepended to the zone line.
+## If addnta is true, a NTA (Negative Trust Anchor) will be added via
+## lua-config-file.
#
# { 'type': 'forward_zones',
# 'op': 'add',
# 'data': {
# '<str zone>': {
-# 'nslist': ['<str nameserver>', ...],
-# 'addNTA': <bool>,
-# 'recursion-desired': <bool>
+# 'server': ['<str nameserver>', ...],
+# 'addnta': <bool>,
+# 'recursion_desired': <bool>
# }
# ...
# }
@@ -305,12 +306,12 @@ tag_regex_schema = op_type_schema.extend({
forward_zone_add_schema = op_type_schema.extend({
'data': {
str: {
- 'nslist': [str],
- 'addNTA': bool,
- 'recursion-desired': bool
+ 'server': [str],
+ 'addnta': Any({}, None),
+ 'recursion_desired': Any({}, None),
}
}
- }, required=True)
+ }, required=False)
hosts_add_schema = op_type_schema.extend({
'data': {
@@ -586,7 +587,7 @@ if __name__ == '__main__':
context = zmq.Context()
socket = context.socket(zmq.REP)
-
+
# Set the right permissions on the socket, then change it back
o_mask = os.umask(0o007)
socket.bind(SOCKET_PATH)
diff --git a/src/utils/vyos-hostsd-client b/src/utils/vyos-hostsd-client
index 48ebc83f7..d4d38315a 100755
--- a/src/utils/vyos-hostsd-client
+++ b/src/utils/vyos-hostsd-client
@@ -99,9 +99,9 @@ try:
raise ValueError("--nameservers is required for this operation")
client.add_forward_zones(
{ args.add_forward_zone: {
- 'nslist': args.nameservers,
- 'addNTA': args.addnta,
- 'recursion-desired': args.recursion_desired
+ 'server': args.nameservers,
+ 'addnta': args.addnta,
+ 'recursion_desired': args.recursion_desired
}
})
elif args.delete_forward_zones: