xref: /freebsd/contrib/tcpdump/print-rpki-rtr.c (revision 0a7e5f1f02aad2ff5fff1c60f44c6975fd07e1d9)
1cac3dcd5SXin LI /*
2cac3dcd5SXin LI  * Copyright (c) 1998-2011 The TCPDUMP project
3cac3dcd5SXin LI  *
4cac3dcd5SXin LI  * Redistribution and use in source and binary forms, with or without
5cac3dcd5SXin LI  * modification, are permitted provided that: (1) source code
6cac3dcd5SXin LI  * distributions retain the above copyright notice and this paragraph
7cac3dcd5SXin LI  * in its entirety, and (2) distributions including binary code include
8cac3dcd5SXin LI  * the above copyright notice and this paragraph in its entirety in
9cac3dcd5SXin LI  * the documentation or other materials provided with the distribution.
10cac3dcd5SXin LI  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11cac3dcd5SXin LI  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12cac3dcd5SXin LI  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13cac3dcd5SXin LI  * FOR A PARTICULAR PURPOSE.
14cac3dcd5SXin LI  *
150bff6a5aSEd Maste  * Original code by Hannes Gredler (hannes@gredler.at)
16cac3dcd5SXin LI  */
17cac3dcd5SXin LI 
183340d773SGleb Smirnoff /* \summary: Resource Public Key Infrastructure (RPKI) to Router Protocol printer */
193340d773SGleb Smirnoff 
203340d773SGleb Smirnoff /* specification: RFC 6810 */
213340d773SGleb Smirnoff 
22ee67461eSJoseph Mingrone #include <config.h>
23cac3dcd5SXin LI 
24ee67461eSJoseph Mingrone #include "netdissect-stdinc.h"
25cac3dcd5SXin LI 
26ee67461eSJoseph Mingrone #define ND_LONGJMP_FROM_TCHECK
273340d773SGleb Smirnoff #include "netdissect.h"
28cac3dcd5SXin LI #include "extract.h"
29cac3dcd5SXin LI #include "addrtoname.h"
30cac3dcd5SXin LI 
313340d773SGleb Smirnoff 
32cac3dcd5SXin LI /*
33cac3dcd5SXin LI  * RPKI/Router PDU header
34cac3dcd5SXin LI  *
35cac3dcd5SXin LI  * Here's what the PDU header looks like.
36cac3dcd5SXin LI  * The length does include the version and length fields.
37cac3dcd5SXin LI  */
38cac3dcd5SXin LI typedef struct rpki_rtr_pdu_ {
39ee67461eSJoseph Mingrone     nd_uint8_t version;		/* Version number */
40ee67461eSJoseph Mingrone     nd_uint8_t pdu_type;		/* PDU type */
41cac3dcd5SXin LI     union {
42ee67461eSJoseph Mingrone 	nd_uint16_t session_id;	/* Session id */
43ee67461eSJoseph Mingrone 	nd_uint16_t error_code;	/* Error code */
44cac3dcd5SXin LI     } u;
45ee67461eSJoseph Mingrone     nd_uint32_t length;
46cac3dcd5SXin LI } rpki_rtr_pdu;
47cac3dcd5SXin LI 
48cac3dcd5SXin LI /*
49cac3dcd5SXin LI  * IPv4 Prefix PDU.
50cac3dcd5SXin LI  */
51cac3dcd5SXin LI typedef struct rpki_rtr_pdu_ipv4_prefix_ {
52cac3dcd5SXin LI     rpki_rtr_pdu pdu_header;
53ee67461eSJoseph Mingrone     nd_uint8_t flags;
54ee67461eSJoseph Mingrone     nd_uint8_t prefix_length;
55ee67461eSJoseph Mingrone     nd_uint8_t max_length;
56ee67461eSJoseph Mingrone     nd_uint8_t zero;
57ee67461eSJoseph Mingrone     nd_ipv4 prefix;
58ee67461eSJoseph Mingrone     nd_uint32_t as;
59cac3dcd5SXin LI } rpki_rtr_pdu_ipv4_prefix;
60cac3dcd5SXin LI 
61cac3dcd5SXin LI /*
62cac3dcd5SXin LI  * IPv6 Prefix PDU.
63cac3dcd5SXin LI  */
64cac3dcd5SXin LI typedef struct rpki_rtr_pdu_ipv6_prefix_ {
65cac3dcd5SXin LI     rpki_rtr_pdu pdu_header;
66ee67461eSJoseph Mingrone     nd_uint8_t flags;
67ee67461eSJoseph Mingrone     nd_uint8_t prefix_length;
68ee67461eSJoseph Mingrone     nd_uint8_t max_length;
69ee67461eSJoseph Mingrone     nd_uint8_t zero;
70ee67461eSJoseph Mingrone     nd_ipv6 prefix;
71ee67461eSJoseph Mingrone     nd_uint32_t as;
72cac3dcd5SXin LI } rpki_rtr_pdu_ipv6_prefix;
73cac3dcd5SXin LI 
74cac3dcd5SXin LI /*
75cac3dcd5SXin LI  * Error report PDU.
76cac3dcd5SXin LI  */
77cac3dcd5SXin LI typedef struct rpki_rtr_pdu_error_report_ {
78cac3dcd5SXin LI     rpki_rtr_pdu pdu_header;
79ee67461eSJoseph Mingrone     nd_uint32_t encapsulated_pdu_length; /* Encapsulated PDU length */
800bff6a5aSEd Maste     /* Copy of Erroneous PDU (variable, optional) */
810bff6a5aSEd Maste     /* Length of Error Text (4 octets in network byte order) */
820bff6a5aSEd Maste     /* Arbitrary Text of Error Diagnostic Message (variable, optional) */
83cac3dcd5SXin LI } rpki_rtr_pdu_error_report;
84cac3dcd5SXin LI 
85cac3dcd5SXin LI /*
86cac3dcd5SXin LI  * PDU type codes
87cac3dcd5SXin LI  */
88cac3dcd5SXin LI #define RPKI_RTR_SERIAL_NOTIFY_PDU	0
89cac3dcd5SXin LI #define RPKI_RTR_SERIAL_QUERY_PDU	1
90cac3dcd5SXin LI #define RPKI_RTR_RESET_QUERY_PDU	2
91cac3dcd5SXin LI #define RPKI_RTR_CACHE_RESPONSE_PDU	3
92cac3dcd5SXin LI #define RPKI_RTR_IPV4_PREFIX_PDU	4
93cac3dcd5SXin LI #define RPKI_RTR_IPV6_PREFIX_PDU	6
94cac3dcd5SXin LI #define RPKI_RTR_END_OF_DATA_PDU	7
95cac3dcd5SXin LI #define RPKI_RTR_CACHE_RESET_PDU	8
96cac3dcd5SXin LI #define RPKI_RTR_ERROR_REPORT_PDU	10
97cac3dcd5SXin LI 
98cac3dcd5SXin LI static const struct tok rpki_rtr_pdu_values[] = {
99cac3dcd5SXin LI     { RPKI_RTR_SERIAL_NOTIFY_PDU, "Serial Notify" },
100cac3dcd5SXin LI     { RPKI_RTR_SERIAL_QUERY_PDU, "Serial Query" },
101cac3dcd5SXin LI     { RPKI_RTR_RESET_QUERY_PDU, "Reset Query" },
102cac3dcd5SXin LI     { RPKI_RTR_CACHE_RESPONSE_PDU, "Cache Response" },
103cac3dcd5SXin LI     { RPKI_RTR_IPV4_PREFIX_PDU, "IPV4 Prefix" },
104cac3dcd5SXin LI     { RPKI_RTR_IPV6_PREFIX_PDU, "IPV6 Prefix" },
105cac3dcd5SXin LI     { RPKI_RTR_END_OF_DATA_PDU, "End of Data" },
106cac3dcd5SXin LI     { RPKI_RTR_CACHE_RESET_PDU, "Cache Reset" },
107cac3dcd5SXin LI     { RPKI_RTR_ERROR_REPORT_PDU, "Error Report" },
108cac3dcd5SXin LI     { 0, NULL}
109cac3dcd5SXin LI };
110cac3dcd5SXin LI 
111cac3dcd5SXin LI static const struct tok rpki_rtr_error_codes[] = {
112cac3dcd5SXin LI     { 0, "Corrupt Data" },
113cac3dcd5SXin LI     { 1, "Internal Error" },
114cac3dcd5SXin LI     { 2, "No Data Available" },
115cac3dcd5SXin LI     { 3, "Invalid Request" },
116cac3dcd5SXin LI     { 4, "Unsupported Protocol Version" },
117cac3dcd5SXin LI     { 5, "Unsupported PDU Type" },
118cac3dcd5SXin LI     { 6, "Withdrawal of Unknown Record" },
119cac3dcd5SXin LI     { 7, "Duplicate Announcement Received" },
120cac3dcd5SXin LI     { 0, NULL}
121cac3dcd5SXin LI };
122cac3dcd5SXin LI 
123cac3dcd5SXin LI /*
1248bdc5a62SPatrick Kelsey  * Build a indentation string for a given indentation level.
125cac3dcd5SXin LI  * XXX this should be really in util.c
126cac3dcd5SXin LI  */
127cac3dcd5SXin LI static char *
indent_string(u_int indent)128cac3dcd5SXin LI indent_string (u_int indent)
129cac3dcd5SXin LI {
130cac3dcd5SXin LI     static char buf[20];
131cac3dcd5SXin LI     u_int idx;
132cac3dcd5SXin LI 
133cac3dcd5SXin LI     idx = 0;
134cac3dcd5SXin LI     buf[idx] = '\0';
135cac3dcd5SXin LI 
136cac3dcd5SXin LI     /*
137cac3dcd5SXin LI      * Does the static buffer fit ?
138cac3dcd5SXin LI      */
139cac3dcd5SXin LI     if (sizeof(buf) < ((indent/8) + (indent %8) + 2)) {
140cac3dcd5SXin LI 	return buf;
141cac3dcd5SXin LI     }
142cac3dcd5SXin LI 
143cac3dcd5SXin LI     /*
144cac3dcd5SXin LI      * Heading newline.
145cac3dcd5SXin LI      */
146cac3dcd5SXin LI     buf[idx] = '\n';
147cac3dcd5SXin LI     idx++;
148cac3dcd5SXin LI 
149cac3dcd5SXin LI     while (indent >= 8) {
150cac3dcd5SXin LI 	buf[idx] = '\t';
151cac3dcd5SXin LI 	idx++;
152cac3dcd5SXin LI 	indent -= 8;
153cac3dcd5SXin LI     }
154cac3dcd5SXin LI 
155cac3dcd5SXin LI     while (indent > 0) {
156cac3dcd5SXin LI 	buf[idx] = ' ';
157cac3dcd5SXin LI 	idx++;
158cac3dcd5SXin LI 	indent--;
159cac3dcd5SXin LI     }
160cac3dcd5SXin LI 
161cac3dcd5SXin LI     /*
162cac3dcd5SXin LI      * Trailing zero.
163cac3dcd5SXin LI      */
164cac3dcd5SXin LI     buf[idx] = '\0';
165cac3dcd5SXin LI 
166cac3dcd5SXin LI     return buf;
167cac3dcd5SXin LI }
168cac3dcd5SXin LI 
169cac3dcd5SXin LI /*
170cac3dcd5SXin LI  * Print a single PDU.
171cac3dcd5SXin LI  */
1720bff6a5aSEd Maste static u_int
rpki_rtr_pdu_print(netdissect_options * ndo,const u_char * tptr,const u_int len,const u_char recurse,const u_int indent)1730bff6a5aSEd Maste rpki_rtr_pdu_print(netdissect_options *ndo, const u_char *tptr, const u_int len,
1740bff6a5aSEd Maste 		   const u_char recurse, const u_int indent)
175cac3dcd5SXin LI {
176cac3dcd5SXin LI     const rpki_rtr_pdu *pdu_header;
177cac3dcd5SXin LI     u_int pdu_type, pdu_len, hexdump;
178cac3dcd5SXin LI     const u_char *msg;
179*0a7e5f1fSJoseph Mingrone     uint8_t pdu_ver;
180cac3dcd5SXin LI 
181*0a7e5f1fSJoseph Mingrone     if (len < sizeof(rpki_rtr_pdu)) {
182*0a7e5f1fSJoseph Mingrone 	ND_PRINT("(%u bytes is too few to decode)", len);
183*0a7e5f1fSJoseph Mingrone 	goto invalid;
184*0a7e5f1fSJoseph Mingrone     }
185*0a7e5f1fSJoseph Mingrone     pdu_header = (const rpki_rtr_pdu *)tptr;
186*0a7e5f1fSJoseph Mingrone     pdu_ver = GET_U_1(pdu_header->version);
187*0a7e5f1fSJoseph Mingrone     if (pdu_ver != 0) {
1880bff6a5aSEd Maste 	/* Skip the rest of the input buffer because even if this is
1890bff6a5aSEd Maste 	 * a well-formed PDU of a future RPKI-Router protocol version
1900bff6a5aSEd Maste 	 * followed by a well-formed PDU of RPKI-Router protocol
1910bff6a5aSEd Maste 	 * version 0, there is no way to know exactly how to skip the
1920bff6a5aSEd Maste 	 * current PDU.
1930bff6a5aSEd Maste 	 */
194*0a7e5f1fSJoseph Mingrone 	ND_PRINT("%sRPKI-RTRv%u (unknown)", indent_string(8), pdu_ver);
1950bff6a5aSEd Maste 	return len;
1960bff6a5aSEd Maste     }
197ee67461eSJoseph Mingrone     pdu_type = GET_U_1(pdu_header->pdu_type);
198ee67461eSJoseph Mingrone     pdu_len = GET_BE_U_4(pdu_header->length);
1990bff6a5aSEd Maste     /* Do not check bounds with pdu_len yet, do it in the case blocks
2000bff6a5aSEd Maste      * below to make it possible to decode at least the beginning of
2010bff6a5aSEd Maste      * a truncated Error Report PDU or a truncated encapsulated PDU.
2020bff6a5aSEd Maste      */
203cac3dcd5SXin LI     hexdump = FALSE;
204cac3dcd5SXin LI 
205ee67461eSJoseph Mingrone     ND_PRINT("%sRPKI-RTRv%u, %s PDU (%u), length: %u",
206cac3dcd5SXin LI 	   indent_string(8),
207*0a7e5f1fSJoseph Mingrone 	   pdu_ver,
208cac3dcd5SXin LI 	   tok2str(rpki_rtr_pdu_values, "Unknown", pdu_type),
209ee67461eSJoseph Mingrone 	   pdu_type, pdu_len);
2100bff6a5aSEd Maste     if (pdu_len < sizeof(rpki_rtr_pdu) || pdu_len > len)
2110bff6a5aSEd Maste 	goto invalid;
212cac3dcd5SXin LI 
213cac3dcd5SXin LI     switch (pdu_type) {
214cac3dcd5SXin LI 
215cac3dcd5SXin LI 	/*
216cac3dcd5SXin LI 	 * The following PDUs share the message format.
217cac3dcd5SXin LI 	 */
218cac3dcd5SXin LI     case RPKI_RTR_SERIAL_NOTIFY_PDU:
219cac3dcd5SXin LI     case RPKI_RTR_SERIAL_QUERY_PDU:
220cac3dcd5SXin LI     case RPKI_RTR_END_OF_DATA_PDU:
2210bff6a5aSEd Maste 	if (pdu_len != sizeof(rpki_rtr_pdu) + 4)
2220bff6a5aSEd Maste 	    goto invalid;
223cac3dcd5SXin LI         msg = (const u_char *)(pdu_header + 1);
224ee67461eSJoseph Mingrone 	ND_PRINT("%sSession ID: 0x%04x, Serial: %u",
225cac3dcd5SXin LI 	       indent_string(indent+2),
226ee67461eSJoseph Mingrone 	       GET_BE_U_2(pdu_header->u.session_id),
227ee67461eSJoseph Mingrone 	       GET_BE_U_4(msg));
228cac3dcd5SXin LI 	break;
229cac3dcd5SXin LI 
230cac3dcd5SXin LI 	/*
231cac3dcd5SXin LI 	 * The following PDUs share the message format.
232cac3dcd5SXin LI 	 */
233cac3dcd5SXin LI     case RPKI_RTR_RESET_QUERY_PDU:
234cac3dcd5SXin LI     case RPKI_RTR_CACHE_RESET_PDU:
2350bff6a5aSEd Maste 	if (pdu_len != sizeof(rpki_rtr_pdu))
2360bff6a5aSEd Maste 	    goto invalid;
2370bff6a5aSEd Maste 	/* no additional boundary to check */
238cac3dcd5SXin LI 
239cac3dcd5SXin LI 	/*
240cac3dcd5SXin LI 	 * Zero payload PDUs.
241cac3dcd5SXin LI 	 */
242cac3dcd5SXin LI 	break;
243cac3dcd5SXin LI 
244cac3dcd5SXin LI     case RPKI_RTR_CACHE_RESPONSE_PDU:
2450bff6a5aSEd Maste 	if (pdu_len != sizeof(rpki_rtr_pdu))
2460bff6a5aSEd Maste 	    goto invalid;
2470bff6a5aSEd Maste 	/* no additional boundary to check */
248ee67461eSJoseph Mingrone 	ND_PRINT("%sSession ID: 0x%04x",
249cac3dcd5SXin LI 	       indent_string(indent+2),
250ee67461eSJoseph Mingrone 	       GET_BE_U_2(pdu_header->u.session_id));
251cac3dcd5SXin LI 	break;
252cac3dcd5SXin LI 
253cac3dcd5SXin LI     case RPKI_RTR_IPV4_PREFIX_PDU:
254cac3dcd5SXin LI 	{
2553340d773SGleb Smirnoff 	    const rpki_rtr_pdu_ipv4_prefix *pdu;
256cac3dcd5SXin LI 
257ee67461eSJoseph Mingrone 	    if (pdu_len != sizeof(rpki_rtr_pdu_ipv4_prefix))
2580bff6a5aSEd Maste 		goto invalid;
2593340d773SGleb Smirnoff 	    pdu = (const rpki_rtr_pdu_ipv4_prefix *)tptr;
260ee67461eSJoseph Mingrone 	    ND_PRINT("%sIPv4 Prefix %s/%u-%u, origin-as %u, flags 0x%02x",
261cac3dcd5SXin LI 		   indent_string(indent+2),
262ee67461eSJoseph Mingrone 		   GET_IPADDR_STRING(pdu->prefix),
263ee67461eSJoseph Mingrone 		   GET_U_1(pdu->prefix_length), GET_U_1(pdu->max_length),
264ee67461eSJoseph Mingrone 		   GET_BE_U_4(pdu->as), GET_U_1(pdu->flags));
265cac3dcd5SXin LI 	}
266cac3dcd5SXin LI 	break;
267cac3dcd5SXin LI 
268cac3dcd5SXin LI     case RPKI_RTR_IPV6_PREFIX_PDU:
269cac3dcd5SXin LI 	{
2703340d773SGleb Smirnoff 	    const rpki_rtr_pdu_ipv6_prefix *pdu;
271cac3dcd5SXin LI 
272ee67461eSJoseph Mingrone 	    if (pdu_len != sizeof(rpki_rtr_pdu_ipv6_prefix))
2730bff6a5aSEd Maste 		goto invalid;
2743340d773SGleb Smirnoff 	    pdu = (const rpki_rtr_pdu_ipv6_prefix *)tptr;
275ee67461eSJoseph Mingrone 	    ND_PRINT("%sIPv6 Prefix %s/%u-%u, origin-as %u, flags 0x%02x",
276cac3dcd5SXin LI 		   indent_string(indent+2),
277ee67461eSJoseph Mingrone 		   GET_IP6ADDR_STRING(pdu->prefix),
278ee67461eSJoseph Mingrone 		   GET_U_1(pdu->prefix_length), GET_U_1(pdu->max_length),
279ee67461eSJoseph Mingrone 		   GET_BE_U_4(pdu->as), GET_U_1(pdu->flags));
280cac3dcd5SXin LI 	}
281cac3dcd5SXin LI 	break;
282cac3dcd5SXin LI 
283cac3dcd5SXin LI     case RPKI_RTR_ERROR_REPORT_PDU:
284cac3dcd5SXin LI 	{
2853340d773SGleb Smirnoff 	    const rpki_rtr_pdu_error_report *pdu;
286cac3dcd5SXin LI 	    u_int encapsulated_pdu_length, text_length, tlen, error_code;
287cac3dcd5SXin LI 
2880bff6a5aSEd Maste 	    tlen = sizeof(rpki_rtr_pdu);
2890bff6a5aSEd Maste 	    /* Do not test for the "Length of Error Text" data element yet. */
2900bff6a5aSEd Maste 	    if (pdu_len < tlen + 4)
2910bff6a5aSEd Maste 		goto invalid;
2923340d773SGleb Smirnoff 	    pdu = (const rpki_rtr_pdu_error_report *)tptr;
293ee67461eSJoseph Mingrone 	    encapsulated_pdu_length = GET_BE_U_4(pdu->encapsulated_pdu_length);
2940bff6a5aSEd Maste 	    tlen += 4;
295*0a7e5f1fSJoseph Mingrone 	    /* Safe up to and including the "Length of Encapsulated PDU"
296*0a7e5f1fSJoseph Mingrone 	     * data element, more data elements may be present.
297*0a7e5f1fSJoseph Mingrone 	     */
298cac3dcd5SXin LI 
299ee67461eSJoseph Mingrone 	    error_code = GET_BE_U_2(pdu->pdu_header.u.error_code);
300ee67461eSJoseph Mingrone 	    ND_PRINT("%sError code: %s (%u), Encapsulated PDU length: %u",
301cac3dcd5SXin LI 		   indent_string(indent+2),
302cac3dcd5SXin LI 		   tok2str(rpki_rtr_error_codes, "Unknown", error_code),
303ee67461eSJoseph Mingrone 		   error_code, encapsulated_pdu_length);
304cac3dcd5SXin LI 
3050bff6a5aSEd Maste 	    if (encapsulated_pdu_length) {
3060bff6a5aSEd Maste 		/* Section 5.10 of RFC 6810 says:
3070bff6a5aSEd Maste 		 * "An Error Report PDU MUST NOT be sent for an Error Report PDU."
3080bff6a5aSEd Maste 		 *
3090bff6a5aSEd Maste 		 * However, as far as the protocol encoding goes Error Report PDUs can
3100bff6a5aSEd Maste 		 * happen to be nested in each other, however many times, in which case
3110bff6a5aSEd Maste 		 * the decoder should still print such semantically incorrect PDUs.
3120bff6a5aSEd Maste 		 *
3130bff6a5aSEd Maste 		 * That said, "the Erroneous PDU field MAY be truncated" (ibid), thus
3140bff6a5aSEd Maste 		 * to keep things simple this implementation decodes only the two
3150bff6a5aSEd Maste 		 * outermost layers of PDUs and makes bounds checks in the outer and
3160bff6a5aSEd Maste 		 * the inner PDU independently.
317cac3dcd5SXin LI 		 */
3180bff6a5aSEd Maste 		if (pdu_len < tlen + encapsulated_pdu_length)
3190bff6a5aSEd Maste 		    goto invalid;
3200bff6a5aSEd Maste 		if (! recurse) {
321ee67461eSJoseph Mingrone 		    ND_TCHECK_LEN(tptr, tlen + encapsulated_pdu_length);
322*0a7e5f1fSJoseph Mingrone 		} else {
323ee67461eSJoseph Mingrone 		    ND_PRINT("%s-----encapsulated PDU-----", indent_string(indent+4));
3240bff6a5aSEd Maste 		    rpki_rtr_pdu_print(ndo, tptr + tlen,
3250bff6a5aSEd Maste 			encapsulated_pdu_length, 0, indent + 2);
3260bff6a5aSEd Maste 		}
3270bff6a5aSEd Maste 		tlen += encapsulated_pdu_length;
328cac3dcd5SXin LI 	    }
329cac3dcd5SXin LI 
3300bff6a5aSEd Maste 	    if (pdu_len < tlen + 4)
3310bff6a5aSEd Maste 		goto invalid;
332cac3dcd5SXin LI 	    /*
333cac3dcd5SXin LI 	     * Extract, trail-zero and print the Error message.
334cac3dcd5SXin LI 	     */
335ee67461eSJoseph Mingrone 	    text_length = GET_BE_U_4(tptr + tlen);
3360bff6a5aSEd Maste 	    tlen += 4;
337*0a7e5f1fSJoseph Mingrone 	    /* Safe up to and including the "Length of Error Text" data element,
338*0a7e5f1fSJoseph Mingrone 	     * one more data element may be present.
339*0a7e5f1fSJoseph Mingrone 	     */
3400bff6a5aSEd Maste 
3410bff6a5aSEd Maste 	    if (text_length) {
3420bff6a5aSEd Maste 		if (pdu_len < tlen + text_length)
3430bff6a5aSEd Maste 		    goto invalid;
344ee67461eSJoseph Mingrone 		/* nd_printn() makes the bounds check */
345ee67461eSJoseph Mingrone 		ND_PRINT("%sError text: ", indent_string(indent+2));
346ee67461eSJoseph Mingrone 		(void)nd_printn(ndo, tptr + tlen, text_length, NULL);
347cac3dcd5SXin LI 	    }
348cac3dcd5SXin LI 	}
349cac3dcd5SXin LI 	break;
350cac3dcd5SXin LI 
351cac3dcd5SXin LI     default:
352ee67461eSJoseph Mingrone 	ND_TCHECK_LEN(tptr, pdu_len);
353cac3dcd5SXin LI 
354cac3dcd5SXin LI 	/*
355cac3dcd5SXin LI 	 * Unknown data, please hexdump.
356cac3dcd5SXin LI 	 */
357cac3dcd5SXin LI 	hexdump = TRUE;
358cac3dcd5SXin LI     }
359cac3dcd5SXin LI 
360cac3dcd5SXin LI     /* do we also want to see a hex dump ? */
3613c602fabSXin LI     if (ndo->ndo_vflag > 1 || (ndo->ndo_vflag && hexdump)) {
3623c602fabSXin LI 	print_unknown_data(ndo,tptr,"\n\t  ", pdu_len);
363cac3dcd5SXin LI     }
3640bff6a5aSEd Maste     return pdu_len;
3658bdc5a62SPatrick Kelsey 
3660bff6a5aSEd Maste invalid:
367ee67461eSJoseph Mingrone     nd_print_invalid(ndo);
368ee67461eSJoseph Mingrone     ND_TCHECK_LEN(tptr, len);
3690bff6a5aSEd Maste     return len;
370cac3dcd5SXin LI }
371cac3dcd5SXin LI 
372cac3dcd5SXin LI void
rpki_rtr_print(netdissect_options * ndo,const u_char * pptr,u_int len)373ee67461eSJoseph Mingrone rpki_rtr_print(netdissect_options *ndo, const u_char *pptr, u_int len)
3748bdc5a62SPatrick Kelsey {
375ee67461eSJoseph Mingrone     ndo->ndo_protocol = "rpki_rtr";
3763c602fabSXin LI     if (!ndo->ndo_vflag) {
377ee67461eSJoseph Mingrone 	ND_PRINT(", RPKI-RTR");
378cac3dcd5SXin LI 	return;
379cac3dcd5SXin LI     }
3800bff6a5aSEd Maste     while (len) {
3810bff6a5aSEd Maste 	u_int pdu_len = rpki_rtr_pdu_print(ndo, pptr, len, 1, 8);
3820bff6a5aSEd Maste 	len -= pdu_len;
3830bff6a5aSEd Maste 	pptr += pdu_len;
384cac3dcd5SXin LI     }
385cac3dcd5SXin LI }
386