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