This diff lets tcpdump detect bad ICMP/ICMPv6 checksums with the -v
flag. It depends on the first diff I sent earlier -
http://marc.info/?l=openbsd-tech&m=138906890129729&w=2
As an example here's how tcpdump -v output would look like for packets
with bad ICMP/ICMPv6 checksums:
00:08:56.994311 192.168.30.1 > 192.168.30.70: icmp: echo request \
(id:4ff0 seq:0) [bad icmp cksum 41fc!] (ttl 64, id 1, len 28)
23:26:03.986838 2001:xxx:e3ae:1::1 > 2001:xxx:e3ae:1::70: icmp6: echo request \
(id:0000 seq:0) [bad icmp6 cksum 8aa2!] (len 8, hlim 64)
For good ICMP/ICMPv6 checksums, a "cksum ok" message is shown just like
tcpdump -v currently does for good TCP/UDP checksums:
00:09:05.376922 192.168.30.1 > 192.168.30.70: icmp: echo request \
(id:4d05 seq:1) [icmp cksum ok] (ttl 255, id 27293, len 84)
00:09:05.376931 192.168.30.70 > 192.168.30.1: icmp: echo reply \
(id:4d05 seq:1) [icmp cksum ok] (ttl 255, id 43014, len 84)
23:24:44.659739 2001:xxx:e3ae:1::1 > 2001:xxx:e3ae:1::70: icmp6: echo request \
(id:0117 seq:0) [icmp6 cksum ok] (len 38, hlim 64)
23:24:44.659756 2001:xxx:e3ae:1::70 > 2001:xxx:e3ae:1::1: icmp6: echo reply \
(id:0117 seq:0) [icmp6 cksum ok] (len 38, hlim 64)
23:24:49.653691 2001:xxx:e3ae:1::1 > 2001:xxx:e3ae:1::70: icmp6: neighbor sol: \
who has 2001:xxx:e3ae:1::70(src lladdr: 00:90:0b:24:e9:30) \
[icmp6 cksum ok] (len 32, hlim 255)
23:24:49.653707 2001:xxx:e3ae:1::70 > 2001:xxx:e3ae:1::1: icmp6: neighbor adv: \
tgt is 2001:xxx:e3ae:1::70(RS) [icmp6 cksum ok] (len 24, hlim 255)
Tested on amd64, i386, loongson, and macppc.
Comments/OK?
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
@@ -371,11 +371,21 @@ icmp_print(const u_char *bp, const u_cha
default:
str = tok2str(icmp2str, "type-#%u", dp->icmp_type);
break;
}
- (void)printf("icmp: %s", str);
+ (void)printf("icmp: %s", str);
+ if (vflag) {
+ u_int16_t sum;
+ if (TTEST2(dp->icmp_type, length)) {
+ sum = in_cksum((const u_short *)dp, length, 0);
+ if (sum != 0)
+ (void)printf(" [bad icmp cksum %x!]", sum);
+ else
+ (void)printf(" [icmp cksum ok]");
+ }
+ }
if (vflag > 1 && !ICMP_INFOTYPE(dp->icmp_type) &&
TTEST(dp->icmp_ip)) {
(void)printf(" for ");
oip = &dp->icmp_ip;
ip_print((u_char *)oip, ntohs(oip->ip_len));
Index: print-icmp6.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/print-icmp6.c,v
retrieving revision 1.11
diff -u -p -U5 -r1.11 print-icmp6.c
--- print-icmp6.c 24 Oct 2013 09:33:22 -0000 1.11
+++ print-icmp6.c 2 Jan 2014 04:23:55 -0000
@@ -43,10 +43,11 @@
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <stdio.h>
+#include <string.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <netinet6/mld6.h>
@@ -90,10 +91,40 @@ static struct tok mldv2report2str[] = {
#define MLDV2_MRD(mant, exp) ((mant | 0x1000) << (exp + 3))
#define MLDV2_QQIC_FLOAT (1 << 7)
#define MLDV2_QQI(mant, exp) ((mant | 0x10) << (exp + 3))
+static int
+icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icmp6,
+ u_int len)
+{
+ union {
+ struct {
+ struct in6_addr ph_src;
+ struct in6_addr ph_dst;
+ u_int32_t ph_len;
+ u_int8_t ph_zero[3];
+ u_int8_t ph_nxt;
+ } ph;
+ u_int16_t pa[20];
+ } phu;
+ size_t i;
+ u_int32_t sum = 0;
+
+ /* pseudo-header */
+ memset(&phu, 0, sizeof(phu));
+ phu.ph.ph_src = ip6->ip6_src;
+ phu.ph.ph_dst = ip6->ip6_dst;
+ phu.ph.ph_len = htonl(len);
+ phu.ph.ph_nxt = IPPROTO_ICMPV6;
+
+ for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
+ sum += phu.pa[i];
+
+ return in_cksum((u_short *)icmp6, len, sum);
+}
+
void
icmp6_print(const u_char *bp, u_int length, const u_char *bp2)
{
register const struct icmp6_hdr *dp;
register const struct ip6_hdr *ip;
@@ -450,10 +481,20 @@ icmp6_print(const u_char *bp, u_int leng
mldv2_report_print((const u_char *) dp, length);
break;
default:
printf("icmp6: type-#%d", dp->icmp6_type);
break;
+ }
+ if (vflag) {
+ u_int16_t sum;
+ if (TTEST2(dp->icmp6_type, length)) {
+ sum = icmp6_cksum(ip, dp, length);
+ if (sum != 0)
+ printf(" [bad icmp6 cksum %x!]", sum);
+ else
+ printf(" [icmp6 cksum ok]");
+ }
}
return;
trunc:
fputs("[|icmp6]", stdout);
#if 0