 bgp_attr_print(netdissect_options *ndo,
               u_int atype, const u_char *pptr, u_int len, const unsigned attr_set_level)
 {
 	int i;
 	uint16_t af;
	uint8_t safi, snpa, nhlen;
        union { /* copy buffer for bandwidth values */
            float f;
            uint32_t i;
        } bw;
	int advance;
	u_int tlen;
	const u_char *tptr;
	char buf[MAXHOSTNAMELEN + 100];
        int  as_size;

        tptr = pptr;
        tlen=len;

	switch (atype) {
	case BGPTYPE_ORIGIN:
		if (len != 1)
			ND_PRINT((ndo, "invalid len"));
		else {
			ND_TCHECK(*tptr);
			ND_PRINT((ndo, "%s", tok2str(bgp_origin_values,
						"Unknown Origin Typecode",
						tptr[0])));
		}
		break;

        /*
         * Process AS4 byte path and AS2 byte path attributes here.
         */
	case BGPTYPE_AS4_PATH:
	case BGPTYPE_AS_PATH:
		if (len % 2) {
			ND_PRINT((ndo, "invalid len"));
			break;
		}
                if (!len) {
			ND_PRINT((ndo, "empty"));
			break;
                }

                /*
                 * BGP updates exchanged between New speakers that support 4
                 * byte AS, ASs are always encoded in 4 bytes. There is no
                 * definitive way to find this, just by the packet's
                 * contents. So, check for packet's TLV's sanity assuming
                 * 2 bytes first, and it does not pass, assume that ASs are
                 * encoded in 4 bytes format and move on.
                 */
                as_size = bgp_attr_get_as_size(ndo, atype, pptr, len);

		while (tptr < pptr + len) {
			ND_TCHECK(tptr[0]);
                        ND_PRINT((ndo, "%s", tok2str(bgp_as_path_segment_open_values,
						"?", tptr[0])));
			ND_TCHECK(tptr[1]);
                        for (i = 0; i < tptr[1] * as_size; i += as_size) {
                            ND_TCHECK2(tptr[2 + i], as_size);
			    ND_PRINT((ndo, "%s ",
				as_printf(ndo, astostr, sizeof(astostr),
				as_size == 2 ?
				EXTRACT_16BITS(&tptr[2 + i]) :
				EXTRACT_32BITS(&tptr[2 + i]))));
                        }
			ND_TCHECK(tptr[0]);
                        ND_PRINT((ndo, "%s", tok2str(bgp_as_path_segment_close_values,
						"?", tptr[0])));
                        ND_TCHECK(tptr[1]);
                        tptr += 2 + tptr[1] * as_size;
		}
		break;
	case BGPTYPE_NEXT_HOP:
		if (len != 4)
			ND_PRINT((ndo, "invalid len"));
		else {
			ND_TCHECK2(tptr[0], 4);
			ND_PRINT((ndo, "%s", ipaddr_string(ndo, tptr)));
		}
		break;
	case BGPTYPE_MULTI_EXIT_DISC:
	case BGPTYPE_LOCAL_PREF:
		if (len != 4)
			ND_PRINT((ndo, "invalid len"));
		else {
			ND_TCHECK2(tptr[0], 4);
			ND_PRINT((ndo, "%u", EXTRACT_32BITS(tptr)));
		}
		break;
	case BGPTYPE_ATOMIC_AGGREGATE:
		if (len != 0)
			ND_PRINT((ndo, "invalid len"));
		break;
        case BGPTYPE_AGGREGATOR:

                /*
                 * Depending on the AS encoded is of 2 bytes or of 4 bytes,
                 * the length of this PA can be either 6 bytes or 8 bytes.
                 */
                if (len != 6 && len != 8) {
                    ND_PRINT((ndo, "invalid len"));
                    break;
                }
                ND_TCHECK2(tptr[0], len);
                if (len == 6) {
		    ND_PRINT((ndo, " AS #%s, origin %s",
			as_printf(ndo, astostr, sizeof(astostr), EXTRACT_16BITS(tptr)),
			ipaddr_string(ndo, tptr + 2)));
                } else {
		    ND_PRINT((ndo, " AS #%s, origin %s",
			as_printf(ndo, astostr, sizeof(astostr),
			EXTRACT_32BITS(tptr)), ipaddr_string(ndo, tptr + 4)));
                }
                break;
	case BGPTYPE_AGGREGATOR4:
		if (len != 8) {
			ND_PRINT((ndo, "invalid len"));
			break;
		}
		ND_TCHECK2(tptr[0], 8);
		ND_PRINT((ndo, " AS #%s, origin %s",
		    as_printf(ndo, astostr, sizeof(astostr), EXTRACT_32BITS(tptr)),
		    ipaddr_string(ndo, tptr + 4)));
		break;
	case BGPTYPE_COMMUNITIES:
		if (len % 4) {
			ND_PRINT((ndo, "invalid len"));
			break;
		}
		while (tlen>0) {
			uint32_t comm;
			ND_TCHECK2(tptr[0], 4);
			comm = EXTRACT_32BITS(tptr);
			switch (comm) {
			case BGP_COMMUNITY_NO_EXPORT:
				ND_PRINT((ndo, " NO_EXPORT"));
				break;
			case BGP_COMMUNITY_NO_ADVERT:
				ND_PRINT((ndo, " NO_ADVERTISE"));
				break;
			case BGP_COMMUNITY_NO_EXPORT_SUBCONFED:
				ND_PRINT((ndo, " NO_EXPORT_SUBCONFED"));
				break;
			default:
				ND_PRINT((ndo, "%u:%u%s",
                                       (comm >> 16) & 0xffff,
                                       comm & 0xffff,
                                       (tlen>4) ? ", " : ""));
				break;
			}
                        tlen -=4;
                        tptr +=4;
		}
		break;
        case BGPTYPE_ORIGINATOR_ID:
		if (len != 4) {
			ND_PRINT((ndo, "invalid len"));
			break;
		}
		ND_TCHECK2(tptr[0], 4);
                ND_PRINT((ndo, "%s",ipaddr_string(ndo, tptr)));
                break;
        case BGPTYPE_CLUSTER_LIST:
		if (len % 4) {
			ND_PRINT((ndo, "invalid len"));
			break;
		}
                while (tlen>0) {
			ND_TCHECK2(tptr[0], 4);
                        ND_PRINT((ndo, "%s%s",
                               ipaddr_string(ndo, tptr),
                                (tlen>4) ? ", " : ""));
                        tlen -=4;
                        tptr +=4;
                }
                break;
	case BGPTYPE_MP_REACH_NLRI:
		ND_TCHECK2(tptr[0], 3);
		af = EXTRACT_16BITS(tptr);
		safi = tptr[2];

                ND_PRINT((ndo, "\n\t    AFI: %s (%u), %sSAFI: %s (%u)",
                       tok2str(af_values, "Unknown AFI", af),
                       af,
                       (safi>128) ? "vendor specific " : "", /* 128 is meanwhile wellknown */
                       tok2str(bgp_safi_values, "Unknown SAFI", safi),
                       safi));

                switch(af<<8 | safi) {
                case (AFNUM_INET<<8 | SAFNUM_UNICAST):
                case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
                case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
                case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
                case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO):
                case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST):
                case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST):
                case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST):
                case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN):
		case (AFNUM_INET<<8 | SAFNUM_MDT):
                case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
                case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
                case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
                case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
                case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST):
                case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST):
                case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST):
                case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
                case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
                case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
                case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST):
                case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST):
                case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST):
                case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST):
                case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST):
                case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST):
                case (AFNUM_VPLS<<8 | SAFNUM_VPLS):
                    break;
                default:
                    ND_TCHECK2(tptr[0], tlen);
                    ND_PRINT((ndo, "\n\t    no AFI %u / SAFI %u decoder", af, safi));
                    if (ndo->ndo_vflag <= 1)
                        print_unknown_data(ndo, tptr, "\n\t    ", tlen);
                    goto done;
                    break;
                }

                tptr +=3;

		ND_TCHECK(tptr[0]);
		nhlen = tptr[0];
                tlen = nhlen;
                tptr++;

		if (tlen) {
                    int nnh = 0;
                    ND_PRINT((ndo, "\n\t    nexthop: "));
                    while (tlen > 0) {
                        if ( nnh++ > 0 ) {
                            ND_PRINT((ndo,  ", " ));
                        }
                        switch(af<<8 | safi) {
                        case (AFNUM_INET<<8 | SAFNUM_UNICAST):
                        case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
                        case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
                        case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
                        case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO):
                        case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN):
                        case (AFNUM_INET<<8 | SAFNUM_MDT):
			    if (tlen < (int)sizeof(struct in_addr)) {
                                ND_PRINT((ndo, "invalid len"));
                                tlen = 0;
                            } else {
                                ND_TCHECK2(tptr[0], sizeof(struct in_addr));
                                ND_PRINT((ndo, "%s",ipaddr_string(ndo, tptr)));
                                tlen -= sizeof(struct in_addr);
                                tptr += sizeof(struct in_addr);
                            }
                            break;
                        case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST):
                        case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST):
                        case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST):
                            if (tlen < (int)(sizeof(struct in_addr)+BGP_VPN_RD_LEN)) {
                                ND_PRINT((ndo, "invalid len"));
                                tlen = 0;
                            } else {
                                ND_TCHECK2(tptr[0], sizeof(struct in_addr)+BGP_VPN_RD_LEN);
                                ND_PRINT((ndo, "RD: %s, %s",
                                       bgp_vpn_rd_print(ndo, tptr),
                                       ipaddr_string(ndo, tptr+BGP_VPN_RD_LEN)));
                                tlen -= (sizeof(struct in_addr)+BGP_VPN_RD_LEN);
                                tptr += (sizeof(struct in_addr)+BGP_VPN_RD_LEN);
                            }
                            break;
                        case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
                        case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
                        case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
                        case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
                            if (tlen < (int)sizeof(struct in6_addr)) {
                                ND_PRINT((ndo, "invalid len"));
                                tlen = 0;
                            } else {
                                ND_TCHECK2(tptr[0], sizeof(struct in6_addr));
                                ND_PRINT((ndo, "%s", ip6addr_string(ndo, tptr)));
                                tlen -= sizeof(struct in6_addr);
                                tptr += sizeof(struct in6_addr);
                            }
                            break;
                        case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST):
                        case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST):
                        case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST):
                            if (tlen < (int)(sizeof(struct in6_addr)+BGP_VPN_RD_LEN)) {
                                ND_PRINT((ndo, "invalid len"));
                                tlen = 0;
                            } else {
                                ND_TCHECK2(tptr[0], sizeof(struct in6_addr)+BGP_VPN_RD_LEN);
                                ND_PRINT((ndo, "RD: %s, %s",
                                       bgp_vpn_rd_print(ndo, tptr),
                                       ip6addr_string(ndo, tptr+BGP_VPN_RD_LEN)));
                                tlen -= (sizeof(struct in6_addr)+BGP_VPN_RD_LEN);
                                tptr += (sizeof(struct in6_addr)+BGP_VPN_RD_LEN);
                            }
                            break;
                        case (AFNUM_VPLS<<8 | SAFNUM_VPLS):
                        case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST):
                        case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST):
                        case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST):
                            if (tlen < (int)sizeof(struct in_addr)) {
                                ND_PRINT((ndo, "invalid len"));
                                tlen = 0;
                            } else {
                                ND_TCHECK2(tptr[0], sizeof(struct in_addr));
                                ND_PRINT((ndo, "%s", ipaddr_string(ndo, tptr)));
                                tlen -= (sizeof(struct in_addr));
                                tptr += (sizeof(struct in_addr));
                            }
                            break;
                        case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
                        case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
                        case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
                            ND_TCHECK2(tptr[0], tlen);
                            ND_PRINT((ndo, "%s", isonsap_string(ndo, tptr, tlen)));
                            tptr += tlen;
                            tlen = 0;
                            break;

                        case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST):
                        case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST):
                        case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST):
                            if (tlen < BGP_VPN_RD_LEN+1) {
                                ND_PRINT((ndo, "invalid len"));
                                tlen = 0;
                            } else {
                                ND_TCHECK2(tptr[0], tlen);
                                ND_PRINT((ndo, "RD: %s, %s",
                                       bgp_vpn_rd_print(ndo, tptr),
                                       isonsap_string(ndo, tptr+BGP_VPN_RD_LEN,tlen-BGP_VPN_RD_LEN)));
                                /* rfc986 mapped IPv4 address ? */
                                if (tlen == BGP_VPN_RD_LEN + 4 + sizeof(struct in_addr)
                                    && EXTRACT_32BITS(tptr+BGP_VPN_RD_LEN) ==  0x47000601)
                                    ND_PRINT((ndo, " = %s", ipaddr_string(ndo, tptr+BGP_VPN_RD_LEN+4)));
                                /* rfc1888 mapped IPv6 address ? */
                                else if (tlen == BGP_VPN_RD_LEN + 3 + sizeof(struct in6_addr)
                                         && EXTRACT_24BITS(tptr+BGP_VPN_RD_LEN) ==  0x350000)
                                    ND_PRINT((ndo, " = %s", ip6addr_string(ndo, tptr+BGP_VPN_RD_LEN+3)));
                                tptr += tlen;
                                tlen = 0;
                            }
                            break;
                        default:
                            ND_TCHECK2(tptr[0], tlen);
                            ND_PRINT((ndo, "no AFI %u/SAFI %u decoder", af, safi));
                            if (ndo->ndo_vflag <= 1)
                                print_unknown_data(ndo, tptr, "\n\t    ", tlen);
                            tptr += tlen;
                            tlen = 0;
                            goto done;
                            break;
                        }
                    }
		}
		ND_PRINT((ndo, ", nh-length: %u", nhlen));
		tptr += tlen;

		ND_TCHECK(tptr[0]);
		snpa = tptr[0];
		tptr++;

		if (snpa) {
			ND_PRINT((ndo, "\n\t    %u SNPA", snpa));
			for (/*nothing*/; snpa > 0; snpa--) {
				ND_TCHECK(tptr[0]);
				ND_PRINT((ndo, "\n\t      %d bytes", tptr[0]));
				tptr += tptr[0] + 1;
			}
		} else {
			ND_PRINT((ndo, ", no SNPA"));
                }

		while (tptr < pptr + len) {
                    switch (af<<8 | safi) {
                    case (AFNUM_INET<<8 | SAFNUM_UNICAST):
                    case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
                    case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
                        advance = decode_prefix4(ndo, tptr, len, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else if (advance == -3)
                            break; /* bytes left, but not enough */
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
                        advance = decode_labeled_prefix4(ndo, tptr, len, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else if (advance == -3)
                            break; /* bytes left, but not enough */
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST):
                    case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST):
                    case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST):
                        advance = decode_labeled_vpn_prefix4(ndo, tptr, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO):
                        advance = decode_rt_routing_info(ndo, tptr, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN): /* fall through */
                    case (AFNUM_INET6<<8 | SAFNUM_MULTICAST_VPN):
                        advance = decode_multicast_vpn(ndo, tptr, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;

		    case (AFNUM_INET<<8 | SAFNUM_MDT):
		      advance = decode_mdt_vpn_nlri(ndo, tptr, buf, sizeof(buf));
		      if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
		       break;
                    case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
                    case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
                    case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
                        advance = decode_prefix6(ndo, tptr, len, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else if (advance == -3)
                            break; /* bytes left, but not enough */
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
                        advance = decode_labeled_prefix6(ndo, tptr, len, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else if (advance == -3)
                            break; /* bytes left, but not enough */
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST):
                    case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST):
                    case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST):
                        advance = decode_labeled_vpn_prefix6(ndo, tptr, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_VPLS<<8 | SAFNUM_VPLS):
                    case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST):
                    case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST):
                    case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST):
                        advance = decode_labeled_vpn_l2(ndo, tptr, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal length)"));
                        else if (advance == -2)
                            goto trunc;
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
                    case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
                    case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
                        advance = decode_clnp_prefix(ndo, tptr, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST):
                    case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST):
                    case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST):
                        advance = decode_labeled_vpn_clnp_prefix(ndo, tptr, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    default:
                        ND_TCHECK2(*tptr,tlen);
                        ND_PRINT((ndo, "\n\t    no AFI %u / SAFI %u decoder", af, safi));
                        if (ndo->ndo_vflag <= 1)
                            print_unknown_data(ndo, tptr, "\n\t    ", tlen);
                        advance = 0;
                        tptr = pptr + len;
                        break;
                    }
                    if (advance < 0)
                        break;
                    tptr += advance;
		}
        done:
		break;

	case BGPTYPE_MP_UNREACH_NLRI:
		ND_TCHECK2(tptr[0], BGP_MP_NLRI_MINSIZE);
		af = EXTRACT_16BITS(tptr);
		safi = tptr[2];

                ND_PRINT((ndo, "\n\t    AFI: %s (%u), %sSAFI: %s (%u)",
                       tok2str(af_values, "Unknown AFI", af),
                       af,
                       (safi>128) ? "vendor specific " : "", /* 128 is meanwhile wellknown */
                       tok2str(bgp_safi_values, "Unknown SAFI", safi),
                       safi));

                if (len == BGP_MP_NLRI_MINSIZE)
                    ND_PRINT((ndo, "\n\t      End-of-Rib Marker (empty NLRI)"));

		tptr += 3;

		while (tptr < pptr + len) {
                    switch (af<<8 | safi) {
                    case (AFNUM_INET<<8 | SAFNUM_UNICAST):
                    case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
                    case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
                        advance = decode_prefix4(ndo, tptr, len, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else if (advance == -3)
                            break; /* bytes left, but not enough */
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
                        advance = decode_labeled_prefix4(ndo, tptr, len, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else if (advance == -3)
                            break; /* bytes left, but not enough */
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST):
                    case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST):
                    case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST):
                        advance = decode_labeled_vpn_prefix4(ndo, tptr, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
                    case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
                    case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
                        advance = decode_prefix6(ndo, tptr, len, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else if (advance == -3)
                            break; /* bytes left, but not enough */
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
                        advance = decode_labeled_prefix6(ndo, tptr, len, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else if (advance == -3)
                            break; /* bytes left, but not enough */
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST):
                    case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST):
                    case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST):
                        advance = decode_labeled_vpn_prefix6(ndo, tptr, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_VPLS<<8 | SAFNUM_VPLS):
                    case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST):
                    case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST):
                    case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST):
                        advance = decode_labeled_vpn_l2(ndo, tptr, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal length)"));
                        else if (advance == -2)
                            goto trunc;
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
                    case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
                    case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
                        advance = decode_clnp_prefix(ndo, tptr, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST):
                    case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST):
                    case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST):
                        advance = decode_labeled_vpn_clnp_prefix(ndo, tptr, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
		    case (AFNUM_INET<<8 | SAFNUM_MDT):
		      advance = decode_mdt_vpn_nlri(ndo, tptr, buf, sizeof(buf));
		      if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
		       break;
                    case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN): /* fall through */
                    case (AFNUM_INET6<<8 | SAFNUM_MULTICAST_VPN):
                        advance = decode_multicast_vpn(ndo, tptr, buf, sizeof(buf));
                        if (advance == -1)
                            ND_PRINT((ndo, "\n\t    (illegal prefix length)"));
                        else if (advance == -2)
                            goto trunc;
                        else
                            ND_PRINT((ndo, "\n\t      %s", buf));
                        break;
                    default:
                        ND_TCHECK2(*(tptr-3),tlen);
                        ND_PRINT((ndo, "no AFI %u / SAFI %u decoder", af, safi));
                        if (ndo->ndo_vflag <= 1)
                            print_unknown_data(ndo, tptr-3, "\n\t    ", tlen);
                        advance = 0;
                        tptr = pptr + len;
                        break;
                    }
                    if (advance < 0)
                        break;
                    tptr += advance;
		}
		break;
        case BGPTYPE_EXTD_COMMUNITIES:
		if (len % 8) {
			ND_PRINT((ndo, "invalid len"));
			break;
		}
                while (tlen>0) {
                    uint16_t extd_comm;

                    ND_TCHECK2(tptr[0], 2);
                    extd_comm=EXTRACT_16BITS(tptr);

		    ND_PRINT((ndo, "\n\t    %s (0x%04x), Flags [%s]",
			   tok2str(bgp_extd_comm_subtype_values,
				      "unknown extd community typecode",
				      extd_comm),
			   extd_comm,
			   bittok2str(bgp_extd_comm_flag_values, "none", extd_comm)));

                    ND_TCHECK2(*(tptr+2), 6);
                    switch(extd_comm) {
                    case BGP_EXT_COM_RT_0:
                    case BGP_EXT_COM_RO_0:
                    case BGP_EXT_COM_L2VPN_RT_0:
                        ND_PRINT((ndo, ": %u:%u (= %s)",
                               EXTRACT_16BITS(tptr+2),
                               EXTRACT_32BITS(tptr+4),
                               ipaddr_string(ndo, tptr+4)));
                        break;
                    case BGP_EXT_COM_RT_1:
                    case BGP_EXT_COM_RO_1:
                    case BGP_EXT_COM_L2VPN_RT_1:
                    case BGP_EXT_COM_VRF_RT_IMP:
                        ND_PRINT((ndo, ": %s:%u",
                               ipaddr_string(ndo, tptr+2),
                               EXTRACT_16BITS(tptr+6)));
                        break;
                    case BGP_EXT_COM_RT_2:
                    case BGP_EXT_COM_RO_2:
			ND_PRINT((ndo, ": %s:%u",
			    as_printf(ndo, astostr, sizeof(astostr),
			    EXTRACT_32BITS(tptr+2)), EXTRACT_16BITS(tptr+6)));
			break;
                    case BGP_EXT_COM_LINKBAND:
		        bw.i = EXTRACT_32BITS(tptr+2);
                        ND_PRINT((ndo, ": bandwidth: %.3f Mbps",
                               bw.f*8/1000000));
                        break;
                    case BGP_EXT_COM_VPN_ORIGIN:
                    case BGP_EXT_COM_VPN_ORIGIN2:
                    case BGP_EXT_COM_VPN_ORIGIN3:
                    case BGP_EXT_COM_VPN_ORIGIN4:
                    case BGP_EXT_COM_OSPF_RID:
                    case BGP_EXT_COM_OSPF_RID2:
                        ND_PRINT((ndo, "%s", ipaddr_string(ndo, tptr+2)));
                        break;
                    case BGP_EXT_COM_OSPF_RTYPE:
                    case BGP_EXT_COM_OSPF_RTYPE2:
                        ND_PRINT((ndo, ": area:%s, router-type:%s, metric-type:%s%s",
                               ipaddr_string(ndo, tptr+2),
                               tok2str(bgp_extd_comm_ospf_rtype_values,
					  "unknown (0x%02x)",
					  *(tptr+6)),
                               (*(tptr+7) &  BGP_OSPF_RTYPE_METRIC_TYPE) ? "E2" : "",
                               ((*(tptr+6) == BGP_OSPF_RTYPE_EXT) || (*(tptr+6) == BGP_OSPF_RTYPE_NSSA)) ? "E1" : ""));
                        break;
                    case BGP_EXT_COM_L2INFO:
                        ND_PRINT((ndo, ": %s Control Flags [0x%02x]:MTU %u",
                               tok2str(l2vpn_encaps_values,
					  "unknown encaps",
					  *(tptr+2)),
                                       *(tptr+3),
                               EXTRACT_16BITS(tptr+4)));
                        break;
                    case BGP_EXT_COM_SOURCE_AS:
                        ND_PRINT((ndo, ": AS %u", EXTRACT_16BITS(tptr+2)));
                        break;
                    default:
                        ND_TCHECK2(*tptr,8);
                        print_unknown_data(ndo, tptr, "\n\t      ", 8);
                        break;
                    }
                    tlen -=8;
                    tptr +=8;
                }
                break;

        case BGPTYPE_PMSI_TUNNEL:
        {
                uint8_t tunnel_type, flags;

                ND_TCHECK2(tptr[0], 5);
                tunnel_type = *(tptr+1);
                flags = *tptr;
                tlen = len;

                ND_PRINT((ndo, "\n\t    Tunnel-type %s (%u), Flags [%s], MPLS Label %u",
                       tok2str(bgp_pmsi_tunnel_values, "Unknown", tunnel_type),
                       tunnel_type,
                       bittok2str(bgp_pmsi_flag_values, "none", flags),
                       EXTRACT_24BITS(tptr+2)>>4));

                tptr +=5;
                tlen -= 5;

                switch (tunnel_type) {
                case BGP_PMSI_TUNNEL_PIM_SM: /* fall through */
                case BGP_PMSI_TUNNEL_PIM_BIDIR:
                    ND_TCHECK2(tptr[0], 8);
                    ND_PRINT((ndo, "\n\t      Sender %s, P-Group %s",
                           ipaddr_string(ndo, tptr),
                           ipaddr_string(ndo, tptr+4)));
                    break;

                case BGP_PMSI_TUNNEL_PIM_SSM:
                    ND_TCHECK2(tptr[0], 8);
                    ND_PRINT((ndo, "\n\t      Root-Node %s, P-Group %s",
                           ipaddr_string(ndo, tptr),
                           ipaddr_string(ndo, tptr+4)));
                    break;
                case BGP_PMSI_TUNNEL_INGRESS:
                    ND_TCHECK2(tptr[0], 4);
                    ND_PRINT((ndo, "\n\t      Tunnel-Endpoint %s",
                           ipaddr_string(ndo, tptr)));
                    break;
                case BGP_PMSI_TUNNEL_LDP_P2MP: /* fall through */
                case BGP_PMSI_TUNNEL_LDP_MP2MP:
                    ND_TCHECK2(tptr[0], 8);
                    ND_PRINT((ndo, "\n\t      Root-Node %s, LSP-ID 0x%08x",
                           ipaddr_string(ndo, tptr),
                           EXTRACT_32BITS(tptr+4)));
                    break;
                case BGP_PMSI_TUNNEL_RSVP_P2MP:
                    ND_TCHECK2(tptr[0], 8);
                    ND_PRINT((ndo, "\n\t      Extended-Tunnel-ID %s, P2MP-ID 0x%08x",
                           ipaddr_string(ndo, tptr),
                           EXTRACT_32BITS(tptr+4)));
                    break;
                default:
                    if (ndo->ndo_vflag <= 1) {
                        print_unknown_data(ndo, tptr, "\n\t      ", tlen);
                    }
                }
                break;
        }
	case BGPTYPE_AIGP:
	{
		uint8_t type;
		uint16_t length;

		tlen = len;

		while (tlen >= 3) {

		    ND_TCHECK2(tptr[0], 3);

		    type = *tptr;
		    length = EXTRACT_16BITS(tptr+1);
		    tptr += 3;
		    tlen -= 3;

		    ND_PRINT((ndo, "\n\t    %s TLV (%u), length %u",
			      tok2str(bgp_aigp_values, "Unknown", type),
			      type, length));

		    if (length < 3)
			goto trunc;
		    length -= 3;

		    /*
		     * Check if we can read the TLV data.
		     */
		    ND_TCHECK2(tptr[3], length);

		    switch (type) {

		    case BGP_AIGP_TLV:
		        if (length < 8)
		            goto trunc;
			ND_PRINT((ndo, ", metric %" PRIu64,
				  EXTRACT_64BITS(tptr)));
			break;

		    default:
			if (ndo->ndo_vflag <= 1) {
			    print_unknown_data(ndo, tptr,"\n\t      ", length);
			}
		    }

		    tptr += length;
		    tlen -= length;
		}
		break;
	}
        case BGPTYPE_ATTR_SET:
                ND_TCHECK2(tptr[0], 4);
                if (len < 4)
                	goto trunc;
		ND_PRINT((ndo, "\n\t    Origin AS: %s",
		    as_printf(ndo, astostr, sizeof(astostr), EXTRACT_32BITS(tptr))));
		tptr+=4;
                len -=4;

                while (len) {
                    u_int aflags, alenlen, alen;

                    ND_TCHECK2(tptr[0], 2);
                    if (len < 2)
                        goto trunc;
                    aflags = *tptr;
                    atype = *(tptr + 1);
                    tptr += 2;
                    len -= 2;
                    alenlen = bgp_attr_lenlen(aflags, tptr);
                    ND_TCHECK2(tptr[0], alenlen);
                    if (len < alenlen)
                        goto trunc;
                    alen = bgp_attr_len(aflags, tptr);
                    tptr += alenlen;
                    len -= alenlen;

                    ND_PRINT((ndo, "\n\t      %s (%u), length: %u",
                           tok2str(bgp_attr_values,
                                      "Unknown Attribute", atype),
                           atype,
                           alen));

                    if (aflags) {
                        ND_PRINT((ndo, ", Flags [%s%s%s%s",
                               aflags & 0x80 ? "O" : "",
                               aflags & 0x40 ? "T" : "",
                               aflags & 0x20 ? "P" : "",
                               aflags & 0x10 ? "E" : ""));
                        if (aflags & 0xf)
                             ND_PRINT((ndo, "+%x", aflags & 0xf));
                         ND_PRINT((ndo, "]: "));
                     }
                    /* The protocol encoding per se allows ATTR_SET to be nested as many times
                     * as the message can accommodate. This printer used to be able to recurse
                     * into ATTR_SET contents until the stack exhaustion, but now there is a
                     * limit on that (if live protocol exchange goes that many levels deep,
                     * something is probably wrong anyway). Feel free to refine this value if
                     * you can find the spec with respective normative text.
                     */
                    if (attr_set_level == 10)
                        ND_PRINT((ndo, "(too many nested levels, not recursing)"));
                    else if (!bgp_attr_print(ndo, atype, tptr, alen, attr_set_level + 1))
                         return 0;
                     tptr += alen;
                     len -= alen;
		}
                break;

	case BGPTYPE_LARGE_COMMUNITY:
		if (len == 0 || len % 12) {
			ND_PRINT((ndo, "invalid len"));
			break;
		}
		ND_PRINT((ndo, "\n\t    "));
		while (len > 0) {
			ND_TCHECK2(*tptr, 12);
			ND_PRINT((ndo, "%u:%u:%u%s",
				 EXTRACT_32BITS(tptr),
				 EXTRACT_32BITS(tptr + 4),
				 EXTRACT_32BITS(tptr + 8),
				 (len > 12) ? ", " : ""));
                        tptr += 12;
                        len -= 12;
		}
		break;
	default:
	    ND_TCHECK2(*pptr,len);
            ND_PRINT((ndo, "\n\t    no Attribute %u decoder", atype)); /* we have no decoder for the attribute */
            if (ndo->ndo_vflag <= 1)
                print_unknown_data(ndo, pptr, "\n\t    ", len);
            break;
	}
        if (ndo->ndo_vflag > 1 && len) { /* omit zero length attributes*/
            ND_TCHECK2(*pptr,len);
            print_unknown_data(ndo, pptr, "\n\t    ", len);
        }
        return 1;

