1/*
2 * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 *	By Jeffrey Mogul/DECWRL
22 *	loosely based on print-bootp.c
23 */
24
25/* \summary: Network Time Protocol (NTP) printer */
26
27/*
28 * specification:
29 *
30 * RFC 1119 - NTPv2
31 * RFC 1305 - NTPv3
32 * RFC 5905 - NTPv4
33 */
34
35#ifdef HAVE_CONFIG_H
36#include <config.h>
37#endif
38
39#include "netdissect-stdinc.h"
40
41#include <time.h>
42
43#include "netdissect.h"
44#include "addrtoname.h"
45#include "extract.h"
46
47#include "ntp.h"
48
49/*
50 * Based on ntp.h from the U of MD implementation
51 *	This file is based on Version 2 of the NTP spec (RFC1119).
52 */
53
54/* rfc2030
55 *                      1                   2                   3
56 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
57 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58 * |LI | VN  |Mode |    Stratum    |     Poll      |   Precision   |
59 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60 * |                          Root Delay                           |
61 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62 * |                       Root Dispersion                         |
63 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
64 * |                     Reference Identifier                      |
65 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66 * |                                                               |
67 * |                   Reference Timestamp (64)                    |
68 * |                                                               |
69 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70 * |                                                               |
71 * |                   Originate Timestamp (64)                    |
72 * |                                                               |
73 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74 * |                                                               |
75 * |                    Receive Timestamp (64)                     |
76 * |                                                               |
77 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
78 * |                                                               |
79 * |                    Transmit Timestamp (64)                    |
80 * |                                                               |
81 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
82 * |                 Key Identifier (optional) (32)                |
83 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
84 * |                                                               |
85 * |                                                               |
86 * |                 Message Digest (optional) (128)               |
87 * |                                                               |
88 * |                                                               |
89 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90 */
91
92/* Length of the NTP data message with the mandatory fields ("the header")
93 * and without any optional fields (extension, Key Identifier,
94 * Message Digest).
95 */
96#define NTP_TIMEMSG_MINLEN 48U
97
98struct ntp_time_data {
99	nd_uint8_t status;		/* status of local clock and leap info */
100	nd_uint8_t stratum;		/* Stratum level */
101	nd_int8_t ppoll;		/* poll value */
102	nd_int8_t precision;
103	struct s_fixedpt root_delay;
104	struct s_fixedpt root_dispersion;
105	nd_uint32_t refid;
106	struct l_fixedpt ref_timestamp;
107	struct l_fixedpt org_timestamp;
108	struct l_fixedpt rec_timestamp;
109	struct l_fixedpt xmt_timestamp;
110	nd_uint32_t key_id;
111	nd_uint8_t  message_digest[20];
112};
113/*
114 *	Leap Second Codes (high order two bits)
115 */
116#define	NO_WARNING	0x00	/* no warning */
117#define	PLUS_SEC	0x40	/* add a second (61 seconds) */
118#define	MINUS_SEC	0x80	/* minus a second (59 seconds) */
119#define	ALARM		0xc0	/* alarm condition (clock unsynchronized) */
120
121/*
122 *	Clock Status Bits that Encode Version
123 */
124#define	NTPVERSION_1	0x08
125#define	VERSIONMASK	0x38
126#define	VERSIONSHIFT	3
127#define LEAPMASK	0xc0
128#define LEAPSHIFT	6
129#ifdef MODEMASK
130#undef MODEMASK					/* Solaris sucks */
131#endif
132#define	MODEMASK	0x07
133#define	MODESHIFT	0
134
135/*
136 *	Code values
137 */
138#define	MODE_UNSPEC	0	/* unspecified */
139#define	MODE_SYM_ACT	1	/* symmetric active */
140#define	MODE_SYM_PAS	2	/* symmetric passive */
141#define	MODE_CLIENT	3	/* client */
142#define	MODE_SERVER	4	/* server */
143#define	MODE_BROADCAST	5	/* broadcast */
144#define	MODE_CONTROL	6	/* control message */
145#define	MODE_RES2	7	/* reserved */
146
147/*
148 *	Stratum Definitions
149 */
150#define	UNSPECIFIED	0
151#define	PRIM_REF	1	/* radio clock */
152#define	INFO_QUERY	62	/* **** THIS implementation dependent **** */
153#define	INFO_REPLY	63	/* **** THIS implementation dependent **** */
154
155static void p_sfix(netdissect_options *ndo, const struct s_fixedpt *);
156static void p_ntp_delta(netdissect_options *, const struct l_fixedpt *, const struct l_fixedpt *);
157static void p_poll(netdissect_options *, const int);
158
159static const struct tok ntp_mode_values[] = {
160    { MODE_UNSPEC,    "unspecified" },
161    { MODE_SYM_ACT,   "symmetric active" },
162    { MODE_SYM_PAS,   "symmetric passive" },
163    { MODE_CLIENT,    "Client" },
164    { MODE_SERVER,    "Server" },
165    { MODE_BROADCAST, "Broadcast" },
166    { MODE_CONTROL,   "Control Message" },
167    { MODE_RES2,      "Reserved" },
168    { 0, NULL }
169};
170
171static const struct tok ntp_leapind_values[] = {
172    { NO_WARNING,     "" },
173    { PLUS_SEC,       "+1s" },
174    { MINUS_SEC,      "-1s" },
175    { ALARM,          "clock unsynchronized" },
176    { 0, NULL }
177};
178
179static const struct tok ntp_stratum_values[] = {
180	{ UNSPECIFIED,	"unspecified" },
181	{ PRIM_REF,	"primary reference" },
182	{ 0, NULL }
183};
184
185/* draft-ietf-ntp-mode-6-cmds-02
186 *  0                   1                   2                   3
187 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
188 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
189 * |LI |  VN |Mode |R|E|M| OpCode  |       Sequence Number         |
190 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
191 * |            Status             |       Association ID          |
192 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
193 * |            Offset             |            Count              |
194 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
195 * |                                                               |
196 * /                    Data (up to 468 bytes)                     /
197 * |                                                               |
198 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
199 * |                    Padding (optional)                         |
200 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
201 * |                                                               |
202 * /              Authenticator (optional, 96 bytes)               /
203 * |                                                               |
204 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
205 *
206 *               Figure 1: NTP Control Message Header
207 */
208
209/* Length of the NTP control message with the mandatory fields ("the header")
210 * and without any optional fields (Data, Padding, Authenticator).
211 */
212#define NTP_CTRLMSG_MINLEN 12U
213
214struct ntp_control_data {
215	nd_uint8_t	magic;		/* LI, VN, Mode */
216	nd_uint8_t	control;	/* R, E, M, OpCode */
217	nd_uint16_t	sequence;	/* Sequence Number */
218	nd_uint16_t	status;		/* Status */
219	nd_uint16_t	assoc;		/* Association ID */
220	nd_uint16_t	offset;		/* Offset */
221	nd_uint16_t	count;		/* Count */
222	nd_uint8_t	data[564];	/* Data, [Padding, [Authenticator]] */
223};
224
225/*
226 * Print NTP time requests and responses
227 */
228static void
229ntp_time_print(netdissect_options *ndo,
230	       const struct ntp_time_data *bp, u_int length)
231{
232	uint8_t stratum;
233
234	if (length < NTP_TIMEMSG_MINLEN)
235		goto invalid;
236
237	stratum = GET_U_1(bp->stratum);
238	ND_PRINT(", Stratum %u (%s)",
239		stratum,
240		tok2str(ntp_stratum_values, (stratum >=2 && stratum<=15) ? "secondary reference" : "reserved", stratum));
241
242	ND_PRINT(", poll %d", GET_S_1(bp->ppoll));
243	p_poll(ndo, GET_S_1(bp->ppoll));
244
245	ND_PRINT(", precision %d", GET_S_1(bp->precision));
246
247	ND_TCHECK_SIZE(&bp->root_delay);
248	ND_PRINT("\n\tRoot Delay: ");
249	p_sfix(ndo, &bp->root_delay);
250
251	ND_TCHECK_SIZE(&bp->root_dispersion);
252	ND_PRINT(", Root dispersion: ");
253	p_sfix(ndo, &bp->root_dispersion);
254
255	ND_TCHECK_4(bp->refid);
256	ND_PRINT(", Reference-ID: ");
257	/* Interpretation depends on stratum */
258	switch (stratum) {
259
260	case UNSPECIFIED:
261		ND_PRINT("(unspec)");
262		break;
263
264	case PRIM_REF:
265		if (nd_printn(ndo, (const u_char *)&(bp->refid), 4, ndo->ndo_snapend))
266			goto trunc;
267		break;
268
269	case INFO_QUERY:
270		ND_PRINT("%s INFO_QUERY", GET_IPADDR_STRING(bp->refid));
271		/* this doesn't have more content */
272		return;
273
274	case INFO_REPLY:
275		ND_PRINT("%s INFO_REPLY", GET_IPADDR_STRING(bp->refid));
276		/* this is too complex to be worth printing */
277		return;
278
279	default:
280		/* In NTPv4 (RFC 5905) refid is an IPv4 address or first 32 bits of
281		   MD5 sum of IPv6 address */
282		ND_PRINT("0x%08x", GET_BE_U_4(bp->refid));
283		break;
284	}
285
286	ND_TCHECK_SIZE(&bp->ref_timestamp);
287	ND_PRINT("\n\t  Reference Timestamp:  ");
288	p_ntp_time(ndo, &(bp->ref_timestamp));
289
290	ND_TCHECK_SIZE(&bp->org_timestamp);
291	ND_PRINT("\n\t  Originator Timestamp: ");
292	p_ntp_time(ndo, &(bp->org_timestamp));
293
294	ND_TCHECK_SIZE(&bp->rec_timestamp);
295	ND_PRINT("\n\t  Receive Timestamp:    ");
296	p_ntp_time(ndo, &(bp->rec_timestamp));
297
298	ND_TCHECK_SIZE(&bp->xmt_timestamp);
299	ND_PRINT("\n\t  Transmit Timestamp:   ");
300	p_ntp_time(ndo, &(bp->xmt_timestamp));
301
302	ND_PRINT("\n\t    Originator - Receive Timestamp:  ");
303	p_ntp_delta(ndo, &(bp->org_timestamp), &(bp->rec_timestamp));
304
305	ND_PRINT("\n\t    Originator - Transmit Timestamp: ");
306	p_ntp_delta(ndo, &(bp->org_timestamp), &(bp->xmt_timestamp));
307
308	/* FIXME: this code is not aware of any extension fields */
309	if (length == NTP_TIMEMSG_MINLEN + 4) {	/* Optional: key-id (crypto-NAK) */
310		ND_PRINT("\n\tKey id: %u", GET_BE_U_4(bp->key_id));
311	} else if (length == NTP_TIMEMSG_MINLEN + 4 + 16) {	/* Optional: key-id + 128-bit digest */
312		ND_PRINT("\n\tKey id: %u", GET_BE_U_4(bp->key_id));
313		ND_TCHECK_LEN(bp->message_digest, 16);
314		ND_PRINT("\n\tAuthentication: %08x%08x%08x%08x",
315			 GET_BE_U_4(bp->message_digest),
316			 GET_BE_U_4(bp->message_digest + 4),
317			 GET_BE_U_4(bp->message_digest + 8),
318			 GET_BE_U_4(bp->message_digest + 12));
319	} else if (length == NTP_TIMEMSG_MINLEN + 4 + 20) {	/* Optional: key-id + 160-bit digest */
320		ND_PRINT("\n\tKey id: %u", GET_BE_U_4(bp->key_id));
321		ND_TCHECK_LEN(bp->message_digest, 20);
322		ND_PRINT("\n\tAuthentication: %08x%08x%08x%08x%08x",
323			 GET_BE_U_4(bp->message_digest),
324			 GET_BE_U_4(bp->message_digest + 4),
325			 GET_BE_U_4(bp->message_digest + 8),
326			 GET_BE_U_4(bp->message_digest + 12),
327			 GET_BE_U_4(bp->message_digest + 16));
328	} else if (length > NTP_TIMEMSG_MINLEN) {
329		ND_PRINT("\n\t(%u more bytes after the header)", length - NTP_TIMEMSG_MINLEN);
330	}
331	return;
332
333invalid:
334	nd_print_invalid(ndo);
335	ND_TCHECK_LEN(bp, length);
336	return;
337
338trunc:
339	nd_print_trunc(ndo);
340}
341
342/*
343 * Print NTP control message requests and responses
344 */
345static void
346ntp_control_print(netdissect_options *ndo,
347		  const struct ntp_control_data *cd, u_int length)
348{
349	uint8_t control, R, E, M, opcode;
350	uint16_t sequence, status, assoc, offset, count;
351
352	if (length < NTP_CTRLMSG_MINLEN)
353		goto invalid;
354
355	control = GET_U_1(cd->control);
356	R = (control & 0x80) != 0;
357	E = (control & 0x40) != 0;
358	M = (control & 0x20) != 0;
359	opcode = control & 0x1f;
360	ND_PRINT(", %s, %s, %s, OpCode=%u\n",
361		  R ? "Response" : "Request", E ? "Error" : "OK",
362		  M ? "More" : "Last", opcode);
363
364	sequence = GET_BE_U_2(cd->sequence);
365	ND_PRINT("\tSequence=%hu", sequence);
366
367	status = GET_BE_U_2(cd->status);
368	ND_PRINT(", Status=%#hx", status);
369
370	assoc = GET_BE_U_2(cd->assoc);
371	ND_PRINT(", Assoc.=%hu", assoc);
372
373	offset = GET_BE_U_2(cd->offset);
374	ND_PRINT(", Offset=%hu", offset);
375
376	count = GET_BE_U_2(cd->count);
377	ND_PRINT(", Count=%hu", count);
378
379	if (NTP_CTRLMSG_MINLEN + count > length)
380		goto invalid;
381	if (count != 0) {
382		ND_TCHECK_LEN(cd->data, count);
383		ND_PRINT("\n\tTO-BE-DONE: data not interpreted");
384	}
385	return;
386
387invalid:
388	nd_print_invalid(ndo);
389	ND_TCHECK_LEN(cd, length);
390	return;
391
392trunc:
393	nd_print_trunc(ndo);
394}
395
396union ntpdata {
397	struct ntp_time_data	td;
398	struct ntp_control_data	cd;
399};
400
401/*
402 * Print NTP requests, handling the common VN, LI, and Mode
403 */
404void
405ntp_print(netdissect_options *ndo,
406	  const u_char *cp, u_int length)
407{
408	const union ntpdata *bp = (const union ntpdata *)cp;
409	u_int mode, version, leapind;
410	uint8_t status;
411
412	ndo->ndo_protocol = "ntp";
413	status = GET_U_1(bp->td.status);
414
415	version = (status & VERSIONMASK) >> VERSIONSHIFT;
416	ND_PRINT("NTPv%u", version);
417
418	mode = (status & MODEMASK) >> MODESHIFT;
419	if (!ndo->ndo_vflag) {
420		ND_PRINT(", %s, length %u",
421			 tok2str(ntp_mode_values, "Unknown mode", mode),
422			 length);
423		return;
424	}
425
426	ND_PRINT(", %s, length %u\n",
427		  tok2str(ntp_mode_values, "Unknown mode", mode), length);
428
429	/* leapind = (status & LEAPMASK) >> LEAPSHIFT; */
430	leapind = (status & LEAPMASK);
431	ND_PRINT("\tLeap indicator: %s (%u)",
432		 tok2str(ntp_leapind_values, "Unknown", leapind),
433		 leapind);
434
435	switch (mode) {
436
437	case MODE_UNSPEC:
438	case MODE_SYM_ACT:
439	case MODE_SYM_PAS:
440	case MODE_CLIENT:
441	case MODE_SERVER:
442	case MODE_BROADCAST:
443		ntp_time_print(ndo, &bp->td, length);
444		break;
445
446	case MODE_CONTROL:
447		ntp_control_print(ndo, &bp->cd, length);
448		break;
449
450	default:
451		break;			/* XXX: not implemented! */
452	}
453}
454
455static void
456p_sfix(netdissect_options *ndo,
457       const struct s_fixedpt *sfp)
458{
459	int i;
460	int f;
461	double ff;
462
463	i = GET_BE_U_2(sfp->int_part);
464	f = GET_BE_U_2(sfp->fraction);
465	ff = f / 65536.0;		/* shift radix point by 16 bits */
466	f = (int)(ff * 1000000.0);	/* Treat fraction as parts per million */
467	ND_PRINT("%d.%06d", i, f);
468}
469
470/* Prints time difference between *lfp and *olfp */
471static void
472p_ntp_delta(netdissect_options *ndo,
473	    const struct l_fixedpt *olfp,
474	    const struct l_fixedpt *lfp)
475{
476	uint32_t u, uf;
477	uint32_t ou, ouf;
478	uint32_t i;
479	uint32_t f;
480	double ff;
481	int signbit;
482
483	u = GET_BE_U_4(lfp->int_part);
484	ou = GET_BE_U_4(olfp->int_part);
485	uf = GET_BE_U_4(lfp->fraction);
486	ouf = GET_BE_U_4(olfp->fraction);
487	if (ou == 0 && ouf == 0) {
488		p_ntp_time(ndo, lfp);
489		return;
490	}
491
492	if (u > ou) {		/* new is definitely greater than old */
493		signbit = 0;
494		i = u - ou;
495		f = uf - ouf;
496		if (ouf > uf)	/* must borrow from high-order bits */
497			i -= 1;
498	} else if (u < ou) {	/* new is definitely less than old */
499		signbit = 1;
500		i = ou - u;
501		f = ouf - uf;
502		if (uf > ouf)	/* must borrow from the high-order bits */
503			i -= 1;
504	} else {		/* int_part is zero */
505		i = 0;
506		if (uf > ouf) {
507			signbit = 0;
508			f = uf - ouf;
509		} else {
510			signbit = 1;
511			f = ouf - uf;
512		}
513	}
514
515	ff = f;
516	if (ff < 0.0)		/* some compilers are buggy */
517		ff += FMAXINT;
518	ff = ff / FMAXINT;			/* shift radix point by 32 bits */
519	f = (uint32_t)(ff * 1000000000.0);	/* treat fraction as parts per billion */
520	ND_PRINT("%s%u.%09u", signbit ? "-" : "+", i, f);
521}
522
523/* Prints polling interval in log2 as seconds or fraction of second */
524static void
525p_poll(netdissect_options *ndo,
526       const int poll_interval)
527{
528	if (poll_interval <= -32 || poll_interval >= 32)
529		return;
530
531	if (poll_interval >= 0)
532		ND_PRINT(" (%us)", 1U << poll_interval);
533	else
534		ND_PRINT(" (1/%us)", 1U << -poll_interval);
535}
536
537