Home | History | Annotate | Download | only in snoop
      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