CVE-2017-13030: Out-of-bounds Read (CWE-125)
value: The PIM parser in tcpdump before 4.9.2 has a buffer over-read in print-pim.c, several functions.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 9.8
Published: 2017-09-14T06:29Z
Repository: https://github.com/the-tcpdump-group/tcpdump
Language: Other
Files changed: print-pim.c, tests/TESTLIST, tests/heapoverflow-in_checksum.out, tests/pim_header_asan.out
Commit date: 2017-09-13 12:25:44 +0100
Commit message: CVE-2017-13030/PIM: Redo bounds checks and add length checks.

Use ND_TCHECK macros to do bounds checking, and add length checks before
the bounds checks.

Add a bounds check that the review process found was missing.

This fixes a buffer over-read discovered by Bhargava Shastry,
SecT/TU Berlin.

Add a test using the capture file supplied by the reporter(s), modified
so the capture file won't be rejected as an invalid capture.

Update one test output file to reflect the changes.

Diff: diff --git a/print-pim.c b/print-pim.c
index ee18d95813..b5c474694f 100644
--- a/print-pim.c
+++ b/print-pim.c
@@ -167,57 +167,78 @@ pimv1_join_prune_print(netdissect_options *ndo,
 		    (bp[25] & 0x80) ? " WC" : "",
 		    (bp[25] & 0x40) ? "RP" : "SPT"));
 		return;
 	}
 
+	if (len < sizeof(struct in_addr))
+		goto trunc;
 	ND_TCHECK2(bp[0], sizeof(struct in_addr));
 	if (ndo->ndo_vflag > 1)
 		ND_PRINT((ndo, "\n"));
 	ND_PRINT((ndo, " Upstream Nbr: %s", ipaddr_string(ndo, bp)));
-	ND_TCHECK2(bp[6], 2);
+	bp += 4;
+	len -= 4;
+	if (len < 4)
+		goto trunc;
+	ND_TCHECK2(bp[2], 2);
 	if (ndo->ndo_vflag > 1)
 		ND_PRINT((ndo, "\n"));
 	ND_PRINT((ndo, " Hold time: "));
-	unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[6]));
+	unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[2]));
 	if (ndo->ndo_vflag < 2)
 		return;
-	bp += 8;
-	len -= 8;
+	bp += 4;
+	len -= 4;
 
+	if (len < 4)
+		goto trunc;
 	ND_TCHECK2(bp[0], 4);
 	ngroups = bp[3];
 	bp += 4;
 	len -= 4;
 	while (ngroups--) {
 		/*
 		 * XXX - does the address have length "addrlen" and the
 		 * mask length "maddrlen"?
 		 */
+		if (len < 4)
+			goto trunc;
 		ND_TCHECK2(bp[0], sizeof(struct in_addr));
 		ND_PRINT((ndo, "\n\tGroup: %s", ipaddr_string(ndo, bp)));
-		ND_TCHECK2(bp[4], sizeof(struct in_addr));
-		if (EXTRACT_32BITS(&bp[4]) != 0xffffffff)
-			ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[4])));
-		ND_TCHECK2(bp[8], 4);
-		njoin = EXTRACT_16BITS(&bp[8]);
-		nprune = EXTRACT_16BITS(&bp[10]);
+		bp += 4;
+		len -= 4;
+		if (len < 4)
+			goto trunc;
+		ND_TCHECK2(bp[0], sizeof(struct in_addr));
+		if (EXTRACT_32BITS(&bp[0]) != 0xffffffff)
+			ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[0])));
+		bp += 4;
+		len -= 4;
+		if (len < 4)
+			goto trunc;
+		ND_TCHECK2(bp[0], 4);
+		njoin = EXTRACT_16BITS(&bp[0]);
+		nprune = EXTRACT_16BITS(&bp[2]);
 		ND_PRINT((ndo, " joined: %d pruned: %d", njoin, nprune));
-		bp += 12;
-		len -= 12;
+		bp += 4;
+		len -= 4;
 		for (njp = 0; njp < (njoin + nprune); njp++) {
 			const char *type;
 
 			if (njp < njoin)
 				type = "Join ";
 			else
 				type = "Prune";
+			if (len < 6)
+				goto trunc;
 			ND_TCHECK2(bp[0], 6);
 			ND_PRINT((ndo, "\n\t%s %s%s%s%s/%d", type,
 			    (bp[0] & 0x01) ? "Sparse " : "Dense ",
 			    (bp[1] & 0x80) ? "WC " : "",
 			    (bp[1] & 0x40) ? "RP " : "SPT ",
-			ipaddr_string(ndo, &bp[2]), bp[1] & 0x3f));
+			    ipaddr_string(ndo, &bp[2]),
+			    bp[1] & 0x3f));
 			bp += 6;
 			len -= 6;
 		}
 	}
 	return;
@@ -228,17 +249,12 @@ trunc:
 
 void
 pimv1_print(netdissect_options *ndo,
             register const u_char *bp, register u_int len)
 {
-	register const u_char *ep;
 	register u_char type;
 
-	ep = (const u_char *)ndo->ndo_snapend;
-	if (bp >= ep)
-		return;
-
 	ND_TCHECK(bp[1]);
 	type = bp[1];
 
 	ND_PRINT((ndo, " %s", tok2str(pimv1_type_str, "[type %u]", type)));
 	switch (type) {
@@ -300,12 +316,15 @@ pimv1_print(netdissect_options *ndo,
 		EXTRACT_32BITS(&bp[24])));
 		break;
 	case PIMV1_TYPE_JOIN_PRUNE:
 	case PIMV1_TYPE_GRAFT:
 	case PIMV1_TYPE_GRAFT_ACK:
-		if (ndo->ndo_vflag)
+		if (ndo->ndo_vflag) {
+			if (len < 8)
+				goto trunc;
 			pimv1_join_prune_print(ndo, &bp[8], len - 8);
+		}
 		break;
 	}
 	ND_TCHECK(bp[4]);
 	if ((bp[4] >> 4) != 1)
 		ND_PRINT((ndo, " [v%d]", bp[4] >> 4));
