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 1991, 2000, 2003 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 *)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 *)ntp->li_vn_mode - 141 dlc_header, 1), 142 "Version = %lu", proto_version); 143 (void) sprintf(get_line((char *)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 *)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 *)ntp->ppoll - dlc_header, 1), 156 "Poll = %hu", 157 ntp->ppoll); 158 (void) sprintf(get_line((char *)ntp->precision - 159 dlc_header, 1), 160 "Precision = %d seconds", 161 ntp->precision); 162 (void) sprintf(get_line((char *)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((char *)ntp->dispersion.int_part - 169 dlc_header, 1), 170 "Synchronizing dispersion = 0x%04x.%04x (%f)", 171 ntohs(ntp->dispersion.int_part), 172 ntohs(ntp->dispersion.fraction), 173 s_fixed_to_double(&ntp->dispersion)); 174 (void) sprintf(get_line((char *)ntp->refid - dlc_header, 1), 175 "Reference clock = %s", 176 show_ref(ntp->stratum, ntp->refid)); 177 178 (void) sprintf(get_line((char *)ntp->reftime.int_part - 179 dlc_header, 1), 180 "Reference time = 0x%08lx.%08lx (%s)", 181 ntohl(ntp->reftime.int_part), 182 ntohl(ntp->reftime.fraction), 183 show_time(ntp->reftime)); 184 185 (void) sprintf(get_line((char *)ntp->org.int_part - 186 dlc_header, 1), 187 "Originate time = 0x%08lx.%08lx (%s)", 188 ntohl(ntp->org.int_part), 189 ntohl(ntp->org.fraction), 190 show_time(ntp->org)); 191 192 (void) sprintf(get_line((char *)ntp->rec.int_part - 193 dlc_header, 1), 194 "Receive time = 0x%08lx.%08lx (%s)", 195 ntohl(ntp->rec.int_part), 196 ntohl(ntp->rec.fraction), 197 show_time(ntp->rec)); 198 199 (void) sprintf(get_line((char *)ntp->xmt.int_part - 200 dlc_header, 1), 201 "Transmit time = 0x%08lx.%08lx (%s)", 202 ntohl(ntp->xmt.int_part), 203 ntohl(ntp->xmt.fraction), 204 show_time(ntp->xmt)); 205 206 if (proto_version > 3 || 207 fraglen < (LEN_PKT_NOMAC + MAC_OCTETS_MIN)) { 208 /* 209 * A newer protocol version we can't parse, 210 * or v3 packet with no valid authentication. 211 */ 212 break; 213 } 214 (void) sprintf(get_line((char *)ntp->keyid - 215 dlc_header, 1), 216 "Key ID = %8lu", ntohl(ntp->keyid)); 217 218 macbytes = fraglen - (LEN_PKT_NOMAC + sizeof (uint32_t)); 219 220 for (i = 0, j = 0; i < macbytes; i++) { 221 hbuf[j++] = hexstr[ntp->mac[i] >> 4 & 0x0f]; 222 hbuf[j++] = hexstr[ntp->mac[i] & 0x0f]; 223 } 224 hbuf[j] = '\0'; 225 (void) sprintf(get_line((char *)ntp->mac - 226 dlc_header, 1), 227 "Authentication code = %s", hbuf); 228 break; 229 230 case MODE_CONTROL: 231 /* NTP Control Message, mode 6 */ 232 233 (void) sprintf(get_line((char *)ntp->li_vn_mode - 234 dlc_header, 1), 235 "Leap = 0x%x (%s)", 236 (int)(ntp->li_vn_mode & LEAPMASK) >> 6, 237 show_leap(ntp->li_vn_mode & LEAPMASK)); 238 (void) sprintf(get_line((char *)ntp->li_vn_mode - 239 dlc_header, 1), 240 "Version = %lu", proto_version); 241 (void) sprintf(get_line((char *)ntp->li_vn_mode - 242 dlc_header, 1), 243 "Mode = %hu (%s)", 244 ntp->li_vn_mode & NTPMODEMASK, 245 show_mode(ntp->li_vn_mode & NTPMODEMASK)); 246 (void) sprintf(get_line((char *)ntpc->r_m_e_op - 247 dlc_header, 1), 248 "Flags and operation code = 0x%02x", 249 ntpc->r_m_e_op); 250 (void) sprintf(get_line((char *)ntpc->r_m_e_op - 251 dlc_header, 1), 252 " %s", 253 getflag(ntpc->r_m_e_op, CTL_RESPONSE, "response", 254 "request")); 255 (void) sprintf(get_line((char *)ntpc->r_m_e_op - 256 dlc_header, 1), 257 " %s", 258 getflag(ntpc->r_m_e_op, CTL_ERROR, "error", 259 "success")); 260 (void) sprintf(get_line((char *)ntpc->r_m_e_op - 261 dlc_header, 1), 262 " %s", 263 getflag(ntpc->r_m_e_op, CTL_MORE, "more", 264 "no more")); 265 (void) sprintf(get_line((char *)ntpc->r_m_e_op - 266 dlc_header, 1), 267 " ...x xxxx = %hd (%s)", 268 ntpc->r_m_e_op & CTL_OP_MASK, 269 show_operation(ntpc->r_m_e_op & CTL_OP_MASK)); 270 (void) sprintf(get_line((char *)ntpc->sequence - 271 dlc_header, 1), 272 "Sequence = %hu", 273 ntohs(ntpc->sequence)); 274 (void) sprintf(get_line((char *)ntpc->status - 275 dlc_header, 1), 276 "Status = 0x%04hx", 277 ntohs(ntpc->status)); 278 (void) sprintf(get_line((char *)ntpc->associd - 279 dlc_header, 1), 280 "Assoc ID = %hu", 281 ntohs(ntpc->associd)); 282 (void) sprintf(get_line((char *)ntpc->offset - 283 dlc_header, 1), 284 "Data offset = %hu", 285 ntohs(ntpc->offset)); 286 (void) sprintf(get_line((char *)ntpc->count - 287 dlc_header, 1), 288 "Data bytes = %hu", 289 ntohs(ntpc->count)); 290 datalen = ntohs(ntpc->count); 291 if (datalen == 0) { 292 break; 293 } else if (datalen > NTPC_DATA_MAXLEN) { 294 datalen = NTPC_DATA_MAXLEN; 295 } 296 show_space(); 297 datap = (char *)ntpc->data; 298 do { 299 (void) sprintf(get_line(datap - 300 dlc_header, 1), 301 "\"%s\"", 302 show_string(datap, linelen, datalen)); 303 sofar += linelen; 304 datap += linelen; 305 if ((sofar + linelen) > datalen) { 306 linelen = datalen - sofar; 307 } 308 } while (sofar < datalen); 309 show_trailer(); 310 break; 311 312 case MODE_PRIVATE: 313 /* NTP Private Message, mode 7 */ 314 315 (void) sprintf(get_line((char *)ntpp->rm_vn_mode - 316 dlc_header, 1), 317 "Version = %hu", 318 INFO_VERSION(ntpp->rm_vn_mode)); 319 (void) sprintf(get_line((char *)ntpp->rm_vn_mode - 320 dlc_header, 1), 321 "Mode = %hu (%s)", 322 INFO_MODE(ntpp->rm_vn_mode), 323 show_mode(INFO_MODE(ntpp->rm_vn_mode))); 324 (void) sprintf(get_line((char *)ntpp->rm_vn_mode - 325 dlc_header, 1), 326 "Flags = 0x%02hx", 327 ntpp->rm_vn_mode); 328 (void) sprintf(get_line((char *)ntpp->rm_vn_mode - 329 dlc_header, 1), 330 " %s", 331 getflag(ntpp->rm_vn_mode, RESP_BIT, "response", 332 "request")); 333 (void) sprintf(get_line((char *)ntpp->rm_vn_mode - 334 dlc_header, 1), 335 " %s", 336 getflag(ntpp->rm_vn_mode, MORE_BIT, "more", 337 "no more")); 338 (void) sprintf(get_line((char *)ntpp->auth_seq - 339 dlc_header, 1), 340 "Authentication and sequence = 0x%02x", 341 ntpp->auth_seq); 342 (void) sprintf(get_line((char *)ntpp->auth_seq - 343 dlc_header, 1), 344 " %s", 345 getflag(ntpp->auth_seq, AUTH_BIT, "authenticated", 346 "unauthenticated")); 347 (void) sprintf(get_line((char *)ntpp->auth_seq - 348 dlc_header, 1), 349 " .xxx xxxx = %hu (sequence number)", 350 INFO_SEQ(ntpp->auth_seq)); 351 (void) sprintf(get_line((char *)ntpp->implementation - 352 dlc_header, 1), 353 "Implementation = %hu", 354 ntpp->implementation); 355 (void) sprintf(get_line((char *)ntpp->request - 356 dlc_header, 1), 357 "Request = %hu", 358 ntpp->request); 359 (void) sprintf(get_line((char *)ntpp->err_nitems - 360 dlc_header, 1), 361 "Error = %hu", 362 INFO_ERR(ntpp->err_nitems)); 363 (void) sprintf(get_line((char *)ntpp->err_nitems - 364 dlc_header, 1), 365 "Items = %hu", 366 INFO_NITEMS(ntpp->err_nitems)); 367 (void) sprintf(get_line((char *)ntpp->mbz_itemsize - 368 dlc_header, 1), 369 "Item size = %hu", 370 INFO_ITEMSIZE(ntpp->mbz_itemsize)); 371 break; 372 373 default: 374 /* Unknown mode */ 375 (void) sprintf(get_line((char *)ntp->li_vn_mode - 376 dlc_header, 1), 377 "Mode = %hu (%s)", 378 ntp->li_vn_mode & NTPMODEMASK, 379 show_mode(ntp->li_vn_mode & NTPMODEMASK)); 380 break; 381 } 382 } 383 384 return (fraglen); 385 } 386 387 char * 388 show_leap(int leap) 389 { 390 switch (leap) { 391 case NO_WARNING: return ("OK"); 392 case PLUS_SEC: return ("add a second (61 seconds)"); 393 case MINUS_SEC: return ("minus a second (59 seconds)"); 394 case ALARM: return ("alarm condition (clock unsynchronized)"); 395 default: return ("unknown"); 396 } 397 } 398 399 char * 400 show_mode(int mode) 401 { 402 switch (mode) { 403 case MODE_UNSPEC: return ("unspecified"); 404 case MODE_SYM_ACT: return ("symmetric active"); 405 case MODE_SYM_PAS: return ("symmetric passive"); 406 case MODE_CLIENT: return ("client"); 407 case MODE_SERVER: return ("server"); 408 case MODE_BROADCAST: return ("broadcast"); 409 case MODE_CONTROL: return ("control"); 410 case MODE_PRIVATE: return ("private"); 411 default: return ("unknown"); 412 } 413 } 414 415 char * 416 show_ref(int mode, ulong_t refid) 417 { 418 static char buff[MAXHOSTNAMELEN + 32]; 419 struct in_addr host; 420 extern char *inet_ntoa(); 421 422 switch (mode) { 423 case 0: 424 case 1: 425 (void) strncpy(buff, (char *)&refid, 4); 426 buff[4] = '\0'; 427 break; 428 429 default: 430 host.s_addr = refid; 431 (void) sprintf(buff, "%s (%s)", 432 inet_ntoa(host), 433 addrtoname(AF_INET, &host)); 434 break; 435 } 436 437 return (buff); 438 } 439 440 /* 441 * Here we have to worry about the high order bit being signed 442 */ 443 double 444 s_fixed_to_double(struct s_fixedpt *t) 445 { 446 double a; 447 448 if (ntohs(t->int_part) & 0x8000) { 449 a = ntohs((int)(~t->fraction) & 0xFFFF); 450 a = a / 65536.0; /* shift dec point over by 16 bits */ 451 a += ntohs((int)(~t->int_part) & 0xFFFF); 452 a = -a; 453 } else { 454 a = ntohs(t->fraction); 455 a = a / 65536.0; /* shift dec point over by 16 bits */ 456 a += ntohs(t->int_part); 457 } 458 return (a); 459 } 460 461 /* 462 * Consistent with RFC-3339, ISO 8601. 463 */ 464 char * 465 iso_date_time(time_t input_time) 466 { 467 struct tm *time_parts; 468 static char tbuf[sizeof ("yyyy-mm-dd hh:mm:ss")]; 469 470 time_parts = localtime(&input_time); 471 (void) strftime(tbuf, sizeof (tbuf), "%Y-%m-%d %H:%M:%S", time_parts); 472 return (tbuf); 473 } 474 475 /* 476 * The base of NTP timestamps is 1900-01-01 00:00:00.00000 477 */ 478 char * 479 show_time(struct l_fixedpt pkt_time) 480 { 481 struct l_fixedpt net_time; 482 unsigned long fracsec; 483 static char buff[32]; 484 485 if (pkt_time.int_part == 0) { 486 buff[0] = '\0'; 487 return (buff); 488 } 489 490 net_time.int_part = ntohl(pkt_time.int_part) - JAN_1970; 491 net_time.fraction = ntohl(pkt_time.fraction); 492 493 fracsec = net_time.fraction / 42949; /* fract / (2**32/10**6) */ 494 495 (void) strlcpy(buff, iso_date_time(net_time.int_part), sizeof (buff)); 496 (void) snprintf(buff, sizeof (buff), "%s.%05lu", buff, fracsec); 497 498 return (buff); 499 } 500 501 char * 502 show_operation(int op) 503 { 504 switch (op) { 505 case CTL_OP_UNSPEC: return ("unspecified"); 506 case CTL_OP_READSTAT: return ("read stats"); 507 case CTL_OP_READVAR: return ("read var"); 508 case CTL_OP_WRITEVAR: return ("write var"); 509 case CTL_OP_READCLOCK: return ("read clock"); 510 case CTL_OP_WRITECLOCK: return ("write clock"); 511 case CTL_OP_SETTRAP: return ("set trap"); 512 case CTL_OP_ASYNCMSG: return ("async msg"); 513 case CTL_OP_UNSETTRAP: return ("unset trap"); 514 default: return ("unknown"); 515 } 516 } 517