80 lines
2.0 KiB
Go
80 lines
2.0 KiB
Go
package ntp
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
|
"github.com/authelia/authelia/v4/internal/logging"
|
|
)
|
|
|
|
// NewProvider instantiate a ntp provider given a configuration.
|
|
func NewProvider(config *schema.NTP) *Provider {
|
|
return &Provider{
|
|
config: config,
|
|
log: logging.Logger(),
|
|
}
|
|
}
|
|
|
|
// StartupCheck implements the startup check provider interface.
|
|
func (p *Provider) StartupCheck() (err error) {
|
|
var offset time.Duration
|
|
|
|
if offset, err = p.GetOffset(); err != nil {
|
|
p.log.WithError(err).Warnf("Could not determine the clock offset due to an error")
|
|
|
|
return nil
|
|
}
|
|
|
|
if offset > p.config.MaximumDesync {
|
|
return errors.New("the system clock is not synchronized accurately enough with the configured NTP server")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetOffset returns the current offset for this provider.
|
|
func (p *Provider) GetOffset() (offset time.Duration, err error) {
|
|
var conn net.Conn
|
|
|
|
if conn, err = net.Dial(p.config.Address.Network(), p.config.Address.NetworkAddress()); err != nil {
|
|
return offset, fmt.Errorf("error occurred during dial: %w", err)
|
|
}
|
|
|
|
defer func() {
|
|
if closeErr := conn.Close(); closeErr != nil {
|
|
p.log.WithError(err).Error("Error occurred closing connection with NTP sever")
|
|
}
|
|
}()
|
|
|
|
if err = conn.SetDeadline(time.Now().Add(5 * time.Second)); err != nil {
|
|
return offset, fmt.Errorf("error occurred setting connection deadline: %w", err)
|
|
}
|
|
|
|
version := ntpV4
|
|
if p.config.Version == 3 {
|
|
version = ntpV3
|
|
}
|
|
|
|
req := &ntpPacket{LeapVersionMode: ntpLeapVersionClientMode(version)}
|
|
|
|
if err = binary.Write(conn, binary.BigEndian, req); err != nil {
|
|
return offset, fmt.Errorf("error occurred writing ntp packet request to the connection: %w", err)
|
|
}
|
|
|
|
now := time.Now()
|
|
|
|
resp := &ntpPacket{}
|
|
|
|
if err = binary.Read(conn, binary.BigEndian, resp); err != nil {
|
|
return offset, fmt.Errorf("error occurred reading ntp packet response to the connection: %w", err)
|
|
}
|
|
|
|
ntpTime := ntpPacketToTime(resp)
|
|
|
|
return calcOffset(now, ntpTime), nil
|
|
}
|