@@ -328,10 +347,12 @@ cisco_autorp_print(netdissect_options *ndo,
 {
 	int type;
 	int numrps;
 	int hold;
 
+	if (len < 8)
+		goto trunc;
 	ND_TCHECK(bp[0]);
 	ND_PRINT((ndo, " auto-rp "));
 	type = bp[0];
 	switch (type) {
 	case 0x11:
@@ -375,30 +396,43 @@ cisco_autorp_print(netdissect_options *ndo,
 	 */
 	while (numrps--) {
 		int nentries;
 		char s;
 
+		if (len < 4)
+			goto trunc;
 		ND_TCHECK2(bp[0], 4);
 		ND_PRINT((ndo, " RP %s", ipaddr_string(ndo, bp)));
-		ND_TCHECK(bp[4]);
-		switch (bp[4] & 0x3) {
+		bp += 4;
+		len -= 4;
+		if (len < 1)
+			goto trunc;
+		ND_TCHECK(bp[0]);
+		switch (bp[0] & 0x3) {
 		case 0: ND_PRINT((ndo, " PIMv?"));
 			break;
 		case 1:	ND_PRINT((ndo, " PIMv1"));
 			break;
 		case 2:	ND_PRINT((ndo, " PIMv2"));
 			break;
 		case 3:	ND_PRINT((ndo, " PIMv1+2"));
 			break;
 		}
-		if (bp[4] & 0xfc)
-			ND_PRINT((ndo, " [rsvd=0x%02x]", bp[4] & 0xfc));
-		ND_TCHECK(bp[5]);
-		nentries = bp[5];
-		bp += 6; len -= 6;
+		if (bp[0] & 0xfc)
+			ND_PRINT((ndo, " [rsvd=0x%02x]", bp[0] & 0xfc));
+		bp += 1;
+		len -= 1;
+		if (len < 1)
+			goto trunc;
+		ND_TCHECK(bp[0]);
+		nentries = bp[0];
+		bp += 1;
+		len -= 1;
 		s = ' ';
 		for (; nentries; nentries--) {
+			if (len < 6)
+				goto trunc;
 			ND_TCHECK2(bp[0], 6);
 			ND_PRINT((ndo, "%c%s%s/%d", s, bp[0] & 1 ? "!" : "",
 			          ipaddr_string(ndo, &bp[2]), bp[1]));
 			if (bp[0] & 0x02) {
 				ND_PRINT((ndo, " bidir"));
@@ -419,20 +453,17 @@ trunc:
 
 void
 pim_print(netdissect_options *ndo,
           register const u_char *bp, register u_int len, const u_char *bp2)
 {
-	register const u_char *ep;
 	register const struct pim *pim = (const struct pim *)bp;
 
-	ep = (const u_char *)ndo->ndo_snapend;
-	if (bp >= ep)
-		return;
 #ifdef notyet			/* currently we see only version and type */
 	ND_TCHECK(pim->pim_rsv);
 #endif
 
+	ND_TCHECK(pim->pim_typever);
 	switch (PIM_VER(pim->pim_typever)) {
 	case 2:
 		if (!ndo->ndo_vflag) {
 			ND_PRINT((ndo, "PIMv%u, %s, length %u",
 			          PIM_VER(pim->pim_typever),
@@ -452,10 +483,14 @@ pim_print(netdissect_options *ndo,
 		          PIM_VER(pim->pim_typever),
 		          len));
 		break;
 	}
 	return;
+
+trunc:
+	ND_PRINT((ndo, "[|pim]"));
+	return;
 }
 
 /*
  * PIMv2 uses encoded address representations.
  *
@@ -494,12 +529,10 @@ pim_print(netdissect_options *ndo,
  * encoding for the address family, and no other encodings are currently
  * specified.
  *
  */
 
-static int pimv2_addr_len;
-
 enum pimv2_addrtype {
 	pimv2_unicast, pimv2_group, pimv2_source
 };
 
 /*  0                   1                   2                   3
@@ -522,66 +555,71 @@ enum pimv2_addrtype {
  * |                        Source Address                         |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  */
 static int
 pimv2_addr_print(netdissect_options *ndo,
-                 const u_char *bp, enum pimv2_addrtype at, int silent)
+                 const u_char *bp, u_int len, enum pimv2_addrtype at,
+                 u_int addr_len, int silent)
 {
 	int af;
-	int len, hdrlen;
+	int hdrlen;
 
-	ND_TCHECK(bp[0]);
-
-	if (pimv2_addr_len == 0) {
+	if (addr_len == 0) {
+		if (len < 2)
+			goto trunc;
 		ND_TCHECK(bp[1]);
 		switch (bp[0]) {
 		case 1:
 			af = AF_INET;
-			len = sizeof(struct in_addr);
+			addr_len = (u_int)sizeof(struct in_addr);
 			break;
 		case 2:
 			af = AF_INET6;
-			len = sizeof(struct in6_addr);
+			addr_len = (u_int)sizeof(struct in6_addr);
 			break;
 		default:
 			return -1;
 		}
 		if (bp[1] != 0)
 			return -1;
 		hdrlen = 2;
 	} else {
-		switch (pimv2_addr_len) {
+		switch (addr_len) {
 		case sizeof(struct in_addr):
 			af = AF_INET;
 			break;
 		case sizeof(struct in6_addr):
 			af = AF_INET6;
 			break;
 		default:
 			return -1;
 			break;
 		}
-		len = pimv2_addr_len;
 		hdrlen = 0;
 	}
 
 	bp += hdrlen;
+	len -= hdrlen;
 	switch (at) {
 	case pimv2_unicast:
-		ND_TCHECK2(bp[0], len);
+		if (len < addr_len)
+			goto trunc;
+		ND_TCHECK2(bp[0], addr_len);
 		if (af == AF_INET) {
 			if (!silent)
 				ND_PRINT((ndo, "%s", ipaddr_string(ndo, bp)));
 		}
 		else if (af == AF_INET6) {
 			if (!silent)
 				ND_PRINT((ndo, "%s", ip6addr_string(ndo, bp)));
 		}
-		return hdrlen + len;
+		return hdrlen + addr_len;
 	case pimv2_group:
 	case pimv2_source:
-		ND_TCHECK2(bp[0], len + 2);
+		if (len < addr_len + 2)
+			goto trunc;
+		ND_TCHECK2(bp[0], addr_len + 2);
 		if (af == AF_INET) {
 			if (!silent) {
 				ND_PRINT((ndo, "%s", ipaddr_string(ndo, bp + 2)));
 				if (bp[1] != 32)
 					ND_PRINT((ndo, "/%u", bp[1]));
@@ -606,11 +644,11 @@ pimv2_addr_print(netdissect_options *ndo,
 					ND_PRINT((ndo, "+0x%02x", bp[0] & 0xf8));
 				}
 				ND_PRINT((ndo, ")"));
 			}
 		}
-		return hdrlen + 2 + len;
+		return hdrlen + 2 + addr_len;
 	default:
 		return -1;
 	}
 trunc:
 	return -1;
@@ -658,21 +696,27 @@ pimv2_print(netdissect_options *ndo,
 {
 	register const u_char *ep;
 	register const struct pim *pim = (const struct pim *)bp;
 	int advance;
 	enum checksum_status cksum_status;
+	int pimv2_addr_len;
 
 	ep = (const u_char *)ndo->ndo_snapend;
 	if (bp >= ep)
 		return;
 	if (ep > bp + len)
 		ep = bp + len;
+	if (len < 2)
+		goto trunc;
 	ND_TCHECK(pim->pim_rsv);
 	pimv2_addr_len = pim->pim_rsv;
 	if (pimv2_addr_len != 0)
 		ND_PRINT((ndo, ", RFC2117-encoding"));
 
+	if (len < 4)
+		goto trunc;
+	ND_TCHECK(pim->pim_cksum);
 	ND_PRINT((ndo, ", cksum 0x%04x ", EXTRACT_16BITS(&pim->pim_cksum)));
 	if (EXTRACT_16BITS(&pim->pim_cksum) == 0) {
 		ND_PRINT((ndo, "(unverified)"));
 	} else {
 		if (PIM_TYPE(pim->pim_typever) == PIMV2_TYPE_REGISTER) {
@@ -709,27 +753,33 @@ pimv2_print(netdissect_options *ndo,
 		case UNVERIFIED:
 			ND_PRINT((ndo, "(unverified)"));
 			break;
 		}
 	}
+	bp += 4;
+	len -= 4;
 
 	switch (PIM_TYPE(pim->pim_typever)) {
 	case PIMV2_TYPE_HELLO:
 	    {
 		uint16_t otype, olen;
-		bp += 4;
-		while (bp < ep) {
+		while (len > 0) {
+			if (len < 4)
+				goto trunc;
 			ND_TCHECK2(bp[0], 4);
 			otype = EXTRACT_16BITS(&bp[0]);
 			olen = EXTRACT_16BITS(&bp[2]);
-			ND_TCHECK2(bp[0], 4 + olen);
 			ND_PRINT((ndo, "\n\t  %s Option (%u), length %u, Value: ",
 			          tok2str(pimv2_hello_option_values, "Unknown", otype),
 			          otype,
 			          olen));
 			bp += 4;
+			len -= 4;
 
+			if (len < olen)
+				goto trunc;
+			ND_TCHECK2(bp[0], olen);
 			switch (otype) {
 			case PIMV2_HELLO_OPTION_HOLDTIME:
 				if (olen != 2) {
 					ND_PRINT((ndo, "ERROR: Option Length != 2 Bytes (%u)", olen));
 				} else {
@@ -795,18 +845,18 @@ pimv2_print(netdissect_options *ndo,
 
 			case PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD:
 			case PIMV2_HELLO_OPTION_ADDRESS_LIST:
 				if (ndo->ndo_vflag > 1) {
 					const u_char *ptr = bp;
+					u_int plen = len;
 					while (ptr < (bp+olen)) {
 						ND_PRINT((ndo, "\n\t    "));
-						advance = pimv2_addr_print(ndo, ptr, pimv2_unicast, 0);
-						if (advance < 0) {
-							ND_PRINT((ndo, "..."));
-							break;
-						}
+						advance = pimv2_addr_print(ndo, ptr, plen, pimv2_unicast, pimv2_addr_len, 0);
+						if (advance < 0)
+							goto trunc;
 						ptr += advance;
+						plen -= advance;
 					}
 				}
 				break;
 			default:
 				if (ndo->ndo_vflag <= 1)
@@ -815,30 +865,37 @@ pimv2_print(netdissect_options *ndo,
 			}
 			/* do we want to see an additionally hexdump ? */
 			if (ndo->ndo_vflag> 1)
 				print_unknown_data(ndo, bp, "\n\t    ", olen);
 			bp += olen;
+			len -= olen;
 		}
 		break;
 	    }
 
 	case PIMV2_TYPE_REGISTER:
 	{
 		const struct ip *ip;
 
-		ND_TCHECK2(*(bp + 4), PIMV2_REGISTER_FLAG_LEN);
+		if (len < 4)
+			goto trunc;
+		ND_TCHECK2(*bp, PIMV2_REGISTER_FLAG_LEN);
 
 		ND_PRINT((ndo, ", Flags [ %s ]\n\t",
 		          tok2str(pimv2_register_flag_values,
 		          "none",
-		          EXTRACT_32BITS(bp+4))));
+		          EXTRACT_32BITS(bp))));
 
-		bp += 8; len -= 8;
+		bp += 4; len -= 4;
 		/* encapsulated multicast packet */
+		if (len == 0)
+			goto trunc;
 		ip = (const struct ip *)bp;
+		ND_TCHECK(ip->ip_vhl);
 		switch (IP_V(ip)) {
                 case 0: /* Null header */
+			ND_TCHECK(ip->ip_dst);
 			ND_PRINT((ndo, "IP-Null-header %s > %s",
 			          ipaddr_string(ndo, &ip->ip_src),
 			          ipaddr_string(ndo, &ip->ip_dst)));
 			break;
 
@@ -856,26 +913,17 @@ pimv2_print(netdissect_options *ndo,
 		}
 		break;
 	}
 
 	case PIMV2_TYPE_REGISTER_STOP:
-		bp += 4; len -= 4;
-		if (bp >= ep)
-			break;
 		ND_PRINT((ndo, " group="));
-		if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0)) < 0) {
-			ND_PRINT((ndo, "..."));
-			break;
-		}
+		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
+			goto trunc;
 		bp += advance; len -= advance;
-		if (bp >= ep)
-			break;
 		ND_PRINT((ndo, " source="));
-		if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
-			ND_PRINT((ndo, "..."));
-			break;
-		}
+		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
+			goto trunc;
 		bp += advance; len -= advance;
 		break;
 
 	case PIMV2_TYPE_JOIN_PRUNE:
 	case PIMV2_TYPE_GRAFT:
@@ -922,23 +970,19 @@ pimv2_print(netdissect_options *ndo,
 		uint16_t holdtime;
 		uint16_t njoin;
 		uint16_t nprune;
 		int i, j;
 
-		bp += 4; len -= 4;
 		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
-			if (bp >= ep)
-				break;
 			ND_PRINT((ndo, ", upstream-neighbor: "));
-			if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
-				ND_PRINT((ndo, "..."));
-				break;
-			}
+			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
+				goto trunc;
 			bp += advance; len -= advance;
 		}
-		if (bp + 4 > ep)
-			break;
+		if (len < 4)
+			goto trunc;
+		ND_TCHECK2(*bp, 4);
 		ngroup = bp[1];
 		holdtime = EXTRACT_16BITS(&bp[2]);
 		ND_PRINT((ndo, "\n\t  %u group(s)", ngroup));
 		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
 			ND_PRINT((ndo, ", holdtime: "));
@@ -947,207 +991,194 @@ pimv2_print(netdissect_options *ndo,
 			else
 				unsigned_relts_print(ndo, holdtime);
 		}
 		bp += 4; len -= 4;
 		for (i = 0; i < ngroup; i++) {
-			if (bp >= ep)
-				goto jp_done;
 			ND_PRINT((ndo, "\n\t    group #%u: ", i+1));
-			if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0)) < 0) {
-				ND_PRINT((ndo, "...)"));
-				goto jp_done;
-			}
+			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
+				goto trunc;
 			bp += advance; len -= advance;
-			if (bp + 4 > ep) {
-				ND_PRINT((ndo, "...)"));
-				goto jp_done;
-			}
+			if (len < 4)
+				goto trunc;
+			ND_TCHECK2(*bp, 4);
 			njoin = EXTRACT_16BITS(&bp[0]);
 			nprune = EXTRACT_16BITS(&bp[2]);
 			ND_PRINT((ndo, ", joined sources: %u, pruned sources: %u", njoin, nprune));
 			bp += 4; len -= 4;
 			for (j = 0; j < njoin; j++) {
 				ND_PRINT((ndo, "\n\t      joined source #%u: ", j+1));
-				if ((advance = pimv2_addr_print(ndo, bp, pimv2_source, 0)) < 0) {
-					ND_PRINT((ndo, "...)"));
-					goto jp_done;
-				}
+				if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_source, pimv2_addr_len, 0)) < 0)
+					goto trunc;
 				bp += advance; len -= advance;
 			}
 			for (j = 0; j < nprune; j++) {
 				ND_PRINT((ndo, "\n\t      pruned source #%u: ", j+1));
-				if ((advance = pimv2_addr_print(ndo, bp, pimv2_source, 0)) < 0) {
-					ND_PRINT((ndo, "...)"));
-					goto jp_done;
-				}
+				if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_source, pimv2_addr_len, 0)) < 0)
+					goto trunc;
 				bp += advance; len -= advance;
 			}
 		}
-	jp_done:
 		break;
 	    }
 
 	case PIMV2_TYPE_BOOTSTRAP:
 	{
 		int i, j, frpcnt;
-		bp += 4;
 
 		/* Fragment Tag, Hash Mask len, and BSR-priority */
-		if (bp + sizeof(uint16_t) >= ep) break;
+		if (len < 2)
+			goto trunc;
+		ND_TCHECK_16BITS(bp);
 		ND_PRINT((ndo, " tag=%x", EXTRACT_16BITS(bp)));
-		bp += sizeof(uint16_t);
-		if (bp >= ep) break;
+		bp += 2;
+		len -= 2;
+		if (len < 1)
+			goto trunc;
+		ND_TCHECK(bp[0]);
 		ND_PRINT((ndo, " hashmlen=%d", bp[0]));
-		if (bp + 1 >= ep) break;
+		if (len < 2)
+			goto trunc;
+		ND_TCHECK(bp[2]);
 		ND_PRINT((ndo, " BSRprio=%d", bp[1]));
 		bp += 2;
+		len -= 2;
 
 		/* Encoded-Unicast-BSR-Address */
-		if (bp >= ep) break;
 		ND_PRINT((ndo, " BSR="));
-		if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
-			ND_PRINT((ndo, "..."));
-			break;
-		}
+		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
+			goto trunc;
 		bp += advance;
+		len -= advance;
 
 		for (i = 0; bp < ep; i++) {
 			/* Encoded-Group Address */
 			ND_PRINT((ndo, " (group%d: ", i));
-			if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0))
-			    < 0) {
-				ND_PRINT((ndo, "...)"));
-				goto bs_done;
-			}
+			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
+				goto trunc;
 			bp += advance;
+			len -= advance;
 
 			/* RP-Count, Frag RP-Cnt, and rsvd */
-			if (bp >= ep) {
-				ND_PRINT((ndo, "...)"));
-				goto bs_done;
-			}
+			if (len < 1)
+				goto trunc;
+			ND_TCHECK(bp[0]);
 			ND_PRINT((ndo, " RPcnt=%d", bp[0]));
-			if (bp + 1 >= ep) {
-				ND_PRINT((ndo, "...)"));
-				goto bs_done;
-			}
+			if (len < 2)
+				goto trunc;
+			ND_TCHECK(bp[1]);
 			ND_PRINT((ndo, " FRPcnt=%d", frpcnt = bp[1]));
+			if (len < 4)
+				goto trunc;
 			bp += 4;
+			len -= 4;
 
 			for (j = 0; j < frpcnt && bp < ep; j++) {
 				/* each RP info */
 				ND_PRINT((ndo, " RP%d=", j));
-				if ((advance = pimv2_addr_print(ndo, bp,
+				if ((advance = pimv2_addr_print(ndo, bp, len,
 								pimv2_unicast,
-								0)) < 0) {
-					ND_PRINT((ndo, "...)"));
-					goto bs_done;
-				}
+								pimv2_addr_len,
+								0)) < 0)
+					goto trunc;
 				bp += advance;
+				len -= advance;
 
-				if (bp + 1 >= ep) {
-					ND_PRINT((ndo, "...)"));
-					goto bs_done;
-				}
+				if (len < 2)
+					goto trunc;
+				ND_TCHECK_16BITS(bp);
 				ND_PRINT((ndo, ",holdtime="));
 				unsigned_relts_print(ndo, EXTRACT_16BITS(bp));
-				if (bp + 2 >= ep) {
-					ND_PRINT((ndo, "...)"));
-					goto bs_done;
-				}
+				if (len < 3)
+					goto trunc;
+				ND_TCHECK(bp[2]);
 				ND_PRINT((ndo, ",prio=%d", bp[2]));
+				if (len < 4)
+					goto trunc;
 				bp += 4;
+				len -= 4;
 			}
 			ND_PRINT((ndo, ")"));
 		}
