diff --git a/internal/network/netif.go b/internal/network/netif.go index 5a8dab6..d77a4fa 100644 --- a/internal/network/netif.go +++ b/internal/network/netif.go @@ -48,7 +48,7 @@ type NetworkInterfaceOptions struct { DefaultHostname string OnStateChange func(state *NetworkInterfaceState) OnInitialCheck func(state *NetworkInterfaceState) - OnDhcpLeaseChange func(lease *udhcpc.Lease) + OnDhcpLeaseChange func(lease *udhcpc.Lease, state *NetworkInterfaceState) OnConfigChange func(config *NetworkConfig) NetworkConfig *NetworkConfig } @@ -94,7 +94,7 @@ func NewNetworkInterfaceState(opts *NetworkInterfaceOptions) (*NetworkInterfaceS _ = s.updateNtpServersFromLease(lease) _ = s.setHostnameIfNotSame() - opts.OnDhcpLeaseChange(lease) + opts.OnDhcpLeaseChange(lease, s) }, }) diff --git a/internal/timesync/ntp.go b/internal/timesync/ntp.go index c32de2a..b9ffa24 100644 --- a/internal/timesync/ntp.go +++ b/internal/timesync/ntp.go @@ -9,17 +9,32 @@ import ( "github.com/beevik/ntp" ) -var defaultNTPServers = []string{ +var defaultNTPServerIPs = []string{ + // These servers are known by static IP and as such don't need DNS lookups + // These are from Google and Cloudflare since if they're down, the internet + // is broken anyway + "162.159.200.1", // time.cloudflare.com IPv4 + "162.159.200.123", // time.cloudflare.com IPv4 + "2606:4700:f1::1", // time.cloudflare.com IPv6 + "2606:4700:f1::123", // time.cloudflare.com IPv6 + "216.239.35.0", // time.google.com IPv4 + "216.239.35.4", // time.google.com IPv4 + "216.239.35.8", // time.google.com IPv4 + "216.239.35.12", // time.google.com IPv4 + "2001:4860:4806::", // time.google.com IPv6 + "2001:4860:4806:4::", // time.google.com IPv6 + "2001:4860:4806:8::", // time.google.com IPv6 + "2001:4860:4806:c::", // time.google.com IPv6 +} + +var defaultNTPServerHostnames = []string{ + // should use something from https://github.com/jauderho/public-ntp-servers "time.apple.com", "time.aws.com", "time.windows.com", "time.google.com", - "162.159.200.123", // time.cloudflare.com IPv4 - "2606:4700:f1::123", // time.cloudflare.com IPv6 - "0.pool.ntp.org", - "1.pool.ntp.org", - "2.pool.ntp.org", - "3.pool.ntp.org", + "time.cloudflare.com", + "pool.ntp.org", } func (t *TimeSync) queryNetworkTime(ntpServers []string) (now *time.Time, offset *time.Duration) { diff --git a/internal/timesync/timesync.go b/internal/timesync/timesync.go index db1c96e..b29a61a 100644 --- a/internal/timesync/timesync.go +++ b/internal/timesync/timesync.go @@ -158,6 +158,7 @@ func (t *TimeSync) Sync() error { var ( now *time.Time offset *time.Duration + log zerolog.Logger ) metricTimeSyncCount.Inc() @@ -166,54 +167,54 @@ func (t *TimeSync) Sync() error { Orders: for _, mode := range syncMode.Ordering { + log = t.l.With().Str("mode", mode).Logger() switch mode { case "ntp_user_provided": if syncMode.Ntp { - t.l.Info().Msg("using NTP custom servers") + log.Info().Msg("using NTP custom servers") now, offset = t.queryNetworkTime(t.networkConfig.TimeSyncNTPServers) if now != nil { - t.l.Info().Str("source", "NTP").Time("now", *now).Msg("time obtained") break Orders } } case "ntp_dhcp": if syncMode.Ntp { - t.l.Info().Msg("using NTP servers from DHCP") + log.Info().Msg("using NTP servers from DHCP") now, offset = t.queryNetworkTime(t.dhcpNtpAddresses) if now != nil { - t.l.Info().Str("source", "NTP DHCP").Time("now", *now).Msg("time obtained") break Orders } } case "ntp": if syncMode.Ntp && syncMode.NtpUseFallback { - t.l.Info().Msg("using NTP fallback") - now, offset = t.queryNetworkTime(defaultNTPServers) + log.Info().Msg("using NTP fallback IPs") + now, offset = t.queryNetworkTime(defaultNTPServerIPs) + if now == nil { + log.Info().Msg("using NTP fallback hostnames") + now, offset = t.queryNetworkTime(defaultNTPServerHostnames) + } if now != nil { - t.l.Info().Str("source", "NTP fallback").Time("now", *now).Msg("time obtained") break Orders } } case "http_user_provided": if syncMode.Http { - t.l.Info().Msg("using HTTP custom URLs") + log.Info().Msg("using HTTP custom URLs") now = t.queryAllHttpTime(t.networkConfig.TimeSyncHTTPUrls) if now != nil { - t.l.Info().Str("source", "HTTP").Time("now", *now).Msg("time obtained") break Orders } } case "http": if syncMode.Http && syncMode.HttpUseFallback { - t.l.Info().Msg("using HTTP fallback") + log.Info().Msg("using HTTP fallback") now = t.queryAllHttpTime(defaultHTTPUrls) if now != nil { - t.l.Info().Str("source", "HTTP fallback").Time("now", *now).Msg("time obtained") break Orders } } default: - t.l.Warn().Str("mode", mode).Msg("unknown time sync mode, skipping") + log.Warn().Msg("unknown time sync mode, skipping") } } @@ -226,6 +227,8 @@ Orders: now = &newNow } + log.Info().Time("now", *now).Msg("time obtained") + err := t.setSystemTime(*now) if err != nil { return fmt.Errorf("failed to set system time: %w", err) diff --git a/main.go b/main.go index c25d8b8..b4de5c9 100644 --- a/main.go +++ b/main.go @@ -96,16 +96,25 @@ func Main() { if !config.AutoUpdateEnabled { return } + + if isTimeSyncNeeded() || !timeSync.IsSyncSuccess() { + logger.Debug().Msg("system time is not synced, will retry in 30 seconds") + time.Sleep(30 * time.Second) + continue + } + if currentSession != nil { logger.Debug().Msg("skipping update since a session is active") time.Sleep(1 * time.Minute) continue } + includePreRelease := config.IncludePreRelease err = TryUpdate(context.Background(), GetDeviceID(), includePreRelease) if err != nil { logger.Warn().Err(err).Msg("failed to auto update") } + time.Sleep(1 * time.Hour) } }() diff --git a/network.go b/network.go index d4f46e7..af8e50f 100644 --- a/network.go +++ b/network.go @@ -15,7 +15,7 @@ var ( networkState *network.NetworkInterfaceState ) -func networkStateChanged() { +func networkStateChanged(isOnline bool) { // do not block the main thread go waitCtrlAndRequestDisplayUpdate(true) @@ -37,6 +37,13 @@ func networkStateChanged() { networkState.GetFQDN(), }, true) } + + // if the network is now online, trigger an NTP sync if still needed + if isOnline && timeSync != nil && (isTimeSyncNeeded() || !timeSync.IsSyncSuccess()) { + if err := timeSync.Sync(); err != nil { + logger.Warn().Str("error", err.Error()).Msg("unable to sync time on network state change") + } + } } func initNetwork() error { @@ -48,13 +55,13 @@ func initNetwork() error { NetworkConfig: config.NetworkConfig, Logger: networkLogger, OnStateChange: func(state *network.NetworkInterfaceState) { - networkStateChanged() + networkStateChanged(state.IsOnline()) }, OnInitialCheck: func(state *network.NetworkInterfaceState) { - networkStateChanged() + networkStateChanged(state.IsOnline()) }, - OnDhcpLeaseChange: func(lease *udhcpc.Lease) { - networkStateChanged() + OnDhcpLeaseChange: func(lease *udhcpc.Lease, state *network.NetworkInterfaceState) { + networkStateChanged(state.IsOnline()) if currentSession == nil { return @@ -64,7 +71,15 @@ func initNetwork() error { }, OnConfigChange: func(networkConfig *network.NetworkConfig) { config.NetworkConfig = networkConfig - networkStateChanged() + networkStateChanged(false) + + if mDNS != nil { + _ = mDNS.SetListenOptions(networkConfig.GetMDNSMode()) + _ = mDNS.SetLocalNames([]string{ + networkState.GetHostname(), + networkState.GetFQDN(), + }, true) + } }, })