rdpdr_process(STREAM s)
{
	uint32 handle;
 	uint16 vmin;
 	uint16 component;
 	uint16 pakid;
	struct stream packet = *s;

 	logger(Protocol, Debug, "rdpdr_process()");
 	/* hexdump(s->p, s->end - s->p); */

	in_uint16(s, component);
	in_uint16(s, pakid);

	if (component == RDPDR_CTYP_CORE)
	{
		switch (pakid)
		{
			case PAKID_CORE_DEVICE_IOREQUEST:
				rdpdr_process_irp(s);
				break;

			case PAKID_CORE_SERVER_ANNOUNCE:
 				/* DR_CORE_SERVER_ANNOUNCE_REQ */
 				in_uint8s(s, 2);	/* skip versionMajor */
 				in_uint16_le(s, vmin);	/* VersionMinor */

 				in_uint32_le(s, g_client_id);	/* ClientID */

				/* g_client_id is sent back to server,
				   so lets check that we actually got
				   valid data from stream to prevent
				   that we leak back data to server */
				if (!s_check(s))
				{
					rdp_protocol_error("rdpdr_process(), consume of g_client_id from stream did overrun", &packet);
				}

 				/* The RDP client is responsibility to provide a random client id
 				   if server version is < 12 */
 				if (vmin < 0x000c)
					g_client_id = 0x815ed39d;	/* IP address (use 127.0.0.1) 0x815ed39d */
				g_epoch++;

#if WITH_SCARD
				/*
				 * We need to release all SCARD contexts to end all
				 * current transactions and pending calls
				 */
				scard_release_all_contexts();

				/*
				 * According to [MS-RDPEFS] 3.2.5.1.2:
				 *
				 * If this packet appears after a sequence of other packets,
				 * it is a signal that the server has reconnected to a new session
				 * and the whole sequence has been reset. The client MUST treat
				 * this packet as the beginning of a new sequence.
				 * The client MUST also cancel all outstanding requests and release
				 * previous references to all devices.
				 *
				 * If any problem arises in the future, please, pay attention to the
				 * "If this packet appears after a sequence of other packets" part
				 *
				 */

#endif

				rdpdr_send_client_announce_reply();
				rdpdr_send_client_name_request();
				break;

			case PAKID_CORE_CLIENTID_CONFIRM:
				rdpdr_send_client_device_list_announce();
				break;

			case PAKID_CORE_DEVICE_REPLY:
				in_uint32(s, handle);
				logger(Protocol, Debug,
				       "rdpdr_process(), server connected to resource %d", handle);
				break;

			case PAKID_CORE_SERVER_CAPABILITY:
				rdpdr_send_client_capability_response();
				break;

			default:
				logger(Protocol, Debug,
				       "rdpdr_process(), pakid 0x%x of component 0x%x", pakid,
				       component);
				break;

		}
	}
	else if (component == RDPDR_CTYP_PRN)
	{
		if (pakid == PAKID_PRN_CACHE_DATA)
			printercache_process(s);
	}
	else
		logger(Protocol, Warning, "rdpdr_process(), unhandled component 0x%x", component);
}


Malicious RDP server security fixes

This commit includes fixes for a set of 21 vulnerabilities in
rdesktop when a malicious RDP server is used.

