Documentation
¶
Overview ¶
Package ntp decodes NTP / SNTP packets per RFC 5905 (v4), RFC 1305 (v3), and RFC 4330 (SNTPv4). NTP is the time- synchronisation protocol every networked device speaks against pool.ntp.org / its vendor pool / a local stratum-2 server. Capturing NTP traffic is the workhorse primitive for time-sync forensics, NTP amplification DDoS detection (mode 7 / monlist abuse), log-timestamp correlation, and certificate-validity-window debugging.
Wrap-vs-native judgement ¶
Native. The NTP wire format is a fixed 48-byte header per RFC 5905 §7.3 with optional extension fields + authenticator at the end. Every field is a fixed-position integer or fixed-point seconds value. NTP timestamps are 64-bit (32-bit integer seconds since 1900-01-01 + 32-bit fractional seconds at 2^-32 resolution). Pasting a hex blob from Wireshark / tshark / tcpdump-of-123 capture is enough — no time server, no key material, no live network attach.
What this package covers ¶
- Byte 0 broken out: LI (Leap Indicator: 0 no warning / 1 +61sec / 2 -61sec / 3 alarm-unsynchronised), VN (Version Number — 1, 2, 3, 4), Mode (1 symmetric active / 2 symmetric passive / 3 client / 4 server / 5 broadcast / 6 NTP control message / 7 private use).
- Stratum (1=primary reference / 2-15=secondary / 16=unsynchronised / 17-255=reserved) with name lookup.
- Poll (signed log2 seconds — the maximum poll interval between successive messages, rendered as both raw log2 and as seconds).
- Precision (signed log2 seconds — the precision of the local clock, similarly rendered).
- Root Delay + Root Dispersion as 32-bit NTPv3 short- format fixed-point seconds (16-bit integer + 16-bit fractional, surfaced as float64 seconds).
- Reference ID with stratum-dependent interpretation:
- Stratum 0: Kiss-o'-Death (KoD) 4-character code (ACST/AUTH/AUTO/BCST/CRYP/DENY/DROP/RSTR/INIT/ MCST/NKEY/NTSN/RATE/RMOT/STEP) per RFC 5905 §7.4.
- Stratum 1: 4-character ASCII source identifier (GPS/PPS/NIST/ACTS/WWV/WWVB/WWVH/DCF/MSF/DTOC/PTB/ USNO/LORC) per RFC 5905 §7.3.
- Stratum 2-15: IPv4 of the upstream server (or the MD5 hash of the upstream IPv6 if IPv6 is being used, but we report the 4 bytes as IPv4 for the common case).
- 4 NTP timestamps: Reference (last time the local clock was set), Origin / T1 (when client sent the request), Receive / T2 (when server received the request), Transmit / T3 (when server sent the response). Each is surfaced as both the raw 64-bit NTP value and an RFC 3339 string in UTC.
- Optional NTPv4 extension fields (RFC 5906) — count + raw hex for each.
- Optional authenticator (key ID + MAC) — detected by remaining bytes after the header + extensions; the key ID and the MAC hex are surfaced (MAC length 16 bytes = MD5, 20 bytes = SHA-1).
What this package does NOT cover (deliberately out of scope) ¶
- NTP control message (mode 6) deep decode — the RFC 1305 §3.5 control message format is its own ~150 LoC parser (op-code + sequence + status + assoc ID + offset + count + data); the envelope is recognised and labeled but the body is surfaced as raw hex.
- NTP mode 7 (private use, vendor-specific) — historically abused for monlist DDoS amplification; we label it but don't dissect the vendor body.
- Autokey (RFC 5906) authentication — extension fields are counted but the certificate / cookie / signature contents are not validated.
- NTS (Network Time Security, RFC 8915) — newer authenticated-NTP variant; the cookie/AEAD extension fields are recognised by tag but the contents are surfaced as raw hex (decryption requires session keys).
- SNTP simple-client behaviour — the wire format is identical to NTP so the same decoder applies.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Authenticator ¶
type Authenticator struct {
KeyID uint32 `json:"key_id"`
MACHex string `json:"mac_hex"`
MACAlg string `json:"mac_algorithm"`
}
Authenticator carries the optional Key Identifier + MAC at the tail of an authenticated NTP packet (RFC 5905 §7.5 + RFC 1305 §3.2).
type NTPTimestamp ¶
type NTPTimestamp struct {
Seconds uint32 `json:"seconds_since_1900"`
Fraction uint32 `json:"fraction"`
UnixSeconds int64 `json:"unix_seconds,omitempty"`
FractionSec float64 `json:"fraction_sec"`
RFC3339 string `json:"rfc3339,omitempty"`
IsZero bool `json:"is_zero,omitempty"`
}
NTPTimestamp is one decoded 64-bit NTP timestamp.
The NTP epoch starts at 1900-01-01 00:00:00 UTC; Unix epoch is 1970-01-01 00:00:00 UTC. The offset between the two is 2,208,988,800 seconds.
type Packet ¶
type Packet struct {
HexInput string `json:"hex_input"`
LeapIndicator int `json:"leap_indicator"`
LeapIndicatorName string `json:"leap_indicator_name"`
VersionNumber int `json:"version_number"`
Mode int `json:"mode"`
ModeName string `json:"mode_name"`
Stratum int `json:"stratum"`
StratumName string `json:"stratum_name"`
PollIntervalLog2 int `json:"poll_interval_log2"`
PollIntervalSec float64 `json:"poll_interval_sec"`
PrecisionLog2 int `json:"precision_log2"`
PrecisionSec float64 `json:"precision_sec"`
RootDelaySec float64 `json:"root_delay_sec"`
RootDispersionSec float64 `json:"root_dispersion_sec"`
ReferenceID *ReferenceID `json:"reference_id"`
ReferenceTime *NTPTimestamp `json:"reference_time,omitempty"`
OriginTime *NTPTimestamp `json:"origin_time,omitempty"`
ReceiveTime *NTPTimestamp `json:"receive_time,omitempty"`
TransmitTime *NTPTimestamp `json:"transmit_time,omitempty"`
ExtensionCount int `json:"extension_count,omitempty"`
ExtensionsHex []string `json:"extensions_hex,omitempty"`
Authenticator *Authenticator `json:"authenticator,omitempty"`
}
Packet is the decoded NTP message view.
type ReferenceID ¶
type ReferenceID struct {
RawHex string `json:"raw_hex"`
Interpretation string `json:"interpretation"`
ASCIICode string `json:"ascii_code,omitempty"`
ASCIIName string `json:"ascii_name,omitempty"`
KoDCode string `json:"kod_code,omitempty"`
KoDName string `json:"kod_name,omitempty"`
IPv4 string `json:"ipv4,omitempty"`
}
ReferenceID is the 4-byte Reference Identifier field interpreted per the current stratum.