1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) Philippe Biondi <phil@secdev.org>
5
6"""
7NTP (Network Time Protocol).
8References : RFC 5905, RC 1305, ntpd source code
9"""
10
11import struct
12import time
13import datetime
14
15from scapy.packet import Packet, bind_layers
16from scapy.fields import (
17 BitEnumField,
18 BitField,
19 ByteEnumField,
20 ByteField,
21 ConditionalField,
22 FieldListField,
23 FixedPointField,
24 FlagsField,
25 IP6Field,
26 IPField,
27 IntField,
28 LEIntField,
29 LEShortField,
30 MayEnd,
31 PacketField,
32 PacketLenField,
33 PacketListField,
34 PadField,
35 ShortField,
36 SignedByteField,
37 StrField,
38 StrFixedLenEnumField,
39 StrFixedLenField,
40 XByteField,
41 XStrFixedLenField,
42)
43from scapy.layers.inet import UDP
44from scapy.utils import lhex
45from scapy.compat import orb
46from scapy.config import conf
47
48
49#############################################################################
50# Constants
51#############################################################################
52
53_NTP_AUTH_MD5_MIN_SIZE = 68
54_NTP_EXT_MIN_SIZE = 16
55_NTP_HDR_WITH_EXT_MIN_SIZE = _NTP_AUTH_MD5_MIN_SIZE + _NTP_EXT_MIN_SIZE
56_NTP_AUTH_MD5_TAIL_SIZE = 20
57_NTP_AUTH_MD5_DGST_SIZE = 16
58_NTP_PRIVATE_PACKET_MIN_SIZE = 8
59
60# ntpd "Private" messages are the shortest
61_NTP_PACKET_MIN_SIZE = _NTP_PRIVATE_PACKET_MIN_SIZE
62
63_NTP_PRIVATE_REQ_PKT_TAIL_LEN = 28
64
65# seconds between 01-01-1900 and 01-01-1970
66_NTP_BASETIME = 2208988800
67
68# include/ntp.h
69_NTP_SHIFT = 8
70_NTP_HASH_SIZE = 128
71
72
73#############################################################################
74# Fields and utilities
75#############################################################################
76
77class XLEShortField(LEShortField):
78 """
79 XShortField which value is encoded in little endian.
80 """
81
82 def i2repr(self, pkt, x):
83 return lhex(self.i2h(pkt, x))
84
85
86class TimeStampField(FixedPointField):
87 """
88 This field handles the timestamp fields in the NTP header.
89 """
90
91 def __init__(self, name, default):
92 FixedPointField.__init__(self, name, default, 64, 32)
93
94 def i2repr(self, pkt, val):
95 if val is None:
96 return "--"
97 val = self.i2h(pkt, val)
98 if val < _NTP_BASETIME:
99 return str(val)
100 return time.strftime(
101 "%a, %d %b %Y %H:%M:%S +0000",
102 time.gmtime(int(val - _NTP_BASETIME))
103 )
104
105 def any2i(self, pkt, val):
106 if isinstance(val, str):
107 val = int(time.mktime(time.strptime(val))) + _NTP_BASETIME
108 elif isinstance(val, datetime.datetime):
109 val = int(val.strftime("%s")) + _NTP_BASETIME
110 return FixedPointField.any2i(self, pkt, val)
111
112 def i2m(self, pkt, val):
113 if val is None:
114 val = FixedPointField.any2i(self, pkt, time.time() + _NTP_BASETIME)
115 return FixedPointField.i2m(self, pkt, val)
116
117
118#############################################################################
119# NTP
120#############################################################################
121
122# RFC 5905 / Section 7.3
123_leap_indicator = {
124 0: "no warning",
125 1: "last minute of the day has 61 seconds",
126 2: "last minute of the day has 59 seconds",
127 3: "unknown (clock unsynchronized)"
128}
129
130
131# RFC 5905 / Section 7.3
132_ntp_modes = {
133 0: "reserved",
134 1: "symmetric active",
135 2: "symmetric passive",
136 3: "client",
137 4: "server",
138 5: "broadcast",
139 6: "NTP control message",
140 7: "reserved for private use"
141}
142
143
144# RFC 5905 / Section 7.3
145_reference_identifiers = {
146 b"GOES": "Geosynchronous Orbit Environment Satellite",
147 b"GPS ": "Global Position System",
148 b"GAL ": "Galileo Positioning System",
149 b"PPS ": "Generic pulse-per-second",
150 b"IRIG": "Inter-Range Instrumentation Group",
151 b"WWVB": "LF Radio WWVB Ft. Collins, CO 60 kHz",
152 b"DCF ": "LF Radio DCF77 Mainflingen, DE 77.5 kHz",
153 b"HBG ": "LF Radio HBG Prangins, HB 75 kHz",
154 b"MSF ": "LF Radio MSF Anthorn, UK 60 kHz",
155 b"JJY ": "LF Radio JJY Fukushima, JP 40 kHz, Saga, JP 60 kHz",
156 b"LORC": "MF Radio LORAN C station, 100 kHz",
157 b"TDF ": "MF Radio Allouis, FR 162 kHz",
158 b"CHU ": "HF Radio CHU Ottawa, Ontario",
159 b"WWV ": "HF Radio WWV Ft. Collins, CO",
160 b"WWVH": "HF Radio WWVH Kauai, HI",
161 b"NIST": "NIST telephone modem",
162 b"ACTS": "NIST telephone modem",
163 b"USNO": "USNO telephone modem",
164 b"PTB ": "European telephone modem",
165}
166
167
168# RFC 5905 / Section 7.4
169_kiss_codes = {
170 "ACST": "The association belongs to a unicast server.",
171 "AUTH": "Server authentication failed.",
172 "AUTO": "Autokey sequence failed.",
173 "BCST": "The association belongs to a broadcast server.",
174 "CRYP": "Cryptographic authentication or identification failed.",
175 "DENY": "Access denied by remote server.",
176 "DROP": "Lost peer in symmetric mode.",
177 "RSTR": "Access denied due to local policy.",
178 "INIT": "The association has not yet synchronized for the first time.",
179 "MCST": "The association belongs to a dynamically discovered server.",
180 "NKEY": "No key found.",
181 "RATE": "Rate exceeded.",
182 "RMOT": "Alteration of association from a remote host running ntpdc."
183}
184
185
186# Used by _ntp_dispatcher to instantiate the appropriate class
187def _ntp_dispatcher(payload):
188 """
189 Returns the right class for a given NTP packet.
190 """
191 # By default, calling NTP() will build a NTP packet as defined in RFC 5905
192 # (see the code of NTPHeader). Use NTPHeader for extension fields and MAC.
193 if payload is None:
194 return NTPHeader
195 else:
196 length = len(payload)
197 if length >= _NTP_PACKET_MIN_SIZE:
198 first_byte = orb(payload[0])
199 # Extract NTP mode
200 mode = first_byte & 7
201 return {6: NTPControl, 7: NTPPrivate}.get(mode, NTPHeader)
202 return conf.raw_layer
203
204
205class NTP(Packet):
206 """
207 Base class that allows easier instantiation of a NTP packet from binary
208 data.
209 """
210
211 @classmethod
212 def dispatch_hook(cls, _pkt=None, *args, **kargs):
213 """
214 Returns the right class for the given data.
215 """
216
217 return _ntp_dispatcher(_pkt)
218
219 def pre_dissect(self, s):
220 """
221 Check that the payload is long enough to build a NTP packet.
222 """
223 length = len(s)
224 if length < _NTP_PACKET_MIN_SIZE:
225 err = " ({}".format(length) + " is < _NTP_PACKET_MIN_SIZE "
226 err += "({})).".format(_NTP_PACKET_MIN_SIZE)
227 raise _NTPInvalidDataException(err)
228 return s
229
230 def mysummary(self):
231 return self.sprintf(
232 "NTP v%ir,{0}.version%, %{0}.mode%".format(self.__class__.__name__)
233 )
234
235
236class _NTPAuthenticatorPaddingField(StrField):
237 """
238 StrField handling the padding that may be found before the
239 "authenticator" field.
240 """
241
242 def getfield(self, pkt, s):
243 ret = None
244 remain = s
245 length = len(s)
246
247 if length > _NTP_AUTH_MD5_TAIL_SIZE:
248 start = length - _NTP_AUTH_MD5_TAIL_SIZE
249 ret = s[:start]
250 remain = s[start:]
251 return remain, ret
252
253
254class NTPAuthenticator(Packet):
255 """
256 Packet handling the "authenticator" part of a NTP packet, as
257 defined in RFC 5905.
258 """
259
260 name = "Authenticator"
261 fields_desc = [
262 _NTPAuthenticatorPaddingField("padding", ""),
263 IntField("key_id", 0),
264 XStrFixedLenField("dgst", "", length_from=lambda x: 16)
265 ]
266
267 def extract_padding(self, s):
268 return b"", s
269
270
271class NTPExtension(Packet):
272 """
273 Packet handling a NTPv4 extension.
274 """
275
276 #########################################################################
277 #
278 # RFC 7822
279 #########################################################################
280 #
281 # 7.5. NTP Extension Field Format
282 #
283 # In NTPv3, one or more extension fields can be inserted after the
284 # header and before the MAC, if a MAC is present.
285 #
286 # Other than defining the field format, this document makes no use
287 # of the field contents. An extension field contains a request or
288 # response message in the format shown in Figure 14.
289 #
290 # 0 1 2 3
291 # 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
292 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
293 # | Field Type | Length |
294 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
295 # . .
296 # . Value .
297 # . .
298 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
299 # | Padding (as needed) |
300 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
301 #
302 # Figure 14: Extension Field Format
303 #
304 #
305 # All extension fields are zero-padded to a word (four octets)
306 # boundary.
307 #########################################################################
308 #
309
310 name = "extension"
311 fields_desc = [
312 ShortField("type", 0),
313 ShortField("len", 0),
314 PadField(PacketField("value", "", Packet), align=4, padwith=b"\x00")
315 ]
316
317
318class NTPExtPacketListField(PacketListField):
319
320 """
321 PacketListField handling NTPv4 extensions (NTPExtension list).
322 """
323
324 def m2i(self, pkt, m):
325 ret = None
326 if len(m) >= 16:
327 ret = NTPExtension(m)
328 else:
329 ret = conf.raw_layer(m)
330 return ret
331
332 def getfield(self, pkt, s):
333 lst = []
334 remain = s
335 length = len(s)
336 if length > _NTP_AUTH_MD5_TAIL_SIZE:
337 end = length - _NTP_AUTH_MD5_TAIL_SIZE
338 extensions = s[:end]
339 remain = s[end:]
340
341 extensions_len = len(extensions)
342 while extensions_len >= 16:
343 ext_len = struct.unpack("!H", extensions[2:4])[0]
344 ext_len = min(ext_len, extensions_len)
345 if ext_len < 1:
346 ext_len = extensions_len
347 current = extensions[:ext_len]
348 extensions = extensions[ext_len:]
349 current_packet = self.m2i(pkt, current)
350 lst.append(current_packet)
351 extensions_len = len(extensions)
352
353 if extensions_len > 0:
354 lst.append(self.m2i(pkt, extensions))
355
356 return remain, lst
357
358
359class NTPExtensions(Packet):
360 """
361 Packet handling the NTPv4 extensions and the "MAC part" of the packet.
362 """
363
364 #########################################################################
365 #
366 # RFC 5905 / RFC 7822
367 #########################################################################
368 #
369 # 7.5. NTP Extension Field Format
370 #
371 # In NTPv4, one or more extension fields can be inserted after the
372 # header and before the MAC, if a MAC is present.
373 #########################################################################
374 #
375
376 name = "NTPv4 extensions"
377 fields_desc = [
378 NTPExtPacketListField("extensions", [], Packet),
379 PacketField("mac", NTPAuthenticator(), NTPAuthenticator)
380 ]
381
382
383class NTPHeader(NTP):
384
385 """
386 Packet handling the RFC 5905 NTP packet.
387 """
388
389 #########################################################################
390 #
391 # RFC 5905
392 #########################################################################
393 #
394 # 0 1 2 3
395 # 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
396 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
397 # |LI | VN |Mode | Stratum | Poll | Precision |
398 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
399 # | Root Delay |
400 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
401 # | Root Dispersion |
402 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
403 # | Reference ID |
404 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
405 # | |
406 # + Reference Timestamp (64) +
407 # | |
408 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
409 # | |
410 # + Origin Timestamp (64) +
411 # | |
412 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
413 # | |
414 # + Receive Timestamp (64) +
415 # | |
416 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
417 # | |
418 # + Transmit Timestamp (64) +
419 # | |
420 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
421 # | |
422 # . .
423 # . Extension Field 1 (variable) .
424 # . .
425 # | |
426 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
427 # | |
428 # . .
429 # . Extension Field 2 (variable) .
430 # . .
431 # | |
432 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
433 # | Key Identifier |
434 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
435 # | |
436 # | dgst (128) |
437 # | |
438 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
439 #
440 # Figure 8: Packet Header Format
441 #########################################################################
442 #
443
444 name = "NTPHeader"
445 match_subclass = True
446 fields_desc = [
447 BitEnumField("leap", 0, 2, _leap_indicator),
448 BitField("version", 4, 3),
449 BitEnumField("mode", 3, 3, _ntp_modes),
450 BitField("stratum", 2, 8),
451 SignedByteField("poll", 0xa),
452 SignedByteField("precision", 0),
453 FixedPointField("delay", 0, size=32, frac_bits=16),
454 FixedPointField("dispersion", 0, size=32, frac_bits=16),
455 ConditionalField(IPField("id", "127.0.0.1"), lambda p: p.stratum > 1),
456 ConditionalField(
457 StrFixedLenEnumField(
458 "ref_id",
459 "",
460 length=4,
461 enum=_reference_identifiers
462 ),
463 lambda p: p.stratum < 2
464 ),
465 TimeStampField("ref", 0),
466 TimeStampField("orig", None),
467 TimeStampField("recv", 0),
468 TimeStampField("sent", None),
469 ]
470
471 def guess_payload_class(self, payload):
472 """
473 Handles NTPv4 extensions and MAC part (when authentication is used.)
474 """
475 plen = len(payload)
476
477 if plen - 4 in [16, 20, 32, 64]: # length of MD5, SHA1, SHA256, SHA512
478 return NTPAuthenticator
479 elif plen > _NTP_AUTH_MD5_TAIL_SIZE:
480 return NTPExtensions
481
482 return Packet.guess_payload_class(self, payload)
483
484
485class _NTPInvalidDataException(Exception):
486 """
487 Raised when it is not possible to instantiate a NTP packet with the
488 given data.
489 """
490
491 def __init__(self, details):
492 Exception.__init__(
493 self,
494 "Data does not seem to be a valid NTP message" + details
495 )
496
497
498##############################################################################
499# Private (mode 7)
500##############################################################################
501
502# Operation codes
503_op_codes = {
504 0: "CTL_OP_UNSPEC",
505 1: "CTL_OP_READSTAT",
506 2: "CTL_OP_READVAR",
507 3: "CTL_OP_WRITEVAR",
508 4: "CTL_OP_READCLOCK",
509 5: "CTL_OP_WRITECLOCK",
510 6: "CTL_OP_SETTRAP",
511 7: "CTL_OP_ASYNCMSG",
512 8: "CTL_OP_CONFIGURE",
513 9: "CTL_OP_SAVECONFIG",
514 10: "CTL_OP_READ_MRU",
515 11: "CTL_OP_READ_ORDLIST_A",
516 12: "CTL_OP_REQ_NONCE",
517 31: "CTL_OP_UNSETTRAP"
518}
519
520
521# System status words
522_system_statuses = {
523 0: "no warning",
524 1: "last minute was 61 seconds",
525 2: "last minute was 59 seconds",
526 3: "alarm condition (clock not synchronized)"
527}
528
529
530_clock_sources = {
531 0: "unspecified or unknown",
532 1: " Calibrated atomic clock",
533 2: "VLF (band 4) or LF (band 5) radio",
534 3: "HF (band 7) radio",
535 4: "UHF (band 9) satellite",
536 5: "local net",
537 6: "UDP/NTP",
538 7: "UDP/TIME",
539 8: "eyeball-and-wristwatch",
540 9: "telephone modem"
541}
542
543
544_system_event_codes = {
545 0: "unspecified",
546 1: "system restart",
547 2: "system or hardware fault",
548 3: "system new status word (leap bits or synchronization change)",
549 4: "system new synchronization source or stratum (sys.peer or sys.stratum change)", # noqa: E501
550 5: "system clock reset (offset correction exceeds CLOCK.MAX)",
551 6: "system invalid time or date",
552 7: "system clock exception",
553}
554
555
556# Peer status words
557_peer_statuses = {
558 0: "configured",
559 1: "authentication enabled",
560 2: "authentication okay",
561 3: "reachability okay",
562 4: "reserved"
563}
564
565
566_peer_selection = {
567 0: "rejected",
568 1: "passed sanity checks",
569 2: "passed correctness checks",
570 3: "passed candidate checks",
571 4: "passed outlyer checks",
572 5: "current synchronization source; max distance exceeded",
573 6: "current synchronization source; max distance okay",
574 7: "reserved"
575}
576
577
578_peer_event_codes = {
579 0: "unspecified",
580 1: "peer IP error",
581 2: "peer authentication failure",
582 3: "peer unreachable",
583 4: "peer reachable",
584 5: "peer clock exception",
585}
586
587
588# Clock status words
589_clock_statuses = {
590 0: "clock operating within nominals",
591 1: "reply timeout",
592 2: "bad reply format",
593 3: "hardware or software fault",
594 4: "propagation failure",
595 5: "bad date format or value",
596 6: "bad time format or value"
597}
598
599
600# Error status words
601_error_statuses = {
602 0: "unspecified",
603 1: "authentication failure",
604 2: "invalid message length or format",
605 3: "invalid opcode",
606 4: "unknown association identifier",
607 5: "unknown variable name",
608 6: "invalid variable value",
609 7: "administratively prohibited"
610}
611
612
613class NTPStatusPacket(Packet):
614 """
615 Packet handling a non specific status word.
616 """
617
618 name = "status"
619 fields_desc = [ShortField("status", 0)]
620
621 def extract_padding(self, s):
622 return b"", s
623
624
625class NTPSystemStatusPacket(Packet):
626
627 """
628 Packet handling the system status fields.
629 """
630
631 name = "system status"
632 fields_desc = [
633 BitEnumField("leap_indicator", 0, 2, _system_statuses),
634 BitEnumField("clock_source", 0, 6, _clock_sources),
635 BitField("system_event_counter", 0, 4),
636 BitEnumField("system_event_code", 0, 4, _system_event_codes),
637 ]
638
639 def extract_padding(self, s):
640 return b"", s
641
642
643class NTPPeerStatusPacket(Packet):
644 """
645 Packet handling the peer status fields.
646 """
647
648 name = "peer status"
649 fields_desc = [
650 BitField("configured", 0, 1),
651 BitField("auth_enabled", 0, 1),
652 BitField("authentic", 0, 1),
653 BitField("reachability", 0, 1),
654 BitField("reserved", 0, 1),
655 BitEnumField("peer_sel", 0, 3, _peer_selection),
656 BitField("peer_event_counter", 0, 4),
657 BitEnumField("peer_event_code", 0, 4, _peer_event_codes),
658 ]
659
660 def extract_padding(self, s):
661 return b"", s
662
663
664class NTPClockStatusPacket(Packet):
665 """
666 Packet handling the clock status fields.
667 """
668
669 name = "clock status"
670 fields_desc = [
671 BitEnumField("clock_status", 0, 8, _clock_statuses),
672 BitField("code", 0, 8)
673 ]
674
675 def extract_padding(self, s):
676 return b"", s
677
678
679class NTPErrorStatusPacket(Packet):
680 """
681 Packet handling the error status fields.
682 """
683
684 name = "error status"
685 fields_desc = [
686 BitEnumField("error_code", 0, 8, _error_statuses),
687 BitField("reserved", 0, 8)
688 ]
689
690 def extract_padding(self, s):
691 return b"", s
692
693
694class NTPControlStatusField(PacketField):
695 """
696 This field provides better readability for the "status" field.
697 """
698
699 #########################################################################
700 #
701 # RFC 1305
702 #########################################################################
703 #
704 # Appendix B.3. Commands // ntpd source code: ntp_control.h
705 #########################################################################
706 #
707
708 def m2i(self, pkt, m):
709 ret = None
710 association_id = struct.unpack("!H", m[2:4])[0]
711
712 if pkt.err == 1:
713 ret = NTPErrorStatusPacket(m)
714
715 # op_code == CTL_OP_READSTAT
716 elif pkt.op_code == 1:
717 if association_id != 0:
718 ret = NTPPeerStatusPacket(m)
719 else:
720 ret = NTPSystemStatusPacket(m)
721
722 # op_code == CTL_OP_READVAR
723 elif pkt.op_code == 2:
724 if association_id != 0:
725 ret = NTPPeerStatusPacket(m)
726 else:
727 ret = NTPSystemStatusPacket(m)
728
729 # op_code == CTL_OP_WRITEVAR
730 elif pkt.op_code == 3:
731 ret = NTPStatusPacket(m)
732
733 # op_code == CTL_OP_READCLOCK or op_code == CTL_OP_WRITECLOCK
734 elif pkt.op_code == 4 or pkt.op_code == 5:
735 ret = NTPClockStatusPacket(m)
736
737 else:
738 ret = NTPStatusPacket(m)
739
740 return ret
741
742
743class NTPPeerStatusDataPacket(Packet):
744 """
745 Packet handling the data field when op_code is CTL_OP_READSTAT
746 and the association_id field is null.
747 """
748
749 name = "data / peer status"
750 fields_desc = [
751 ShortField("association_id", 0),
752 PacketField("peer_status", NTPPeerStatusPacket(), NTPPeerStatusPacket),
753 ]
754
755
756class NTPControlDataPacketLenField(PacketLenField):
757
758 """
759 PacketField handling the "data" field of NTP control messages.
760 """
761
762 def m2i(self, pkt, m):
763 ret = None
764 if not m:
765 return ret
766
767 # op_code == CTL_OP_READSTAT
768 if pkt.op_code == 1:
769 if pkt.association_id == 0:
770 # Data contains association ID and peer status
771 ret = NTPPeerStatusDataPacket(m)
772 else:
773 ret = conf.raw_layer(m)
774 else:
775 ret = conf.raw_layer(m)
776
777 return ret
778
779 def getfield(self, pkt, s):
780 length = self.length_from(pkt)
781 i = None
782 if length > 0:
783 # RFC 1305
784 # The maximum number of data octets is 468.
785 #
786 # include/ntp_control.h
787 # u_char data[480 + MAX_MAC_LEN]; /* data + auth */
788 #
789 # Set the minimum length to 480 - 468
790 length = max(12, length)
791 if length % 4:
792 length += (4 - length % 4)
793 try:
794 i = self.m2i(pkt, s[:length])
795 except Exception:
796 if conf.debug_dissector:
797 raise
798 i = conf.raw_layer(load=s[:length])
799 return s[length:], i
800
801
802class NTPControl(NTP):
803 """
804 Packet handling NTP mode 6 / "Control" messages.
805 """
806
807 #########################################################################
808 #
809 # RFC 1305
810 #########################################################################
811 #
812 # Appendix B.3. Commands // ntpd source code: ntp_control.h
813 #########################################################################
814 #
815
816 name = "Control message"
817 match_subclass = True
818 fields_desc = [
819 BitField("zeros", 0, 2),
820 BitField("version", 2, 3),
821 BitEnumField("mode", 6, 3, _ntp_modes),
822 BitField("response", 0, 1),
823 BitField("err", 0, 1),
824 BitField("more", 0, 1),
825 BitEnumField("op_code", 0, 5, _op_codes),
826 ShortField("sequence", 0),
827 ConditionalField(NTPControlStatusField(
828 "status_word", "", Packet), lambda p: p.response == 1),
829 ConditionalField(ShortField("status", 0), lambda p: p.response == 0),
830 ShortField("association_id", 0),
831 ShortField("offset", 0),
832 ShortField("count", None),
833 MayEnd(NTPControlDataPacketLenField(
834 "data", "", Packet, length_from=lambda p: p.count)),
835 PacketField("authenticator", "", NTPAuthenticator),
836 ]
837
838 def post_build(self, p, pay):
839 if self.count is None:
840 length = 0
841 if self.data:
842 length = len(self.data)
843 p = p[:11] + struct.pack("!H", length) + p[13:]
844 return p + pay
845
846
847##############################################################################
848# Private (mode 7)
849##############################################################################
850
851_information_error_codes = {
852 0: "INFO_OKAY",
853 1: "INFO_ERR_IMPL",
854 2: "INFO_ERR_REQ",
855 3: "INFO_ERR_FMT",
856 4: "INFO_ERR_NODATA",
857 7: "INFO_ERR_AUTH"
858}
859
860
861_implementations = {
862 0: "IMPL_UNIV",
863 2: "IMPL_XNTPD_OLD",
864 3: "XNTPD"
865}
866
867
868_request_codes = {
869 0: "REQ_PEER_LIST",
870 1: "REQ_PEER_LIST_SUM",
871 2: "REQ_PEER_INFO",
872 3: "REQ_PEER_STATS",
873 4: "REQ_SYS_INFO",
874 5: "REQ_SYS_STATS",
875 6: "REQ_IO_STATS",
876 7: "REQ_MEM_STATS",
877 8: "REQ_LOOP_INFO",
878 9: "REQ_TIMER_STATS",
879 10: "REQ_CONFIG",
880 11: "REQ_UNCONFIG",
881 12: "REQ_SET_SYS_FLAG",
882 13: "REQ_CLR_SYS_FLAG",
883 14: "REQ_MONITOR",
884 15: "REQ_NOMONITOR",
885 16: "REQ_GET_RESTRICT",
886 17: "REQ_RESADDFLAGS",
887 18: "REQ_RESSUBFLAGS",
888 19: "REQ_UNRESTRICT",
889 20: "REQ_MON_GETLIST",
890 21: "REQ_RESET_STATS",
891 22: "REQ_RESET_PEER",
892 23: "REQ_REREAD_KEYS",
893 24: "REQ_DO_DIRTY_HACK",
894 25: "REQ_DONT_DIRTY_HACK",
895 26: "REQ_TRUSTKEY",
896 27: "REQ_UNTRUSTKEY",
897 28: "REQ_AUTHINFO",
898 29: "REQ_TRAPS",
899 30: "REQ_ADD_TRAP",
900 31: "REQ_CLR_TRAP",
901 32: "REQ_REQUEST_KEY",
902 33: "REQ_CONTROL_KEY",
903 34: "REQ_GET_CTLSTATS",
904 35: "REQ_GET_LEAPINFO",
905 36: "REQ_GET_CLOCKINFO",
906 37: "REQ_SET_CLKFUDGE",
907 38: "REQ_GET_KERNEL",
908 39: "REQ_GET_CLKBUGINFO",
909 41: "REQ_SET_PRECISION",
910 42: "REQ_MON_GETLIST_1",
911 43: "REQ_HOSTNAME_ASSOCID",
912 44: "REQ_IF_STATS",
913 45: "REQ_IF_RELOAD"
914}
915
916
917# Flags in the peer information returns
918_peer_flags = [
919 "INFO_FLAG_CONFIG",
920 "INFO_FLAG_SYSPEER",
921 "INFO_FLAG_BURST",
922 "INFO_FLAG_REFCLOCK",
923 "INFO_FLAG_PREFER",
924 "INFO_FLAG_AUTHENABLE",
925 "INFO_FLAG_SEL_CANDIDATE",
926 "INFO_FLAG_SHORTLIST",
927 "INFO_FLAG_IBURST"
928]
929
930
931# Flags in the system information returns
932_sys_info_flags = [
933 "INFO_FLAG_BCLIENT",
934 "INFO_FLAG_AUTHENTICATE",
935 "INFO_FLAG_NTP",
936 "INFO_FLAG_KERNEL",
937 "INFO_FLAG_CAL",
938 "INFO_FLAG_PPS_SYNC",
939 "INFO_FLAG_MONITOR",
940 "INFO_FLAG_FILEGEN",
941]
942
943
944class NTPInfoPeerList(Packet):
945
946 """
947 Used to return raw lists of peers.
948 """
949 name = "info_peer_list"
950 fields_desc = [
951 IPField("addr", "0.0.0.0"),
952 ShortField("port", 0),
953 ByteEnumField("hmode", 0, _ntp_modes),
954 FlagsField("flags", 0, 8, _peer_flags),
955 IntField("v6_flag", 0),
956 IntField("unused1", 0),
957 IP6Field("addr6", "::")
958 ]
959
960
961class NTPInfoPeerSummary(Packet):
962 """
963 Sort of the info that ntpdc returns by default.
964 """
965 name = "info_peer_summary"
966 fields_desc = [
967 IPField("dstaddr", "0.0.0.0"),
968 IPField("srcaddr", "0.0.0.0"),
969 ShortField("srcport", 0),
970 ByteField("stratum", 0),
971 ByteField("hpoll", 0),
972 ByteField("ppoll", 0),
973 ByteField("reach", 0),
974 FlagsField("flags", 0, 8, _peer_flags),
975 ByteField("hmode", _ntp_modes),
976 FixedPointField("delay", 0, size=32, frac_bits=16),
977 TimeStampField("offset", 0),
978 FixedPointField("dispersion", 0, size=32, frac_bits=16),
979 IntField("v6_flag", 0),
980 IntField("unused1", 0),
981 IP6Field("dstaddr6", "::"),
982 IP6Field("srcaddr6", "::")
983 ]
984
985
986class NTPInfoPeer(Packet):
987 """
988 Peer information structure.
989 """
990
991 name = "info_peer"
992 fields_desc = [
993 IPField("dstaddr", "0.0.0.0"),
994 IPField("srcaddr", "0.0.0.0"),
995 ShortField("srcport", 0),
996 FlagsField("flags", 0, 8, _peer_flags),
997 ByteField("leap", 0),
998 ByteEnumField("hmode", 0, _ntp_modes),
999 ByteField("pmode", 0),
1000 ByteField("stratum", 0),
1001 ByteField("ppoll", 0),
1002 ByteField("hpoll", 0),
1003 SignedByteField("precision", 0),
1004 ByteField("version", 0),
1005 ByteField("unused8", 0),
1006 ByteField("reach", 0),
1007 ByteField("unreach", 0),
1008 XByteField("flash", 0),
1009 ByteField("ttl", 0),
1010 XLEShortField("flash2", 0),
1011 ShortField("associd", 0),
1012 LEIntField("keyid", 0),
1013 IntField("pkeyid", 0),
1014 IPField("refid", 0),
1015 IntField("timer", 0),
1016 FixedPointField("rootdelay", 0, size=32, frac_bits=16),
1017 FixedPointField("rootdispersion", 0, size=32, frac_bits=16),
1018 TimeStampField("reftime", 0),
1019 TimeStampField("org", 0),
1020 TimeStampField("rec", 0),
1021 TimeStampField("xmt", 0),
1022 FieldListField(
1023 "filtdelay",
1024 [0.0 for i in range(0, _NTP_SHIFT)],
1025 FixedPointField("", 0, size=32, frac_bits=16),
1026 count_from=lambda p: _NTP_SHIFT
1027 ),
1028 FieldListField(
1029 "filtoffset",
1030 [0.0 for i in range(0, _NTP_SHIFT)],
1031 TimeStampField("", 0),
1032 count_from=lambda p: _NTP_SHIFT
1033 ),
1034 FieldListField(
1035 "order",
1036 [0 for i in range(0, _NTP_SHIFT)],
1037 ByteField("", 0),
1038 count_from=lambda p: _NTP_SHIFT
1039 ),
1040 FixedPointField("delay", 0, size=32, frac_bits=16),
1041 FixedPointField("dispersion", 0, size=32, frac_bits=16),
1042 TimeStampField("offset", 0),
1043 FixedPointField("selectdisp", 0, size=32, frac_bits=16),
1044 IntField("unused1", 0),
1045 IntField("unused2", 0),
1046 IntField("unused3", 0),
1047 IntField("unused4", 0),
1048 IntField("unused5", 0),
1049 IntField("unused6", 0),
1050 IntField("unused7", 0),
1051 FixedPointField("estbdelay", 0, size=32, frac_bits=16),
1052 IntField("v6_flag", 0),
1053 IntField("unused9", 0),
1054 IP6Field("dstaddr6", "::"),
1055 IP6Field("srcaddr6", "::"),
1056 ]
1057
1058
1059class NTPInfoPeerStats(Packet):
1060 """
1061 Peer statistics structure.
1062 """
1063
1064 name = "info_peer_stats"
1065 fields_desc = [
1066 IPField("dstaddr", "0.0.0.0"),
1067 IPField("srcaddr", "0.0.0.0"),
1068 ShortField("srcport", 0),
1069 FlagsField("flags", 0, 16, _peer_flags),
1070 IntField("timereset", 0),
1071 IntField("timereceived", 0),
1072 IntField("timetosend", 0),
1073 IntField("timereachable", 0),
1074 IntField("sent", 0),
1075 IntField("unused1", 0),
1076 IntField("processed", 0),
1077 IntField("unused2", 0),
1078 IntField("badauth", 0),
1079 IntField("bogusorg", 0),
1080 IntField("oldpkt", 0),
1081 IntField("unused3", 0),
1082 IntField("unused4", 0),
1083 IntField("seldisp", 0),
1084 IntField("selbroken", 0),
1085 IntField("unused5", 0),
1086 ByteField("candidate", 0),
1087 ByteField("unused6", 0),
1088 ByteField("unused7", 0),
1089 ByteField("unused8", 0),
1090 IntField("v6_flag", 0),
1091 IntField("unused9", 0),
1092 IP6Field("dstaddr6", "::"),
1093 IP6Field("srcaddr6", "::"),
1094 ]
1095
1096
1097class NTPInfoLoop(Packet):
1098 """
1099 Loop filter variables.
1100 """
1101
1102 name = "info_loop"
1103 fields_desc = [
1104 TimeStampField("last_offset", 0),
1105 TimeStampField("drift_comp", 0),
1106 IntField("compliance", 0),
1107 IntField("watchdog_timer", 0)
1108 ]
1109
1110
1111class NTPInfoSys(Packet):
1112 """
1113 System info. Mostly the sys.* variables, plus a few unique to
1114 the implementation.
1115 """
1116
1117 name = "info_sys"
1118 fields_desc = [
1119 IPField("peer", "0.0.0.0"),
1120 ByteField("peer_mode", 0),
1121 ByteField("leap", 0),
1122 ByteField("stratum", 0),
1123 SignedByteField("precision", 0),
1124 FixedPointField("rootdelay", 0, size=32, frac_bits=16),
1125 FixedPointField("rootdispersion", 0, size=32, frac_bits=16),
1126 IPField("refid", 0),
1127 TimeStampField("reftime", 0),
1128 IntField("poll", 0),
1129 FlagsField("flags", 0, 8, _sys_info_flags),
1130 ByteField("unused1", 0),
1131 ByteField("unused2", 0),
1132 ByteField("unused3", 0),
1133 FixedPointField("bdelay", 0, size=32, frac_bits=16),
1134 FixedPointField("frequency", 0, size=32, frac_bits=16),
1135 TimeStampField("authdelay", 0),
1136 FixedPointField("stability", 0, size=32, frac_bits=16),
1137 IntField("v6_flag", 0),
1138 IntField("unused4", 0),
1139 IP6Field("peer6", "::")
1140 ]
1141
1142
1143class NTPInfoSysStats(Packet):
1144 """
1145 System stats. These are collected in the protocol module.
1146 """
1147
1148 name = "info_sys_stats"
1149 fields_desc = [
1150 IntField("timeup", 0),
1151 IntField("timereset", 0),
1152 IntField("denied", 0),
1153 IntField("oldversionpkt", 0),
1154 IntField("newversionpkt", 0),
1155 IntField("unknownversion", 0),
1156 IntField("badlength", 0),
1157 IntField("processed", 0),
1158 IntField("badauth", 0),
1159 IntField("received", 0),
1160 IntField("limitrejected", 0)
1161 ]
1162
1163
1164class NTPInfoMemStats(Packet):
1165 """
1166 Peer memory statistics.
1167 """
1168
1169 name = "info_mem_stats"
1170 fields_desc = [
1171 IntField("timereset", 0),
1172 ShortField("totalpeermem", 0),
1173 ShortField("freepeermem", 0),
1174 IntField("findpeer_calls", 0),
1175 IntField("allocations", 0),
1176 IntField("demobilizations", 0),
1177 FieldListField(
1178 "hashcount",
1179 [0.0 for i in range(0, _NTP_HASH_SIZE)],
1180 ByteField("", 0),
1181 count_from=lambda p: _NTP_HASH_SIZE,
1182 max_count=_NTP_HASH_SIZE
1183 )
1184 ]
1185
1186
1187class NTPInfoIOStats(Packet):
1188 """
1189 I/O statistics.
1190 """
1191
1192 name = "info_io_stats"
1193 fields_desc = [
1194 IntField("timereset", 0),
1195 ShortField("totalrecvbufs", 0),
1196 ShortField("freerecvbufs", 0),
1197 ShortField("fullrecvbufs", 0),
1198 ShortField("lowwater", 0),
1199 IntField("dropped", 0),
1200 IntField("ignored", 0),
1201 IntField("received", 0),
1202 IntField("sent", 0),
1203 IntField("notsent", 0),
1204 IntField("interrupts", 0),
1205 IntField("int_received", 0)
1206 ]
1207
1208
1209class NTPInfoTimerStats(Packet):
1210 """
1211 Timer stats.
1212 """
1213
1214 name = "info_timer_stats"
1215 fields_desc = [
1216 IntField("timereset", 0),
1217 IntField("alarms", 0),
1218 IntField("overflows", 0),
1219 IntField("xmtcalls", 0),
1220 ]
1221
1222
1223_conf_peer_flags = [
1224 "CONF_FLAG_AUTHENABLE",
1225 "CONF_FLAG_PREFER",
1226 "CONF_FLAG_BURST",
1227 "CONF_FLAG_IBURST",
1228 "CONF_FLAG_NOSELECT",
1229 "CONF_FLAG_SKEY"
1230]
1231
1232
1233class NTPConfPeer(Packet):
1234 """
1235 Structure for passing peer configuration information.
1236 """
1237
1238 name = "conf_peer"
1239 fields_desc = [
1240 IPField("peeraddr", "0.0.0.0"),
1241 ByteField("hmode", 0),
1242 ByteField("version", 0),
1243 ByteField("minpoll", 0),
1244 ByteField("maxpoll", 0),
1245 FlagsField("flags", 0, 8, _conf_peer_flags),
1246 ByteField("ttl", 0),
1247 ShortField("unused1", 0),
1248 IntField("keyid", 0),
1249 StrFixedLenField("keystr", "", length=128),
1250 IntField("v6_flag", 0),
1251 IntField("unused2", 0),
1252 IP6Field("peeraddr6", "::")
1253 ]
1254
1255
1256class NTPConfUnpeer(Packet):
1257 """
1258 Structure for passing peer deletion information.
1259 """
1260
1261 name = "conf_unpeer"
1262 fields_desc = [
1263 IPField("peeraddr", "0.0.0.0"),
1264 IntField("v6_flag", 0),
1265 IP6Field("peeraddr6", "::")
1266 ]
1267
1268
1269_restrict_flags = [
1270 "RES_IGNORE",
1271 "RES_DONTSERVE",
1272 "RES_DONTTRUST",
1273 "RES_VERSION",
1274 "RES_NOPEER",
1275 "RES_LIMITED",
1276 "RES_NOQUERY",
1277 "RES_NOMODIFY",
1278 "RES_NOTRAP",
1279 "RES_LPTRAP",
1280 "RES_KOD",
1281 "RES_MSSNTP",
1282 "RES_FLAKE",
1283 "RES_NOMRULIST",
1284]
1285
1286
1287class NTPConfRestrict(Packet):
1288 """
1289 Structure used for specifying restrict entries.
1290 """
1291
1292 name = "conf_restrict"
1293 fields_desc = [
1294 IPField("addr", "0.0.0.0"),
1295 IPField("mask", "0.0.0.0"),
1296 FlagsField("flags", 0, 16, _restrict_flags),
1297 ShortField("m_flags", 0),
1298 IntField("v6_flag", 0),
1299 IP6Field("addr6", "::"),
1300 IP6Field("mask6", "::")
1301 ]
1302
1303
1304class NTPInfoKernel(Packet):
1305 """
1306 Structure used for returning kernel pll/PPS information
1307 """
1308
1309 name = "info_kernel"
1310 fields_desc = [
1311 IntField("offset", 0),
1312 IntField("freq", 0),
1313 IntField("maxerror", 0),
1314 IntField("esterror", 0),
1315 ShortField("status", 0),
1316 ShortField("shift", 0),
1317 IntField("constant", 0),
1318 IntField("precision", 0),
1319 IntField("tolerance", 0),
1320 IntField("ppsfreq", 0),
1321 IntField("jitter", 0),
1322 IntField("stabil", 0),
1323 IntField("jitcnt", 0),
1324 IntField("calcnt", 0),
1325 IntField("errcnt", 0),
1326 IntField("stbcnt", 0),
1327 ]
1328
1329
1330class NTPInfoIfStatsIPv4(Packet):
1331 """
1332 Interface statistics.
1333 """
1334
1335 name = "info_if_stats"
1336 fields_desc = [
1337 PadField(IPField("unaddr", "0.0.0.0"), 16, padwith=b"\x00"),
1338 PadField(IPField("unbcast", "0.0.0.0"), 16, padwith=b"\x00"),
1339 PadField(IPField("unmask", "0.0.0.0"), 16, padwith=b"\x00"),
1340 IntField("v6_flag", 0),
1341 StrFixedLenField("ifname", "", length=32),
1342 IntField("flags", 0),
1343 IntField("last_ttl", 0),
1344 IntField("num_mcast", 0),
1345 IntField("received", 0),
1346 IntField("sent", 0),
1347 IntField("notsent", 0),
1348 IntField("uptime", 0),
1349 IntField("scopeid", 0),
1350 IntField("ifindex", 0),
1351 IntField("ifnum", 0),
1352 IntField("peercnt", 0),
1353 ShortField("family", 0),
1354 ByteField("ignore_packets", 0),
1355 ByteField("action", 0),
1356 IntField("_filler0", 0)
1357 ]
1358
1359
1360class NTPInfoIfStatsIPv6(Packet):
1361 """
1362 Interface statistics.
1363 """
1364
1365 name = "info_if_stats"
1366 fields_desc = [
1367 IP6Field("unaddr", "::"),
1368 IP6Field("unbcast", "::"),
1369 IP6Field("unmask", "::"),
1370 IntField("v6_flag", 0),
1371 StrFixedLenField("ifname", "", length=32),
1372 IntField("flags", 0),
1373 IntField("last_ttl", 0),
1374 IntField("num_mcast", 0),
1375 IntField("received", 0),
1376 IntField("sent", 0),
1377 IntField("notsent", 0),
1378 IntField("uptime", 0),
1379 IntField("scopeid", 0),
1380 IntField("ifindex", 0),
1381 IntField("ifnum", 0),
1382 IntField("peercnt", 0),
1383 ShortField("family", 0),
1384 ByteField("ignore_packets", 0),
1385 ByteField("action", 0),
1386 IntField("_filler0", 0)
1387 ]
1388
1389
1390class NTPInfoMonitor1(Packet):
1391 """
1392 Structure used for returning monitor data.
1393 """
1394
1395 name = "InfoMonitor1"
1396 fields_desc = [
1397 IntField("lasttime", 0),
1398 IntField("firsttime", 0),
1399 IntField("lastdrop", 0),
1400 IntField("count", 0),
1401 IPField("addr", "0.0.0.0"),
1402 IPField("daddr", "0.0.0.0"),
1403 IntField("flags", 0),
1404 ShortField("port", 0),
1405 ByteField("mode", 0),
1406 ByteField("version", 0),
1407 IntField("v6_flag", 0),
1408 IntField("unused1", 0),
1409 IP6Field("addr6", "::"),
1410 IP6Field("daddr6", "::")
1411 ]
1412
1413
1414class NTPInfoAuth(Packet):
1415 """
1416 Structure used to return information concerning the authentication module.
1417 """
1418
1419 name = "info_auth"
1420 fields_desc = [
1421 IntField("timereset", 0),
1422 IntField("numkeys", 0),
1423 IntField("numfreekeys", 0),
1424 IntField("keylookups", 0),
1425 IntField("keynotfound", 0),
1426 IntField("encryptions", 0),
1427 IntField("decryptions", 0),
1428 IntField("expired", 0),
1429 IntField("keyuncached", 0),
1430 ]
1431
1432
1433class NTPConfTrap(Packet):
1434 """
1435 Structure used to pass add/clear trap information to the client
1436 """
1437
1438 name = "conf_trap"
1439 fields_desc = [
1440 IPField("local_address", "0.0.0.0"),
1441 IPField("trap_address", "0.0.0.0"),
1442 ShortField("trap_port", 0),
1443 ShortField("unused", 0),
1444 IntField("v6_flag", 0),
1445 IP6Field("local_address6", "::"),
1446 IP6Field("trap_address6", "::"),
1447 ]
1448
1449
1450class NTPInfoControl(Packet):
1451 """
1452 Structure used to return statistics from the control module.
1453 """
1454
1455 name = "info_control"
1456 fields_desc = [
1457 IntField("ctltimereset", 0),
1458 IntField("numctlreq", 0),
1459 IntField("numctlbadpkts", 0),
1460 IntField("numctlresponses", 0),
1461 IntField("numctlfrags", 0),
1462 IntField("numctlerrors", 0),
1463 IntField("numctltooshort", 0),
1464 IntField("numctlinputresp", 0),
1465 IntField("numctlinputfrag", 0),
1466 IntField("numctlinputerr", 0),
1467 IntField("numctlbadoffset", 0),
1468 IntField("numctlbadversion", 0),
1469 IntField("numctldatatooshort", 0),
1470 IntField("numctlbadop", 0),
1471 IntField("numasyncmsgs", 0),
1472 ]
1473
1474
1475# ntp_request.h
1476_ntpd_private_errors = {
1477 0: "no error",
1478 1: "incompatible implementation number",
1479 2: "unimplemented request code",
1480 3: "format error (wrong data items, data size, packet size etc.)",
1481 4: "no data available (e.g. request for details on unknown peer)",
1482 5: "I don\"t know",
1483 6: "I don\"t know",
1484 7: "authentication failure (i.e. permission denied)",
1485}
1486
1487
1488# dict mapping request codes to the right response data class
1489_private_data_objects = {
1490 0: NTPInfoPeerList, # "REQ_PEER_LIST",
1491 1: NTPInfoPeerSummary, # "REQ_PEER_LIST_SUM",
1492 2: NTPInfoPeer, # "REQ_PEER_INFO",
1493 3: NTPInfoPeerStats, # "REQ_PEER_STATS",
1494 4: NTPInfoSys, # "REQ_SYS_INFO",
1495 5: NTPInfoSysStats, # "REQ_SYS_STATS",
1496 6: NTPInfoIOStats, # "REQ_IO_STATS",
1497 7: NTPInfoMemStats, # "REQ_MEM_STATS",
1498 8: NTPInfoLoop, # "REQ_LOOP_INFO",
1499 9: NTPInfoTimerStats, # "REQ_TIMER_STATS",
1500 10: NTPConfPeer, # "REQ_CONFIG",
1501 11: NTPConfUnpeer, # "REQ_UNCONFIG",
1502 28: NTPInfoAuth, # "REQ_AUTHINFO",
1503 30: NTPConfTrap, # "REQ_ADD_TRAP",
1504 34: NTPInfoControl, # "REQ_GET_CTLSTATS",
1505 38: NTPInfoKernel, # "REQ_GET_KERNEL",
1506 42: NTPInfoMonitor1, # "REQ_MON_GETLIST_1",
1507}
1508
1509
1510class NTPPrivateRespPacketListField(PacketListField):
1511 """
1512 PacketListField handling the response data.
1513 """
1514
1515 def m2i(self, pkt, s):
1516 ret = None
1517
1518 # info_if_stats
1519 if pkt.request_code == 44 or pkt.request_code == 45:
1520 is_v6 = struct.unpack("!I", s[48:52])[0]
1521 ret = NTPInfoIfStatsIPv6(s) if is_v6 else NTPInfoIfStatsIPv4(s)
1522 else:
1523 ret = _private_data_objects.get(pkt.request_code, conf.raw_layer)(s) # noqa: E501
1524
1525 return ret
1526
1527 def getfield(self, pkt, s):
1528 lst = []
1529 remain = s
1530 length = pkt.data_item_size
1531 if length > 0:
1532 item_counter = 0
1533 # Response payloads can be placed in several packets
1534 while len(remain) >= pkt.data_item_size and item_counter < pkt.nb_items: # noqa: E501
1535 current = remain[:length]
1536 remain = remain[length:]
1537 current_packet = self.m2i(pkt, current)
1538 lst.append(current_packet)
1539 item_counter += 1
1540
1541 return remain, lst
1542
1543
1544class NTPPrivateReqPacket(Packet):
1545 """
1546 Packet handling request data.
1547 """
1548
1549 name = "request data"
1550 fields_desc = [StrField("req_data", "")]
1551
1552
1553_request_codes = {
1554 0: "REQ_PEER_LIST",
1555 1: "REQ_PEER_LIST_SUM",
1556 2: "REQ_PEER_INFO",
1557 3: "REQ_PEER_STATS",
1558 4: "REQ_SYS_INFO",
1559 5: "REQ_SYS_STATS",
1560 6: "REQ_IO_STATS",
1561 7: "REQ_MEM_STATS",
1562 8: "REQ_LOOP_INFO",
1563 9: "REQ_TIMER_STATS",
1564 10: "REQ_CONFIG",
1565 11: "REQ_UNCONFIG",
1566 12: "REQ_SET_SYS_FLAG",
1567 13: "REQ_CLR_SYS_FLAG",
1568 14: "REQ_MONITOR",
1569 15: "REQ_NOMONITOR",
1570 16: "REQ_GET_RESTRICT",
1571 17: "REQ_RESADDFLAGS",
1572 18: "REQ_RESSUBFLAGS",
1573 19: "REQ_UNRESTRICT",
1574 20: "REQ_MON_GETLIST",
1575 21: "REQ_RESET_STATS",
1576 22: "REQ_RESET_PEER",
1577 23: "REQ_REREAD_KEYS",
1578 24: "REQ_DO_DIRTY_HACK",
1579 25: "REQ_DONT_DIRTY_HACK",
1580 26: "REQ_TRUSTKEY",
1581 27: "REQ_UNTRUSTKEY",
1582 28: "REQ_AUTHINFO",
1583 29: "REQ_TRAPS",
1584 30: "REQ_ADD_TRAP",
1585 31: "REQ_CLR_TRAP",
1586 32: "REQ_REQUEST_KEY",
1587 33: "REQ_CONTROL_KEY",
1588 34: "REQ_GET_CTLSTATS",
1589 35: "REQ_GET_LEAPINFO",
1590 36: "REQ_GET_CLOCKINFO",
1591 37: "REQ_SET_CLKFUDGE",
1592 38: "REQ_GET_KERNEL",
1593 39: "REQ_GET_CLKBUGINFO",
1594 41: "REQ_SET_PRECISION",
1595 42: "REQ_MON_GETLIST_1",
1596 43: "REQ_HOSTNAME_ASSOCID",
1597 44: "REQ_IF_STATS",
1598 45: "REQ_IF_RELOAD"
1599}
1600
1601
1602class NTPPrivateReqPacketListField(PacketListField):
1603 """
1604 Handles specific request packets.
1605 """
1606
1607 # See ntpdc/ntpdc.c and ntpdc/ntpdc_ops.c
1608
1609 def m2i(self, pkt, s):
1610 ret = None
1611
1612 if pkt.request_code == 2 or pkt.request_code == 3:
1613 # REQ_PEER_INFO (see ntpdc/ntpdc_ops.c: showpeer())
1614 # REQ_PEER_STATS (for request only)
1615 ret = NTPInfoPeerList(s)
1616
1617 elif pkt.request_code == 10:
1618 # REQ_CONFIG
1619 ret = NTPConfPeer(s)
1620
1621 elif pkt.request_code == 11:
1622 # REQ_CONFIG
1623 ret = NTPConfUnpeer(s)
1624
1625 elif pkt.request_code == 17:
1626 # REQ_RESADDFLAGS
1627 ret = NTPConfRestrict(s)
1628
1629 elif pkt.request_code == 18:
1630 # REQ_RESSUBFLAGS
1631 ret = NTPConfRestrict(s)
1632
1633 elif pkt.request_code == 22:
1634 # REQ_RESET_PEER
1635 ret = NTPConfUnpeer(s)
1636
1637 elif pkt.request_code == 30 or pkt.request_code == 31:
1638 # REQ_ADD_TRAP
1639 ret = NTPConfTrap(s)
1640
1641 else:
1642 ret = NTPPrivateReqPacket(s)
1643
1644 return ret
1645
1646 def getfield(self, pkt, s):
1647 lst = []
1648 remain = s
1649 length = pkt.data_item_size
1650 if length > 0:
1651 item_counter = 0
1652 while len(remain) >= pkt.data_item_size * pkt.nb_items and item_counter < pkt.nb_items: # noqa: E501
1653 current = remain[:length]
1654 remain = remain[length:]
1655 current_packet = self.m2i(pkt, current)
1656 lst.append(current_packet)
1657 item_counter += 1
1658
1659 # If "auth" bit is set, don't forget the padding bytes
1660 if pkt.auth:
1661 padding_end = len(remain) - _NTP_PRIVATE_REQ_PKT_TAIL_LEN
1662 current_packet = conf.raw_layer(remain[:padding_end])
1663 lst.append(current_packet)
1664 remain = remain[padding_end:]
1665
1666 return remain, lst
1667
1668
1669class NTPPrivatePktTail(Packet):
1670 """
1671 include/ntp_request.h
1672 The req_pkt_tail structure is used by ntpd to adjust for different
1673 packet sizes that may arrive.
1674 """
1675
1676 name = "req_pkt_tail"
1677 fields_desc = [
1678 TimeStampField("tstamp", 0),
1679 IntField("key_id", 0),
1680 XStrFixedLenField(
1681 "dgst", "", length_from=lambda x: _NTP_AUTH_MD5_DGST_SIZE)
1682 ]
1683
1684
1685class NTPPrivate(NTP):
1686 """
1687 Packet handling the private (mode 7) messages.
1688 """
1689
1690 #########################################################################
1691 # ntpd source code: ntp_request.h
1692 #########################################################################
1693 #
1694 # A mode 7 packet is used exchanging data between an NTP server
1695 # and a client for purposes other than time synchronization, e.g.
1696 # monitoring, statistics gathering and configuration. A mode 7
1697 # packet has the following format:
1698 #
1699 # 0 1 2 3
1700 # 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
1701 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1702 # |R|M| VN | Mode|A| Sequence | Implementation| Req Code |
1703 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1704 # | Err | Number of data items | MBZ | Size of data item |
1705 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1706 # | |
1707 # | Data (Minimum 0 octets, maximum 500 octets) |
1708 # | |
1709 # [...] |
1710 # | |
1711 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1712 # | Encryption Keyid (when A bit set) |
1713 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1714 # | |
1715 # | Message Authentication Code (when A bit set) |
1716 # | |
1717 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1718 #
1719 # where the fields are (note that the client sends requests, the server
1720 # responses):
1721 #
1722 # Response Bit: This packet is a response (if clear, packet is a request).
1723 #
1724 # More Bit: Set for all packets but the last in a response which
1725 # requires more than one packet.
1726 #
1727 # Version Number: 2 for current version
1728 #
1729 # Mode: Always 7
1730 #
1731 # Authenticated bit: If set, this packet is authenticated.
1732 #
1733 # Sequence number: For a multipacket response, contains the sequence
1734 # number of this packet. 0 is the first in the sequence,
1735 # 127 (or less) is the last. The More Bit must be set in
1736 # all packets but the last.
1737 #
1738 # Implementation number: The number of the implementation this request code
1739 # is defined by. An implementation number of zero is used
1740 # for request codes/data formats which all implementations
1741 # agree on. Implementation number 255 is reserved (for
1742 # extensions, in case we run out).
1743 #
1744 # Request code: An implementation-specific code which specifies the
1745 # operation to be (which has been) performed and/or the
1746 # format and semantics of the data included in the packet.
1747 #
1748 # Err: Must be 0 for a request. For a response, holds an error
1749 # code relating to the request. If nonzero, the operation
1750 # requested wasn't performed.
1751 #
1752 # 0 - no error
1753 # 1 - incompatible implementation number
1754 # 2 - unimplemented request code
1755 # 3 - format error (wrong data items, data size, packet size etc.) # noqa: E501
1756 # 4 - no data available (e.g. request for details on unknown peer) # noqa: E501
1757 # 5-6 I don"t know
1758 # 7 - authentication failure (i.e. permission denied)
1759 #
1760 # Number of data items: number of data items in packet. 0 to 500
1761 #
1762 # MBZ: A reserved data field, must be zero in requests and responses.
1763 #
1764 # Size of data item: size of each data item in packet. 0 to 500
1765 #
1766 # Data: Variable sized area containing request/response data. For
1767 # requests and responses the size in octets must be greater
1768 # than or equal to the product of the number of data items
1769 # and the size of a data item. For requests the data area
1770 # must be exactly 40 octets in length. For responses the
1771 # data area may be any length between 0 and 500 octets
1772 # inclusive.
1773 #
1774 # Message Authentication Code: Same as NTP spec, in definition and function. # noqa: E501
1775 # May optionally be included in requests which require
1776 # authentication, is never included in responses.
1777 #
1778 # The version number, mode and keyid have the same function and are
1779 # in the same location as a standard NTP packet. The request packet
1780 # is the same size as a standard NTP packet to ease receive buffer
1781 # management, and to allow the same encryption procedure to be used
1782 # both on mode 7 and standard NTP packets. The mac is included when
1783 # it is required that a request be authenticated, the keyid should be
1784 # zero in requests in which the mac is not included.
1785 #
1786 # The data format depends on the implementation number/request code pair
1787 # and whether the packet is a request or a response. The only requirement
1788 # is that data items start in the octet immediately following the size
1789 # word and that data items be concatenated without padding between (i.e.
1790 # if the data area is larger than data_items*size, all padding is at
1791 # the end). Padding is ignored, other than for encryption purposes.
1792 # Implementations using encryption might want to include a time stamp
1793 # or other data in the request packet padding. The key used for requests
1794 # is implementation defined, but key 15 is suggested as a default.
1795 #########################################################################
1796 #
1797
1798 name = "Private (mode 7)"
1799 match_subclass = True
1800 fields_desc = [
1801 BitField("response", 0, 1),
1802 BitField("more", 0, 1),
1803 BitField("version", 2, 3),
1804 BitEnumField("mode", 7, 3, _ntp_modes),
1805 BitField("auth", 0, 1),
1806 BitField("seq", 0, 7),
1807 ByteEnumField("implementation", 0, _implementations),
1808 ByteEnumField("request_code", 0, _request_codes),
1809 BitEnumField("err", 0, 4, _ntpd_private_errors),
1810 BitField("nb_items", 0, 12),
1811 BitField("mbz", 0, 4),
1812 BitField("data_item_size", 0, 12),
1813 ConditionalField(
1814 NTPPrivateReqPacketListField(
1815 "req_data",
1816 [],
1817 Packet,
1818 length_from=lambda p: p.data_item_size,
1819 count_from=lambda p: p.nb_items
1820 ),
1821 lambda p: p.response == 0
1822 ),
1823 # Responses
1824 ConditionalField(
1825 NTPPrivateRespPacketListField(
1826 "data",
1827 [],
1828 Packet,
1829 length_from=lambda p: p.data_item_size,
1830 count_from=lambda p: p.nb_items
1831 ),
1832 lambda p: p.response == 1
1833 ),
1834 # Responses are not supposed to be authenticated
1835 ConditionalField(PacketField("authenticator", "", NTPPrivatePktTail),
1836 lambda p: p.response == 0 and p.auth == 1),
1837 ]
1838
1839
1840##############################################################################
1841# Layer bindings
1842##############################################################################
1843
1844bind_layers(UDP, NTP, {"sport": 123})
1845bind_layers(UDP, NTP, {"dport": 123})
1846bind_layers(UDP, NTP, {"sport": 123, "dport": 123})