All vulnerabilities was identified and reported by Eyal Itkin.

 * Add rdp_protocol_error function that is used in several fixes
 * Refactor of process_bitmap_updates
 * Fix possible integer overflow in s_check_rem() on 32bit arch
 * Fix memory corruption in process_bitmap_data - CVE-2018-8794
 * Fix remote code execution in process_bitmap_data - CVE-2018-8795
 * Fix remote code execution in process_plane - CVE-2018-8797
 * Fix Denial of Service in mcs_recv_connect_response - CVE-2018-20175
 * Fix Denial of Service in mcs_parse_domain_params - CVE-2018-20175
 * Fix Denial of Service in sec_parse_crypt_info - CVE-2018-20176
 * Fix Denial of Service in sec_recv - CVE-2018-20176
 * Fix minor information leak in rdpdr_process - CVE-2018-8791
 * Fix Denial of Service in cssp_read_tsrequest - CVE-2018-8792
 * Fix remote code execution in cssp_read_tsrequest - CVE-2018-8793
 * Fix Denial of Service in process_bitmap_data - CVE-2018-8796
 * Fix minor information leak in rdpsnd_process_ping - CVE-2018-8798
 * Fix Denial of Service in process_secondary_order - CVE-2018-8799
 * Fix remote code execution in in ui_clip_handle_data - CVE-2018-8800
 * Fix major information leak in ui_clip_handle_data - CVE-2018-20174
 * Fix memory corruption in rdp_in_unistr - CVE-2018-20177
 * Fix Denial of Service in process_demand_active - CVE-2018-20178
 * Fix remote code execution in lspci_process - CVE-2018-20179
 * Fix remote code execution in rdpsnddbg_process - CVE-2018-20180
 * Fix remote code execution in seamless_process - CVE-2018-20181
 * Fix remote code execution in seamless_process_line - CVE-2018-20182

seamless_process(STREAM s)
 {
 	unsigned int pkglen;
 	char *buf;

 	pkglen = s->end - s->p;
 	/* str_handle_lines requires null terminated strings */
	buf = xmalloc(pkglen + 1);
	STRNCPY(buf, (char *) s->p, pkglen + 1);
	str_handle_lines(buf, &seamless_rest, seamless_line_handler, NULL);

	xfree(buf);
}

rdesktop versions up to and including v1.8.3 contain an Out-Of-Bounds Read in function process_secondary_order() that results in a Denial of Service (segfault).


seamless_process(STREAM s)
 {
 	unsigned int pkglen;
 	char *buf;
	struct stream packet = *s;

	if (!s_check(s))
	{
		rdp_protocol_error("seamless_process(), stream is in unstable state", &packet);
	}

 	pkglen = s->end - s->p;
 	/* str_handle_lines requires null terminated strings */
	buf = xmalloc(pkglen + 1);
	STRNCPY(buf, (char *) s->p, pkglen + 1);
	str_handle_lines(buf, &seamless_rest, seamless_line_handler, NULL);

	xfree(buf);
}


lspci_process(STREAM s)
{
 	unsigned int pkglen;
 	static char *rest = NULL;
 	char *buf;

 	pkglen = s->end - s->p;
 	/* str_handle_lines requires null terminated strings */
	buf = xmalloc(pkglen + 1);
	STRNCPY(buf, (char *) s->p, pkglen + 1);
	str_handle_lines(buf, &rest, lspci_process_line, NULL);
	xfree(buf);
}


lspci_process(STREAM s)
{
 	unsigned int pkglen;
 	static char *rest = NULL;
 	char *buf;
	struct stream packet = *s;

	if (!s_check(s))
	{
		rdp_protocol_error("lspci_process(), stream is in unstable state", &packet);
	}

 	pkglen = s->end - s->p;
 	/* str_handle_lines requires null terminated strings */
	buf = xmalloc(pkglen + 1);
	STRNCPY(buf, (char *) s->p, pkglen + 1);
	str_handle_lines(buf, &rest, lspci_process_line, NULL);
	xfree(buf);
}


