#!/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 . # # 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)