trunc:
        return 0;
}


(for 4.9.3) CVE-2018-16229/DCCP: Fix printing "Timestamp" and "Timestamp Echo" options

Add some comments.

Moreover:
Put a function definition name at the beginning of the line.

(This change was ported from commit 6df4852 in the master branch.)

Ryan Ackroyd had independently identified this buffer over-read later by
means of fuzzing and provided the packet capture file for the test.

static int dccp_print_option(netdissect_options *ndo, const u_char *option, u_int hlen)
 {
 	uint8_t optlen, i;

	ND_TCHECK(*option);

	if (*option >= 32) {
		ND_TCHECK(*(option+1));
		optlen = *(option +1);
		if (optlen < 2) {
			if (*option >= 128)
				ND_PRINT((ndo, "CCID option %u optlen too short", *option));
			else
				ND_PRINT((ndo, "%s optlen too short",
					  tok2str(dccp_option_values, "Option %u", *option)));
			return 0;
		}
	} else
		optlen = 1;

	if (hlen < optlen) {
		if (*option >= 128)
			ND_PRINT((ndo, "CCID option %u optlen goes past header length",
				  *option));
		else
			ND_PRINT((ndo, "%s optlen goes past header length",
				  tok2str(dccp_option_values, "Option %u", *option)));
		return 0;
	}
	ND_TCHECK2(*option, optlen);

	if (*option >= 128) {
		ND_PRINT((ndo, "CCID option %d", *option));
		switch (optlen) {
			case 4:
				ND_PRINT((ndo, " %u", EXTRACT_16BITS(option + 2)));
				break;
			case 6:
				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
				break;
			default:
				break;
		}
	} else {
		ND_PRINT((ndo, "%s", tok2str(dccp_option_values, "Option %u", *option)));
		switch (*option) {
		case 32:
		case 33:
		case 34:
		case 35:
			if (optlen < 3) {
				ND_PRINT((ndo, " optlen too short"));
				return optlen;
			}
			if (*(option + 2) < 10){
				ND_PRINT((ndo, " %s", dccp_feature_nums[*(option + 2)]));
				for (i = 0; i < optlen - 3; i++)
					ND_PRINT((ndo, " %d", *(option + 3 + i)));
			}
			break;
		case 36:
			if (optlen > 2) {
				ND_PRINT((ndo, " 0x"));
				for (i = 0; i < optlen - 2; i++)
					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
			}
			break;
		case 37:
			for (i = 0; i < optlen - 2; i++)
				ND_PRINT((ndo, " %d", *(option + 2 + i)));
			break;
		case 38:
			if (optlen > 2) {
				ND_PRINT((ndo, " 0x"));
				for (i = 0; i < optlen - 2; i++)
					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
			}
			break;
		case 39:
			if (optlen > 2) {
				ND_PRINT((ndo, " 0x"));
				for (i = 0; i < optlen - 2; i++)
					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
			}
			break;
		case 40:
			if (optlen > 2) {
				ND_PRINT((ndo, " 0x"));
				for (i = 0; i < optlen - 2; i++)
					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
 			}
 			break;
 		case 41:
			if (optlen == 4)
 				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
 			else
				ND_PRINT((ndo, " optlen != 4"));
 			break;
 		case 42:
			if (optlen == 4)
 				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
			else
				ND_PRINT((ndo, " optlen != 4"));
 			break;
 		case 43:
 			if (optlen == 6)
 				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
 			else if (optlen == 4)
 				ND_PRINT((ndo, " %u", EXTRACT_16BITS(option + 2)));
 			else
				ND_PRINT((ndo, " optlen != 4 or 6"));
 			break;
 		case 44:
 			if (optlen > 2) {
				ND_PRINT((ndo, " "));
				for (i = 0; i < optlen - 2; i++)
					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
			}
			break;
		}
	}

	return optlen;
trunc:
	ND_PRINT((ndo, "%s", tstr));
	return 0;
}