-	   bs_done:
 		break;
 	}
 	case PIMV2_TYPE_ASSERT:
-		bp += 4; len -= 4;
-		if (bp >= ep)
-			break;
 		ND_PRINT((ndo, " group="));
-		if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0)) < 0) {
-			ND_PRINT((ndo, "..."));
-			break;
-		}
+		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
+			goto trunc;
 		bp += advance; len -= advance;
-		if (bp >= ep)
-			break;
 		ND_PRINT((ndo, " src="));
-		if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
-			ND_PRINT((ndo, "..."));
-			break;
-		}
+		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
+			goto trunc;
 		bp += advance; len -= advance;
-		if (bp + 8 > ep)
-			break;
+		if (len < 8)
+			goto trunc;
+		ND_TCHECK2(*bp, 8);
 		if (bp[0] & 0x80)
 			ND_PRINT((ndo, " RPT"));
 		ND_PRINT((ndo, " pref=%u", EXTRACT_32BITS(&bp[0]) & 0x7fffffff));
 		ND_PRINT((ndo, " metric=%u", EXTRACT_32BITS(&bp[4])));
 		break;
 
 	case PIMV2_TYPE_CANDIDATE_RP:
 	{
 		int i, pfxcnt;
-		bp += 4;
 
 		/* Prefix-Cnt, Priority, and Holdtime */
-		if (bp >= ep) break;
+		if (len < 1)
+			goto trunc;
+		ND_TCHECK(bp[0]);
 		ND_PRINT((ndo, " prefix-cnt=%d", bp[0]));
 		pfxcnt = bp[0];
-		if (bp + 1 >= ep) break;
+		if (len < 2)
+			goto trunc;
+		ND_TCHECK(bp[1]);
 		ND_PRINT((ndo, " prio=%d", bp[1]));
-		if (bp + 3 >= ep) break;
+		if (len < 4)
+			goto trunc;
+		ND_TCHECK_16BITS(&bp[2]);
 		ND_PRINT((ndo, " holdtime="));
 		unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[2]));
 		bp += 4;
