X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/fd1ef53ef60441ce79786346fdb84667333ba1f0..1ee09c1510704191a14df4eb914dba3d5dc9ab58:/print-icmp.c diff --git a/print-icmp.c b/print-icmp.c index fc17c263..862b095a 100644 --- a/print-icmp.c +++ b/print-icmp.c @@ -20,23 +20,18 @@ */ #ifndef lint -static const char rcsid[] = - "@(#) $Header: /tcpdump/master/tcpdump/print-icmp.c,v 1.67 2002-07-21 21:03:07 guy Exp $ (LBL)"; +static const char rcsid[] _U_ = + "@(#) $Header: /tcpdump/master/tcpdump/print-icmp.c,v 1.81 2005-04-06 21:32:40 mcr Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include -#include -#include - -#include +#include #include #include -#include /* for MAXHOSTNAMELEN on some platforms */ #include "interface.h" #include "addrtoname.h" @@ -44,6 +39,8 @@ static const char rcsid[] = #include "ip.h" #include "udp.h" +#include "ipproto.h" +#include "mpls.h" /* * Interface Control Message Protocol Definitions. @@ -89,6 +86,12 @@ struct icmp { struct ip idi_ip; /* options and then 64 bits of data */ } id_ip; + struct mpls_ext { + u_int8_t legacy_header[128]; /* extension header starts 128 bytes after ICMP header */ + u_int8_t version_res[2]; + u_int8_t checksum[2]; + u_int8_t data[1]; + } mpls_ext; u_int32_t id_mask; u_int8_t id_data[1]; } icmp_dun; @@ -98,8 +101,14 @@ struct icmp { #define icmp_ip icmp_dun.id_ip.idi_ip #define icmp_mask icmp_dun.id_mask #define icmp_data icmp_dun.id_data +#define icmp_mpls_ext_version icmp_dun.mpls_ext.version_res +#define icmp_mpls_ext_checksum icmp_dun.mpls_ext.checksum +#define icmp_mpls_ext_data icmp_dun.mpls_ext.data }; +#define ICMP_MPLS_EXT_EXTRACT_VERSION(x) (((x)&0xf0)>>4) +#define ICMP_MPLS_EXT_VERSION 2 + /* * Lower bounds on packet lengths for various types. * For the error advice packets must first insure that the @@ -109,6 +118,7 @@ struct icmp { * ip header length. */ #define ICMP_MINLEN 8 /* abs minimum */ +#define ICMP_EXTD_MINLEN (156 - sizeof (struct ip)) /* draft-bonica-icmp-mpls-02 */ #define ICMP_TSLEN (8 + 3 * sizeof (u_int32_t)) /* timestamp */ #define ICMP_MASKLEN 12 /* address mask */ #define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ @@ -162,6 +172,8 @@ struct icmp { (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) +#define ICMP_MPLS_EXT_TYPE(type) \ + ((type) == ICMP_UNREACH || (type) == ICMP_TIMXCEED) /* rfc1700 */ #ifndef ICMP_UNREACH_NET_UNKNOWN #define ICMP_UNREACH_NET_UNKNOWN 6 /* destination net unknown */ @@ -264,8 +276,21 @@ struct id_rdiscovery { u_int32_t ird_pref; }; +/* draft-bonica-icmp-mpls-02 */ +struct icmp_mpls_ext_object_header_t { + u_int8_t length[2]; + u_int8_t class_num; + u_int8_t ctype; +}; + +static const struct tok icmp_mpls_ext_obj_values[] = { + { 1, "MPLS Stack Entry" }, + { 2, "Extended Payload" }, + { 0, NULL} +}; + void -icmp_print(const u_char *bp, u_int plen, const u_char *bp2) +icmp_print(const u_char *bp, u_int plen, const u_char *bp2, int fragmented) { char *cp; const struct icmp *dp; @@ -273,7 +298,10 @@ icmp_print(const u_char *bp, u_int plen, const u_char *bp2) const char *str, *fmt; const struct ip *oip; const struct udphdr *ouh; - u_int hlen, dport, mtu; + const u_int8_t *obj_tptr; + u_int32_t raw_label; + const struct icmp_mpls_ext_object_header_t *icmp_mpls_ext_object_header; + u_int hlen, dport, mtu, obj_tlen, obj_class_num, obj_ctype; char buf[MAXHOSTNAMELEN + 100]; dp = (struct icmp *)bp; @@ -284,15 +312,12 @@ icmp_print(const u_char *bp, u_int plen, const u_char *bp2) switch (dp->icmp_type) { case ICMP_ECHO: - TCHECK(dp->icmp_seq); - (void)snprintf(buf, sizeof(buf), "echo request seq %u", - (unsigned)ntohs(dp->icmp_seq)); - break; - case ICMP_ECHOREPLY: TCHECK(dp->icmp_seq); - (void)snprintf(buf, sizeof(buf), "echo reply seq %u", - (unsigned)ntohs(dp->icmp_seq)); + (void)snprintf(buf, sizeof(buf), "echo %s seq %u", + dp->icmp_type == ICMP_ECHO ? + "request" : "reply", + EXTRACT_16BITS(&dp->icmp_seq)); break; case ICMP_UNREACH: @@ -312,7 +337,8 @@ icmp_print(const u_char *bp, u_int plen, const u_char *bp2) oip = &dp->icmp_ip; hlen = IP_HL(oip) * 4; ouh = (struct udphdr *)(((u_char *)oip) + hlen); - dport = ntohs(ouh->uh_dport); + TCHECK(ouh->uh_dport); + dport = EXTRACT_16BITS(&ouh->uh_dport); switch (oip->ip_p) { case IPPROTO_TCP: @@ -457,52 +483,127 @@ icmp_print(const u_char *bp, u_int plen, const u_char *bp2) case ICMP_MASKREPLY: TCHECK(dp->icmp_mask); (void)snprintf(buf, sizeof(buf), "address mask is 0x%08x", - (unsigned)ntohl(dp->icmp_mask)); + EXTRACT_32BITS(&dp->icmp_mask)); break; case ICMP_TSTAMP: TCHECK(dp->icmp_seq); (void)snprintf(buf, sizeof(buf), "time stamp query id %u seq %u", - (unsigned)ntohs(dp->icmp_id), - (unsigned)ntohs(dp->icmp_seq)); + EXTRACT_16BITS(&dp->icmp_id), + EXTRACT_16BITS(&dp->icmp_seq)); break; case ICMP_TSTAMPREPLY: TCHECK(dp->icmp_ttime); (void)snprintf(buf, sizeof(buf), - "time stamp reply id %u seq %u : org 0x%lx recv 0x%lx xmit 0x%lx", - (unsigned)ntohs(dp->icmp_id), - (unsigned)ntohs(dp->icmp_seq), - (unsigned long)ntohl(dp->icmp_otime), - (unsigned long)ntohl(dp->icmp_rtime), - (unsigned long)ntohl(dp->icmp_ttime)); + "time stamp reply id %u seq %u : org 0x%x recv 0x%x xmit 0x%x", + EXTRACT_16BITS(&dp->icmp_id), + EXTRACT_16BITS(&dp->icmp_seq), + EXTRACT_32BITS(&dp->icmp_otime), + EXTRACT_32BITS(&dp->icmp_rtime), + EXTRACT_32BITS(&dp->icmp_ttime)); break; default: str = tok2str(icmp2str, "type-#%d", dp->icmp_type); break; } - (void)printf("icmp %d: %s", plen, str); - if (vflag) { + (void)printf("ICMP %s, length %u", str, plen); + if (vflag && !fragmented) { /* don't attempt checksumming if this is a frag */ u_int16_t sum, icmp_sum; if (TTEST2(*bp, plen)) { sum = in_cksum((u_short*)dp, plen, 0); if (sum != 0) { - icmp_sum = ntohs(dp->icmp_cksum); + icmp_sum = EXTRACT_16BITS(&dp->icmp_cksum); (void)printf(" (wrong icmp cksum %x (->%x)!)", icmp_sum, in_cksum_shouldbe(icmp_sum, sum)); } } } - if (vflag > 1 && !ICMP_INFOTYPE(dp->icmp_type)) { + if (vflag >= 1 && !ICMP_INFOTYPE(dp->icmp_type)) { bp += 8; - (void)printf(" for "); + (void)printf("\n\t"); ip = (struct ip *)bp; snaplen = snapend - bp; - ip_print(bp, ntohs(ip->ip_len)); + ip_print(gndo, bp, EXTRACT_16BITS(&ip->ip_len)); } + + if (vflag >= 1 && plen > ICMP_EXTD_MINLEN && ICMP_MPLS_EXT_TYPE(dp->icmp_type)) { + + TCHECK(*(dp->icmp_mpls_ext_version)); + printf("\n\tMPLS extension v%u",ICMP_MPLS_EXT_EXTRACT_VERSION(*(dp->icmp_mpls_ext_version))); + + /* + * Sanity checking of the header. + */ + if (ICMP_MPLS_EXT_EXTRACT_VERSION(*(dp->icmp_mpls_ext_version)) != ICMP_MPLS_EXT_VERSION) { + printf(" packet not supported"); + return; + } + + hlen = plen - ICMP_EXTD_MINLEN; + TCHECK2(*(dp->icmp_mpls_ext_checksum), 2); + printf(", checksum 0x%04x (unverified), length %u", /* FIXME */ + EXTRACT_16BITS(dp->icmp_mpls_ext_checksum), + hlen); + + hlen -= 4; /* subtract common header size */ + obj_tptr = (u_int8_t *)dp->icmp_mpls_ext_data; + + while (hlen > sizeof(struct icmp_mpls_ext_object_header_t)) { + + icmp_mpls_ext_object_header = (struct icmp_mpls_ext_object_header_t *)obj_tptr; + TCHECK(*icmp_mpls_ext_object_header); + obj_tlen = EXTRACT_16BITS(icmp_mpls_ext_object_header->length); + obj_class_num = icmp_mpls_ext_object_header->class_num; + obj_ctype = icmp_mpls_ext_object_header->ctype; + obj_tptr += sizeof(struct icmp_mpls_ext_object_header_t); + + printf("\n\t %s Object (%u), Class-Type: %u, length %u", + tok2str(icmp_mpls_ext_obj_values,"unknown",obj_class_num), + obj_class_num, + obj_ctype, + obj_tlen); + + hlen-=sizeof(struct icmp_mpls_ext_object_header_t); /* length field includes tlv header */ + if (obj_tlen < sizeof(struct icmp_mpls_ext_object_header_t)) + break; + obj_tlen-=sizeof(struct icmp_mpls_ext_object_header_t); + + switch (obj_class_num) { + case 1: + switch(obj_ctype) { + case 1: + TCHECK2(*obj_tptr, 4); + raw_label = EXTRACT_32BITS(obj_tptr); + printf("\n\t label %u, exp %u", MPLS_LABEL(raw_label), MPLS_EXP(raw_label)); + if (MPLS_STACK(raw_label)) + printf(", [S]"); + printf(", ttl %u", MPLS_TTL(raw_label)); + break; + default: + print_unknown_data(obj_tptr, "\n\t ", obj_tlen); + } + break; + + /* + * FIXME those are the defined objects that lack a decoder + * you are welcome to contribute code ;-) + */ + case 2: + default: + print_unknown_data(obj_tptr, "\n\t ", obj_tlen); + break; + } + if (hlen < obj_tlen) + break; + hlen -= obj_tlen; + obj_tptr += obj_tlen; + } + } + return; trunc: fputs("[|icmp]", stdout);