The DCCP parser in tcpdump before 4.9.3 has a buffer over-read in print-dccp.c:dccp_print_option().


static int dccp_print_option(netdissect_options *ndo, const u_char *option, u_int hlen)
static int
dccp_print_option(netdissect_options *ndo, const u_char *option, u_int hlen)
 {
 	uint8_t optlen, i;

	ND_TCHECK(*option);

	if (*option >= 32) {
		ND_TCHECK(*(option+1));
		optlen = *(option +1);
		if (optlen < 2) {
			if (*option >= 128)
				ND_PRINT((ndo, "CCID option %u optlen too short", *option));
			else
				ND_PRINT((ndo, "%s optlen too short",
					  tok2str(dccp_option_values, "Option %u", *option)));
			return 0;
		}
	} else
		optlen = 1;

	if (hlen < optlen) {
		if (*option >= 128)
			ND_PRINT((ndo, "CCID option %u optlen goes past header length",
				  *option));
		else
			ND_PRINT((ndo, "%s optlen goes past header length",
				  tok2str(dccp_option_values, "Option %u", *option)));
		return 0;
	}
	ND_TCHECK2(*option, optlen);

	if (*option >= 128) {
		ND_PRINT((ndo, "CCID option %d", *option));
		switch (optlen) {
			case 4:
				ND_PRINT((ndo, " %u", EXTRACT_16BITS(option + 2)));
				break;
			case 6:
				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
				break;
			default:
				break;
		}
	} else {
		ND_PRINT((ndo, "%s", tok2str(dccp_option_values, "Option %u", *option)));
		switch (*option) {
		case 32:
		case 33:
		case 34:
		case 35:
			if (optlen < 3) {
				ND_PRINT((ndo, " optlen too short"));
				return optlen;
			}
			if (*(option + 2) < 10){
				ND_PRINT((ndo, " %s", dccp_feature_nums[*(option + 2)]));
				for (i = 0; i < optlen - 3; i++)
					ND_PRINT((ndo, " %d", *(option + 3 + i)));
			}
			break;
		case 36:
			if (optlen > 2) {
				ND_PRINT((ndo, " 0x"));
				for (i = 0; i < optlen - 2; i++)
					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
			}
			break;
		case 37:
			for (i = 0; i < optlen - 2; i++)
				ND_PRINT((ndo, " %d", *(option + 2 + i)));
			break;
		case 38:
			if (optlen > 2) {
				ND_PRINT((ndo, " 0x"));
				for (i = 0; i < optlen - 2; i++)
					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
			}
			break;
		case 39:
			if (optlen > 2) {
				ND_PRINT((ndo, " 0x"));
				for (i = 0; i < optlen - 2; i++)
					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
			}
			break;
		case 40:
			if (optlen > 2) {
				ND_PRINT((ndo, " 0x"));
				for (i = 0; i < optlen - 2; i++)
					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
 			}
 			break;
 		case 41:
		/*
		 * 13.1.  Timestamp Option
		 *
		 *  +--------+--------+--------+--------+--------+--------+
		 *  |00101001|00000110|          Timestamp Value          |
		 *  +--------+--------+--------+--------+--------+--------+
		 *   Type=41  Length=6
		 */
			if (optlen == 6)
 				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
 			else
				ND_PRINT((ndo, " [optlen != 6]"));
 			break;
 		case 42:
		/*
		 * 13.3.  Timestamp Echo Option
		 *
		 *  +--------+--------+--------+--------+--------+--------+
		 *  |00101010|00000110|           Timestamp Echo          |
		 *  +--------+--------+--------+--------+--------+--------+
		 *   Type=42    Len=6
		 *
		 *  +--------+--------+------- ... -------+--------+--------+
		 *  |00101010|00001000|  Timestamp Echo   |   Elapsed Time  |
		 *  +--------+--------+------- ... -------+--------+--------+
		 *   Type=42    Len=8       (4 bytes)
		 *
		 *  +--------+--------+------- ... -------+------- ... -------+
		 *  |00101010|00001010|  Timestamp Echo   |    Elapsed Time   |
		 *  +--------+--------+------- ... -------+------- ... -------+
		 *   Type=42   Len=10       (4 bytes)           (4 bytes)
		 */
			switch (optlen) {
			case 6:
 				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
				break;
			case 8:
				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
				ND_PRINT((ndo, " (elapsed time %u)", EXTRACT_16BITS(option + 6)));
				break;
			case 10:
				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
				ND_PRINT((ndo, " (elapsed time %u)", EXTRACT_32BITS(option + 6)));
				break;
			default:
				ND_PRINT((ndo, " [optlen != 6 or 8 or 10]"));
				break;
			}
 			break;
 		case 43:
 			if (optlen == 6)
 				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
 			else if (optlen == 4)
 				ND_PRINT((ndo, " %u", EXTRACT_16BITS(option + 2)));
 			else
				ND_PRINT((ndo, " [optlen != 4 or 6]"));
 			break;
 		case 44:
 			if (optlen > 2) {
				ND_PRINT((ndo, " "));
				for (i = 0; i < optlen - 2; i++)
					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
			}
			break;
		}
	}

	return optlen;
trunc:
	ND_PRINT((ndo, "%s", tstr));
	return 0;
}


