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 #ifdef HAVE_CONFIG_H 28 #include "config.h" 29 #endif 30 31 #include <netdissect-stdinc.h> 32 33 #ifdef HAVE_STRFTIME 34 #include <time.h> 35 #endif 36 37 #include "netdissect.h" 38 #include "addrtoname.h" 39 #include "extract.h" 40 41 /* 42 * Based on ntp.h from the U of MD implementation 43 * This file is based on Version 2 of the NTP spec (RFC1119). 44 */ 45 46 /* 47 * Definitions for the masses 48 */ 49 #define JAN_1970 2208988800U /* 1970 - 1900 in seconds */ 50 51 /* 52 * Structure definitions for NTP fixed point values 53 * 54 * 0 1 2 3 55 * 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 56 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 57 * | Integer Part | 58 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 59 * | Fraction Part | 60 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 61 * 62 * 0 1 2 3 63 * 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 64 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 65 * | Integer Part | Fraction Part | 66 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 67 */ 68 struct l_fixedpt { 69 uint32_t int_part; 70 uint32_t fraction; 71 }; 72 73 struct s_fixedpt { 74 uint16_t int_part; 75 uint16_t fraction; 76 }; 77 78 /* rfc2030 79 * 1 2 3 80 * 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 81 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 82 * |LI | VN |Mode | Stratum | Poll | Precision | 83 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 84 * | Root Delay | 85 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 86 * | Root Dispersion | 87 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 88 * | Reference Identifier | 89 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 90 * | | 91 * | Reference Timestamp (64) | 92 * | | 93 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 94 * | | 95 * | Originate Timestamp (64) | 96 * | | 97 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 98 * | | 99 * | Receive Timestamp (64) | 100 * | | 101 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 102 * | | 103 * | Transmit Timestamp (64) | 104 * | | 105 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 106 * | Key Identifier (optional) (32) | 107 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 108 * | | 109 * | | 110 * | Message Digest (optional) (128) | 111 * | | 112 * | | 113 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 114 */ 115 116 struct ntpdata { 117 u_char status; /* status of local clock and leap info */ 118 u_char stratum; /* Stratum level */ 119 u_char ppoll; /* poll value */ 120 int precision:8; 121 struct s_fixedpt root_delay; 122 struct s_fixedpt root_dispersion; 123 uint32_t refid; 124 struct l_fixedpt ref_timestamp; 125 struct l_fixedpt org_timestamp; 126 struct l_fixedpt rec_timestamp; 127 struct l_fixedpt xmt_timestamp; 128 uint32_t key_id; 129 uint8_t message_digest[16]; 130 }; 131 /* 132 * Leap Second Codes (high order two bits) 133 */ 134 #define NO_WARNING 0x00 /* no warning */ 135 #define PLUS_SEC 0x40 /* add a second (61 seconds) */ 136 #define MINUS_SEC 0x80 /* minus a second (59 seconds) */ 137 #define ALARM 0xc0 /* alarm condition (clock unsynchronized) */ 138 139 /* 140 * Clock Status Bits that Encode Version 141 */ 142 #define NTPVERSION_1 0x08 143 #define VERSIONMASK 0x38 144 #define LEAPMASK 0xc0 145 #ifdef MODEMASK 146 #undef MODEMASK /* Solaris sucks */ 147 #endif 148 #define MODEMASK 0x07 149 150 /* 151 * Code values 152 */ 153 #define MODE_UNSPEC 0 /* unspecified */ 154 #define MODE_SYM_ACT 1 /* symmetric active */ 155 #define MODE_SYM_PAS 2 /* symmetric passive */ 156 #define MODE_CLIENT 3 /* client */ 157 #define MODE_SERVER 4 /* server */ 158 #define MODE_BROADCAST 5 /* broadcast */ 159 #define MODE_RES1 6 /* reserved */ 160 #define MODE_RES2 7 /* reserved */ 161 162 /* 163 * Stratum Definitions 164 */ 165 #define UNSPECIFIED 0 166 #define PRIM_REF 1 /* radio clock */ 167 #define INFO_QUERY 62 /* **** THIS implementation dependent **** */ 168 #define INFO_REPLY 63 /* **** THIS implementation dependent **** */ 169 170 static void p_sfix(netdissect_options *ndo, const struct s_fixedpt *); 171 static void p_ntp_time(netdissect_options *, const struct l_fixedpt *); 172 static void p_ntp_delta(netdissect_options *, const struct l_fixedpt *, const struct l_fixedpt *); 173 174 static const struct tok ntp_mode_values[] = { 175 { MODE_UNSPEC, "unspecified" }, 176 { MODE_SYM_ACT, "symmetric active" }, 177 { MODE_SYM_PAS, "symmetric passive" }, 178 { MODE_CLIENT, "Client" }, 179 { MODE_SERVER, "Server" }, 180 { MODE_BROADCAST, "Broadcast" }, 181 { MODE_RES1, "Reserved" }, 182 { MODE_RES2, "Reserved" }, 183 { 0, NULL } 184 }; 185 186 static const struct tok ntp_leapind_values[] = { 187 { NO_WARNING, "" }, 188 { PLUS_SEC, "+1s" }, 189 { MINUS_SEC, "-1s" }, 190 { ALARM, "clock unsynchronized" }, 191 { 0, NULL } 192 }; 193 194 static const struct tok ntp_stratum_values[] = { 195 { UNSPECIFIED, "unspecified" }, 196 { PRIM_REF, "primary reference" }, 197 { 0, NULL } 198 }; 199 200 /* 201 * Print ntp requests 202 */ 203 void 204 ntp_print(netdissect_options *ndo, 205 register const u_char *cp, u_int length) 206 { 207 register const struct ntpdata *bp; 208 int mode, version, leapind; 209 210 bp = (const struct ntpdata *)cp; 211 212 ND_TCHECK(bp->status); 213 214 version = (int)(bp->status & VERSIONMASK) >> 3; 215 ND_PRINT((ndo, "NTPv%d", version)); 216 217 mode = bp->status & MODEMASK; 218 if (!ndo->ndo_vflag) { 219 ND_PRINT((ndo, ", %s, length %u", 220 tok2str(ntp_mode_values, "Unknown mode", mode), 221 length)); 222 return; 223 } 224 225 ND_PRINT((ndo, ", length %u\n\t%s", 226 length, 227 tok2str(ntp_mode_values, "Unknown mode", mode))); 228 229 leapind = bp->status & LEAPMASK; 230 ND_PRINT((ndo, ", Leap indicator: %s (%u)", 231 tok2str(ntp_leapind_values, "Unknown", leapind), 232 leapind)); 233 234 ND_TCHECK(bp->stratum); 235 ND_PRINT((ndo, ", Stratum %u (%s)", 236 bp->stratum, 237 tok2str(ntp_stratum_values, (bp->stratum >=2 && bp->stratum<=15) ? "secondary reference" : "reserved", bp->stratum))); 238 239 ND_TCHECK(bp->ppoll); 240 ND_PRINT((ndo, ", poll %u (%us)", bp->ppoll, 1 << bp->ppoll)); 241 242 /* Can't ND_TCHECK bp->precision bitfield so bp->distance + 0 instead */ 243 ND_TCHECK2(bp->root_delay, 0); 244 ND_PRINT((ndo, ", precision %d", bp->precision)); 245 246 ND_TCHECK(bp->root_delay); 247 ND_PRINT((ndo, "\n\tRoot Delay: ")); 248 p_sfix(ndo, &bp->root_delay); 249 250 ND_TCHECK(bp->root_dispersion); 251 ND_PRINT((ndo, ", Root dispersion: ")); 252 p_sfix(ndo, &bp->root_dispersion); 253 254 ND_TCHECK(bp->refid); 255 ND_PRINT((ndo, ", Reference-ID: ")); 256 /* Interpretation depends on stratum */ 257 switch (bp->stratum) { 258 259 case UNSPECIFIED: 260 ND_PRINT((ndo, "(unspec)")); 261 break; 262 263 case PRIM_REF: 264 if (fn_printn(ndo, (const u_char *)&(bp->refid), 4, ndo->ndo_snapend)) 265 goto trunc; 266 break; 267 268 case INFO_QUERY: 269 ND_PRINT((ndo, "%s INFO_QUERY", ipaddr_string(ndo, &(bp->refid)))); 270 /* this doesn't have more content */ 271 return; 272 273 case INFO_REPLY: 274 ND_PRINT((ndo, "%s INFO_REPLY", ipaddr_string(ndo, &(bp->refid)))); 275 /* this is too complex to be worth printing */ 276 return; 277 278 default: 279 ND_PRINT((ndo, "%s", ipaddr_string(ndo, &(bp->refid)))); 280 break; 281 } 282 283 ND_TCHECK(bp->ref_timestamp); 284 ND_PRINT((ndo, "\n\t Reference Timestamp: ")); 285 p_ntp_time(ndo, &(bp->ref_timestamp)); 286 287 ND_TCHECK(bp->org_timestamp); 288 ND_PRINT((ndo, "\n\t Originator Timestamp: ")); 289 p_ntp_time(ndo, &(bp->org_timestamp)); 290 291 ND_TCHECK(bp->rec_timestamp); 292 ND_PRINT((ndo, "\n\t Receive Timestamp: ")); 293 p_ntp_time(ndo, &(bp->rec_timestamp)); 294 295 ND_TCHECK(bp->xmt_timestamp); 296 ND_PRINT((ndo, "\n\t Transmit Timestamp: ")); 297 p_ntp_time(ndo, &(bp->xmt_timestamp)); 298 299 ND_PRINT((ndo, "\n\t Originator - Receive Timestamp: ")); 300 p_ntp_delta(ndo, &(bp->org_timestamp), &(bp->rec_timestamp)); 301 302 ND_PRINT((ndo, "\n\t Originator - Transmit Timestamp: ")); 303 p_ntp_delta(ndo, &(bp->org_timestamp), &(bp->xmt_timestamp)); 304 305 if ( (sizeof(struct ntpdata) - length) == 16) { /* Optional: key-id */ 306 ND_TCHECK(bp->key_id); 307 ND_PRINT((ndo, "\n\tKey id: %u", bp->key_id)); 308 } else if ( (sizeof(struct ntpdata) - length) == 0) { /* Optional: key-id + authentication */ 309 ND_TCHECK(bp->key_id); 310 ND_PRINT((ndo, "\n\tKey id: %u", bp->key_id)); 311 ND_TCHECK2(bp->message_digest, sizeof (bp->message_digest)); 312 ND_PRINT((ndo, "\n\tAuthentication: %08x%08x%08x%08x", 313 EXTRACT_32BITS(bp->message_digest), 314 EXTRACT_32BITS(bp->message_digest + 4), 315 EXTRACT_32BITS(bp->message_digest + 8), 316 EXTRACT_32BITS(bp->message_digest + 12))); 317 } 318 return; 319 320 trunc: 321 ND_PRINT((ndo, " [|ntp]")); 322 } 323 324 static void 325 p_sfix(netdissect_options *ndo, 326 register const struct s_fixedpt *sfp) 327 { 328 register int i; 329 register int f; 330 register double ff; 331 332 i = EXTRACT_16BITS(&sfp->int_part); 333 f = EXTRACT_16BITS(&sfp->fraction); 334 ff = f / 65536.0; /* shift radix point by 16 bits */ 335 f = (int)(ff * 1000000.0); /* Treat fraction as parts per million */ 336 ND_PRINT((ndo, "%d.%06d", i, f)); 337 } 338 339 #define FMAXINT (4294967296.0) /* floating point rep. of MAXINT */ 340 341 static void 342 p_ntp_time(netdissect_options *ndo, 343 register const struct l_fixedpt *lfp) 344 { 345 register int32_t i; 346 register uint32_t uf; 347 register uint32_t f; 348 register double ff; 349 350 i = EXTRACT_32BITS(&lfp->int_part); 351 uf = EXTRACT_32BITS(&lfp->fraction); 352 ff = uf; 353 if (ff < 0.0) /* some compilers are buggy */ 354 ff += FMAXINT; 355 ff = ff / FMAXINT; /* shift radix point by 32 bits */ 356 f = (uint32_t)(ff * 1000000000.0); /* treat fraction as parts per billion */ 357 ND_PRINT((ndo, "%u.%09d", i, f)); 358 359 #ifdef HAVE_STRFTIME 360 /* 361 * print the time in human-readable format. 362 */ 363 if (i) { 364 time_t seconds = i - JAN_1970; 365 struct tm *tm; 366 char time_buf[128]; 367 368 tm = localtime(&seconds); 369 strftime(time_buf, sizeof (time_buf), "%Y/%m/%d %H:%M:%S", tm); 370 ND_PRINT((ndo, " (%s)", time_buf)); 371 } 372 #endif 373 } 374 375 /* Prints time difference between *lfp and *olfp */ 376 static void 377 p_ntp_delta(netdissect_options *ndo, 378 register const struct l_fixedpt *olfp, 379 register const struct l_fixedpt *lfp) 380 { 381 register int32_t i; 382 register uint32_t u, uf; 383 register uint32_t ou, ouf; 384 register uint32_t f; 385 register double ff; 386 int signbit; 387 388 u = EXTRACT_32BITS(&lfp->int_part); 389 ou = EXTRACT_32BITS(&olfp->int_part); 390 uf = EXTRACT_32BITS(&lfp->fraction); 391 ouf = EXTRACT_32BITS(&olfp->fraction); 392 if (ou == 0 && ouf == 0) { 393 p_ntp_time(ndo, lfp); 394 return; 395 } 396 397 i = u - ou; 398 399 if (i > 0) { /* new is definitely greater than old */ 400 signbit = 0; 401 f = uf - ouf; 402 if (ouf > uf) /* must borrow from high-order bits */ 403 i -= 1; 404 } else if (i < 0) { /* new is definitely less than old */ 405 signbit = 1; 406 f = ouf - uf; 407 if (uf > ouf) /* must carry into the high-order bits */ 408 i += 1; 409 i = -i; 410 } else { /* int_part is zero */ 411 if (uf > ouf) { 412 signbit = 0; 413 f = uf - ouf; 414 } else { 415 signbit = 1; 416 f = ouf - uf; 417 } 418 } 419 420 ff = f; 421 if (ff < 0.0) /* some compilers are buggy */ 422 ff += FMAXINT; 423 ff = ff / FMAXINT; /* shift radix point by 32 bits */ 424 f = (uint32_t)(ff * 1000000000.0); /* treat fraction as parts per billion */ 425 ND_PRINT((ndo, "%s%d.%09d", signbit ? "-" : "+", i, f)); 426 } 427 428