Coverage Report

Created: 2026-10-17 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/NtpLayer.cpp
Line
Count
Source
1
3.42k
#define LOG_MODULE PacketLogModuleNtpLayer
2
3
#include "Logger.h"
4
#include "NtpLayer.h"
5
#include "SystemUtils.h"
6
#include "GeneralUtils.h"
7
#include <cmath>
8
9
namespace pcpp
10
{
11
  /// 2^16 as a double
12
  constexpr double NtpFraction16Scale = 65536.;
13
  /// 2^32 as a double
14
  constexpr double NtpFraction32Scale = 4294967296.;
15
  /// Epoch offset between Unix time and NTP
16
  constexpr uint64_t NtpEpochOffset = 2208988800ULL;
17
  NtpLayer::NtpLayer()
18
0
  {
19
0
    allocData(sizeof(ntp_header));
20
0
    m_Protocol = NTP;
21
0
  }
22
23
  NtpLayer::LeapIndicator NtpLayer::getLeapIndicator() const
24
1.22k
  {
25
1.22k
    if (getNtpHeader()->leapIndicator < 4)  // Since leap indicator field is 2bit
26
1.22k
      return static_cast<LeapIndicator>(getNtpHeader()->leapIndicator);
27
0
    PCPP_LOG_ERROR("Unknown NTP Leap Indicator");
28
0
    return Unknown;
29
1.22k
  }
30
31
  void NtpLayer::setLeapIndicator(LeapIndicator val)
32
0
  {
33
0
    getNtpHeader()->leapIndicator = val;
34
0
  }
35
36
  uint8_t NtpLayer::getVersion() const
37
6.13k
  {
38
6.13k
    return getNtpHeader()->version;
39
6.13k
  }
40
41
  void NtpLayer::setVersion(uint8_t val)
42
0
  {
43
0
    getNtpHeader()->version = val;
44
0
  }
45
46
  NtpLayer::Mode NtpLayer::getMode() const
47
4.90k
  {
48
4.90k
    if (getNtpHeader()->mode < 8)  // Since mode field 3bit
49
4.90k
      return static_cast<Mode>(getNtpHeader()->mode);
50
0
    PCPP_LOG_ERROR("Unknown NTP Mode");
51
0
    return Reserved;
52
4.90k
  }
53
54
  std::string NtpLayer::getModeString() const
55
3.67k
  {
56
3.67k
    switch (getMode())
57
3.67k
    {
58
354
    case Reserved:
59
354
      return "Reserved";
60
165
    case SymActive:
61
165
      return "Symmetrically Active";
62
3
    case SymPassive:
63
3
      return "Symmetrically Passive";
64
1.42k
    case Client:
65
1.42k
      return "Client";
66
651
    case Server:
67
651
      return "Server";
68
627
    case Broadcast:
69
627
      return "Broadcast";
70
15
    case Control:
71
15
      return "Control";
72
438
    case PrivateUse:
73
438
      return "Private Use";
74
0
    default:
75
0
      PCPP_LOG_ERROR("Unknown NTP Mode");
76
0
      return std::string();
77
3.67k
    }
78
3.67k
  }
79
80
  void NtpLayer::setMode(Mode val)
81
0
  {
82
0
    getNtpHeader()->mode = val;
83
0
  }
84
85
  uint8_t NtpLayer::getStratum() const
86
2.45k
  {
87
2.45k
    return getNtpHeader()->stratum;
88
2.45k
  }
89
90
  void NtpLayer::setStratum(uint8_t val)
91
0
  {
92
0
    getNtpHeader()->stratum = val;
93
0
  }
94
95
  int8_t NtpLayer::getPollInterval() const
96
2.45k
  {
97
2.45k
    return getNtpHeader()->pollInterval;
98
2.45k
  }
99
100
  void NtpLayer::setPollInterval(int8_t val)
101
0
  {
102
0
    getNtpHeader()->pollInterval = val;
103
0
  }
104
105
  double NtpLayer::getPollIntervalInSecs() const
106
1.22k
  {
107
1.22k
    return pow(2, getPollInterval());
108
1.22k
  }
109
110
  int8_t NtpLayer::getPrecision() const
111
2.45k
  {
112
2.45k
    return getNtpHeader()->precision;
113
2.45k
  }
114
115
  void NtpLayer::setPrecision(int8_t val)
116
0
  {
117
0
    getNtpHeader()->precision = val;
118
0
  }
119
120
  double NtpLayer::getPrecisionInSecs() const
121
1.22k
  {
122
1.22k
    return pow(2, getPrecision());
123
1.22k
  }
124
125
  uint32_t NtpLayer::getRootDelay() const
126
2.45k
  {
127
2.45k
    return getNtpHeader()->rootDelay;
128
2.45k
  }
129
130
  void NtpLayer::setRootDelay(uint32_t val)
131
0
  {
132
0
    getNtpHeader()->rootDelay = val;
133
0
  }
134
135
  double NtpLayer::getRootDelayInSecs() const
136
1.22k
  {
137
1.22k
    return convertFromShortFormat(getRootDelay());
138
1.22k
  }
139
140
  void NtpLayer::setRootDelayInSecs(double val)
141
1.22k
  {
142
1.22k
    getNtpHeader()->rootDelay = convertToShortFormat(val);
143
1.22k
  }
144
145
  uint32_t NtpLayer::getRootDispersion() const
146
2.45k
  {
147
2.45k
    return getNtpHeader()->rootDispersion;
148
2.45k
  }
149
150
  void NtpLayer::setRootDispersion(uint32_t val)
151
0
  {
152
0
    getNtpHeader()->rootDispersion = val;
153
0
  }
154
155
  double NtpLayer::getRootDispersionInSecs() const
156
1.22k
  {
157
1.22k
    return convertFromShortFormat(getRootDispersion());
158
1.22k
  }
159
160
  void NtpLayer::setRootDispersionInSecs(double val)
161
0
  {
162
0
    getNtpHeader()->rootDispersion = convertToShortFormat(val);
163
0
  }
164
165
  uint32_t NtpLayer::getReferenceIdentifier() const
166
2.79k
  {
167
2.79k
    return getNtpHeader()->referenceIdentifier;
168
2.79k
  }
169
170
  void NtpLayer::setReferenceIdentifier(IPv4Address val)
171
0
  {
172
0
    getNtpHeader()->referenceIdentifier = val.toInt();
173
0
  }
174
175
  void NtpLayer::setReferenceIdentifier(ClockSource val)
176
0
  {
177
0
    getNtpHeader()->referenceIdentifier = static_cast<uint32_t>(val);
178
0
  }
179
180
  void NtpLayer::setReferenceIdentifier(KissODeath val)
181
0
  {
182
0
    getNtpHeader()->referenceIdentifier = static_cast<uint32_t>(val);
183
0
  }
184
185
  std::string NtpLayer::getReferenceIdentifierString() const
186
1.22k
  {
187
1.22k
    uint8_t stratum = getStratum();
188
1.22k
    uint8_t version = getVersion();
189
1.22k
    uint32_t refID = getReferenceIdentifier();
190
191
1.22k
    if (stratum == 0)
192
611
    {
193
611
      switch (version)
194
611
      {
195
8
      case 3:
196
8
      {
197
8
        switch (static_cast<ClockSource>(refID))
198
8
        {
199
0
        case ClockSource::DCN:
200
0
          return "DCN routing protocol";
201
0
        case ClockSource::NIST:
202
0
          return "NIST public modem";
203
0
        case ClockSource::TSP:
204
0
          return "TSP time protocol";
205
0
        case ClockSource::DTS:
206
0
          return "Digital Time Service";
207
8
        default:
208
8
          return "Unknown";
209
8
        }
210
8
      }
211
463
      case 4:
212
463
      {
213
463
        switch (static_cast<KissODeath>(refID))
214
463
        {
215
0
        case KissODeath::ACST:
216
0
          return "The association belongs to a anycast server";
217
0
        case KissODeath::AUTH:
218
0
          return "Server authentication failed";
219
0
        case KissODeath::AUTO:
220
0
          return "Autokey sequence failed";
221
0
        case KissODeath::BCST:
222
0
          return "The association belongs to a broadcast server";
223
0
        case KissODeath::CRYP:
224
0
          return "Cryptographic authentication or identification failed";
225
0
        case KissODeath::DENY:
226
0
          return "Access denied by remote server";
227
0
        case KissODeath::DROP:
228
0
          return "Lost peer in symmetric mode";
229
0
        case KissODeath::RSTR:
230
0
          return "Access denied due to local policy";
231
16
        case KissODeath::INIT:
232
16
          return "The association has not yet synchronized for the first time";
233
0
        case KissODeath::MCST:
234
0
          return "The association belongs to a manycast server";
235
0
        case KissODeath::NKEY:
236
0
          return "No key found.  Either the key was never installed or is not trusted";
237
63
        case KissODeath::RATE:
238
63
          return "Rate exceeded.  The server has temporarily denied access because the client exceeded the rate "
239
63
                 "threshold";
240
0
        case KissODeath::RMOT:
241
0
          return "Somebody is tinkering with the association from a remote host running ntpdc.  Not to worry "
242
0
                 "unless some rascal has stolen your keys";
243
18
        case KissODeath::STEP:
244
18
          return "A step change in system time has occurred, but the association has not yet resynchronized";
245
366
        default:
246
366
        {
247
          // clang-format off
248
366
          char arrBuff[5] = {
249
366
            static_cast<char>((refID >> 24) & 0xFF),
250
366
            static_cast<char>((refID >> 16) & 0xFF),
251
366
            static_cast<char>((refID >> 8) & 0xFF),
252
366
            static_cast<char>((refID) & 0xFF), '\0'
253
366
          };
254
          // clang-format on
255
366
          return arrBuff;
256
0
        }
257
463
        }
258
463
      }
259
611
      }
260
611
    }
261
615
    else if (stratum == 1)
262
270
    {
263
270
      switch (version)
264
270
      {
265
204
      case 3:
266
204
      {
267
204
        switch (static_cast<ClockSource>(refID))
268
204
        {
269
0
        case ClockSource::ATOM:
270
0
          return "Atomic clock";
271
0
        case ClockSource::VLF:
272
0
          return "VLF radio";
273
0
        case ClockSource::LORC:
274
0
          return "LORAN-C radionavigation";
275
0
        case ClockSource::GOES:
276
0
          return "GOES UHF environment satellite";
277
0
        case ClockSource::GPS:
278
0
          return "GPS UHF satellite positioning";
279
204
        default:
280
204
          return "Unknown";
281
204
        }
282
204
      }
283
48
      case 4:
284
48
      {
285
48
        switch (static_cast<ClockSource>(refID))
286
48
        {
287
0
        case ClockSource::GOES:
288
0
          return "Geosynchronous Orbit Environment Satellite";
289
0
        case ClockSource::GPS:
290
0
          return "Global Position System";
291
0
        case ClockSource::GAL:
292
0
          return "Galileo Positioning System";
293
0
        case ClockSource::PPS:
294
0
          return "Generic pulse-per-second";
295
0
        case ClockSource::IRIG:
296
0
          return "Inter-Range Instrumentation Group";
297
0
        case ClockSource::WWVB:
298
0
          return "LF Radio WWVB Ft. Collins, CO 60 kHz";
299
0
        case ClockSource::DCF:
300
0
          return "LF Radio DCF77 Mainflingen, DE 77.5 kHz";
301
0
        case ClockSource::HBG:
302
0
          return "LF Radio HBG Prangins, HB 75 kHz";
303
0
        case ClockSource::MSF:
304
0
          return "LF Radio MSF Anthorn, UK 60 kHz";
305
0
        case ClockSource::JJY:
306
0
          return "LF Radio JJY Fukushima, JP 40 kHz, Saga, JP 60 kHz";
307
0
        case ClockSource::LORC:
308
0
          return "MF Radio LORAN C station, 100 kHz";
309
0
        case ClockSource::TDF:
310
0
          return "MF Radio Allouis, FR 162 kHz";
311
0
        case ClockSource::CHU:
312
0
          return "HF Radio CHU Ottawa, Ontario";
313
0
        case ClockSource::WWV:
314
0
          return "HF Radio WWV Ft. Collins, CO";
315
0
        case ClockSource::WWVH:
316
0
          return "HF Radio WWVH Kauai, HI";
317
0
        case ClockSource::NIST:
318
0
          return "NIST telephone modem";
319
0
        case ClockSource::ACTS:
320
0
          return "NIST telephone modem";
321
0
        case ClockSource::USNO:
322
0
          return "USNO telephone modem";
323
0
        case ClockSource::PTB:
324
0
          return "European telephone modem";
325
0
        case ClockSource::MRS:
326
0
          return "Multi Reference Sources";
327
0
        case ClockSource::XFAC:
328
0
          return "Inter Face Association Changed";
329
16
        case ClockSource::STEP:
330
16
          return "Step time change";
331
0
        case ClockSource::GOOG:
332
0
          return "Google NTP servers";
333
0
        case ClockSource::DCFa:
334
0
          return "Meinberg DCF77 with amplitude modulation";
335
0
        case ClockSource::DCFp:
336
0
          return "Meinberg DCF77 with phase modulation)/pseudo random phase modulation";
337
0
        case ClockSource::GPSs:
338
0
          return "Meinberg GPS (with shared memory access)";
339
0
        case ClockSource::GPSi:
340
0
          return "Meinberg GPS (with interrupt based access)";
341
0
        case ClockSource::GLNs:
342
0
          return "Meinberg GPS/GLONASS (with shared memory access)";
343
32
        case ClockSource::GLNi:
344
32
          return "Meinberg GPS/GLONASS (with interrupt based access)";
345
0
        case ClockSource::LCL:
346
0
          return "Meinberg Undisciplined local clock";
347
0
        case ClockSource::LOCL:
348
0
          return "Meinberg Undisciplined local clock";
349
0
        default:
350
0
          return "Unknown";
351
48
        }
352
48
      }
353
270
      }
354
270
    }
355
345
    else
356
345
    {
357
      // TODO: Support IPv6 cases for NTPv4, it equals to MD5 hash of first four octets of IPv6 address
358
359
345
      pcpp::IPv4Address addr(getReferenceIdentifier());
360
345
      return addr.toString();
361
345
    }
362
363
158
    PCPP_LOG_ERROR("Unknown Stratum type");
364
158
    return std::string();
365
1.22k
  }
366
367
  uint64_t NtpLayer::getReferenceTimestamp() const
368
3.67k
  {
369
3.67k
    return getNtpHeader()->referenceTimestamp;
370
3.67k
  }
371
372
  void NtpLayer::setReferenceTimestamp(uint64_t val)
373
0
  {
374
0
    getNtpHeader()->referenceTimestamp = val;
375
0
  }
376
377
  double NtpLayer::getReferenceTimestampInSecs() const
378
1.22k
  {
379
1.22k
    return convertFromTimestampFormat(getReferenceTimestamp());
380
1.22k
  }
381
382
  void NtpLayer::setReferenceTimestampInSecs(double val)
383
1.22k
  {
384
1.22k
    getNtpHeader()->referenceTimestamp = convertToTimestampFormat(val);
385
1.22k
  }
386
387
  std::string NtpLayer::getReferenceTimestampAsString()
388
1.22k
  {
389
1.22k
    return convertToIsoFormat(getReferenceTimestamp());
390
1.22k
  }
391
392
  uint64_t NtpLayer::getOriginTimestamp() const
393
3.67k
  {
394
3.67k
    return getNtpHeader()->originTimestamp;
395
3.67k
  }
396
397
  void NtpLayer::setOriginTimestamp(uint64_t val)
398
0
  {
399
0
    getNtpHeader()->originTimestamp = val;
400
0
  }
401
402
  double NtpLayer::getOriginTimestampInSecs() const
403
1.22k
  {
404
1.22k
    return convertFromTimestampFormat(getOriginTimestamp());
405
1.22k
  }
406
407
  void NtpLayer::setOriginTimestampInSecs(double val)
408
0
  {
409
0
    getNtpHeader()->originTimestamp = convertToTimestampFormat(val);
410
0
  }
411
412
  std::string NtpLayer::getOriginTimestampAsString()
413
1.22k
  {
414
1.22k
    return convertToIsoFormat(getOriginTimestamp());
415
1.22k
  }
416
417
  uint64_t NtpLayer::getReceiveTimestamp() const
418
3.67k
  {
419
3.67k
    return getNtpHeader()->receiveTimestamp;
420
3.67k
  }
421
422
  void NtpLayer::setReceiveTimestamp(uint64_t val)
423
0
  {
424
0
    getNtpHeader()->receiveTimestamp = val;
425
0
  }
426
427
  double NtpLayer::getReceiveTimestampInSecs() const
428
1.22k
  {
429
1.22k
    return convertFromTimestampFormat(getReceiveTimestamp());
430
1.22k
  }
431
432
  void NtpLayer::setReceiveTimestampInSecs(double val)
433
0
  {
434
0
    getNtpHeader()->receiveTimestamp = convertToTimestampFormat(val);
435
0
  }
436
437
  std::string NtpLayer::getReceiveTimestampAsString()
438
1.22k
  {
439
1.22k
    return convertToIsoFormat(getReceiveTimestamp());
440
1.22k
  }
441
442
  uint64_t NtpLayer::getTransmitTimestamp() const
443
3.67k
  {
444
3.67k
    return getNtpHeader()->transmitTimestamp;
445
3.67k
  }
446
447
  void NtpLayer::setTransmitTimestamp(uint64_t val)
448
0
  {
449
0
    getNtpHeader()->transmitTimestamp = val;
450
0
  }
451
452
  double NtpLayer::getTransmitTimestampInSecs() const
453
1.22k
  {
454
1.22k
    return convertFromTimestampFormat(getTransmitTimestamp());
455
1.22k
  }
456
457
  void NtpLayer::setTransmitTimestampInSecs(double val)
458
0
  {
459
0
    getNtpHeader()->transmitTimestamp = convertToTimestampFormat(val);
460
0
  }
461
462
  std::string NtpLayer::getTransmitTimestampAsString()
463
1.22k
  {
464
1.22k
    return convertToIsoFormat(getTransmitTimestamp());
465
1.22k
  }
466
467
  uint32_t NtpLayer::getKeyID() const
468
1.22k
  {
469
1.22k
    switch (getVersion())
470
1.22k
    {
471
213
    case 3:
472
213
    {
473
213
      if (m_DataLen < (sizeof(ntp_header) + sizeof(ntp_v3_auth)))
474
52
        return 0;
475
476
161
      ntp_v3_auth* header = (ntp_v3_auth*)(m_Data + sizeof(ntp_header));
477
161
      return header->keyID;
478
213
    }
479
518
    case 4:
480
518
    {
481
      // TODO: Add support for extension fields
482
518
      if (m_DataLen == (sizeof(ntp_header) + sizeof(ntp_v4_auth_md5)))
483
79
      {
484
79
        ntp_v4_auth_md5* header = (ntp_v4_auth_md5*)(m_Data + m_DataLen - sizeof(ntp_v4_auth_md5));
485
79
        return header->keyID;
486
79
      }
487
439
      if (m_DataLen == (sizeof(ntp_header) + sizeof(ntp_v4_auth_sha1)))
488
156
      {
489
156
        ntp_v4_auth_sha1* header = (ntp_v4_auth_sha1*)(m_Data + m_DataLen - sizeof(ntp_v4_auth_sha1));
490
156
        return header->keyID;
491
156
      }
492
493
283
      PCPP_LOG_ERROR("NTP authentication parsing with extension fields are not supported");
494
283
      return 0;
495
439
    }
496
495
    default:
497
495
    {
498
495
      PCPP_LOG_ERROR("NTP version not supported");
499
495
      return 0;
500
439
    }
501
1.22k
    }
502
1.22k
  }
503
504
  std::string NtpLayer::getDigest() const
505
1.22k
  {
506
1.22k
    switch (getVersion())
507
1.22k
    {
508
213
    case 3:
509
213
    {
510
213
      if (m_DataLen < (sizeof(ntp_header) + sizeof(ntp_v3_auth)))
511
52
        return std::string();
512
513
161
      ntp_v3_auth* header = (ntp_v3_auth*)(m_Data + sizeof(ntp_header));
514
161
      return byteArrayToHexString(header->dgst, 8);
515
213
    }
516
518
    case 4:
517
518
    {
518
518
      if (m_DataLen == (sizeof(ntp_header) + sizeof(ntp_v4_auth_md5)))
519
79
      {
520
79
        ntp_v4_auth_md5* header = (ntp_v4_auth_md5*)(m_Data + m_DataLen - sizeof(ntp_v4_auth_md5));
521
79
        return byteArrayToHexString(header->dgst, 16);
522
79
      }
523
439
      if (m_DataLen == (sizeof(ntp_header) + sizeof(ntp_v4_auth_sha1)))
524
156
      {
525
156
        ntp_v4_auth_sha1* header = (ntp_v4_auth_sha1*)(m_Data + m_DataLen - sizeof(ntp_v4_auth_sha1));
526
156
        return byteArrayToHexString(header->dgst, 20);
527
156
      }
528
529
283
      PCPP_LOG_ERROR("NTP authentication parsing with extension fields are not supported");
530
283
      return std::string();
531
439
    }
532
495
    default:
533
495
      PCPP_LOG_ERROR("NTP version not supported");
534
495
      return std::string();
535
1.22k
    }
536
1.22k
  }
537
538
  double NtpLayer::convertFromShortFormat(const uint32_t val)
539
2.45k
  {
540
2.45k
    double integerPart = netToHost16(val & 0xFFFF);
541
2.45k
    double fractionPart = netToHost16(((val & 0xFFFF0000) >> 16)) / NtpFraction16Scale;
542
543
2.45k
    return integerPart + fractionPart;
544
2.45k
  }
545
546
  double NtpLayer::convertFromTimestampFormat(const uint64_t val)
547
9.80k
  {
548
9.80k
    double integerPart = netToHost32(val & 0xFFFFFFFF);
549
9.80k
    double fractionPart = netToHost32(((val & 0xFFFFFFFF00000000) >> 32)) / NtpFraction32Scale;
550
551
    // TODO: Return integer and fraction parts as struct to increase precision
552
    // Offset change should be done here because of overflow
553
9.80k
    return integerPart + fractionPart - NtpEpochOffset;
554
9.80k
  }
555
556
  uint32_t NtpLayer::convertToShortFormat(const double val)
557
1.22k
  {
558
1.22k
    double integerPart;
559
1.22k
    double fractionPart = modf(val, &integerPart);
560
561
    // Cast values to 16bit
562
1.22k
    uint32_t integerPartInt = hostToNet16(integerPart);
563
1.22k
    uint32_t fractionPartInt = hostToNet16(fractionPart * NtpFraction16Scale);
564
565
1.22k
    return integerPartInt | (fractionPartInt << 16);
566
1.22k
  }
567
568
  uint64_t NtpLayer::convertToTimestampFormat(const double val)
569
1.22k
  {
570
1.22k
    double integerPart;
571
1.22k
    double fractionPart = modf(val, &integerPart);
572
573
    // Cast values to 32bit
574
1.22k
    uint64_t integerPartInt = hostToNet32(integerPart + NtpEpochOffset);
575
1.22k
    uint64_t fractionPartInt = hostToNet32(fractionPart * NtpFraction32Scale);
576
577
1.22k
    return integerPartInt | (fractionPartInt << 32);
578
1.22k
  }
579
580
  std::string NtpLayer::convertToIsoFormat(const double timestamp)
581
4.90k
  {
582
4.90k
    double integerPart;
583
4.90k
    double fractionPart = modf(timestamp, &integerPart);
584
585
4.90k
    struct tm* timer;
586
4.90k
    time_t timeStruct = integerPart;
587
#if defined(_WIN32)
588
    if (timeStruct < 0)
589
      timeStruct = 0;
590
    timer = gmtime(&timeStruct);
591
#else
592
4.90k
    struct tm timer_r;
593
4.90k
    timer = gmtime_r(&timeStruct, &timer_r);
594
595
4.90k
    if (timer != nullptr)
596
4.90k
      timer = &timer_r;
597
4.90k
#endif
598
4.90k
    if (timer == nullptr)
599
0
    {
600
0
      PCPP_LOG_ERROR("Can't convert time");
601
0
      return std::string();
602
0
    }
603
4.90k
    char buffer[50], bufferFraction[15];
604
4.90k
    strftime(buffer, sizeof(buffer) - sizeof(bufferFraction), "%Y-%m-%dT%H:%M:%S", timer);
605
606
4.90k
    snprintf(bufferFraction, sizeof(bufferFraction), "%.04lfZ", fabs(fractionPart));
607
4.90k
    strncat(buffer, &bufferFraction[1], sizeof(bufferFraction));
608
609
4.90k
    return std::string(buffer);
610
4.90k
  }
611
612
  std::string NtpLayer::convertToIsoFormat(const uint64_t timestampInNTPformat)
613
4.90k
  {
614
4.90k
    return convertToIsoFormat(convertFromTimestampFormat(timestampInNTPformat));
615
4.90k
  }
616
617
  bool NtpLayer::isDataValid(const uint8_t* data, size_t dataSize)
618
7.59k
  {
619
7.59k
    return data && dataSize >= sizeof(ntp_header);
620
7.59k
  }
621
622
  const FieldDescriptor NtpLayer::SerializedFields::LeapIndicator{ Layer::SerializedFields::MaxID + 1,
623
                                                                 "leapIndicator" };
624
  const FieldDescriptor NtpLayer::SerializedFields::Version{ Layer::SerializedFields::MaxID + 2, "version" };
625
  const FieldDescriptor NtpLayer::SerializedFields::Mode{ Layer::SerializedFields::MaxID + 3, "mode" };
626
  const FieldDescriptor NtpLayer::SerializedFields::ModeName{ Layer::SerializedFields::MaxID + 4, "modeName" };
627
  const FieldDescriptor NtpLayer::SerializedFields::Stratum{ Layer::SerializedFields::MaxID + 5, "stratum" };
628
  const FieldDescriptor NtpLayer::SerializedFields::PollInterval{ Layer::SerializedFields::MaxID + 6,
629
                                                                "pollInterval" };
630
  const FieldDescriptor NtpLayer::SerializedFields::Precision{ Layer::SerializedFields::MaxID + 7, "precision" };
631
  const FieldDescriptor NtpLayer::SerializedFields::RootDelay{ Layer::SerializedFields::MaxID + 8, "rootDelay" };
632
  const FieldDescriptor NtpLayer::SerializedFields::RootDispersion{ Layer::SerializedFields::MaxID + 9,
633
                                                                  "rootDispersion" };
634
  const FieldDescriptor NtpLayer::SerializedFields::ReferenceIdentifier{ Layer::SerializedFields::MaxID + 10,
635
                                                                       "referenceIdentifier" };
636
  const FieldDescriptor NtpLayer::SerializedFields::ReferenceTimestamp{ Layer::SerializedFields::MaxID + 11,
637
                                                                      "referenceTimestamp" };
638
  const FieldDescriptor NtpLayer::SerializedFields::OriginTimestamp{ Layer::SerializedFields::MaxID + 12,
639
                                                                   "originTimestamp" };
640
  const FieldDescriptor NtpLayer::SerializedFields::ReceiveTimestamp{ Layer::SerializedFields::MaxID + 13,
641
                                                                    "receiveTimestamp" };
642
  const FieldDescriptor NtpLayer::SerializedFields::TransmitTimestamp{ Layer::SerializedFields::MaxID + 14,
643
                                                                     "transmitTimestamp" };
644
645
  const FieldDescriptor NtpLayer::SerializedFields::KeyID{ Layer::SerializedFields::MaxID + 15, "keyID" };
646
  const FieldDescriptor NtpLayer::SerializedFields::Digest{ Layer::SerializedFields::MaxID + 16, "digest" };
647
648
  static constexpr const char* leapIndicatorToString(NtpLayer::LeapIndicator indicator)
649
0
  {
650
0
    switch (indicator)
651
0
    {
652
0
    case NtpLayer::NoWarning:
653
0
      return "No warning";
654
0
    case NtpLayer::Last61Secs:
655
0
      return "Last minute has 61 seconds";
656
0
    case NtpLayer::Last59Secs:
657
0
      return "Last minute has 59 seconds";
658
0
    default:
659
0
      return "Unknown";
660
0
    }
661
0
  }
662
663
  void NtpLayer::serializeLayer(ObjectScope& serializer) const
664
0
  {
665
0
    serializer.writeField(SerializedFields::LeapIndicator, leapIndicatorToString(getLeapIndicator()));
666
0
    serializer.writeField(SerializedFields::Version, getVersion());
667
0
    serializer.writeField(SerializedFields::Mode, static_cast<uint8_t>(getMode()));
668
0
    serializer.writeField(SerializedFields::ModeName, getModeString());
669
0
    serializer.writeField(SerializedFields::Stratum, getStratum());
670
0
    serializer.writeField(SerializedFields::PollInterval, getPollInterval());
671
0
    serializer.writeField(SerializedFields::Precision, getPrecision());
672
0
    serializer.writeField(SerializedFields::RootDelay, netToHost32(getRootDelay()));
673
0
    serializer.writeField(SerializedFields::RootDispersion, netToHost32(getRootDispersion()));
674
0
    serializer.writeHexField(SerializedFields::ReferenceIdentifier, netToHost32(getReferenceIdentifier()));
675
0
    serializer.writeField(SerializedFields::ReferenceTimestamp, convertToIsoFormat(getReferenceTimestamp()));
676
0
    serializer.writeField(SerializedFields::OriginTimestamp, convertToIsoFormat(getOriginTimestamp()));
677
0
    serializer.writeField(SerializedFields::ReceiveTimestamp, convertToIsoFormat(getReceiveTimestamp()));
678
0
    serializer.writeField(SerializedFields::TransmitTimestamp, convertToIsoFormat(getTransmitTimestamp()));
679
    // Match the authentication formats supported by getKeyID() and getDigest().
680
0
    if ((getVersion() == 3 && m_DataLen >= sizeof(ntp_header) + sizeof(ntp_v3_auth)) ||
681
0
        (getVersion() == 4 && (m_DataLen == sizeof(ntp_header) + sizeof(ntp_v4_auth_md5) ||
682
0
                               m_DataLen == sizeof(ntp_header) + sizeof(ntp_v4_auth_sha1))))
683
0
    {
684
0
      serializer.writeField(SerializedFields::KeyID, netToHost32(getKeyID()));
685
0
      serializer.writeField(SerializedFields::Digest, getDigest());
686
0
    }
687
0
  }
688
689
  std::string NtpLayer::toString() const
690
2.45k
  {
691
2.45k
    return std::string("NTP Layer v") + std::to_string(getVersion()) + ", Mode: " + getModeString();
692
2.45k
  }
693
}  // namespace pcpp