RFC 9327

Control Messages Protocol for Use with Network Time Protocol Version 4

πŸ“… published November 2022, from ietf

RFC 9327: Control Messages Protocol for Use with Network Time Protocol Version 4 πŸŽ€

okay bestie, here are the key facts from the title block so you know what you're getting into πŸ’…

  • Authors: B. Haberman, Ed. (JHU)
  • Stream: Internet Engineering Task Force (IETF) πŸ¦‹
  • Category: Historic πŸ“œ
  • Date: November 2022
  • ISSN: 2070-1721
  • Obsoletes / Updates: the header doesn't list anything it obsoletes or updates

Abstract ✨

this doc describes the structure of the control messages NTP used historically, back before fancier control and management tools existed. πŸ•°οΈ these messages let people monitor and control the NTP application on any computer that's attached to an IP network. the original description lived in Appendix B of RFC 1305. the goal here is to give an updated version of those control messages so they line up with the updated NTP spec in RFC 5905. πŸ’–

publishing this doc does not mean anyone should go build and roll out these control messages. it's just a current reference for them, since RFC 1305 is where things stand right now. πŸ™ˆ

Status of This Memo πŸ“œ

this isn't an Internet Standards Track spec. it's published for the historical record, so it's a Historic Document for the Internet community. 🌸 it's a product of the IETF, it reflects IETF consensus, it got public review, and the IESG approved it. not every IESG-approved doc is a candidate for any level of Internet Standard, so see Section 2 of RFC 7841 for that. 🧐

for the current status, any errata, and how to send feedback, check https://www.rfc-editor.org/info/rfc9327. πŸ”—

Copyright (c) 2022 IETF Trust and the persons identified as the document authors. All rights reserved. πŸ”’

this doc is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they were in effect on the publication date. please read those carefully, because they spell out your rights and restrictions for this document. Code Components pulled out of this doc must include Revised BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they come without warranty, same as the Revised BSD License says. πŸ’…

this doc may contain material from IETF Documents or IETF Contributions published or made publicly available before November 10, 2008. the people who control the copyright in some of that material may not have given the IETF Trust permission to allow modifications outside the IETF Standards Process. so unless you've got an adequate license from those copyright holders, this doc may not be modified outside the IETF Standards Process, and derivative works of it may not be created outside the IETF Standards Process. the exceptions are formatting it for publication as an RFC or translating it into languages other than English. 🌈

Table of Contents πŸ—‚οΈ

1.  Introduction
  1.1.  Terminology
  1.2.  Control Message Overview
  1.3.  Remote Facility Message Overview
2.  NTP Control Message Format
3.  Status Words
  3.1.  System Status Word
  3.2.  Peer Status Word
  3.3.  Clock Status Word
  3.4.  Error Status Word
4.  Commands
5.  IANA Considerations
6.  Security Considerations
7.  References
  7.1.  Normative References
  7.2.  Informative References
Appendix A.  NTP Remote Facility Message Format
Acknowledgements
Contributors
Author's Address

1. Introduction 🧚

okay so [RFC1305] describes a set of control messages for use within the Network Time Protocol (NTP) back when a full network management solution wasn't around. πŸ•°οΈ those control message definitions never got promoted into [RFC5905] when NTP version 4 was documented. these messages were meant only for systems that had no other management options, like dedicated-function bus peripherals. πŸ”§ support for them isn't required to conform to [RFC5905]. this doc describes them as a current reference for use with an NTP implementation from RFC 5905. πŸ’œ

again, publishing this doc isn't meant to encourage anyone to develop and deploy these control messages. it's only a current reference, given where RFC 1305 stands today. 🌸

1.1. Terminology πŸ“–

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

1.2. Control Message Overview πŸŽ€

the NTP mode 6 control messages are used by NTP management programs (e.g., ntpq) when a more robust network management facility (e.g., SNMP) isn't available. 🫢 these control messages give you rudimentary control and monitoring functions for managing a running NTP server. they aren't designed for communication between running NTP servers, so no swapping notes between servers, sorry πŸ™ˆ

the NTP control message has the value 6 in the mode field of the first octet of the NTP header, and it's formatted as shown in Figure 1. the data field format depends on each command or response, but most of the time it's designed to be built and read by humans, so it's coded in free-form ASCII. ✨ that makes it way easier to write and implement simple management tools when fully evolved network-management facilities aren't around. as in ordinary NTP messages, the authenticator field comes after the data field. if the authenticator is used, the data field gets zero-padded to a 32-bit boundary. the padding bits aren't counted as part of the data field and aren't included in the field count. πŸ’…

IP hosts aren't required to reassemble datagrams over a certain size (576 octets for IPv4 [RFC0791] and 1280 octets for IPv6 [RFC8200]). still, some commands or responses may involve more data than fits in a single datagram. πŸ“¦ so there's a simple reassembly feature where every octet of the message data is numbered, starting from zero. as each fragment goes out, the number of its first octet goes in the offset field, and the number of octets goes in the count field. the more-data (M) bit is set in every fragment except the last one. 🧩

