Our tcpdump has the ability to detect bad TCP and UDP checksums with the -v flag, but not ICMP and ICMPv6 checksums. Here are two diffs to let tcpdump detect bad ICMP/ICMPv6 checksums, which should help when debugging issues caused by such checksums. :)
The first diff (below) is simply a mechanical change to make icmp_print() accept the length variable, which is the length of the packet without the IP header. This value is needed by tcpdump's in_cksum() (used by the second diff) to determine if an ICMP checksum is correct. Related functions like {tcp,udp,icmp6}_print() already accept this length variable, so this change will make icmp_print() consistent with them as well. This diff introduces no functional change. The second diff does the actual ICMP/ICMPv6 checksum verification; I'll send it in a separate mail. Index: interface.h =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/interface.h,v retrieving revision 1.61 diff -u -p -U5 -r1.61 interface.h --- interface.h 6 Apr 2010 16:01:57 -0000 1.61 +++ interface.h 1 Jan 2014 20:36:46 -0000 @@ -208,11 +208,11 @@ extern void ether_if_print(u_char *, con const u_char *); extern void fddi_if_print(u_char *, const struct pcap_pkthdr *, const u_char *); extern void ppp_ether_if_print(u_char *, const struct pcap_pkthdr *, const u_char *); extern void gre_print(const u_char *, u_int); -extern void icmp_print(const u_char *, const u_char *); +extern void icmp_print(const u_char *, u_int, const u_char *); extern void ieee802_11_if_print(u_char *, const struct pcap_pkthdr *, const u_char *); extern void ieee802_11_radio_if_print(u_char *, const struct pcap_pkthdr *, const u_char *); extern void iapp_print(const u_char *, u_int); Index: print-icmp.c =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/print-icmp.c,v retrieving revision 1.20 diff -u -p -U5 -r1.20 print-icmp.c --- print-icmp.c 27 Oct 2009 23:59:55 -0000 1.20 +++ print-icmp.c 2 Jan 2014 04:41:04 -0000 @@ -163,11 +163,11 @@ struct id_rdiscovery { u_int32_t ird_addr; u_int32_t ird_pref; }; void -icmp_print(const u_char *bp, const u_char *bp2) +icmp_print(const u_char *bp, u_int length, const u_char *bp2) { const struct icmp *dp; const struct ip *ip; const char *str, *fmt; const struct ip *oip; Index: print-ip.c =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/print-ip.c,v retrieving revision 1.36 diff -u -p -U5 -r1.36 print-ip.c --- print-ip.c 12 Jan 2010 06:10:33 -0000 1.36 +++ print-ip.c 1 Jan 2014 20:37:01 -0000 @@ -425,11 +425,11 @@ ip_print(register const u_char *bp, regi case IPPROTO_UDP: udp_print(cp, len, (const u_char *)ip); break; case IPPROTO_ICMP: - icmp_print(cp, (const u_char *)ip); + icmp_print(cp, len, (const u_char *)ip); break; #ifndef IPPROTO_IGRP #define IPPROTO_IGRP 9 #endif Index: print-ipsec.c =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/print-ipsec.c,v retrieving revision 1.17 diff -u -p -U5 -r1.17 print-ipsec.c --- print-ipsec.c 3 May 2012 10:17:23 -0000 1.17 +++ print-ipsec.c 1 Jan 2014 20:37:50 -0000 @@ -185,11 +185,11 @@ esp_decrypt (const u_char *bp, u_int len break; case IPPROTO_IPV4: ip_print(data, len); break; case IPPROTO_ICMP: - icmp_print(data, bp2); + icmp_print(data, len, bp2); break; case IPPROTO_ICMPV6: icmp6_print(data, len, bp2); break; default: @@ -296,11 +296,12 @@ ah_print (register const u_char *bp, reg case IPPROTO_IPIP: /* Tunnel Mode, IP-in-IP */ ip_print(bp + pl_len, len - pl_len); break; case IPPROTO_ICMP: /* From here and down; Transport mode */ - icmp_print(bp + pl_len, (const u_char *) ip); + icmp_print(bp + pl_len, len - pl_len, + (const u_char *) ip); break; case IPPROTO_ICMPV6: icmp6_print(bp + pl_len, len - pl_len, (const u_char *) ip);