process_secondary_order(STREAM s)
{
	/* The length isn't calculated correctly by the server.
	 * For very compact orders the length becomes negative
	 * so a signed integer must be used. */
	uint16 length;
 	uint16 flags;
 	uint8 type;
 	uint8 *next_order;

 	in_uint16_le(s, length);
 	in_uint16_le(s, flags);	/* used by bmpcache2 */
 	in_uint8(s, type);

 	next_order = s->p + (sint16) length + 7;

 	switch (type)
	{
		case RDP_ORDER_RAW_BMPCACHE:
			process_raw_bmpcache(s);
			break;

		case RDP_ORDER_COLCACHE:
			process_colcache(s);
			break;

		case RDP_ORDER_BMPCACHE:
			process_bmpcache(s);
			break;

		case RDP_ORDER_FONTCACHE:
			process_fontcache(s);
			break;

		case RDP_ORDER_RAW_BMPCACHE2:
			process_bmpcache2(s, flags, False);	/* uncompressed */
			break;

		case RDP_ORDER_BMPCACHE2:
			process_bmpcache2(s, flags, True);	/* compressed */
			break;

		case RDP_ORDER_BRUSHCACHE:
			process_brushcache(s, flags);
			break;

		default:
			logger(Graphics, Warning,
			       "process_secondary_order(), unhandled secondary order %d", type);
	}

	s->p = next_order;
}


process_secondary_order(STREAM s)
{
	/* The length isn't calculated correctly by the server.
	 * For very compact orders the length becomes negative
	 * so a signed integer must be used. */
	uint16 length;
 	uint16 flags;
 	uint8 type;
 	uint8 *next_order;
	struct stream packet = *s;

 	in_uint16_le(s, length);
 	in_uint16_le(s, flags);	/* used by bmpcache2 */
 	in_uint8(s, type);

	if (!s_check_rem(s, length + 7))
	{
		rdp_protocol_error("process_secondary_order(), next order pointer would overrun stream", &packet);
	}

 	next_order = s->p + (sint16) length + 7;

 	switch (type)
	{
		case RDP_ORDER_RAW_BMPCACHE:
			process_raw_bmpcache(s);
			break;

		case RDP_ORDER_COLCACHE:
			process_colcache(s);
			break;

		case RDP_ORDER_BMPCACHE:
			process_bmpcache(s);
			break;

		case RDP_ORDER_FONTCACHE:
			process_fontcache(s);
			break;

		case RDP_ORDER_RAW_BMPCACHE2:
			process_bmpcache2(s, flags, False);	/* uncompressed */
			break;

		case RDP_ORDER_BMPCACHE2:
			process_bmpcache2(s, flags, True);	/* compressed */
			break;

		case RDP_ORDER_BRUSHCACHE:
			process_brushcache(s, flags);
			break;

		default:
			logger(Graphics, Warning,
			       "process_secondary_order(), unhandled secondary order %d", type);
	}

	s->p = next_order;
}


rdpsnddbg_process(STREAM s)
{
	unsigned int pkglen;
 	static char *rest = NULL;
 	char *buf;

 	pkglen = s->end - s->p;
 	/* str_handle_lines requires null terminated strings */
 	buf = (char *) xmalloc(pkglen + 1);
	STRNCPY(buf, (char *) s->p, pkglen + 1);

	str_handle_lines(buf, &rest, rdpsnddbg_line_handler, NULL);

	xfree(buf);
}


rdpsnddbg_process(STREAM s)
{
	unsigned int pkglen;
 	static char *rest = NULL;
 	char *buf;

	if (!s_check(s))
	{
		rdp_protocol_error("rdpsnddbg_process(), stream is in unstable state", s);
	}

 	pkglen = s->end - s->p;
 	/* str_handle_lines requires null terminated strings */
 	buf = (char *) xmalloc(pkglen + 1);
	STRNCPY(buf, (char *) s->p, pkglen + 1);

	str_handle_lines(buf, &rest, rdpsnddbg_line_handler, NULL);

	xfree(buf);
}


(for 4.9.3) CVE-2018-16452/SMB: prevent stack exhaustion

Enforce a limit on how many times smb_fdata() can recurse.

This fixes a stack exhaustion discovered by Include Security working
under the Mozilla SOS program in 2018 by means of code audit.