most control functions involve sending a command and getting a response, sometimes split across several fragments. the sender picks a distinct, nonzero sequence number and sets the status field, the "R" bit, and the "E" bit to zero. 🌱 the responder interprets the opcode and the extra info in the data field, updates the status field, sets the "R" bit to one, and sends back the three 32-bit words of the header along with extra info in the data field. if the message format or contents are invalid, the responder puts a code in the status field, sets the "R" and "E" bits to one, and can optionally include a diagnostic message in the data field. 🚨

some commands read or write system variables (e.g., s.offset) and peer variables (e.g., p.stratum) for an association named in the command. others read or write variables tied to a radio clock or another device directly connected to a source of primary synchronization information. πŸ“‘ to tell which type of variable and association you mean, there's the Association ID. system variables are marked with the identifier zero. when each association gets mobilized, it's given a unique, nonzero identifier. these identifiers get reused in a cyclic fashion, so the chance of accidentally hitting an old identifier that matches a newly created association is remote. πŸ” a management entity can ask for a list of current identifiers and then use them to read and write variables for each association. if you try to use an expired identifier, you get an exception response, and after that you can request the list again. πŸ™ƒ

some exception events, like a peer becoming reachable or unreachable, happen spontaneously and aren't necessarily tied to a command. 🚦 an implementation can choose to save the event info for later retrieval, to send an asynchronous response (called a trap), or both. for a trap, the IP address and port number come from a previous command, and the sequence field is set as described below. the current status and summary info for the latest exception event goes into all normal responses. bits in the status field show whether an exception has happened since the last response and whether more than one exception has happened. πŸ‘€

commands don't have to come from an NTP peer, so ordinary access-control procedures may not apply. πŸ›‘οΈ however, the optional mask/match mechanism suggested in Section 6 lets you control access by mode number, so you could use it to limit control messages (mode 6) to selected address ranges. πŸ’œ

1.3. Remote Facility Message Overview πŸ¦‹

the original NTP daemon came with a Remote Facility for monitoring and configuration. πŸ› οΈ this facility used mode 7 commands to talk to the NTP daemon. this doc only illustrates the mode 7 packet format. the commands inside mode 7 messages are implementation specific and aren't standardized in any way, so don't go looking for them in the spec πŸ™ƒ the mode 7 message format is described in Appendix A. ✨

2. NTP Control Message Format ✨

okay so this is where the NTP Control Message header lives, right after the UDP header πŸŽ€ it's giving layout energy. Figure 1 shows the whole thing, and then we go field by field πŸ’…

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |LI |  VN |Mode |R|E|M| opcode  |       Sequence Number         |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |            Status             |       Association ID          |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |            Offset             |            Count              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                                                               |
     /                    Data (up to 468 bytes)                     /
     |                                                               |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                    Padding (optional)                         |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                                                               |
     /              Authenticator (optional, 20 or 24 bits)          /
     |                                                               |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 1: NTP Control Message Header

Leap Indicator (LI): This is a 2-bit integer that is set to b00 for control message requests and responses. The Leap Indicator value used at this position in most NTP modes is in the system status word provided in some control message responses.

Version Number (VN): This is a 3-bit integer indicating a minimum NTP version number. NTP servers do not respond to control messages with an unrecognized version number. Requests may intentionally use a lower version number to enable interoperability with earlier versions of NTP. Responses carry the same version as the corresponding request. 🫢

Mode: This is a 3-bit integer indicating the mode. The value 6 indicates an NTP control message.

Response Bit (R): Set to zero for commands; set to one for responses.

Error Bit (E): Set to zero for normal responses; set to one for an error response.

More Bit (M): Set to zero for the last fragment; set to one for all others.

Operation Code (opcode): This is a 5-bit integer specifying the command function. Values currently defined include the following: πŸ”₯

  +=======+================================================+
  | Code  | Meaning                                        |
  +=======+================================================+
  | 0     | reserved                                       |
  +-------+------------------------------------------------+
  | 1     | read status command/response                   |
  +-------+------------------------------------------------+
  | 2     | read variables command/response                |
  +-------+------------------------------------------------+
  | 3     | write variables command/response               |
  +-------+------------------------------------------------+
  | 4     | read clock variables command/response          |
  +-------+------------------------------------------------+
  | 5     | write clock variables command/response         |
  +-------+------------------------------------------------+
  | 6     | set trap address/port command/response         |
  +-------+------------------------------------------------+
  | 7     | trap response                                  |
  +-------+------------------------------------------------+
  | 8     | runtime configuration command/response         |
  +-------+------------------------------------------------+
  | 9     | export configuration to file command/response  |
  +-------+------------------------------------------------+
  | 10    | retrieve remote address stats command/response |
  +-------+------------------------------------------------+
  | 11    | retrieve ordered list command/response         |
  +-------+------------------------------------------------+
  | 12    | request client-specific nonce command/response |
  +-------+------------------------------------------------+
  | 13-30 | reserved                                       |
  +-------+------------------------------------------------+
  | 31    | unset trap address/port command/response       |
  +-------+------------------------------------------------+

