117680Spst/* 217680Spst * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996 317680Spst * The Regents of the University of California. All rights reserved. 417680Spst * 517680Spst * Redistribution and use in source and binary forms, with or without 617680Spst * modification, are permitted provided that: (1) source code distributions 717680Spst * retain the above copyright notice and this paragraph in its entirety, (2) 817680Spst * distributions including binary code include the above copyright notice and 917680Spst * this paragraph in its entirety in the documentation or other materials 1017680Spst * provided with the distribution, and (3) all advertising materials mentioning 1117680Spst * features or use of this software display the following acknowledgement: 1217680Spst * ``This product includes software developed by the University of California, 1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1417680Spst * the University nor the names of its contributors may be used to endorse 1517680Spst * or promote products derived from this software without specific prior 1617680Spst * written permission. 1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2056896Sfenner * 2156896Sfenner * $FreeBSD$ 2217680Spst */ 2317680Spst 2417680Spst#ifndef lint 25127675Sbmsstatic const char rcsid[] _U_ = 26190207Srpaulo "@(#) $Header: /tcpdump/master/tcpdump/print-icmp.c,v 1.87 2007-09-13 17:42:31 guy Exp $ (LBL)"; 2717680Spst#endif 2817680Spst 2956896Sfenner#ifdef HAVE_CONFIG_H 3056896Sfenner#include "config.h" 3156896Sfenner#endif 3256896Sfenner 33127675Sbms#include <tcpdump-stdinc.h> 3417680Spst 3517680Spst#include <stdio.h> 3617680Spst#include <string.h> 3717680Spst 3817680Spst#include "interface.h" 3917680Spst#include "addrtoname.h" 4017680Spst#include "extract.h" /* must come after interface.h */ 4117680Spst 4275118Sfenner#include "ip.h" 4375118Sfenner#include "udp.h" 44127675Sbms#include "ipproto.h" 45146778Ssam#include "mpls.h" 4675118Sfenner 4775118Sfenner/* 4875118Sfenner * Interface Control Message Protocol Definitions. 4975118Sfenner * Per RFC 792, September 1981. 5075118Sfenner */ 5175118Sfenner 5275118Sfenner/* 5375118Sfenner * Structure of an icmp header. 5475118Sfenner */ 5575118Sfennerstruct icmp { 5675118Sfenner u_int8_t icmp_type; /* type of message, see below */ 5775118Sfenner u_int8_t icmp_code; /* type sub code */ 5875118Sfenner u_int16_t icmp_cksum; /* ones complement cksum of struct */ 5975118Sfenner union { 6075118Sfenner u_int8_t ih_pptr; /* ICMP_PARAMPROB */ 6175118Sfenner struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ 6275118Sfenner struct ih_idseq { 6375118Sfenner u_int16_t icd_id; 6475118Sfenner u_int16_t icd_seq; 6575118Sfenner } ih_idseq; 6675118Sfenner u_int32_t ih_void; 6775118Sfenner } icmp_hun; 6875118Sfenner#define icmp_pptr icmp_hun.ih_pptr 6975118Sfenner#define icmp_gwaddr icmp_hun.ih_gwaddr 7075118Sfenner#define icmp_id icmp_hun.ih_idseq.icd_id 7175118Sfenner#define icmp_seq icmp_hun.ih_idseq.icd_seq 7275118Sfenner#define icmp_void icmp_hun.ih_void 7375118Sfenner union { 7475118Sfenner struct id_ts { 7575118Sfenner u_int32_t its_otime; 7675118Sfenner u_int32_t its_rtime; 7775118Sfenner u_int32_t its_ttime; 7875118Sfenner } id_ts; 7975118Sfenner struct id_ip { 8075118Sfenner struct ip idi_ip; 8175118Sfenner /* options and then 64 bits of data */ 8275118Sfenner } id_ip; 8375118Sfenner u_int32_t id_mask; 8475118Sfenner u_int8_t id_data[1]; 8575118Sfenner } icmp_dun; 8675118Sfenner#define icmp_otime icmp_dun.id_ts.its_otime 8775118Sfenner#define icmp_rtime icmp_dun.id_ts.its_rtime 8875118Sfenner#define icmp_ttime icmp_dun.id_ts.its_ttime 8975118Sfenner#define icmp_ip icmp_dun.id_ip.idi_ip 9075118Sfenner#define icmp_mask icmp_dun.id_mask 9175118Sfenner#define icmp_data icmp_dun.id_data 9275118Sfenner}; 9375118Sfenner 94146778Ssam#define ICMP_MPLS_EXT_EXTRACT_VERSION(x) (((x)&0xf0)>>4) 95146778Ssam#define ICMP_MPLS_EXT_VERSION 2 96146778Ssam 9775118Sfenner/* 9875118Sfenner * Lower bounds on packet lengths for various types. 9975118Sfenner * For the error advice packets must first insure that the 10075118Sfenner * packet is large enought to contain the returned ip header. 10175118Sfenner * Only then can we do the check to see if 64 bits of packet 10275118Sfenner * data have been returned, since we need to check the returned 10375118Sfenner * ip header length. 10475118Sfenner */ 10575118Sfenner#define ICMP_MINLEN 8 /* abs minimum */ 106172686Smlaier#define ICMP_EXTD_MINLEN (156 - sizeof (struct ip)) /* draft-bonica-internet-icmp-08 */ 10775118Sfenner#define ICMP_TSLEN (8 + 3 * sizeof (u_int32_t)) /* timestamp */ 10875118Sfenner#define ICMP_MASKLEN 12 /* address mask */ 10975118Sfenner#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ 11075118Sfenner#define ICMP_ADVLEN(p) (8 + (IP_HL(&(p)->icmp_ip) << 2) + 8) 11175118Sfenner /* N.B.: must separately check that ip_hl >= 5 */ 11275118Sfenner 11375118Sfenner/* 11475118Sfenner * Definition of type and code field values. 11575118Sfenner */ 11675118Sfenner#define ICMP_ECHOREPLY 0 /* echo reply */ 11775118Sfenner#define ICMP_UNREACH 3 /* dest unreachable, codes: */ 11875118Sfenner#define ICMP_UNREACH_NET 0 /* bad net */ 11975118Sfenner#define ICMP_UNREACH_HOST 1 /* bad host */ 12075118Sfenner#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ 12175118Sfenner#define ICMP_UNREACH_PORT 3 /* bad port */ 12275118Sfenner#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ 12375118Sfenner#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ 12475118Sfenner#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ 12575118Sfenner#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ 12675118Sfenner#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ 12775118Sfenner#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ 12875118Sfenner#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ 12975118Sfenner#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ 13075118Sfenner#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ 13175118Sfenner#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ 13275118Sfenner#define ICMP_REDIRECT 5 /* shorter route, codes: */ 13375118Sfenner#define ICMP_REDIRECT_NET 0 /* for network */ 13475118Sfenner#define ICMP_REDIRECT_HOST 1 /* for host */ 13575118Sfenner#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ 13675118Sfenner#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ 13775118Sfenner#define ICMP_ECHO 8 /* echo service */ 13875118Sfenner#define ICMP_ROUTERADVERT 9 /* router advertisement */ 13975118Sfenner#define ICMP_ROUTERSOLICIT 10 /* router solicitation */ 14075118Sfenner#define ICMP_TIMXCEED 11 /* time exceeded, code: */ 14175118Sfenner#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ 14275118Sfenner#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ 14375118Sfenner#define ICMP_PARAMPROB 12 /* ip header bad */ 14475118Sfenner#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ 14575118Sfenner#define ICMP_TSTAMP 13 /* timestamp request */ 14675118Sfenner#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ 14775118Sfenner#define ICMP_IREQ 15 /* information request */ 14875118Sfenner#define ICMP_IREQREPLY 16 /* information reply */ 14975118Sfenner#define ICMP_MASKREQ 17 /* address mask request */ 15075118Sfenner#define ICMP_MASKREPLY 18 /* address mask reply */ 15175118Sfenner 15275118Sfenner#define ICMP_MAXTYPE 18 15375118Sfenner 15475118Sfenner#define ICMP_INFOTYPE(type) \ 15575118Sfenner ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ 15675118Sfenner (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ 15775118Sfenner (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ 15875118Sfenner (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ 15975118Sfenner (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) 160146778Ssam#define ICMP_MPLS_EXT_TYPE(type) \ 161172686Smlaier ((type) == ICMP_UNREACH || \ 162172686Smlaier (type) == ICMP_TIMXCEED || \ 163172686Smlaier (type) == ICMP_PARAMPROB) 16417680Spst/* rfc1700 */ 16517680Spst#ifndef ICMP_UNREACH_NET_UNKNOWN 16617680Spst#define ICMP_UNREACH_NET_UNKNOWN 6 /* destination net unknown */ 16717680Spst#endif 16817680Spst#ifndef ICMP_UNREACH_HOST_UNKNOWN 16917680Spst#define ICMP_UNREACH_HOST_UNKNOWN 7 /* destination host unknown */ 17017680Spst#endif 17117680Spst#ifndef ICMP_UNREACH_ISOLATED 17217680Spst#define ICMP_UNREACH_ISOLATED 8 /* source host isolated */ 17317680Spst#endif 17417680Spst#ifndef ICMP_UNREACH_NET_PROHIB 17517680Spst#define ICMP_UNREACH_NET_PROHIB 9 /* admin prohibited net */ 17617680Spst#endif 17717680Spst#ifndef ICMP_UNREACH_HOST_PROHIB 17817680Spst#define ICMP_UNREACH_HOST_PROHIB 10 /* admin prohibited host */ 17917680Spst#endif 18017680Spst#ifndef ICMP_UNREACH_TOSNET 18117680Spst#define ICMP_UNREACH_TOSNET 11 /* tos prohibited net */ 18217680Spst#endif 18317680Spst#ifndef ICMP_UNREACH_TOSHOST 18417680Spst#define ICMP_UNREACH_TOSHOST 12 /* tos prohibited host */ 18517680Spst#endif 18617680Spst 18717680Spst/* rfc1716 */ 18817680Spst#ifndef ICMP_UNREACH_FILTER_PROHIB 18917680Spst#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */ 19017680Spst#endif 19117680Spst#ifndef ICMP_UNREACH_HOST_PRECEDENCE 19217680Spst#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host precedence violation */ 19317680Spst#endif 19417680Spst#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF 19517680Spst#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* precedence cutoff */ 19617680Spst#endif 19717680Spst 19817680Spst/* Most of the icmp types */ 19917680Spststatic struct tok icmp2str[] = { 20017680Spst { ICMP_ECHOREPLY, "echo reply" }, 20117680Spst { ICMP_SOURCEQUENCH, "source quench" }, 20217680Spst { ICMP_ECHO, "echo request" }, 20317680Spst { ICMP_ROUTERSOLICIT, "router solicitation" }, 20417680Spst { ICMP_TSTAMP, "time stamp request" }, 20517680Spst { ICMP_TSTAMPREPLY, "time stamp reply" }, 20617680Spst { ICMP_IREQ, "information request" }, 20717680Spst { ICMP_IREQREPLY, "information reply" }, 20817680Spst { ICMP_MASKREQ, "address mask request" }, 20917680Spst { 0, NULL } 21017680Spst}; 21117680Spst 21217680Spst/* Formats for most of the ICMP_UNREACH codes */ 21317680Spststatic struct tok unreach2str[] = { 21417680Spst { ICMP_UNREACH_NET, "net %s unreachable" }, 21517680Spst { ICMP_UNREACH_HOST, "host %s unreachable" }, 21617680Spst { ICMP_UNREACH_SRCFAIL, 21717680Spst "%s unreachable - source route failed" }, 21817680Spst { ICMP_UNREACH_NET_UNKNOWN, "net %s unreachable - unknown" }, 21917680Spst { ICMP_UNREACH_HOST_UNKNOWN, "host %s unreachable - unknown" }, 22017680Spst { ICMP_UNREACH_ISOLATED, 22117680Spst "%s unreachable - source host isolated" }, 22217680Spst { ICMP_UNREACH_NET_PROHIB, 22317680Spst "net %s unreachable - admin prohibited" }, 22417680Spst { ICMP_UNREACH_HOST_PROHIB, 22517680Spst "host %s unreachable - admin prohibited" }, 22617680Spst { ICMP_UNREACH_TOSNET, 22717680Spst "net %s unreachable - tos prohibited" }, 22817680Spst { ICMP_UNREACH_TOSHOST, 22917680Spst "host %s unreachable - tos prohibited" }, 23017680Spst { ICMP_UNREACH_FILTER_PROHIB, 23117680Spst "host %s unreachable - admin prohibited filter" }, 23217680Spst { ICMP_UNREACH_HOST_PRECEDENCE, 23317680Spst "host %s unreachable - host precedence violation" }, 23417680Spst { ICMP_UNREACH_PRECEDENCE_CUTOFF, 23517680Spst "host %s unreachable - precedence cutoff" }, 23617680Spst { 0, NULL } 23717680Spst}; 23817680Spst 23917680Spst/* Formats for the ICMP_REDIRECT codes */ 24017680Spststatic struct tok type2str[] = { 24117680Spst { ICMP_REDIRECT_NET, "redirect %s to net %s" }, 24217680Spst { ICMP_REDIRECT_HOST, "redirect %s to host %s" }, 24317680Spst { ICMP_REDIRECT_TOSNET, "redirect-tos %s to net %s" }, 24498527Sfenner { ICMP_REDIRECT_TOSHOST, "redirect-tos %s to host %s" }, 24517680Spst { 0, NULL } 24617680Spst}; 24717680Spst 24817680Spst/* rfc1191 */ 24917680Spststruct mtu_discovery { 25075118Sfenner u_int16_t unused; 25175118Sfenner u_int16_t nexthopmtu; 25217680Spst}; 25317680Spst 25417680Spst/* rfc1256 */ 25517680Spststruct ih_rdiscovery { 25675118Sfenner u_int8_t ird_addrnum; 25775118Sfenner u_int8_t ird_addrsiz; 25875118Sfenner u_int16_t ird_lifetime; 25917680Spst}; 26017680Spst 26117680Spststruct id_rdiscovery { 26217680Spst u_int32_t ird_addr; 26317680Spst u_int32_t ird_pref; 26417680Spst}; 26517680Spst 266172686Smlaier/* 267172686Smlaier * draft-bonica-internet-icmp-08 268172686Smlaier * 269172686Smlaier * The Destination Unreachable, Time Exceeded 270172686Smlaier * and Parameter Problem messages are slighly changed as per 271172686Smlaier * the above draft. A new Length field gets added to give 272172686Smlaier * the caller an idea about the length of the piggypacked 273172686Smlaier * IP packet before the MPLS extension header starts. 274172686Smlaier * 275172686Smlaier * The Length field represents length of the padded "original datagram" 276172686Smlaier * field measured in 32-bit words. 277172686Smlaier * 278172686Smlaier * 0 1 2 3 279172686Smlaier * 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 280172686Smlaier * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 281172686Smlaier * | Type | Code | Checksum | 282172686Smlaier * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 283172686Smlaier * | unused | Length | unused | 284172686Smlaier * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 285172686Smlaier * | Internet Header + leading octets of original datagram | 286172686Smlaier * | | 287172686Smlaier * | // | 288172686Smlaier * | | 289172686Smlaier * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 290172686Smlaier */ 291172686Smlaier 292172686Smlaierstruct icmp_ext_t { 293172686Smlaier u_int8_t icmp_type; 294172686Smlaier u_int8_t icmp_code; 295172686Smlaier u_int8_t icmp_checksum[2]; 296172686Smlaier u_int8_t icmp_reserved; 297172686Smlaier u_int8_t icmp_length; 298172686Smlaier u_int8_t icmp_reserved2[2]; 299172686Smlaier u_int8_t icmp_ext_legacy_header[128]; /* extension header starts 128 bytes after ICMP header */ 300172686Smlaier u_int8_t icmp_ext_version_res[2]; 301172686Smlaier u_int8_t icmp_ext_checksum[2]; 302172686Smlaier u_int8_t icmp_ext_data[1]; 303172686Smlaier}; 304172686Smlaier 305146778Ssamstruct icmp_mpls_ext_object_header_t { 306146778Ssam u_int8_t length[2]; 307146778Ssam u_int8_t class_num; 308146778Ssam u_int8_t ctype; 309146778Ssam}; 310146778Ssam 311146778Ssamstatic const struct tok icmp_mpls_ext_obj_values[] = { 312146778Ssam { 1, "MPLS Stack Entry" }, 313146778Ssam { 2, "Extended Payload" }, 314146778Ssam { 0, NULL} 315146778Ssam}; 316146778Ssam 317147904Ssam/* prototypes */ 318147904Ssamconst char *icmp_tstamp_print(u_int); 319147904Ssam 320147904Ssam/* print the milliseconds since midnight UTC */ 321147904Ssamconst char * 322147904Ssamicmp_tstamp_print(u_int tstamp) { 323147904Ssam u_int msec,sec,min,hrs; 324147904Ssam 325147904Ssam static char buf[64]; 326147904Ssam 327147904Ssam msec = tstamp % 1000; 328147904Ssam sec = tstamp / 1000; 329147904Ssam min = sec / 60; sec -= min * 60; 330147904Ssam hrs = min / 60; min -= hrs * 60; 331147904Ssam snprintf(buf, sizeof(buf), "%02u:%02u:%02u.%03u",hrs,min,sec,msec); 332147904Ssam return buf; 333147904Ssam} 334147904Ssam 33517680Spstvoid 336127675Sbmsicmp_print(const u_char *bp, u_int plen, const u_char *bp2, int fragmented) 33717680Spst{ 33898527Sfenner char *cp; 33998527Sfenner const struct icmp *dp; 340172686Smlaier const struct icmp_ext_t *ext_dp; 34198527Sfenner const struct ip *ip; 34298527Sfenner const char *str, *fmt; 34398527Sfenner const struct ip *oip; 34498527Sfenner const struct udphdr *ouh; 345146778Ssam const u_int8_t *obj_tptr; 346146778Ssam u_int32_t raw_label; 347172686Smlaier const u_char *snapend_save; 348146778Ssam const struct icmp_mpls_ext_object_header_t *icmp_mpls_ext_object_header; 349146778Ssam u_int hlen, dport, mtu, obj_tlen, obj_class_num, obj_ctype; 35066644Skris char buf[MAXHOSTNAMELEN + 100]; 351235530Sdelphij struct cksum_vec vec[1]; 35217680Spst 35317680Spst dp = (struct icmp *)bp; 354172686Smlaier ext_dp = (struct icmp_ext_t *)bp; 35517680Spst ip = (struct ip *)bp2; 35617680Spst str = buf; 35717680Spst 35817680Spst TCHECK(dp->icmp_code); 35917680Spst switch (dp->icmp_type) { 36017680Spst 361127675Sbms case ICMP_ECHO: 362127675Sbms case ICMP_ECHOREPLY: 363127675Sbms TCHECK(dp->icmp_seq); 364147904Ssam (void)snprintf(buf, sizeof(buf), "echo %s, id %u, seq %u", 365147904Ssam dp->icmp_type == ICMP_ECHO ? 366147904Ssam "request" : "reply", 367147904Ssam EXTRACT_16BITS(&dp->icmp_id), 368147904Ssam EXTRACT_16BITS(&dp->icmp_seq)); 369127675Sbms break; 370127675Sbms 37117680Spst case ICMP_UNREACH: 37217680Spst TCHECK(dp->icmp_ip.ip_dst); 37317680Spst switch (dp->icmp_code) { 37417680Spst 37517680Spst case ICMP_UNREACH_PROTOCOL: 37617680Spst TCHECK(dp->icmp_ip.ip_p); 37775118Sfenner (void)snprintf(buf, sizeof(buf), 37875118Sfenner "%s protocol %d unreachable", 37975118Sfenner ipaddr_string(&dp->icmp_ip.ip_dst), 38075118Sfenner dp->icmp_ip.ip_p); 38117680Spst break; 38217680Spst 38317680Spst case ICMP_UNREACH_PORT: 38417680Spst TCHECK(dp->icmp_ip.ip_p); 38517680Spst oip = &dp->icmp_ip; 38675118Sfenner hlen = IP_HL(oip) * 4; 38717680Spst ouh = (struct udphdr *)(((u_char *)oip) + hlen); 388127675Sbms TCHECK(ouh->uh_dport); 389127675Sbms dport = EXTRACT_16BITS(&ouh->uh_dport); 39017680Spst switch (oip->ip_p) { 39117680Spst 39217680Spst case IPPROTO_TCP: 39366644Skris (void)snprintf(buf, sizeof(buf), 39417680Spst "%s tcp port %s unreachable", 39517680Spst ipaddr_string(&oip->ip_dst), 39617680Spst tcpport_string(dport)); 39717680Spst break; 39817680Spst 39917680Spst case IPPROTO_UDP: 40066644Skris (void)snprintf(buf, sizeof(buf), 40117680Spst "%s udp port %s unreachable", 40217680Spst ipaddr_string(&oip->ip_dst), 40317680Spst udpport_string(dport)); 40417680Spst break; 40517680Spst 40617680Spst default: 40766644Skris (void)snprintf(buf, sizeof(buf), 40817680Spst "%s protocol %d port %d unreachable", 40917680Spst ipaddr_string(&oip->ip_dst), 41017680Spst oip->ip_p, dport); 41117680Spst break; 41217680Spst } 41317680Spst break; 41417680Spst 41517680Spst case ICMP_UNREACH_NEEDFRAG: 41675118Sfenner { 41717680Spst register const struct mtu_discovery *mp; 418190207Srpaulo mp = (struct mtu_discovery *)(u_char *)&dp->icmp_void; 41998527Sfenner mtu = EXTRACT_16BITS(&mp->nexthopmtu); 42098527Sfenner if (mtu) { 42175118Sfenner (void)snprintf(buf, sizeof(buf), 42275118Sfenner "%s unreachable - need to frag (mtu %d)", 42375118Sfenner ipaddr_string(&dp->icmp_ip.ip_dst), mtu); 42498527Sfenner } else { 42575118Sfenner (void)snprintf(buf, sizeof(buf), 42675118Sfenner "%s unreachable - need to frag", 42775118Sfenner ipaddr_string(&dp->icmp_ip.ip_dst)); 42817680Spst } 42975118Sfenner } 43017680Spst break; 43117680Spst 43217680Spst default: 43317680Spst fmt = tok2str(unreach2str, "#%d %%s unreachable", 43417680Spst dp->icmp_code); 43566644Skris (void)snprintf(buf, sizeof(buf), fmt, 43617680Spst ipaddr_string(&dp->icmp_ip.ip_dst)); 43717680Spst break; 43817680Spst } 43917680Spst break; 44017680Spst 44117680Spst case ICMP_REDIRECT: 44217680Spst TCHECK(dp->icmp_ip.ip_dst); 44317680Spst fmt = tok2str(type2str, "redirect-#%d %%s to net %%s", 44417680Spst dp->icmp_code); 44566644Skris (void)snprintf(buf, sizeof(buf), fmt, 44617680Spst ipaddr_string(&dp->icmp_ip.ip_dst), 44717680Spst ipaddr_string(&dp->icmp_gwaddr)); 44817680Spst break; 44917680Spst 45017680Spst case ICMP_ROUTERADVERT: 45175118Sfenner { 45217680Spst register const struct ih_rdiscovery *ihp; 45317680Spst register const struct id_rdiscovery *idp; 45417680Spst u_int lifetime, num, size; 45517680Spst 45675118Sfenner (void)snprintf(buf, sizeof(buf), "router advertisement"); 45717680Spst cp = buf + strlen(buf); 45817680Spst 45917680Spst ihp = (struct ih_rdiscovery *)&dp->icmp_void; 46017680Spst TCHECK(*ihp); 46175118Sfenner (void)strncpy(cp, " lifetime ", sizeof(buf) - (cp - buf)); 46217680Spst cp = buf + strlen(buf); 46317680Spst lifetime = EXTRACT_16BITS(&ihp->ird_lifetime); 46475118Sfenner if (lifetime < 60) { 46575118Sfenner (void)snprintf(cp, sizeof(buf) - (cp - buf), "%u", 46675118Sfenner lifetime); 46775118Sfenner } else if (lifetime < 60 * 60) { 46875118Sfenner (void)snprintf(cp, sizeof(buf) - (cp - buf), "%u:%02u", 46917680Spst lifetime / 60, lifetime % 60); 47075118Sfenner } else { 47175118Sfenner (void)snprintf(cp, sizeof(buf) - (cp - buf), 47275118Sfenner "%u:%02u:%02u", 47317680Spst lifetime / 3600, 47417680Spst (lifetime % 3600) / 60, 47517680Spst lifetime % 60); 47675118Sfenner } 47717680Spst cp = buf + strlen(buf); 47817680Spst 47917680Spst num = ihp->ird_addrnum; 48075118Sfenner (void)snprintf(cp, sizeof(buf) - (cp - buf), " %d:", num); 48117680Spst cp = buf + strlen(buf); 48217680Spst 48317680Spst size = ihp->ird_addrsiz; 48417680Spst if (size != 2) { 48575118Sfenner (void)snprintf(cp, sizeof(buf) - (cp - buf), 48675118Sfenner " [size %d]", size); 48717680Spst break; 48817680Spst } 48917680Spst idp = (struct id_rdiscovery *)&dp->icmp_data; 49017680Spst while (num-- > 0) { 49117680Spst TCHECK(*idp); 49275118Sfenner (void)snprintf(cp, sizeof(buf) - (cp - buf), " {%s %u}", 49317680Spst ipaddr_string(&idp->ird_addr), 49417680Spst EXTRACT_32BITS(&idp->ird_pref)); 49517680Spst cp = buf + strlen(buf); 49675118Sfenner ++idp; 49717680Spst } 49875118Sfenner } 49917680Spst break; 50017680Spst 50117680Spst case ICMP_TIMXCEED: 50217680Spst TCHECK(dp->icmp_ip.ip_dst); 50317680Spst switch (dp->icmp_code) { 50417680Spst 50517680Spst case ICMP_TIMXCEED_INTRANS: 50617680Spst str = "time exceeded in-transit"; 50717680Spst break; 50817680Spst 50917680Spst case ICMP_TIMXCEED_REASS: 51017680Spst str = "ip reassembly time exceeded"; 51117680Spst break; 51217680Spst 51317680Spst default: 51475118Sfenner (void)snprintf(buf, sizeof(buf), "time exceeded-#%d", 51575118Sfenner dp->icmp_code); 51617680Spst break; 51717680Spst } 51817680Spst break; 51917680Spst 52017680Spst case ICMP_PARAMPROB: 52117680Spst if (dp->icmp_code) 52275118Sfenner (void)snprintf(buf, sizeof(buf), 52375118Sfenner "parameter problem - code %d", dp->icmp_code); 52417680Spst else { 52517680Spst TCHECK(dp->icmp_pptr); 52675118Sfenner (void)snprintf(buf, sizeof(buf), 52775118Sfenner "parameter problem - octet %d", dp->icmp_pptr); 52817680Spst } 52917680Spst break; 53017680Spst 53117680Spst case ICMP_MASKREPLY: 53217680Spst TCHECK(dp->icmp_mask); 53366644Skris (void)snprintf(buf, sizeof(buf), "address mask is 0x%08x", 534127675Sbms EXTRACT_32BITS(&dp->icmp_mask)); 53517680Spst break; 53617680Spst 53775118Sfenner case ICMP_TSTAMP: 53875118Sfenner TCHECK(dp->icmp_seq); 53975118Sfenner (void)snprintf(buf, sizeof(buf), 54075118Sfenner "time stamp query id %u seq %u", 541127675Sbms EXTRACT_16BITS(&dp->icmp_id), 542127675Sbms EXTRACT_16BITS(&dp->icmp_seq)); 54375118Sfenner break; 54475118Sfenner 54575118Sfenner case ICMP_TSTAMPREPLY: 54675118Sfenner TCHECK(dp->icmp_ttime); 54775118Sfenner (void)snprintf(buf, sizeof(buf), 548147904Ssam "time stamp reply id %u seq %u: org %s", 549147904Ssam EXTRACT_16BITS(&dp->icmp_id), 550147904Ssam EXTRACT_16BITS(&dp->icmp_seq), 551147904Ssam icmp_tstamp_print(EXTRACT_32BITS(&dp->icmp_otime))); 55275118Sfenner 553147904Ssam (void)snprintf(buf+strlen(buf),sizeof(buf)-strlen(buf),", recv %s", 554147904Ssam icmp_tstamp_print(EXTRACT_32BITS(&dp->icmp_rtime))); 555147904Ssam (void)snprintf(buf+strlen(buf),sizeof(buf)-strlen(buf),", xmit %s", 556147904Ssam icmp_tstamp_print(EXTRACT_32BITS(&dp->icmp_ttime))); 557147904Ssam break; 558147904Ssam 55917680Spst default: 56017680Spst str = tok2str(icmp2str, "type-#%d", dp->icmp_type); 56117680Spst break; 56217680Spst } 563146778Ssam (void)printf("ICMP %s, length %u", str, plen); 564127675Sbms if (vflag && !fragmented) { /* don't attempt checksumming if this is a frag */ 565127675Sbms u_int16_t sum, icmp_sum; 566235530Sdelphij struct cksum_vec vec[1]; 56756896Sfenner if (TTEST2(*bp, plen)) { 568235530Sdelphij vec[0].ptr = (const u_int8_t *)(void *)dp; 569235530Sdelphij vec[0].len = plen; 570235530Sdelphij sum = in_cksum(vec, 1); 571127675Sbms if (sum != 0) { 572127675Sbms icmp_sum = EXTRACT_16BITS(&dp->icmp_cksum); 573127675Sbms (void)printf(" (wrong icmp cksum %x (->%x)!)", 574127675Sbms icmp_sum, 575127675Sbms in_cksum_shouldbe(icmp_sum, sum)); 576127675Sbms } 57756896Sfenner } 57856896Sfenner } 579172686Smlaier 580172686Smlaier /* 581172686Smlaier * print the remnants of the IP packet. 582172686Smlaier * save the snaplength as this may get overidden in the IP printer. 583172686Smlaier */ 584146778Ssam if (vflag >= 1 && !ICMP_INFOTYPE(dp->icmp_type)) { 585127675Sbms bp += 8; 586146778Ssam (void)printf("\n\t"); 587127675Sbms ip = (struct ip *)bp; 588127675Sbms snaplen = snapend - bp; 589172686Smlaier snapend_save = snapend; 590146778Ssam ip_print(gndo, bp, EXTRACT_16BITS(&ip->ip_len)); 591172686Smlaier snapend = snapend_save; 592127675Sbms } 593146778Ssam 594172686Smlaier /* 595172686Smlaier * Attempt to decode the MPLS extensions only for some ICMP types. 596172686Smlaier */ 597146778Ssam if (vflag >= 1 && plen > ICMP_EXTD_MINLEN && ICMP_MPLS_EXT_TYPE(dp->icmp_type)) { 598146778Ssam 599172686Smlaier TCHECK(*ext_dp); 600172686Smlaier 601172686Smlaier /* 602172686Smlaier * Check first if the mpls extension header shows a non-zero length. 603172686Smlaier * If the length field is not set then silently verify the checksum 604172686Smlaier * to check if an extension header is present. This is expedient, 605172686Smlaier * however not all implementations set the length field proper. 606172686Smlaier */ 607235530Sdelphij if (!ext_dp->icmp_length) { 608235530Sdelphij vec[0].ptr = (const u_int8_t *)(void *)&ext_dp->icmp_ext_version_res; 609235530Sdelphij vec[0].len = plen - ICMP_EXTD_MINLEN; 610235530Sdelphij if (in_cksum(vec, 1)) { 611235530Sdelphij return; 612235530Sdelphij } 613172686Smlaier } 614172686Smlaier 615172686Smlaier printf("\n\tMPLS extension v%u", 616172686Smlaier ICMP_MPLS_EXT_EXTRACT_VERSION(*(ext_dp->icmp_ext_version_res))); 617146778Ssam 618146778Ssam /* 619146778Ssam * Sanity checking of the header. 620146778Ssam */ 621172686Smlaier if (ICMP_MPLS_EXT_EXTRACT_VERSION(*(ext_dp->icmp_ext_version_res)) != 622172686Smlaier ICMP_MPLS_EXT_VERSION) { 623146778Ssam printf(" packet not supported"); 624146778Ssam return; 625146778Ssam } 626146778Ssam 627146778Ssam hlen = plen - ICMP_EXTD_MINLEN; 628235530Sdelphij vec[0].ptr = (const u_int8_t *)(void *)&ext_dp->icmp_ext_version_res; 629235530Sdelphij vec[0].len = hlen; 630172686Smlaier printf(", checksum 0x%04x (%scorrect), length %u", 631172686Smlaier EXTRACT_16BITS(ext_dp->icmp_ext_checksum), 632235530Sdelphij in_cksum(vec, 1) ? "in" : "", 633146778Ssam hlen); 634146778Ssam 635146778Ssam hlen -= 4; /* subtract common header size */ 636172686Smlaier obj_tptr = (u_int8_t *)ext_dp->icmp_ext_data; 637146778Ssam 638146778Ssam while (hlen > sizeof(struct icmp_mpls_ext_object_header_t)) { 639146778Ssam 640146778Ssam icmp_mpls_ext_object_header = (struct icmp_mpls_ext_object_header_t *)obj_tptr; 641146778Ssam TCHECK(*icmp_mpls_ext_object_header); 642146778Ssam obj_tlen = EXTRACT_16BITS(icmp_mpls_ext_object_header->length); 643146778Ssam obj_class_num = icmp_mpls_ext_object_header->class_num; 644146778Ssam obj_ctype = icmp_mpls_ext_object_header->ctype; 645146778Ssam obj_tptr += sizeof(struct icmp_mpls_ext_object_header_t); 646146778Ssam 647146778Ssam printf("\n\t %s Object (%u), Class-Type: %u, length %u", 648146778Ssam tok2str(icmp_mpls_ext_obj_values,"unknown",obj_class_num), 649146778Ssam obj_class_num, 650146778Ssam obj_ctype, 651146778Ssam obj_tlen); 652146778Ssam 653146778Ssam hlen-=sizeof(struct icmp_mpls_ext_object_header_t); /* length field includes tlv header */ 654172686Smlaier 655172686Smlaier /* infinite loop protection */ 656172686Smlaier if ((obj_class_num == 0) || 657172686Smlaier (obj_tlen < sizeof(struct icmp_mpls_ext_object_header_t))) { 658172686Smlaier return; 659172686Smlaier } 660146778Ssam obj_tlen-=sizeof(struct icmp_mpls_ext_object_header_t); 661146778Ssam 662146778Ssam switch (obj_class_num) { 663146778Ssam case 1: 664146778Ssam switch(obj_ctype) { 665146778Ssam case 1: 666146778Ssam TCHECK2(*obj_tptr, 4); 667146778Ssam raw_label = EXTRACT_32BITS(obj_tptr); 668146778Ssam printf("\n\t label %u, exp %u", MPLS_LABEL(raw_label), MPLS_EXP(raw_label)); 669146778Ssam if (MPLS_STACK(raw_label)) 670146778Ssam printf(", [S]"); 671146778Ssam printf(", ttl %u", MPLS_TTL(raw_label)); 672146778Ssam break; 673146778Ssam default: 674146778Ssam print_unknown_data(obj_tptr, "\n\t ", obj_tlen); 675146778Ssam } 676146778Ssam break; 677146778Ssam 678146778Ssam /* 679146778Ssam * FIXME those are the defined objects that lack a decoder 680146778Ssam * you are welcome to contribute code ;-) 681146778Ssam */ 682146778Ssam case 2: 683146778Ssam default: 684146778Ssam print_unknown_data(obj_tptr, "\n\t ", obj_tlen); 685146778Ssam break; 686146778Ssam } 687146778Ssam if (hlen < obj_tlen) 688146778Ssam break; 689146778Ssam hlen -= obj_tlen; 690146778Ssam obj_tptr += obj_tlen; 691146778Ssam } 692146778Ssam } 693146778Ssam 69417680Spst return; 69517680Spsttrunc: 69617680Spst fputs("[|icmp]", stdout); 69717680Spst} 698