+		len -= 4;
 
 		/* Encoded-Unicast-RP-Address */
-		if (bp >= ep) break;
 		ND_PRINT((ndo, " RP="));
-		if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
-			ND_PRINT((ndo, "..."));
-			break;
-		}
+		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
+			goto trunc;
 		bp += advance;
+		len -= advance;
 
 		/* Encoded-Group Addresses */
 		for (i = 0; i < pfxcnt && bp < ep; i++) {
 			ND_PRINT((ndo, " Group%d=", i));
-			if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0))
-			    < 0) {
-				ND_PRINT((ndo, "..."));
-				break;
-			}
+			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
+				goto trunc;
 			bp += advance;
+			len -= advance;
 		}
 		break;
 	}
 
 	case PIMV2_TYPE_PRUNE_REFRESH:
 		ND_PRINT((ndo, " src="));
-		if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
-			ND_PRINT((ndo, "..."));
-			break;
-		}
+		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
+			goto trunc;
 		bp += advance;
+		len -= advance;
 		ND_PRINT((ndo, " grp="));
-		if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0)) < 0) {
-			ND_PRINT((ndo, "..."));
-			break;
-		}
+		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
+			goto trunc;
 		bp += advance;
+		len -= advance;
 		ND_PRINT((ndo, " forwarder="));
