1235427Sdelphij/*
2235427Sdelphij * Copyright (c) 1998-2011 The TCPDUMP project
3235427Sdelphij *
4235427Sdelphij * Redistribution and use in source and binary forms, with or without
5235427Sdelphij * modification, are permitted provided that: (1) source code
6235427Sdelphij * distributions retain the above copyright notice and this paragraph
7235427Sdelphij * in its entirety, and (2) distributions including binary code include
8235427Sdelphij * the above copyright notice and this paragraph in its entirety in
9235427Sdelphij * the documentation or other materials provided with the distribution.
10235427Sdelphij * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11235427Sdelphij * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12235427Sdelphij * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13235427Sdelphij * FOR A PARTICULAR PURPOSE.
14235427Sdelphij *
15251158Sdelphij * support for the The RPKI/Router Protocol as RFC6810
16235427Sdelphij *
17235427Sdelphij * Original code by Hannes Gredler (hannes@juniper.net)
18235427Sdelphij */
19235427Sdelphij
20235427Sdelphij#ifndef lint
21235427Sdelphijstatic const char rcsid[] _U_ =
22235427Sdelphij"@(#) $Header: /tcpdump/master/tcpdump/print-rpki_rtr.c,v 1.10 2008-03-20 09:30:56 hannes Exp $";
23235427Sdelphij#endif
24235427Sdelphij
25235427Sdelphij#ifdef HAVE_CONFIG_H
26235427Sdelphij#include "config.h"
27235427Sdelphij#endif
28235427Sdelphij
29235427Sdelphij#include <tcpdump-stdinc.h>
30235427Sdelphij
31235427Sdelphij#include <stdio.h>
32235427Sdelphij#include <stdlib.h>
33235427Sdelphij#include <string.h>
34235427Sdelphij
35235427Sdelphij#include "interface.h"
36235427Sdelphij#include "extract.h"
37235427Sdelphij#include "addrtoname.h"
38235427Sdelphij
39235427Sdelphij/*
40235427Sdelphij * RPKI/Router PDU header
41235427Sdelphij *
42235427Sdelphij * Here's what the PDU header looks like.
43235427Sdelphij * The length does include the version and length fields.
44235427Sdelphij */
45235427Sdelphijtypedef struct rpki_rtr_pdu_ {
46235427Sdelphij    u_char version;		/* Version number */
47235427Sdelphij    u_char pdu_type;		/* PDU type */
48235427Sdelphij    union {
49251158Sdelphij	u_char session_id[2];	/* Session id */
50235427Sdelphij	u_char error_code[2];	/* Error code */
51235427Sdelphij    } u;
52235427Sdelphij    u_char length[4];
53235427Sdelphij} rpki_rtr_pdu;
54235427Sdelphij#define RPKI_RTR_PDU_OVERHEAD (offsetof(rpki_rtr_pdu, rpki_rtr_pdu_msg))
55235427Sdelphij
56235427Sdelphij/*
57235427Sdelphij * IPv4 Prefix PDU.
58235427Sdelphij */
59235427Sdelphijtypedef struct rpki_rtr_pdu_ipv4_prefix_ {
60235427Sdelphij    rpki_rtr_pdu pdu_header;
61235427Sdelphij    u_char flags;
62235427Sdelphij    u_char prefix_length;
63235427Sdelphij    u_char max_length;
64235427Sdelphij    u_char zero;
65235427Sdelphij    u_char prefix[4];
66235427Sdelphij    u_char as[4];
67235427Sdelphij} rpki_rtr_pdu_ipv4_prefix;
68235427Sdelphij
69235427Sdelphij/*
70235427Sdelphij * IPv6 Prefix PDU.
71235427Sdelphij */
72235427Sdelphijtypedef struct rpki_rtr_pdu_ipv6_prefix_ {
73235427Sdelphij    rpki_rtr_pdu pdu_header;
74235427Sdelphij    u_char flags;
75235427Sdelphij    u_char prefix_length;
76235427Sdelphij    u_char max_length;
77235427Sdelphij    u_char zero;
78235427Sdelphij    u_char prefix[16];
79235427Sdelphij    u_char as[4];
80235427Sdelphij} rpki_rtr_pdu_ipv6_prefix;
81235427Sdelphij
82235427Sdelphij/*
83235427Sdelphij * Error report PDU.
84235427Sdelphij */
85235427Sdelphijtypedef struct rpki_rtr_pdu_error_report_ {
86235427Sdelphij    rpki_rtr_pdu pdu_header;
87235427Sdelphij    u_char encapsulated_pdu_length[4]; /* Encapsulated PDU length */
88235427Sdelphij} rpki_rtr_pdu_error_report;
89235427Sdelphij
90235427Sdelphij/*
91235427Sdelphij * PDU type codes
92235427Sdelphij */
93235427Sdelphij#define RPKI_RTR_SERIAL_NOTIFY_PDU	0
94235427Sdelphij#define RPKI_RTR_SERIAL_QUERY_PDU	1
95235427Sdelphij#define RPKI_RTR_RESET_QUERY_PDU	2
96235427Sdelphij#define RPKI_RTR_CACHE_RESPONSE_PDU	3
97235427Sdelphij#define RPKI_RTR_IPV4_PREFIX_PDU	4
98235427Sdelphij#define RPKI_RTR_IPV6_PREFIX_PDU	6
99235427Sdelphij#define RPKI_RTR_END_OF_DATA_PDU	7
100235427Sdelphij#define RPKI_RTR_CACHE_RESET_PDU	8
101235427Sdelphij#define RPKI_RTR_ERROR_REPORT_PDU	10
102235427Sdelphij
103235427Sdelphijstatic const struct tok rpki_rtr_pdu_values[] = {
104235427Sdelphij    { RPKI_RTR_SERIAL_NOTIFY_PDU, "Serial Notify" },
105235427Sdelphij    { RPKI_RTR_SERIAL_QUERY_PDU, "Serial Query" },
106235427Sdelphij    { RPKI_RTR_RESET_QUERY_PDU, "Reset Query" },
107235427Sdelphij    { RPKI_RTR_CACHE_RESPONSE_PDU, "Cache Response" },
108235427Sdelphij    { RPKI_RTR_IPV4_PREFIX_PDU, "IPV4 Prefix" },
109235427Sdelphij    { RPKI_RTR_IPV6_PREFIX_PDU, "IPV6 Prefix" },
110235427Sdelphij    { RPKI_RTR_END_OF_DATA_PDU, "End of Data" },
111235427Sdelphij    { RPKI_RTR_CACHE_RESET_PDU, "Cache Reset" },
112235427Sdelphij    { RPKI_RTR_ERROR_REPORT_PDU, "Error Report" },
113235427Sdelphij    { 0, NULL}
114235427Sdelphij};
115235427Sdelphij
116235427Sdelphijstatic const struct tok rpki_rtr_error_codes[] = {
117235427Sdelphij    { 0, "Corrupt Data" },
118235427Sdelphij    { 1, "Internal Error" },
119235427Sdelphij    { 2, "No Data Available" },
120235427Sdelphij    { 3, "Invalid Request" },
121235427Sdelphij    { 4, "Unsupported Protocol Version" },
122235427Sdelphij    { 5, "Unsupported PDU Type" },
123235427Sdelphij    { 6, "Withdrawal of Unknown Record" },
124235427Sdelphij    { 7, "Duplicate Announcement Received" },
125235427Sdelphij    { 0, NULL}
126235427Sdelphij};
127235427Sdelphij
128235427Sdelphij/*
129235427Sdelphij * Build a identation string for a given identation level.
130235427Sdelphij * XXX this should be really in util.c
131235427Sdelphij */
132235427Sdelphijstatic char *
133235427Sdelphijindent_string (u_int indent)
134235427Sdelphij{
135235427Sdelphij    static char buf[20];
136235427Sdelphij    u_int idx;
137235427Sdelphij
138235427Sdelphij    idx = 0;
139235427Sdelphij    buf[idx] = '\0';
140235427Sdelphij
141235427Sdelphij    /*
142235427Sdelphij     * Does the static buffer fit ?
143235427Sdelphij     */
144235427Sdelphij    if (sizeof(buf) < ((indent/8) + (indent %8) + 2)) {
145235427Sdelphij	return buf;
146235427Sdelphij    }
147235427Sdelphij
148235427Sdelphij    /*
149235427Sdelphij     * Heading newline.
150235427Sdelphij     */
151235427Sdelphij    buf[idx] = '\n';
152235427Sdelphij    idx++;
153235427Sdelphij
154235427Sdelphij    while (indent >= 8) {
155235427Sdelphij	buf[idx] = '\t';
156235427Sdelphij	idx++;
157235427Sdelphij	indent -= 8;
158235427Sdelphij    }
159235427Sdelphij
160235427Sdelphij    while (indent > 0) {
161235427Sdelphij	buf[idx] = ' ';
162235427Sdelphij	idx++;
163235427Sdelphij	indent--;
164235427Sdelphij    }
165235427Sdelphij
166235427Sdelphij    /*
167235427Sdelphij     * Trailing zero.
168235427Sdelphij     */
169235427Sdelphij    buf[idx] = '\0';
170251158Sdelphij
171235427Sdelphij    return buf;
172235427Sdelphij}
173235427Sdelphij
174235427Sdelphij/*
175235427Sdelphij * Print a single PDU.
176235427Sdelphij */
177235427Sdelphijstatic void
178235427Sdelphijrpki_rtr_pdu_print (const u_char *tptr, u_int indent)
179235427Sdelphij{
180235427Sdelphij    const rpki_rtr_pdu *pdu_header;
181235427Sdelphij    u_int pdu_type, pdu_len, hexdump;
182235427Sdelphij    const u_char *msg;
183235427Sdelphij
184235427Sdelphij    pdu_header = (rpki_rtr_pdu *)tptr;
185235427Sdelphij    pdu_type = pdu_header->pdu_type;
186235427Sdelphij    pdu_len = EXTRACT_32BITS(pdu_header->length);
187235427Sdelphij    hexdump = FALSE;
188235427Sdelphij
189235427Sdelphij    printf("%sRPKI-RTRv%u, %s PDU (%u), length: %u",
190235427Sdelphij	   indent_string(8),
191235427Sdelphij	   pdu_header->version,
192235427Sdelphij	   tok2str(rpki_rtr_pdu_values, "Unknown", pdu_type),
193235427Sdelphij	   pdu_type, pdu_len);
194235427Sdelphij
195235427Sdelphij    switch (pdu_type) {
196235427Sdelphij
197235427Sdelphij	/*
198235427Sdelphij	 * The following PDUs share the message format.
199235427Sdelphij	 */
200235427Sdelphij    case RPKI_RTR_SERIAL_NOTIFY_PDU:
201235427Sdelphij    case RPKI_RTR_SERIAL_QUERY_PDU:
202235427Sdelphij    case RPKI_RTR_END_OF_DATA_PDU:
203235427Sdelphij        msg = (const u_char *)(pdu_header + 1);
204251158Sdelphij	printf("%sSession ID: 0x%04x, Serial: %u",
205235427Sdelphij	       indent_string(indent+2),
206251158Sdelphij	       EXTRACT_16BITS(pdu_header->u.session_id),
207235427Sdelphij	       EXTRACT_32BITS(msg));
208235427Sdelphij	break;
209235427Sdelphij
210235427Sdelphij	/*
211235427Sdelphij	 * The following PDUs share the message format.
212235427Sdelphij	 */
213235427Sdelphij    case RPKI_RTR_RESET_QUERY_PDU:
214235427Sdelphij    case RPKI_RTR_CACHE_RESET_PDU:
215235427Sdelphij
216235427Sdelphij	/*
217235427Sdelphij	 * Zero payload PDUs.
218235427Sdelphij	 */
219235427Sdelphij	break;
220235427Sdelphij
221235427Sdelphij    case RPKI_RTR_CACHE_RESPONSE_PDU:
222251158Sdelphij	printf("%sSession ID: 0x%04x",
223235427Sdelphij	       indent_string(indent+2),
224251158Sdelphij	       EXTRACT_16BITS(pdu_header->u.session_id));
225235427Sdelphij	break;
226235427Sdelphij
227235427Sdelphij    case RPKI_RTR_IPV4_PREFIX_PDU:
228235427Sdelphij	{
229235427Sdelphij	    rpki_rtr_pdu_ipv4_prefix *pdu;
230235427Sdelphij
231235427Sdelphij	    pdu = (rpki_rtr_pdu_ipv4_prefix *)tptr;
232235427Sdelphij	    printf("%sIPv4 Prefix %s/%u-%u, origin-as %u, flags 0x%02x",
233235427Sdelphij		   indent_string(indent+2),
234235427Sdelphij		   ipaddr_string(pdu->prefix),
235235427Sdelphij		   pdu->prefix_length, pdu->max_length,
236235427Sdelphij		   EXTRACT_32BITS(pdu->as), pdu->flags);
237235427Sdelphij	}
238235427Sdelphij	break;
239235427Sdelphij
240235427Sdelphij#ifdef INET6
241235427Sdelphij    case RPKI_RTR_IPV6_PREFIX_PDU:
242235427Sdelphij	{
243235427Sdelphij	    rpki_rtr_pdu_ipv6_prefix *pdu;
244235427Sdelphij
245235427Sdelphij	    pdu = (rpki_rtr_pdu_ipv6_prefix *)tptr;
246235427Sdelphij	    printf("%sIPv6 Prefix %s/%u-%u, origin-as %u, flags 0x%02x",
247235427Sdelphij		   indent_string(indent+2),
248235427Sdelphij		   ip6addr_string(pdu->prefix),
249235427Sdelphij		   pdu->prefix_length, pdu->max_length,
250235427Sdelphij		   EXTRACT_32BITS(pdu->as), pdu->flags);
251235427Sdelphij	}
252235427Sdelphij	break;
253235427Sdelphij#endif
254235427Sdelphij
255235427Sdelphij    case RPKI_RTR_ERROR_REPORT_PDU:
256235427Sdelphij	{
257235427Sdelphij	    rpki_rtr_pdu_error_report *pdu;
258235427Sdelphij	    u_int encapsulated_pdu_length, text_length, tlen, error_code;
259235427Sdelphij	    u_char buf[80];
260235427Sdelphij
261235427Sdelphij	    pdu = (rpki_rtr_pdu_error_report *)tptr;
262235427Sdelphij	    encapsulated_pdu_length = EXTRACT_32BITS(pdu->encapsulated_pdu_length);
263235427Sdelphij	    tlen = pdu_len;
264235427Sdelphij
265235427Sdelphij	    error_code = EXTRACT_16BITS(pdu->pdu_header.u.error_code);
266235427Sdelphij	    printf("%sError code: %s (%u), Encapsulated PDU length: %u",
267235427Sdelphij		   indent_string(indent+2),
268235427Sdelphij		   tok2str(rpki_rtr_error_codes, "Unknown", error_code),
269235427Sdelphij		   error_code, encapsulated_pdu_length);
270235427Sdelphij
271235427Sdelphij	    tptr += sizeof(*pdu);
272235427Sdelphij	    tlen -= sizeof(*pdu);
273235427Sdelphij
274235427Sdelphij	    /*
275235427Sdelphij	     * Recurse if there is an encapsulated PDU.
276235427Sdelphij	     */
277235427Sdelphij	    if (encapsulated_pdu_length &&
278235427Sdelphij		(encapsulated_pdu_length <= tlen)) {
279235427Sdelphij		printf("%s-----encapsulated PDU-----", indent_string(indent+4));
280235427Sdelphij		rpki_rtr_pdu_print(tptr, indent+2);
281235427Sdelphij	    }
282235427Sdelphij
283235427Sdelphij	    tptr += encapsulated_pdu_length;
284235427Sdelphij	    tlen -= encapsulated_pdu_length;
285235427Sdelphij
286235427Sdelphij	    /*
287235427Sdelphij	     * Extract, trail-zero and print the Error message.
288235427Sdelphij	     */
289235427Sdelphij	    text_length = 0;
290235427Sdelphij	    if (tlen > 4) {
291235427Sdelphij		text_length = EXTRACT_32BITS(tptr);
292235427Sdelphij		tptr += 4;
293235427Sdelphij		tlen -= 4;
294235427Sdelphij	    }
295235427Sdelphij	    if (text_length && (text_length <= tlen )) {
296235427Sdelphij		memcpy(buf, tptr, MIN(sizeof(buf)-1, text_length));
297235427Sdelphij		buf[text_length] = '\0';
298235427Sdelphij		printf("%sError text: %s", indent_string(indent+2), buf);
299235427Sdelphij	    }
300235427Sdelphij	}
301235427Sdelphij	break;
302235427Sdelphij
303235427Sdelphij    default:
304235427Sdelphij
305235427Sdelphij	/*
306235427Sdelphij	 * Unknown data, please hexdump.
307235427Sdelphij	 */
308235427Sdelphij	hexdump = TRUE;
309235427Sdelphij    }
310235427Sdelphij
311235427Sdelphij    /* do we also want to see a hex dump ? */
312235427Sdelphij    if (vflag > 1 || (vflag && hexdump)) {
313235427Sdelphij	print_unknown_data(tptr,"\n\t  ", pdu_len);
314235427Sdelphij    }
315235427Sdelphij}
316235427Sdelphij
317235427Sdelphijvoid
318235427Sdelphijrpki_rtr_print(register const u_char *pptr, register u_int len) {
319235427Sdelphij
320235427Sdelphij    u_int tlen, pdu_type, pdu_len;
321235427Sdelphij    const u_char *tptr;
322235427Sdelphij    const rpki_rtr_pdu *pdu_header;
323251158Sdelphij
324235427Sdelphij    tptr = pptr;
325235427Sdelphij    tlen = len;
326235427Sdelphij
327235427Sdelphij    if (!vflag) {
328235427Sdelphij	printf(", RPKI-RTR");
329235427Sdelphij	return;
330235427Sdelphij    }
331235427Sdelphij
332235427Sdelphij    while (tlen >= sizeof(rpki_rtr_pdu)) {
333235427Sdelphij
334235427Sdelphij        TCHECK2(*tptr, sizeof(rpki_rtr_pdu));
335235427Sdelphij
336235427Sdelphij	pdu_header = (rpki_rtr_pdu *)tptr;
337235427Sdelphij        pdu_type = pdu_header->pdu_type;
338235427Sdelphij        pdu_len = EXTRACT_32BITS(pdu_header->length);
339235427Sdelphij
340235427Sdelphij        /* infinite loop check */
341235427Sdelphij        if (!pdu_type || !pdu_len) {
342235427Sdelphij            break;
343235427Sdelphij        }
344235427Sdelphij
345235427Sdelphij        TCHECK2(*tptr, pdu_len);
346235427Sdelphij        if (tlen < pdu_len) {
347235427Sdelphij            goto trunc;
348235427Sdelphij        }
349235427Sdelphij
350235427Sdelphij	/*
351235427Sdelphij	 * Print the PDU.
352235427Sdelphij	 */
353235427Sdelphij	rpki_rtr_pdu_print(tptr, 8);
354235427Sdelphij
355235427Sdelphij        tlen -= pdu_len;
356235427Sdelphij        tptr += pdu_len;
357235427Sdelphij    }
358235427Sdelphij    return;
359235427Sdelphij trunc:
360235427Sdelphij    printf("\n\t[|RPKI-RTR]");
361235427Sdelphij}
362235427Sdelphij
363235427Sdelphij/*
364235427Sdelphij * Local Variables:
365235427Sdelphij * c-style: whitesmith
366235427Sdelphij * c-basic-offset: 4
367235427Sdelphij * End:
368235427Sdelphij */
369