Table 1: Operation Codes

Sequence Number: This is a 16-bit integer indicating the sequence number of the command or response. Each request uses a different sequence number. Each response carries the same sequence number as its corresponding request. For asynchronous trap responses, the responder increments the sequence number by one for each response, allowing trap receivers to detect missing trap responses. The sequence number of each fragment of a multiple-datagram response carries the same sequence number, copied from the request. πŸ¦‹

Status: This is a 16-bit code indicating the current status of the system, peer, or clock with values coded as described in following sections.

Association ID: This is a 16-bit unsigned integer identifying a valid association or zero for the system clock.

Offset: This is a 16-bit unsigned integer indicating the offset, in octets, of the first octet in the data area. The offset is set to zero in requests. Responses spanning multiple datagrams use a positive offset in all but the first datagram.

Count: This is a 16-bit unsigned integer indicating the length of the data field, in octets.

Data: This contains the message data for the command or response. The maximum number of data octets is 468.

Padding (optional): Contains zero to 3 octets with a value of zero, as needed to ensure the overall control message size is a multiple of 4 octets.

Authenticator (optional): When the NTP authentication mechanism is implemented, this contains the authenticator information defined in Appendix C of [RFC1305].


3. Status Words ✨

okay so status words are how the system, its associations, and the clock show off their current vibe πŸ’– they're built for network-monitoring programs to read, and they come in one of four 16-bit formats, shown in Figure 2 and described here. 🌸

System and peer status words go with responses for all commands except the read clock variables, write clock variables, and set trap address/port commands. The association identifier zero picks the system status word, while a nonzero identifier picks out a particular peer association. The status word returned for read clock variables and write clock variables commands tells you the state of the clock hardware and decoding software. And if something's malformed or a value is invalid, a special error status word gets used to report it. πŸ™ˆ

                      0                   1
                      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                     | LI| Clock Src | Count | Code  |
                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                            System Status Word

                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                     |  Status | SEL | Count | Code  |
                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                             Peer Status Word

                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                     | Clock Status  |    Code       |
                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                             Radio Status Word

                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                     |   Error Code  |   Reserved    |
                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                             Error Status Word

                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                     |   Reserved    | Count | Code  |
                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                             Clock Status Word

                       Figure 2: Status Word Formats

3.1. System Status Word ✨

okay so the system status word is the thing that shows up in the status field when you send a read status or read variables command with a zero association identifier πŸŽ€ that's the only time it pops up, so don't expect it anywhere else bestie πŸ’… here's how it's laid out:

Leap Indicator (LI): this is a 2-bit code that gives you a heads up about an upcoming leap second, which gets inserted or deleted in the last minute of the current day πŸ•°οΈ bit 0 and bit 1 are coded like this:

+====+=================================================+
| LI | Meaning                                         |
+====+=================================================+
| 00 | no warning                                      |
+----+-------------------------------------------------+
| 01 | insert second after 23:59:59 of the current day |
+----+-------------------------------------------------+
| 10 | delete second 23:59:59 of the current day       |
+----+-------------------------------------------------+
| 11 | unsynchronized                                  |
+----+-------------------------------------------------+

              Table 2: Leap Indicator Codes

Clock Source (Clock Src): this one is a 6-bit integer that tells you what the current synchronization source is πŸ›°οΈ the values go like this:

+=======+========================================================+
| Code  | Meaning                                                |
+=======+========================================================+
| 0     | unspecified or unknown                                 |
+-------+--------------------------------------------------------+
| 1     | Calibrated atomic clock (e.g., PPS, HP 5061)           |
+-------+--------------------------------------------------------+
| 2     | VLF (band 4) or LF (band 5) radio (e.g., OMEGA,, WWVB) |
+-------+--------------------------------------------------------+
| 3     | HF (band 7) radio (e.g., CHU, MSF, WWV/H)              |
+-------+--------------------------------------------------------+
| 4     | UHF (band 9) satellite (e.g., GOES, GPS)               |
+-------+--------------------------------------------------------+
| 5     | local net (e.g., DCN, TSP, DTS)                        |
+-------+--------------------------------------------------------+
| 6     | UDP/NTP                                                |
+-------+--------------------------------------------------------+
| 7     | UDP/TIME                                               |
+-------+--------------------------------------------------------+
| 8     | eyeball-and-wristwatch                                 |
+-------+--------------------------------------------------------+
| 9     | telephone modem (e.g., NIST)                           |
+-------+--------------------------------------------------------+
| 10-63 | reserved                                               |
+-------+--------------------------------------------------------+

                 Table 3: Clock Source Values

System Event Counter (Count): this is a 4-bit integer that counts how many system events have happened since the System Event Code last changed πŸ“Š once it hits 15, any further events with that same code stop getting counted πŸ™ˆ

System Event Code (Code): this is a 4-bit integer that tells you the latest system exception event 🚨 new values overwrite the old ones, and the codes are:

