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