-		if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
-			ND_PRINT((ndo, "..."));
-			break;
-		}
+		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
+			goto trunc;
 		bp += advance;
-		ND_TCHECK2(bp[0], 2);
+		len -= advance;
+		if (len < 2)
+			goto trunc;
+		ND_TCHECK_16BITS(bp);
 		ND_PRINT((ndo, " TUNR "));
 		unsigned_relts_print(ndo, EXTRACT_16BITS(bp));
 		break;
 
 
diff --git a/tests/TESTLIST b/tests/TESTLIST
index e553c2cadd..0dcfab1711 100644
--- a/tests/TESTLIST
+++ b/tests/TESTLIST
@@ -533,10 +533,11 @@ isis_stlv_asan-2	isis_stlv_asan-2.pcap		isis_stlv_asan-2.out	-v
 isis_stlv_asan-3	isis_stlv_asan-3.pcap		isis_stlv_asan-3.out	-v
 isis_stlv_asan-4	isis_stlv_asan-4.pcap		isis_stlv_asan-4.out	-v
 lldp_mgmt_addr_tlv_asan	lldp_mgmt_addr_tlv_asan.pcap	lldp_mgmt_addr_tlv_asan.out	-v
 bootp_asan		bootp_asan.pcap			bootp_asan.out		-v
 ppp_ccp_config_deflate_option_asan	ppp_ccp_config_deflate_option_asan.pcap	ppp_ccp_config_deflate_option_asan.out	-v