+======+============================================================+
| Code | Meaning                                                    |
+======+============================================================+
| 0    | unspecified                                                |
+------+------------------------------------------------------------+
| 1    | frequency correction (drift) file not available            |
+------+------------------------------------------------------------+
| 2    | frequency correction started (frequency stepped)           |
+------+------------------------------------------------------------+
| 3    | spike detected and ignored, starting stepout timer         |
+------+------------------------------------------------------------+
| 4    | frequency training started                                 |
+------+------------------------------------------------------------+
| 5    | clock synchronized                                         |
+------+------------------------------------------------------------+
| 6    | system restart                                             |
+------+------------------------------------------------------------+
| 7    | panic stop (required step greater than panic threshold)    |
+------+------------------------------------------------------------+
| 8    | no system peer                                             |
+------+------------------------------------------------------------+
| 9    | leap second insertion/deletion armed for the current       |
|      | month                                                      |
+------+------------------------------------------------------------+
| 10   | leap second disarmed                                       |
+------+------------------------------------------------------------+
| 11   | leap second inserted or deleted                            |
+------+------------------------------------------------------------+
| 12   | clock stepped (stepout timer expired)                      |
+------+------------------------------------------------------------+
| 13   | kernel loop discipline status changed                      |
+------+------------------------------------------------------------+
| 14   | leapseconds table loaded from file                         |
+------+------------------------------------------------------------+
| 15   | leapseconds table outdated, updated file needed            |
+------+------------------------------------------------------------+

                  Table 4: System Event Codes

3.2. Peer Status Word

A peer status word is returned in the status field of a response to a read status, read variables, or write variables command. It also shows up in the list of Association IDs and status words that comes back from a read status command with a zero Association ID. Here's the layout πŸ’…βœ¨

Peer Status (Status): This is a 5-bit code that tells you the status of the peer, as worked out by the packet procedure. The bits are assigned like this 🫢

+=================+==========================================+
| Peer Status bit | Meaning                                  |
+=================+==========================================+
| 0               | configured (peer.config)                 |
+-----------------+------------------------------------------+
| 1               | authentication enabled (peer.authenable) |
+-----------------+------------------------------------------+
| 2               | authentication okay (peer.authentic)     |
+-----------------+------------------------------------------+
| 3               | reachability okay (peer.reach != 0)      |
+-----------------+------------------------------------------+
| 4               | broadcast association                    |
+-----------------+------------------------------------------+

                  Table 5: Peer Status Bits

Peer Selection (SEL): This is a 3-bit integer that shows the status of the peer as decided by the clock-selection procedure. The values are coded like so 🌸

+=====+=======================================================+
| Sel | Meaning                                               |
+=====+=======================================================+
| 0   | rejected                                              |
+-----+-------------------------------------------------------+
| 1   | discarded by intersection algorithm                   |
+-----+-------------------------------------------------------+
| 2   | discarded by table overflow (not currently used)      |
+-----+-------------------------------------------------------+
| 3   | discarded by the cluster algorithm                    |
+-----+-------------------------------------------------------+
| 4   | included by the combine algorithm                     |
+-----+-------------------------------------------------------+
| 5   | backup source (with more than sys.maxclock survivors) |
+-----+-------------------------------------------------------+
| 6   | system peer (synchronization source)                  |
+-----+-------------------------------------------------------+
| 7   | PPS (pulse per second) peer                           |
+-----+-------------------------------------------------------+

                 Table 6: Peer Selection Values

Peer Event Counter (Count): This is a 4-bit integer that counts how many peer exception events have happened since the peer event code last changed. Once it hits 15, any further events with that same code don't get counted. It's giving counter cap 🧚

Peer Event Code (Code): This is a 4-bit integer that identifies the latest peer exception event. New values overwrite the old ones, and they're coded as follows πŸŽ€

+=================+===================================+
| Peer Event Code | Meaning                           |
+=================+===================================+
| 0               | unspecified                       |
+-----------------+-----------------------------------+
| 1               | association mobilized             |
+-----------------+-----------------------------------+
| 2               | association demobilized           |
+-----------------+-----------------------------------+
| 3               | peer unreachable (peer.reach was  |
|                 | nonzero now zero)                 |
+-----------------+-----------------------------------+
| 4               | peer reachable (peer.reach was    |
|                 | zero now nonzero)                 |
+-----------------+-----------------------------------+
| 5               | association restarted or timed    |
|                 | out                               |
+-----------------+-----------------------------------+
| 6               | no reply (only used with one-shot |
|                 | clock set command)                |
+-----------------+-----------------------------------+
| 7               | peer rate limit exceeded (kiss    |
|                 | code RATE received)               |
+-----------------+-----------------------------------+
| 8               | access denied (kiss code DENY     |
|                 | received)                         |
+-----------------+-----------------------------------+
| 9               | leap second insertion/deletion at |
|                 | month's end armed by peer vote    |
+-----------------+-----------------------------------+
| 10              | became system peer (sys.peer)     |
+-----------------+-----------------------------------+
| 11              | reference clock event (see clock  |
|                 | status word)                      |
+-----------------+-----------------------------------+
| 12              | authentication failed             |
+-----------------+-----------------------------------+
| 13              | popcorn spike suppressed by peer  |
|                 | clock filter register             |
+-----------------+-----------------------------------+
| 14              | entering interleaved mode         |
+-----------------+-----------------------------------+
| 15              | recovered from interleave error   |
+-----------------+-----------------------------------+

              Table 7: Peer Event Code Values

