github.com/sagernet/sing@v0.4.0-beta.19.0.20240518125136-f67a0988a636/common/ntp/message.go (about)

     1  // Copyright 2015-2017 Brett Vickers.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package ntp provides an implementation of a Simple NTP (SNTP) client
     6  // capable of querying the current time from a remote NTP server.  See
     7  // RFC5905 (https://tools.ietf.org/html/rfc5905) for more details.
     8  //
     9  // This approach grew out of a go-nuts post by Michael Hofmann:
    10  // https://groups.google.com/forum/?fromgroups#!topic/golang-nuts/FlcdMU5fkLQ
    11  package ntp
    12  
    13  import (
    14  	"errors"
    15  	"fmt"
    16  	"time"
    17  )
    18  
    19  // The LeapIndicator is used to warn if a leap second should be inserted
    20  // or deleted in the last minute of the current month.
    21  type LeapIndicator uint8
    22  
    23  const (
    24  	// LeapNoWarning indicates no impending leap second.
    25  	LeapNoWarning LeapIndicator = 0
    26  
    27  	// LeapAddSecond indicates the last minute of the day has 61 seconds.
    28  	LeapAddSecond = 1
    29  
    30  	// LeapDelSecond indicates the last minute of the day has 59 seconds.
    31  	LeapDelSecond = 2
    32  
    33  	// LeapNotInSync indicates an unsynchronized leap second.
    34  	LeapNotInSync = 3
    35  )
    36  
    37  // Internal constants
    38  const (
    39  	defaultNtpVersion = 4
    40  	nanoPerSec        = 1000000000
    41  	maxStratum        = 16
    42  	defaultTimeout    = 5 * time.Second
    43  	maxPollInterval   = (1 << 17) * time.Second
    44  	maxDispersion     = 16 * time.Second
    45  )
    46  
    47  // Internal variables
    48  var (
    49  	ntpEpoch = time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)
    50  )
    51  
    52  type mode uint8
    53  
    54  // NTP modes. This package uses only client mode.
    55  const (
    56  	reserved mode = 0 + iota
    57  	symmetricActive
    58  	symmetricPassive
    59  	client
    60  	server
    61  	broadcast
    62  	controlMessage
    63  	reservedPrivate
    64  )
    65  
    66  // An ntpTime is a 64-bit fixed-point (Q32.32) representation of the number of
    67  // seconds elapsed.
    68  type ntpTime uint64
    69  
    70  // Duration interprets the fixed-point ntpTime as a number of elapsed seconds
    71  // and returns the corresponding time.Duration value.
    72  func (t ntpTime) Duration() time.Duration {
    73  	sec := (t >> 32) * nanoPerSec
    74  	frac := (t & 0xffffffff) * nanoPerSec
    75  	nsec := frac >> 32
    76  	if uint32(frac) >= 0x80000000 {
    77  		nsec++
    78  	}
    79  	return time.Duration(sec + nsec)
    80  }
    81  
    82  // Time interprets the fixed-point ntpTime as an absolute time and returns
    83  // the corresponding time.Time value.
    84  func (t ntpTime) Time() time.Time {
    85  	return ntpEpoch.Add(t.Duration())
    86  }
    87  
    88  // toNtpTime converts the time.Time value t into its 64-bit fixed-point
    89  // ntpTime representation.
    90  func toNtpTime(t time.Time) ntpTime {
    91  	nsec := uint64(t.Sub(ntpEpoch))
    92  	sec := nsec / nanoPerSec
    93  	nsec = uint64(nsec-sec*nanoPerSec) << 32
    94  	frac := uint64(nsec / nanoPerSec)
    95  	if nsec%nanoPerSec >= nanoPerSec/2 {
    96  		frac++
    97  	}
    98  	return ntpTime(sec<<32 | frac)
    99  }
   100  
   101  // An ntpTimeShort is a 32-bit fixed-point (Q16.16) representation of the
   102  // number of seconds elapsed.
   103  type ntpTimeShort uint32
   104  
   105  // Duration interprets the fixed-point ntpTimeShort as a number of elapsed
   106  // seconds and returns the corresponding time.Duration value.
   107  func (t ntpTimeShort) Duration() time.Duration {
   108  	sec := uint64(t>>16) * nanoPerSec
   109  	frac := uint64(t&0xffff) * nanoPerSec
   110  	nsec := frac >> 16
   111  	if uint16(frac) >= 0x8000 {
   112  		nsec++
   113  	}
   114  	return time.Duration(sec + nsec)
   115  }
   116  
   117  // msg is an internal representation of an NTP packet.
   118  type msg struct {
   119  	LiVnMode       uint8 // Leap Indicator (2) + Version (3) + Mode (3)
   120  	Stratum        uint8
   121  	Poll           int8
   122  	Precision      int8
   123  	RootDelay      ntpTimeShort
   124  	RootDispersion ntpTimeShort
   125  	ReferenceID    uint32
   126  	ReferenceTime  ntpTime
   127  	OriginTime     ntpTime
   128  	ReceiveTime    ntpTime
   129  	TransmitTime   ntpTime
   130  }
   131  
   132  // setVersion sets the NTP protocol version on the message.
   133  func (m *msg) setVersion(v int) {
   134  	m.LiVnMode = (m.LiVnMode & 0xc7) | uint8(v)<<3
   135  }
   136  
   137  // setMode sets the NTP protocol mode on the message.
   138  func (m *msg) setMode(md mode) {
   139  	m.LiVnMode = (m.LiVnMode & 0xf8) | uint8(md)
   140  }
   141  
   142  // setLeap modifies the leap indicator on the message.
   143  func (m *msg) setLeap(li LeapIndicator) {
   144  	m.LiVnMode = (m.LiVnMode & 0x3f) | uint8(li)<<6
   145  }
   146  
   147  // getVersion returns the version value in the message.
   148  func (m *msg) getVersion() int {
   149  	return int((m.LiVnMode >> 3) & 0x07)
   150  }
   151  
   152  // getMode returns the mode value in the message.
   153  func (m *msg) getMode() mode {
   154  	return mode(m.LiVnMode & 0x07)
   155  }
   156  
   157  // getLeap returns the leap indicator on the message.
   158  func (m *msg) getLeap() LeapIndicator {
   159  	return LeapIndicator((m.LiVnMode >> 6) & 0x03)
   160  }
   161  
   162  // A Response contains time data, some of which is returned by the NTP server
   163  // and some of which is calculated by the client.
   164  type Response struct {
   165  	// Time is the transmit time reported by the server just before it
   166  	// responded to the client's NTP query.
   167  	Time time.Time
   168  
   169  	// ClockOffset is the estimated offset of the client clock relative to
   170  	// the server. Add this to the client's system clock time to obtain a
   171  	// more accurate time.
   172  	ClockOffset time.Duration
   173  
   174  	// RTT is the measured round-trip-time delay estimate between the client
   175  	// and the server.
   176  	RTT time.Duration
   177  
   178  	// Precision is the reported precision of the server's clock.
   179  	Precision time.Duration
   180  
   181  	// Stratum is the "stratum level" of the server. The smaller the number,
   182  	// the closer the server is to the reference clock. Stratum 1 servers are
   183  	// attached directly to the reference clock. A stratum value of 0
   184  	// indicates the "kiss of death," which typically occurs when the client
   185  	// issues too many requests to the server in a short period of time.
   186  	Stratum uint8
   187  
   188  	// ReferenceID is a 32-bit identifier identifying the server or
   189  	// reference clock.
   190  	ReferenceID uint32
   191  
   192  	// ReferenceTime is the time when the server's system clock was last
   193  	// set or corrected.
   194  	ReferenceTime time.Time
   195  
   196  	// RootDelay is the server's estimated aggregate round-trip-time delay to
   197  	// the stratum 1 server.
   198  	RootDelay time.Duration
   199  
   200  	// RootDispersion is the server's estimated maximum measurement error
   201  	// relative to the stratum 1 server.
   202  	RootDispersion time.Duration
   203  
   204  	// RootDistance is an estimate of the total synchronization distance
   205  	// between the client and the stratum 1 server.
   206  	RootDistance time.Duration
   207  
   208  	// Leap indicates whether a leap second should be added or removed from
   209  	// the current month's last minute.
   210  	Leap LeapIndicator
   211  
   212  	// MinError is a lower bound on the error between the client and server
   213  	// clocks. When the client and server are not synchronized to the same
   214  	// clock, the reported timestamps may appear to violate the principle of
   215  	// causality. In other words, the NTP server's response may indicate
   216  	// that a message was received before it was sent. In such cases, the
   217  	// minimum error may be useful.
   218  	MinError time.Duration
   219  
   220  	// KissCode is a 4-character string describing the reason for a
   221  	// "kiss of death" response (stratum = 0). For a list of standard kiss
   222  	// codes, see https://tools.ietf.org/html/rfc5905#section-7.4.
   223  	KissCode string
   224  
   225  	// Poll is the maximum interval between successive NTP polling messages.
   226  	// It is not relevant for simple NTP clients like this one.
   227  	Poll time.Duration
   228  }
   229  
   230  // Validate checks if the response is valid for the purposes of time
   231  // synchronization.
   232  func (r *Response) Validate() error {
   233  	// Handle invalid stratum values.
   234  	if r.Stratum == 0 {
   235  		return fmt.Errorf("kiss of death received: %s", r.KissCode)
   236  	}
   237  	if r.Stratum >= maxStratum {
   238  		return errors.New("invalid stratum in response")
   239  	}
   240  
   241  	// Handle invalid leap second indicator.
   242  	if r.Leap == LeapNotInSync {
   243  		return errors.New("invalid leap second")
   244  	}
   245  
   246  	// Estimate the "freshness" of the time. If it exceeds the maximum
   247  	// polling interval (~36 hours), then it cannot be considered "fresh".
   248  	freshness := r.Time.Sub(r.ReferenceTime)
   249  	if freshness > maxPollInterval {
   250  		return errors.New("server clock not fresh")
   251  	}
   252  
   253  	// Calculate the peer synchronization distance, lambda:
   254  	//  	lambda := RootDelay/2 + RootDispersion
   255  	// If this value exceeds MAXDISP (16s), then the time is not suitable
   256  	// for synchronization purposes.
   257  	// https://tools.ietf.org/html/rfc5905#appendix-A.5.1.1.
   258  	lambda := r.RootDelay/2 + r.RootDispersion
   259  	if lambda > maxDispersion {
   260  		return errors.New("invalid dispersion")
   261  	}
   262  
   263  	// If the server's transmit time is before its reference time, the
   264  	// response is invalid.
   265  	if r.Time.Before(r.ReferenceTime) {
   266  		return errors.New("invalid time reported")
   267  	}
   268  
   269  	// nil means the response is valid.
   270  	return nil
   271  }
   272  
   273  // parseTime parses the NTP packet along with the packet receive time to
   274  // generate a Response record.
   275  func parseTime(m *msg, recvTime ntpTime) *Response {
   276  	r := &Response{
   277  		Time:           m.TransmitTime.Time(),
   278  		ClockOffset:    offset(m.OriginTime, m.ReceiveTime, m.TransmitTime, recvTime),
   279  		RTT:            rtt(m.OriginTime, m.ReceiveTime, m.TransmitTime, recvTime),
   280  		Precision:      toInterval(m.Precision),
   281  		Stratum:        m.Stratum,
   282  		ReferenceID:    m.ReferenceID,
   283  		ReferenceTime:  m.ReferenceTime.Time(),
   284  		RootDelay:      m.RootDelay.Duration(),
   285  		RootDispersion: m.RootDispersion.Duration(),
   286  		Leap:           m.getLeap(),
   287  		MinError:       minError(m.OriginTime, m.ReceiveTime, m.TransmitTime, recvTime),
   288  		Poll:           toInterval(m.Poll),
   289  	}
   290  
   291  	// Calculate values depending on other calculated values
   292  	r.RootDistance = rootDistance(r.RTT, r.RootDelay, r.RootDispersion)
   293  
   294  	// If a kiss of death was received, interpret the reference ID as
   295  	// a kiss code.
   296  	if r.Stratum == 0 {
   297  		r.KissCode = kissCode(r.ReferenceID)
   298  	}
   299  
   300  	return r
   301  }
   302  
   303  // The following helper functions calculate additional metadata about the
   304  // timestamps received from an NTP server.  The timestamps returned by
   305  // the server are given the following variable names:
   306  //
   307  //   org = Origin Timestamp (client send time)
   308  //   rec = Receive Timestamp (server receive time)
   309  //   xmt = Transmit Timestamp (server reply time)
   310  //   dst = Destination Timestamp (client receive time)
   311  
   312  func rtt(org, rec, xmt, dst ntpTime) time.Duration {
   313  	// round trip delay time
   314  	//   rtt = (dst-org) - (xmt-rec)
   315  	a := dst.Time().Sub(org.Time())
   316  	b := xmt.Time().Sub(rec.Time())
   317  	rtt := a - b
   318  	if rtt < 0 {
   319  		rtt = 0
   320  	}
   321  	return rtt
   322  }
   323  
   324  func offset(org, rec, xmt, dst ntpTime) time.Duration {
   325  	// local clock offset
   326  	//   offset = ((rec-org) + (xmt-dst)) / 2
   327  	a := rec.Time().Sub(org.Time())
   328  	b := xmt.Time().Sub(dst.Time())
   329  	return (a + b) / time.Duration(2)
   330  }
   331  
   332  func minError(org, rec, xmt, dst ntpTime) time.Duration {
   333  	// Each NTP response contains two pairs of send/receive timestamps.
   334  	// When either pair indicates a "causality violation", we calculate the
   335  	// error as the difference in time between them. The minimum error is
   336  	// the greater of the two causality violations.
   337  	var error0, error1 ntpTime
   338  	if org >= rec {
   339  		error0 = org - rec
   340  	}
   341  	if xmt >= dst {
   342  		error1 = xmt - dst
   343  	}
   344  	if error0 > error1 {
   345  		return error0.Duration()
   346  	}
   347  	return error1.Duration()
   348  }
   349  
   350  func rootDistance(rtt, rootDelay, rootDisp time.Duration) time.Duration {
   351  	// The root distance is:
   352  	// 	the maximum error due to all causes of the local clock
   353  	//	relative to the primary server. It is defined as half the
   354  	//	total delay plus total dispersion plus peer jitter.
   355  	//	(https://tools.ietf.org/html/rfc5905#appendix-A.5.5.2)
   356  	//
   357  	// In the reference implementation, it is calculated as follows:
   358  	//	rootDist = max(MINDISP, rootDelay + rtt)/2 + rootDisp
   359  	//			+ peerDisp + PHI * (uptime - peerUptime)
   360  	//			+ peerJitter
   361  	// For an SNTP client which sends only a single packet, most of these
   362  	// terms are irrelevant and become 0.
   363  	totalDelay := rtt + rootDelay
   364  	return totalDelay/2 + rootDisp
   365  }
   366  
   367  func toInterval(t int8) time.Duration {
   368  	switch {
   369  	case t > 0:
   370  		return time.Duration(uint64(time.Second) << uint(t))
   371  	case t < 0:
   372  		return time.Duration(uint64(time.Second) >> uint(-t))
   373  	default:
   374  		return time.Second
   375  	}
   376  }
   377  
   378  func kissCode(id uint32) string {
   379  	isPrintable := func(ch byte) bool { return ch >= 32 && ch <= 126 }
   380  
   381  	b := []byte{
   382  		byte(id >> 24),
   383  		byte(id >> 16),
   384  		byte(id >> 8),
   385  		byte(id),
   386  	}
   387  	for _, ch := range b {
   388  		if !isPrintable(ch) {
   389  			return ""
   390  		}
   391  	}
   392  	return string(b)
   393  }