+pim_header_asan		pim_header_asan.pcap		pim_header_asan.out		-v
 
 # RTP tests
 # fuzzed pcap
 rtp-seg-fault-1  rtp-seg-fault-1.pcap  rtp-seg-fault-1.out  -v -T rtp
 rtp-seg-fault-2  rtp-seg-fault-2.pcap  rtp-seg-fault-2.out  -v -T rtp
diff --git a/tests/heapoverflow-in_checksum.out b/tests/heapoverflow-in_checksum.out
index fffc6920c2..aa59acb0cc 100644
--- a/tests/heapoverflow-in_checksum.out
+++ b/tests/heapoverflow-in_checksum.out
@@ -1,3 +1,4 @@
 IP (tos 0x30, ttl 48, id 12336, offset 0, flags [DF], proto PIM (103), length 12336, bad cksum 3030 (->2947)!)
     48.48.48.48 > 48.48.48.48: PIMv2, length 12316
-	Hello, RFC2117-encoding, cksum 0x3030 (unverified)[|pim]
+	Hello, RFC2117-encoding, cksum 0x3030 (unverified)
+	  Unknown Option (12336), length 12336, Value: [|pim]
diff --git a/tests/pim_header_asan.out b/tests/pim_header_asan.out
new file mode 100644
index 0000000000..397fe1e1b6
--- /dev/null
+++ b/tests/pim_header_asan.out
@@ -0,0 +1,2 @@
+IP6 (class 0x76, flowlabel 0xf6767, hlim 109, next-header PIM (103) payload length: 30311) 6767:6767:6767:8267:6767:6765:6767:6767 > 6700:80:74:24:2424:2424:2424:2509: PIMv2, length 30311
+	Bootstrap, RFC2117-encoding[|pim]
diff --git a/tests/pim_header_asan.pcap b/tests/pim_header_asan.pcap
new file mode 100644
index 0000000000..12f81bedd1
Binary files /dev/null and b/tests/pim_header_asan.pcap differ

