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