import chrony-3.5-1.el8
This commit is contained in:
		
						commit
						ceebba24d5
					
				
							
								
								
									
										2
									
								
								.chrony.metadata
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.chrony.metadata
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | 79e9aeace143550300387a99f17bff04b45673f7 SOURCES/chrony-3.5.tar.gz | ||||||
|  | 84d41ec6da2317dab5e41d9b73ec028c78325700 SOURCES/clknetsim-3f5ef9.tar.gz | ||||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | SOURCES/chrony-3.5.tar.gz | ||||||
|  | SOURCES/clknetsim-3f5ef9.tar.gz | ||||||
							
								
								
									
										8
									
								
								SOURCES/chrony-dnssrv@.service
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								SOURCES/chrony-dnssrv@.service
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | [Unit] | ||||||
|  | Description=DNS SRV lookup of %I for chrony | ||||||
|  | After=chronyd.service network-online.target | ||||||
|  | Wants=network-online.target | ||||||
|  | 
 | ||||||
|  | [Service] | ||||||
|  | Type=oneshot | ||||||
|  | ExecStart=/usr/libexec/chrony-helper update-dnssrv-servers %I | ||||||
							
								
								
									
										9
									
								
								SOURCES/chrony-dnssrv@.timer
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								SOURCES/chrony-dnssrv@.timer
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | [Unit] | ||||||
|  | Description=Periodic DNS SRV lookup of %I for chrony | ||||||
|  | 
 | ||||||
|  | [Timer] | ||||||
|  | OnActiveSec=0 | ||||||
|  | OnUnitInactiveSec=1h | ||||||
|  | 
 | ||||||
|  | [Install] | ||||||
|  | WantedBy=timers.target | ||||||
							
								
								
									
										11
									
								
								SOURCES/chrony-service-helper.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								SOURCES/chrony-service-helper.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | diff -up chrony-3.5/examples/chronyd.service.service-helper chrony-3.5/examples/chronyd.service
 | ||||||
|  | --- chrony-3.5/examples/chronyd.service.service-helper	2019-05-10 12:22:57.000000000 +0200
 | ||||||
|  | +++ chrony-3.5/examples/chronyd.service	2019-05-14 13:42:38.069516800 +0200
 | ||||||
|  | @@ -10,6 +10,7 @@ Type=forking
 | ||||||
|  |  PIDFile=/run/chrony/chronyd.pid | ||||||
|  |  EnvironmentFile=-/etc/sysconfig/chronyd | ||||||
|  |  ExecStart=/usr/sbin/chronyd $OPTIONS | ||||||
|  | +ExecStartPost=/usr/libexec/chrony-helper update-daemon
 | ||||||
|  |  PrivateTmp=yes | ||||||
|  |  ProtectHome=yes | ||||||
|  |  ProtectSystem=full | ||||||
							
								
								
									
										20
									
								
								SOURCES/chrony.dhclient
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								SOURCES/chrony.dhclient
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | #!/bin/bash | ||||||
|  | 
 | ||||||
|  | SERVERFILE=$SAVEDIR/chrony.servers.$interface | ||||||
|  | 
 | ||||||
