| // Copyright 2016 Google, Inc. All rights reserved. |
| // |
| // Use of this source code is governed by a BSD-style license |
| // that can be found in the LICENSE file in the root of the source |
| // tree. |
| // |
| //****************************************************************************** |
| |
| package layers |
| |
| import ( |
| "encoding/binary" |
| "errors" |
| |
| "github.com/google/gopacket" |
| ) |
| |
| //****************************************************************************** |
| // |
| // Network Time Protocol (NTP) Decoding Layer |
| // ------------------------------------------ |
| // This file provides a GoPacket decoding layer for NTP. |
| // |
| //****************************************************************************** |
| // |
| // About The Network Time Protocol (NTP) |
| // ------------------------------------- |
| // NTP is a protocol that enables computers on the internet to set their |
| // clocks to the correct time (or to a time that is acceptably close to the |
| // correct time). NTP runs on top of UDP. |
| // |
| // There have been a series of versions of the NTP protocol. The latest |
| // version is V4 and is specified in RFC 5905: |
| // http://www.ietf.org/rfc/rfc5905.txt |
| // |
| //****************************************************************************** |
| // |
| // References |
| // ---------- |
| // |
| // Wikipedia's NTP entry: |
| // https://en.wikipedia.org/wiki/Network_Time_Protocol |
| // This is the best place to get an overview of NTP. |
| // |
| // Network Time Protocol Home Website: |
| // http://www.ntp.org/ |
| // This appears to be the official website of NTP. |
| // |
| // List of current NTP Protocol RFCs: |
| // http://www.ntp.org/rfc.html |
| // |
| // RFC 958: "Network Time Protocol (NTP)" (1985) |
| // https://tools.ietf.org/html/rfc958 |
| // This is the original NTP specification. |
| // |
| // RFC 1305: "Network Time Protocol (Version 3) Specification, Implementation and Analysis" (1992) |
| // https://tools.ietf.org/html/rfc1305 |
| // The protocol was updated in 1992 yielding NTP V3. |
| // |
| // RFC 5905: "Network Time Protocol Version 4: Protocol and Algorithms Specification" (2010) |
| // https://www.ietf.org/rfc/rfc5905.txt |
| // The protocol was updated in 2010 yielding NTP V4. |
| // V4 is backwards compatible with all previous versions of NTP. |
| // |
| // RFC 5906: "Network Time Protocol Version 4: Autokey Specification" |
| // https://tools.ietf.org/html/rfc5906 |
| // This document addresses the security of the NTP protocol |
| // and is probably not relevant to this package. |
| // |
| // RFC 5907: "Definitions of Managed Objects for Network Time Protocol Version 4 (NTPv4)" |
| // https://tools.ietf.org/html/rfc5907 |
| // This document addresses the management of NTP servers and |
| // is probably not relevant to this package. |
| // |
| // RFC 5908: "Network Time Protocol (NTP) Server Option for DHCPv6" |
| // https://tools.ietf.org/html/rfc5908 |
| // This document addresses the use of NTP in DHCPv6 and is |
| // probably not relevant to this package. |
| // |
| // "Let's make a NTP Client in C" |
| // https://lettier.github.io/posts/2016-04-26-lets-make-a-ntp-client-in-c.html |
| // This web page contains useful information about the details of NTP, |
| // including an NTP record struture in C, and C code. |
| // |
| // "NTP Packet Header (NTP Reference Implementation) (Computer Network Time Synchronization)" |
| // http://what-when-how.com/computer-network-time-synchronization/ |
| // ntp-packet-header-ntp-reference-implementation-computer-network-time-synchronization/ |
| // This web page contains useful information on the details of NTP. |
| // |
| // "Technical information - NTP Data Packet" |
| // https://www.meinbergglobal.com/english/info/ntp-packet.htm |
| // This page has a helpful diagram of an NTP V4 packet. |
| // |
| //****************************************************************************** |
| // |
| // Obsolete References |
| // ------------------- |
| // |
| // RFC 1119: "RFC-1119 "Network Time Protocol (Version 2) Specification and Implementation" (1989) |
| // https://tools.ietf.org/html/rfc1119 |
| // Version 2 was drafted in 1989. |
| // It is unclear whether V2 was ever implememented or whether the |
| // ideas ended up in V3 (which was implemented in 1992). |
| // |
| // RFC 1361: "Simple Network Time Protocol (SNTP)" |
| // https://tools.ietf.org/html/rfc1361 |
| // This document is obsoleted by RFC 1769 and is included only for completeness. |
| // |
| // RFC 1769: "Simple Network Time Protocol (SNTP)" |
| // https://tools.ietf.org/html/rfc1769 |
| // This document is obsoleted by RFC 2030 and RFC 4330 and is included only for completeness. |
| // |
| // RFC 2030: "Simple Network Time Protocol (SNTP) Version 4 for IPv4, IPv6 and OSI" |
| // https://tools.ietf.org/html/rfc2030 |
| // This document is obsoleted by RFC 4330 and is included only for completeness. |
| // |
| // RFC 4330: "Simple Network Time Protocol (SNTP) Version 4 for IPv4, IPv6 and OSI" |
| // https://tools.ietf.org/html/rfc4330 |
| // This document is obsoleted by RFC 5905 and is included only for completeness. |
| // |
| //****************************************************************************** |
| // |
| // Endian And Bit Numbering Issues |
| // ------------------------------- |
| // |
| // Endian and bit numbering issues can be confusing. Here is some |
| // clarification: |
| // |
| // ENDIAN: Values are sent big endian. |
| // https://en.wikipedia.org/wiki/Endianness |
| // |
| // BIT NUMBERING: Bits are numbered 0 upwards from the most significant |
| // bit to the least significant bit. This means that if there is a 32-bit |
| // value, the most significant bit is called bit 0 and the least |
| // significant bit is called bit 31. |
| // |
| // See RFC 791 Appendix B for more discussion. |
| // |
| //****************************************************************************** |
| // |
| // NTP V3 and V4 Packet Format |
| // --------------------------- |
| // NTP packets are UDP packets whose payload contains an NTP record. |
| // |
| // The NTP RFC defines the format of the NTP record. |
| // |
| // There have been four versions of the protocol: |
| // |
| // V1 in 1985 |
| // V2 in 1989 |
| // V3 in 1992 |
| // V4 in 2010 |
| // |
| // It is clear that V1 and V2 are obsolete, and there is no need to |
| // cater for these formats. |
| // |
| // V3 and V4 essentially use the same format, with V4 adding some optional |
| // fields on the end. So this package supports the V3 and V4 formats. |
| // |
| // The current version of NTP (NTP V4)'s RFC (V4 - RFC 5905) contains |
| // the following diagram for the NTP record format: |
| |
| // 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 | Stratum | Poll | Precision | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // | Root Delay | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // | Root Dispersion | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // | Reference ID | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // | | |
| // + Reference Timestamp (64) + |
| // | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // | | |
| // + Origin Timestamp (64) + |
| // | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // | | |
| // + Receive Timestamp (64) + |
| // | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // | | |
| // + Transmit Timestamp (64) + |
| // | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // | | |
| // . . |
| // . Extension Field 1 (variable) . |
| // . . |
| // | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // | | |
| // . . |
| // . Extension Field 2 (variable) . |
| // . . |
| // | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // | Key Identifier | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // | | |
| // | dgst (128) | |
| // | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // From http://www.ietf.org/rfc/rfc5905.txt |
| // |
| // The fields "Extension Field 1 (variable)" and later are optional fields, |
| // and so we can set a minimum NTP record size of 48 bytes. |
| // |
| const ntpMinimumRecordSizeInBytes int = 48 |
| |
| //****************************************************************************** |
| |
| // NTP Type |
| // -------- |
| // Type NTP implements the DecodingLayer interface. Each NTP object |
| // represents in a structured form the NTP record present as the UDP |
| // payload in an NTP UDP packet. |
| // |
| |
| type NTPLeapIndicator uint8 |
| type NTPVersion uint8 |
| type NTPMode uint8 |
| type NTPStratum uint8 |
| type NTPLog2Seconds int8 |
| type NTPFixed16Seconds uint32 |
| type NTPReferenceID uint32 |
| type NTPTimestamp uint64 |
| |
| type NTP struct { |
| BaseLayer // Stores the packet bytes and payload bytes. |
| |
| LeapIndicator NTPLeapIndicator // [0,3]. Indicates whether leap second(s) is to be added. |
| Version NTPVersion // [0,7]. Version of the NTP protocol. |
| Mode NTPMode // [0,7]. Mode. |
| Stratum NTPStratum // [0,255]. Stratum of time server in the server tree. |
| Poll NTPLog2Seconds // [-128,127]. The maximum interval between successive messages, in log2 seconds. |
| Precision NTPLog2Seconds // [-128,127]. The precision of the system clock, in log2 seconds. |
| RootDelay NTPFixed16Seconds // [0,2^32-1]. Total round trip delay to the reference clock in seconds times 2^16. |
| RootDispersion NTPFixed16Seconds // [0,2^32-1]. Total dispersion to the reference clock, in seconds times 2^16. |
| ReferenceID NTPReferenceID // ID code of reference clock [0,2^32-1]. |
| ReferenceTimestamp NTPTimestamp // Most recent timestamp from the reference clock. |
| OriginTimestamp NTPTimestamp // Local time when request was sent from local host. |
| ReceiveTimestamp NTPTimestamp // Local time (on server) that request arrived at server host. |
| TransmitTimestamp NTPTimestamp // Local time (on server) that request departed server host. |
| |
| // FIX: This package should analyse the extension fields and represent the extension fields too. |
| ExtensionBytes []byte // Just put extensions in a byte slice. |
| } |
| |
| //****************************************************************************** |
| |
| // LayerType returns the layer type of the NTP object, which is LayerTypeNTP. |
| func (d *NTP) LayerType() gopacket.LayerType { |
| return LayerTypeNTP |
| } |
| |
| //****************************************************************************** |
| |
| // decodeNTP analyses a byte slice and attempts to decode it as an NTP |
| // record of a UDP packet. |
| // |
| // If it succeeds, it loads p with information about the packet and returns nil. |
| // If it fails, it returns an error (non nil). |
| // |
| // This function is employed in layertypes.go to register the NTP layer. |
| func decodeNTP(data []byte, p gopacket.PacketBuilder) error { |
| |
| // Attempt to decode the byte slice. |
| d := &NTP{} |
| err := d.DecodeFromBytes(data, p) |
| if err != nil { |
| return err |
| } |
| |
| // If the decoding worked, add the layer to the packet and set it |
| // as the application layer too, if there isn't already one. |
| p.AddLayer(d) |
| p.SetApplicationLayer(d) |
| |
| return nil |
| } |
| |
| //****************************************************************************** |
| |
| // DecodeFromBytes analyses a byte slice and attempts to decode it as an NTP |
| // record of a UDP packet. |
| // |
| // Upon succeeds, it loads the NTP object with information about the packet |
| // and returns nil. |
| // Upon failure, it returns an error (non nil). |
| func (d *NTP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { |
| |
| // If the data block is too short to be a NTP record, then return an error. |
| if len(data) < ntpMinimumRecordSizeInBytes { |
| df.SetTruncated() |
| return errors.New("NTP packet too short") |
| } |
| |
| // RFC 5905 does not appear to define a maximum NTP record length. |
| // The protocol allows "extension fields" to be included in the record, |
| // and states about these fields:" |
| // |
| // "While the minimum field length containing required fields is |
| // four words (16 octets), a maximum field length remains to be |
| // established." |
| // |
| // For this reason, the packet length is not checked here for being too long. |
| |
| // NTP type embeds type BaseLayer which contains two fields: |
| // Contents is supposed to contain the bytes of the data at this level. |
| // Payload is supposed to contain the payload of this level. |
| // Here we set the baselayer to be the bytes of the NTP record. |
| d.BaseLayer = BaseLayer{Contents: data[:len(data)]} |
| |
| // Extract the fields from the block of bytes. |
| // To make sense of this, refer to the packet diagram |
| // above and the section on endian conventions. |
| |
| // The first few fields are all packed into the first 32 bits. Unpack them. |
| f := data[0] |
| d.LeapIndicator = NTPLeapIndicator((f & 0xC0) >> 6) |
| d.Version = NTPVersion((f & 0x38) >> 3) |
| d.Mode = NTPMode(f & 0x07) |
| d.Stratum = NTPStratum(data[1]) |
| d.Poll = NTPLog2Seconds(data[2]) |
| d.Precision = NTPLog2Seconds(data[3]) |
| |
| // The remaining fields can just be copied in big endian order. |
| d.RootDelay = NTPFixed16Seconds(binary.BigEndian.Uint32(data[4:8])) |
| d.RootDispersion = NTPFixed16Seconds(binary.BigEndian.Uint32(data[8:12])) |
| d.ReferenceID = NTPReferenceID(binary.BigEndian.Uint32(data[12:16])) |
| d.ReferenceTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[16:24])) |
| d.OriginTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[24:32])) |
| d.ReceiveTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[32:40])) |
| d.TransmitTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[40:48])) |
| |
| // This layer does not attempt to analyse the extension bytes. |
| // But if there are any, we'd like the user to know. So we just |
| // place them all in an ExtensionBytes field. |
| d.ExtensionBytes = data[48:] |
| |
| // Return no error. |
| return nil |
| } |
| |
| // SerializeTo writes the serialized form of this layer into the |
| // SerializationBuffer, implementing gopacket.SerializableLayer. |
| // See the docs for gopacket.SerializableLayer for more info. |
| func (d *NTP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { |
| data, err := b.PrependBytes(ntpMinimumRecordSizeInBytes) |
| if err != nil { |
| return err |
| } |
| |
| // Pack the first few fields into the first 32 bits. |
| h := uint8(0) |
| h |= (uint8(d.LeapIndicator) << 6) & 0xC0 |
| h |= (uint8(d.Version) << 3) & 0x38 |
| h |= (uint8(d.Mode)) & 0x07 |
| data[0] = byte(h) |
| data[1] = byte(d.Stratum) |
| data[2] = byte(d.Poll) |
| data[3] = byte(d.Precision) |
| |
| // The remaining fields can just be copied in big endian order. |
| binary.BigEndian.PutUint32(data[4:8], uint32(d.RootDelay)) |
| binary.BigEndian.PutUint32(data[8:12], uint32(d.RootDispersion)) |
| binary.BigEndian.PutUint32(data[12:16], uint32(d.ReferenceID)) |
| binary.BigEndian.PutUint64(data[16:24], uint64(d.ReferenceTimestamp)) |
| binary.BigEndian.PutUint64(data[24:32], uint64(d.OriginTimestamp)) |
| binary.BigEndian.PutUint64(data[32:40], uint64(d.ReceiveTimestamp)) |
| binary.BigEndian.PutUint64(data[40:48], uint64(d.TransmitTimestamp)) |
| |
| ex, err := b.AppendBytes(len(d.ExtensionBytes)) |
| if err != nil { |
| return err |
| } |
| copy(ex, d.ExtensionBytes) |
| |
| return nil |
| } |
| |
| //****************************************************************************** |
| |
| // CanDecode returns a set of layers that NTP objects can decode. |
| // As NTP objects can only decide the NTP layer, we can return just that layer. |
| // Apparently a single layer type implements LayerClass. |
| func (d *NTP) CanDecode() gopacket.LayerClass { |
| return LayerTypeNTP |
| } |
| |
| //****************************************************************************** |
| |
| // NextLayerType specifies the next layer that GoPacket should attempt to |
| // analyse after this (NTP) layer. As NTP packets do not contain any payload |
| // bytes, there are no further layers to analyse. |
| func (d *NTP) NextLayerType() gopacket.LayerType { |
| return gopacket.LayerTypeZero |
| } |
| |
| //****************************************************************************** |
| |
| // NTP packets do not carry any data payload, so the empty byte slice is retured. |
| // In Go, a nil slice is functionally identical to an empty slice, so we |
| // return nil to avoid a heap allocation. |
| func (d *NTP) Payload() []byte { |
| return nil |
| } |
| |
| //****************************************************************************** |
| //* End Of NTP File * |
| //****************************************************************************** |