summaryrefslogtreecommitdiff
path: root/src/conf_mode/dhcpv6_server.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/conf_mode/dhcpv6_server.py')
-rwxr-xr-xsrc/conf_mode/dhcpv6_server.py150
1 files changed, 74 insertions, 76 deletions
diff --git a/src/conf_mode/dhcpv6_server.py b/src/conf_mode/dhcpv6_server.py
index 94a307826..159d16401 100755
--- a/src/conf_mode/dhcpv6_server.py
+++ b/src/conf_mode/dhcpv6_server.py
@@ -23,7 +23,7 @@ from copy import deepcopy
from vyos.config import Config
from vyos.template import render
from vyos.util import call
-from vyos.validate import is_subnet_connected
+from vyos.validate import is_subnet_connected, is_ipv6
from vyos import ConfigError
config_file = r'/run/dhcp-server/dhcpdv6.conf'
@@ -37,24 +37,25 @@ default_config_data = {
def get_config():
dhcpv6 = deepcopy(default_config_data)
conf = Config()
- if not conf.exists('service dhcpv6-server'):
+ base = ['service', 'dhcpv6-server']
+ if not conf.exists(base):
return None
else:
- conf.set_level('service dhcpv6-server')
+ conf.set_level(base)
# Check for global disable of DHCPv6 service
- if conf.exists('disable'):
+ if conf.exists(['disable']):
dhcpv6['disabled'] = True
return dhcpv6
# Preference of this DHCPv6 server compared with others
- if conf.exists('preference'):
- dhcpv6['preference'] = conf.return_value('preference')
+ if conf.exists(['preference']):
+ dhcpv6['preference'] = conf.return_value(['preference'])
# check for multiple, shared networks served with DHCPv6 addresses
- if conf.exists('shared-network-name'):
- for network in conf.list_nodes('shared-network-name'):
- conf.set_level('service dhcpv6-server shared-network-name {0}'.format(network))
+ if conf.exists(['shared-network-name']):
+ for network in conf.list_nodes(['shared-network-name']):
+ conf.set_level(base + ['shared-network-name', network])
config = {
'name': network,
'disabled': False,
@@ -62,13 +63,13 @@ def get_config():
}
# If disabled, the shared-network configuration becomes inactive
- if conf.exists('disable'):
+ if conf.exists(['disable']):
config['disabled'] = True
# check for multiple subnet configurations in a shared network
- if conf.exists('subnet'):
- for net in conf.list_nodes('subnet'):
- conf.set_level('service dhcpv6-server shared-network-name {0} subnet {1}'.format(network, net))
+ if conf.exists(['subnet']):
+ for net in conf.list_nodes(['subnet']):
+ conf.set_level(base + ['shared-network-name', network, 'subnet', net])
subnet = {
'network': net,
'range6_prefix': [],
@@ -94,25 +95,25 @@ def get_config():
# least one address range statement. The range statement gives the lowest and highest
# IP addresses in a range. All IP addresses in the range should be in the subnet in
# which the range statement is declared.
- if conf.exists('address-range prefix'):
- for prefix in conf.list_nodes('address-range prefix'):
+ if conf.exists(['address-range', 'prefix']):
+ for prefix in conf.list_nodes(['address-range', 'prefix']):
range = {
'prefix': prefix,
'temporary': False
}
# Address range will be used for temporary addresses
- if conf.exists('address-range prefix {0} temporary'.format(range['prefix'])):
+ if conf.exists(['address-range' 'prefix', prefix, 'temporary']):
range['temporary'] = True
# Append to subnet temporary range6 list
subnet['range6_prefix'].append(range)
- if conf.exists('address-range start'):
- for range in conf.list_nodes('address-range start'):
+ if conf.exists(['address-range', 'start']):
+ for range in conf.list_nodes(['address-range', 'start']):
range = {
'start': range,
- 'stop': conf.return_value('address-range start {0} stop'.format(range))
+ 'stop': conf.return_value(['address-range', 'start', range, 'stop'])
}
# Append to subnet range6 list
@@ -120,70 +121,68 @@ def get_config():
# The domain-search option specifies a 'search list' of Domain Names to be used
# by the client to locate not-fully-qualified domain names.
- if conf.exists('domain-search'):
- for domain in conf.return_values('domain-search'):
- subnet['domain_search'].append('"' + domain + '"')
+ if conf.exists(['domain-search']):
+ subnet['domain_search'] = conf.return_values(['domain-search'])
# IPv6 address valid lifetime
# (at the end the address is no longer usable by the client)
# (set to 30 days, the usual IPv6 default)
- if conf.exists('lease-time default'):
- subnet['lease_def'] = conf.return_value('lease-time default')
+ if conf.exists(['lease-time', 'default']):
+ subnet['lease_def'] = conf.return_value(['lease-time', 'default'])
# Time should be the maximum length in seconds that will be assigned to a lease.
# The only exception to this is that Dynamic BOOTP lease lengths, which are not
# specified by the client, are not limited by this maximum.
- if conf.exists('lease-time maximum'):
- subnet['lease_max'] = conf.return_value('lease-time maximum')
+ if conf.exists(['lease-time', 'maximum']):
+ subnet['lease_max'] = conf.return_value(['lease-time', 'maximum'])
# Time should be the minimum length in seconds that will be assigned to a lease
- if conf.exists('lease-time minimum'):
- subnet['lease_min'] = conf.return_value('lease-time minimum')
+ if conf.exists(['lease-time', 'minimum']):
+ subnet['lease_min'] = conf.return_value(['lease-time', 'minimum'])
# Specifies a list of Domain Name System name servers available to the client.
# Servers should be listed in order of preference.
- if conf.exists('name-server'):
- subnet['dns_server'] = conf.return_values('name-server')
+ if conf.exists(['name-server']):
+ subnet['dns_server'] = conf.return_values(['name-server'])
# Ancient NIS (Network Information Service) domain name
- if conf.exists('nis-domain'):
- subnet['nis_domain'] = conf.return_value('nis-domain')
+ if conf.exists(['nis-domain']):
+ subnet['nis_domain'] = conf.return_value(['nis-domain'])
# Ancient NIS (Network Information Service) servers
- if conf.exists('nis-server'):
- subnet['nis_server'] = conf.return_values('nis-server')
+ if conf.exists(['nis-server']):
+ subnet['nis_server'] = conf.return_values(['nis-server'])
# Ancient NIS+ (Network Information Service) domain name
- if conf.exists('nisplus-domain'):
- subnet['nisp_domain'] = conf.return_value('nisplus-domain')
+ if conf.exists(['nisplus-domain']):
+ subnet['nisp_domain'] = conf.return_value(['nisplus-domain'])
# Ancient NIS+ (Network Information Service) servers
- if conf.exists('nisplus-server'):
- subnet['nisp_server'] = conf.return_values('nisplus-server')
+ if conf.exists(['nisplus-server']):
+ subnet['nisp_server'] = conf.return_values(['nisplus-server'])
# Prefix Delegation (RFC 3633)
- if conf.exists('prefix-delegation'):
+ if conf.exists(['prefix-delegation']):
print('TODO: This option is actually not implemented right now!')
# Local SIP server that is to be used for all outbound SIP requests - IPv6 address
- if conf.exists('sip-server-address'):
- subnet['sip_address'] = conf.return_values('sip-server-address')
-
- # Local SIP server that is to be used for all outbound SIP requests - hostname
- if conf.exists('sip-server-name'):
- for hostname in conf.return_values('sip-server-name'):
- subnet['sip_hostname'].append('"' + hostname + '"')
+ if conf.exists(['sip-server']):
+ for value in conf.return_values(['sip-server']):
+ if is_ipv6(value):
+ subnet['sip_address'].append(value)
+ else:
+ subnet['sip_hostname'].append(value)
# List of local SNTP servers available for the client to synchronize their clocks
- if conf.exists('sntp-server'):
- subnet['sntp_server'] = conf.return_values('sntp-server')
+ if conf.exists(['sntp-server']):
+ subnet['sntp_server'] = conf.return_values(['sntp-server'])
#
# Static DHCP v6 leases
#
- if conf.exists('static-mapping'):
- for mapping in conf.list_nodes('static-mapping'):
- conf.set_level('service dhcpv6-server shared-network-name {0} subnet {1} static-mapping {2}'.format(network, net, mapping))
+ if conf.exists(['static-mapping']):
+ for mapping in conf.list_nodes(['static-mapping']):
+ conf.set_level(base + ['shared-network-name', network, 'subnet', net, 'static-mapping', mapping])
mapping = {
'name': mapping,
'disabled': False,
@@ -192,16 +191,16 @@ def get_config():
}
# This static lease is disabled
- if conf.exists('disable'):
+ if conf.exists(['disable']):
mapping['disabled'] = True
# IPv6 address used for this DHCP client
- if conf.exists('ipv6-address'):
- mapping['ipv6_address'] = conf.return_value('ipv6-address')
+ if conf.exists(['ipv6-address']):
+ mapping['ipv6_address'] = conf.return_value(['ipv6-address'])
# This option specifies the client’s DUID identifier. DUIDs are similar but different from DHCPv4 client identifiers
- if conf.exists('identifier'):
- mapping['client_identifier'] = conf.return_value('identifier')
+ if conf.exists(['identifier']):
+ mapping['client_identifier'] = conf.return_value(['identifier'])
# append static mapping configuration tu subnet list
subnet['static_mapping'].append(mapping)
@@ -209,10 +208,13 @@ def get_config():
# append subnet configuration to shared network subnet list
config['subnet'].append(subnet)
-
# append shared network configuration to config dictionary
dhcpv6['shared_network'].append(config)
+ # If all shared-networks are disabled, there's nothing to do.
+ if all(net['disabled'] for net in dhcpv6['shared_network']):
+ return None
+
return dhcpv6
def verify(dhcpv6):
@@ -302,22 +304,22 @@ def verify(dhcpv6):
else:
subnets.append(subnet['network'])
- # DHCPv6 requires at least one configured address range or one static mapping
- # (FIXME: is not actually checked right now?)
+ # DHCPv6 requires at least one configured address range or one static mapping
+ # (FIXME: is not actually checked right now?)
- # There must be one subnet connected to a listen interface if network is not disabled.
- if not network['disabled']:
- if is_subnet_connected(subnet['network']):
- listen_ok = True
+ # There must be one subnet connected to a listen interface if network is not disabled.
+ if not network['disabled']:
+ if is_subnet_connected(subnet['network']):
+ listen_ok = True
- # DHCPv6 subnet must not overlap. ISC DHCP also complains about overlapping
- # subnets: "Warning: subnet 2001:db8::/32 overlaps subnet 2001:db8:1::/32"
- net = ipaddress.ip_network(subnet['network'])
- for n in subnets:
- net2 = ipaddress.ip_network(n)
- if (net != net2):
- if net.overlaps(net2):
- raise ConfigError('DHCPv6 conflicting subnet ranges: {0} overlaps {1}'.format(net, net2))
+ # DHCPv6 subnet must not overlap. ISC DHCP also complains about overlapping
+ # subnets: "Warning: subnet 2001:db8::/32 overlaps subnet 2001:db8:1::/32"
+ net = ipaddress.ip_network(subnet['network'])
+ for n in subnets:
+ net2 = ipaddress.ip_network(n)
+ if (net != net2):
+ if net.overlaps(net2):
+ raise ConfigError('DHCPv6 conflicting subnet ranges: {0} overlaps {1}'.format(net, net2))
if not listen_ok:
raise ConfigError('None of the DHCPv6 subnets are connected to a subnet6 on\n' \
@@ -331,11 +333,6 @@ def generate(dhcpv6):
if not dhcpv6 or dhcpv6['disabled']:
return None
- # Create configuration directory on demand
- dirname = os.path.dirname(config_file)
- if not os.path.isdir(dirname):
- os.mkdir(dirname)
-
render(config_file, 'dhcpv6-server/dhcpdv6.conf.tmpl', dhcpv6)
return None
@@ -346,6 +343,7 @@ def apply(dhcpv6):
if os.path.exists(config_file):
os.unlink(config_file)
+ else:
call('systemctl restart isc-dhcp-server6.service')
return None