]> The Tcpdump Group git mirrors - tcpdump/commitdiff
Fix checksumming of PIMv2 Register messages.
authorGuy Harris <[email protected]>
Sat, 2 May 2015 17:15:42 +0000 (10:15 -0700)
committerGuy Harris <[email protected]>
Mon, 4 May 2015 00:51:58 +0000 (17:51 -0700)
The checksum only covers the header, not the encapsulated packet, so
only checksum that.  However, if that checksum fails, try checksumming
the entire packet, as, according to RFC 4601, packets with the entire
packet checksummed should also be accepted, for interoperability.

netdissect.h
print-ip.c
print-ip6.c
print-pim.c

index d507f580aa125d3f81e7c450594afac833fc6a2d..9440afb7a67dceed97e98ba941c5be751908a0d9 100644 (file)
@@ -503,7 +503,7 @@ extern void tftp_print(netdissect_options *, const u_char *, u_int);
 extern void vrrp_print(netdissect_options *, const u_char *, u_int, const u_char *, int);
 extern void pimv1_print(netdissect_options *, const u_char *, u_int);
 extern void cisco_autorp_print(netdissect_options *, const u_char *, u_int);
-extern void pim_print(netdissect_options *, const u_char *, u_int, u_int);
+extern void pim_print(netdissect_options *, const u_char *, u_int, const u_char *);
 extern const u_char * ns_nprint (netdissect_options *, register const u_char *, register const u_char *);
 extern void ns_print(netdissect_options *, const u_char *, u_int, int);
 extern void bootp_print(netdissect_options *, const u_char *, u_int);
index ceea5363f28b3b00b5a8923b5f498028cad034cb..5d17b391a926eb6e078b1dc55475184d32d727be 100644 (file)
@@ -324,7 +324,6 @@ ip_print_demux(netdissect_options *ndo,
               struct ip_print_demux_state *ipds)
 {
        struct protoent *proto;
-       struct cksum_vec vec[1];
 
 again:
        switch (ipds->nh) {
@@ -455,9 +454,7 @@ again:
                break;
 
        case IPPROTO_PIM:
-               vec[0].ptr = ipds->cp;
-               vec[0].len = ipds->len;
-               pim_print(ndo, ipds->cp, ipds->len, in_cksum(vec, 1));
+               pim_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip);
                break;
 
        case IPPROTO_VRRP:
index dd6b7f5105adb6037059988ca943547d566d14bf..7cad6a878073c46d2562eb52cf9358ce660e91c1 100644 (file)
@@ -223,8 +223,7 @@ ip6_print(netdissect_options *ndo, const u_char *bp, u_int length)
                    }
 
                case IPPROTO_PIM:
-                       pim_print(ndo, cp, len, nextproto6_cksum(ip6, cp, len, len,
-                                                           IPPROTO_PIM));
+                       pim_print(ndo, cp, len, (const u_char *)ip6);
                        return;
 
                case IPPROTO_OSPF:
index 15f4c51300e880b8fc447b5a5bf0cb9f1ff0ecaf..b362911ae5c6825fc7ca044a62bc75b35b936d70 100644 (file)
@@ -31,6 +31,7 @@
 #include "extract.h"
 
 #include "ip.h"
+#include "ip6.h"
 
 #define PIMV1_TYPE_QUERY           0
 #define PIMV1_TYPE_REGISTER        1
@@ -134,7 +135,7 @@ struct pim {
        u_short pim_cksum;      /* IP style check sum */
 };
 
-static void pimv2_print(netdissect_options *, register const u_char *bp, register u_int len, u_int cksum);
+static void pimv2_print(netdissect_options *, register const u_char *bp, register u_int len, const u_char *);
 
 static void
 pimv1_join_prune_print(netdissect_options *ndo,
@@ -415,7 +416,7 @@ trunc:
 
 void
 pim_print(netdissect_options *ndo,
-          register const u_char *bp, register u_int len, u_int cksum)
+          register const u_char *bp, register u_int len, const u_char *bp2)
 {
        register const u_char *ep;
        register struct pim *pim = (struct pim *)bp;
@@ -440,7 +441,7 @@ pim_print(netdissect_options *ndo,
                                  PIM_VER(pim->pim_typever),
                                  len,
                                  tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever))));
-                       pimv2_print(ndo, bp, len, cksum);
+                       pimv2_print(ndo, bp, len, bp2);
                }
                break;
        default:
@@ -620,13 +621,45 @@ trunc:
        return -1;
 }
 
+enum checksum_status {
+       CORRECT,
+       INCORRECT,
+       UNVERIFIED
+};
+
+static enum checksum_status
+pimv2_check_checksum(const u_char *bp, const u_char *bp2, u_int len)
+{
+       const struct ip *ip;
+       u_int cksum;
+
+       ip = (const struct ip *)bp2;
+       if (IP_V(ip) == 4) {
+               struct cksum_vec vec[1];
+
+               vec[0].ptr = bp;
+               vec[0].len = len;
+               cksum = in_cksum(vec, 1);
+               return (cksum ? INCORRECT : CORRECT);
+       } else if (IP_V(ip) == 6) {
+               const struct ip6_hdr *ip6;
+
+               ip6 = (const struct ip6_hdr *)bp2;
+               cksum = nextproto6_cksum(ip6, bp, len, len, IPPROTO_PIM);
+               return (cksum ? INCORRECT : CORRECT);
+       } else {
+               return (UNVERIFIED);
+       }
+}
+
 static void
 pimv2_print(netdissect_options *ndo,
-            register const u_char *bp, register u_int len, u_int cksum)
+            register const u_char *bp, register u_int len, const u_char *bp2)
 {
        register const u_char *ep;
        register struct pim *pim = (struct pim *)bp;
        int advance;
+       enum checksum_status cksum_status;
 
        ep = (const u_char *)ndo->ndo_snapend;
        if (bp >= ep)
@@ -642,7 +675,41 @@ pimv2_print(netdissect_options *ndo,
        if (EXTRACT_16BITS(&pim->pim_cksum) == 0) {
                ND_PRINT((ndo, "(unverified)"));
        } else {
-               ND_PRINT((ndo, "(%scorrect)", ND_TTEST2(bp[0], len) && cksum ? "in" : "" ));
+               if (PIM_TYPE(pim->pim_typever) == PIMV2_TYPE_REGISTER) {
+                       /*
+                        * The checksum only covers the packet header,
+                        * not the encapsulated packet.
+                        */
+                       cksum_status = pimv2_check_checksum(bp, bp2, 8);
+                       if (cksum_status == INCORRECT) {
+                               /*
+                                * To quote RFC 4601, "For interoperability
+                                * reasons, a message carrying a checksum
+                                * calculated over the entire PIM Register
+                                * message should also be accepted."
+                                */
+                               cksum_status = pimv2_check_checksum(bp, bp2, len);
+                       }
+               } else {
+                       /*
+                        * The checksum covers the entire packet.
+                        */
+                       cksum_status = pimv2_check_checksum(bp, bp2, len);
+               }
+               switch (cksum_status) {
+
+               case CORRECT:
+                       ND_PRINT((ndo, "(correct)"));
+                       break;
+
+               case INCORRECT:
+                       ND_PRINT((ndo, "(incorrect)"));
+                       break;
+
+               case UNVERIFIED:
+                       ND_PRINT((ndo, "(unverified)"));
+                       break;
+               }
        }
 
        switch (PIM_TYPE(pim->pim_typever)) {