dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.sbin / snoop / snoop_ntp.c
blob4f6fae3986d285076a1dd890ee0a0b3fd87daeb8
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
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"
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.
46 #define OCTETS_PER_LINE 64
48 extern char *dlc_header;
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);
58 int
59 interpret_ntp(int flags, struct ntpdata *ntp_pkt, int fraglen)
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;
67 char *datap;
68 char hbuf[2 * MAC_OCTETS_MAX + 1];
69 static char *hexstr = "0123456789ABCDEF";
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;
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;
88 * Copying packet contents into a local buffer avoids
89 * problems of interpretation if the packet is truncated.
91 (void) memcpy(&fragbuf, ntp_pkt, MIN(sizeof (fragbuf), fraglen));
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;
124 proto_version = (ntp->li_vn_mode & VERSIONMASK) >> 3;
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));
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));
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));
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));
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));
207 if (proto_version > 3 ||
208 fraglen < (LEN_PKT_NOMAC + MAC_OCTETS_MIN)) {
210 * A newer protocol version we can't parse,
211 * or v3 packet with no valid authentication.
213 break;
215 (void) sprintf(get_line((char *)ntp->keyid -
216 dlc_header, 1),
217 "Key ID = %8lu", ntohl(ntp->keyid));
219 macbytes = fraglen - (LEN_PKT_NOMAC + sizeof (uint32_t));
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];
225 hbuf[j] = '\0';
226 (void) sprintf(get_line((char *)ntp->mac -
227 dlc_header, 1),
228 "Authentication code = %s", hbuf);
229 break;
231 case MODE_CONTROL:
232 /* NTP Control Message, mode 6 */
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;
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;
309 } while (sofar < datalen);
310 show_trailer();
311 break;
313 case MODE_PRIVATE:
314 /* NTP Private Message, mode 7 */
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;
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;
373 return (fraglen);
376 char *
377 show_leap(int leap)
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");
388 char *
389 show_mode(int mode)
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");
404 char *
405 show_ref(int mode, ulong_t refid)
407 static char buff[MAXHOSTNAMELEN + 32];
408 struct in_addr host;
409 extern char *inet_ntoa();
411 switch (mode) {
412 case 0:
413 case 1:
414 (void) strncpy(buff, (char *)&refid, 4);
415 buff[4] = '\0';
416 break;
418 default:
419 host.s_addr = refid;
420 (void) sprintf(buff, "%s (%s)",
421 inet_ntoa(host),
422 addrtoname(AF_INET, &host));
423 break;
426 return (buff);
430 * Here we have to worry about the high order bit being signed
432 double
433 s_fixed_to_double(struct s_fixedpt *t)
435 double a;
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);
447 return (a);
451 * Consistent with RFC-3339, ISO 8601.
453 char *
454 iso_date_time(time_t input_time)
456 struct tm *time_parts;
457 static char tbuf[sizeof ("yyyy-mm-dd hh:mm:ss")];
459 time_parts = localtime(&input_time);
460 (void) strftime(tbuf, sizeof (tbuf), "%Y-%m-%d %H:%M:%S", time_parts);
461 return (tbuf);
465 * The base of NTP timestamps is 1900-01-01 00:00:00.00000
467 char *
468 show_time(struct l_fixedpt pkt_time)
470 struct l_fixedpt net_time;
471 unsigned long fracsec;
472 static char buff[32];
474 if (pkt_time.int_part == 0) {
475 buff[0] = '\0';
476 return (buff);
479 net_time.int_part = ntohl(pkt_time.int_part) - JAN_1970;
480 net_time.fraction = ntohl(pkt_time.fraction);
482 fracsec = net_time.fraction / 42949; /* fract / (2**32/10**6) */
484 (void) strlcpy(buff, iso_date_time(net_time.int_part), sizeof (buff));
485 (void) snprintf(buff, sizeof (buff), "%s.%05lu", buff, fracsec);
487 return (buff);
490 char *
491 show_operation(int op)
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");