(for 4.9.3) CVE-2018-16227/IEEE 802.11: add a missing bounds check

ieee802_11_print() tried to access the Mesh Flags subfield of the Mesh
Control field to find the size of the latter and increment the expected
802.11 header length before checking it is fully present in the input
buffer. Add an intermediate bounds check to make it safe.

This fixes a buffer over-read discovered by Ryan Ackroyd.

Add a test using the capture file supplied by the reporter(s).

ieee802_11_print(netdissect_options *ndo,
                 const u_char *p, u_int length, u_int orig_caplen, int pad,
                 u_int fcslen)
{
	uint16_t fc;
	u_int caplen, hdrlen, meshdrlen;
	struct lladdr_info src, dst;
	int llc_hdrlen;

	caplen = orig_caplen;
	/* Remove FCS, if present */
	if (length < fcslen) {
		ND_PRINT((ndo, "%s", tstr));
		return caplen;
	}
	length -= fcslen;
	if (caplen > length) {
		/* Amount of FCS in actual packet data, if any */
		fcslen = caplen - length;
		caplen -= fcslen;
		ndo->ndo_snapend -= fcslen;
	}

	if (caplen < IEEE802_11_FC_LEN) {
		ND_PRINT((ndo, "%s", tstr));
		return orig_caplen;
	}

	fc = EXTRACT_LE_16BITS(p);
	hdrlen = extract_header_length(ndo, fc);
	if (hdrlen == 0) {
		/* Unknown frame type or control frame subtype; quit. */
		return (0);
	}
	if (pad)
 		hdrlen = roundup2(hdrlen, 4);
 	if (ndo->ndo_Hflag && FC_TYPE(fc) == T_DATA &&
 	    DATA_FRAME_IS_QOS(FC_SUBTYPE(fc))) {
 		meshdrlen = extract_mesh_header_length(p+hdrlen);
 		hdrlen += meshdrlen;
 	} else
		meshdrlen = 0;

	if (caplen < hdrlen) {
		ND_PRINT((ndo, "%s", tstr));
		return hdrlen;
	}

	if (ndo->ndo_eflag)
		ieee_802_11_hdr_print(ndo, fc, p, hdrlen, meshdrlen);

	/*
	 * Go past the 802.11 header.
	 */
	length -= hdrlen;
	caplen -= hdrlen;
	p += hdrlen;

	src.addr_string = etheraddr_string;
	dst.addr_string = etheraddr_string;
	switch (FC_TYPE(fc)) {
	case T_MGMT:
		get_mgmt_src_dst_mac(p - hdrlen, &src.addr, &dst.addr);
		if (!mgmt_body_print(ndo, fc, src.addr, p, length)) {
			ND_PRINT((ndo, "%s", tstr));
			return hdrlen;
		}
		break;
	case T_CTRL:
		if (!ctrl_body_print(ndo, fc, p - hdrlen)) {
			ND_PRINT((ndo, "%s", tstr));
			return hdrlen;
		}
		break;
	case T_DATA:
		if (DATA_FRAME_IS_NULL(FC_SUBTYPE(fc)))
			return hdrlen;	/* no-data frame */
		/* There may be a problem w/ AP not having this bit set */
		if (FC_PROTECTED(fc)) {
			ND_PRINT((ndo, "Data"));
			if (!wep_print(ndo, p)) {
				ND_PRINT((ndo, "%s", tstr));
				return hdrlen;
			}
		} else {
			get_data_src_dst_mac(fc, p - hdrlen, &src.addr, &dst.addr);
			llc_hdrlen = llc_print(ndo, p, length, caplen, &src, &dst);
			if (llc_hdrlen < 0) {
				/*
				 * Some kinds of LLC packet we cannot
				 * handle intelligently
				 */
				if (!ndo->ndo_suppress_default_print)
					ND_DEFAULTPRINT(p, caplen);
				llc_hdrlen = -llc_hdrlen;
			}
			hdrlen += llc_hdrlen;
		}
		break;
	default:
		/* We shouldn't get here - we should already have quit */
		break;
	}

	return hdrlen;
}

The IEEE 802.11 parser in tcpdump before 4.9.3 has a buffer over-read in print-802_11.c for the Mesh Flags subfield.


