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