1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <fcntl.h> 30 #include <sys/socket.h> 31 #include <sys/sysmacros.h> 32 #include <netinet/in.h> 33 #include <netdb.h> 34 #include <stdio.h> 35 #include <string.h> 36 #include <tzfile.h> 37 #include "snoop.h" 38 #include "ntp.h" 39 40 /* 41 * In verbose mode, how many octets of the control-mode data payload 42 * are displayed per line of output. The value 64 fits well on an 43 * 80-column screen and, as a power of 2, is easily correlated to 44 * hexadecimal output. 45 */ 46 #define OCTETS_PER_LINE 64 47 48 extern char *dlc_header; 49 50 static char *show_leap(int); 51 static char *show_mode(int); 52 static char *show_ref(int, ulong_t); 53 static char *show_time(struct l_fixedpt); 54 static double s_fixed_to_double(struct s_fixedpt *); 55 static char *iso_date_time(time_t); 56 static char *show_operation(int); 57 58 int 59 interpret_ntp(int flags, struct ntpdata *ntp_pkt, int fraglen) 60 { 61 unsigned int i, j, macbytes; 62 unsigned int proto_version; 63 unsigned int datalen; 64 unsigned int linelen = OCTETS_PER_LINE; 65 unsigned int sofar = 0; 66 67 char *datap; 68 char hbuf[2 * MAC_OCTETS_MAX + 1]; 69 static char *hexstr = "0123456789ABCDEF"; 70 71 union ntp_pkt_buf { 72 struct ntpdata ntp_msg; 73 union ntpc_buf { 74 struct ntp_control chdr; 75 uchar_t data2[NTPC_DATA_MAXLEN - 1]; 76 } ntpc_msg; 77 union ntpp_buf { 78 struct ntp_private phdr; 79 uchar_t data2[1]; 80 } ntpp_msg; 81 } fragbuf; 82 83 struct ntpdata *ntp = &fragbuf.ntp_msg; 84 struct ntp_control *ntpc = (struct ntp_control *)&fragbuf.ntpc_msg; 85 struct ntp_private *ntpp = (struct ntp_private *)&fragbuf.ntpp_msg; 86 87 /* 88 * Copying packet contents into a local buffer avoids 89 * problems of interpretation if the packet is truncated. 90 */ 91 (void) memcpy(&fragbuf, ntp_pkt, MIN(sizeof (fragbuf), fraglen)); 92 93 if (flags & F_SUM) { 94 switch (ntp->li_vn_mode & NTPMODEMASK) { 95 case MODE_SYM_ACT: 96 case MODE_SYM_PAS: 97 case MODE_CLIENT: 98 case MODE_SERVER: 99 case MODE_BROADCAST: 100 (void) sprintf(get_sum_line(), 101 "NTP %s [st=%hd] (%s)", 102 show_mode(ntp->li_vn_mode & NTPMODEMASK), 103 ntp->stratum, 104 show_time(ntp->xmt)); 105 break; 106 case MODE_CONTROL: 107 (void) sprintf(get_sum_line(), 108 "NTP %s " 109 "(Flags/op=0x%02x Seq=%hu Status=0x%04hx Assoc=%hu)", 110 show_mode(ntpc->li_vn_mode & NTPMODEMASK), 111 ntpc->r_m_e_op, 112 ntohs(ntpc->sequence), 113 ntohs(ntpc->status), 114 ntohs(ntpc->associd)); 115 break; 116 default: 117 (void) sprintf(get_sum_line(), 118 "NTP %s", 119 show_mode(ntpp->rm_vn_mode & NTPMODEMASK)); 120 break; 121 } 122 } 123 124 proto_version = (ntp->li_vn_mode & VERSIONMASK) >> 3; 125 126 if (flags & F_DTAIL) { 127 show_header("NTP: ", "Network Time Protocol", fraglen); 128 show_space(); 129 switch (ntp->li_vn_mode & NTPMODEMASK) { 130 case MODE_SYM_ACT: 131 case MODE_SYM_PAS: 132 case MODE_CLIENT: 133 case MODE_SERVER: 134 case MODE_BROADCAST: 135 (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode - 136 dlc_header, 1), 137 "Leap = 0x%x (%s)", 138 (int)(ntp->li_vn_mode & LEAPMASK) >> 6, 139 show_leap(ntp->li_vn_mode & LEAPMASK)); 140 (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode - 141 dlc_header, 1), 142 "Version = %lu", proto_version); 143 (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode - 144 dlc_header, 1), 145 "Mode = %hu (%s)", 146 ntp->li_vn_mode & NTPMODEMASK, 147 show_mode(ntp->li_vn_mode & NTPMODEMASK)); 148 (void) sprintf(get_line((char *)(uintptr_t)ntp->stratum - 149 dlc_header, 1), 150 "Stratum = %d (%s)", 151 ntp->stratum, 152 ntp->stratum == 0 ? "unspecified" : 153 ntp->stratum == 1 ? "primary reference" : 154 "secondary reference"); 155 (void) sprintf(get_line((char *)(uintptr_t)ntp->ppoll - 156 dlc_header, 1), "Poll = %hu", ntp->ppoll); 157 (void) sprintf(get_line((char *)(uintptr_t)ntp->precision - 158 dlc_header, 1), 159 "Precision = %d seconds", 160 ntp->precision); 161 (void) sprintf(get_line( 162 (char *)(uintptr_t)ntp->distance.int_part - 163 dlc_header, 1), 164 "Synchronizing distance = 0x%04x.%04x (%f)", 165 ntohs(ntp->distance.int_part), 166 ntohs(ntp->distance.fraction), 167 s_fixed_to_double(&ntp->distance)); 168 (void) sprintf(get_line( 169 (char *)(uintptr_t)ntp->dispersion.int_part - 170 dlc_header, 1), 171 "Synchronizing dispersion = 0x%04x.%04x (%f)", 172 ntohs(ntp->dispersion.int_part), 173 ntohs(ntp->dispersion.fraction), 174 s_fixed_to_double(&ntp->dispersion)); 175 (void) sprintf(get_line((char *)(uintptr_t)ntp->refid - 176 dlc_header, 1), "Reference clock = %s", 177 show_ref(ntp->stratum, ntp->refid)); 178 179 (void) sprintf(get_line( 180 (char *)(uintptr_t)ntp->reftime.int_part - dlc_header, 181 1), "Reference time = 0x%08lx.%08lx (%s)", 182 ntohl(ntp->reftime.int_part), 183 ntohl(ntp->reftime.fraction), 184 show_time(ntp->reftime)); 185 186 (void) sprintf(get_line( 187 (char *)(uintptr_t)ntp->org.int_part - dlc_header, 1), 188 "Originate time = 0x%08lx.%08lx (%s)", 189 ntohl(ntp->org.int_part), 190 ntohl(ntp->org.fraction), 191 show_time(ntp->org)); 192 193 (void) sprintf(get_line( 194 (char *)(uintptr_t)ntp->rec.int_part - dlc_header, 1), 195 "Receive time = 0x%08lx.%08lx (%s)", 196 ntohl(ntp->rec.int_part), 197 ntohl(ntp->rec.fraction), 198 show_time(ntp->rec)); 199 200 (void) sprintf(get_line( 201 (char *)(uintptr_t)ntp->xmt.int_part - dlc_header, 1), 202 "Transmit time = 0x%08lx.%08lx (%s)", 203 ntohl(ntp->xmt.int_part), 204 ntohl(ntp->xmt.fraction), 205 show_time(ntp->xmt)); 206 207 if (proto_version > 3 || 208 fraglen < (LEN_PKT_NOMAC + MAC_OCTETS_MIN)) { 209 /* 210 * A newer protocol version we can't parse, 211 * or v3 packet with no valid authentication. 212 */ 213 break; 214 } 215 (void) sprintf(get_line((char *)ntp->keyid - 216 dlc_header, 1), 217 "Key ID = %8lu", ntohl(ntp->keyid)); 218 219 macbytes = fraglen - (LEN_PKT_NOMAC + sizeof (uint32_t)); 220 221 for (i = 0, j = 0; i < macbytes; i++) { 222 hbuf[j++] = hexstr[ntp->mac[i] >> 4 & 0x0f]; 223 hbuf[j++] = hexstr[ntp->mac[i] & 0x0f]; 224 } 225 hbuf[j] = '\0'; 226 (void) sprintf(get_line((char *)ntp->mac - 227 dlc_header, 1), 228 "Authentication code = %s", hbuf); 229 break; 230 231 case MODE_CONTROL: 232 /* NTP Control Message, mode 6 */ 233 234 (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode - 235 dlc_header, 1), 236 "Leap = 0x%x (%s)", 237 (int)(ntp->li_vn_mode & LEAPMASK) >> 6, 238 show_leap(ntp->li_vn_mode & LEAPMASK)); 239 (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode - 240 dlc_header, 1), 241 "Version = %lu", proto_version); 242 (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode - 243 dlc_header, 1), 244 "Mode = %hu (%s)", 245 ntp->li_vn_mode & NTPMODEMASK, 246 show_mode(ntp->li_vn_mode & NTPMODEMASK)); 247 (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op - 248 dlc_header, 1), 249 "Flags and operation code = 0x%02x", 250 ntpc->r_m_e_op); 251 (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op - 252 dlc_header, 1), 253 " %s", 254 getflag(ntpc->r_m_e_op, CTL_RESPONSE, "response", 255 "request")); 256 (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op - 257 dlc_header, 1), 258 " %s", 259 getflag(ntpc->r_m_e_op, CTL_ERROR, "error", 260 "success")); 261 (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op - 262 dlc_header, 1), 263 " %s", 264 getflag(ntpc->r_m_e_op, CTL_MORE, "more", 265 "no more")); 266 (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op - 267 dlc_header, 1), 268 " ...x xxxx = %hd (%s)", 269 ntpc->r_m_e_op & CTL_OP_MASK, 270 show_operation(ntpc->r_m_e_op & CTL_OP_MASK)); 271 (void) sprintf(get_line((char *)(uintptr_t)ntpc->sequence - 272 dlc_header, 1), 273 "Sequence = %hu", 274 ntohs(ntpc->sequence)); 275 (void) sprintf(get_line((char *)(uintptr_t)ntpc->status - 276 dlc_header, 1), 277 "Status = 0x%04hx", 278 ntohs(ntpc->status)); 279 (void) sprintf(get_line((char *)(uintptr_t)ntpc->associd - 280 dlc_header, 1), 281 "Assoc ID = %hu", 282 ntohs(ntpc->associd)); 283 (void) sprintf(get_line((char *)(uintptr_t)ntpc->offset - 284 dlc_header, 1), 285 "Data offset = %hu", 286 ntohs(ntpc->offset)); 287 (void) sprintf(get_line((char *)(uintptr_t)ntpc->count - 288 dlc_header, 1), 289 "Data bytes = %hu", 290 ntohs(ntpc->count)); 291 datalen = ntohs(ntpc->count); 292 if (datalen == 0) { 293 break; 294 } else if (datalen > NTPC_DATA_MAXLEN) { 295 datalen = NTPC_DATA_MAXLEN; 296 } 297 show_space(); 298 datap = (char *)ntpc->data; 299 do { 300 (void) sprintf(get_line(datap - 301 dlc_header, 1), 302 "\"%s\"", 303 show_string(datap, linelen, datalen)); 304 sofar += linelen; 305 datap += linelen; 306 if ((sofar + linelen) > datalen) { 307 linelen = datalen - sofar; 308 } 309 } while (sofar < datalen); 310 show_trailer(); 311 break; 312 313 case MODE_PRIVATE: 314 /* NTP Private Message, mode 7 */ 315 316 (void) sprintf(get_line( 317 (char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1), 318 "Version = %hu", INFO_VERSION(ntpp->rm_vn_mode)); 319 (void) sprintf(get_line( 320 (char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1), 321 "Mode = %hu (%s)", INFO_MODE(ntpp->rm_vn_mode), 322 show_mode(INFO_MODE(ntpp->rm_vn_mode))); 323 (void) sprintf(get_line( 324 (char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1), 325 "Flags = 0x%02hx", ntpp->rm_vn_mode); 326 (void) sprintf(get_line( 327 (char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1), 328 " %s", 329 getflag(ntpp->rm_vn_mode, RESP_BIT, "response", 330 "request")); 331 (void) sprintf(get_line( 332 (char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1), 333 " %s", 334 getflag(ntpp->rm_vn_mode, MORE_BIT, "more", "no more")); 335 (void) sprintf(get_line((char *)(uintptr_t)ntpp->auth_seq - 336 dlc_header, 1), 337 "Authentication and sequence = 0x%02x", ntpp->auth_seq); 338 (void) sprintf(get_line((char *)(uintptr_t)ntpp->auth_seq - 339 dlc_header, 1), 340 " %s", 341 getflag(ntpp->auth_seq, AUTH_BIT, "authenticated", 342 "unauthenticated")); 343 (void) sprintf(get_line((char *)(uintptr_t)ntpp->auth_seq - 344 dlc_header, 1), 345 " .xxx xxxx = %hu (sequence number)", 346 INFO_SEQ(ntpp->auth_seq)); 347 (void) sprintf(get_line( 348 (char *)(uintptr_t)ntpp->implementation - dlc_header, 349 1), "Implementation = %hu", ntpp->implementation); 350 (void) sprintf(get_line((char *)(uintptr_t)ntpp->request - 351 dlc_header, 1), "Request = %hu", ntpp->request); 352 (void) sprintf(get_line( 353 (char *)(uintptr_t)ntpp->err_nitems - dlc_header, 1), 354 "Error = %hu", INFO_ERR(ntpp->err_nitems)); 355 (void) sprintf(get_line( 356 (char *)(uintptr_t)ntpp->err_nitems - dlc_header, 1), 357 "Items = %hu", INFO_NITEMS(ntpp->err_nitems)); 358 (void) sprintf(get_line( 359 (char *)(uintptr_t)ntpp->mbz_itemsize - dlc_header, 1), 360 "Item size = %hu", INFO_ITEMSIZE(ntpp->mbz_itemsize)); 361 break; 362 363 default: 364 /* Unknown mode */ 365 (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode - 366 dlc_header, 1), "Mode = %hu (%s)", 367 ntp->li_vn_mode & NTPMODEMASK, 368 show_mode(ntp->li_vn_mode & NTPMODEMASK)); 369 break; 370 } 371 } 372 373 return (fraglen); 374 } 375 376 char * 377 show_leap(int leap) 378 { 379 switch (leap) { 380 case NO_WARNING: return ("OK"); 381 case PLUS_SEC: return ("add a second (61 seconds)"); 382 case MINUS_SEC: return ("minus a second (59 seconds)"); 383 case ALARM: return ("alarm condition (clock unsynchronized)"); 384 default: return ("unknown"); 385 } 386 } 387 388 char * 389 show_mode(int mode) 390 { 391 switch (mode) { 392 case MODE_UNSPEC: return ("unspecified"); 393 case MODE_SYM_ACT: return ("symmetric active"); 394 case MODE_SYM_PAS: return ("symmetric passive"); 395 case MODE_CLIENT: return ("client"); 396 case MODE_SERVER: return ("server"); 397 case MODE_BROADCAST: return ("broadcast"); 398 case MODE_CONTROL: return ("control"); 399 case MODE_PRIVATE: return ("private"); 400 default: return ("unknown"); 401 } 402 } 403 404 char * 405 show_ref(int mode, ulong_t refid) 406 { 407 static char buff[MAXHOSTNAMELEN + 32]; 408 struct in_addr host; 409 extern char *inet_ntoa(); 410 411 switch (mode) { 412 case 0: 413 case 1: 414 (void) strncpy(buff, (char *)&refid, 4); 415 buff[4] = '\0'; 416 break; 417 418 default: 419 host.s_addr = refid; 420 (void) sprintf(buff, "%s (%s)", 421 inet_ntoa(host), 422 addrtoname(AF_INET, &host)); 423 break; 424 } 425 426 return (buff); 427 } 428 429 /* 430 * Here we have to worry about the high order bit being signed 431 */ 432 double 433 s_fixed_to_double(struct s_fixedpt *t) 434 { 435 double a; 436 437 if (ntohs(t->int_part) & 0x8000) { 438 a = ntohs((int)(~t->fraction) & 0xFFFF); 439 a = a / 65536.0; /* shift dec point over by 16 bits */ 440 a += ntohs((int)(~t->int_part) & 0xFFFF); 441 a = -a; 442 } else { 443 a = ntohs(t->fraction); 444 a = a / 65536.0; /* shift dec point over by 16 bits */ 445 a += ntohs(t->int_part); 446 } 447 return (a); 448 } 449 450 /* 451 * Consistent with RFC-3339, ISO 8601. 452 */ 453 char * 454 iso_date_time(time_t input_time) 455 { 456 struct tm *time_parts; 457 static char tbuf[sizeof ("yyyy-mm-dd hh:mm:ss")]; 458 459 time_parts = localtime(&input_time); 460 (void) strftime(tbuf, sizeof (tbuf), "%Y-%m-%d %H:%M:%S", time_parts); 461 return (tbuf); 462 } 463 464 /* 465 * The base of NTP timestamps is 1900-01-01 00:00:00.00000 466 */ 467 char * 468 show_time(struct l_fixedpt pkt_time) 469 { 470 struct l_fixedpt net_time; 471 unsigned long fracsec; 472 static char buff[32]; 473 474 if (pkt_time.int_part == 0) { 475 buff[0] = '\0'; 476 return (buff); 477 } 478 479 net_time.int_part = ntohl(pkt_time.int_part) - JAN_1970; 480 net_time.fraction = ntohl(pkt_time.fraction); 481 482 fracsec = net_time.fraction / 42949; /* fract / (2**32/10**6) */ 483 484 (void) strlcpy(buff, iso_date_time(net_time.int_part), sizeof (buff)); 485 (void) snprintf(buff, sizeof (buff), "%s.%05lu", buff, fracsec); 486 487 return (buff); 488 } 489 490 char * 491 show_operation(int op) 492 { 493 switch (op) { 494 case CTL_OP_UNSPEC: return ("unspecified"); 495 case CTL_OP_READSTAT: return ("read stats"); 496 case CTL_OP_READVAR: return ("read var"); 497 case CTL_OP_WRITEVAR: return ("write var"); 498 case CTL_OP_READCLOCK: return ("read clock"); 499 case CTL_OP_WRITECLOCK: return ("write clock"); 500 case CTL_OP_SETTRAP: return ("set trap"); 501 case CTL_OP_ASYNCMSG: return ("async msg"); 502 case CTL_OP_UNSETTRAP: return ("unset trap"); 503 default: return ("unknown"); 504 } 505 } 506