Coverage Report

Created: 2023-01-17 06:15

/src/PcapPlusPlus/Packet++/header/NtpLayer.h
Line
Count
Source (jump to first uncovered line)
1
#ifndef PACKETPP_NTP_LAYER
2
#define PACKETPP_NTP_LAYER
3
4
#include "Logger.h"
5
#include "Layer.h"
6
#include "IpAddress.h"
7
8
/// @file
9
10
/**
11
 * \namespace pcpp
12
 * \brief The main namespace for the PcapPlusPlus lib
13
 */
14
namespace pcpp
15
{
16
    /**
17
   * @class NtpLayer
18
   * Represents a NTP (Network Time Protocol) layer
19
     *
20
     * @brief The NTP packet consists of an integral number of 32-bit (4 octet) words in network byte order.
21
     * The packet format consists of three components: the header itself, one or more optional extension fields (for v4),
22
     * and an optional message authentication code (MAC). Currently the extension fields are not supported. The NTP header is:
23
     *
24
     * @verbatim
25
       0                   1                   2                   3
26
       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
27
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28
      |LI | VN  |Mode |    Stratum     |     Poll      |  Precision   |
29
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30
      |                         Root Delay                            |
31
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32
      |                         Root Dispersion                       |
33
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34
      |                          Reference ID                         |
35
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36
      |                                                               |
37
      +                     Reference Timestamp (64)                  +
38
      |                                                               |
39
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40
      |                                                               |
41
      +                      Origin Timestamp (64)                    +
42
      |                                                               |
43
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44
      |                                                               |
45
      +                      Receive Timestamp (64)                   +
46
      |                                                               |
47
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48
      |                                                               |
49
      +                      Transmit Timestamp (64)                  +
50
      |                                                               |
51
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52
      |                                                               |
53
      .                                                               .
54
      .                Extension Field 1 (variable, only v4)          .
55
      .                                                               .
56
      |                                                               |
57
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58
      |                                                               |
59
      .                                                               .
60
      .                Extension Field 1 (variable, only v4)          .
61
      .                                                               .
62
      |                                                               |
63
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
64
      |                          Key Identifier                       |
65
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66
      |                                                               |
67
      |                   dgst (128 for v4, 64 for v3)                |
68
      |                                                               |
69
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70
     @endverbatim
71
     *
72
   */
73
    class NtpLayer : public Layer
74
    {
75
    private:
76
#pragma pack(push, 1)
77
        struct ntp_header
78
        {
79
#if (BYTE_ORDER == LITTLE_ENDIAN)
80
            /// 3-bit integer representing the mode
81
            uint8_t mode:3,
82
            /// 3-bit integer representing the NTP version number
83
            version:3,
84
            /// LI Leap Indicator (leap): 2-bit integer warning of an impending leap second to be inserted or deleted in the last minute of the current month
85
            leapIndicator:2;
86
#else
87
            /// LI Leap Indicator (leap): 2-bit integer warning of an impending leap second to be inserted or deleted in the last minute of the current month
88
            uint8_t leapIndicator:2,
89
            /// 3-bit integer representing the NTP version number
90
            version:3,
91
            /// 3-bit integer representing the mode
92
            mode:3;
93
#endif
94
            /// 8-bit integer representing the stratum
95
            uint8_t stratum;
96
            /// Total round-trip delay to the reference clock, in log2 seconds.
97
            int8_t pollInterval,
98
            /// 8-bit signed integer representing the precision of the system clock, in log2 seconds.
99
            precision;
100
            /// Total round-trip delay to the reference clock, in NTP short format.
101
            uint32_t rootDelay,
102
            /// Total dispersion to the reference clock, in NTP short format.
103
            rootDispersion,
104
            /// 32-bit code identifying the particular server or reference clock.  The interpretation depends on the value in the stratum field.
105
            referenceIdentifier;
106
            /// Time when the system clock was last set or corrected, in NTP timestamp format.
107
            uint64_t referenceTimestamp,
108
            /// Time at the client when the request departed for the server, in NTP timestamp format.
109
            originTimestamp,
110
            /// Time at the client when the request departed for the server, in NTP timestamp format.
111
            receiveTimestamp,
112
            /// Time at the server when the response left for the client, in NTP timestamp format.
113
            transmitTimestamp;
114
        };
115
#pragma pack(pop)
116
117
#pragma pack(push, 1)
118
        struct ntp_v3_auth
119
        {
120
            /// An integer identifying the cryptographic key used to generate the message-authentication code
121
            uint32_t keyID;
122
            /// This is an integer identifying the cryptographic key used to generate the message-authentication code.
123
            uint8_t dgst[8]; // 64 bit DES based
124
        };
125
#pragma pack(pop)
126
127
#pragma pack(push, 1)
128
        struct ntp_v4_auth_md5
129
        {
130
            /// 32-bit unsigned integer used by the client and server to designate a secret 128-bit MD5 key.
131
            uint32_t keyID;
132
            /// 128-bit MD5 hash
133
            uint8_t dgst[16];
134
        };
135
#pragma pack(pop)
136
137
#pragma pack(push, 1)
138
        struct ntp_v4_auth_sha1
139
        {
140
            /// 32-bit unsigned integer used by the client and server to designate a secret 160-bit SHA1 key.
141
            uint32_t keyID;
142
            /// 160-bit SHA1 hash
143
            uint8_t dgst[20];
144
        };
145
#pragma pack(pop)
146
147
0
        ntp_header *getNtpHeader() const { return (ntp_header *)m_Data; }
148
149
    public:
150
        /**
151
        * Warning of an impending leap second to be inserted or deleted in the last minute of the current month
152
        */
153
        enum LeapIndicator
154
        {
155
            /// Normal, no leap second
156
            NoWarning = 0,
157
            /// Last minute of the day has 61 seconds
158
            Last61Secs,
159
            /// Last minute of the day has 59 seconds
160
            Last59Secs,
161
            /// Unknown (clock unsynchronized)
162
            Unknown
163
        };
164
165
        /**
166
         * Representing the NTP association modes
167
         */
168
        enum Mode
169
        {
170
            /// Reserved variable
171
            Reserved = 0,
172
            /// Symmetrically active
173
            SymActive,
174
            /// Symmetrically passive
175
            SymPassive,
176
            /// Client mode
177
            Client,
178
            /// Server mode
179
            Server,
180
            /// Broadcasting mode
181
            Broadcast,
182
            /// NTP control messages
183
            Control,
184
            /// Reserved for private use
185
            PrivateUse
186
        };
187
188
        /**
189
         * 32-bit code identifying the particular server or reference clock.
190
         * The interpretation depends on the value in the stratum field.
191
         */
192
        enum ClockSource
193
        {
194
            // NTPv4
195
196
            /// Geosynchronous Orbit Environment Satellite
197
            GOES = ('G') | ('O' << 8) | ('E' << 16) | ('S' << 24),
198
            /// Global Position System
199
            GPS = ('G') | ('P' << 8) | ('S' << 16),
200
            /// Galileo Positioning System
201
            GAL = ('G') | ('A' << 8) | ('L' << 16),
202
            /// Generic pulse-per-second
203
            PPS = ('P') | ('P' << 8) | ('S' << 16),
204
            /// Inter-Range Instrumentation Group
205
            IRIG = ('I') | ('R' << 8) | ('I' << 16) | ('G' << 24),
206
            /// LF Radio WWVB Ft. Collins, CO 60 kHz
207
            WWVB = ('W') | ('W' << 8) | ('V' << 16) | ('B' << 24),
208
            /// LF Radio DCF77 Mainflingen, DE 77.5 kHz
209
            DCF = ('D') | ('C' << 8) | ('F' << 16),
210
            /// LF Radio HBG Prangins, HB 75 kHz
211
            HBG = ('H') | ('B' << 8) | ('G' << 16),
212
            /// LF Radio MSF Anthorn, UK 60 kHz
213
            MSF = ('M') | ('S' << 8) | ('F' << 16),
214
            /// LF Radio JJY Fukushima, JP 40 kHz, Saga, JP 60 kHz
215
            JJY = ('J') | ('J' << 8) | ('Y' << 16),
216
            /// MF Radio LORAN C station, 100 kHz
217
            LORC = ('L') | ('O' << 8) | ('R' << 16) | ('C' << 24),
218
            /// MF Radio Allouis, FR 162 kHz
219
            TDF = ('T') | ('D' << 8) | ('F' << 16),
220
            /// HF Radio CHU Ottawa, Ontario
221
            CHU = ('C') | ('H' << 8) | ('U' << 16),
222
            /// HF Radio WWV Ft. Collins, CO
223
            WWV = ('W') | ('W' << 8) | ('V' << 16),
224
            /// HF Radio WWVH Kauai, HI
225
            WWVH = ('W') | ('W' << 8) | ('V' << 16) | ('H' << 24),
226
            /// NIST telephone modem
227
            NIST = ('N') | ('I' << 8) | ('S' << 16) | ('T' << 24),
228
            /// NIST telephone modem
229
            ACTS = ('A') | ('C' << 8) | ('T' << 16) | ('S' << 24),
230
            /// USNO telephone modem
231
            USNO = ('U') | ('S' << 8) | ('N' << 16) | ('O' << 24),
232
            /// European telephone modem
233
            PTB = ('P') | ('T' << 8) | ('B' << 16),
234
            /// Meinberg DCF77 with amplitude modulation (Ref: https://www.meinbergglobal.com/english/info/ntp-refid.htm)
235
            DCFa = ('D') | ('C' << 8) | ('F' << 16) | ('a' << 24),
236
            /// Meinberg DCF77 with phase modulation)/pseudo random phase modulation (Ref: https://www.meinbergglobal.com/english/info/ntp-refid.htm)
237
            DCFp = ('D') | ('C' << 8) | ('F' << 16) | ('p' << 24),
238
            /// Meinberg GPS (with shared memory access) (Ref: https://www.meinbergglobal.com/english/info/ntp-refid.htm)
239
            GPSs = ('G') | ('P' << 8) | ('S' << 16) | ('s' << 24),
240
            /// Meinberg GPS (with interrupt based access) (Ref: https://www.meinbergglobal.com/english/info/ntp-refid.htm)
241
            GPSi = ('G') | ('P' << 8) | ('S' << 16) | ('i' << 24),
242
            /// Meinberg GPS/GLONASS (with shared memory access) (Ref: https://www.meinbergglobal.com/english/info/ntp-refid.htm)
243
            GLNs = ('G') | ('L' << 8) | ('N' << 16) | ('s' << 24),
244
            /// Meinberg GPS/GLONASS (with interrupt based access) (Ref: https://www.meinbergglobal.com/english/info/ntp-refid.htm)
245
            GLNi = ('G') | ('L' << 8) | ('N' << 16) | ('i' << 24),
246
            /// Meinberg Undisciplined local clock (Ref: https://www.meinbergglobal.com/english/info/ntp-refid.htm)
247
            LCL = ('L') | ('C' << 8) | ('L' << 16),
248
            /// Meinberg Undisciplined local clock (Ref: https://www.meinbergglobal.com/english/info/ntp-refid.htm)
249
            LOCL = ('L') | ('O' << 8) | ('C' << 16) | ('L' << 24),
250
251
            // NTPv3
252
253
            /// DCN routing protocol
254
            DCN = ('D') | ('C' << 8) | ('N' << 16),
255
            /// TSP time protocol
256
            TSP = ('T') | ('S' << 8) | ('P' << 16),
257
            /// Digital Time Service
258
            DTS = ('D') | ('T' << 8) | ('S' << 16),
259
            /// Atomic clock (calibrated)
260
            ATOM = ('A') | ('T' << 8) | ('O' << 16) | ('M' << 24),
261
            /// VLF radio (OMEGA, etc.)
262
            VLF = ('V') | ('L' << 8) | ('F' << 16)
263
264
        };
265
266
        /**
267
     * A constructor that creates the layer from an existing packet raw data
268
     * @param[in] data A pointer to the raw data
269
     * @param[in] dataLen Size of the data in bytes
270
     * @param[in] prevLayer A pointer to the previous layer
271
     * @param[in] packet A pointer to the Packet instance where layer will be stored in
272
     */
273
425
        NtpLayer(uint8_t *data, size_t dataLen, Layer *prevLayer, Packet *packet) : Layer(data, dataLen, prevLayer, packet) { m_Protocol = NTP; }
274
275
        /**
276
         * Empty c'tor
277
         */
278
        NtpLayer();
279
280
        /**
281
         * @return The leap indicator
282
         */
283
        LeapIndicator getLeapIndicator() const;
284
285
        /**
286
         * Set the leap indicator
287
         */
288
        void setLeapIndicator(LeapIndicator val);
289
290
        /**
291
         * @return The version of NTP
292
         */
293
        uint8_t getVersion() const;
294
295
        /**
296
         * Set the version of NTP
297
         */
298
        void setVersion(uint8_t val);
299
300
        /**
301
         * @return The mode value
302
         */
303
        Mode getMode() const;
304
305
        /**
306
         * @return The mode as string
307
         */
308
        std::string getModeString() const;
309
310
        /**
311
         * Set the mode
312
         */
313
        void setMode(Mode val);
314
315
        /**
316
         * @return The value of stratum
317
         */
318
        uint8_t getStratum() const;
319
320
        /**
321
         * Set the value of stratum
322
         */
323
        void setStratum(uint8_t val);
324
325
        /**
326
         * @return The value of poll interval in log2 seconds
327
         */
328
        int8_t getPollInterval() const;
329
330
        /**
331
         * Set the value of poll interval
332
         * @param[in] val Poll interval in log2 seconds
333
         */
334
        void setPollInterval(int8_t val);
335
336
        /**
337
         * @return The value of poll interval in seconds
338
         */
339
        double getPollIntervalInSecs() const;
340
341
        /**
342
         * @return The value of precision in log2 seconds
343
         */
344
        int8_t getPrecision() const;
345
346
        /**
347
         * Set the value of precision
348
         * @param[in] val Precision in log2 seconds
349
         */
350
        void setPrecision(int8_t val);
351
352
        /**
353
         * @return The value of precision in seconds
354
         */
355
        double getPrecisionInSecs() const;
356
357
        /**
358
         * @return The value of root delay in NTP short format
359
         */
360
        uint32_t getRootDelay() const;
361
362
        /**
363
         * Set the value of root delay
364
         * @param[in] val Root delay in NTP short format
365
         */
366
        void setRootDelay(uint32_t val);
367
368
        /**
369
         * @return The value of root delay in seconds
370
         */
371
        double getRootDelayInSecs() const;
372
373
        /**
374
         * Set the value of root delay
375
         * @param[in] val Root delay in seconds
376
         */
377
        void setRootDelayInSecs(double val);
378
379
        /**
380
         * @return The value of root dispersion in NTP short format
381
         */
382
        uint32_t getRootDispersion() const;
383
384
        /**
385
         * Set the value of root delay
386
         * @param[in] val Root dispersion in NTP short format
387
         */
388
        void setRootDispersion(uint32_t val);
389
390
        /**
391
         * @return The value of root dispersion in seconds
392
         */
393
        double getRootDispersionInSecs() const;
394
395
        /**
396
         * Set the value of root dispersion
397
         * @param[in] val Root dispersion in seconds
398
         */
399
        void setRootDispersionInSecs(double val);
400
401
        /**
402
         * @return The value of reference identifier
403
         */
404
        uint32_t getReferenceIdentifier() const;
405
406
        /**
407
         * Set the value of reference identifier
408
         * @param[in] val Value of the reference identifier as IPv4 address
409
         */
410
        void setReferenceIdentifier(IPv4Address val);
411
412
        /**
413
         * Set the value of reference identifier
414
         * @param[in] val Value of the reference identifier as ClockSource
415
         */
416
        void setReferenceIdentifier(ClockSource val);
417
418
        /**
419
         * @return The value of reference identifier as a string. String representation of NTP clock source if stratum is 1,
420
         * IPv4 address or MD5 hash of first four octets of IPv6
421
         */
422
        std::string getReferenceIdentifierString() const;
423
424
        /**
425
         * @return The value of reference timestamp in NTP timestamp format
426
         */
427
        uint64_t getReferenceTimestamp() const;
428
429
        /**
430
         * Set the value of reference timestamp
431
         * @param[in] val Timestamp in NTP timestamp format
432
         */
433
        void setReferenceTimestamp(uint64_t val);
434
435
        /**
436
         * @return The value of reference timestamp in seconds from Unix Epoch (1 Jan 1970)
437
         */
438
        double getReferenceTimestampInSecs() const;
439
440
        /**
441
         * Set the value of reference timestamp
442
         * @param[in] val Value in seconds from Unix Epoch (1 Jan 1970)
443
         */
444
        void setReferenceTimestampInSecs(double val);
445
446
        /**
447
         * @return The reference timestamp value as readable string in ISO8601 format
448
         */
449
        std::string getReferenceTimestampAsString();
450
451
        /**
452
         * @return The value of origin timestamp in NTP timestamp format
453
         */
454
        uint64_t getOriginTimestamp() const;
455
456
        /**
457
         * Set the value of origin timestamp
458
         * @param[in] val Value in NTP timestamp format
459
         */
460
        void setOriginTimestamp(uint64_t val);
461
462
        /**
463
         * @return The value of origin timestamp in seconds from Unix Epoch (1 Jan 1970)
464
         */
465
        double getOriginTimestampInSecs() const;
466
467
        /**
468
         * Set the value of origin timestamp
469
         * @param[in] val Value in seconds from Unix Epoch (1 Jan 1970)
470
         */
471
        void setOriginTimestampInSecs(double val);
472
473
        /**
474
         * @return the origin timestamp value as readable string in ISO8601 format
475
         */
476
        std::string getOriginTimestampAsString();
477
478
        /**
479
         * @return The value of receive timestamp in NTP timestamp format
480
         */
481
        uint64_t getReceiveTimestamp() const;
482
483
        /**
484
         * Set the value of receive timestamp
485
         * @param[in] val Value in NTP timestamp format
486
         */
487
        void setReceiveTimestamp(uint64_t val);
488
489
        /**
490
         * @return The value of receive timestampin seconds from Unix Epoch (1 Jan 1970)
491
         */
492
        double getReceiveTimestampInSecs() const;
493
494
        /**
495
         * Set the value of receive timestamp
496
         * @param[in] val Value in seconds from Unix Epoch (1 Jan 1970)
497
         */
498
        void setReceiveTimestampInSecs(double val);
499
500
        /**
501
         * @return The receive timestamp value as readable string in ISO8601 format
502
         */
503
        std::string getReceiveTimestampAsString();
504
505
        /**
506
         * @return The value of transmit timestamp in NTP timestamp format
507
         */
508
        uint64_t getTransmitTimestamp() const;
509
510
        /**
511
         * Set the value of transmit timestamp
512
         * @param[in] val Value in NTP timestamp format
513
         */
514
        void setTransmitTimestamp(uint64_t val);
515
516
        /**
517
         * @return The value of transmit timestamp in seconds from Unix Epoch (1 Jan 1970)
518
         */
519
        double getTransmitTimestampInSecs() const;
520
521
        /**
522
         * Set the value of transmit timestamp
523
         * @param[in] val Value in seconds from Unix Epoch (1 Jan 1970)
524
         */
525
        void setTransmitTimestampInSecs(double val);
526
527
        /**
528
         * @return The transmit timestamp value as readable string in ISO8601 format
529
         */
530
        std::string getTransmitTimestampAsString();
531
532
        /**
533
         * @return Returns the key identifier if exists, returns 0 on unsupported NTP version or key identifier not found
534
         */
535
        uint32_t getKeyID() const;
536
537
        /**
538
         * @return Get the digest value as hexadecimal string, empty string on unsupported version
539
         */
540
        std::string getDigest() const;
541
542
        /**
543
         * Convert NTP short format to seconds from the Unix Epoch
544
         *
545
         * @param[in] val Value in NTP short format
546
         * @return Value in seconds from Unix Epoch (1 Jan 1970)
547
         */
548
        static double convertFromShortFormat(const uint32_t val);
549
550
        /**
551
         * Convert NTP timestamp format to seconds from the Unix Epoch
552
         *
553
         * @param[in] val Value in NTP timestamp format
554
         * @return Value in seconds from Unix Epoch (1 Jan 1970)
555
         */
556
        static double convertFromTimestampFormat(const uint64_t val);
557
558
        /**
559
         * Convert seconds from the Unix Epoch to NTP short format
560
         *
561
         * @param[in] val Value in seconds from Unix Epoch (1 Jan 1970)
562
         * @return Value in NTP short format
563
         */
564
        static uint32_t convertToShortFormat(const double val);
565
566
        /**
567
         * Convert seconds from the Unix Epoch to NTP timestamp format
568
         *
569
         * @param[in] val Value in seconds from Unix Epoch (1 Jan 1970)
570
         * @return Value in NTP timestamp format
571
         */
572
        static uint64_t convertToTimestampFormat(const double val);
573
574
        /**
575
         * A static method to convert timestamp value to ISO8601 date time format
576
         * @param[in] timestamp Value in seconds from the Unix Epoch
577
         * @return std::string ISO8601 formatted string
578
         */
579
        static std::string convertToIsoFormat(const double timestamp);
580
581
        /**
582
         * A static method to convert timestamp value to ISO8601 date time format
583
         * @param[in] timestampInNTPformat Value in NTP timestamp format
584
         * @return std::string ISO8601 formatted string
585
         */
586
        static std::string convertToIsoFormat(const uint64_t timestampInNTPformat);
587
588
        /**
589
     * A static method that takes a byte array and detects whether it is a NTP message
590
     * @param[in] data A byte array
591
     * @param[in] dataSize The byte array size (in bytes)
592
     * @return True if the data is identified as NTP message
593
     */
594
        static bool isDataValid(const uint8_t *data, size_t dataSize);
595
596
        /**
597
     * A static method that checks whether the port is considered as NTP
598
     * @param[in] port The port number to be checked
599
     */
600
35.5k
        static bool isNTPPort(uint16_t port) { return port == 123; }
601
602
        // overridden methods
603
604
        /// Parses the next layer. NTP is the always last so does nothing for this layer
605
425
        void parseNextLayer() {}
606
607
        /**
608
         * @return Get the size of the layer (Including the extension and authentication fields if exists)
609
         */
610
0
        size_t getHeaderLen() const { return m_DataLen; }
611
612
        /// Does nothing for this layer
613
0
        void computeCalculateFields() {}
614
615
        /**
616
         * @return The OSI layer level of NTP (Application Layer).
617
         */
618
425
        OsiModelLayer getOsiModelLayer() const { return OsiModelApplicationLayer; }
619
620
        /**
621
         * @return Returns the protocol info as readable string
622
         */
623
        std::string toString() const;
624
    };
625
626
} // namespace pcpp
627
628
#endif /* PACKETPP_NTP_LAYER */