3.3. Clock Status Word

There are two ways a reference clock can hook up to an NTP service host. One is a dedicated device managed by the operating system, and the other is a synthetic peer managed by NTP πŸ’– The Association ID is what tells you which variable belongs to which clock, same as in the read status command: zero for the system clock and nonzero for a peer clock. Only one system clock is supported by the protocol, but lots of peer clocks can be supported πŸ¦‹ A system or peer clock status word shows up in the status field of the response to a read clock variables or write clock variables command. You can think of this word as an extension of the system status word or the peer status word, whichever fits. Here's the format of the clock status word 🌈

Reserved: This is an 8-bit integer that requesters ignore and responders zero out.

Count: This is a 4-bit integer that counts how many clock events have happened since the clock event code last changed. Once it reaches 15, further events with the same code aren't counted.

Clock Code (Code): This is a 4-bit integer that shows the current clock status, with values coded as follows ⭐

+==============+=================================+
| Clock Status | Meaning                         |
+==============+=================================+
| 0            | clock operating within nominals |
+--------------+---------------------------------+
| 1            | reply timeout                   |
+--------------+---------------------------------+
| 2            | bad reply format                |
+--------------+---------------------------------+
| 3            | hardware or software fault      |
+--------------+---------------------------------+
| 4            | propagation failure             |
+--------------+---------------------------------+
| 5            | bad date format or value        |
+--------------+---------------------------------+
| 6            | bad time format or value        |
+--------------+---------------------------------+
| 7-15         | reserved                        |
+--------------+---------------------------------+

                    Table 8: Clock Code Values

3.4. Error Status Word

An error status word comes back in the status field of an error response, which happens when the message format or contents are invalid. You'll know it's there when the E (error) bit is set along with the response (R) bit in the response. It's an 8-bit integer coded as follows πŸ™ˆ

+==============+==================================+
| Error Status | Meaning                          |
+==============+==================================+
| 0            | unspecified                      |
+--------------+----------------------------------+
| 1            | authentication failure           |
+--------------+----------------------------------+
| 2            | invalid message length or format |
+--------------+----------------------------------+
| 3            | invalid opcode                   |
+--------------+----------------------------------+
| 4            | unknown Association ID           |
+--------------+----------------------------------+
| 5            | unknown variable name            |
+--------------+----------------------------------+
| 6            | invalid variable value           |
+--------------+----------------------------------+
| 7            | administratively prohibited      |
+--------------+----------------------------------+
| 8-255        | reserved                         |
+--------------+----------------------------------+

                  Table 9: Error Status Word Codes

4. Commands πŸŽ€

okay bestie, so a command is basically the header plus an optional data field, see Figure 1 ✨. when the data field is there, it holds a list of identifiers or assignments that look like this:

<<identifier>>[=<<value>>],<<identifier>>[=<<value>>],...

The <<identifier>> is the ASCII name of a system or peer variable, like the ones in RFC 5905, and <<value>> is a decimal, hexadecimal, or string constant written in C syntax πŸ’…. If there's no ambiguity, you can drop the sys. or peer. prefixes. You can also add spaces (ASCII nonprinting format effectors) to make things easier to read for simple monitoring programs that don't reformat the data field 🫢.

Here are the representations you should know about:

  • IPv4 internet addresses are written in the form [n.n.n.n], where n is in decimal notation and the brackets are optional πŸ¦‹
  • IPv6 internet addresses are formulated based on the guidelines defined in [RFC5952] 🌈
  • Timestamps (including reference, originate, receive, and transmit values) and the logical clock are represented in units of seconds and fractions, preferably in hexadecimal notation ⭐
  • Delay, offset, dispersion, and distance values are represented in units of milliseconds and fractions, preferably in decimal notation 🧚
  • All other values are represented as is, preferably in decimal notation πŸ“

Implementations may define variables other than those described in RFC 5905. These are called "extramural variables", and you can spot them because their name includes some character type other than alphanumeric or "." πŸ‘€. For commands that return a list of assignments in the response data field, if the command data field is empty, it is expected that all available variables defined in RFC 5905 will be included in the response. For the read commands, if the command data field is nonempty, an implementation may choose to process this field to individually select which variables are returned πŸ’œ.

Okay, here's how each command is interpreted πŸ‘‘:

Read Status (1):

The command data field is empty or contains a list of identifiers separated by commas. This command works in two ways depending on the value of the Association ID. If this identifier is nonzero, the response includes the peer identifier and status word. Optionally, the response data field may contain other information, such as described in the Read Variables command. If the association identifier is zero, the response includes the system identifier (0) and status word, and the data field contains a list of binary-coded pairs <<Association ID>> <<status word>>, one for each currently defined association 🌸.