smb_fdata(netdissect_options *ndo,
          const u_char *buf, const char *fmt, const u_char *maxbuf,
          int unicodestr)
{
    static int depth = 0;
    char s[128];
    char *p;

    while (*fmt) {
	switch (*fmt) {
	case '*':
	    fmt++;
 	    while (buf < maxbuf) {
 		const u_char *buf2;
 		depth++;
		buf2 = smb_fdata(ndo, buf, fmt, maxbuf, unicodestr);
 		depth--;
 		if (buf2 == NULL)
 		    return(NULL);
		if (buf2 == buf)
		    return(buf);
		buf = buf2;
	    }
	    return(buf);

	case '|':
	    fmt++;
	    if (buf >= maxbuf)
		return(buf);
	    break;

	case '%':
	    fmt++;
	    buf = maxbuf;
	    break;

	case '#':
	    fmt++;
	    return(buf);
	    break;

	case '[':
	    fmt++;
	    if (buf >= maxbuf)
		return(buf);
	    memset(s, 0, sizeof(s));
	    p = strchr(fmt, ']');
	    if ((size_t)(p - fmt + 1) > sizeof(s)) {
		/* overrun */
		return(buf);
	    }
	    strncpy(s, fmt, p - fmt);
	    s[p - fmt] = '\0';
	    fmt = p + 1;
	    buf = smb_fdata1(ndo, buf, s, maxbuf, unicodestr);
	    if (buf == NULL)
		return(NULL);
	    break;

	default:
	    ND_PRINT((ndo, "%c", *fmt));
	    fmt++;
	    break;
	}
    }
    if (!depth && buf < maxbuf) {
	size_t len = PTR_DIFF(maxbuf, buf);
	ND_PRINT((ndo, "Data: (%lu bytes)\n", (unsigned long)len));
	smb_print_data(ndo, buf, len);
	return(buf + len);
    }
    return(buf);
}

The SMB parser in tcpdump before 4.9.3 has stack exhaustion in smbutil.c:smb_fdata() via recursion.


smb_fdata(netdissect_options *ndo,
          const u_char *buf, const char *fmt, const u_char *maxbuf,
          int unicodestr)
{
    static int depth = 0;
    char s[128];
    char *p;

    while (*fmt) {
	switch (*fmt) {
	case '*':
	    fmt++;
 	    while (buf < maxbuf) {
 		const u_char *buf2;
 		depth++;
		/* Not sure how this relates with the protocol specification,
		 * but in order to avoid stack exhaustion recurse at most that
		 * many levels.
		 */
		if (depth == 10)
			ND_PRINT((ndo, "(too many nested levels, not recursing)"));
		else
			buf2 = smb_fdata(ndo, buf, fmt, maxbuf, unicodestr);
 		depth--;
 		if (buf2 == NULL)
 		    return(NULL);
		if (buf2 == buf)
		    return(buf);
		buf = buf2;
	    }
	    return(buf);

	case '|':
	    fmt++;
	    if (buf >= maxbuf)
		return(buf);
	    break;

	case '%':
	    fmt++;
	    buf = maxbuf;
	    break;

	case '#':
	    fmt++;
	    return(buf);
	    break;

	case '[':
	    fmt++;
	    if (buf >= maxbuf)
		return(buf);
	    memset(s, 0, sizeof(s));
	    p = strchr(fmt, ']');
	    if ((size_t)(p - fmt + 1) > sizeof(s)) {
		/* overrun */
		return(buf);
	    }
	    strncpy(s, fmt, p - fmt);
	    s[p - fmt] = '\0';
	    fmt = p + 1;
	    buf = smb_fdata1(ndo, buf, s, maxbuf, unicodestr);
	    if (buf == NULL)
		return(NULL);
	    break;

	default:
	    ND_PRINT((ndo, "%c", *fmt));
	    fmt++;
	    break;
	}
    }
    if (!depth && buf < maxbuf) {
	size_t len = PTR_DIFF(maxbuf, buf);
	ND_PRINT((ndo, "Data: (%lu bytes)\n", (unsigned long)len));
	smb_print_data(ndo, buf, len);
	return(buf + len);
    }
    return(buf);
}


