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