ieee802_11_print(netdissect_options *ndo,
                 const u_char *p, u_int length, u_int orig_caplen, int pad,
                 u_int fcslen)
{
	uint16_t fc;
	u_int caplen, hdrlen, meshdrlen;
	struct lladdr_info src, dst;
	int llc_hdrlen;

	caplen = orig_caplen;
	/* Remove FCS, if present */
	if (length < fcslen) {
		ND_PRINT((ndo, "%s", tstr));
		return caplen;
	}
	length -= fcslen;
	if (caplen > length) {
		/* Amount of FCS in actual packet data, if any */
		fcslen = caplen - length;
		caplen -= fcslen;
		ndo->ndo_snapend -= fcslen;
	}

	if (caplen < IEEE802_11_FC_LEN) {
		ND_PRINT((ndo, "%s", tstr));
		return orig_caplen;
	}

	fc = EXTRACT_LE_16BITS(p);
	hdrlen = extract_header_length(ndo, fc);
	if (hdrlen == 0) {
		/* Unknown frame type or control frame subtype; quit. */
		return (0);
	}
	if (pad)
 		hdrlen = roundup2(hdrlen, 4);
 	if (ndo->ndo_Hflag && FC_TYPE(fc) == T_DATA &&
 	    DATA_FRAME_IS_QOS(FC_SUBTYPE(fc))) {
		if (caplen < hdrlen + 1) {
			ND_PRINT((ndo, "%s", tstr));
			return hdrlen;
		}
 		meshdrlen = extract_mesh_header_length(p+hdrlen);
 		hdrlen += meshdrlen;
 	} else
		meshdrlen = 0;

	if (caplen < hdrlen) {
		ND_PRINT((ndo, "%s", tstr));
		return hdrlen;
	}

	if (ndo->ndo_eflag)
		ieee_802_11_hdr_print(ndo, fc, p, hdrlen, meshdrlen);

	/*
	 * Go past the 802.11 header.
	 */
	length -= hdrlen;
	caplen -= hdrlen;
	p += hdrlen;

	src.addr_string = etheraddr_string;
	dst.addr_string = etheraddr_string;
	switch (FC_TYPE(fc)) {
	case T_MGMT:
		get_mgmt_src_dst_mac(p - hdrlen, &src.addr, &dst.addr);
		if (!mgmt_body_print(ndo, fc, src.addr, p, length)) {
			ND_PRINT((ndo, "%s", tstr));
			return hdrlen;
		}
		break;
	case T_CTRL:
		if (!ctrl_body_print(ndo, fc, p - hdrlen)) {
			ND_PRINT((ndo, "%s", tstr));
			return hdrlen;
		}
		break;
	case T_DATA:
		if (DATA_FRAME_IS_NULL(FC_SUBTYPE(fc)))
			return hdrlen;	/* no-data frame */
		/* There may be a problem w/ AP not having this bit set */
		if (FC_PROTECTED(fc)) {
			ND_PRINT((ndo, "Data"));
			if (!wep_print(ndo, p)) {
				ND_PRINT((ndo, "%s", tstr));
				return hdrlen;
			}
		} else {
			get_data_src_dst_mac(fc, p - hdrlen, &src.addr, &dst.addr);
			llc_hdrlen = llc_print(ndo, p, length, caplen, &src, &dst);
			if (llc_hdrlen < 0) {
				/*
				 * Some kinds of LLC packet we cannot
				 * handle intelligently
				 */
				if (!ndo->ndo_suppress_default_print)
					ND_DEFAULTPRINT(p, caplen);
				llc_hdrlen = -llc_hdrlen;
			}
			hdrlen += llc_hdrlen;
		}
		break;
	default:
		/* We shouldn't get here - we should already have quit */
		break;
	}

	return hdrlen;
}


(for 4.9.3) CVE-2018-14880/OSPFv3: Fix a bounds check

Need to test bounds check for the last field of the structure lsa6_hdr.
No need to test other fields.

Include Security working under the Mozilla SOS program had independently
identified this vulnerability in 2018 by means of code audit.

Wang Junjie of 360 ESG Codesafe Team had independently identified this
vulnerability in 2018 by means of fuzzing and provided the packet capture
file for the test.

ospf6_print_lshdr(netdissect_options *ndo,
                  register const struct lsa6_hdr *lshp, const u_char *dataend)
 {
 	if ((const u_char *)(lshp + 1) > dataend)
 		goto trunc;
	ND_TCHECK(lshp->ls_type);
	ND_TCHECK(lshp->ls_seq);

 	ND_PRINT((ndo, "\n\t  Advertising Router %s, seq 0x%08x, age %us, length %u",
                ipaddr_string(ndo, &lshp->ls_router),
               EXTRACT_32BITS(&lshp->ls_seq),
               EXTRACT_16BITS(&lshp->ls_age),
               EXTRACT_16BITS(&lshp->ls_length)-(u_int)sizeof(struct lsa6_hdr)));

	ospf6_print_ls_type(ndo, EXTRACT_16BITS(&lshp->ls_type), &lshp->ls_stateid);

	return (0);
trunc:
	return (1);
}

The OSPFv3 parser in tcpdump before 4.9.3 has a buffer over-read in print-ospf6.c:ospf6_print_lshdr().


ospf6_print_lshdr(netdissect_options *ndo,
                  register const struct lsa6_hdr *lshp, const u_char *dataend)
 {
 	if ((const u_char *)(lshp + 1) > dataend)
 		goto trunc;
	ND_TCHECK(lshp->ls_length);	/* last field of struct lsa6_hdr */

 	ND_PRINT((ndo, "\n\t  Advertising Router %s, seq 0x%08x, age %us, length %u",
                ipaddr_string(ndo, &lshp->ls_router),
               EXTRACT_32BITS(&lshp->ls_seq),
               EXTRACT_16BITS(&lshp->ls_age),
               EXTRACT_16BITS(&lshp->ls_length)-(u_int)sizeof(struct lsa6_hdr)));

	ospf6_print_ls_type(ndo, EXTRACT_16BITS(&lshp->ls_type), &lshp->ls_stateid);

	return (0);
trunc:
	return (1);
}


(for 4.9.3) CVE-2018-14879/fix -V to fail invalid input safely

get_next_file() did not check the return value of strlen() and
underflowed an array index if the line read by fgets() from the file
started with \0. This caused an out-of-bounds read and could cause a
write. Add the missing check.

This vulnerability was discovered by Brian Carpenter & Geeknik Labs.

 get_next_file(FILE *VFile, char *ptr)
 {
 	char *ret;

 	ret = fgets(ptr, PATH_MAX, VFile);
 	if (!ret)
 		return NULL;

	if (ptr[strlen(ptr) - 1] == '\n')
		ptr[strlen(ptr) - 1] = '\0';

 	return ret;
 }

The command-line argument parser in tcpdump before 4.9.3 has a buffer overflow in tcpdump.c:get_next_file().


 get_next_file(FILE *VFile, char *ptr)
 {
 	char *ret;
	size_t len;

 	ret = fgets(ptr, PATH_MAX, VFile);
 	if (!ret)
 		return NULL;

	len = strlen (ptr);
	if (len > 0 && ptr[len - 1] == '\n')
		ptr[len - 1] = '\0';

 	return ret;
 }


cjpeg: Fix OOB read caused by malformed 8-bit BMP

... in which one or more of the color indices is out of range for the
number of palette entries.

Fix partly borrowed from jpeg-9c.  This commit also adopts Guido's
JERR_PPM_OUTOFRANGE enum value in lieu of our project-specific
JERR_PPM_TOOLARGE enum value.

Fixes #258

METHODDEF(JDIMENSION)
get_8bit_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
/* This version is for reading 8-bit colormap indexes */
 {
   bmp_source_ptr source = (bmp_source_ptr)sinfo;
   register JSAMPARRAY colormap = source->colormap;
   JSAMPARRAY image_ptr;
   register int t;
   register JSAMPROW inptr, outptr;
  register JDIMENSION col;

  if (source->use_inversion_array) {
    /* Fetch next row from virtual array */
    source->source_row--;
    image_ptr = (*cinfo->mem->access_virt_sarray)
      ((j_common_ptr)cinfo, source->whole_image,
       source->source_row, (JDIMENSION)1, FALSE);
    inptr = image_ptr[0];
  } else {
    if (!ReadOK(source->pub.input_file, source->iobuffer, source->row_width))
      ERREXIT(cinfo, JERR_INPUT_EOF);
    inptr = source->iobuffer;
  }

  /* Expand the colormap indexes to real data */
  outptr = source->pub.buffer[0];
   if (cinfo->in_color_space == JCS_GRAYSCALE) {
     for (col = cinfo->image_width; col > 0; col--) {
       t = GETJSAMPLE(*inptr++);
       *outptr++ = colormap[0][t];
     }
   } else if (cinfo->in_color_space == JCS_CMYK) {
     for (col = cinfo->image_width; col > 0; col--) {
       t = GETJSAMPLE(*inptr++);
       rgb_to_cmyk(colormap[0][t], colormap[1][t], colormap[2][t], outptr,
                   outptr + 1, outptr + 2, outptr + 3);
       outptr += 4;
    }
  } else {
    register int rindex = rgb_red[cinfo->in_color_space];
    register int gindex = rgb_green[cinfo->in_color_space];
    register int bindex = rgb_blue[cinfo->in_color_space];
    register int aindex = alpha_index[cinfo->in_color_space];
    register int ps = rgb_pixelsize[cinfo->in_color_space];

     if (aindex >= 0) {
       for (col = cinfo->image_width; col > 0; col--) {
         t = GETJSAMPLE(*inptr++);
         outptr[rindex] = colormap[0][t];
         outptr[gindex] = colormap[1][t];
         outptr[bindex] = colormap[2][t];
        outptr[aindex] = 0xFF;
        outptr += ps;
      }
     } else {
       for (col = cinfo->image_width; col > 0; col--) {
         t = GETJSAMPLE(*inptr++);
         outptr[rindex] = colormap[0][t];
         outptr[gindex] = colormap[1][t];
         outptr[bindex] = colormap[2][t];
        outptr += ps;
      }
    }
  }

  return 1;
}

get_8bit_row in rdbmp.c in libjpeg-turbo through 1.5.90 and MozJPEG through 3.3.1 allows attackers to cause a denial of service (heap-based buffer over-read and application crash) via a crafted 8-bit BMP in which one or more of the color indices is out of range for the number of palette entries.


METHODDEF(JDIMENSION)
get_8bit_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
/* This version is for reading 8-bit colormap indexes */
 {
   bmp_source_ptr source = (bmp_source_ptr)sinfo;
   register JSAMPARRAY colormap = source->colormap;
  int cmaplen = source->cmap_length;
   JSAMPARRAY image_ptr;
   register int t;
   register JSAMPROW inptr, outptr;
  register JDIMENSION col;

  if (source->use_inversion_array) {
    /* Fetch next row from virtual array */
    source->source_row--;
    image_ptr = (*cinfo->mem->access_virt_sarray)
      ((j_common_ptr)cinfo, source->whole_image,
       source->source_row, (JDIMENSION)1, FALSE);
    inptr = image_ptr[0];
  } else {
    if (!ReadOK(source->pub.input_file, source->iobuffer, source->row_width))
      ERREXIT(cinfo, JERR_INPUT_EOF);
    inptr = source->iobuffer;
  }

  /* Expand the colormap indexes to real data */
  outptr = source->pub.buffer[0];
   if (cinfo->in_color_space == JCS_GRAYSCALE) {
     for (col = cinfo->image_width; col > 0; col--) {
       t = GETJSAMPLE(*inptr++);
      if (t >= cmaplen)
        ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
       *outptr++ = colormap[0][t];
     }
   } else if (cinfo->in_color_space == JCS_CMYK) {
     for (col = cinfo->image_width; col > 0; col--) {
       t = GETJSAMPLE(*inptr++);
      if (t >= cmaplen)
        ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
       rgb_to_cmyk(colormap[0][t], colormap[1][t], colormap[2][t], outptr,
                   outptr + 1, outptr + 2, outptr + 3);
       outptr += 4;
    }
  } else {
    register int rindex = rgb_red[cinfo->in_color_space];
    register int gindex = rgb_green[cinfo->in_color_space];
    register int bindex = rgb_blue[cinfo->in_color_space];
    register int aindex = alpha_index[cinfo->in_color_space];
    register int ps = rgb_pixelsize[cinfo->in_color_space];

     if (aindex >= 0) {
       for (col = cinfo->image_width; col > 0; col--) {
         t = GETJSAMPLE(*inptr++);
        if (t >= cmaplen)
          ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
         outptr[rindex] = colormap[0][t];
         outptr[gindex] = colormap[1][t];
         outptr[bindex] = colormap[2][t];
        outptr[aindex] = 0xFF;
        outptr += ps;
      }
     } else {
       for (col = cinfo->image_width; col > 0; col--) {
         t = GETJSAMPLE(*inptr++);
        if (t >= cmaplen)
          ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
         outptr[rindex] = colormap[0][t];
         outptr[gindex] = colormap[1][t];
         outptr[bindex] = colormap[2][t];
        outptr += ps;
      }
    }
  }

  return 1;
}


