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

Reply via email to