|  | chrony_config() { | ||||||
|  | 	rm -f "$SERVERFILE" | ||||||
|  | 	if [ "$PEERNTP" != "no" ]; then | ||||||
|  | 		for server in $new_ntp_servers; do | ||||||
|  | 			echo "$server ${NTPSERVERARGS:-iburst}" >> "$SERVERFILE" | ||||||
|  | 		done | ||||||
|  | 		/usr/libexec/chrony-helper update-daemon || : | ||||||
|  | 	fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | chrony_restore() { | ||||||
|  | 	if [ -f "$SERVERFILE" ]; then | ||||||
|  | 		rm -f "$SERVERFILE" | ||||||
|  | 		/usr/libexec/chrony-helper update-daemon || : | ||||||
|  | 	fi | ||||||
|  | } | ||||||
							
								
								
									
										265
									
								
								SOURCES/chrony.helper
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								SOURCES/chrony.helper
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,265 @@ | |||||||
|  | #!/bin/bash | ||||||
|  | # This script configures running chronyd to use NTP servers obtained from | ||||||
|  | # DHCP and _ntp._udp DNS SRV records. Files with servers from DHCP are managed | ||||||
|  | # externally (e.g. by a dhclient script). Files with servers from DNS SRV | ||||||
|  | # records are updated here using the dig utility. The script can also list | ||||||
|  | # and set static sources in the chronyd configuration file. | ||||||
|  | 
 | ||||||
|  | chronyc=/usr/bin/chronyc | ||||||
|  | chrony_conf=/etc/chrony.conf | ||||||
|  | chrony_service=chronyd.service | ||||||
|  | helper_dir=/var/run/chrony-helper | ||||||
|  | added_servers_file=$helper_dir/added_servers | ||||||
|  | 
 | ||||||
|  | network_sysconfig_file=/etc/sysconfig/network | ||||||
|  | dhclient_servers_files="/var/lib/dhclient/chrony.servers.*" | ||||||
|  | dnssrv_servers_files="$helper_dir/dnssrv@*" | ||||||
|  | dnssrv_timer_prefix=chrony-dnssrv@ | ||||||
|  | 
 | ||||||
|  | . $network_sysconfig_file &> /dev/null | ||||||
|  | 
 | ||||||
|  | chrony_command() { | ||||||
|  |     $chronyc -a -n -m "$1" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | is_running() { | ||||||
|  |     chrony_command "tracking" &> /dev/null | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | get_servers_files() { | ||||||
|  |     [ "$PEERNTP" != "no" ] && echo "$dhclient_servers_files" | ||||||
|  |     echo "$dnssrv_servers_files" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | is_update_needed() { | ||||||
|  |     for file in $(get_servers_files) $added_servers_file; do | ||||||
|  |         [ -e "$file" ] && return 0 | ||||||
|  |     done | ||||||
|  |     return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | update_daemon() { | ||||||
|  |     local all_servers_with_args all_servers added_servers | ||||||
|  | 
 | ||||||
|  |     if ! is_running; then | ||||||
|  |         rm -f $added_servers_file | ||||||
|  |         return 0 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     all_servers_with_args=$(cat $(get_servers_files) 2> /dev/null) | ||||||
|  | 
 | ||||||
|  |     all_servers=$( | ||||||
|  |         echo "$all_servers_with_args" | | ||||||
|  |             while read -r server serverargs; do | ||||||
|  |                 echo "$server" | ||||||
|  |             done | sort -u) | ||||||
|  |     added_servers=$( ( | ||||||
|  |         cat $added_servers_file 2> /dev/null | ||||||
|  |         echo "$all_servers_with_args" | | ||||||
|  |             while read -r server serverargs; do | ||||||
|  |                 [ -z "$server" ] && continue | ||||||
|  |                 chrony_command "add server $server $serverargs" &> /dev/null && | ||||||
|  |                     echo "$server" | ||||||
|  |             done) | sort -u) | ||||||
|  | 
 | ||||||
|  |     comm -23 <(echo -n "$added_servers") <(echo -n "$all_servers") | | ||||||
|  |         while read -r server; do | ||||||
|  |             chrony_command "delete $server" &> /dev/null | ||||||
|  |         done | ||||||
|  | 
 | ||||||
|  |     added_servers=$(comm -12 <(echo -n "$added_servers") <(echo -n "$all_servers")) | ||||||
|  | 
 | ||||||
|  |     if [ -n "$added_servers" ]; then | ||||||
|  |         echo "$added_servers" > $added_servers_file | ||||||
|  |     else | ||||||
|  |         rm -f $added_servers_file | ||||||
|  |     fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | get_dnssrv_servers() { | ||||||
|  |     local name=$1 output | ||||||
|  | 
 | ||||||
|  |     if ! command -v dig &> /dev/null; then | ||||||
|  |         echo "Missing dig (DNS lookup utility)" >&2 | ||||||
|  |         return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     output=$(dig "$name" srv +short +ndots=2 +search 2> /dev/null) || return 0 | ||||||
|  | 
 | ||||||
|  |     echo "$output" | while read -r _ _ port target; do | ||||||
|  |         server=${target%.} | ||||||
|  |         [ -z "$server" ] && continue | ||||||
|  |         echo "$server port $port ${NTPSERVERARGS:-iburst}" | ||||||
|  |     done | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | check_dnssrv_name() { | ||||||
|  |     local name=$1 | ||||||
|  | 
 | ||||||
|  |     if [ -z "$name" ]; then | ||||||
|  |         echo "No DNS SRV name specified" >&2 | ||||||
|  |         return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     if [ "${name:0:9}" != _ntp._udp ]; then | ||||||
|  |         echo "DNS SRV name $name doesn't start with _ntp._udp" >&2 | ||||||
|  |         return 1 | ||||||
|  |     fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | update_dnssrv_servers() { | ||||||
|  |     local name=$1 | ||||||
|  |     local srv_file=$helper_dir/dnssrv@$name servers | ||||||
|  | 
 | ||||||
|  |     check_dnssrv_name "$name" || return 1 | ||||||
|  | 
 | ||||||
|  |     servers=$(get_dnssrv_servers "$name") | ||||||
|  |     if [ -n "$servers" ]; then | ||||||
|  |         echo "$servers" > "$srv_file" | ||||||
|  |     else | ||||||
|  |         rm -f "$srv_file" | ||||||
|  |     fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | set_dnssrv_timer() { | ||||||
|  |     local state=$1 name=$2 | ||||||
|  |     local srv_file=$helper_dir/dnssrv@$name servers | ||||||
|  |     local timer | ||||||
|  | 
 | ||||||
|  |     timer=$dnssrv_timer_prefix$(systemd-escape "$name").timer || return 1 | ||||||
|  | 
 | ||||||
|  |     check_dnssrv_name "$name" || return 1 | ||||||
|  | 
 | ||||||
|  |     if [ "$state" = enable ]; then | ||||||
|  |         systemctl enable "$timer" | ||||||
|  |         systemctl start "$timer" | ||||||
|  |     elif [ "$state" = disable ]; then | ||||||
|  |         systemctl stop "$timer" | ||||||
|  |         systemctl disable "$timer" | ||||||
|  |         rm -f "$srv_file" | ||||||
|  |     fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | list_dnssrv_timers() { | ||||||
|  |     systemctl --all --full -t timer list-units | grep "^$dnssrv_timer_prefix" | \ | ||||||
|  |             sed "s|^$dnssrv_timer_prefix\(.*\)\.timer.*|\1|" | | ||||||
|  |         while read -r name; do | ||||||
|  |             systemd-escape --unescape "$name" | ||||||
|  |         done | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | prepare_helper_dir() { | ||||||
|  |     mkdir -p $helper_dir | ||||||
|  |     exec 100> $helper_dir/lock | ||||||
|  |     if ! flock -w 20 100; then | ||||||
|  |         echo "Failed to lock $helper_dir" >&2 | ||||||
|  |         return 1 | ||||||
|  |     fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | is_source_line() { | ||||||
|  |     local pattern="^[ \t]*(server|pool|peer|refclock)[ \t]+[^ \t]+" | ||||||
|  |     [[ "$1" =~ $pattern ]] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | list_static_sources() { | ||||||
|  |     while read -r line; do | ||||||
|  |         if is_source_line "$line"; then | ||||||
|  |             echo "$line" | ||||||
|  |         fi | ||||||
|  |     done < $chrony_conf | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | set_static_sources() { | ||||||
|  |     local new_config tmp_conf | ||||||
|  | 
 | ||||||
|  |     new_config=$( | ||||||
|  |         sources=$( | ||||||
|  |             while read -r line; do | ||||||
|  |                 is_source_line "$line" && echo "$line" | ||||||
|  |             done) | ||||||
|  | 
 | ||||||
|  |         while read -r line; do | ||||||
|  |             if ! is_source_line "$line"; then | ||||||
|  |                 echo "$line" | ||||||
|  |                 continue | ||||||
|  |             fi | ||||||
|  | 
 | ||||||
|  |             tmp_sources=$( | ||||||
|  |                 local removed=0 | ||||||
|  | 
 | ||||||
|  |                 echo "$sources" | while read -r line2; do | ||||||
|  |                     if [ "$removed" -ne 0 ] || [ "$line" != "$line2" ]; then | ||||||
|  |                         echo "$line2" | ||||||
|  |                     else | ||||||
|  |                         removed=1 | ||||||
|  |                     fi | ||||||
|  |                 done) | ||||||
|  | 
 | ||||||
|  |             [ "$sources" == "$tmp_sources" ] && continue | ||||||
|  |             sources=$tmp_sources | ||||||
|  |             echo "$line" | ||||||
|  |         done < $chrony_conf | ||||||
|  | 
 | ||||||
|  |         echo "$sources" | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     tmp_conf=${chrony_conf}.tmp | ||||||
|  | 
 | ||||||
|  |     cp -a $chrony_conf $tmp_conf && | ||||||
|  |         echo "$new_config" > $tmp_conf && | ||||||
|  |         mv $tmp_conf $chrony_conf || return 1 | ||||||
|  | 
 | ||||||
|  |     systemctl try-restart $chrony_service | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | print_help() { | ||||||
|  |     echo "Usage: $0 COMMAND" | ||||||
|  |     echo | ||||||
|  |     echo "Commands:" | ||||||
|  |     echo "	update-daemon" | ||||||
|  |     echo "	update-dnssrv-servers NAME" | ||||||
|  |     echo "	enable-dnssrv NAME" | ||||||
|  |     echo "	disable-dnssrv NAME" | ||||||
|  |     echo "	list-dnssrv" | ||||||
|  |     echo "	list-static-sources" | ||||||
|  |     echo "	set-static-sources < sources.list" | ||||||
|  |     echo "	is-running" | ||||||
|  |     echo "	command CHRONYC-COMMAND" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | case "$1" in | ||||||
|  |     update-daemon|add-dhclient-servers|remove-dhclient-servers) | ||||||
|  |         is_update_needed || exit 0 | ||||||
|  |         prepare_helper_dir && update_daemon | ||||||
|  |         ;; | ||||||
|  |     update-dnssrv-servers) | ||||||
|  |         prepare_helper_dir && update_dnssrv_servers "$2" && update_daemon | ||||||
|  |         ;; | ||||||
|  |     enable-dnssrv) | ||||||
|  |         set_dnssrv_timer enable "$2" | ||||||
|  |         ;; | ||||||
|  |     disable-dnssrv) | ||||||
|  |         set_dnssrv_timer disable "$2" && prepare_helper_dir && update_daemon | ||||||
|  |         ;; | ||||||
|  |     list-dnssrv) | ||||||
|  |         list_dnssrv_timers | ||||||
|  |         ;; | ||||||
|  |     list-static-sources) | ||||||
|  |         list_static_sources | ||||||
|  |         ;; | ||||||
|  |     set-static-sources) | ||||||
|  |         set_static_sources | ||||||
|  |         ;; | ||||||
|  |     is-running) | ||||||
|  |         is_running | ||||||
|  |         ;; | ||||||
|  |     command|forced-command) | ||||||
|  |         chrony_command "$2" | ||||||
|  |         ;; | ||||||
|  |     *) | ||||||
|  |         print_help | ||||||
|  |         exit 2 | ||||||
|  | esac | ||||||
|  | 
 | ||||||
|  | exit $? | ||||||
							
								
								
									
										671
									
								
								SOURCES/ntp2chrony.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										671
									
								
								SOURCES/ntp2chrony.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,671 @@ | |||||||
|  | #!/usr/bin/python | ||||||
|  | # | ||||||
|  | # Convert ntp configuration to chrony | ||||||
|  | # | ||||||
|  | # Copyright (C) 2018-2019  Miroslav Lichvar <mlichvar@redhat.com> | ||||||
|  | # | ||||||
|  | # Permission is hereby granted, free of charge, to any person obtaining | ||||||
|  | # a copy of this software and associated documentation files (the | ||||||
|  | # "Software"), to deal in the Software without restriction, including | ||||||
|  | # without limitation the rights to use, copy, modify, merge, publish, | ||||||
|  | # distribute, sublicense, and/or sell copies of the Software, and to | ||||||
|  | # permit persons to whom the Software is furnished to do so, subject to | ||||||
|  | # the following conditions: | ||||||
|  | # | ||||||
|  | # The above copyright notice and this permission notice shall be included | ||||||
|  | # in all copies or substantial portions of the Software. | ||||||
|  | # | ||||||
|  | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||||
|  | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||||
|  | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||||||
|  | # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||||||
|  | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||||||
|  | # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||||||
|  | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | import argparse | ||||||
|  | import ipaddress | ||||||
|  | import logging | ||||||
|  | import os | ||||||
|  | import os.path | ||||||
|  | import re | ||||||
|  | import subprocess | ||||||
|  | import sys | ||||||
|  | 
 | ||||||
|  | # python2 compatibility hacks | ||||||
|  | if sys.version_info[0] < 3: | ||||||
|  |     from io import open | ||||||
|  |     reload(sys) | ||||||
|  |     sys.setdefaultencoding("utf-8") | ||||||
|  | 
 | ||||||
|  | class NtpConfiguration(object): | ||||||
|  |     def __init__(self, root_dir, ntp_conf, step_tickers): | ||||||
|  |         self.root_dir = root_dir if root_dir != "/" else "" | ||||||
|  |         self.ntp_conf_path = ntp_conf | ||||||
|  |         self.step_tickers_path = step_tickers | ||||||
|  | 
 | ||||||
|  |         # Read and write files using an 8-bit transparent encoding | ||||||
|  |         self.file_encoding = "latin-1" | ||||||
|  |         self.enabled_services = set() | ||||||
|  |         self.step_tickers = [] | ||||||
|  |         self.time_sources = [] | ||||||
|  |         self.fudges = {} | ||||||
|  |         self.restrictions = { | ||||||
|  |                 # Built-in defaults | ||||||
|  |                 ipaddress.ip_network(u"0.0.0.0/0"): set(), | ||||||
|  |                 ipaddress.ip_network(u"::/0"): set(), | ||||||
|  |         } | ||||||
|  |         self.keyfile = "" | ||||||
|  |         self.keys = [] | ||||||
|  |         self.trusted_keys = [] | ||||||
|  |         self.driftfile = "" | ||||||
|  |         self.statistics = [] | ||||||
|  |         self.leapfile = "" | ||||||
|  |         self.tos_options = {} | ||||||
|  |         self.ignored_directives = set() | ||||||
|  |         self.ignored_lines = [] | ||||||
|  | 
 | ||||||
|  |         #self.detect_enabled_services() | ||||||
|  |         self.parse_step_tickers() | ||||||
|  |         self.parse_ntp_conf() | ||||||
|  | 
 | ||||||
|  |     def detect_enabled_services(self): | ||||||
|  |         for service in ["ntpdate", "ntpd", "ntp-wait"]: | ||||||
|  |             if os.path.islink("{}/etc/systemd/system/multi-user.target.wants/{}.service" | ||||||
|  |                     .format(self.root_dir, service)): | ||||||
|  |                 self.enabled_services.add(service) | ||||||
|  |         logging.info("Enabled services found in /etc/systemd/system: %s", | ||||||
|  |                      " ".join(self.enabled_services)) | ||||||
|  | 
 | ||||||
|  |     def parse_step_tickers(self): | ||||||
|  |         if not self.step_tickers_path: | ||||||
|  |             return | ||||||
|  | 
 | ||||||
|  |         path = os.path.join(self.root_dir, self.step_tickers_path) | ||||||
|  |         if not os.path.isfile(path): | ||||||
|  |             logging.info("Missing %s", path) | ||||||
|  |             return | ||||||
|  | 
 | ||||||
|  |         with open(path, encoding=self.file_encoding) as f: | ||||||
|  |             for line in f: | ||||||
|  |                 line = line[:line.find('#')] | ||||||
|  | 
 | ||||||
|  |                 words = line.split() | ||||||
|  | 
 | ||||||
|  |                 if not words: | ||||||
|  |                     continue | ||||||
|  | 
 | ||||||
|  |                 self.step_tickers.extend(words) | ||||||
|  | 
 | ||||||
|  |     def parse_ntp_conf(self, path=None): | ||||||
|  |         if path is None: | ||||||
|  |             path = os.path.join(self.root_dir, self.ntp_conf_path) | ||||||
|  | 
 | ||||||
|  |         with open(path, encoding=self.file_encoding) as f: | ||||||
|  |             logging.info("Reading %s", path) | ||||||
|  | 
 | ||||||
|  |             for line in f: | ||||||
|  |                 line = line[:line.find('#')] | ||||||
|  | 
 | ||||||
|  |                 words = line.split() | ||||||
|  | 
 | ||||||
|  |                 if not words: | ||||||
|  |                     continue | ||||||
|  | 
 | ||||||
|  |                 if not self.parse_directive(words): | ||||||
|  |                     self.ignored_lines.append(line) | ||||||
|  | 
 | ||||||
|  |     def parse_directive(self, words): | ||||||
|  |         name = words.pop(0) | ||||||
|  |         if name.startswith("logconfig"): | ||||||
|  |             name = "logconfig" | ||||||
|  | 
 | ||||||
|  |         if words: | ||||||
|  |             if name in ["server", "peer", "pool"]: | ||||||
|  |                 return self.parse_source(name, words) | ||||||
|  |             elif name == "fudge": | ||||||
|  |                 return self.parse_fudge(words) | ||||||
|  |             elif name == "restrict": | ||||||
|  |                 return self.parse_restrict(words) | ||||||
|  |             elif name == "tos": | ||||||
|  |                 return self.parse_tos(words) | ||||||
|  |             elif name == "includefile": | ||||||
|  |                 return self.parse_includefile(words) | ||||||
|  |             elif name == "keys": | ||||||
|  |                 return self.parse_keys(words) | ||||||
|  |             elif name == "trustedkey": | ||||||
|  |                 return self.parse_trustedkey(words) | ||||||
|  |             elif name == "driftfile": | ||||||
|  |                 self.driftfile = words[0] | ||||||
|  |             elif name == "statistics": | ||||||
|  |                 self.statistics = words | ||||||
|  |             elif name == "leapfile": | ||||||
|  |                 self.leapfile = words[0] | ||||||
|  |             else: | ||||||
|  |                 self.ignored_directives.add(name) | ||||||
|  |                 return False | ||||||
|  |         else: | ||||||
|  |             self.ignored_directives.add(name) | ||||||
|  |             return False | ||||||
|  | 
 | ||||||
|  |         return True | ||||||
|  | 
 | ||||||
|  |     def parse_source(self, source_type, words): | ||||||
|  |         ipv4_only = False | ||||||
|  |         ipv6_only = False | ||||||
|  |         source = { | ||||||
|  |                 "type": source_type, | ||||||
|  |                 "options": [] | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if words[0] == "-4": | ||||||
|  |             ipv4_only = True | ||||||
|  |             words.pop(0) | ||||||
|  |         elif words[0] == "-6": | ||||||
|  |             ipv6_only = True | ||||||
|  |             words.pop(0) | ||||||
|  | 
 | ||||||
|  |         if not words: | ||||||
|  |             return False | ||||||
|  | 
 | ||||||
|  |         source["address"] = words.pop(0) | ||||||
|  | 
 | ||||||
|  |         # Check if -4/-6 corresponds to the address and ignore hostnames | ||||||
|  |         if ipv4_only or ipv6_only: | ||||||
|  |             try: | ||||||
|  |                 version = ipaddress.ip_address(source["address"]).version | ||||||
|  |                 if (ipv4_only and version != 4) or (ipv6_only and version != 6): | ||||||
|  |                     return False | ||||||
|  |             except ValueError: | ||||||
|  |                 return False | ||||||
|  | 
 | ||||||
|  |         if source["address"].startswith("127.127."): | ||||||
|  |             if not source["address"].startswith("127.127.1."): | ||||||
|  |                 # Ignore non-LOCAL refclocks | ||||||
|  |                 return False | ||||||
|  | 
 | ||||||
|  |         while words: | ||||||
|  |             if len(words) >= 2 and words[0] in ["minpoll", "maxpoll", "version", "key"]: | ||||||
|  |                 source["options"].append((words[0], words[1])) | ||||||
|  |                 words = words[2:] | ||||||
|  |             elif words[0] in ["burst", "iburst", "noselect", "prefer", "true", "xleave"]: | ||||||
|  |                 source["options"].append((words[0],)) | ||||||
|  |                 words.pop(0) | ||||||
|  |             else: | ||||||
|  |                 return False | ||||||
|  | 
 | ||||||
|  |         self.time_sources.append(source) | ||||||
|  |         return True | ||||||
|  | 
 | ||||||
|  |     def parse_fudge(self, words): | ||||||
|  |         address = words.pop(0) | ||||||
|  |         options = {} | ||||||
|  | 
 | ||||||
|  |         while words: | ||||||
|  |             if len(words) >= 2 and words[0] in ["stratum"]: | ||||||
|  |                 if not words[1].isdigit(): | ||||||
|  |                     return False | ||||||
|  |                 options[words[0]] = int(words[1]) | ||||||
|  |                 words = words[2:] | ||||||
|  |             elif len(words) >= 2: | ||||||
|  |                 words = words[2:] | ||||||
|  |             else: | ||||||
|  |                 return False | ||||||
|  | 
 | ||||||
|  |         self.fudges[address] = options | ||||||
|  |         return True | ||||||
|  | 
 | ||||||
|  |     def parse_restrict(self, words): | ||||||
|  |         ipv4_only = False | ||||||
|  |         ipv6_only = False | ||||||
|  |         flags = set() | ||||||
|  |         mask = "" | ||||||
|  | 
 | ||||||
|  |         if words[0] == "-4": | ||||||
|  |             ipv4_only = True | ||||||
|  |             words.pop(0) | ||||||
|  |         elif words[0] == "-6": | ||||||
|  |             ipv6_only = True | ||||||
|  |             words.pop(0) | ||||||
|  | 
 | ||||||
|  |         if not words: | ||||||
|  |             return False | ||||||
|  | 
 | ||||||
|  |         address = words.pop(0) | ||||||
|  | 
 | ||||||
|  |         while words: | ||||||
|  |             if len(words) >= 2 and words[0] == "mask": | ||||||
|  |                 mask = words[1] | ||||||
|  |                 words = words[2:] | ||||||
|  |             else: | ||||||
|  |                 if words[0] not in ["kod", "nomodify", "notrap", "nopeer", "noquery", | ||||||
|  |                                     "limited", "ignore", "noserve"]: | ||||||
|  |                     return False | ||||||
|  |                 flags.add(words[0]) | ||||||
|  |                 words.pop(0) | ||||||
|  | 
 | ||||||
|  |         # Convert to IP network(s), ignoring restrictions with hostnames | ||||||
|  |         networks = [] | ||||||
|  |         if address == "default" and not mask: | ||||||
|  |             if not ipv6_only: | ||||||
|  |                 networks.append(ipaddress.ip_network(u"0.0.0.0/0")) | ||||||
|  |             if not ipv4_only: | ||||||
|  |                 networks.append(ipaddress.ip_network(u"::/0")) | ||||||
|  |         else: | ||||||
|  |             try: | ||||||
|  |                 if mask: | ||||||
|  |                     networks.append(ipaddress.ip_network(u"{}/{}".format(address, mask))) | ||||||
|  |                 else: | ||||||
|  |                     networks.append(ipaddress.ip_network(address)) | ||||||
|  |             except ValueError: | ||||||
|  |                 return False | ||||||
|  | 
 | ||||||
|  |             if (ipv4_only and networks[-1].version != 4) or \ | ||||||
|  |                     (ipv6_only and networks[-1].version != 6): | ||||||
|  |                 return False | ||||||
|  | 
 | ||||||
|  |         for network in networks: | ||||||
|  |             self.restrictions[network] = flags | ||||||
|  | 
 | ||||||
|  |         return True | ||||||
|  | 
 | ||||||
|  |     def parse_tos(self, words): | ||||||
|  |         options = {} | ||||||
|  |         while words: | ||||||
|  |             if len(words) >= 2 and words[0] in ["minsane", "orphan"]: | ||||||
|  |                 if not words[1].isdigit(): | ||||||
|  |                     return False | ||||||
|  |                 options[words[0]] = int(words[1]) | ||||||
|  |                 words = words[2:] | ||||||
|  |             elif len(words) >= 2 and words[0] in ["maxdist"]: | ||||||
|  |                 # Check if it is a float value | ||||||
|  |                 if not words[1].replace('.', '', 1).isdigit(): | ||||||
|  |                     return False | ||||||
|  |                 options[words[0]] = float(words[1]) | ||||||
|  |                 words = words[2:] | ||||||
|  |             else: | ||||||
|  |                 return False | ||||||
|  | 
 | ||||||
|  |         self.tos_options.update(options) | ||||||
|  | 
 | ||||||
|  |         return True | ||||||
|  | 
 | ||||||
|  |     def parse_includefile(self, words): | ||||||
|  |         path = os.path.join(self.root_dir, words[0]) | ||||||
|  |         if not os.path.isfile(path): | ||||||
|  |             return False | ||||||
|  | 
 | ||||||
|  |         self.parse_ntp_conf(path) | ||||||
|  |         return True | ||||||
|  | 
 | ||||||
|  |     def parse_keys(self, words): | ||||||
|  |         keyfile = words[0] | ||||||
|  |         path = os.path.join(self.root_dir, keyfile) | ||||||
|  |         if not os.path.isfile(path): | ||||||
|  |             logging.info("Missing %s", path) | ||||||
|  |             return False | ||||||
|  | 
 | ||||||
|  |         with open(path, encoding=self.file_encoding) as f: | ||||||
|  |             logging.info("Reading %s", path) | ||||||
|  |             keys = [] | ||||||
|  |             for line in f: | ||||||
|  |                 words = line.split() | ||||||
|  |                 if len(words) < 3 or not words[0].isdigit(): | ||||||
|  |                     continue | ||||||
|  |                 keys.append((int(words[0]), words[1], words[2])) | ||||||
|  | 
 | ||||||
|  |             self.keyfile = keyfile | ||||||
|  |             self.keys = keys | ||||||
|  | 
 | ||||||
|  |         return True | ||||||
|  | 
 | ||||||
|  |     def parse_trustedkey(self, words): | ||||||
|  |         key_ranges = [] | ||||||
|  |         for word in words: | ||||||
|  |             if word.isdigit(): | ||||||
|  |                 key_ranges.append((int(word), int(word))) | ||||||
|  |             elif re.match("^[0-9]+-[0-9]+$", word): | ||||||
|  |                 first, last = word.split("-") | ||||||
|  |                 key_ranges.append((int(first), int(last))) | ||||||
|  |             else: | ||||||
|  |                 return False | ||||||
|  | 
 | ||||||
|  |         self.trusted_keys = key_ranges | ||||||
|  |         return True | ||||||
|  | 
 | ||||||
|  |     def write_chrony_configuration(self, chrony_conf_path, chrony_keys_path, | ||||||
|  |                                    dry_run=False, backup=False): | ||||||
|  |         chrony_conf = self.get_chrony_conf(chrony_keys_path) | ||||||
|  |         logging.debug("Generated %s:\n%s", chrony_conf_path, chrony_conf) | ||||||
|  | 
 | ||||||
|  |         if not dry_run: | ||||||
|  |             self.write_file(chrony_conf_path, 0o644, chrony_conf, backup) | ||||||
|  | 
 | ||||||
|  |         chrony_keys = self.get_chrony_keys() | ||||||
|  |         if chrony_keys: | ||||||
|  |             logging.debug("Generated %s:\n%s", chrony_keys_path, chrony_keys) | ||||||
|  | 
 | ||||||
|  |         if not dry_run: | ||||||
|  |             self.write_file(chrony_keys_path, 0o640, chrony_keys, backup) | ||||||
|  | 
 | ||||||
|  |     def get_processed_time_sources(self): | ||||||
|  |         # Convert {0,1,2,3}.*pool.ntp.org servers to 2.*pool.ntp.org pools | ||||||
|  | 
 | ||||||
|  |         # Make shallow copies of all sources (only type will be modified) | ||||||
|  |         time_sources = [s.copy() for s in self.time_sources] | ||||||
|  | 
 | ||||||
|  |         pools = {} | ||||||
|  |         for source in time_sources: | ||||||
|  |             if source["type"] != "server": | ||||||
|  |                 continue | ||||||
|  |             m = re.match("^([0123])(\\.\\w+)?\\.pool\\.ntp\\.org$", source["address"]) | ||||||
|  |             if m is None: | ||||||
|  |                 continue | ||||||
|  |             number = m.group(1) | ||||||
|  |             zone = m.group(2) | ||||||
|  |             if zone not in pools: | ||||||
|  |                 pools[zone] = [] | ||||||
|  |             pools[zone].append((int(number), source)) | ||||||
|  | 
 | ||||||
|  |         remove_servers = set() | ||||||
|  |         for zone, pool in pools.items(): | ||||||
|  |             # sort and skip all pools not in [0, 3] range | ||||||
|  |             pool.sort() | ||||||
|  |             if [number for number, source in pool] != [0, 1, 2, 3]: | ||||||
|  |                 # only exact group of 4 servers can be converted, nothing to do here | ||||||
|  |                 continue | ||||||
|  |             # verify that parameters are the same for all servers in the pool | ||||||
|  |             if not all([p[1]["options"] == pool[0][1]["options"] for p in pool]): | ||||||
|  |                 break | ||||||
|  |             remove_servers.update([pool[i][1]["address"] for i in [0, 1, 3]]) | ||||||
|  |             pool[2][1]["type"] = "pool" | ||||||
|  | 
 | ||||||
|  |         processed_sources = [] | ||||||
|  |         for source in time_sources: | ||||||
|  |             if source["type"] == "server" and source["address"] in remove_servers: | ||||||
|  |                 continue | ||||||
|  |             processed_sources.append(source) | ||||||
|  |         return processed_sources | ||||||
|  | 
 | ||||||
|  |     def get_chrony_conf_sources(self): | ||||||
|  |         conf = "" | ||||||
|  | 
 | ||||||
|  |         if self.step_tickers: | ||||||
|  |             conf += "# Specify NTP servers used for initial correction.\n" | ||||||
|  |             conf += "initstepslew 0.1 {}\n".format(" ".join(self.step_tickers)) | ||||||
|  |             conf += "\n" | ||||||
|  | 
 | ||||||
|  |         conf += "# Specify time sources.\n" | ||||||
|  | 
 | ||||||
|  |         for source in self.get_processed_time_sources(): | ||||||
|  |             address = source["address"] | ||||||
|  |             if address.startswith("127.127."): | ||||||
|  |                 if address.startswith("127.127.1."): | ||||||
|  |                     continue | ||||||
|  |                 # No other refclocks are expected from the parser | ||||||
|  |                 assert False | ||||||
|  |             else: | ||||||
|  |                 conf += "{} {}".format(source["type"], address) | ||||||
|  |                 for option in source["options"]: | ||||||
|  |                     if option[0] in ["minpoll", "maxpoll", "version", "key", | ||||||
|  |                                      "iburst", "noselect", "prefer", "xleave"]: | ||||||
|  |                         conf += " {}".format(" ".join(option)) | ||||||
|  |                     elif option[0] == "burst": | ||||||
|  |                         conf += " presend 6" | ||||||
|  |                     elif option[0] == "true": | ||||||
|  |                         conf += " trust" | ||||||
|  |                     else: | ||||||
|  |                         # No other options are expected from the parser | ||||||
|  |                         assert False | ||||||
|  |                 conf += "\n" | ||||||
|  |         conf += "\n" | ||||||
|  | 
 | ||||||
|  |         return conf | ||||||
|  | 
 | ||||||
|  |     def get_chrony_conf_allows(self): | ||||||
|  |         allowed_networks = filter(lambda n: "ignore" not in self.restrictions[n] and | ||||||
|  |                                     "noserve" not in self.restrictions[n], | ||||||
|  |                                   self.restrictions.keys()) | ||||||
|  | 
 | ||||||
|  |         conf = "" | ||||||
|  |         for network in sorted(allowed_networks, key=lambda n: (n.version, n)): | ||||||
|  |             if network.num_addresses > 1: | ||||||
|  |                 conf += "allow {}\n".format(network) | ||||||
|  |             else: | ||||||
|  |                 conf += "allow {}\n".format(network.network_address) | ||||||
|  | 
 | ||||||
|  |         if conf: | ||||||
|  |             conf = "# Allow NTP client access.\n" + conf | ||||||
|  |             conf += "\n" | ||||||
|  | 
 | ||||||
|  |         return conf | ||||||
|  | 
 | ||||||
|  |     def get_chrony_conf_cmdallows(self): | ||||||
|  |         allowed_networks = filter(lambda n: "ignore" not in self.restrictions[n] and | ||||||
|  |                                     "noquery" not in self.restrictions[n] and | ||||||
|  |                                     n != ipaddress.ip_network(u"127.0.0.1/32") and | ||||||
|  |                                     n != ipaddress.ip_network(u"::1/128"), | ||||||
|  |                                   self.restrictions.keys()) | ||||||
|  | 
 | ||||||
|  |         ip_versions = set() | ||||||
|  |         conf = "" | ||||||
|  |         for network in sorted(allowed_networks, key=lambda n: (n.version, n)): | ||||||
|  |             ip_versions.add(network.version) | ||||||
|  |             if network.num_addresses > 1: | ||||||
|  |                 conf += "cmdallow {}\n".format(network) | ||||||
|  |             else: | ||||||
|  |                 conf += "cmdallow {}\n".format(network.network_address) | ||||||
|  | 
 | ||||||
|  |         if conf: | ||||||
|  |             conf = "# Allow remote monitoring.\n" + conf | ||||||
|  |             if 4 in ip_versions: | ||||||
|  |                 conf += "bindcmdaddress 0.0.0.0\n" | ||||||
|  |             if 6 in ip_versions: | ||||||
|  |                 conf += "bindcmdaddress ::\n" | ||||||
|  |             conf += "\n" | ||||||
|  | 
 | ||||||
|  |         return conf | ||||||
|  | 
 | ||||||
|  |     def get_chrony_conf(self, chrony_keys_path): | ||||||
|  |         local_stratum = 0 | ||||||
|  |         maxdistance = 0.0 | ||||||
|  |         minsources = 1 | ||||||
|  |         orphan_stratum = 0 | ||||||
|  |         logs = [] | ||||||
|  | 
 | ||||||
|  |         for source in self.time_sources: | ||||||
|  |             address = source["address"] | ||||||
|  |             if address.startswith("127.127.1."): | ||||||
|  |                 if address in self.fudges and "stratum" in self.fudges[address]: | ||||||
|  |                     local_stratum = self.fudges[address]["stratum"] | ||||||
|  |                 else: | ||||||
|  |                     local_stratum = 5 | ||||||
|  | 
 | ||||||
|  |         if "maxdist" in self.tos_options: | ||||||
|  |             maxdistance = self.tos_options["maxdist"] | ||||||
|  |         if "minsane" in self.tos_options: | ||||||
|  |             minsources = self.tos_options["minsane"] | ||||||
|  |         if "orphan" in self.tos_options: | ||||||
|  |             orphan_stratum = self.tos_options["orphan"] | ||||||
|  | 
 | ||||||
|  |         if "clockstats" in self.statistics: | ||||||
|  |             logs.append("refclocks"); | ||||||
|  |         if "loopstats" in self.statistics: | ||||||
|  |             logs.append("tracking") | ||||||
|  |         if "peerstats" in self.statistics: | ||||||
|  |             logs.append("statistics"); | ||||||
|  |         if "rawstats" in self.statistics: | ||||||
|  |             logs.append("measurements") | ||||||
|  | 
 | ||||||
|  |         conf = "# This file was converted from {}{}.\n".format( | ||||||
|  |                     self.ntp_conf_path, | ||||||
|  |                     " and " + self.step_tickers_path if self.step_tickers_path else "") | ||||||
|  |         conf += "\n" | ||||||
|  | 
 | ||||||
|  |         if self.ignored_lines: | ||||||
|  |             conf += "# The following directives were ignored in the conversion:\n" | ||||||
|  | 
 | ||||||
|  |             for line in self.ignored_lines: | ||||||
|  |                 # Remove sensitive information | ||||||
|  |                 line = re.sub(r"\s+pw\s+\S+", " pw XXX", line.rstrip()) | ||||||
|  |                 conf += "# " + line + "\n" | ||||||
|  |             conf += "\n" | ||||||
|  | 
 | ||||||
|  |         conf += self.get_chrony_conf_sources() | ||||||
|  | 
 | ||||||
|  |         conf += "# Record the rate at which the system clock gains/losses time.\n" | ||||||
|  |         if not self.driftfile: | ||||||
|  |             conf += "#" | ||||||
|  |         conf += "driftfile /var/lib/chrony/drift\n" | ||||||
|  |         conf += "\n" | ||||||
|  | 
 | ||||||
|  |         conf += "# Allow the system clock to be stepped in the first three updates\n" | ||||||
|  |         conf += "# if its offset is larger than 1 second.\n" | ||||||
|  |         conf += "makestep 1.0 3\n" | ||||||
|  |         conf += "\n" | ||||||
|  | 
 | ||||||
|  |         conf += "# Enable kernel synchronization of the real-time clock (RTC).\n" | ||||||
|  |         conf += "rtcsync\n" | ||||||
|  |         conf += "\n" | ||||||
|  | 
 | ||||||
|  |         conf += "# Enable hardware timestamping on all interfaces that support it.\n" | ||||||
|  |         conf += "#hwtimestamp *\n" | ||||||
|  |         conf += "\n" | ||||||
|  | 
 | ||||||
|  |         if maxdistance > 0.0: | ||||||
|  |             conf += "# Specify the maximum distance of sources to be selectable.\n" | ||||||
|  |             conf += "maxdistance {}\n".format(maxdistance) | ||||||
|  |             conf += "\n" | ||||||
|  | 
 | ||||||
|  |         conf += "# Increase the minimum number of selectable sources required to adjust\n" | ||||||
|  |         conf += "# the system clock.\n" | ||||||
|  |         if minsources > 1: | ||||||
|  |             conf += "minsources {}\n".format(minsources) | ||||||
|  |         else: | ||||||
|  |             conf += "#minsources 2\n" | ||||||
|  |         conf += "\n" | ||||||
|  | 
 | ||||||
|  |         conf += self.get_chrony_conf_allows() | ||||||
|  | 
 | ||||||
|  |         conf += self.get_chrony_conf_cmdallows() | ||||||
|  | 
 | ||||||
|  |         conf += "# Serve time even if not synchronized to a time source.\n" | ||||||
|  |         if orphan_stratum > 0 and orphan_stratum < 16: | ||||||
|  |             conf += "local stratum {} orphan\n".format(orphan_stratum) | ||||||
|  |         elif local_stratum > 0 and local_stratum < 16: | ||||||
|  |             conf += "local stratum {}\n".format(local_stratum) | ||||||
|  |         else: | ||||||
|  |             conf += "#local stratum 10\n" | ||||||
|  |         conf += "\n" | ||||||
|  | 
 | ||||||
|  |         conf += "# Specify file containing keys for NTP authentication.\n" | ||||||
|  |         conf += "keyfile {}\n".format(chrony_keys_path) | ||||||
|  |         conf += "\n" | ||||||
|  | 
 | ||||||
|  |         conf += "# Get TAI-UTC offset and leap seconds from the system tz database.\n" | ||||||
|  |         conf += "leapsectz right/UTC\n" | ||||||
|  |         conf += "\n" | ||||||
|  | 
 | ||||||
|  |         conf += "# Specify directory for log files.\n" | ||||||
|  |         conf += "logdir /var/log/chrony\n" | ||||||
|  |         conf += "\n" | ||||||
|  | 
 | ||||||
|  |         conf += "# Select which information is logged.\n" | ||||||
|  |         if logs: | ||||||
|  |             conf += "log {}\n".format(" ".join(logs)) | ||||||
|  |         else: | ||||||
|  |             conf += "#log measurements statistics tracking\n" | ||||||
|  | 
 | ||||||
|  |         return conf | ||||||
|  | 
 | ||||||
|  |     def get_chrony_keys(self): | ||||||
|  |         if not self.keyfile: | ||||||
|  |             return "" | ||||||
|  | 
 | ||||||
|  |         keys = "# This file was converted from {}.\n".format(self.keyfile) | ||||||
|  |         keys += "\n" | ||||||
|  | 
 | ||||||
|  |         for key in self.keys: | ||||||
|  |             key_id = key[0] | ||||||
|  |             key_type = key[1] | ||||||
|  |             password = key[2] | ||||||
|  | 
 | ||||||
|  |             if key_type in ["m", "M"]: | ||||||
|  |                 key_type = "MD5" | ||||||
|  |             elif key_type not in ["MD5", "SHA1", "SHA256", "SHA384", "SHA512"]: | ||||||
|  |                 continue | ||||||
|  | 
 | ||||||
|  |             prefix = "ASCII" if len(password) <= 20 else "HEX" | ||||||
|  | 
 | ||||||
|  |             for first, last in self.trusted_keys: | ||||||
|  |                 if first <= key_id <= last: | ||||||
|  |                     trusted = True | ||||||
|  |                     break | ||||||
|  |             else: | ||||||
|  |                 trusted = False | ||||||
|  | 
 | ||||||
|  |             # Disable keys that were not marked as trusted | ||||||
|  |             if not trusted: | ||||||
|  |                 keys += "#" | ||||||
|  | 
 | ||||||
|  |             keys += "{} {} {}:{}\n".format(key_id, key_type, prefix, password) | ||||||
|  | 
 | ||||||
|  |         return keys | ||||||
|  | 
 | ||||||
|  |     def write_file(self, path, mode, content, backup): | ||||||
|  |         path = self.root_dir + path | ||||||
|  |         if backup and os.path.isfile(path): | ||||||
|  |             os.rename(path, path + ".old") | ||||||
|  | 
 | ||||||
|  |         with open(os.open(path, os.O_CREAT | os.O_WRONLY | os.O_EXCL, mode), "w", | ||||||
|  |                   encoding=self.file_encoding) as f: | ||||||
|  |             logging.info("Writing %s", path) | ||||||
|  |             f.write(u"" + content) | ||||||
|  | 
 | ||||||
|  |         # Fix SELinux context if restorecon is installed | ||||||
|  |         try: | ||||||
|  |             subprocess.call(["restorecon", path]) | ||||||
|  |         except OSError: | ||||||
|  |             pass | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def main(): | ||||||
|  |     parser = argparse.ArgumentParser(description="Convert ntp configuration to chrony.") | ||||||
|  |     parser.add_argument("-r", "--root", dest="roots", default=["/"], nargs="+", | ||||||
|  |                         metavar="DIR", help="specify root directory (default /)") | ||||||
|  |     parser.add_argument("--ntp-conf", action="store", default="/etc/ntp.conf", | ||||||
|  |                         metavar="FILE", help="specify ntp config (default /etc/ntp.conf)") | ||||||
|  |     parser.add_argument("--step-tickers", action="store", default="", | ||||||
|  |                         metavar="FILE", help="specify ntpdate step-tickers config (no default)") | ||||||
|  |     parser.add_argument("--chrony-conf", action="store", default="/etc/chrony.conf", | ||||||
|  |                         metavar="FILE", help="specify chrony config (default /etc/chrony.conf)") | ||||||
|  |     parser.add_argument("--chrony-keys", action="store", default="/etc/chrony.keys", | ||||||
|  |                         metavar="FILE", help="specify chrony keyfile (default /etc/chrony.keys)") | ||||||
|  |     parser.add_argument("-b", "--backup", action="store_true", help="backup existing configs before writing") | ||||||
|  |     parser.add_argument("-L", "--ignored-lines", action="store_true", help="print ignored lines") | ||||||
|  |     parser.add_argument("-D", "--ignored-directives", action="store_true", | ||||||
|  |                         help="print names of ignored directives") | ||||||
|  |     parser.add_argument("-n", "--dry-run", action="store_true", help="don't make any changes") | ||||||
|  |     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase verbosity") | ||||||
|  | 
 | ||||||
|  |     args = parser.parse_args() | ||||||
|  | 
 | ||||||
|  |     logging.basicConfig(format="%(message)s", | ||||||
|  |                         level=[logging.ERROR, logging.INFO, logging.DEBUG][min(args.verbose, 2)]) | ||||||
|  | 
 | ||||||
|  |     for root in args.roots: | ||||||
|  |         conf = NtpConfiguration(root, args.ntp_conf, args.step_tickers) | ||||||
|  | 
 | ||||||
|  |         if args.ignored_lines: | ||||||
|  |             for line in conf.ignored_lines: | ||||||
|  |                 print(line) | ||||||
|  | 
 | ||||||
|  |         if args.ignored_directives: | ||||||
|  |             for directive in conf.ignored_directives: | ||||||
|  |                 print(directive) | ||||||
|  | 
 | ||||||
|  |         conf.write_chrony_configuration(args.chrony_conf, args.chrony_keys, args.dry_run, args.backup) | ||||||
|  | 
 | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     main() | ||||||
							
								
								
									
										553
									
								
								SPECS/chrony.spec
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										553
									
								
								SPECS/chrony.spec
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,553 @@ | |||||||
|  | %global _hardened_build 1 | ||||||
|  | %global clknetsim_ver 3f5ef9 | ||||||
|  | %global ntp2chrony_ver 2a0512 | ||||||
|  | %bcond_without debug | ||||||
|  | 
 | ||||||
|  | Name:           chrony | ||||||
|  | Version:        3.5 | ||||||
|  | Release:        1%{?dist} | ||||||
|  | Summary:        An NTP client/server | ||||||
|  | 
 | ||||||
|  | Group:          System Environment/Daemons | ||||||
|  | License:        GPLv2 | ||||||
|  | URL:            https://chrony.tuxfamily.org | ||||||
|  | Source0:        https://download.tuxfamily.org/chrony/chrony-%{version}%{?prerelease}.tar.gz | ||||||
|  | Source1:        chrony.dhclient | ||||||
|  | Source2:        chrony.helper | ||||||
|  | Source3:        chrony-dnssrv@.service | ||||||
|  | Source4:        chrony-dnssrv@.timer | ||||||
|  | # simulator for test suite | ||||||
|  | Source10:       https://github.com/mlichvar/clknetsim/archive/%{clknetsim_ver}/clknetsim-%{clknetsim_ver}.tar.gz | ||||||
|  | # script for converting ntp configuration to chrony | ||||||
|  | Source11:       https://github.com/mlichvar/ntp2chrony/raw/%{ntp2chrony_ver}/ntp2chrony/ntp2chrony.py | ||||||
|  | %{?gitpatch:Patch0: chrony-%{version}%{?prerelease}-%{gitpatch}.patch.gz} | ||||||
|  | 
 | ||||||
|  | # add NTP servers from DHCP when starting service | ||||||
|  | Patch2:         chrony-service-helper.patch | ||||||
|  | 
 | ||||||
|  | BuildRequires:  libcap-devel libedit-devel nettle-devel pps-tools-devel | ||||||
|  | %ifarch %{ix86} x86_64 %{arm} aarch64 mipsel mips64el ppc64 ppc64le s390 s390x | ||||||
|  | BuildRequires:  libseccomp-devel | ||||||
|  | %endif | ||||||
|  | BuildRequires:  gcc bison systemd | ||||||
|  | BuildRequires:  kernel-headers > 4.18.0-87 | ||||||
|  | 
 | ||||||
|  | Requires(pre):  shadow-utils | ||||||
|  | %{?systemd_requires} | ||||||
|  | 
 | ||||||
|  | # install timedated implementation that can control chronyd service | ||||||
|  | Recommends:     timedatex | ||||||
|  | 
 | ||||||
|  | # suggest drivers for hardware reference clocks | ||||||
|  | Suggests:       ntp-refclock | ||||||
|  | 
 | ||||||
|  | %description | ||||||
|  | chrony is a versatile implementation of the Network Time Protocol (NTP). | ||||||
|  | It can synchronise the system clock with NTP servers, reference clocks | ||||||
|  | (e.g. GPS receiver), and manual input using wristwatch and keyboard. It | ||||||
|  | can also operate as an NTPv4 (RFC 5905) server and peer to provide a time | ||||||
|  | service to other computers in the network. | ||||||
|  | 
 | ||||||
|  | %if 0%{!?vendorzone:1} | ||||||
|  | %global vendorzone %(source /etc/os-release && echo ${ID}.) | ||||||
|  | %endif | ||||||
|  | 
 | ||||||
|  | %prep | ||||||
|  | %setup -q -n %{name}-%{version}%{?prerelease} -a 10 | ||||||
|  | %{?gitpatch:%patch0 -p1} | ||||||
|  | %patch2 -p1 -b .service-helper | ||||||
|  | 
 | ||||||
|  | %{?gitpatch: echo %{version}-%{gitpatch} > version.txt} | ||||||
|  | 
 | ||||||
|  | # review changes in packaged configuration files and scripts | ||||||
|  | md5sum -c <<-EOF | (! grep -v 'OK$') | ||||||
|  |         47ad7eccc410b981d2f2101cf5682616  examples/chrony-wait.service | ||||||
|  |         e473a9fab7fe200cacce3dca8b66290b  examples/chrony.conf.example2 | ||||||
|  |         96999221eeef476bd49fe97b97503126  examples/chrony.keys.example | ||||||
|  |         6a3178c4670de7de393d9365e2793740  examples/chrony.logrotate | ||||||
|  |         8748a663f0b1943ea491858f414a6b26  examples/chrony.nm-dispatcher | ||||||
|  |         b23bcc3bd78e195ca2849459e459f3ed  examples/chronyd.service | ||||||
|  | EOF | ||||||
|  | 
 | ||||||
|  | # don't allow packaging without vendor zone | ||||||
|  | test -n "%{vendorzone}" | ||||||
|  | 
 | ||||||
|  | # use example chrony.conf as the default config with some modifications: | ||||||
|  | # - use our vendor zone (2.*pool.ntp.org names include IPv6 addresses) | ||||||
|  | # - enable leapsectz to get TAI-UTC offset and leap seconds from tzdata | ||||||
|  | # - enable keyfile | ||||||
|  | sed -e 's|^\(pool \)\(pool.ntp.org\)|\12.%{vendorzone}\2|' \ | ||||||
|  |     -e 's|#\(leapsectz\)|\1|' \ | ||||||
|  |     -e 's|#\(keyfile\)|\1|' \ | ||||||
|  |         < examples/chrony.conf.example2 > chrony.conf | ||||||
|  | 
 | ||||||
|  | touch -r examples/chrony.conf.example2 chrony.conf | ||||||
|  | 
 | ||||||
|  | # regenerate the file from getdate.y | ||||||
|  | rm -f getdate.c | ||||||
|  | 
 | ||||||
|  | mv clknetsim-%{clknetsim_ver}* test/simulation/clknetsim | ||||||
|  | 
 | ||||||
|  | install -m 644 -p %{SOURCE11} ntp2chrony.py | ||||||
|  | 
 | ||||||
|  | %build | ||||||
|  | %configure \ | ||||||
|  | %{?with_debug: --enable-debug} \ | ||||||
|  |         --enable-ntp-signd \ | ||||||
|  |         --enable-scfilter \ | ||||||
|  |         --docdir=%{_docdir} \ | ||||||
|  |         --with-ntp-era=$(date -d '1970-01-01 00:00:00+00:00' +'%s') \ | ||||||
|  |         --with-user=chrony \ | ||||||
|  |         --with-hwclockfile=%{_sysconfdir}/adjtime \ | ||||||
|  |         --with-sendmail=%{_sbindir}/sendmail | ||||||
|  | make %{?_smp_mflags} | ||||||
|  | 
 | ||||||
|  | %install | ||||||
|  | make install DESTDIR=$RPM_BUILD_ROOT | ||||||
|  | 
 | ||||||
|  | rm -rf $RPM_BUILD_ROOT%{_docdir} | ||||||
|  | 
 | ||||||
|  | mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/{sysconfig,logrotate.d} | ||||||
|  | mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/{lib,log}/chrony | ||||||
|  | mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/NetworkManager/dispatcher.d | ||||||
|  | mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/dhcp/dhclient.d | ||||||
|  | mkdir -p $RPM_BUILD_ROOT%{_libexecdir} | ||||||
|  | mkdir -p $RPM_BUILD_ROOT{%{_unitdir},%{_prefix}/lib/systemd/ntp-units.d} | ||||||
|  | 
 | ||||||
|  | install -m 644 -p chrony.conf $RPM_BUILD_ROOT%{_sysconfdir}/chrony.conf | ||||||
|  | 
 | ||||||
|  | install -m 640 -p examples/chrony.keys.example \ | ||||||
|  |         $RPM_BUILD_ROOT%{_sysconfdir}/chrony.keys | ||||||
|  | install -m 755 -p examples/chrony.nm-dispatcher \ | ||||||
|  |         $RPM_BUILD_ROOT%{_sysconfdir}/NetworkManager/dispatcher.d/20-chrony | ||||||
|  | install -m 755 -p %{SOURCE1} \ | ||||||
|  |         $RPM_BUILD_ROOT%{_sysconfdir}/dhcp/dhclient.d/chrony.sh | ||||||
|  | install -m 644 -p examples/chrony.logrotate \ | ||||||
|  |         $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/chrony | ||||||
|  | 
 | ||||||
|  | install -m 644 -p examples/chronyd.service \ | ||||||
|  |         $RPM_BUILD_ROOT%{_unitdir}/chronyd.service | ||||||
|  | install -m 644 -p examples/chrony-wait.service \ | ||||||
|  |         $RPM_BUILD_ROOT%{_unitdir}/chrony-wait.service | ||||||
|  | install -m 644 -p %{SOURCE3} $RPM_BUILD_ROOT%{_unitdir}/chrony-dnssrv@.service | ||||||
|  | install -m 644 -p %{SOURCE4} $RPM_BUILD_ROOT%{_unitdir}/chrony-dnssrv@.timer | ||||||
|  | 
 | ||||||
|  | install -m 755 -p %{SOURCE2} $RPM_BUILD_ROOT%{_libexecdir}/chrony-helper | ||||||
|  | 
 | ||||||
|  | cat > $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/chronyd <<EOF | ||||||
|  | # Command-line options for chronyd | ||||||
|  | OPTIONS="" | ||||||
|  | EOF | ||||||
|  | 
 | ||||||
|  | touch $RPM_BUILD_ROOT%{_localstatedir}/lib/chrony/{drift,rtc} | ||||||
|  | 
 | ||||||
|  | echo 'chronyd.service' > \ | ||||||
|  |         $RPM_BUILD_ROOT%{_prefix}/lib/systemd/ntp-units.d/50-chronyd.list | ||||||
|  | 
 | ||||||
|  | %check | ||||||
|  | # set random seed to get deterministic results | ||||||
|  | export CLKNETSIM_RANDOM_SEED=24502 | ||||||
|  | make %{?_smp_mflags} -C test/simulation/clknetsim | ||||||
|  | make quickcheck | ||||||
|  | 
 | ||||||
|  | %pre | ||||||
|  | getent group chrony > /dev/null || /usr/sbin/groupadd -r chrony | ||||||
|  | getent passwd chrony > /dev/null || /usr/sbin/useradd -r -g chrony \ | ||||||
|  |        -d %{_localstatedir}/lib/chrony -s /sbin/nologin chrony | ||||||
|  | : | ||||||
|  | 
 | ||||||
|  | %post | ||||||
|  | # fix PIDFile in local chronyd.service on upgrades from chrony < 3.3-2 | ||||||
|  | if grep -q 'PIDFile=%{_localstatedir}/run/chronyd.pid' \ | ||||||
|  |                 %{_sysconfdir}/systemd/system/chronyd.service 2> /dev/null && \ | ||||||
|  |         ! grep -qi '^[ '$'\t'']*pidfile' %{_sysconfdir}/chrony.conf 2> /dev/null | ||||||
|  | then | ||||||
|  |         sed -i '/PIDFile=/s|/run/|/run/chrony/|' \ | ||||||
|  |                 %{_sysconfdir}/systemd/system/chronyd.service | ||||||
|  | fi | ||||||
|  | # workaround for late reload of unit file (#1614751) | ||||||
|  | %{_bindir}/systemctl daemon-reload | ||||||
|  | %systemd_post chronyd.service chrony-wait.service | ||||||
|  | 
 | ||||||
|  | %preun | ||||||
|  | %systemd_preun chronyd.service chrony-wait.service | ||||||
|  | 
 | ||||||
|  | %postun | ||||||
|  | %systemd_postun_with_restart chronyd.service | ||||||
|  | 
 | ||||||
|  | %files | ||||||
|  | %{!?_licensedir:%global license %%doc} | ||||||
|  | %license COPYING | ||||||
|  | %doc FAQ NEWS README ntp2chrony.py | ||||||
|  | %config(noreplace) %{_sysconfdir}/chrony.conf | ||||||
|  | %config(noreplace) %verify(not md5 size mtime) %attr(640,root,chrony) %{_sysconfdir}/chrony.keys | ||||||
|  | %config(noreplace) %{_sysconfdir}/logrotate.d/chrony | ||||||
|  | %config(noreplace) %{_sysconfdir}/sysconfig/chronyd | ||||||
|  | %{_sysconfdir}/NetworkManager/dispatcher.d/20-chrony | ||||||
|  | %{_sysconfdir}/dhcp/dhclient.d/chrony.sh | ||||||
|  | %{_bindir}/chronyc | ||||||
|  | %{_sbindir}/chronyd | ||||||
|  | %{_libexecdir}/chrony-helper | ||||||
|  | %{_prefix}/lib/systemd/ntp-units.d/*.list | ||||||
|  | %{_unitdir}/chrony*.service | ||||||
|  | %{_unitdir}/chrony*.timer | ||||||
|  | %{_mandir}/man[158]/%{name}*.[158]* | ||||||
|  | %dir %attr(-,chrony,chrony) %{_localstatedir}/lib/chrony | ||||||
|  | %ghost %attr(-,chrony,chrony) %{_localstatedir}/lib/chrony/drift | ||||||
|  | %ghost %attr(-,chrony,chrony) %{_localstatedir}/lib/chrony/rtc | ||||||
|  | %dir %attr(-,chrony,chrony) %{_localstatedir}/log/chrony | ||||||
|  | 
 | ||||||
|  | %changelog | ||||||
|  | * Tue May 21 2019 Miroslav Lichvar <mlichvar@redhat.com> 3.5-1 | ||||||
|  | - update to 3.5 (#1685469 #1677218) | ||||||
|  | - fix shellcheck warnings in helper scripts (#1711948) | ||||||
|  | - update ntp2chrony script | ||||||
|  | 
 | ||||||
|  | * Mon Aug 13 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-3 | ||||||
|  | - fix PIDFile in local chronyd.service on upgrades from chrony < 3.3-2 | ||||||
|  |   (#1614800) | ||||||
|  | - add workaround for late reload of unit file (#1614751) | ||||||
|  | 
 | ||||||
|  | * Mon Jun 18 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-2 | ||||||
|  | - move pidfile to /var/run/chrony to allow chronyd to remove it on exit | ||||||
|  |   (#1584585) | ||||||
|  | - avoid blocking in getrandom system call (#1592425) | ||||||
|  | 
 | ||||||
|  | * Thu Apr 05 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-1 | ||||||
|  | - update to 3.3 | ||||||
|  | - enable keyfile by default again | ||||||
|  | - update ntp2chrony script | ||||||
|  | 
 | ||||||
|  | * Mon Mar 19 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-0.2.pre1 | ||||||
|  | - include ntp2chrony script in documentation (#1530987) | ||||||
|  | 
 | ||||||
|  | * Thu Mar 15 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-0.1.pre1 | ||||||
|  | - update to 3.3-pre1 | ||||||
|  | - switch to nettle for crypto hashing | ||||||
|  | - add gcc to build requirements | ||||||
|  | 
 | ||||||
|  | * Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 3.2-4 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Tue Jan 30 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.2-3 | ||||||
|  | - use systemd macro for scriptlet dependencies | ||||||
|  | 
 | ||||||
|  | * Thu Jan 25 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.2-2 | ||||||
|  | - fix chronyc getting stuck in infinite loop after clock step | ||||||
|  | - don't allow packaging without vendor zone | ||||||
|  | - suggest ntp-refclock | ||||||
|  | - remove obsolete dependency | ||||||
|  | - update description | ||||||
|  | 
 | ||||||
|  | * Fri Sep 15 2017 Miroslav Lichvar <mlichvar@redhat.com> 3.2-1 | ||||||
|  | - update to 3.2 | ||||||
|  | - get TAI-UTC offset and leap seconds from tzdata by default | ||||||
|  | 
 | ||||||
|  | * Tue Aug 29 2017 Miroslav Lichvar <mlichvar@redhat.com> 3.2-0.4.pre2 | ||||||
|  | - update to 3.2-pre2 | ||||||
|  | 
 | ||||||
|  | * Wed Aug 02 2017 Fedora Release Engineering <releng@fedoraproject.org> - 3.2-0.3.pre1 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 3.2-0.2.pre1 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Tue Jul 25 2017 Miroslav Lichvar <mlichvar@redhat.com> 3.2-0.1.pre1 | ||||||
|  | - update to 3.2-pre1 | ||||||
|  | 
 | ||||||
|  | * Thu May 04 2017 Miroslav Lichvar <mlichvar@redhat.com> 3.1-5 | ||||||
|  | - check PEERNTP variable before loading existing dhclient files | ||||||
|  | 
 | ||||||
|  | * Thu Apr 20 2017 Miroslav Lichvar <mlichvar@redhat.com> 3.1-4 | ||||||
|  | - use ID from /etc/os-release to set pool.ntp.org vendor zone (#1443599) | ||||||
|  | - fix seccomp filter for new glibc once again | ||||||
|  | - don't drop PHC samples with zero delay | ||||||
|  | 
 | ||||||
|  | * Mon Mar 13 2017 Miroslav Lichvar <mlichvar@redhat.com> 3.1-3 | ||||||
|  | - fix seccomp filter for new glibc | ||||||
|  | 
 | ||||||
|  | * Fri Feb 10 2017 Fedora Release Engineering <releng@fedoraproject.org> - 3.1-2 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Tue Jan 31 2017 Miroslav Lichvar <mlichvar@redhat.com> 3.1-1 | ||||||
|  | - update to 3.1 | ||||||
|  | - enable seccomp support on more archs | ||||||
|  | - package chronyd sysconfig file | ||||||
|  | 
 | ||||||
|  | * Tue Jan 24 2017 Miroslav Lichvar <mlichvar@redhat.com> 3.1-0.1.pre1 | ||||||
|  | - update to 3.1-pre1 | ||||||
|  | 
 | ||||||
|  | * Mon Jan 16 2017 Miroslav Lichvar <mlichvar@redhat.com> 3.0-1 | ||||||
|  | - update to 3.0 | ||||||
|  | 
 | ||||||
|  | * Fri Jan 06 2017 Miroslav Lichvar <mlichvar@redhat.com> 3.0-0.3.pre3 | ||||||
|  | - update to 3.0-pre3 | ||||||
|  | 
 | ||||||
|  | * Thu Dec 15 2016 Miroslav Lichvar <mlichvar@redhat.com> 3.0-0.2.pre2 | ||||||
|  | - update to 3.0-pre2 | ||||||
|  | - enable support for MS-SNTP authentication in Samba | ||||||
|  | 
 | ||||||
|  | * Fri Dec 09 2016 Miroslav Lichvar <mlichvar@redhat.com> 3.0-0.1.pre1 | ||||||
|  | - update to 3.0-pre1 | ||||||
|  | 
 | ||||||
|  | * Mon Nov 21 2016 Miroslav Lichvar <mlichvar@redhat.com> 2.4.1-1 | ||||||
|  | - update to 2.4.1 | ||||||
|  | 
 | ||||||
|  | * Thu Oct 27 2016 Miroslav Lichvar <mlichvar@redhat.com> 2.4-4 | ||||||
|  | - avoid AVC denials in chrony-wait service (#1350815) | ||||||
|  | 
 | ||||||
|  | * Tue Sep 13 2016 Miroslav Lichvar <mlichvar@redhat.com> 2.4-3 | ||||||
|  | - fix chrony-helper to escape names of systemd units (#1374767) | ||||||
|  | 
 | ||||||
|  | * Tue Jun 28 2016 Miroslav Lichvar <mlichvar@redhat.com> 2.4-2 | ||||||
|  | - fix chrony-helper to exit with correct status (#1350531) | ||||||
|  | 
 | ||||||
|  | * Tue Jun 07 2016 Miroslav Lichvar <mlichvar@redhat.com> 2.4-1 | ||||||
|  | - update to 2.4 | ||||||
|  | - don't require info | ||||||
|  | 
 | ||||||
|  | * Mon May 16 2016 Miroslav Lichvar <mlichvar@redhat.com> 2.4-0.1.pre1 | ||||||
|  | - update to 2.4-pre1 | ||||||
|  | - extend chrony-helper to allow management of static sources (#1331655) | ||||||
|  | 
 | ||||||
|  | * Tue Feb 16 2016 Miroslav Lichvar <mlichvar@redhat.com> 2.3-1 | ||||||
|  | - update to 2.3 | ||||||
|  | 
 | ||||||
|  | * Tue Feb 02 2016 Miroslav Lichvar <mlichvar@redhat.com> 2.3-0.1.pre1 | ||||||
|  | - update to 2.3-pre1 | ||||||
|  | 
 | ||||||
|  | * Thu Jan 21 2016 Miroslav Lichvar <mlichvar@redhat.com> 2.2.1-1 | ||||||
|  | - update to 2.2.1 (CVE-2016-1567) | ||||||
|  | - set NTP era split explicitly | ||||||
|  | 
 | ||||||
|  | * Mon Oct 19 2015 Miroslav Lichvar <mlichvar@redhat.com> 2.2-1 | ||||||
|  | - update to 2.2 | ||||||
|  | 
 | ||||||
|  | * Fri Oct 09 2015 Miroslav Lichvar <mlichvar@redhat.com> 2.2-0.2.pre2 | ||||||
|  | - update to 2.2-pre2 | ||||||
|  | - require libseccomp-devel on supported archs only | ||||||
|  | 
 | ||||||
|  | * Fri Oct 02 2015 Miroslav Lichvar <mlichvar@redhat.com> 2.2-0.1.pre1 | ||||||
|  | - update to 2.2-pre1 | ||||||
|  | - enable seccomp support | ||||||
|  | - use weak dependency for timedatex on Fedora 24 and later | ||||||
|  | 
 | ||||||
|  | * Tue Jun 23 2015 Miroslav Lichvar <mlichvar@redhat.com> 2.1.1-1 | ||||||
|  | - update to 2.1.1 | ||||||
|  | - add -n option to gzip command to not save timestamp | ||||||
|  | 
 | ||||||
|  | * Mon Jun 22 2015 Miroslav Lichvar <mlichvar@redhat.com> 2.1-1 | ||||||
|  | - update to 2.1 | ||||||
|  | - extend chrony-helper to allow using servers from DNS SRV records (#1234406) | ||||||
|  | - set random seed in testing to get deterministic results | ||||||
|  | 
 | ||||||
|  | * Wed Jun 17 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.1-0.2.pre1 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Wed Jun 10 2015 Miroslav Lichvar <mlichvar@redhat.com> 2.1-0.1.pre1 | ||||||
|  | - update to 2.1-pre1 | ||||||
|  | 
 | ||||||
|  | * Mon Apr 27 2015 Miroslav Lichvar <mlichvar@redhat.com> 2.0-1 | ||||||
|  | - update to 2.0 | ||||||
|  | 
 | ||||||
|  | * Wed Apr 08 2015 Miroslav Lichvar <mlichvar@redhat.com> 2.0-0.3.pre2 | ||||||
|  | - update to 2.0-pre2 (CVE-2015-1853 CVE-2015-1821 CVE-2015-1822) | ||||||
|  | 
 | ||||||
|  | * Thu Jan 29 2015 Miroslav Lichvar <mlichvar@redhat.com> 2.0-0.2.pre1 | ||||||
|  | - require timedatex (#1136905) | ||||||
|  | 
 | ||||||
|  | * Tue Jan 27 2015 Miroslav Lichvar <mlichvar@redhat.com> 2.0-0.1.pre1 | ||||||
|  | - update to 2.0-pre1 | ||||||
|  | 
 | ||||||
|  | * Thu Sep 11 2014 Miroslav Lichvar <mlichvar@redhat.com> 1.31-1 | ||||||
|  | - update to 1.31 | ||||||
|  | - add servers from DHCP with iburst option by default | ||||||
|  | - use upstream configuration files and scripts | ||||||
|  | - don't package configuration examples | ||||||
|  | - compress chrony.txt | ||||||
|  | 
 | ||||||
|  | * Thu Aug 21 2014 Miroslav Lichvar <mlichvar@redhat.com> 1.31-0.1.pre1 | ||||||
|  | - update to 1.31-pre1 | ||||||
|  | - use license macro if available | ||||||
|  | 
 | ||||||
|  | * Sat Aug 16 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.30-3 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Fri Aug 15 2014 Miroslav Lichvar <mlichvar@redhat.com> 1.30-2 | ||||||
|  | - reconnect client sockets (#1124059) | ||||||
|  | 
 | ||||||
|  | * Tue Jul 01 2014 Miroslav Lichvar <mlichvar@redhat.com> 1.30-1 | ||||||
|  | - update to 1.30 | ||||||
|  | - enable debug messages | ||||||
|  | 
 | ||||||
|  | * Mon Jun 09 2014 Miroslav Lichvar <mlichvar@redhat.com> 1.30-0.1.pre1 | ||||||
|  | - update to 1.30-pre1 | ||||||
|  | - execute test suite | ||||||
|  | - avoid calling systemctl in helper script | ||||||
|  | - call chronyc directly from logrotate and NM dispatcher scripts | ||||||
|  | - add conflict with systemd-timesyncd service | ||||||
|  | 
 | ||||||
|  | * Sat Jun 07 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.29.1-2 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Fri Jan 31 2014 Miroslav Lichvar <mlichvar@redhat.com> 1.29.1-1 | ||||||
|  | - update to 1.29.1 (CVE-2014-0021) | ||||||
|  | - replace hardening build flags with _hardened_build | ||||||
|  | 
 | ||||||
|  | * Tue Nov 19 2013 Miroslav Lichvar <mlichvar@redhat.com> 1.29-3 | ||||||
|  | - let systemd remove pid file (#974305) | ||||||
|  | 
 | ||||||
|  | * Thu Oct 03 2013 Miroslav Lichvar <mlichvar@redhat.com> 1.29-2 | ||||||
|  | - add ordering dependency to not start chronyd before ntpd stopped | ||||||
|  | 
 | ||||||
|  | * Thu Aug 08 2013 Miroslav Lichvar <mlichvar@redhat.com> 1.29-1 | ||||||
|  | - update to 1.29 (CVE-2012-4502, CVE-2012-4503) | ||||||
|  | 
 | ||||||
|  | * Sat Aug 03 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.28-2 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Wed Jul 17 2013 Miroslav Lichvar <mlichvar@redhat.com> 1.28-1 | ||||||
|  | - update to 1.28 | ||||||
|  | - change default makestep limit to 10 seconds | ||||||
|  | 
 | ||||||
|  | * Mon Jun 24 2013 Miroslav Lichvar <mlichvar@redhat.com> 1.28-0.2.pre1 | ||||||
|  | - buildrequire systemd-units | ||||||
|  | 
 | ||||||
|  | * Fri Jun 21 2013 Miroslav Lichvar <mlichvar@redhat.com> 1.28-0.1.pre1 | ||||||
|  | - update to 1.28-pre1 | ||||||
|  | - listen for commands only on localhost by default | ||||||
|  | 
 | ||||||
|  | * Thu May 09 2013 Miroslav Lichvar <mlichvar@redhat.com> 1.27-3 | ||||||
|  | - disable chrony-wait service by default (#961047) | ||||||
|  | - drop old systemd scriptlets | ||||||
|  | - don't own ntp-units.d directory | ||||||
|  | - move files from /lib | ||||||
|  | - remove unncessary dependency on syslog target | ||||||
|  | 
 | ||||||
|  | * Tue Mar 12 2013 Miroslav Lichvar <mlichvar@redhat.com> 1.27-2 | ||||||
|  | - suppress error messages from tr when generating key (#907914) | ||||||
|  | - fix delta calculation with extreme frequency offsets | ||||||
|  | 
 | ||||||
|  | * Fri Feb 01 2013 Miroslav Lichvar <mlichvar@redhat.com> 1.27-1 | ||||||
|  | - update to 1.27 | ||||||
|  | - start chrony-wait service with chronyd | ||||||
|  | - start chronyd service after sntp | ||||||
|  | - remove obsolete macros | ||||||
|  | 
 | ||||||
|  | * Tue Sep 11 2012 Miroslav Lichvar <mlichvar@redhat.com> 1.27-0.5.pre1.git1ca844 | ||||||
|  | - update to git snapshot 1ca844 | ||||||
|  | - update systemd integration (#846303) | ||||||
|  | - use systemd macros if available (#850151) | ||||||
|  | - use correct vendor pool.ntp.org zone on RHEL (#845981) | ||||||
|  | - don't log output of chrony-wait service | ||||||
|  | 
 | ||||||
|  | * Wed Jul 18 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.27-0.4.pre1 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Fri Apr 27 2012 Miroslav Lichvar <mlichvar@redhat.com> 1.27-0.3.pre1 | ||||||
|  | - update service file for systemd-timedated-ntp target (#816493) | ||||||
|  | 
 | ||||||
|  | * Fri Apr 06 2012 Miroslav Lichvar <mlichvar@redhat.com> 1.27-0.2.pre1 | ||||||
|  |   use systemctl is-active instead of status in chrony-helper (#794771) | ||||||
|  | 
 | ||||||
|  | * Tue Feb 28 2012 Miroslav Lichvar <mlichvar@redhat.com> 1.27-0.1.pre1 | ||||||
|  | - update to 1.27-pre1 | ||||||
|  | - generate SHA1 command key instead of MD5 | ||||||
|  | 
 | ||||||
|  | * Wed Feb 15 2012 Miroslav Lichvar <mlichvar@redhat.com> 1.26-6.20110831gitb088b7 | ||||||
|  | - remove old servers on DHCP update (#787042) | ||||||
|  | 
 | ||||||
|  | * Fri Feb 10 2012 Miroslav Lichvar <mlichvar@redhat.com> 1.26-5.20110831gitb088b7 | ||||||
|  | - improve chrony-helper to keep track of servers added from DHCP (#787042) | ||||||
|  | - fix dhclient script to always return with zero exit code (#767859) | ||||||
|  | 
 | ||||||
|  | * Thu Jan 12 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.26-4.20110831gitb088b7 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Tue Sep 06 2011 Miroslav Lichvar <mlichvar@redhat.com> 1.26-3.20110831gitb088b7 | ||||||
|  | - update to git snapshot 20110831gitb088b7 | ||||||
|  | - on first start generate password with 16 chars | ||||||
|  | - change systemd service type to forking | ||||||
|  | - add forced-command to chrony-helper (#735821) | ||||||
|  | 
 | ||||||
|  | * Mon Aug 15 2011 Miroslav Lichvar <mlichvar@redhat.com> 1.26-2 | ||||||
|  | - fix iburst with very high jitters and long delays | ||||||
|  | - use timepps header from pps-tools-devel | ||||||
|  | 
 | ||||||
|  | * Wed Jul 13 2011 Miroslav Lichvar <mlichvar@redhat.com> 1.26-1 | ||||||
|  | - update to 1.26 | ||||||
|  | - read options from sysconfig file if it exists | ||||||
|  | 
 | ||||||
|  | * Fri Jun 24 2011 Miroslav Lichvar <mlichvar@redhat.com> 1.26-0.1.pre1 | ||||||
|  | - update to 1.26-pre1 | ||||||
|  | - fix service name in %%triggerun | ||||||
|  | - drop SysV init script | ||||||
|  | - add chrony-wait service | ||||||
|  | 
 | ||||||
|  | * Fri May 06 2011 Bill Nottingham <notting@redhat.com> 1.25-2 | ||||||
|  | - fix systemd scriptlets for the upgrade case | ||||||
|  | 
 | ||||||
|  | * Wed May 04 2011 Miroslav Lichvar <mlichvar@redhat.com> 1.25-1 | ||||||
|  | - update to 1.25 | ||||||
|  | 
 | ||||||
|  | * Wed Apr 20 2011 Miroslav Lichvar <mlichvar@redhat.com> 1.25-0.3.pre2 | ||||||
|  | - update to 1.25-pre2 | ||||||
|  | - link with -Wl,-z,relro,-z,now options | ||||||
|  | 
 | ||||||
|  | * Tue Feb 08 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.25-0.2.pre1 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Tue Feb 01 2011 Miroslav Lichvar <mlichvar@redhat.com> 1.25-0.1.pre1 | ||||||
|  | - update to 1.25-pre1 | ||||||
|  | - use iburst, four pool servers, rtcsync, stratumweight in default config | ||||||
|  | - add systemd support | ||||||
|  | - drop sysconfig file  | ||||||
|  | - suppress install-info errors | ||||||
|  | 
 | ||||||
|  | * Thu Apr 29 2010 Miroslav Lichvar <mlichvar@redhat.com> 1.24-4.20100428git73d775 | ||||||
|  | - update to 20100428git73d775 | ||||||
|  | - replace initstepslew directive with makestep in default config | ||||||
|  | - add NetworkManager dispatcher script | ||||||
|  | - add dhclient script | ||||||
|  | - retry server/peer name resolution at least once to workaround | ||||||
|  |   NetworkManager race condition on boot | ||||||
|  | - don't verify chrony.keys | ||||||
|  | 
 | ||||||
|  | * Fri Mar 12 2010 Miroslav Lichvar <mlichvar@redhat.com> 1.24-3.20100302git5fb555 | ||||||
|  | - update to snapshot 20100302git5fb555 | ||||||
|  | - compile with PPS API support | ||||||
|  | 
 | ||||||
|  | * Thu Feb 04 2010 Miroslav Lichvar <mlichvar@redhat.com> 1.24-1 | ||||||
|  | - update to 1.24 (#555367, CVE-2010-0292 CVE-2010-0293 CVE-2010-0294) | ||||||
|  | - modify default config | ||||||
|  |   - step clock on start if it is off by more than 100 seconds | ||||||
|  |   - disable client log | ||||||
|  | - build with -fPIE on sparc | ||||||
|  | 
 | ||||||
|  | * Tue Dec 15 2009 Miroslav Lichvar <mlichvar@redhat.com> 1.24-0.1.pre1 | ||||||
|  | - update to 1.24-pre1 | ||||||
|  | 
 | ||||||
|  | * Fri Jul 24 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.23-7.20081106gitbe42b4 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Fri Jul 17 2009 Miroslav Lichvar <mlichvar@redhat.com> 1.23-6.20081106gitbe42b4 | ||||||
|  | - switch to editline | ||||||
|  | - support arbitrary chronyc commands in init script | ||||||
|  | 
 | ||||||
|  | * Mon Jun 08 2009 Dan Horak <dan[at]danny.cz> 1.23-5.20081106gitbe42b4 | ||||||
|  | - add patch with support for s390/s390x | ||||||
|  | 
 | ||||||
|  | * Mon Mar 09 2009 Miroslav Lichvar <mlichvar@redhat.com> 1.23-4.20081106gitbe42b4 | ||||||
|  | - fix building with broken libcap header (#483548) | ||||||
|  | 
 | ||||||
|  | * Mon Feb 23 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.23-3.20081106gitbe42b4 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Wed Nov 19 2008 Miroslav Lichvar <mlichvar@redhat.com> 1.23-2.20081106gitbe42b4 | ||||||
|  | - fix info uninstall | ||||||
|  | - generate random command key in init script | ||||||
|  | - support cyclelogs, online, offline commands in init script | ||||||
|  | - add logrotate script | ||||||
|  | 
 | ||||||
|  | * Tue Nov 11 2008 Miroslav Lichvar <mlichvar@redhat.com> 1.23-1.20081106gitbe42b4 | ||||||
|  | - initial release | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user