251 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			251 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 
								 | 
							
								#!/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@
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								chrony_command() {
							 | 
						||
| 
								 | 
							
								    $chronyc -a -n -m "$1"
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								is_running() {
							 | 
						||
| 
								 | 
							
								    chrony_command "tracking" &> /dev/null
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								is_update_needed() {
							 | 
						||
| 
								 | 
							
								    for file in $dhclient_servers_files $dnssrv_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 $dhclient_servers_files $dnssrv_servers_files 2> /dev/null)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    all_servers=$(
							 | 
						||
| 
								 | 
							
								        echo "$all_servers_with_args" |
							 | 
						||
| 
								 | 
							
								            while read server serverargs; do
							 | 
						||
| 
								 | 
							
								                echo "$server"
							 | 
						||
| 
								 | 
							
								            done | sort -u)
							 | 
						||
| 
								 | 
							
								    added_servers=$( (
							 | 
						||
| 
								 | 
							
								        cat $added_servers_file 2> /dev/null
							 | 
						||
| 
								 | 
							
								        echo "$all_servers_with_args" |
							 | 
						||
| 
								 | 
							
								            while read 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 server; do
							 | 
						||
| 
								 | 
							
								            chrony_command "delete $server" &> /dev/null
							 | 
						||
| 
								 | 
							
								        done
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    added_servers=$(comm -12 <(echo -n "$added_servers") <(echo -n "$all_servers"))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    [ -n "$added_servers" ] && echo "$added_servers" > $added_servers_file ||
							 | 
						||
| 
								 | 
							
								        rm -f $added_servers_file
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								get_dnssrv_servers() {
							 | 
						||
| 
								 | 
							
								    local name=$1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ! command -v dig &> /dev/null; then
							 | 
						||
| 
								 | 
							
								        echo "Missing dig (DNS lookup utility)" >&2
							 | 
						||
| 
								 | 
							
								        return 1
							 | 
						||
| 
								 | 
							
								    fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    (
							 | 
						||
| 
								 | 
							
								        . $network_sysconfig_file &> /dev/null
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        output=$(dig "$name" srv +short +ndots=2 +search 2> /dev/null)
							 | 
						||
| 
								 | 
							
								        [ $? -ne 0 ] && return 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        echo "$output" | while read prio weight 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")
							 | 
						||
| 
								 | 
							
								    [ -n "$servers" ] && echo "$servers" > "$srv_file" || rm -f "$srv_file"
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								set_dnssrv_timer() {
							 | 
						||
| 
								 | 
							
								    local state=$1 name=$2
							 | 
						||
| 
								 | 
							
								    local srv_file=$helper_dir/dnssrv@$name servers
							 | 
						||
| 
								 | 
							
								    local timer=$dnssrv_timer_prefix$(systemd-escape "$name").timer
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    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 line; do
							 | 
						||
| 
								 | 
							
								        is_source_line "$line" && echo "$line" || :
							 | 
						||
| 
								 | 
							
								    done < $chrony_conf
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								set_static_sources() {
							 | 
						||
| 
								 | 
							
								    local new_config tmp_conf
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    new_config=$(
							 | 
						||
| 
								 | 
							
								        sources=$(
							 | 
						||
| 
								 | 
							
								            while read line; do
							 | 
						||
| 
								 | 
							
								                is_source_line "$line" && echo "$line"
							 | 
						||
| 
								 | 
							
								            done)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        while read line; do
							 | 
						||
| 
								 | 
							
								            if ! is_source_line "$line"; then
							 | 
						||
| 
								 | 
							
								                echo "$line"
							 | 
						||
| 
								 | 
							
								                continue
							 | 
						||
| 
								 | 
							
								            fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            tmp_sources=$(
							 | 
						||
| 
								 | 
							
								                local removed=0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                echo "$sources" | while read line2; do
							 | 
						||
| 
								 | 
							
								                    [ "$removed" -ne 0 -o "$line" != "$line2" ] && \
							 | 
						||
| 
								 | 
							
								                        echo "$line2" || removed=1
							 | 
						||
| 
								 | 
							
								                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 $?
							 |