(for 4.9.3) CVE-2018-14470/Babel: fix an existing length check

In babel_print_v2() the non-verbose branch for an Update TLV compared
the TLV Length against 1 instead of 10 (probably a typo), put it right.

This fixes a buffer over-read discovered by Henri Salo from Nixu
Corporation.

Add a test using the capture file supplied by the reporter(s).

babel_print_v2(netdissect_options *ndo,
               const u_char *cp, u_int length)
{
    u_int i;
    u_short bodylen;
    u_char v4_prefix[16] =
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
    u_char v6_prefix[16] = {0};

    ND_TCHECK2(*cp, 4);
    if (length < 4)
        goto invalid;
    bodylen = EXTRACT_16BITS(cp + 2);
    ND_PRINT((ndo, " (%u)", bodylen));

    /* Process the TLVs in the body */
    i = 0;
    while(i < bodylen) {
        const u_char *message;
        u_int type, len;

        message = cp + 4 + i;

        ND_TCHECK2(*message, 1);
        if((type = message[0]) == MESSAGE_PAD1) {
            ND_PRINT((ndo, ndo->ndo_vflag ? "\n\tPad 1" : " pad1"));
            i += 1;
            continue;
        }

        ND_TCHECK2(*message, 2);
        ICHECK(i, 2);
        len = message[1];

        ND_TCHECK2(*message, 2 + len);
        ICHECK(i, 2 + len);

        switch(type) {
        case MESSAGE_PADN: {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " padN"));
            else
                ND_PRINT((ndo, "\n\tPad %d", len + 2));
        }
            break;

        case MESSAGE_ACK_REQ: {
            u_short nonce, interval;
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " ack-req"));
            else {
                ND_PRINT((ndo, "\n\tAcknowledgment Request "));
                if(len < 6) goto invalid;
                nonce = EXTRACT_16BITS(message + 4);
                interval = EXTRACT_16BITS(message + 6);
                ND_PRINT((ndo, "%04x %s", nonce, format_interval(interval)));
            }
        }
            break;

        case MESSAGE_ACK: {
            u_short nonce;
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " ack"));
            else {
                ND_PRINT((ndo, "\n\tAcknowledgment "));
                if(len < 2) goto invalid;
                nonce = EXTRACT_16BITS(message + 2);
                ND_PRINT((ndo, "%04x", nonce));
            }
        }
            break;

        case MESSAGE_HELLO:  {
            u_short seqno, interval;
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " hello"));
            else {
                ND_PRINT((ndo, "\n\tHello "));
                if(len < 6) goto invalid;
                seqno = EXTRACT_16BITS(message + 4);
                interval = EXTRACT_16BITS(message + 6);
                ND_PRINT((ndo, "seqno %u interval %s", seqno, format_interval(interval)));
                /* Extra data. */
                if(len > 6)
                    subtlvs_print(ndo, message + 8, message + 2 + len, type);
            }
        }
            break;

        case MESSAGE_IHU: {
            unsigned short txcost, interval;
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " ihu"));
            else {
                u_char address[16];
                int rc;
                ND_PRINT((ndo, "\n\tIHU "));
                if(len < 6) goto invalid;
                txcost = EXTRACT_16BITS(message + 4);
                interval = EXTRACT_16BITS(message + 6);
                rc = network_address(message[2], message + 8, len - 6, address);
                if(rc < 0) { ND_PRINT((ndo, "%s", tstr)); break; }
                ND_PRINT((ndo, "%s txcost %u interval %s",
                       format_address(ndo, address), txcost, format_interval(interval)));
                /* Extra data. */
                if((u_int)rc < len - 6)
                    subtlvs_print(ndo, message + 8 + rc, message + 2 + len,
                                  type);
            }
        }
            break;

        case MESSAGE_ROUTER_ID: {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " router-id"));
            else {
                ND_PRINT((ndo, "\n\tRouter Id"));
                if(len < 10) goto invalid;
                ND_PRINT((ndo, " %s", format_id(message + 4)));
            }
        }
            break;

        case MESSAGE_NH: {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " nh"));
            else {
                int rc;
                u_char nh[16];
                ND_PRINT((ndo, "\n\tNext Hop"));
                if(len < 2) goto invalid;
                rc = network_address(message[2], message + 4, len - 2, nh);
                if(rc < 0) goto invalid;
                ND_PRINT((ndo, " %s", format_address(ndo, nh)));
            }
        }
            break;

         case MESSAGE_UPDATE: {
             if (!ndo->ndo_vflag) {
                 ND_PRINT((ndo, " update"));
                if(len < 1)
                     ND_PRINT((ndo, "/truncated"));
                 else
                     ND_PRINT((ndo, "%s%s%s",
                           (message[3] & 0x80) ? "/prefix": "",
                           (message[3] & 0x40) ? "/id" : "",
                           (message[3] & 0x3f) ? "/unknown" : ""));
            } else {
                u_short interval, seqno, metric;
                u_char plen;
                int rc;
                u_char prefix[16];
                ND_PRINT((ndo, "\n\tUpdate"));
                if(len < 10) goto invalid;
                plen = message[4] + (message[2] == 1 ? 96 : 0);
                rc = network_prefix(message[2], message[4], message[5],
                                    message + 12,
                                    message[2] == 1 ? v4_prefix : v6_prefix,
                                    len - 10, prefix);
                if(rc < 0) goto invalid;
                interval = EXTRACT_16BITS(message + 6);
                seqno = EXTRACT_16BITS(message + 8);
                metric = EXTRACT_16BITS(message + 10);
                ND_PRINT((ndo, "%s%s%s %s metric %u seqno %u interval %s",
                       (message[3] & 0x80) ? "/prefix": "",
                       (message[3] & 0x40) ? "/id" : "",
                       (message[3] & 0x3f) ? "/unknown" : "",
                       format_prefix(ndo, prefix, plen),
                       metric, seqno, format_interval_update(interval)));
                if(message[3] & 0x80) {
                    if(message[2] == 1)
                        memcpy(v4_prefix, prefix, 16);
                    else
                        memcpy(v6_prefix, prefix, 16);
                }
                /* extra data? */
                if((u_int)rc < len - 10)
                    subtlvs_print(ndo, message + 12 + rc, message + 2 + len, type);
            }
        }
            break;

        case MESSAGE_REQUEST: {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " request"));
            else {
                int rc;
                u_char prefix[16], plen;
                ND_PRINT((ndo, "\n\tRequest "));
                if(len < 2) goto invalid;
                plen = message[3] + (message[2] == 1 ? 96 : 0);
                rc = network_prefix(message[2], message[3], 0,
                                    message + 4, NULL, len - 2, prefix);
                if(rc < 0) goto invalid;
                ND_PRINT((ndo, "for %s",
                       message[2] == 0 ? "any" : format_prefix(ndo, prefix, plen)));
            }
        }
            break;

        case MESSAGE_MH_REQUEST : {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " mh-request"));
            else {
                int rc;
                u_short seqno;
                u_char prefix[16], plen;
                ND_PRINT((ndo, "\n\tMH-Request "));
                if(len < 14) goto invalid;
                seqno = EXTRACT_16BITS(message + 4);
                rc = network_prefix(message[2], message[3], 0,
                                    message + 16, NULL, len - 14, prefix);
                if(rc < 0) goto invalid;
                plen = message[3] + (message[2] == 1 ? 96 : 0);
                ND_PRINT((ndo, "(%u hops) for %s seqno %u id %s",
                       message[6], format_prefix(ndo, prefix, plen),
                       seqno, format_id(message + 8)));
            }
        }
            break;
        case MESSAGE_TSPC :
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " tspc"));
            else {
                ND_PRINT((ndo, "\n\tTS/PC "));
                if(len < 6) goto invalid;
                ND_PRINT((ndo, "timestamp %u packetcounter %u", EXTRACT_32BITS (message + 4),
                       EXTRACT_16BITS(message + 2)));
            }
            break;
        case MESSAGE_HMAC : {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " hmac"));
            else {
                unsigned j;
                ND_PRINT((ndo, "\n\tHMAC "));
                if(len < 18) goto invalid;
                ND_PRINT((ndo, "key-id %u digest-%u ", EXTRACT_16BITS(message + 2), len - 2));
                for (j = 0; j < len - 2; j++)
                    ND_PRINT((ndo, "%02X", message[4 + j]));
            }
        }
            break;

        case MESSAGE_UPDATE_SRC_SPECIFIC : {
            if(!ndo->ndo_vflag) {
                ND_PRINT((ndo, " ss-update"));
            } else {
                u_char prefix[16], src_prefix[16];
                u_short interval, seqno, metric;
                u_char ae, plen, src_plen, omitted;
                int rc;
                int parsed_len = 10;
                ND_PRINT((ndo, "\n\tSS-Update"));
                if(len < 10) goto invalid;
                ae = message[2];
                src_plen = message[3];
                plen = message[4];
                omitted = message[5];
                interval = EXTRACT_16BITS(message + 6);
                seqno = EXTRACT_16BITS(message + 8);
                metric = EXTRACT_16BITS(message + 10);
                rc = network_prefix(ae, plen, omitted, message + 2 + parsed_len,
                                    ae == 1 ? v4_prefix : v6_prefix,
                                    len - parsed_len, prefix);
                if(rc < 0) goto invalid;
                if(ae == 1)
                    plen += 96;
                parsed_len += rc;
                rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
                                    NULL, len - parsed_len, src_prefix);
                if(rc < 0) goto invalid;
                if(ae == 1)
                    src_plen += 96;
                parsed_len += rc;

                ND_PRINT((ndo, " %s from", format_prefix(ndo, prefix, plen)));
                ND_PRINT((ndo, " %s metric %u seqno %u interval %s",
                          format_prefix(ndo, src_prefix, src_plen),
                          metric, seqno, format_interval_update(interval)));
                /* extra data? */
                if((u_int)parsed_len < len)
                    subtlvs_print(ndo, message + 2 + parsed_len,
                                  message + 2 + len, type);
            }
        }
            break;

        case MESSAGE_REQUEST_SRC_SPECIFIC : {
            if(!ndo->ndo_vflag)
                ND_PRINT((ndo, " ss-request"));
            else {
                int rc, parsed_len = 3;
                u_char ae, plen, src_plen, prefix[16], src_prefix[16];
                ND_PRINT((ndo, "\n\tSS-Request "));
                if(len < 3) goto invalid;
                ae = message[2];
                plen = message[3];
                src_plen = message[4];
                rc = network_prefix(ae, plen, 0, message + 2 + parsed_len,
                                    NULL, len - parsed_len, prefix);
                if(rc < 0) goto invalid;
                if(ae == 1)
                    plen += 96;
                parsed_len += rc;
                rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
                                    NULL, len - parsed_len, src_prefix);
                if(rc < 0) goto invalid;
                if(ae == 1)
                    src_plen += 96;
                parsed_len += rc;
                if(ae == 0) {
                    ND_PRINT((ndo, "for any"));
                } else {
                    ND_PRINT((ndo, "for (%s, ", format_prefix(ndo, prefix, plen)));
                    ND_PRINT((ndo, "%s)", format_prefix(ndo, src_prefix, src_plen)));
                }
            }
        }
            break;

        case MESSAGE_MH_REQUEST_SRC_SPECIFIC : {
            if(!ndo->ndo_vflag)
                ND_PRINT((ndo, " ss-mh-request"));
            else {
                int rc, parsed_len = 14;
                u_short seqno;
                u_char ae, plen, src_plen, prefix[16], src_prefix[16], hopc;
                const u_char *router_id = NULL;
                ND_PRINT((ndo, "\n\tSS-MH-Request "));
                if(len < 14) goto invalid;
                ae = message[2];
                plen = message[3];
                seqno = EXTRACT_16BITS(message + 4);
                hopc = message[6];
                src_plen = message[7];
                router_id = message + 8;
                rc = network_prefix(ae, plen, 0, message + 2 + parsed_len,
                                    NULL, len - parsed_len, prefix);
                if(rc < 0) goto invalid;
                if(ae == 1)
                    plen += 96;
                parsed_len += rc;
                rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
                                    NULL, len - parsed_len, src_prefix);
                if(rc < 0) goto invalid;
                if(ae == 1)
                    src_plen += 96;
                ND_PRINT((ndo, "(%u hops) for (%s, ",
                          hopc, format_prefix(ndo, prefix, plen)));
                ND_PRINT((ndo, "%s) seqno %u id %s",
                          format_prefix(ndo, src_prefix, src_plen),
                          seqno, format_id(router_id)));
            }
        }
            break;

        default:
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " unknown"));
            else
                ND_PRINT((ndo, "\n\tUnknown message type %d", type));
        }
        i += len + 2;
    }
    return;

 trunc:
    ND_PRINT((ndo, " %s", tstr));
    return;

 invalid:
    ND_PRINT((ndo, "%s", istr));
    return;
}