(for 4.9.3) SMB: Add two missing bounds checks

print_trans(netdissect_options *ndo,
            const u_char *words, const u_char *data1, const u_char *buf, const u_char *maxbuf)
{
    u_int bcc;
    const char *f1, *f2, *f3, *f4;
    const u_char *data, *param;
    const u_char *w = words + 1;
    int datalen, paramlen;

    if (request) {
	ND_TCHECK2(w[12 * 2], 2);
	paramlen = EXTRACT_LE_16BITS(w + 9 * 2);
	param = buf + EXTRACT_LE_16BITS(w + 10 * 2);
	datalen = EXTRACT_LE_16BITS(w + 11 * 2);
	data = buf + EXTRACT_LE_16BITS(w + 12 * 2);
	f1 = "TotParamCnt=[d] \nTotDataCnt=[d] \nMaxParmCnt=[d] \nMaxDataCnt=[d]\nMaxSCnt=[d] \nTransFlags=[w] \nRes1=[w] \nRes2=[w] \nRes3=[w]\nParamCnt=[d] \nParamOff=[d] \nDataCnt=[d] \nDataOff=[d] \nSUCnt=[d]\n";
	f2 = "|Name=[S]\n";
	f3 = "|Param ";
	f4 = "|Data ";
    } else {
	ND_TCHECK2(w[7 * 2], 2);
	paramlen = EXTRACT_LE_16BITS(w + 3 * 2);
	param = buf + EXTRACT_LE_16BITS(w + 4 * 2);
	datalen = EXTRACT_LE_16BITS(w + 6 * 2);
	data = buf + EXTRACT_LE_16BITS(w + 7 * 2);
	f1 = "TotParamCnt=[d] \nTotDataCnt=[d] \nRes1=[d]\nParamCnt=[d] \nParamOff=[d] \nRes2=[d] \nDataCnt=[d] \nDataOff=[d] \nRes3=[d]\nLsetup=[d]\n";
	f2 = "|Unknown ";
	f3 = "|Param ";
	f4 = "|Data ";
    }

    smb_fdata(ndo, words + 1, f1, min(words + 1 + 2 * words[0], maxbuf),
        unicodestr);

    ND_TCHECK2(*data1, 2);
    bcc = EXTRACT_LE_16BITS(data1);
     ND_PRINT((ndo, "smb_bcc=%u\n", bcc));
     if (bcc > 0) {
 	smb_fdata(ndo, data1 + 2, f2, maxbuf - (paramlen + datalen), unicodestr);
	if (strcmp((const char *)(data1 + 2), "\\MAILSLOT\\BROWSE") == 0) {
 	    print_browse(ndo, param, paramlen, data, datalen);
 	    return;
 	}

	if (strcmp((const char *)(data1 + 2), "\\PIPE\\LANMAN") == 0) {
 	    print_ipc(ndo, param, paramlen, data, datalen);
 	    return;
 	}

 	if (paramlen)
 	    smb_fdata(ndo, param, f3, min(param + paramlen, maxbuf), unicodestr);
	if (datalen)
	    smb_fdata(ndo, data, f4, min(data + datalen, maxbuf), unicodestr);
    }
    return;
trunc:
    ND_PRINT((ndo, "%s", tstr));
}

The SMB parser in tcpdump before 4.9.3 has buffer over-reads in print-smb.c:print_trans() for \MAILSLOT\BROWSE and \PIPE\LANMAN.


