summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsrc/conf_mode/dns_forwarding.py64
-rwxr-xr-xsrc/conf_mode/host_name.py321
2 files changed, 210 insertions, 175 deletions
diff --git a/src/conf_mode/dns_forwarding.py b/src/conf_mode/dns_forwarding.py
index 135f6fec0..7559a0af6 100755
--- a/src/conf_mode/dns_forwarding.py
+++ b/src/conf_mode/dns_forwarding.py
@@ -19,12 +19,18 @@
import sys
import os
-import netifaces
+import argparse
import jinja2
+import netifaces
from vyos.config import Config
from vyos import ConfigError
+
+parser = argparse.ArgumentParser()
+parser.add_argument("--dhclient", action="store_true",
+ help="Started from dhclient-script")
+
config_file = r'/etc/powerdns/recursor.conf'
# XXX: pdns recursor doesn't like whitespace near entry separators,
@@ -84,31 +90,36 @@ default_config_data = {
'name_servers': [],
'negative_ttl': 3600,
'domains': [],
- 'dnssec' : 'process-no-validate'
+ 'dnssec': 'process-no-validate'
}
# borrowed from: https://github.com/donjajo/py-world/blob/master/resolvconfReader.py, THX!
def get_resolvers(file):
- resolvers = []
try:
with open(file, 'r') as resolvconf:
- for line in resolvconf.readlines():
- line = line.split('#',1)[0];
- line = line.rstrip();
- if 'nameserver' in line:
- resolvers.append(line.split()[1])
+ lines = [line.split('#', 1)[0].rstrip()
+ for line in resolvconf.readlines()]
+ resolvers = [line.split()[1]
+ for line in lines if 'nameserver' in line]
return resolvers
except IOError:
return []
-def get_config():
+
+def get_config(arguments):
dns = default_config_data
conf = Config()
+
+ if arguments.dhclient:
+ conf.exists = conf.exists_effective
+ conf.return_value = conf.return_effective_value
+ conf.return_values = conf.return_effective_values
+
if not conf.exists('service dns forwarding'):
return None
- else:
- conf.set_level('service dns forwarding')
+
+ conf.set_level('service dns forwarding')
if conf.exists('cache-size'):
cache_size = conf.return_value('cache-size')
@@ -139,7 +150,8 @@ def get_config():
system_name_servers = []
system_name_servers = conf.return_values('name-server')
if not system_name_servers:
- print("DNS forwarding warning: No name-servers set under 'system name-server'\n")
+ print(
+ "DNS forwarding warning: No name-servers set under 'system name-server'\n")
else:
dns['name_servers'] = dns['name_servers'] + system_name_servers
conf.set_level('service dns forwarding')
@@ -171,9 +183,10 @@ def get_config():
try:
addrs = netifaces.ifaddresses(interface)
except ValueError:
- print("WARNING: interface {0} does not exist".format(interface))
+ print(
+ "WARNING: interface {0} does not exist".format(interface))
continue
-
+
if netifaces.AF_INET in addrs.keys():
for ip4 in addrs[netifaces.AF_INET]:
listen4.append(ip4['addr'])
@@ -183,7 +196,8 @@ def get_config():
listen6.append(ip6['addr'])
if (not listen4) and (not (listen6)):
- print("WARNING: interface {0} has no configured addresses".format(interface))
+ print(
+ "WARNING: interface {0} has no configured addresses".format(interface))
dns['listen_on'] = dns['listen_on'] + listen4 + listen6
@@ -195,31 +209,37 @@ def get_config():
interfaces = []
interfaces = conf.return_values('dhcp')
for interface in interfaces:
- dhcp_resolvers = get_resolvers("/etc/resolv.conf.dhclient-new-{0}".format(interface))
+ dhcp_resolvers = get_resolvers(
+ "/etc/resolv.conf.dhclient-new-{0}".format(interface))
if dhcp_resolvers:
dns['name_servers'] = dns['name_servers'] + dhcp_resolvers
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(dns):
# bail out early - looks like removal from running config
if dns is None:
return None
if not dns['listen_on']:
- raise ConfigError("Error: DNS forwarding requires either a listen-address (preferred) or a listen-on option")
+ raise ConfigError(
+ "Error: DNS forwarding requires either a listen-address (preferred) or a listen-on option")
if dns['domains']:
for domain in dns['domains']:
if not domain['servers']:
- raise ConfigError('Error: No server configured for domain {0}'.format(domain['name']))
+ raise ConfigError(
+ 'Error: No server configured for domain {0}'.format(domain['name']))
return None
+
def generate(dns):
# bail out early - looks like removal from running config
if dns is None:
@@ -232,19 +252,21 @@ def generate(dns):
f.write(config_text)
return None
+
def apply(dns):
if dns is not None:
os.system("systemctl restart pdns-recursor")
else:
# DNS forwarding is removed in the commit
os.system("systemctl stop pdns-recursor")
- os.unlink(config_file)
+ if os.path.isfile(config_file):
+ os.unlink(config_file)
- return None
if __name__ == '__main__':
+ args = parser.parse_args()
try:
- c = get_config()
+ c = get_config(args)
verify(c)
generate(c)
apply(c)
diff --git a/src/conf_mode/host_name.py b/src/conf_mode/host_name.py
index 81a52e87f..621ccd7e0 100755
--- a/src/conf_mode/host_name.py
+++ b/src/conf_mode/host_name.py
@@ -23,14 +23,19 @@ conf-mode script for 'system host-name' and 'system domain-name'.
import os
import re
import sys
-import subprocess
import copy
-import jinja2
import glob
+import argparse
+import jinja2
from vyos.config import Config
from vyos import ConfigError
+
+parser = argparse.ArgumentParser()
+parser.add_argument("--dhclient", action="store_true",
+ help="Started from dhclient-script")
+
config_file_hosts = '/etc/hosts'
config_file_resolv = '/etc/resolv.conf'
@@ -72,32 +77,6 @@ search {{ domain_search | join(" ") }}
"""
-# borrowed from: https://github.com/donjajo/py-world/blob/master/resolvconfReader.py, THX!
-def get_resolvers(file):
- resolvers = []
- try:
- with open(file, 'r') as resolvconf:
- for line in resolvconf.readlines():
- line = line.split('#',1)[0];
- line = line.rstrip();
- if 'nameserver' in line:
- resolvers.append(line.split()[1])
- return resolvers
- except IOError:
- return []
-
-def get_dhcp_search_doms(file):
- search_doms = []
- try:
- with open(file, 'r') as resolvconf:
- for line in resolvconf.readlines():
- line = line.split('#',1)[0];
- line = line.rstrip();
- if 'search' in line:
- return re.sub('^search','',line).lstrip().split()
- except IOError:
- return []
-
default_config_data = {
'hostname': 'vyos',
'domain_name': '',
@@ -106,158 +85,192 @@ default_config_data = {
'no_dhcp_ns': False
}
-def get_config():
- conf = Config()
- hosts = copy.deepcopy(default_config_data)
+# borrowed from: https://github.com/donjajo/py-world/blob/master/resolvconfReader.py, THX!
+def get_resolvers(file):
+ resolv = {}
+ try:
+ with open(file, 'r') as resolvconf:
+ lines = [line.split('#', 1)[0].rstrip()
+ for line in resolvconf.readlines()]
+ resolvers = [line.split()[1]
+ for line in lines if 'nameserver' in line]
+ domains = [line.split()[1] for line in lines if 'search' in line]
+ resolv['resolvers'] = resolvers
+ resolv['domains'] = domains
+ return resolv
+ except IOError:
+ return []
- if conf.exists("system host-name"):
- hosts['hostname'] = conf.return_value("system host-name")
- if conf.exists("system domain-name"):
- hosts['domain_name'] = conf.return_value("system domain-name")
- hosts['domain_search'].append(hosts['domain_name'])
+def get_config(arguments):
+ conf = Config()
+ hosts = copy.deepcopy(default_config_data)
- for search in conf.return_values("system domain-search domain"):
- hosts['domain_search'].append(search)
+ if arguments.dhclient:
+ conf.exists = conf.exists_effective
+ conf.return_value = conf.return_effective_value
+ conf.return_values = conf.return_effective_values
- if conf.exists("system name-server"):
- hosts['nameserver'] = conf.return_values("system name-server")
+ if conf.exists("system host-name"):
+ hosts['hostname'] = conf.return_value("system host-name")
- if conf.exists("system disable-dhcp-nameservers"):
- hosts['no_dhcp_ns'] = conf.exists('system disable-dhcp-nameservers')
+ if conf.exists("system domain-name"):
+ hosts['domain_name'] = conf.return_value("system domain-name")
+ hosts['domain_search'].append(hosts['domain_name'])
- ## system static-host-mapping
- hosts['static_host_mapping'] = { 'hostnames' : {}}
+ for search in conf.return_values("system domain-search domain"):
+ hosts['domain_search'].append(search)
- if conf.exists('system static-host-mapping host-name'):
- for hn in conf.list_nodes('system static-host-mapping host-name'):
- hosts['static_host_mapping']['hostnames'][hn] = {
- 'ipaddr' : conf.return_value('system static-host-mapping host-name ' + hn + ' inet'),
- 'alias' : ''
- }
-
- if conf.exists('system static-host-mapping host-name ' + hn + ' alias'):
- a = conf.return_values('system static-host-mapping host-name ' + hn + ' alias')
- hosts['static_host_mapping']['hostnames'][hn]['alias'] = " ".join( conf.return_values('system static-host-mapping host-name ' + hn + ' alias') )
+ if conf.exists("system name-server"):
+ hosts['nameserver'] = conf.return_values("system name-server")
- return hosts
+ if conf.exists("system disable-dhcp-nameservers"):
+ hosts['no_dhcp_ns'] = conf.exists('system disable-dhcp-nameservers')
-def verify(config):
- if config is None:
- return None
+ # system static-host-mapping
+ hosts['static_host_mapping'] = {'hostnames': {}}
- # pattern $VAR(@) "^[[:alnum:]][-.[:alnum:]]*[[:alnum:]]$" ; "invalid host name $VAR(@)"
- hostname_regex = re.compile("^[A-Za-z0-9][-.A-Za-z0-9]*[A-Za-z0-9]$")
- if not hostname_regex.match(config['hostname']):
- raise ConfigError('Invalid host name ' + config["hostname"])
+ if conf.exists('system static-host-mapping host-name'):
+ for hn in conf.list_nodes('system static-host-mapping host-name'):
+ hosts['static_host_mapping']['hostnames'][hn] = {
+ 'ipaddr': conf.return_value('system static-host-mapping host-name ' + hn + ' inet'),
+ 'alias': ''
+ }
- # pattern $VAR(@) "^.{1,63}$" ; "invalid host-name length"
- length = len(config['hostname'])
- if length < 1 or length > 63:
- raise ConfigError('Invalid host-name length, must be less than 63 characters')
+ if conf.exists('system static-host-mapping host-name ' + hn + ' alias'):
+ a = conf.return_values(
+ 'system static-host-mapping host-name ' + hn + ' alias')
+ hosts['static_host_mapping']['hostnames'][hn]['alias'] = " ".join(a)
- # The search list is currently limited to six domains with a total of 256 characters.
- # https://linux.die.net/man/5/resolv.conf
- if len(config['domain_search']) > 6:
- raise ConfigError('The search list is currently limited to six domains')
+ return hosts
- tmp = ' '.join(config['domain_search'])
- if len(tmp) > 256:
- raise ConfigError('The search list is currently limited to 256 characters')
- # static mappings alias hostname
- if config['static_host_mapping']['hostnames']:
- for hn in config['static_host_mapping']['hostnames']:
- if not config['static_host_mapping']['hostnames'][hn]['ipaddr']:
- raise ConfigError('IP address required for ' + hn)
- for hn_alias in config['static_host_mapping']['hostnames'][hn]['alias'].split(' '):
- if not hostname_regex.match(hn_alias) and len (hn_alias) !=0:
- raise ConfigError('Invalid hostname alias ' + hn_alias)
+def verify(config):
+ if config is None:
+ return None
+
+ # pattern $VAR(@) "^[[:alnum:]][-.[:alnum:]]*[[:alnum:]]$" ; "invalid host name $VAR(@)"
+ hostname_regex = re.compile("^[A-Za-z0-9][-.A-Za-z0-9]*[A-Za-z0-9]$")
+ if not hostname_regex.match(config['hostname']):
+ raise ConfigError('Invalid host name ' + config["hostname"])
+
+ # pattern $VAR(@) "^.{1,63}$" ; "invalid host-name length"
+ length = len(config['hostname'])
+ if length < 1 or length > 63:
+ raise ConfigError(
+ 'Invalid host-name length, must be less than 63 characters')
+
+ # The search list is currently limited to six domains with a total of 256 characters.
+ # https://linux.die.net/man/5/resolv.conf
+ if len(config['domain_search']) > 6:
+ raise ConfigError(
+ 'The search list is currently limited to six domains')
+
+ tmp = ' '.join(config['domain_search'])
+ if len(tmp) > 256:
+ raise ConfigError(
+ 'The search list is currently limited to 256 characters')
+
+ # static mappings alias hostname
+ if config['static_host_mapping']['hostnames']:
+ for hn in config['static_host_mapping']['hostnames']:
+ if not config['static_host_mapping']['hostnames'][hn]['ipaddr']:
+ raise ConfigError('IP address required for ' + hn)
+ for hn_alias in config['static_host_mapping']['hostnames'][hn]['alias'].split(' '):
+ if not hostname_regex.match(hn_alias) and len(hn_alias) != 0:
+ raise ConfigError('Invalid hostname alias ' + hn_alias)
+
+ return None
- return None
def generate(config):
- if config is None:
+ if config is None:
+ return None
+
+ # If "system disable-dhcp-nameservers" is __configured__ all DNS resolvers
+ # received via dhclient should not be added into the final 'resolv.conf'.
+ #
+ # We iterate over every resolver file and retrieve the received nameservers
+ # for later adjustment of the system nameservers
+ dhcp_ns = []
+ dhcp_sd = []
+ for file in glob.glob('/etc/resolv.conf.dhclient-new*'):
+ for key, value in get_resolvers(file).items():
+ ns = [r for r in value if key == 'resolvers']
+ dhcp_ns.extend(ns)
+ sd = [d for d in value if key == 'domains']
+ dhcp_sd.extend(sd)
+
+ if not config['no_dhcp_ns']:
+ config['nameserver'] += dhcp_ns
+ config['domain_search'] += dhcp_sd
+
+ # We have third party scripts altering /etc/hosts, too.
+ # One example are the DHCP hostname update scripts thus we need to cache in
+ # every modification first - so changing domain-name, domain-search or hostname
+ # during runtime works
+ old_hosts = ""
+ with open(config_file_hosts, 'r') as f:
+ # Skips text before the beginning of our marker.
+ # NOTE: Marker __MUST__ match the one specified in config_tmpl_hosts
+ for line in f:
+ if line.strip() == '### modifications from other scripts should be added below':
+ break
+
+ for line in f:
+ # This additional line.strip() filters empty lines
+ if line.strip():
+ old_hosts += line
+
+ # Add an additional newline
+ old_hosts += '\n'
+
+ tmpl = jinja2.Template(config_tmpl_hosts)
+ config_text = tmpl.render(config)
+
+ with open(config_file_hosts, 'w') as f:
+ f.write(config_text)
+ f.write(old_hosts)
+
+ tmpl = jinja2.Template(config_tmpl_resolv)
+ config_text = tmpl.render(config)
+ with open(config_file_resolv, 'w') as f:
+ f.write(config_text)
+
return None
- # If "system disable-dhcp-nameservers" is __configured__ all DNS resolvers
- # received via dhclient should not be added into the final 'resolv.conf'.
- #
- # We iterate over every resolver file and retrieve the received nameservers
- # for later adjustment of the system nameservers
- dhcp_ns = []
- for file in glob.glob('/etc/resolv.conf.dhclient-new*'):
- for r in get_resolvers(file):
- dhcp_ns.append(r)
-
- if not config['no_dhcp_ns']:
- config['nameserver'] += dhcp_ns
- for file in glob.glob('/etc/resolv.conf.dhclient-new*'):
- config['domain_search'] = get_dhcp_search_doms(file)
-
- # We have third party scripts altering /etc/hosts, too.
- # One example are the DHCP hostname update scripts thus we need to cache in
- # every modification first - so changing domain-name, domain-search or hostname
- # during runtime works
- old_hosts = ""
- with open(config_file_hosts, 'r') as f:
- # Skips text before the beginning of our marker.
- # NOTE: Marker __MUST__ match the one specified in config_tmpl_hosts
- for line in f:
- if line.strip() == '### modifications from other scripts should be added below':
- break
-
- for line in f:
- # This additional line.strip() filters empty lines
- if line.strip():
- old_hosts += line
-
- # Add an additional newline
- old_hosts += '\n'
-
- tmpl = jinja2.Template(config_tmpl_hosts)
- config_text = tmpl.render(config)
-
- with open(config_file_hosts, 'w') as f:
- f.write(config_text)
- f.write(old_hosts)
-
- tmpl = jinja2.Template(config_tmpl_resolv)
- config_text = tmpl.render(config)
- with open(config_file_resolv, 'w') as f:
- f.write(config_text)
-
- return None
def apply(config):
- if config is None:
- return None
+ if config is None:
+ return None
- fqdn = config['hostname']
- if config['domain_name']:
- fqdn += '.' + config['domain_name']
+ fqdn = config['hostname']
+ if config['domain_name']:
+ fqdn += '.' + config['domain_name']
- os.system("hostnamectl set-hostname --static {0}".format(fqdn.rstrip('.')))
+ os.system("hostnamectl set-hostname --static {0}".format(fqdn.rstrip('.')))
- # Restart services that use the hostname
- os.system("systemctl restart rsyslog.service")
+ # Restart services that use the hostname
+ os.system("systemctl restart rsyslog.service")
- # If SNMP is running, restart it too
- if os.system("pgrep snmpd > /dev/null") == 0:
- os.system("systemctl restart snmpd.service")
+ # If SNMP is running, restart it too
+ if os.system("pgrep snmpd > /dev/null") == 0:
+ os.system("systemctl restart snmpd.service")
- # restart pdns if it is used
- if os.system("/usr/bin/rec_control ping >/dev/null 2>&1") == 0:
- os.system("/etc/init.d/pdns-recursor restart >/dev/null")
+ # restart pdns if it is used
+ if os.system("/usr/bin/rec_control ping >/dev/null 2>&1") == 0:
+ os.system("/etc/init.d/pdns-recursor restart >/dev/null")
+
+ return None
- return None
if __name__ == '__main__':
- try:
- c = get_config()
- verify(c)
- generate(c)
- apply(c)
- except ConfigError as e:
- print(e)
- sys.exit(1)
+ args = parser.parse_args()
+ try:
+ c = get_config(args)
+ verify(c)
+ generate(c)
+ apply(c)
+ except ConfigError as e:
+ print(e)
+ sys.exit(1)