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