authelia/internal/ntp/ntp.go
yossbg 05406cfc7b
feat(ntp): check clock sync on startup (#2251)
This adds method to validate the system clock is synchronized on startup. Configuration allows adjusting the server address, enabled state, desync limit, and if the error is fatal.

Co-authored-by: James Elliott <james-d-elliott@users.noreply.github.com>
2021-09-17 14:44:35 +10:00

56 lines
1.5 KiB
Go

package ntp
import (
"encoding/binary"
"fmt"
"net"
"time"
"github.com/authelia/authelia/v4/internal/configuration/schema"
"github.com/authelia/authelia/v4/internal/utils"
)
// NewProvider instantiate a ntp provider given a configuration.
func NewProvider(config *schema.NTPConfiguration) *Provider {
return &Provider{config}
}
// StartupCheck checks if the system clock is not out of sync.
func (p *Provider) StartupCheck() (failed bool, err error) {
conn, err := net.Dial("udp", p.config.Address)
if err != nil {
return false, fmt.Errorf("could not connect to NTP server to validate the time desync: %w", err)
}
defer conn.Close()
if err := conn.SetDeadline(time.Now().Add(5 * time.Second)); err != nil {
return false, fmt.Errorf("could not connect to NTP server to validate the time desync: %w", err)
}
version := ntpV4
if p.config.Version == 3 {
version = ntpV3
}
req := &ntpPacket{LeapVersionMode: ntpLeapVersionClientMode(false, version)}
if err := binary.Write(conn, binary.BigEndian, req); err != nil {
return false, fmt.Errorf("could not write to the NTP server socket to validate the time desync: %w", err)
}
now := time.Now()
resp := &ntpPacket{}
if err := binary.Read(conn, binary.BigEndian, resp); err != nil {
return false, fmt.Errorf("could not read from the NTP server socket to validate the time desync: %w", err)
}
maxOffset, _ := utils.ParseDurationString(p.config.MaximumDesync)
ntpTime := ntpPacketToTime(resp)
return ntpIsOffsetTooLarge(maxOffset, now, ntpTime), nil
}