1 /* 2 * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and 9 * this paragraph in its entirety in the documentation or other materials 10 * provided with the distribution, and (3) all advertising materials mentioning 11 * features or use of this software display the following acknowledgement: 12 * ``This product includes software developed by the University of California, 13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 * the University nor the names of its contributors may be used to endorse 15 * or promote products derived from this software without specific prior 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 * 21 * By Jeffrey Mogul/DECWRL 22 * loosely based on print-bootp.c 23 */ 24 25 /* \summary: Network Time Protocol (NTP) printer */ 26 27 #include <sys/cdefs.h> 28 #ifndef lint 29 __RCSID("$NetBSD: print-ntp.c,v 1.9 2023/08/17 20:19:40 christos Exp $"); 30 #endif 31 32 /* 33 * specification: 34 * 35 * RFC 1119 - NTPv2 36 * RFC 1305 - NTPv3 37 * RFC 5905 - NTPv4 38 */ 39 40 #ifdef HAVE_CONFIG_H 41 #include <config.h> 42 #endif 43 44 #include "netdissect-stdinc.h" 45 46 #include <time.h> 47 48 #include "netdissect.h" 49 #include "addrtoname.h" 50 #include "extract.h" 51 52 #include "ntp.h" 53 54 /* 55 * Based on ntp.h from the U of MD implementation 56 * This file is based on Version 2 of the NTP spec (RFC1119). 57 */ 58 59 /* rfc2030 60 * 1 2 3 61 * 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 62 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 63 * |LI | VN |Mode | Stratum | Poll | Precision | 64 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 65 * | Root Delay | 66 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 67 * | Root Dispersion | 68 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 69 * | Reference Identifier | 70 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 71 * | | 72 * | Reference Timestamp (64) | 73 * | | 74 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 75 * | | 76 * | Originate Timestamp (64) | 77 * | | 78 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 79 * | | 80 * | Receive Timestamp (64) | 81 * | | 82 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 83 * | | 84 * | Transmit Timestamp (64) | 85 * | | 86 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 87 * | Key Identifier (optional) (32) | 88 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 89 * | | 90 * | | 91 * | Message Digest (optional) (128) | 92 * | | 93 * | | 94 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 95 */ 96 97 /* Length of the NTP data message with the mandatory fields ("the header") 98 * and without any optional fields (extension, Key Identifier, 99 * Message Digest). 100 */ 101 #define NTP_TIMEMSG_MINLEN 48U 102 103 struct ntp_time_data { 104 nd_uint8_t status; /* status of local clock and leap info */ 105 nd_uint8_t stratum; /* Stratum level */ 106 nd_int8_t ppoll; /* poll value */ 107 nd_int8_t precision; 108 struct s_fixedpt root_delay; 109 struct s_fixedpt root_dispersion; 110 nd_uint32_t refid; 111 struct l_fixedpt ref_timestamp; 112 struct l_fixedpt org_timestamp; 113 struct l_fixedpt rec_timestamp; 114 struct l_fixedpt xmt_timestamp; 115 nd_uint32_t key_id; 116 nd_uint8_t message_digest[20]; 117 }; 118 /* 119 * Leap Second Codes (high order two bits) 120 */ 121 #define NO_WARNING 0x00 /* no warning */ 122 #define PLUS_SEC 0x40 /* add a second (61 seconds) */ 123 #define MINUS_SEC 0x80 /* minus a second (59 seconds) */ 124 #define ALARM 0xc0 /* alarm condition (clock unsynchronized) */ 125 126 /* 127 * Clock Status Bits that Encode Version 128 */ 129 #define NTPVERSION_1 0x08 130 #define VERSIONMASK 0x38 131 #define VERSIONSHIFT 3 132 #define LEAPMASK 0xc0 133 #define LEAPSHIFT 6 134 #ifdef MODEMASK 135 #undef MODEMASK /* Solaris sucks */ 136 #endif 137 #define MODEMASK 0x07 138 #define MODESHIFT 0 139 140 /* 141 * Code values 142 */ 143 #define MODE_UNSPEC 0 /* unspecified */ 144 #define MODE_SYM_ACT 1 /* symmetric active */ 145 #define MODE_SYM_PAS 2 /* symmetric passive */ 146 #define MODE_CLIENT 3 /* client */ 147 #define MODE_SERVER 4 /* server */ 148 #define MODE_BROADCAST 5 /* broadcast */ 149 #define MODE_CONTROL 6 /* control message */ 150 #define MODE_RES2 7 /* reserved */ 151 152 /* 153 * Stratum Definitions 154 */ 155 #define UNSPECIFIED 0 156 #define PRIM_REF 1 /* radio clock */ 157 #define INFO_QUERY 62 /* **** THIS implementation dependent **** */ 158 #define INFO_REPLY 63 /* **** THIS implementation dependent **** */ 159 160 static void p_sfix(netdissect_options *ndo, const struct s_fixedpt *); 161 static void p_ntp_delta(netdissect_options *, const struct l_fixedpt *, const struct l_fixedpt *); 162 static void p_poll(netdissect_options *, const int); 163 164 static const struct tok ntp_mode_values[] = { 165 { MODE_UNSPEC, "unspecified" }, 166 { MODE_SYM_ACT, "symmetric active" }, 167 { MODE_SYM_PAS, "symmetric passive" }, 168 { MODE_CLIENT, "Client" }, 169 { MODE_SERVER, "Server" }, 170 { MODE_BROADCAST, "Broadcast" }, 171 { MODE_CONTROL, "Control Message" }, 172 { MODE_RES2, "Reserved" }, 173 { 0, NULL } 174 }; 175 176 static const struct tok ntp_leapind_values[] = { 177 { NO_WARNING, "" }, 178 { PLUS_SEC, "+1s" }, 179 { MINUS_SEC, "-1s" }, 180 { ALARM, "clock unsynchronized" }, 181 { 0, NULL } 182 }; 183 184 static const struct tok ntp_stratum_values[] = { 185 { UNSPECIFIED, "unspecified" }, 186 { PRIM_REF, "primary reference" }, 187 { 0, NULL } 188 }; 189 190 /* draft-ietf-ntp-mode-6-cmds-02 191 * 0 1 2 3 192 * 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 193 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 194 * |LI | VN |Mode |R|E|M| OpCode | Sequence Number | 195 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 196 * | Status | Association ID | 197 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 198 * | Offset | Count | 199 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 200 * | | 201 * / Data (up to 468 bytes) / 202 * | | 203 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 204 * | Padding (optional) | 205 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 206 * | | 207 * / Authenticator (optional, 96 bytes) / 208 * | | 209 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 210 * 211 * Figure 1: NTP Control Message Header 212 */ 213 214 /* Length of the NTP control message with the mandatory fields ("the header") 215 * and without any optional fields (Data, Padding, Authenticator). 216 */ 217 #define NTP_CTRLMSG_MINLEN 12U 218 219 struct ntp_control_data { 220 nd_uint8_t magic; /* LI, VN, Mode */ 221 nd_uint8_t control; /* R, E, M, OpCode */ 222 nd_uint16_t sequence; /* Sequence Number */ 223 nd_uint16_t status; /* Status */ 224 nd_uint16_t assoc; /* Association ID */ 225 nd_uint16_t offset; /* Offset */ 226 nd_uint16_t count; /* Count */ 227 nd_uint8_t data[564]; /* Data, [Padding, [Authenticator]] */ 228 }; 229 230 /* 231 * Print NTP time requests and responses 232 */ 233 static void 234 ntp_time_print(netdissect_options *ndo, 235 const struct ntp_time_data *bp, u_int length) 236 { 237 uint8_t stratum; 238 239 if (length < NTP_TIMEMSG_MINLEN) 240 goto invalid; 241 242 stratum = GET_U_1(bp->stratum); 243 ND_PRINT(", Stratum %u (%s)", 244 stratum, 245 tok2str(ntp_stratum_values, (stratum >=2 && stratum<=15) ? "secondary reference" : "reserved", stratum)); 246 247 ND_PRINT(", poll %d", GET_S_1(bp->ppoll)); 248 p_poll(ndo, GET_S_1(bp->ppoll)); 249 250 ND_PRINT(", precision %d", GET_S_1(bp->precision)); 251 252 ND_TCHECK_SIZE(&bp->root_delay); 253 ND_PRINT("\n\tRoot Delay: "); 254 p_sfix(ndo, &bp->root_delay); 255 256 ND_TCHECK_SIZE(&bp->root_dispersion); 257 ND_PRINT(", Root dispersion: "); 258 p_sfix(ndo, &bp->root_dispersion); 259 260 ND_TCHECK_4(bp->refid); 261 ND_PRINT(", Reference-ID: "); 262 /* Interpretation depends on stratum */ 263 switch (stratum) { 264 265 case UNSPECIFIED: 266 ND_PRINT("(unspec)"); 267 break; 268 269 case PRIM_REF: 270 if (nd_printn(ndo, (const u_char *)&(bp->refid), 4, ndo->ndo_snapend)) 271 goto trunc; 272 break; 273 274 case INFO_QUERY: 275 ND_PRINT("%s INFO_QUERY", GET_IPADDR_STRING(bp->refid)); 276 /* this doesn't have more content */ 277 return; 278 279 case INFO_REPLY: 280 ND_PRINT("%s INFO_REPLY", GET_IPADDR_STRING(bp->refid)); 281 /* this is too complex to be worth printing */ 282 return; 283 284 default: 285 /* In NTPv4 (RFC 5905) refid is an IPv4 address or first 32 bits of 286 MD5 sum of IPv6 address */ 287 ND_PRINT("0x%08x", GET_BE_U_4(bp->refid)); 288 break; 289 } 290 291 ND_TCHECK_SIZE(&bp->ref_timestamp); 292 ND_PRINT("\n\t Reference Timestamp: "); 293 p_ntp_time(ndo, &(bp->ref_timestamp)); 294 295 ND_TCHECK_SIZE(&bp->org_timestamp); 296 ND_PRINT("\n\t Originator Timestamp: "); 297 p_ntp_time(ndo, &(bp->org_timestamp)); 298 299 ND_TCHECK_SIZE(&bp->rec_timestamp); 300 ND_PRINT("\n\t Receive Timestamp: "); 301 p_ntp_time(ndo, &(bp->rec_timestamp)); 302 303 ND_TCHECK_SIZE(&bp->xmt_timestamp); 304 ND_PRINT("\n\t Transmit Timestamp: "); 305 p_ntp_time(ndo, &(bp->xmt_timestamp)); 306 307 ND_PRINT("\n\t Originator - Receive Timestamp: "); 308 p_ntp_delta(ndo, &(bp->org_timestamp), &(bp->rec_timestamp)); 309 310 ND_PRINT("\n\t Originator - Transmit Timestamp: "); 311 p_ntp_delta(ndo, &(bp->org_timestamp), &(bp->xmt_timestamp)); 312 313 /* FIXME: this code is not aware of any extension fields */ 314 if (length == NTP_TIMEMSG_MINLEN + 4) { /* Optional: key-id (crypto-NAK) */ 315 ND_PRINT("\n\tKey id: %u", GET_BE_U_4(bp->key_id)); 316 } else if (length == NTP_TIMEMSG_MINLEN + 4 + 16) { /* Optional: key-id + 128-bit digest */ 317 ND_PRINT("\n\tKey id: %u", GET_BE_U_4(bp->key_id)); 318 ND_TCHECK_LEN(bp->message_digest, 16); 319 ND_PRINT("\n\tAuthentication: %08x%08x%08x%08x", 320 GET_BE_U_4(bp->message_digest), 321 GET_BE_U_4(bp->message_digest + 4), 322 GET_BE_U_4(bp->message_digest + 8), 323 GET_BE_U_4(bp->message_digest + 12)); 324 } else if (length == NTP_TIMEMSG_MINLEN + 4 + 20) { /* Optional: key-id + 160-bit digest */ 325 ND_PRINT("\n\tKey id: %u", GET_BE_U_4(bp->key_id)); 326 ND_TCHECK_LEN(bp->message_digest, 20); 327 ND_PRINT("\n\tAuthentication: %08x%08x%08x%08x%08x", 328 GET_BE_U_4(bp->message_digest), 329 GET_BE_U_4(bp->message_digest + 4), 330 GET_BE_U_4(bp->message_digest + 8), 331 GET_BE_U_4(bp->message_digest + 12), 332 GET_BE_U_4(bp->message_digest + 16)); 333 } else if (length > NTP_TIMEMSG_MINLEN) { 334 ND_PRINT("\n\t(%u more bytes after the header)", length - NTP_TIMEMSG_MINLEN); 335 } 336 return; 337 338 invalid: 339 nd_print_invalid(ndo); 340 ND_TCHECK_LEN(bp, length); 341 return; 342 343 trunc: 344 nd_print_trunc(ndo); 345 } 346 347 /* 348 * Print NTP control message requests and responses 349 */ 350 static void 351 ntp_control_print(netdissect_options *ndo, 352 const struct ntp_control_data *cd, u_int length) 353 { 354 uint8_t control, R, E, M, opcode; 355 uint16_t sequence, status, assoc, offset, count; 356 357 if (length < NTP_CTRLMSG_MINLEN) 358 goto invalid; 359 360 control = GET_U_1(cd->control); 361 R = (control & 0x80) != 0; 362 E = (control & 0x40) != 0; 363 M = (control & 0x20) != 0; 364 opcode = control & 0x1f; 365 ND_PRINT(", %s, %s, %s, OpCode=%u\n", 366 R ? "Response" : "Request", E ? "Error" : "OK", 367 M ? "More" : "Last", opcode); 368 369 sequence = GET_BE_U_2(cd->sequence); 370 ND_PRINT("\tSequence=%hu", sequence); 371 372 status = GET_BE_U_2(cd->status); 373 ND_PRINT(", Status=%#hx", status); 374 375 assoc = GET_BE_U_2(cd->assoc); 376 ND_PRINT(", Assoc.=%hu", assoc); 377 378 offset = GET_BE_U_2(cd->offset); 379 ND_PRINT(", Offset=%hu", offset); 380 381 count = GET_BE_U_2(cd->count); 382 ND_PRINT(", Count=%hu", count); 383 384 if (NTP_CTRLMSG_MINLEN + count > length) 385 goto invalid; 386 if (count != 0) { 387 ND_TCHECK_LEN(cd->data, count); 388 ND_PRINT("\n\tTO-BE-DONE: data not interpreted"); 389 } 390 return; 391 392 invalid: 393 nd_print_invalid(ndo); 394 ND_TCHECK_LEN(cd, length); 395 return; 396 397 trunc: 398 nd_print_trunc(ndo); 399 } 400 401 union ntpdata { 402 struct ntp_time_data td; 403 struct ntp_control_data cd; 404 }; 405 406 /* 407 * Print NTP requests, handling the common VN, LI, and Mode 408 */ 409 void 410 ntp_print(netdissect_options *ndo, 411 const u_char *cp, u_int length) 412 { 413 const union ntpdata *bp = (const union ntpdata *)cp; 414 u_int mode, version, leapind; 415 uint8_t status; 416 417 ndo->ndo_protocol = "ntp"; 418 status = GET_U_1(bp->td.status); 419 420 version = (status & VERSIONMASK) >> VERSIONSHIFT; 421 ND_PRINT("NTPv%u", version); 422 423 mode = (status & MODEMASK) >> MODESHIFT; 424 if (!ndo->ndo_vflag) { 425 ND_PRINT(", %s, length %u", 426 tok2str(ntp_mode_values, "Unknown mode", mode), 427 length); 428 return; 429 } 430 431 ND_PRINT(", %s, length %u\n", 432 tok2str(ntp_mode_values, "Unknown mode", mode), length); 433 434 /* leapind = (status & LEAPMASK) >> LEAPSHIFT; */ 435 leapind = (status & LEAPMASK); 436 ND_PRINT("\tLeap indicator: %s (%u)", 437 tok2str(ntp_leapind_values, "Unknown", leapind), 438 leapind); 439 440 switch (mode) { 441 442 case MODE_UNSPEC: 443 case MODE_SYM_ACT: 444 case MODE_SYM_PAS: 445 case MODE_CLIENT: 446 case MODE_SERVER: 447 case MODE_BROADCAST: 448 ntp_time_print(ndo, &bp->td, length); 449 break; 450 451 case MODE_CONTROL: 452 ntp_control_print(ndo, &bp->cd, length); 453 break; 454 455 default: 456 break; /* XXX: not implemented! */ 457 } 458 } 459 460 static void 461 p_sfix(netdissect_options *ndo, 462 const struct s_fixedpt *sfp) 463 { 464 int i; 465 int f; 466 double ff; 467 468 i = GET_BE_U_2(sfp->int_part); 469 f = GET_BE_U_2(sfp->fraction); 470 ff = f / 65536.0; /* shift radix point by 16 bits */ 471 f = (int)(ff * 1000000.0); /* Treat fraction as parts per million */ 472 ND_PRINT("%d.%06d", i, f); 473 } 474 475 /* Prints time difference between *lfp and *olfp */ 476 static void 477 p_ntp_delta(netdissect_options *ndo, 478 const struct l_fixedpt *olfp, 479 const struct l_fixedpt *lfp) 480 { 481 uint32_t u, uf; 482 uint32_t ou, ouf; 483 uint32_t i; 484 uint32_t f; 485 double ff; 486 int signbit; 487 488 u = GET_BE_U_4(lfp->int_part); 489 ou = GET_BE_U_4(olfp->int_part); 490 uf = GET_BE_U_4(lfp->fraction); 491 ouf = GET_BE_U_4(olfp->fraction); 492 if (ou == 0 && ouf == 0) { 493 p_ntp_time(ndo, lfp); 494 return; 495 } 496 497 if (u > ou) { /* new is definitely greater than old */ 498 signbit = 0; 499 i = u - ou; 500 f = uf - ouf; 501 if (ouf > uf) /* must borrow from high-order bits */ 502 i -= 1; 503 } else if (u < ou) { /* new is definitely less than old */ 504 signbit = 1; 505 i = ou - u; 506 f = ouf - uf; 507 if (uf > ouf) /* must borrow from the high-order bits */ 508 i -= 1; 509 } else { /* int_part is zero */ 510 i = 0; 511 if (uf > ouf) { 512 signbit = 0; 513 f = uf - ouf; 514 } else { 515 signbit = 1; 516 f = ouf - uf; 517 } 518 } 519 520 ff = f; 521 if (ff < 0.0) /* some compilers are buggy */ 522 ff += FMAXINT; 523 ff = ff / FMAXINT; /* shift radix point by 32 bits */ 524 f = (uint32_t)(ff * 1000000000.0); /* treat fraction as parts per billion */ 525 ND_PRINT("%s%u.%09u", signbit ? "-" : "+", i, f); 526 } 527 528 /* Prints polling interval in log2 as seconds or fraction of second */ 529 static void 530 p_poll(netdissect_options *ndo, 531 const int poll_interval) 532 { 533 if (poll_interval <= -32 || poll_interval >= 32) 534 return; 535 536 if (poll_interval >= 0) 537 ND_PRINT(" (%us)", 1U << poll_interval); 538 else 539 ND_PRINT(" (1/%us)", 1U << -poll_interval); 540 } 541