The Babel parser in tcpdump before 4.9.3 has a buffer over-read in print-babel.c:babel_print_v2().


babel_print_v2(netdissect_options *ndo,
               const u_char *cp, u_int length)
{
    u_int i;
    u_short bodylen;
    u_char v4_prefix[16] =
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
    u_char v6_prefix[16] = {0};

    ND_TCHECK2(*cp, 4);
    if (length < 4)
        goto invalid;
    bodylen = EXTRACT_16BITS(cp + 2);
    ND_PRINT((ndo, " (%u)", bodylen));

    /* Process the TLVs in the body */
    i = 0;
    while(i < bodylen) {
        const u_char *message;
        u_int type, len;

        message = cp + 4 + i;

        ND_TCHECK2(*message, 1);
        if((type = message[0]) == MESSAGE_PAD1) {
            ND_PRINT((ndo, ndo->ndo_vflag ? "\n\tPad 1" : " pad1"));
            i += 1;
            continue;
        }

        ND_TCHECK2(*message, 2);
        ICHECK(i, 2);
        len = message[1];

        ND_TCHECK2(*message, 2 + len);
        ICHECK(i, 2 + len);

        switch(type) {
        case MESSAGE_PADN: {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " padN"));
            else
                ND_PRINT((ndo, "\n\tPad %d", len + 2));
        }
            break;

        case MESSAGE_ACK_REQ: {
            u_short nonce, interval;
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " ack-req"));
            else {
                ND_PRINT((ndo, "\n\tAcknowledgment Request "));
                if(len < 6) goto invalid;
                nonce = EXTRACT_16BITS(message + 4);
                interval = EXTRACT_16BITS(message + 6);
                ND_PRINT((ndo, "%04x %s", nonce, format_interval(interval)));
            }
        }
            break;

        case MESSAGE_ACK: {
            u_short nonce;
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " ack"));
            else {
                ND_PRINT((ndo, "\n\tAcknowledgment "));
                if(len < 2) goto invalid;
                nonce = EXTRACT_16BITS(message + 2);
                ND_PRINT((ndo, "%04x", nonce));
            }
        }
            break;

        case MESSAGE_HELLO:  {
            u_short seqno, interval;
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " hello"));
            else {
                ND_PRINT((ndo, "\n\tHello "));
                if(len < 6) goto invalid;
                seqno = EXTRACT_16BITS(message + 4);
                interval = EXTRACT_16BITS(message + 6);
                ND_PRINT((ndo, "seqno %u interval %s", seqno, format_interval(interval)));
                /* Extra data. */
                if(len > 6)
                    subtlvs_print(ndo, message + 8, message + 2 + len, type);
            }
        }
            break;

        case MESSAGE_IHU: {
            unsigned short txcost, interval;
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " ihu"));
            else {
                u_char address[16];
                int rc;
                ND_PRINT((ndo, "\n\tIHU "));
                if(len < 6) goto invalid;
                txcost = EXTRACT_16BITS(message + 4);
                interval = EXTRACT_16BITS(message + 6);
                rc = network_address(message[2], message + 8, len - 6, address);
                if(rc < 0) { ND_PRINT((ndo, "%s", tstr)); break; }
                ND_PRINT((ndo, "%s txcost %u interval %s",
                       format_address(ndo, address), txcost, format_interval(interval)));
                /* Extra data. */
                if((u_int)rc < len - 6)
                    subtlvs_print(ndo, message + 8 + rc, message + 2 + len,
                                  type);
            }
        }
            break;

        case MESSAGE_ROUTER_ID: {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " router-id"));
            else {
                ND_PRINT((ndo, "\n\tRouter Id"));
                if(len < 10) goto invalid;
                ND_PRINT((ndo, " %s", format_id(message + 4)));
            }
        }
            break;

        case MESSAGE_NH: {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " nh"));
            else {
                int rc;
                u_char nh[16];
                ND_PRINT((ndo, "\n\tNext Hop"));
                if(len < 2) goto invalid;
                rc = network_address(message[2], message + 4, len - 2, nh);
                if(rc < 0) goto invalid;
                ND_PRINT((ndo, " %s", format_address(ndo, nh)));
            }
        }
            break;

         case MESSAGE_UPDATE: {
             if (!ndo->ndo_vflag) {
                 ND_PRINT((ndo, " update"));
                if(len < 10)
                     ND_PRINT((ndo, "/truncated"));
                 else
                     ND_PRINT((ndo, "%s%s%s",
                           (message[3] & 0x80) ? "/prefix": "",
                           (message[3] & 0x40) ? "/id" : "",
                           (message[3] & 0x3f) ? "/unknown" : ""));
            } else {
                u_short interval, seqno, metric;
                u_char plen;
                int rc;
                u_char prefix[16];
                ND_PRINT((ndo, "\n\tUpdate"));
                if(len < 10) goto invalid;
                plen = message[4] + (message[2] == 1 ? 96 : 0);
                rc = network_prefix(message[2], message[4], message[5],
                                    message + 12,
                                    message[2] == 1 ? v4_prefix : v6_prefix,
                                    len - 10, prefix);
                if(rc < 0) goto invalid;
                interval = EXTRACT_16BITS(message + 6);
                seqno = EXTRACT_16BITS(message + 8);
                metric = EXTRACT_16BITS(message + 10);
                ND_PRINT((ndo, "%s%s%s %s metric %u seqno %u interval %s",
                       (message[3] & 0x80) ? "/prefix": "",
                       (message[3] & 0x40) ? "/id" : "",
                       (message[3] & 0x3f) ? "/unknown" : "",
                       format_prefix(ndo, prefix, plen),
                       metric, seqno, format_interval_update(interval)));
                if(message[3] & 0x80) {
                    if(message[2] == 1)
                        memcpy(v4_prefix, prefix, 16);
                    else
                        memcpy(v6_prefix, prefix, 16);
                }
                /* extra data? */
                if((u_int)rc < len - 10)
                    subtlvs_print(ndo, message + 12 + rc, message + 2 + len, type);
            }
        }
            break;

        case MESSAGE_REQUEST: {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " request"));
            else {
                int rc;
                u_char prefix[16], plen;
                ND_PRINT((ndo, "\n\tRequest "));
                if(len < 2) goto invalid;
                plen = message[3] + (message[2] == 1 ? 96 : 0);
                rc = network_prefix(message[2], message[3], 0,
                                    message + 4, NULL, len - 2, prefix);
                if(rc < 0) goto invalid;
                ND_PRINT((ndo, "for %s",
                       message[2] == 0 ? "any" : format_prefix(ndo, prefix, plen)));
            }
        }
            break;

        case MESSAGE_MH_REQUEST : {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " mh-request"));
            else {
                int rc;
                u_short seqno;
                u_char prefix[16], plen;
                ND_PRINT((ndo, "\n\tMH-Request "));
                if(len < 14) goto invalid;
                seqno = EXTRACT_16BITS(message + 4);
                rc = network_prefix(message[2], message[3], 0,
                                    message + 16, NULL, len - 14, prefix);
                if(rc < 0) goto invalid;
                plen = message[3] + (message[2] == 1 ? 96 : 0);
                ND_PRINT((ndo, "(%u hops) for %s seqno %u id %s",
                       message[6], format_prefix(ndo, prefix, plen),
                       seqno, format_id(message + 8)));
            }
        }
            break;
        case MESSAGE_TSPC :
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " tspc"));
            else {
                ND_PRINT((ndo, "\n\tTS/PC "));
                if(len < 6) goto invalid;
                ND_PRINT((ndo, "timestamp %u packetcounter %u", EXTRACT_32BITS (message + 4),
                       EXTRACT_16BITS(message + 2)));
            }
            break;
        case MESSAGE_HMAC : {
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " hmac"));
            else {
                unsigned j;
                ND_PRINT((ndo, "\n\tHMAC "));
                if(len < 18) goto invalid;
                ND_PRINT((ndo, "key-id %u digest-%u ", EXTRACT_16BITS(message + 2), len - 2));
                for (j = 0; j < len - 2; j++)
                    ND_PRINT((ndo, "%02X", message[4 + j]));
            }
        }
            break;

        case MESSAGE_UPDATE_SRC_SPECIFIC : {
            if(!ndo->ndo_vflag) {
                ND_PRINT((ndo, " ss-update"));
            } else {
                u_char prefix[16], src_prefix[16];
                u_short interval, seqno, metric;
                u_char ae, plen, src_plen, omitted;
                int rc;
                int parsed_len = 10;
                ND_PRINT((ndo, "\n\tSS-Update"));
                if(len < 10) goto invalid;
                ae = message[2];
                src_plen = message[3];
                plen = message[4];
                omitted = message[5];
                interval = EXTRACT_16BITS(message + 6);
                seqno = EXTRACT_16BITS(message + 8);
                metric = EXTRACT_16BITS(message + 10);
                rc = network_prefix(ae, plen, omitted, message + 2 + parsed_len,
                                    ae == 1 ? v4_prefix : v6_prefix,
                                    len - parsed_len, prefix);
                if(rc < 0) goto invalid;
                if(ae == 1)
                    plen += 96;
                parsed_len += rc;
                rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
                                    NULL, len - parsed_len, src_prefix);
                if(rc < 0) goto invalid;
                if(ae == 1)
                    src_plen += 96;
                parsed_len += rc;

                ND_PRINT((ndo, " %s from", format_prefix(ndo, prefix, plen)));
                ND_PRINT((ndo, " %s metric %u seqno %u interval %s",
                          format_prefix(ndo, src_prefix, src_plen),
                          metric, seqno, format_interval_update(interval)));
                /* extra data? */
                if((u_int)parsed_len < len)
                    subtlvs_print(ndo, message + 2 + parsed_len,
                                  message + 2 + len, type);
            }
        }
            break;

        case MESSAGE_REQUEST_SRC_SPECIFIC : {
            if(!ndo->ndo_vflag)
                ND_PRINT((ndo, " ss-request"));
            else {
                int rc, parsed_len = 3;
                u_char ae, plen, src_plen, prefix[16], src_prefix[16];
                ND_PRINT((ndo, "\n\tSS-Request "));
                if(len < 3) goto invalid;
                ae = message[2];
                plen = message[3];
                src_plen = message[4];
                rc = network_prefix(ae, plen, 0, message + 2 + parsed_len,
                                    NULL, len - parsed_len, prefix);
                if(rc < 0) goto invalid;
                if(ae == 1)
                    plen += 96;
                parsed_len += rc;
                rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
                                    NULL, len - parsed_len, src_prefix);
                if(rc < 0) goto invalid;
                if(ae == 1)
                    src_plen += 96;
                parsed_len += rc;
                if(ae == 0) {
                    ND_PRINT((ndo, "for any"));
                } else {
                    ND_PRINT((ndo, "for (%s, ", format_prefix(ndo, prefix, plen)));
                    ND_PRINT((ndo, "%s)", format_prefix(ndo, src_prefix, src_plen)));
                }
            }
        }
            break;

        case MESSAGE_MH_REQUEST_SRC_SPECIFIC : {
            if(!ndo->ndo_vflag)
                ND_PRINT((ndo, " ss-mh-request"));
            else {
                int rc, parsed_len = 14;
                u_short seqno;
                u_char ae, plen, src_plen, prefix[16], src_prefix[16], hopc;
                const u_char *router_id = NULL;
                ND_PRINT((ndo, "\n\tSS-MH-Request "));
                if(len < 14) goto invalid;
                ae = message[2];
                plen = message[3];
                seqno = EXTRACT_16BITS(message + 4);
                hopc = message[6];
                src_plen = message[7];
                router_id = message + 8;
                rc = network_prefix(ae, plen, 0, message + 2 + parsed_len,
                                    NULL, len - parsed_len, prefix);
                if(rc < 0) goto invalid;
                if(ae == 1)
                    plen += 96;
                parsed_len += rc;
                rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
                                    NULL, len - parsed_len, src_prefix);
                if(rc < 0) goto invalid;
                if(ae == 1)
                    src_plen += 96;
                ND_PRINT((ndo, "(%u hops) for (%s, ",
                          hopc, format_prefix(ndo, prefix, plen)));
                ND_PRINT((ndo, "%s) seqno %u id %s",
                          format_prefix(ndo, src_prefix, src_plen),
                          seqno, format_id(router_id)));
            }
        }
            break;

        default:
            if (!ndo->ndo_vflag)
                ND_PRINT((ndo, " unknown"));
            else
                ND_PRINT((ndo, "\n\tUnknown message type %d", type));
        }
        i += len + 2;
    }
    return;

 trunc:
    ND_PRINT((ndo, " %s", tstr));
    return;

 invalid:
    ND_PRINT((ndo, "%s", istr));
    return;
}


