"Fossies" - the Fresh Open Source Software Archive

Member "tcpdump-4.99.1/./print-icmp.c" (7 Jun 2021, 25005 Bytes) of package /linux/misc/tcpdump-4.99.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "print-icmp.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.99.0_vs_4.99.1.

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