Vulnerable code: 	ND_TCHECK2(bp[6], 2);
	unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[6]));
	bp += 8;
	len -= 8;
		ND_TCHECK2(bp[4], sizeof(struct in_addr));
		if (EXTRACT_32BITS(&bp[4]) != 0xffffffff)
			ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[4])));
		ND_TCHECK2(bp[8], 4);
		njoin = EXTRACT_16BITS(&bp[8]);
		nprune = EXTRACT_16BITS(&bp[10]);
		bp += 12;
		len -= 12;
			ipaddr_string(ndo, &bp[2]), bp[1] & 0x3f));
	register const u_char *ep;
	ep = (const u_char *)ndo->ndo_snapend;
	if (bp >= ep)
		return;

		if (ndo->ndo_vflag)
		ND_TCHECK(bp[4]);
		switch (bp[4] & 0x3) {
		if (bp[4] & 0xfc)
			ND_PRINT((ndo, " [rsvd=0x%02x]", bp[4] & 0xfc));
		ND_TCHECK(bp[5]);
		nentries = bp[5];
		bp += 6; len -= 6;
	register const u_char *ep;
	ep = (const u_char *)ndo->ndo_snapend;
	if (bp >= ep)
		return;
static int pimv2_addr_len;

                 const u_char *bp, enum pimv2_addrtype at, int silent)
	int len, hdrlen;
	ND_TCHECK(bp[0]);

	if (pimv2_addr_len == 0) {
			len = sizeof(struct in_addr);
			len = sizeof(struct in6_addr);
		switch (pimv2_addr_len) {
		len = pimv2_addr_len;
		ND_TCHECK2(bp[0], len);
		return hdrlen + len;
		ND_TCHECK2(bp[0], len + 2);
		return hdrlen + 2 + len;
		bp += 4;
		while (bp < ep) {
			ND_TCHECK2(bp[0], 4 + olen);
						advance = pimv2_addr_print(ndo, ptr, pimv2_unicast, 0);
						if (advance < 0) {
							ND_PRINT((ndo, "..."));
							break;
						}
		ND_TCHECK2(*(bp + 4), PIMV2_REGISTER_FLAG_LEN);
		          EXTRACT_32BITS(bp+4))));
		bp += 8; len -= 8;
		bp += 4; len -= 4;
		if (bp >= ep)
			break;
		if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0)) < 0) {
			ND_PRINT((ndo, "..."));
			break;
		}
		if (bp >= ep)
			break;
		if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
			ND_PRINT((ndo, "..."));
			break;
		}
		bp += 4; len -= 4;
			if (bp >= ep)
				break;
			if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
				ND_PRINT((ndo, "..."));
				break;
			}
		if (bp + 4 > ep)
			break;
			if (bp >= ep)
				goto jp_done;
			if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0)) < 0) {
				ND_PRINT((ndo, "...)"));
				goto jp_done;
			}
			if (bp + 4 > ep) {
				ND_PRINT((ndo, "...)"));
				goto jp_done;
			}
				if ((advance = pimv2_addr_print(ndo, bp, pimv2_source, 0)) < 0) {
					ND_PRINT((ndo, "...)"));
					goto jp_done;
				}
				if ((advance = pimv2_addr_print(ndo, bp, pimv2_source, 0)) < 0) {
					ND_PRINT((ndo, "...)"));
					goto jp_done;
				}
	jp_done:
		bp += 4;
		if (bp + sizeof(uint16_t) >= ep) break;
		bp += sizeof(uint16_t);
		if (bp >= ep) break;
		if (bp + 1 >= ep) break;
		if (bp >= ep) break;
		if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
			ND_PRINT((ndo, "..."));
			break;
		}
			if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0))
			    < 0) {
				ND_PRINT((ndo, "...)"));
				goto bs_done;
			}
			if (bp >= ep) {
				ND_PRINT((ndo, "...)"));
				goto bs_done;
			}
			if (bp + 1 >= ep) {
				ND_PRINT((ndo, "...)"));
				goto bs_done;
			}
				if ((advance = pimv2_addr_print(ndo, bp,
								0)) < 0) {
					ND_PRINT((ndo, "...)"));
					goto bs_done;
				}
				if (bp + 1 >= ep) {
					ND_PRINT((ndo, "...)"));
					goto bs_done;
				}
				if (bp + 2 >= ep) {
					ND_PRINT((ndo, "...)"));
					goto bs_done;
				}
	   bs_done:
		bp += 4; len -= 4;
		if (bp >= ep)
			break;
		if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0)) < 0) {
			ND_PRINT((ndo, "..."));
			break;
		}
		if (bp >= ep)
			break;
		if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
			ND_PRINT((ndo, "..."));
			break;
		}
		if (bp + 8 > ep)
			break;
		bp += 4;
		if (bp >= ep) break;
		if (bp + 1 >= ep) break;
		if (bp + 3 >= ep) break;
		if (bp >= ep) break;
		if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
			ND_PRINT((ndo, "..."));
			break;
		}
			if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0))
			    < 0) {
				ND_PRINT((ndo, "..."));
				break;
			}
		if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
			ND_PRINT((ndo, "..."));
			break;
		}
		if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0)) < 0) {
			ND_PRINT((ndo, "..."));
			break;
		}
		if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
			ND_PRINT((ndo, "..."));
			break;
		}
		ND_TCHECK2(bp[0], 2);
	Hello, RFC2117-encoding, cksum 0x3030 (unverified)[|pim]
