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