diff options
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | interface-definitions/ntp.xml | 67 | ||||
-rwxr-xr-x | src/conf-mode/vyos-config-ntp.py | 130 |
3 files changed, 202 insertions, 1 deletions
@@ -13,9 +13,13 @@ interface_definitions: rm -f $(TMPL_DIR)/service/dns/node.def rm -f $(TMPL_DIR)/protocols/node.def - # Workaround for special nodes that should not have "type: txt" + # Workaround for T604: vyos-1x: node.def generation always contains "type: txt" sed -i '/^type: txt/d' $(TMPL_DIR)/service/dns/forwarding/ignore-hosts-file/node.def sed -i '/^type: txt/d' $(TMPL_DIR)/service/dns/forwarding/system/node.def + sed -i '/^type: txt/d' $(TMPL_DIR)/system/ntp/server/node.tag/dynamic/node.def + sed -i '/^type: txt/d' $(TMPL_DIR)/system/ntp/server/node.tag/noselect/node.def + sed -i '/^type: txt/d' $(TMPL_DIR)/system/ntp/server/node.tag/preempt/node.def + sed -i '/^type: txt/d' $(TMPL_DIR)/system/ntp/server/node.tag/prefer/node.def .PHONY: all all: interface_definitions diff --git a/interface-definitions/ntp.xml b/interface-definitions/ntp.xml new file mode 100644 index 000000000..c756da611 --- /dev/null +++ b/interface-definitions/ntp.xml @@ -0,0 +1,67 @@ +<?xml version="1.0"?> + +<!-- NTP configuration --> + +<interfaceDefinition> + <node name="system"> + <children> + <node name="ntp" owner="${vyos_sbindir}/vyos-config-ntp.py"> + <properties> + <help>Network Time Protocol (NTP) configuration</help> + <priority>400</priority> + </properties> + <children> + <tagNode name="server"> + <properties> + <help>Network Time Protocol (NTP) server</help> + </properties> + <children> + <leafNode name="dynamic"> + <properties> + <help>Allow server to be configured even if not reachable</help> + </properties> + </leafNode> + <leafNode name="noselect"> + <properties> + <help>Marks the server as unused</help> + </properties> + </leafNode> + <leafNode name="preempt"> + <properties> + <help>Specifies the association as preemptable rather than the default persistent</help> + </properties> + </leafNode> + <leafNode name="prefer"> + <properties> + <help>Marks the server as preferred</help> + </properties> + </leafNode> + </children> + </tagNode> + <node name="allow-clients"> + <properties> + <help>Network Time Protocol (NTP) server options</help> + </properties> + <children> + <leafNode name="address"> + <properties> + <help>IP address</help> + <valueHelp> + <format>ipv4net</format> + <description>IP address and prefix length</description> + </valueHelp> + <valueHelp> + <format>ipv6net</format> + <description>IPv6 address and prefix length</description> + </valueHelp> + <multi/> + <type>ipv4net,ipv6net</type> + </properties> + </leafNode> + </children> + </node> + </children> + </node> + </children> + </node> +</interfaceDefinition> diff --git a/src/conf-mode/vyos-config-ntp.py b/src/conf-mode/vyos-config-ntp.py new file mode 100755 index 000000000..8d2ca99ba --- /dev/null +++ b/src/conf-mode/vyos-config-ntp.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2018 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# + +import sys +import os +import time +import socket +import ipaddress + +from vyos.config import Config +from vyos.util import ConfigError + +config_file = r'/etc/ntp.conf' + +def get_config(): + ntp = {} + conf = Config() + conf.set_level('system ntp') + if not conf.exists(''): + return ntp + + if conf.exists('allow-clients address'): + ntp.setdefault('allow-networks', []) + networks = [] + networks = conf.return_values('allow-clients address') + for network in networks: + ntp['allow-networks'].append(network) + + if conf.exists('server'): + ntp.setdefault('servers', []) + for node in conf.list_nodes('server'): + server = { + "name": node, + "dynamic": False, + "noselect": False, + "preempt": False, + "prefer": False, + } + if conf.exists('server {0} dynamic'.format(node)): + server['dynamic'] = True + if conf.exists('server {0} noselect'.format(node)): + server['noselect'] = True + if conf.exists('server {0} preempt'.format(node)): + server['preempt'] = True + if conf.exists('server {0} prefer'.format(node)): + server['prefer'] = True + + ntp['servers'].append(server) + + return ntp + +def verify(ntp): + if 'allow-networks' in ntp.keys(): + for network in ntp['allow-networks']: + try: + addr = ipaddress.ip_network(network) + except ValueError: + raise ConfigError("{0} does not appear to be a valid IPv4 or IPv6 network, check host bits.".format(network)) + + return None + +def generate(ntp): + config_header = '### Autogenerated by vyos-config-ntp.py on {tm} ###\n'.format(tm=time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())) + + # write new configuration file + f = open(config_file, 'w') + f.write(config_header) + f.write('driftfile /var/lib/ntp/ntp.drift\n') + f.write('# By default, only allow ntpd to query time sources, ignore any\n') + f.write('# incoming requests.\n') + f.write('restrict default ignore\n') + f.write('\n') + f.write('# Local users have unrestricted access, allowing reconfiguration\n') + f.write('# via ntpdc\n') + f.write('restrict 127.0.0.1\n') + f.write('restrict -6 ::1\n') + f.write('\n') + + if 'servers' in ntp.keys(): + for server in ntp['servers']: + addr = socket.gethostbyname(server['name']) + opt = ['dynamic', 'noselect', 'preempt', 'prefer'] + f.write('# Server configuration {0}\n'.format(server['name'])) + f.write('server {0} iburst {1}\n'.format(addr, '{0}'.format(' '.join(str(o) for o in opt if server[o])))) + f.write('restrict {0} nomodify notrap nopeer noquery\n'.format(addr)) + f.write('\n') + + if 'allow-networks' in ntp.keys(): + for network in ntp['allow-networks']: + addr = ipaddress.ip_network(network) + f.write('# Client configuration: {0}\n'.format(network)) + f.write('restrict {0} mask {1} nomodify notrap nopeer\n'.format(addr.network_address, addr.netmask)) + f.write('\n') + + f.close() + return None + +def apply(ntp): + if len(ntp) == 0: + cmd = "sudo /usr/sbin/invoke-rc.d ntp stop" + else: + cmd = "sudo /usr/sbin/invoke-rc.d ntp force-reload" + + os.system(cmd) + return None + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + sys.exit(1) |