From ec9fb0cddc9b7603db969f00bdd929cd9567bd22 Mon Sep 17 00:00:00 2001 From: Vivek Kumar Dutta Date: Wed, 9 Aug 2023 14:13:07 +0530 Subject: [PATCH] timemngr: 1.0.0 --- timemngr/Config.in | 20 +++ timemngr/Makefile | 69 +++++++ .../files/etc/hotplug.d/iface/21-timemngr | 34 ++++ timemngr/files/etc/init.d/timemngr | 62 +++++++ timemngr/files/etc/timemngr/input.json | 15 ++ timemngr/files/etc/timemngr/ntpd_config.sh | 168 ++++++++++++++++++ .../etc/uci-defaults/96-system-ntp-migrate | 70 ++++++++ 7 files changed, 438 insertions(+) create mode 100644 timemngr/Config.in create mode 100644 timemngr/Makefile create mode 100644 timemngr/files/etc/hotplug.d/iface/21-timemngr create mode 100755 timemngr/files/etc/init.d/timemngr create mode 100644 timemngr/files/etc/timemngr/input.json create mode 100755 timemngr/files/etc/timemngr/ntpd_config.sh create mode 100644 timemngr/files/etc/uci-defaults/96-system-ntp-migrate diff --git a/timemngr/Config.in b/timemngr/Config.in new file mode 100644 index 000000000..6360a8fe2 --- /dev/null +++ b/timemngr/Config.in @@ -0,0 +1,20 @@ +if PACKAGE_timemngr +choice + prompt "Select backend of time management" + default TIMEMNGR_NTPD + depends on PACKAGE_timemngr + help + Select which backend daemon to use for time management + +config TIMEMNGR_NTPD + bool "Use NTPD for time management" + +endchoice +config TIMEMNGR_MIGRATE_SYSTEM + bool "Migrate time definition from system uci" + default y + help + Timemngr can be configured with time uci file, or by a migration + script to migrate ntp uci definition from system uci to time uci. + Enable this option to install the ntp migration script. +endif diff --git a/timemngr/Makefile b/timemngr/Makefile new file mode 100644 index 000000000..393fbabf4 --- /dev/null +++ b/timemngr/Makefile @@ -0,0 +1,69 @@ +# +# Copyright (C) 2023 IOPSYS +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=timemngr +PKG_VERSION:=1.0.0 + +LOCAL_DEV:=0 +ifneq ($(LOCAL_DEV),1) +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://dev.iopsys.eu/bbf/timemngr.git +PKG_SOURCE_VERSION:=7803c29c7c16e808f10dec226ec66d1ade5e84ec +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz +PKG_MIRROR_HASH:=skip +endif + +PKG_LICENSE:=BSD-3-Clause +PKG_LICENSE_FILES:=LICENSE + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=utils + CATEGORY:=Utilities + SUBMENU:=TRx69 + TITLE:=Time manager daemon based on ntpd + DEPENDS:=+bbfdmd +ntpd +libuci +libubox +ubus + MENU:=1 +endef + +define Package/$(PKG_NAME)/config + source "$(SOURCE)/Config.in" +endef + +MAKE_PATH:=src + +define Package/$(PKG_NAME)/description + Manage device time with ntpd and provides Device.Time. datamodel object based on TR181-2.16 +endef + +ifeq ($(LOCAL_DEV),1) +define Build/Prepare + $(CP) -rf ~/git/timemngr/* $(PKG_BUILD_DIR)/ +endef +endif + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/etc/timemngr/ + $(INSTALL_DIR) $(1)/etc/hotplug.d/iface + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/timemngr $(1)/usr/sbin/timemngr + $(INSTALL_DATA) $(PKG_BUILD_DIR)/src/libtimemngr.so $(1)/etc/timemngr/ + $(INSTALL_DATA) ./files/etc/timemngr/input.json $(1)/etc/timemngr/ + $(INSTALL_BIN) ./files/etc/hotplug.d/iface/21-timemngr $(1)/etc/hotplug.d/iface/ + $(INSTALL_BIN) ./files/etc/init.d/timemngr $(1)/etc/init.d/ +ifeq ($(CONFIG_TIMEMNGR_MIGRATE_SYSTEM),y) + $(INSTALL_DIR) $(1)/etc/uci-defaults + $(INSTALL_BIN) ./files/etc/uci-defaults/96-system-ntp-migrate $(1)/etc/uci-defaults/ +endif +ifeq ($(CONFIG_TIMEMNGR_NTPD),y) + $(CP) ./files/etc/timemngr/ntpd_config.sh $(1)/etc/timemngr/time.sh +endif +endef + + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/timemngr/files/etc/hotplug.d/iface/21-timemngr b/timemngr/files/etc/hotplug.d/iface/21-timemngr new file mode 100644 index 000000000..9bc3c9e57 --- /dev/null +++ b/timemngr/files/etc/hotplug.d/iface/21-timemngr @@ -0,0 +1,34 @@ +#!/bin/sh + +NAME=time + +. /usr/share/libubox/jshn.sh + +configure_ntp_servers() +{ + local ntp_interface + + # Only change the ntp servers if interface matches with the defined interface + ntp_interface="$(uci -q get ${NAME}.dhcp_driven.client_interface)" + + if [ "${ntp_interface}" != "${1}" ]; then + return 0 + fi + + json_load "$(ifstatus $ntp_interface)" + json_select data + json_get_var servers ntpserver "" + + dhcp_ntp_server="${servers// /,}" + + exist_dhcp_ntp_server="$(uci -q get ${NAME}.dhcp_driven.server)" + if [ "${dhcp_ntp_server}" != "${exist_dhcp_ntp_server}" ]; then + uci -q set ${NAME}.dhcp_driven.server="${dhcp_ntp_server}" + eval ubus call uci commit '{\"config\":\"$NAME\"}' + fi +} + +[ "$ACTION" = "ifup" -a "$(uci -q get network.$INTERFACE.is_lan)" != "1" ] && { + configure_ntp_servers ${INTERFACE} +} + diff --git a/timemngr/files/etc/init.d/timemngr b/timemngr/files/etc/init.d/timemngr new file mode 100755 index 000000000..921081188 --- /dev/null +++ b/timemngr/files/etc/init.d/timemngr @@ -0,0 +1,62 @@ +#!/bin/sh /etc/rc.common + +START=20 +STOP=01 + +. /etc/bbfdm/bbfdm_services.sh +. /etc/timemngr/time.sh + +USE_PROCD=1 +PROG_UBUS=/usr/sbin/timemngr + +DM_INPUT="/etc/timemngr/input.json" + +validate_global_section() { + uci_validate_section time global global \ + 'enable:bool:1' +} + +start_service() { + if uci -q get system.ntp >/dev/null 2>&1; then + logger -t timemngr.init "Not starting timemngr, legacy ntp definition detected" + return 1 + fi + + local enable + validate_global_section || { + return 1 + } + + if [ "$enable" != 1 ]; then + return 1 + fi + + procd_open_instance timemngr_ubus + procd_set_param command $PROG_UBUS -l 1 + procd_close_instance + + generate_config + create_service + + bbfdm_add_service "bbfdm.time" "${DM_INPUT}" +} + +reload_service() { + stop + start +} + +service_triggers() { + procd_add_reload_trigger "time" + + local enable_server server_mode ttl interface + validate_server_section || { + return 1 + } + + if [ "$enable_server" != 0 ] && [ "$server_mode" = "Broadcast" ] && [ -n "$interface" ]; then + procd_open_trigger + procd_add_interface_trigger "interface.*.up" $interface /etc/init.d/timemngr restart + procd_close_trigger + fi +} diff --git a/timemngr/files/etc/timemngr/input.json b/timemngr/files/etc/timemngr/input.json new file mode 100644 index 000000000..7faff3aef --- /dev/null +++ b/timemngr/files/etc/timemngr/input.json @@ -0,0 +1,15 @@ +{ + "daemon": { + "input": { + "type": "DotSo", + "name": "/etc/timemngr/libtimemngr.so" + }, + "output": { + "type": "UBUS", + "name": "bbfdm.time", + "parent_dm": "Device.", + "object": "Time", + "root_obj": "bbfdm" + } + } +} diff --git a/timemngr/files/etc/timemngr/ntpd_config.sh b/timemngr/files/etc/timemngr/ntpd_config.sh new file mode 100755 index 000000000..40d680d6d --- /dev/null +++ b/timemngr/files/etc/timemngr/ntpd_config.sh @@ -0,0 +1,168 @@ +#!/bin/sh + +. /lib/functions.sh + +CONF_FILE=/tmp/timemngr/timemngr.conf + +trunc() { + mkdir -p $(dirname ${CONF_FILE}) + chown -R ntp:ntp $(dirname ${CONF_FILE}) + echo -n "" > ${CONF_FILE} +} + +emit() { + echo -e "$@" >> ${CONF_FILE} +} + +validate_global_section() { + uci_validate_section time global global \ + 'enable:bool:1' +} + +validate_server_section() { + uci_validate_section time server server \ + 'enable_server:bool:1'\ + 'server_mode:string:Unicast'\ + 'ttl:uinteger:255'\ + 'interface:string' +} + +validate_client_section() { + uci_validate_section time client $1 \ + 'enable_client:bool:1'\ + 'iburst:bool:1'\ + 'version:uinteger:4'\ + 'peer:bool:0'\ + 'minpoll:uinteger:6'\ + 'maxpoll:uinteger:10'\ + 'client_mode:string:Unicast'\ + 'server:string' +} + +generate_config() { + local enable + validate_global_section || { + return 1 + } + + if [ "$enable" != 1 ]; then + return 1 + fi + + enable_client_sec=$(uci -q show time | grep enable_client=\'1\' | cut -d'.' -f 2) + local enable_client iburst version peer minpoll maxpoll client_mode server + if [ -n $enable_client_sec ]; then + validate_client_section $enable_client_sec || { + return 1 + } + else + enable_client=0 + fi + + local enable_server server_mode ttl interface + validate_server_section || { + return 1 + } + + [ "$enable_client" = 0 ] && [ "$enable_server" = 0 ] && return + + trunc + emit "driftfile /tmp/timemngr/ntp.drift\n" + + str1="restrict -4 default noserve" + str2="restrict -6 default noserve" + if [ "$enable_server" != 0 ]; then + str1="restrict default limited kod nomodify notrap" + str2="restrict -6 default limited kod nomodify notrap" + fi + + if [ "$enable_client" == 0 ] || [ "$peer" == 0 ]; then + str1="${str1} nopeer" + str2="${str2} nopeer" + fi + + emit "${str1}" + emit "${str2}" + emit "restrict source noquery" + + emit "\n# No limits for local monitoring" + emit "restrict 127.0.0.1" + emit "restrict -6 ::1\n" + + if [ "$enable_client" != 0 ]; then + if [ "$client_mode" = "Broadcast" ]; then + emit "broadcastclient\n" + elif [ "$client_mode" = "Multicast" ]; then + emit "multicastclient 224.0.1.1 minpoll $minpoll maxpoll $maxpoll version $version\n" + elif [ "$client_mode" = "Manycast" ]; then + emit "manycastclient 224.0.1.1 minpoll $minpoll maxpoll $maxpoll version $version\n" + else + for i in ${server//,/ }; do + str="server $i minpoll $minpoll maxpoll $maxpoll version $version" + if [ "$iburst" != 0 ]; then + str="${str} iburst" + fi + emit "${str}" + done + + if [ "$peer" != 0 ]; then + for i in ${server//,/ }; do + str="peer $i minpoll $minpoll maxpoll $maxpoll version $version" + if [ "$iburst" != 0 ]; then + str="${str} iburst" + fi + emit "${str}" + done + fi + fi + fi + + emit "" + if [ "$enable_server" != 0 ]; then + if [ "$server_mode" = "Broadcast" ] && [ -n "$interface" ]; then + ip=$(ubus call network.interface dump | jsonfilter -e "@.interface[@.interface='$interface']['ipv4-address'][0]['address']") + mask=$(ubus call network.interface dump | jsonfilter -e "@.interface[@.interface='$interface']['ipv4-address'][0]['mask']") + + if [ -n "$ip" ] && [ -n "$mask" ]; then + pref=$(( $mask / 8 )) + bcast_ip=$(echo $ip | cut -d. -f1-$pref) + for i in `seq $pref 3`; do + bcast_ip=$bcast_ip".255" + done + + str="broadcast $bcast_ip" + if [ -n "$ttl" ]; then + str="${str} ttl ${ttl}" + fi + + emit "${str}" + fi + elif [ "$server_mode" = "Multicast" ]; then + str="broadcast 224.0.1.1" + if [ -n "$ttl" ]; then + str="${str} ttl ${ttl}" + fi + emit "${str}" + elif [ "$server_mode" = "Manycast" ]; then + emit "manycastserver 224.0.1.1" + fi + + emit "" + if [ -n "$interface" ]; then + local loopback=$(ubus call network.interface dump | jsonfilter -e "@.interface[@.interface='loopback']['device']") + local l3_intf=$(ubus call network.interface dump | jsonfilter -e "@.interface[@.interface='$interface']['device']") + local saw_lo= + emit "interface listen $l3_intf" + [ "$l3_intf" = "$loopback" ] && saw_lo=1 + [ -z "$saw_lo" ] && emit "interface listen $loopback" + emit "" + fi + fi + +} + +create_service() { + procd_open_instance timemngr + procd_set_param command "/sbin/ntpd" -g -u ntp:ntp -n -c ${CONF_FILE} + procd_close_instance +} diff --git a/timemngr/files/etc/uci-defaults/96-system-ntp-migrate b/timemngr/files/etc/uci-defaults/96-system-ntp-migrate new file mode 100644 index 000000000..12042d0b0 --- /dev/null +++ b/timemngr/files/etc/uci-defaults/96-system-ntp-migrate @@ -0,0 +1,70 @@ +#!/bin/sh + +function get_system_ntp_option() +{ + local val + + val="$(uci -q get system.ntp.${1})" + echo "${val}" +} + +# migrate system ntp servers to time +if uci -q get system.ntp >/dev/null 2>&1; then + if [ ! -f "/etc/config/time" ]; then + touch /etc/config/time + + uci -q set time.global="global" + uci -q set time.global.enable="1" + + uci -q set time.client="client" + + enabled="$(get_system_ntp_option enabled)" + if [ -z "${enabled}" ]; then + enabled="1" + fi + + uci -q set time.client.enable_client="$enabled" + uci -q set time.client.iburst="1" + uci -q set time.client.version="4" + uci -q set time.client.peer="0" + uci -q set time.client.minpoll="6" + uci -q set time.client.maxpoll="10" + uci -q set time.client.client_mode="Unicast" + + servers="$(get_system_ntp_option server)" + if [ -n "${servers}" ]; then + servers="${servers// /,}" + else + servers="ntp1.sth.netnod.se,ntp1.gbg.netnod.se" + fi + uci -q set time.client.server="${servers}" + + # DHCP client instance + uci -q set time.dhcp_driven="client" + uci -q set time.dhcp_driven.enable_client="0" + + interface="$(get_system_ntp_option interface)" + if [ -n "${interface}" ]; then + uci -q set time.dhcp_driven.client_interface="${interface}" + else + uci -q set time.dhcp_driven.client_interface="wan" + fi + + uci -q set time.dhcp_driven.iburst="1" + uci -q set time.dhcp_driven.version="4" + uci -q set time.dhcp_driven.peer="0" + uci -q set time.dhcp_driven.minpoll="6" + uci -q set time.dhcp_driven.maxpoll="10" + uci -q set time.dhcp_driven.client_mode="Unicast" + + # Add timeserver + uci -q set time.server="server" + uci -q set time.server.enable_server="$(get_system_ntp_option enable_server)" + uci -q set time.server.server_mode="Unicast" + uci -q set time.server.ttl="255" + uci -q commit time + fi + + uci -q delete system.ntp + uci -q commit system +fi