print_trans(netdissect_options *ndo,
            const u_char *words, const u_char *data1, const u_char *buf, const u_char *maxbuf)
{
    u_int bcc;
    const char *f1, *f2, *f3, *f4;
    const u_char *data, *param;
    const u_char *w = words + 1;
    int datalen, paramlen;

    if (request) {
	ND_TCHECK2(w[12 * 2], 2);
	paramlen = EXTRACT_LE_16BITS(w + 9 * 2);
	param = buf + EXTRACT_LE_16BITS(w + 10 * 2);
	datalen = EXTRACT_LE_16BITS(w + 11 * 2);
	data = buf + EXTRACT_LE_16BITS(w + 12 * 2);
	f1 = "TotParamCnt=[d] \nTotDataCnt=[d] \nMaxParmCnt=[d] \nMaxDataCnt=[d]\nMaxSCnt=[d] \nTransFlags=[w] \nRes1=[w] \nRes2=[w] \nRes3=[w]\nParamCnt=[d] \nParamOff=[d] \nDataCnt=[d] \nDataOff=[d] \nSUCnt=[d]\n";
	f2 = "|Name=[S]\n";
	f3 = "|Param ";
	f4 = "|Data ";
    } else {
	ND_TCHECK2(w[7 * 2], 2);
	paramlen = EXTRACT_LE_16BITS(w + 3 * 2);
	param = buf + EXTRACT_LE_16BITS(w + 4 * 2);
	datalen = EXTRACT_LE_16BITS(w + 6 * 2);
	data = buf + EXTRACT_LE_16BITS(w + 7 * 2);
	f1 = "TotParamCnt=[d] \nTotDataCnt=[d] \nRes1=[d]\nParamCnt=[d] \nParamOff=[d] \nRes2=[d] \nDataCnt=[d] \nDataOff=[d] \nRes3=[d]\nLsetup=[d]\n";
	f2 = "|Unknown ";
	f3 = "|Param ";
	f4 = "|Data ";
    }

    smb_fdata(ndo, words + 1, f1, min(words + 1 + 2 * words[0], maxbuf),
        unicodestr);

    ND_TCHECK2(*data1, 2);
    bcc = EXTRACT_LE_16BITS(data1);
     ND_PRINT((ndo, "smb_bcc=%u\n", bcc));
     if (bcc > 0) {
 	smb_fdata(ndo, data1 + 2, f2, maxbuf - (paramlen + datalen), unicodestr);
#define MAILSLOT_BROWSE_STR "\\MAILSLOT\\BROWSE"
	ND_TCHECK2(*(data1 + 2), strlen(MAILSLOT_BROWSE_STR) + 1);
	if (strcmp((const char *)(data1 + 2), MAILSLOT_BROWSE_STR) == 0) {
 	    print_browse(ndo, param, paramlen, data, datalen);
 	    return;
 	}
#undef MAILSLOT_BROWSE_STR

#define PIPE_LANMAN_STR "\\PIPE\\LANMAN"
	ND_TCHECK2(*(data1 + 2), strlen(PIPE_LANMAN_STR) + 1);
	if (strcmp((const char *)(data1 + 2), PIPE_LANMAN_STR) == 0) {
 	    print_ipc(ndo, param, paramlen, data, datalen);
 	    return;
 	}
#undef PIPE_LANMAN_STR

 	if (paramlen)
 	    smb_fdata(ndo, param, f3, min(param + paramlen, maxbuf), unicodestr);
	if (datalen)
	    smb_fdata(ndo, data, f4, min(data + datalen, maxbuf), unicodestr);
    }
    return;
trunc:
    ND_PRINT((ndo, "%s", tstr));
}


(for 4.9.3) CVE-2018-16300/BGP: prevent stack exhaustion

Enforce a limit on how many times bgp_attr_print() can recurse.

This fixes a stack exhaustion discovered by Include Security working
under the Mozilla SOS program in 2018 by means of code audit.

 bgp_attr_print(netdissect_options *ndo,
               u_int atype, const u_char *pptr, u_int len)
 {
 	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, "]: "));
                     }
                    /* FIXME check for recursion */
                    if (!bgp_attr_print(ndo, atype, tptr, alen))
                         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;
}

The BGP parser in tcpdump before 4.9.3 allows stack consumption in print-bgp.c:bgp_attr_print() because of unlimited recursion.