Read Variables (2):

The command data field is empty or contains a list of identifiers separated by commas. If the Association ID is nonzero, the response includes the requested peer identifier and status word, and the data field contains a list of peer variables and values as described above. If the Association ID is zero, the data field contains a list of system variables. If a peer has been selected as the synchronization source, the response includes the peer identifier and status word. Otherwise, the response includes the system identifier (0) and status word πŸŽ€.

Write Variables (3):

The command data field contains a list of assignments as described above. The variables are updated as indicated. The response is as described for the Read Variables command ✨.

Read Clock Variables (4):

The command data field is empty or contains a list of identifiers separated by commas. The Association ID selects the system clock variables or peer clock variables in the same way as in the Read Variables command. The response includes the requested clock identifier and status word. The data field contains a list of clock variables and values, including the last timecode message received from the clock πŸ•°οΈ.

Write Clock Variables (5):

The command data field contains a list of assignments as described above. The clock variables are updated as indicated. The response is as described for the read clock variables command πŸ¦„.

Set Trap Address/Port (6):

The command Association ID, status, and data fields are ignored. The address and port number for subsequent trap messages are taken from the source address and port of the control message itself. The initial trap counter for trap response messages is taken from the sequence field of the command. The response association identifier, status, and data fields are not significant. Implementations should include logical timeouts that prevent trap transmissions if the monitoring program does not renew this information after a lengthy interval. this one is giving "set it and remember to renew it" energy 😭🫢.

Trap Response (7):

This message is sent when a system, peer, or clock exception event occurs. The opcode field is 7 and the R bit is set. The trap counter is incremented by one for each trap sent, and the sequence field is set to that value. The trap message is sent using the IP address and port fields established by the set trap address/port command. For a system trap, the Association ID field is set to zero and the status field contains the system status word. For a peer trap, the Association ID field is set to that peer and the status field contains the peer status word. Optional ASCII-coded information can be included in the data field 🚨.

Configure (8):

The command data is parsed and applied as if it were supplied in the daemon configuration file πŸ› οΈ.

Save Configuration (9):

This writes a snapshot of the current configuration to the file name supplied as the command data. Further, the command is refused unless a directory in which to store the resulting files has been explicitly configured by the operator πŸ“.

Read Most Recently Used (MRU) list (10):

This retrieves records of recently seen remote addresses and their associated statistics. This command supports all of the state variables defined in Section 9 of [RFC5905]. The command data consists of name=value pairs that control the selection of records, as well as a requestor-specific nonce previously retrieved using this command or opcode 12 (Request Nonce). The response consists of name=value pairs. Some names can appear multiple times, using a dot followed by a zero-based index to tell them apart and to associate elements of the same record with the same index. A new nonce is provided with each successful response 🧾.

Read ordered list (11):

This retrieves a list ordered by IP address, where IPv4 information comes before IPv6 information. If the command data is empty or is the seven characters "ifstats", the associated statistics, status, and counters for each local address are returned. If the command data is the characters "addr_restrictions", then the set of IPv4 remote address restrictions is returned, followed by the set of IPv6 remote address restrictions (access control lists). Other command data returns error code 5 (unknown variable name). Similar to Read MRU, response information uses zero-based indexes as part of the variable name preceding the equals sign and value, where each index relates information for a single address or network. This opcode requires authentication πŸ”.

Request Nonce (12):

This retrieves a 96-bit nonce specific to the requesting remote address, and it's valid for a limited period. Command data is not used in the request. The nonce consists of a 64-bit NTP timestamp and 32 bits of hash derived from that timestamp, the remote address, and a salt known only to the server, which varies between daemon runs. When a management agent includes the nonce, it demonstrates to the server that the agent can receive datagrams sent to the source address of the request. This makes source address "spoofing" harder, in a similar way to TCP's three-way handshake. the nonce is basically a little proof of "yep, it's really me" πŸ₯Ήβœ¨.

Unset Trap (31):

This removes the requesting remote address and port from the list of trap receivers. Command data is not used in the request. If the address and port are not in the list of trap receivers, the error code is 4 (bad association) πŸ™ˆ.


5. IANA Considerations 🌈

This document has no IANA actions πŸ’–.

6. Security Considerations πŸ”₯

okay bestie, this is the scary part πŸ’€ A bunch of security vulnerabilities have been identified with these control messages, so we need to talk about them 🫢