(for 4.9.3) CVE-2018-14469/ISAKMP: Add a missing bounds check

In ikev1_n_print() check bounds before trying to fetch the replay detection
status.

This fixes a buffer over-read discovered by Bhargava Shastry.

Add a test using the capture file supplied by the reporter(s).

ikev1_n_print(netdissect_options *ndo, u_char tpay _U_,
	      const struct isakmp_gen *ext, u_int item_len,
	      const u_char *ep, uint32_t phase _U_, uint32_t doi0 _U_,
	      uint32_t proto0 _U_, int depth _U_)
{
	const struct ikev1_pl_n *p;
	struct ikev1_pl_n n;
	const u_char *cp;
	const u_char *ep2;
	uint32_t doi;
	uint32_t proto;
	static const char *notify_error_str[] = {
		NULL,				"INVALID-PAYLOAD-TYPE",
		"DOI-NOT-SUPPORTED",		"SITUATION-NOT-SUPPORTED",
		"INVALID-COOKIE",		"INVALID-MAJOR-VERSION",
		"INVALID-MINOR-VERSION",	"INVALID-EXCHANGE-TYPE",
		"INVALID-FLAGS",		"INVALID-MESSAGE-ID",
		"INVALID-PROTOCOL-ID",		"INVALID-SPI",
		"INVALID-TRANSFORM-ID",		"ATTRIBUTES-NOT-SUPPORTED",
		"NO-PROPOSAL-CHOSEN",		"BAD-PROPOSAL-SYNTAX",
		"PAYLOAD-MALFORMED",		"INVALID-KEY-INFORMATION",
		"INVALID-ID-INFORMATION",	"INVALID-CERT-ENCODING",
		"INVALID-CERTIFICATE",		"CERT-TYPE-UNSUPPORTED",
		"INVALID-CERT-AUTHORITY",	"INVALID-HASH-INFORMATION",
		"AUTHENTICATION-FAILED",	"INVALID-SIGNATURE",
		"ADDRESS-NOTIFICATION",		"NOTIFY-SA-LIFETIME",
		"CERTIFICATE-UNAVAILABLE",	"UNSUPPORTED-EXCHANGE-TYPE",
		"UNEQUAL-PAYLOAD-LENGTHS",
	};
	static const char *ipsec_notify_error_str[] = {
		"RESERVED",
	};
	static const char *notify_status_str[] = {
		"CONNECTED",
	};
	static const char *ipsec_notify_status_str[] = {
		"RESPONDER-LIFETIME",		"REPLAY-STATUS",
		"INITIAL-CONTACT",
	};
/* NOTE: these macro must be called with x in proper range */

/* 0 - 8191 */
#define NOTIFY_ERROR_STR(x) \
	STR_OR_ID((x), notify_error_str)

/* 8192 - 16383 */
#define IPSEC_NOTIFY_ERROR_STR(x) \
	STR_OR_ID((u_int)((x) - 8192), ipsec_notify_error_str)

/* 16384 - 24575 */
#define NOTIFY_STATUS_STR(x) \
	STR_OR_ID((u_int)((x) - 16384), notify_status_str)

/* 24576 - 32767 */
#define IPSEC_NOTIFY_STATUS_STR(x) \
	STR_OR_ID((u_int)((x) - 24576), ipsec_notify_status_str)

	ND_PRINT((ndo,"%s:", NPSTR(ISAKMP_NPTYPE_N)));

	p = (const struct ikev1_pl_n *)ext;
	ND_TCHECK(*p);
	UNALIGNED_MEMCPY(&n, ext, sizeof(n));
	doi = ntohl(n.doi);
	proto = n.prot_id;
	if (doi != 1) {
		ND_PRINT((ndo," doi=%d", doi));
		ND_PRINT((ndo," proto=%d", proto));
		if (ntohs(n.type) < 8192)
			ND_PRINT((ndo," type=%s", NOTIFY_ERROR_STR(ntohs(n.type))));
		else if (ntohs(n.type) < 16384)
			ND_PRINT((ndo," type=%s", numstr(ntohs(n.type))));
		else if (ntohs(n.type) < 24576)
			ND_PRINT((ndo," type=%s", NOTIFY_STATUS_STR(ntohs(n.type))));
		else
			ND_PRINT((ndo," type=%s", numstr(ntohs(n.type))));
		if (n.spi_size) {
			ND_PRINT((ndo," spi="));
			if (!rawprint(ndo, (const uint8_t *)(p + 1), n.spi_size))
				goto trunc;
		}
		return (const u_char *)(p + 1) + n.spi_size;
	}

	ND_PRINT((ndo," doi=ipsec"));
	ND_PRINT((ndo," proto=%s", PROTOIDSTR(proto)));
	if (ntohs(n.type) < 8192)
		ND_PRINT((ndo," type=%s", NOTIFY_ERROR_STR(ntohs(n.type))));
	else if (ntohs(n.type) < 16384)
		ND_PRINT((ndo," type=%s", IPSEC_NOTIFY_ERROR_STR(ntohs(n.type))));
	else if (ntohs(n.type) < 24576)
		ND_PRINT((ndo," type=%s", NOTIFY_STATUS_STR(ntohs(n.type))));
	else if (ntohs(n.type) < 32768)
		ND_PRINT((ndo," type=%s", IPSEC_NOTIFY_STATUS_STR(ntohs(n.type))));
	else
		ND_PRINT((ndo," type=%s", numstr(ntohs(n.type))));
	if (n.spi_size) {
		ND_PRINT((ndo," spi="));
		if (!rawprint(ndo, (const uint8_t *)(p + 1), n.spi_size))
			goto trunc;
	}

	cp = (const u_char *)(p + 1) + n.spi_size;
	ep2 = (const u_char *)p + item_len;

	if (cp < ep) {
		switch (ntohs(n.type)) {
		case IPSECDOI_NTYPE_RESPONDER_LIFETIME:
		    {
			const struct attrmap *map = oakley_t_map;
			size_t nmap = sizeof(oakley_t_map)/sizeof(oakley_t_map[0]);
			ND_PRINT((ndo," attrs=("));
			while (cp < ep && cp < ep2) {
				cp = ikev1_attrmap_print(ndo, cp, ep2, map, nmap);
				if (cp == NULL) {
					ND_PRINT((ndo,")"));
					goto trunc;
				}
			}
			ND_PRINT((ndo,")"));
			break;
 		    }
 		case IPSECDOI_NTYPE_REPLAY_STATUS:
 			ND_PRINT((ndo," status=("));
 			ND_PRINT((ndo,"replay detection %sabled",
 				  EXTRACT_32BITS(cp) ? "en" : "dis"));
 			ND_PRINT((ndo,")"));
			break;
		default:
			/*
			 * XXX - fill in more types here; see, for example,
			 * draft-ietf-ipsec-notifymsg-04.
			 */
			if (ndo->ndo_vflag > 3) {
				ND_PRINT((ndo," data=("));
				if (!rawprint(ndo, (const uint8_t *)(cp), ep - cp))
					goto trunc;
				ND_PRINT((ndo,")"));
			} else {
				if (!ike_show_somedata(ndo, cp, ep))
					goto trunc;
			}
			break;
		}
	}
	return (const u_char *)ext + item_len;
trunc:
	ND_PRINT((ndo," [|%s]", NPSTR(ISAKMP_NPTYPE_N)));
	return NULL;
}

The IKEv1 parser in tcpdump before 4.9.3 has a buffer over-read in print-isakmp.c:ikev1_n_print().