]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/print-icmp.c
zfs: merge openzfs/zfs@009d3288d
[FreeBSD/FreeBSD.git] / contrib / tcpdump / print-icmp.c
1 /*
2  * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996
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
22 /* \summary: Internet Control Message Protocol (ICMP) printer */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include "netdissect-stdinc.h"
29
30 #include <stdio.h>
31 #include <string.h>
32
33 #include "netdissect.h"
34 #include "addrtoname.h"
35 #include "extract.h"
36
37 #include "ip.h"
38 #include "udp.h"
39 #include "ipproto.h"
40 #include "mpls.h"
41
42 /*
43  * Interface Control Message Protocol Definitions.
44  * Per RFC 792, September 1981.
45  */
46
47 /*
48  * Structure of an icmp header.
49  */
50 struct icmp {
51         nd_uint8_t  icmp_type;          /* type of message, see below */
52         nd_uint8_t  icmp_code;          /* type sub code */
53         nd_uint16_t icmp_cksum;         /* ones complement cksum of struct */
54         union {
55                 nd_uint8_t ih_pptr;     /* ICMP_PARAMPROB */
56                 nd_ipv4 ih_gwaddr;      /* ICMP_REDIRECT */
57                 struct ih_idseq {
58                         nd_uint16_t icd_id;
59                         nd_uint16_t icd_seq;
60                 } ih_idseq;
61                 nd_uint32_t ih_void;
62         } icmp_hun;
63 #define icmp_pptr       icmp_hun.ih_pptr
64 #define icmp_gwaddr     icmp_hun.ih_gwaddr
65 #define icmp_id         icmp_hun.ih_idseq.icd_id
66 #define icmp_seq        icmp_hun.ih_idseq.icd_seq
67 #define icmp_void       icmp_hun.ih_void
68         union {
69                 struct id_ts {
70                         nd_uint32_t its_otime;
71                         nd_uint32_t its_rtime;
72                         nd_uint32_t its_ttime;
73                 } id_ts;
74                 struct id_ip  {
75                         struct ip idi_ip;
76                         /* options and then 64 bits of data */
77                 } id_ip;
78                 nd_uint32_t id_mask;
79                 nd_byte id_data[1];
80         } icmp_dun;
81 #define icmp_otime      icmp_dun.id_ts.its_otime
82 #define icmp_rtime      icmp_dun.id_ts.its_rtime
83 #define icmp_ttime      icmp_dun.id_ts.its_ttime
84 #define icmp_ip         icmp_dun.id_ip.idi_ip
85 #define icmp_mask       icmp_dun.id_mask
86 #define icmp_data       icmp_dun.id_data
87 };
88
89 /*
90  * Lower bounds on packet lengths for various types.
91  * For the error advice packets must first insure that the
92  * packet is large enough to contain the returned ip header.
93  * Only then can we do the check to see if 64 bits of packet
94  * data have been returned, since we need to check the returned
95  * ip header length.
96  */
97 #define ICMP_MINLEN     8                               /* abs minimum */
98 #define ICMP_EXTD_MINLEN (156 - sizeof (struct ip))     /* draft-bonica-internet-icmp-08 */
99 #define ICMP_TSLEN      (8 + 3 * sizeof (uint32_t))     /* timestamp */
100 #define ICMP_MASKLEN    12                              /* address mask */
101 #define ICMP_ADVLENMIN  (8 + sizeof (struct ip) + 8)    /* min */
102 #define ICMP_ADVLEN(p)  (8 + (IP_HL(&(p)->icmp_ip) << 2) + 8)
103         /* N.B.: must separately check that ip_hl >= 5 */
104
105 /*
106  * Definition of type and code field values.
107  */
108 #define ICMP_ECHOREPLY          0               /* echo reply */
109 #define ICMP_UNREACH            3               /* dest unreachable, codes: */
110 #define         ICMP_UNREACH_NET        0               /* bad net */
111 #define         ICMP_UNREACH_HOST       1               /* bad host */
112 #define         ICMP_UNREACH_PROTOCOL   2               /* bad protocol */
113 #define         ICMP_UNREACH_PORT       3               /* bad port */
114 #define         ICMP_UNREACH_NEEDFRAG   4               /* IP_DF caused drop */
115 #define         ICMP_UNREACH_SRCFAIL    5               /* src route failed */
116 #define         ICMP_UNREACH_NET_UNKNOWN 6              /* unknown net */
117 #define         ICMP_UNREACH_HOST_UNKNOWN 7             /* unknown host */
118 #define         ICMP_UNREACH_ISOLATED   8               /* src host isolated */
119 #define         ICMP_UNREACH_NET_PROHIB 9               /* prohibited access */
120 #define         ICMP_UNREACH_HOST_PROHIB 10             /* ditto */
121 #define         ICMP_UNREACH_TOSNET     11              /* bad tos for net */
122 #define         ICMP_UNREACH_TOSHOST    12              /* bad tos for host */
123 #define ICMP_SOURCEQUENCH       4               /* packet lost, slow down */
124 #define ICMP_REDIRECT           5               /* shorter route, codes: */
125 #define         ICMP_REDIRECT_NET       0               /* for network */
126 #define         ICMP_REDIRECT_HOST      1               /* for host */
127 #define         ICMP_REDIRECT_TOSNET    2               /* for tos and net */
128 #define         ICMP_REDIRECT_TOSHOST   3               /* for tos and host */
129 #define ICMP_ECHO               8               /* echo service */
130 #define ICMP_ROUTERADVERT       9               /* router advertisement */
131 #define ICMP_ROUTERSOLICIT      10              /* router solicitation */
132 #define ICMP_TIMXCEED           11              /* time exceeded, code: */
133 #define         ICMP_TIMXCEED_INTRANS   0               /* ttl==0 in transit */
134 #define         ICMP_TIMXCEED_REASS     1               /* ttl==0 in reass */
135 #define ICMP_PARAMPROB          12              /* ip header bad */
136 #define         ICMP_PARAMPROB_OPTABSENT 1              /* req. opt. absent */
137 #define ICMP_TSTAMP             13              /* timestamp request */
138 #define ICMP_TSTAMPREPLY        14              /* timestamp reply */
139 #define ICMP_IREQ               15              /* information request */
140 #define ICMP_IREQREPLY          16              /* information reply */
141 #define ICMP_MASKREQ            17              /* address mask request */
142 #define ICMP_MASKREPLY          18              /* address mask reply */
143
144 #define ICMP_MAXTYPE            18
145
146 #define ICMP_ERRTYPE(type) \
147         ((type) == ICMP_UNREACH || (type) == ICMP_SOURCEQUENCH || \
148         (type) == ICMP_REDIRECT || (type) == ICMP_TIMXCEED || \
149         (type) == ICMP_PARAMPROB)
150 #define ICMP_MULTIPART_EXT_TYPE(type) \
151         ((type) == ICMP_UNREACH || \
152          (type) == ICMP_TIMXCEED || \
153          (type) == ICMP_PARAMPROB)
154 /* rfc1700 */
155 #ifndef ICMP_UNREACH_NET_UNKNOWN
156 #define ICMP_UNREACH_NET_UNKNOWN        6       /* destination net unknown */
157 #endif
158 #ifndef ICMP_UNREACH_HOST_UNKNOWN
159 #define ICMP_UNREACH_HOST_UNKNOWN       7       /* destination host unknown */
160 #endif
161 #ifndef ICMP_UNREACH_ISOLATED
162 #define ICMP_UNREACH_ISOLATED           8       /* source host isolated */
163 #endif
164 #ifndef ICMP_UNREACH_NET_PROHIB
165 #define ICMP_UNREACH_NET_PROHIB         9       /* admin prohibited net */
166 #endif
167 #ifndef ICMP_UNREACH_HOST_PROHIB
168 #define ICMP_UNREACH_HOST_PROHIB        10      /* admin prohibited host */
169 #endif
170 #ifndef ICMP_UNREACH_TOSNET
171 #define ICMP_UNREACH_TOSNET             11      /* tos prohibited net */
172 #endif
173 #ifndef ICMP_UNREACH_TOSHOST
174 #define ICMP_UNREACH_TOSHOST            12      /* tos prohibited host */
175 #endif
176
177 /* rfc1716 */
178 #ifndef ICMP_UNREACH_FILTER_PROHIB
179 #define ICMP_UNREACH_FILTER_PROHIB      13      /* admin prohibited filter */
180 #endif
181 #ifndef ICMP_UNREACH_HOST_PRECEDENCE
182 #define ICMP_UNREACH_HOST_PRECEDENCE    14      /* host precedence violation */
183 #endif
184 #ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
185 #define ICMP_UNREACH_PRECEDENCE_CUTOFF  15      /* precedence cutoff */
186 #endif
187
188 /* Most of the icmp types */
189 static const struct tok icmp2str[] = {
190         { ICMP_ECHOREPLY,               "echo reply" },
191         { ICMP_SOURCEQUENCH,            "source quench" },
192         { ICMP_ECHO,                    "echo request" },
193         { ICMP_ROUTERSOLICIT,           "router solicitation" },
194         { ICMP_TSTAMP,                  "time stamp request" },
195         { ICMP_TSTAMPREPLY,             "time stamp reply" },
196         { ICMP_IREQ,                    "information request" },
197         { ICMP_IREQREPLY,               "information reply" },
198         { ICMP_MASKREQ,                 "address mask request" },
199         { 0,                            NULL }
200 };
201
202 /* rfc1191 */
203 struct mtu_discovery {
204         nd_uint16_t unused;
205         nd_uint16_t nexthopmtu;
206 };
207
208 /* rfc1256 */
209 struct ih_rdiscovery {
210         nd_uint8_t ird_addrnum;
211         nd_uint8_t ird_addrsiz;
212         nd_uint16_t ird_lifetime;
213 };
214
215 struct id_rdiscovery {
216         nd_uint32_t ird_addr;
217         nd_uint32_t ird_pref;
218 };
219
220 /*
221  * RFC 4884 - Extended ICMP to Support Multi-Part Messages
222  *
223  * This is a general extension mechanism, based on the mechanism
224  * in draft-bonica-icmp-mpls-02 ICMP Extensions for MultiProtocol
225  * Label Switching.
226  *
227  * The Destination Unreachable, Time Exceeded
228  * and Parameter Problem messages are slightly changed as per
229  * the above RFC. A new Length field gets added to give
230  * the caller an idea about the length of the piggybacked
231  * IP packet before the extension header starts.
232  *
233  * The Length field represents length of the padded "original datagram"
234  * field  measured in 32-bit words.
235  *
236  * 0                   1                   2                   3
237  * 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
238  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
239  * |     Type      |     Code      |          Checksum             |
240  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
241  * |     unused    |    Length     |          unused               |
242  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
243  * |      Internet Header + leading octets of original datagram    |
244  * |                                                               |
245  * |                           //                                  |
246  * |                                                               |
247  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
248  */
249
250 struct icmp_ext_t {
251     nd_uint8_t  icmp_type;
252     nd_uint8_t  icmp_code;
253     nd_uint16_t icmp_checksum;
254     nd_byte     icmp_reserved;
255     nd_uint8_t  icmp_length;
256     nd_byte     icmp_reserved2[2];
257     nd_byte     icmp_ext_legacy_header[128]; /* extension header starts 128 bytes after ICMP header */
258     nd_byte     icmp_ext_version_res[2];
259     nd_uint16_t icmp_ext_checksum;
260     nd_byte     icmp_ext_data[1];
261 };
262
263 /*
264  * Extract version from the first octet of icmp_ext_version_res.
265  */
266 #define ICMP_EXT_EXTRACT_VERSION(x) (((x)&0xf0)>>4)
267
268 /*
269  * Current version.
270  */
271 #define ICMP_EXT_VERSION 2
272
273 /*
274  * Extension object class numbers.
275  *
276  * Class 1 dates back to draft-bonica-icmp-mpls-02.
277  */
278
279 /* rfc4950  */
280 #define MPLS_STACK_ENTRY_OBJECT_CLASS            1
281
282 struct icmp_multipart_ext_object_header_t {
283     nd_uint16_t length;
284     nd_uint8_t  class_num;
285     nd_uint8_t  ctype;
286 };
287
288 static const struct tok icmp_multipart_ext_obj_values[] = {
289     { 1, "MPLS Stack Entry" },
290     { 2, "Interface Identification" },
291     { 0, NULL}
292 };
293
294 /* prototypes */
295 const char *icmp_tstamp_print(u_int);
296
297 /* print the milliseconds since midnight UTC */
298 const char *
299 icmp_tstamp_print(u_int tstamp)
300 {
301     u_int msec,sec,min,hrs;
302
303     static char buf[64];
304
305     msec = tstamp % 1000;
306     sec = tstamp / 1000;
307     min = sec / 60; sec -= min * 60;
308     hrs = min / 60; min -= hrs * 60;
309     snprintf(buf, sizeof(buf), "%02u:%02u:%02u.%03u",hrs,min,sec,msec);
310     return buf;
311 }
312
313 void
314 icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, const u_char *bp2,
315            int fragmented)
316 {
317         char *cp;
318         const struct icmp *dp;
319         uint8_t icmp_type, icmp_code;
320         const struct icmp_ext_t *ext_dp;
321         const struct ip *ip;
322         const char *str;
323         const struct ip *oip;
324         uint8_t ip_proto;
325         const struct udphdr *ouh;
326         const uint8_t *obj_tptr;
327         uint32_t raw_label;
328         const struct icmp_multipart_ext_object_header_t *icmp_multipart_ext_object_header;
329         u_int hlen, mtu, obj_tlen, obj_class_num, obj_ctype;
330         uint16_t dport;
331         char buf[MAXHOSTNAMELEN + 100];
332         struct cksum_vec vec[1];
333
334         ndo->ndo_protocol = "icmp";
335         dp = (const struct icmp *)bp;
336         ext_dp = (const struct icmp_ext_t *)bp;
337         ip = (const struct ip *)bp2;
338         str = buf;
339
340         icmp_type = GET_U_1(dp->icmp_type);
341         icmp_code = GET_U_1(dp->icmp_code);
342         switch (icmp_type) {
343
344         case ICMP_ECHO:
345         case ICMP_ECHOREPLY:
346                 (void)snprintf(buf, sizeof(buf), "echo %s, id %u, seq %u",
347                                icmp_type == ICMP_ECHO ?
348                                "request" : "reply",
349                                GET_BE_U_2(dp->icmp_id),
350                                GET_BE_U_2(dp->icmp_seq));
351                 break;
352
353         case ICMP_UNREACH:
354                 switch (icmp_code) {
355
356                 case ICMP_UNREACH_NET:
357                         (void)snprintf(buf, sizeof(buf),
358                             "net %s unreachable",
359                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
360                         break;
361
362                 case ICMP_UNREACH_HOST:
363                         (void)snprintf(buf, sizeof(buf),
364                             "host %s unreachable",
365                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
366                         break;
367
368                 case ICMP_UNREACH_PROTOCOL:
369                         (void)snprintf(buf, sizeof(buf),
370                             "%s protocol %u unreachable",
371                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst),
372                             GET_U_1(dp->icmp_ip.ip_p));
373                         break;
374
375                 case ICMP_UNREACH_PORT:
376                         ND_TCHECK_1(dp->icmp_ip.ip_p);
377                         oip = &dp->icmp_ip;
378                         hlen = IP_HL(oip) * 4;
379                         ouh = (const struct udphdr *)(((const u_char *)oip) + hlen);
380                         dport = GET_BE_U_2(ouh->uh_dport);
381                         ip_proto = GET_U_1(oip->ip_p);
382                         switch (ip_proto) {
383
384                         case IPPROTO_TCP:
385                                 (void)snprintf(buf, sizeof(buf),
386                                         "%s tcp port %s unreachable",
387                                         GET_IPADDR_STRING(oip->ip_dst),
388                                         tcpport_string(ndo, dport));
389                                 break;
390
391                         case IPPROTO_UDP:
392                                 (void)snprintf(buf, sizeof(buf),
393                                         "%s udp port %s unreachable",
394                                         GET_IPADDR_STRING(oip->ip_dst),
395                                         udpport_string(ndo, dport));
396                                 break;
397
398                         default:
399                                 (void)snprintf(buf, sizeof(buf),
400                                         "%s protocol %u port %u unreachable",
401                                         GET_IPADDR_STRING(oip->ip_dst),
402                                         ip_proto, dport);
403                                 break;
404                         }
405                         break;
406
407                 case ICMP_UNREACH_NEEDFRAG:
408                     {
409                         const struct mtu_discovery *mp;
410                         mp = (const struct mtu_discovery *)(const u_char *)&dp->icmp_void;
411                         mtu = GET_BE_U_2(mp->nexthopmtu);
412                         if (mtu) {
413                                 (void)snprintf(buf, sizeof(buf),
414                                     "%s unreachable - need to frag (mtu %u)",
415                                     GET_IPADDR_STRING(dp->icmp_ip.ip_dst), mtu);
416                         } else {
417                                 (void)snprintf(buf, sizeof(buf),
418                                     "%s unreachable - need to frag",
419                                     GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
420                         }
421                     }
422                         break;
423
424                 case ICMP_UNREACH_SRCFAIL:
425                         (void)snprintf(buf, sizeof(buf),
426                             "%s unreachable - source route failed",
427                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
428                         break;
429
430                 case ICMP_UNREACH_NET_UNKNOWN:
431                         (void)snprintf(buf, sizeof(buf),
432                             "net %s unreachable - unknown",
433                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
434                         break;
435
436                 case ICMP_UNREACH_HOST_UNKNOWN:
437                         (void)snprintf(buf, sizeof(buf),
438                             "host %s unreachable - unknown",
439                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
440                         break;
441
442                 case ICMP_UNREACH_ISOLATED:
443                         (void)snprintf(buf, sizeof(buf),
444                             "%s unreachable - source host isolated",
445                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
446                         break;
447
448                 case ICMP_UNREACH_NET_PROHIB:
449                         (void)snprintf(buf, sizeof(buf),
450                             "net %s unreachable - admin prohibited",
451                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
452                         break;
453
454                 case ICMP_UNREACH_HOST_PROHIB:
455                         (void)snprintf(buf, sizeof(buf),
456                             "host %s unreachable - admin prohibited",
457                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
458                         break;
459
460                 case ICMP_UNREACH_TOSNET:
461                         (void)snprintf(buf, sizeof(buf),
462                             "net %s unreachable - tos prohibited",
463                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
464                         break;
465
466                 case ICMP_UNREACH_TOSHOST:
467                         (void)snprintf(buf, sizeof(buf),
468                             "host %s unreachable - tos prohibited",
469                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
470                         break;
471
472                 case ICMP_UNREACH_FILTER_PROHIB:
473                         (void)snprintf(buf, sizeof(buf),
474                             "host %s unreachable - admin prohibited filter",
475                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
476                         break;
477
478                 case ICMP_UNREACH_HOST_PRECEDENCE:
479                         (void)snprintf(buf, sizeof(buf),
480                             "host %s unreachable - host precedence violation",
481                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
482                         break;
483
484                 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
485                         (void)snprintf(buf, sizeof(buf),
486                             "host %s unreachable - precedence cutoff",
487                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst));
488                         break;
489
490                 default:
491                         (void)snprintf(buf, sizeof(buf),
492                             "%s unreachable - #%u",
493                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst),
494                             icmp_code);
495                         break;
496                 }
497                 break;
498
499         case ICMP_REDIRECT:
500                 switch (icmp_code) {
501
502                 case ICMP_REDIRECT_NET:
503                         (void)snprintf(buf, sizeof(buf),
504                             "redirect %s to net %s",
505                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst),
506                             GET_IPADDR_STRING(dp->icmp_gwaddr));
507                         break;
508
509                 case ICMP_REDIRECT_HOST:
510                         (void)snprintf(buf, sizeof(buf),
511                             "redirect %s to host %s",
512                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst),
513                             GET_IPADDR_STRING(dp->icmp_gwaddr));
514                         break;
515
516                 case ICMP_REDIRECT_TOSNET:
517                         (void)snprintf(buf, sizeof(buf),
518                             "redirect-tos %s to net %s",
519                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst),
520                             GET_IPADDR_STRING(dp->icmp_gwaddr));
521                         break;
522
523                 case ICMP_REDIRECT_TOSHOST:
524                         (void)snprintf(buf, sizeof(buf),
525                             "redirect-tos %s to host %s",
526                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst),
527                             GET_IPADDR_STRING(dp->icmp_gwaddr));
528                         break;
529
530                 default:
531                         (void)snprintf(buf, sizeof(buf),
532                             "redirect-#%u %s to %s", icmp_code,
533                             GET_IPADDR_STRING(dp->icmp_ip.ip_dst),
534                             GET_IPADDR_STRING(dp->icmp_gwaddr));
535                         break;
536                 }
537                 break;
538
539         case ICMP_ROUTERADVERT:
540             {
541                 const struct ih_rdiscovery *ihp;
542                 const struct id_rdiscovery *idp;
543                 u_int lifetime, num, size;
544
545                 (void)snprintf(buf, sizeof(buf), "router advertisement");
546                 cp = buf + strlen(buf);
547
548                 ihp = (const struct ih_rdiscovery *)&dp->icmp_void;
549                 ND_TCHECK_SIZE(ihp);
550                 (void)strncpy(cp, " lifetime ", sizeof(buf) - (cp - buf));
551                 cp = buf + strlen(buf);
552                 lifetime = GET_BE_U_2(ihp->ird_lifetime);
553                 if (lifetime < 60) {
554                         (void)snprintf(cp, sizeof(buf) - (cp - buf), "%u",
555                             lifetime);
556                 } else if (lifetime < 60 * 60) {
557                         (void)snprintf(cp, sizeof(buf) - (cp - buf), "%u:%02u",
558                             lifetime / 60, lifetime % 60);
559                 } else {
560                         (void)snprintf(cp, sizeof(buf) - (cp - buf),
561                             "%u:%02u:%02u",
562                             lifetime / 3600,
563                             (lifetime % 3600) / 60,
564                             lifetime % 60);
565                 }
566                 cp = buf + strlen(buf);
567
568                 num = GET_U_1(ihp->ird_addrnum);
569                 (void)snprintf(cp, sizeof(buf) - (cp - buf), " %u:", num);
570                 cp = buf + strlen(buf);
571
572                 size = GET_U_1(ihp->ird_addrsiz);
573                 if (size != 2) {
574                         (void)snprintf(cp, sizeof(buf) - (cp - buf),
575                             " [size %u]", size);
576                         break;
577                 }
578                 idp = (const struct id_rdiscovery *)&dp->icmp_data;
579                 while (num > 0) {
580                         ND_TCHECK_SIZE(idp);
581                         (void)snprintf(cp, sizeof(buf) - (cp - buf), " {%s %u}",
582                             GET_IPADDR_STRING(idp->ird_addr),
583                             GET_BE_U_4(idp->ird_pref));
584                         cp = buf + strlen(buf);
585                         ++idp;
586                 num--;
587                 }
588             }
589                 break;
590
591         case ICMP_TIMXCEED:
592                 ND_TCHECK_4(dp->icmp_ip.ip_dst);
593                 switch (icmp_code) {
594
595                 case ICMP_TIMXCEED_INTRANS:
596                         str = "time exceeded in-transit";
597                         break;
598
599                 case ICMP_TIMXCEED_REASS:
600                         str = "ip reassembly time exceeded";
601                         break;
602
603                 default:
604                         (void)snprintf(buf, sizeof(buf), "time exceeded-#%u",
605                             icmp_code);
606                         break;
607                 }
608                 break;
609
610         case ICMP_PARAMPROB:
611                 if (icmp_code)
612                         (void)snprintf(buf, sizeof(buf),
613                             "parameter problem - code %u", icmp_code);
614                 else {
615                         (void)snprintf(buf, sizeof(buf),
616                             "parameter problem - octet %u",
617                             GET_U_1(dp->icmp_pptr));
618                 }
619                 break;
620
621         case ICMP_MASKREPLY:
622                 (void)snprintf(buf, sizeof(buf), "address mask is 0x%08x",
623                     GET_BE_U_4(dp->icmp_mask));
624                 break;
625
626         case ICMP_TSTAMP:
627                 (void)snprintf(buf, sizeof(buf),
628                     "time stamp query id %u seq %u",
629                     GET_BE_U_2(dp->icmp_id),
630                     GET_BE_U_2(dp->icmp_seq));
631                 break;
632
633         case ICMP_TSTAMPREPLY:
634                 ND_TCHECK_4(dp->icmp_ttime);
635                 (void)snprintf(buf, sizeof(buf),
636                     "time stamp reply id %u seq %u: org %s",
637                                GET_BE_U_2(dp->icmp_id),
638                                GET_BE_U_2(dp->icmp_seq),
639                                icmp_tstamp_print(GET_BE_U_4(dp->icmp_otime)));
640
641                 (void)snprintf(buf+strlen(buf),sizeof(buf)-strlen(buf),", recv %s",
642                          icmp_tstamp_print(GET_BE_U_4(dp->icmp_rtime)));
643                 (void)snprintf(buf+strlen(buf),sizeof(buf)-strlen(buf),", xmit %s",
644                          icmp_tstamp_print(GET_BE_U_4(dp->icmp_ttime)));
645                 break;
646
647         default:
648                 str = tok2str(icmp2str, "type-#%u", icmp_type);
649                 break;
650         }
651         ND_PRINT("ICMP %s, length %u", str, plen);
652         if (ndo->ndo_vflag && !fragmented) { /* don't attempt checksumming if this is a frag */
653                 if (ND_TTEST_LEN(bp, plen)) {
654                         uint16_t sum;
655
656                         vec[0].ptr = (const uint8_t *)(const void *)dp;
657                         vec[0].len = plen;
658                         sum = in_cksum(vec, 1);
659                         if (sum != 0) {
660                                 uint16_t icmp_sum = GET_BE_U_2(dp->icmp_cksum);
661                                 ND_PRINT(" (wrong icmp cksum %x (->%x)!)",
662                                              icmp_sum,
663                                              in_cksum_shouldbe(icmp_sum, sum));
664                         }
665                 }
666         }
667
668         /*
669          * print the remnants of the IP packet.
670          * save the snaplength as this may get overridden in the IP printer.
671          */
672         if (ndo->ndo_vflag >= 1 && ICMP_ERRTYPE(icmp_type)) {
673                 const u_char *snapend_save;
674
675                 bp += 8;
676                 ND_PRINT("\n\t");
677                 ip = (const struct ip *)bp;
678                 snapend_save = ndo->ndo_snapend;
679                 /*
680                  * Update the snapend because extensions (MPLS, ...) may be
681                  * present after the IP packet. In this case the current
682                  * (outer) packet's snapend is not what ip_print() needs to
683                  * decode an IP packet nested in the middle of an ICMP payload.
684                  *
685                  * This prevents that, in ip_print(), for the nested IP packet,
686                  * the remaining length < remaining caplen.
687                  */
688                 ndo->ndo_snapend = ND_MIN(bp + GET_BE_U_2(ip->ip_len),
689                                           ndo->ndo_snapend);
690                 ip_print(ndo, bp, GET_BE_U_2(ip->ip_len));
691                 ndo->ndo_snapend = snapend_save;
692         }
693
694         /* ndo_protocol reassignment after ip_print() call */
695         ndo->ndo_protocol = "icmp";
696
697         /*
698          * Attempt to decode multi-part message extensions (rfc4884) only for some ICMP types.
699          */
700         if (ndo->ndo_vflag >= 1 && plen > ICMP_EXTD_MINLEN && ICMP_MULTIPART_EXT_TYPE(icmp_type)) {
701
702             ND_TCHECK_SIZE(ext_dp);
703
704             /*
705              * Check first if the multi-part extension header shows a non-zero length.
706              * If the length field is not set then silently verify the checksum
707              * to check if an extension header is present. This is expedient,
708              * however not all implementations set the length field proper.
709              */
710             if (GET_U_1(ext_dp->icmp_length) == 0 &&
711                 ND_TTEST_LEN(ext_dp->icmp_ext_version_res, plen - ICMP_EXTD_MINLEN)) {
712                 vec[0].ptr = (const uint8_t *)(const void *)&ext_dp->icmp_ext_version_res;
713                 vec[0].len = plen - ICMP_EXTD_MINLEN;
714                 if (in_cksum(vec, 1)) {
715                     return;
716                 }
717             }
718
719             ND_PRINT("\n\tICMP Multi-Part extension v%u",
720                    ICMP_EXT_EXTRACT_VERSION(*(ext_dp->icmp_ext_version_res)));
721
722             /*
723              * Sanity checking of the header.
724              */
725             if (ICMP_EXT_EXTRACT_VERSION(*(ext_dp->icmp_ext_version_res)) !=
726                 ICMP_EXT_VERSION) {
727                 ND_PRINT(" packet not supported");
728                 return;
729             }
730
731             hlen = plen - ICMP_EXTD_MINLEN;
732             if (ND_TTEST_LEN(ext_dp->icmp_ext_version_res, hlen)) {
733                 vec[0].ptr = (const uint8_t *)(const void *)&ext_dp->icmp_ext_version_res;
734                 vec[0].len = hlen;
735                 ND_PRINT(", checksum 0x%04x (%scorrect), length %u",
736                        GET_BE_U_2(ext_dp->icmp_ext_checksum),
737                        in_cksum(vec, 1) ? "in" : "",
738                        hlen);
739             }
740
741             hlen -= 4; /* subtract common header size */
742             obj_tptr = (const uint8_t *)ext_dp->icmp_ext_data;
743
744             while (hlen > sizeof(struct icmp_multipart_ext_object_header_t)) {
745
746                 icmp_multipart_ext_object_header = (const struct icmp_multipart_ext_object_header_t *)obj_tptr;
747                 ND_TCHECK_SIZE(icmp_multipart_ext_object_header);
748                 obj_tlen = GET_BE_U_2(icmp_multipart_ext_object_header->length);
749                 obj_class_num = GET_U_1(icmp_multipart_ext_object_header->class_num);
750                 obj_ctype = GET_U_1(icmp_multipart_ext_object_header->ctype);
751                 obj_tptr += sizeof(struct icmp_multipart_ext_object_header_t);
752
753                 ND_PRINT("\n\t  %s Object (%u), Class-Type: %u, length %u",
754                        tok2str(icmp_multipart_ext_obj_values,"unknown",obj_class_num),
755                        obj_class_num,
756                        obj_ctype,
757                        obj_tlen);
758
759                 hlen-=sizeof(struct icmp_multipart_ext_object_header_t); /* length field includes tlv header */
760
761                 /* infinite loop protection */
762                 if ((obj_class_num == 0) ||
763                     (obj_tlen < sizeof(struct icmp_multipart_ext_object_header_t))) {
764                     return;
765                 }
766                 obj_tlen-=sizeof(struct icmp_multipart_ext_object_header_t);
767
768                 switch (obj_class_num) {
769                 case MPLS_STACK_ENTRY_OBJECT_CLASS:
770                     switch(obj_ctype) {
771                     case 1:
772                         raw_label = GET_BE_U_4(obj_tptr);
773                         ND_PRINT("\n\t    label %u, tc %u", MPLS_LABEL(raw_label), MPLS_TC(raw_label));
774                         if (MPLS_STACK(raw_label))
775                             ND_PRINT(", [S]");
776                         ND_PRINT(", ttl %u", MPLS_TTL(raw_label));
777                         break;
778                     default:
779                         print_unknown_data(ndo, obj_tptr, "\n\t    ", obj_tlen);
780                     }
781                     break;
782
783                 default:
784                     print_unknown_data(ndo, obj_tptr, "\n\t    ", obj_tlen);
785                     break;
786                 }
787                 if (hlen < obj_tlen)
788                     break;
789                 hlen -= obj_tlen;
790                 obj_tptr += obj_tlen;
791             }
792         }
793
794         return;
795 trunc:
796         nd_print_trunc(ndo);
797 }