NTP's control query interface lets you read and write system, peer, and clock variables remotely, from arbitrary IP addresses, using the commands from Section 4 😳 Overwriting these variables requires authentication by default, but reading them doesn't. This document argues that an NTP host must authenticate all control queries, not just the ones that overwrite these variables πŸ” Alternatively, the host can use an access control list to explicitly list the IP addresses that are allowed to control query the clients. These access controls are required for the following reasons:

  • NTP as a Distributed Denial-of-Service (DDoS) vector πŸ’₯: NTP timing query and response packets (modes 1-2, 3-4, and 5) are usually short in size. However, some NTP control queries generate a very long packet in response to a short query. So there's a whole history of people using these control queries to perform DoS attacks 😀 These off-path attacks exploit the large size of NTP control queries to cause UDP-based amplification attacks (for example, the mode 7 monlist command generates a very long packet in response to a small query [CVE-DOS]). These attacks only use NTP as a vector for DoS attacks on other protocols, but they don't affect the time service on the NTP host itself. To limit the sources of these malicious commands, NTP server operators are recommended to deploy ingress filtering [RFC3704].
  • Time-shifting attacks through information leakage/overwriting ⏰: NTP hosts save important system and peer state variables. An off-path attacker who can read these variables remotely can leverage the information leaked by these control queries to perform time-shifting and DDoS attacks on NTP clients. These attacks do affect time synchronization on the NTP hosts. For instance:
    • In the client/server mode, the client stores its local time when it sends the query to the server in its xmt peer variable. This variable is used to perform TEST2 to non-cryptographically authenticate the server (i.e., if the origin timestamp field in the corresponding server response packet matches the xmt peer variable, then the client accepts the packet). An off-path attacker with the ability to read this variable can easily spoof server response packets for the client, which will pass TEST2 and can deny service or shift time on the NTP client. The specific attack is described in [CVE-SPOOF].
    • The client also stores its local time when the server response is received in its rec peer variable. This variable is used for authentication in interleaved-pivot mode. An off-path attacker with the ability to read this state variable can easily shift time on the client by passing this test. This attack is described in [CVE-SHIFT].
  • Fast-Scanning πŸ”Ž: NTP mode 6 control messages are usually small UDP packets. Fast-scanning tools like ZMap can be used to spray the entire (potentially reachable) Internet with these messages within hours to identify vulnerable hosts. To make things worse, these attacks can be extremely low-rate, only requiring a control query for reconnaissance and a spoofed response to shift time on vulnerable clients.

The mode 6 and 7 messages are vulnerable to replay attacks [CVE-Replay] πŸ”: If an attacker observes mode 6/7 packets that modify the configuration of the server in any way, the attacker can apply the same change at any time later by simply sending the packets to the server again. The use of the nonce (Request Nonce command) provides limited protection against replay attacks.

NTP best practices recommend configuring NTP with the no-query parameter. The no-query parameter blocks access to all remote control queries. However, sometimes the hosts do not want to block all queries and want to give access for certain control queries remotely. This could be for the purpose of remote management and configuration of the hosts in certain scenarios. Such hosts tend to use firewalls or other middleboxes to blacklist certain queries within the network.

Significantly fewer hosts respond to mode 7 monlist queries as compared to other control queries, because it is a well-known and exploited control query. These queries are likely blocked using blacklists on firewalls and middleboxes rather than the no-query option on NTP hosts. The remaining control queries that can be exploited likely remain out of the blacklist because they are undocumented in the current NTP specification [RFC5905].

This document describes all of the mode 6 control queries allowed by NTP and can help administrators make informed decisions on security measures to protect NTP devices from harmful queries, and likely make those systems less vulnerable. The use of the legacy mode 6 interface is NOT RECOMMENDED. Regardless of which mode 6 commands an administrator may elect to allow, remote access to this facility needs to be protected from unauthorized access (e.g., strict Access Control Lists (ACLs)). Additionally, the legacy interface for mode 6 commands SHOULD NOT be utilized in new deployments or implementation of NTP.


7. References πŸ“š

7.1. Normative References

[RFC1305]  Mills, D., "Network Time Protocol (Version 3)
           Specification, Implementation and Analysis", RFC 1305,
           DOI 10.17487/RFC1305, March 1992,
           <https://www.rfc-editor.org/info/rfc1305>.

[RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
           Requirement Levels", BCP 14, RFC 2119,
           DOI 10.17487/RFC2119, March 1997,
           <https://www.rfc-editor.org/info/rfc2119>.

[RFC3704]  Baker, F. and P. Savola, "Ingress Filtering for Multihomed
           Networks", BCP 84, RFC 3704, DOI 10.17487/RFC3704, March
           2004, <https://www.rfc-editor.org/info/rfc3704>.

[RFC5905]  Mills, D., Martin, J., Ed., Burbank, J., and W. Kasch,
           "Network Time Protocol Version 4: Protocol and Algorithms
           Specification", RFC 5905, DOI 10.17487/RFC5905, June 2010,
           <https://www.rfc-editor.org/info/rfc5905>.

[RFC5952]  Kawamura, S. and M. Kawashima, "A Recommendation for IPv6
           Address Text Representation", RFC 5952,
           DOI 10.17487/RFC5952, August 2010,
           <https://www.rfc-editor.org/info/rfc5952>.

[RFC8174]  Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
           2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
           May 2017, <https://www.rfc-editor.org/info/rfc8174>.

7.2. Informative References

[CVE-DOS]  NIST National Vulnerability Database, "CVE-2013-5211
           Detail", 2 January 2014,
           <https://nvd.nist.gov/vuln/detail/CVE-2013-5211>.

[CVE-Replay]
           NIST National Vulnerability Database, "CVE-2015-8140
           Detail", 30 January 2015,
           <https://nvd.nist.gov/vuln/detail/CVE-2015-8140>.

[CVE-SHIFT]
           NIST National Vulnerability Database, "CVE-2016-1548
           Detail", 6 January 2017,
           <https://nvd.nist.gov/vuln/detail/CVE-2016-1548>.

[CVE-SPOOF]
           NIST National Vulnerability Database, "CVE-2015-8139
           Detail", 30 January 2017,
           <https://nvd.nist.gov/vuln/detail/CVE-2015-8139>.

[RFC0791]  Postel, J., "Internet Protocol", STD 5, RFC 791,
           DOI 10.17487/RFC0791, September 1981,
           <https://www.rfc-editor.org/info/rfc791>.

[RFC8200]  Deering, S. and R. Hinden, "Internet Protocol, Version 6
           (IPv6) Specification", STD 86, RFC 8200,
           DOI 10.17487/RFC8200, July 2017,
           <https://www.rfc-editor.org/info/rfc8200>.

Appendix A. NTP Remote Facility Message Format πŸŽ€

okay so bestie, the NTP Remote Facility Message header is the bit that sits right after the UDP header πŸ¦‹ Figure 3 shows the whole layout, and the field descriptions come after it. heads up: any bit marked as zero is reserved, and it should always be sent as zero πŸ’…

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|R|M| VN  |Mode |A|  Sequence   | Implementation|   Req Code    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Err  |        Count          |  MBZ  |       Size            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
/                    Data (up to 500 bytes)                     /
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                Encryption KeyID (when A bit set)              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
/          Message Authentication Code (when A bit set)         /
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 3: NTP Remote Facility Message Header

Response Bit (R): πŸ’– set to 0 if the packet is a request, and set to 1 if it's a response.

More Bit (M): 🌸 set to 0 if this is the last packet in a response. otherwise, set it to 1 in responses that need more than one packet.

Version Number (VN): ✨ set to the version number of the NTP daemon.

Mode: 🧚 set to 7 for Remote Facility messages.

Authenticated Bit (A): πŸ” if it's set to 1, the packet has authentication info in it.

Sequence: πŸ“ for a multi-packet response, this field holds the sequence number of the packet. the packets in a multi-packet response are numbered starting at 0, and the More Bit is set to 1 on every packet except the last one.

Implementation: πŸ‘‘ this is the version number of the implementation that defined the request code used in the message. an implementation number of 0 is used for a request code that every version of the NTP daemon supports. the value 255 is reserved for future extensions.

Request Code (Req Code): πŸ”₯ an implementation-specific code that says which operation is being requested. a request code definition includes the format and meaning of the data in the packet.

Error (Err): πŸ’€ set to 0 for a request. for a response, this field has an error code for the request. if the Error is nonzero, the requested operation wasn't performed. the codes are:

  • 0: no error
  • 1: incompatible implementation number
  • 2: unimplemented request code
  • 3: format error
  • 4: no data available
  • 7: authentication failure

Count: 🌈 the number of data items in the packet. the range is 0 to 500.

Must Be Zero (MBZ): πŸ™ˆ a reserved field that's set to 0 in both requests and responses.

Size: πŸ¦‹ the size of each data item in the packet. the range is 0 to 500.

Data: πŸ“¦ a variable-sized field that holds the request or response data. for requests and responses, the size in octets must be greater than or equal to the product of the number of data items (Count) and the size of a data item (Size). for requests, the data area is exactly 40 octets long. for responses, the data area can be anywhere from 0 to 500 octets, inclusive.

Encryption KeyID: πŸ—οΈ a 32-bit unsigned integer that picks out the key used for the Message Authentication Code. this field is only included when the A bit is set to 1.

Message Authentication Code: πŸ›‘οΈ an optional Message Authentication Code, defined by the version of the NTP daemon named in the Implementation field. this field is only included when the A bit is set to 1.


Acknowledgements 🫢

Tim Plunkett created the original version of this document. Aanchal Malhotra wrote the first version of the Security Considerations section, which is so iconic of her ✨

Karen O'Donoghue, David Hart, Harlan Stenn, and Philip Chimento deserve credit for parts of this document because of their earlier work documenting these commands 🌷

Miroshav Lichvar, Ulrich Windl, Dieter Sibold, J Ignacio Alvarez-Hamelin, and Alex Campbell gave valuable comments on various draft versions of this document πŸ’œ

Contributors 🌸

Dr. David Mills specified the vast majority of the mode 6 commands during the development of [RFC1305]. he deserves the credit for their existence and their use πŸ‘‘

Author's Address πŸ¦‹

Brian Haberman (editor)

JHU

Email: brian@innovationslab.net

πŸ“¦ where this page comes from