forked from google/gopacket
-
Notifications
You must be signed in to change notification settings - Fork 1
/
ntp.go
416 lines (376 loc) · 17.6 KB
/
ntp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
// 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 *
//******************************************************************************