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