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