NTP users are strongly urged to take immediate action to ensure that their NTP daemons are not susceptible to being used in distributed denial-of-service (DDoS) attacks. Please also take this opportunity to defeat denial-of-service attacks by implementing Ingress and Egress filtering through BCP38. See RefidFormatDev for discussion of this topic.
ntp-4.2.8p15 was released on 23 June 2020. It addresses 1 medium-severity security issue in ntpd, and provides 13 non-security bugfixes over 4.2.8p13.
Are you using Autokey in production? If so, please contact Harlan - he's got some questions for you.
8.1. REFID Format
Related Topics: Bug #278
command of the
utility (also available using the
command) includes the Refid of each time source in the second column of the output.
In the packet of data exchanged between the
process and the server, the Refid is represented as a four-byte data field.
then translates this value into a string for display as follows:
- If the associated time source has a stratum of 0, the bytes represent a
- If the associated time source has a stratum of 1, the bytes are converted to their ASCII representation, and the resulting up-to-four-character string is printed with leading and trailing period characters. Thus, the refid will indicate the type of reference clock, e.g.
- If the associated time source has a stratum > 1, the four bytes are treated as an IPv4 address and printed in dotted-quad notation, e.g.
Note that if the time source has stratum > 1, the Refid it sends to the client will be related to the server to which that source itself is synchronized. The value is intended to be a unique identifier for a particular time server and is used to allow detection of timing loops.
Historically, the Refid sent was simply the (IPv4) address used to reach the synchronization server.
Recent versions of ntpd can instead use an IPv6 address to reach the synchronization server. Since IPv6 addresses don't fit into four bytes, ntpd "compresses" those address by using the first four bytes of the (binary) md5 digest of the IPv6 address as the Refid value.
has no way to know which type of Refid the server is sending and always displays the Refid value in dotted-quad format -- which means that any IPv6 Refids will be listed as if they were IPv4 addresses, even though they are not.
Starting with versions 4.2.8p3 and 4.3.41,
command which lists the Refid as an 8-character hexidecimal number, with no punctuation, instead of as a dotted quad. Other than the difference in representation, the two commands treat Refids in the same way.
Starting with 4.2.8.p3 and 4.3.47, if leap-smearing is underway, the ntpd server will generate a special Refid for itself, where the first byte will be "254", and the other three bytes will contain 24 encoded bits of the current smear value. Currently ntpq does not recognize this as being special, and simply reports the value as if it were an IPv4 number (but since the 254.0.0.0 network is in a reserved range, such a value should never occur as an actual Refid). Once the leap smear period is over, the ntpd will return to using its usual Refid. For more information see the README.leapsmear file.
There is some ongoing discussion about updating the Refid display format in UpdatingTheRefidFormat
The explanation of the Refid field values can be found in the RFCs:
Common Variables section of RFC1305
Packet Header Variables section of RFC5904
8.1.2. Example Code for Generating IPv6 Refids.
The following simple Python code can be used to generate Refids that match the ones NTP would use for IPv6 addresses (e.g. to confirm that the value displayed in an
listing does indeed match a particular upstream server).
# returns the refid string that NTP would use for the given IPv6 address
# (passed in string form)
# * first, convert passed string to a packed binary representation of
# the IPv6 addr
# * the NTP refid is the first four bytes of the md5 digest (in binary
# form) generated from the binary v6 address, expressed as an IPv4
# dotted-quad IP number
# reformats the input dotted-quad IP number (a string) into an 8-character
# hex representation of those four bytes (with no punctuation)
return 4*"%02x" % tuple(map(int, ipv4.split(".")))
# reformats a hex string into a dotted-quad-format string.
# (First, split the string into two-character chunks, then interpret each of those
# chunks as a base-16 integer, then convert back to a (base-10) string
# representation, and finally join those strings with period between them.
# [No input validation is done, so if the input isn't 8 hex characters the output
# will not actually be a four-byte dotted-quad address....])
return ".".join(map(lambda x:str(int(x,16)),re.findall("..",hex)))
# print the NTP refid that would be used for each IP address associated
# with the given hostname
print "NTP Refid HexRefid (addr type)"
for a in addrinfo_list:
# for each tuple "a", a is the address family, and a is a
# sockaddr tuple, where a is the string representation
# of the ip address.
if a == socket.AF_INET6:
print "%-16s" % refid, ipv4_to_hex(refid), " (IPv6: " + ip + ")"
if a == socket.AF_INET:
print "%-16s" % ip, ipv4_to_hex(ip), " (IPv4)"
So, for example, after starting a Python interactive session and cutting-and-pasting the above lines into the command prompt, one can view the Refids would be used for both types of addresses assigned to the
time server by running:
NTP Refid HexRefid (addr type)
220.127.116.11 9191ddfc (IPv6: 2607:f248::45)
18.104.22.168 d8e4c045 (IPv4)