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