Fixed code: 	if (len < sizeof(struct in_addr))
		goto trunc;
	bp += 4;
	len -= 4;
	if (len < 4)
		goto trunc;
	ND_TCHECK2(bp[2], 2);
	unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[2]));
	bp += 4;
	len -= 4;
	if (len < 4)
		goto trunc;
		if (len < 4)
			goto trunc;
		bp += 4;
		len -= 4;
		if (len < 4)
			goto trunc;
		ND_TCHECK2(bp[0], sizeof(struct in_addr));
		if (EXTRACT_32BITS(&bp[0]) != 0xffffffff)
			ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[0])));
		bp += 4;
		len -= 4;
		if (len < 4)
			goto trunc;
		ND_TCHECK2(bp[0], 4);
		njoin = EXTRACT_16BITS(&bp[0]);
		nprune = EXTRACT_16BITS(&bp[2]);
		bp += 4;
		len -= 4;
			if (len < 6)
				goto trunc;
			    ipaddr_string(ndo, &bp[2]),
			    bp[1] & 0x3f));
		if (ndo->ndo_vflag) {
			if (len < 8)
				goto trunc;
		}
	if (len < 8)
		goto trunc;
		if (len < 4)
			goto trunc;
		bp += 4;
		len -= 4;
		if (len < 1)
			goto trunc;
		ND_TCHECK(bp[0]);
		switch (bp[0] & 0x3) {
		if (bp[0] & 0xfc)
			ND_PRINT((ndo, " [rsvd=0x%02x]", bp[0] & 0xfc));
		bp += 1;
		len -= 1;
		if (len < 1)
			goto trunc;
		ND_TCHECK(bp[0]);
		nentries = bp[0];
		bp += 1;
		len -= 1;
			if (len < 6)
				goto trunc;
	ND_TCHECK(pim->pim_typever);

trunc:
	ND_PRINT((ndo, "[|pim]"));
	return;
                 const u_char *bp, u_int len, enum pimv2_addrtype at,
                 u_int addr_len, int silent)
	int hdrlen;
	if (addr_len == 0) {
		if (len < 2)
			goto trunc;
			addr_len = (u_int)sizeof(struct in_addr);
			addr_len = (u_int)sizeof(struct in6_addr);
		switch (addr_len) {
	len -= hdrlen;
		if (len < addr_len)
			goto trunc;
		ND_TCHECK2(bp[0], addr_len);
		return hdrlen + addr_len;
		if (len < addr_len + 2)
			goto trunc;
		ND_TCHECK2(bp[0], addr_len + 2);
		return hdrlen + 2 + addr_len;
	int pimv2_addr_len;
	if (len < 2)
		goto trunc;
	if (len < 4)
		goto trunc;
	ND_TCHECK(pim->pim_cksum);
	bp += 4;
	len -= 4;
		while (len > 0) {
			if (len < 4)
				goto trunc;
			len -= 4;
			if (len < olen)
				goto trunc;
			ND_TCHECK2(bp[0], olen);
					u_int plen = len;
						advance = pimv2_addr_print(ndo, ptr, plen, pimv2_unicast, pimv2_addr_len, 0);
						if (advance < 0)
							goto trunc;
						plen -= advance;
			len -= olen;
		if (len < 4)
			goto trunc;
		ND_TCHECK2(*bp, PIMV2_REGISTER_FLAG_LEN);
		          EXTRACT_32BITS(bp))));
		bp += 4; len -= 4;
		if (len == 0)
			goto trunc;
		ND_TCHECK(ip->ip_vhl);
			ND_TCHECK(ip->ip_dst);
		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
			goto trunc;
		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
			goto trunc;
			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
				goto trunc;
		if (len < 4)
			goto trunc;
		ND_TCHECK2(*bp, 4);
			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
				goto trunc;
			if (len < 4)
				goto trunc;
			ND_TCHECK2(*bp, 4);
				if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_source, pimv2_addr_len, 0)) < 0)
					goto trunc;
				if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_source, pimv2_addr_len, 0)) < 0)
					goto trunc;
		if (len < 2)
			goto trunc;
		ND_TCHECK_16BITS(bp);
		bp += 2;
		len -= 2;
		if (len < 1)
			goto trunc;
		ND_TCHECK(bp[0]);
		if (len < 2)
			goto trunc;
		ND_TCHECK(bp[2]);
		len -= 2;
		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
			goto trunc;
		len -= advance;
			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
				goto trunc;
			len -= advance;
			if (len < 1)
				goto trunc;
			ND_TCHECK(bp[0]);
			if (len < 2)
				goto trunc;
			ND_TCHECK(bp[1]);
			if (len < 4)
				goto trunc;
			len -= 4;
				if ((advance = pimv2_addr_print(ndo, bp, len,
								pimv2_addr_len,
								0)) < 0)
					goto trunc;
				len -= advance;
				if (len < 2)
					goto trunc;
				ND_TCHECK_16BITS(bp);
				if (len < 3)
					goto trunc;
				ND_TCHECK(bp[2]);
				if (len < 4)
					goto trunc;
				len -= 4;
		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
			goto trunc;
		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
			goto trunc;
		if (len < 8)
			goto trunc;
		ND_TCHECK2(*bp, 8);
		if (len < 1)
			goto trunc;
		ND_TCHECK(bp[0]);
		if (len < 2)
			goto trunc;
		ND_TCHECK(bp[1]);
		if (len < 4)
			goto trunc;
		ND_TCHECK_16BITS(&bp[2]);
		len -= 4;
		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
			goto trunc;
		len -= advance;
			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
				goto trunc;
			len -= advance;
		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
			goto trunc;
		len -= advance;
		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
			goto trunc;
		len -= advance;
		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
			goto trunc;
		len -= advance;
		if (len < 2)
			goto trunc;
		ND_TCHECK_16BITS(bp);
pim_header_asan		pim_header_asan.pcap		pim_header_asan.out		-v
	Hello, RFC2117-encoding, cksum 0x3030 (unverified)
	  Unknown Option (12336), length 12336, Value: [|pim]
IP6 (class 0x76, flowlabel 0xf6767, hlim 109, next-header PIM (103) payload length: 30311) 6767:6767:6767:8267:6767:6765:6767:6767 > 6700:80:74:24:2424:2424:2424:2509: PIMv2, length 30311
	Bootstrap, RFC2117-encoding[|pim]