Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (c) 1998-2011 The TCPDUMP project
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that: (1) source code
      6  * distributions retain the above copyright notice and this paragraph
      7  * in its entirety, and (2) distributions including binary code include
      8  * the above copyright notice and this paragraph in its entirety in
      9  * the documentation or other materials provided with the distribution.
     10  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
     11  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
     12  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     13  * FOR A PARTICULAR PURPOSE.
     14  *
     15  * Original code by Hannes Gredler (hannes (at) juniper.net)
     16  */
     17 
     18 /* \summary: Resource Public Key Infrastructure (RPKI) to Router Protocol printer */
     19 
     20 /* specification: RFC 6810 */
     21 
     22 #ifdef HAVE_CONFIG_H
     23 #include "config.h"
     24 #endif
     25 
     26 #include <netdissect-stdinc.h>
     27 
     28 #include <string.h>
     29 
     30 #include "netdissect.h"
     31 #include "extract.h"
     32 #include "addrtoname.h"
     33 
     34 static const char tstr[] = "[|RPKI-RTR]";
     35 
     36 /*
     37  * RPKI/Router PDU header
     38  *
     39  * Here's what the PDU header looks like.
     40  * The length does include the version and length fields.
     41  */
     42 typedef struct rpki_rtr_pdu_ {
     43     u_char version;		/* Version number */
     44     u_char pdu_type;		/* PDU type */
     45     union {
     46 	u_char session_id[2];	/* Session id */
     47 	u_char error_code[2];	/* Error code */
     48     } u;
     49     u_char length[4];
     50 } rpki_rtr_pdu;
     51 #define RPKI_RTR_PDU_OVERHEAD (offsetof(rpki_rtr_pdu, rpki_rtr_pdu_msg))
     52 
     53 /*
     54  * IPv4 Prefix PDU.
     55  */
     56 typedef struct rpki_rtr_pdu_ipv4_prefix_ {
     57     rpki_rtr_pdu pdu_header;
     58     u_char flags;
     59     u_char prefix_length;
     60     u_char max_length;
     61     u_char zero;
     62     u_char prefix[4];
     63     u_char as[4];
     64 } rpki_rtr_pdu_ipv4_prefix;
     65 
     66 /*
     67  * IPv6 Prefix PDU.
     68  */
     69 typedef struct rpki_rtr_pdu_ipv6_prefix_ {
     70     rpki_rtr_pdu pdu_header;
     71     u_char flags;
     72     u_char prefix_length;
     73     u_char max_length;
     74     u_char zero;
     75     u_char prefix[16];
     76     u_char as[4];
     77 } rpki_rtr_pdu_ipv6_prefix;
     78 
     79 /*
     80  * Error report PDU.
     81  */
     82 typedef struct rpki_rtr_pdu_error_report_ {
     83     rpki_rtr_pdu pdu_header;
     84     u_char encapsulated_pdu_length[4]; /* Encapsulated PDU length */
     85 } rpki_rtr_pdu_error_report;
     86 
     87 /*
     88  * PDU type codes
     89  */
     90 #define RPKI_RTR_SERIAL_NOTIFY_PDU	0
     91 #define RPKI_RTR_SERIAL_QUERY_PDU	1
     92 #define RPKI_RTR_RESET_QUERY_PDU	2
     93 #define RPKI_RTR_CACHE_RESPONSE_PDU	3
     94 #define RPKI_RTR_IPV4_PREFIX_PDU	4
     95 #define RPKI_RTR_IPV6_PREFIX_PDU	6
     96 #define RPKI_RTR_END_OF_DATA_PDU	7
     97 #define RPKI_RTR_CACHE_RESET_PDU	8
     98 #define RPKI_RTR_ERROR_REPORT_PDU	10
     99 
    100 static const struct tok rpki_rtr_pdu_values[] = {
    101     { RPKI_RTR_SERIAL_NOTIFY_PDU, "Serial Notify" },
    102     { RPKI_RTR_SERIAL_QUERY_PDU, "Serial Query" },
    103     { RPKI_RTR_RESET_QUERY_PDU, "Reset Query" },
    104     { RPKI_RTR_CACHE_RESPONSE_PDU, "Cache Response" },
    105     { RPKI_RTR_IPV4_PREFIX_PDU, "IPV4 Prefix" },
    106     { RPKI_RTR_IPV6_PREFIX_PDU, "IPV6 Prefix" },
    107     { RPKI_RTR_END_OF_DATA_PDU, "End of Data" },
    108     { RPKI_RTR_CACHE_RESET_PDU, "Cache Reset" },
    109     { RPKI_RTR_ERROR_REPORT_PDU, "Error Report" },
    110     { 0, NULL}
    111 };
    112 
    113 static const struct tok rpki_rtr_error_codes[] = {
    114     { 0, "Corrupt Data" },
    115     { 1, "Internal Error" },
    116     { 2, "No Data Available" },
    117     { 3, "Invalid Request" },
    118     { 4, "Unsupported Protocol Version" },
    119     { 5, "Unsupported PDU Type" },
    120     { 6, "Withdrawal of Unknown Record" },
    121     { 7, "Duplicate Announcement Received" },
    122     { 0, NULL}
    123 };
    124 
    125 /*
    126  * Build a indentation string for a given indentation level.
    127  * XXX this should be really in util.c
    128  */
    129 static char *
    130 indent_string (u_int indent)
    131 {
    132     static char buf[20];
    133     u_int idx;
    134 
    135     idx = 0;
    136     buf[idx] = '\0';
    137 
    138     /*
    139      * Does the static buffer fit ?
    140      */
    141     if (sizeof(buf) < ((indent/8) + (indent %8) + 2)) {
    142 	return buf;
    143     }
    144 
    145     /*
    146      * Heading newline.
    147      */
    148     buf[idx] = '\n';
    149     idx++;
    150 
    151     while (indent >= 8) {
    152 	buf[idx] = '\t';
    153 	idx++;
    154 	indent -= 8;
    155     }
    156 
    157     while (indent > 0) {
    158 	buf[idx] = ' ';
    159 	idx++;
    160 	indent--;
    161     }
    162 
    163     /*
    164      * Trailing zero.
    165      */
    166     buf[idx] = '\0';
    167 
    168     return buf;
    169 }
    170 
    171 /*
    172  * Print a single PDU.
    173  */
    174 static int
    175 rpki_rtr_pdu_print (netdissect_options *ndo, const u_char *tptr, u_int indent)
    176 {
    177     const rpki_rtr_pdu *pdu_header;
    178     u_int pdu_type, pdu_len, hexdump;
    179     const u_char *msg;
    180 
    181     pdu_header = (const rpki_rtr_pdu *)tptr;
    182     pdu_type = pdu_header->pdu_type;
    183     pdu_len = EXTRACT_32BITS(pdu_header->length);
    184     ND_TCHECK2(*tptr, pdu_len);
    185     hexdump = FALSE;
    186 
    187     ND_PRINT((ndo, "%sRPKI-RTRv%u, %s PDU (%u), length: %u",
    188 	   indent_string(8),
    189 	   pdu_header->version,
    190 	   tok2str(rpki_rtr_pdu_values, "Unknown", pdu_type),
    191 	   pdu_type, pdu_len));
    192 
    193     switch (pdu_type) {
    194 
    195 	/*
    196 	 * The following PDUs share the message format.
    197 	 */
    198     case RPKI_RTR_SERIAL_NOTIFY_PDU:
    199     case RPKI_RTR_SERIAL_QUERY_PDU:
    200     case RPKI_RTR_END_OF_DATA_PDU:
    201         msg = (const u_char *)(pdu_header + 1);
    202 	ND_PRINT((ndo, "%sSession ID: 0x%04x, Serial: %u",
    203 	       indent_string(indent+2),
    204 	       EXTRACT_16BITS(pdu_header->u.session_id),
    205 	       EXTRACT_32BITS(msg)));
    206 	break;
    207 
    208 	/*
    209 	 * The following PDUs share the message format.
    210 	 */
    211     case RPKI_RTR_RESET_QUERY_PDU:
    212     case RPKI_RTR_CACHE_RESET_PDU:
    213 
    214 	/*
    215 	 * Zero payload PDUs.
    216 	 */
    217 	break;
    218 
    219     case RPKI_RTR_CACHE_RESPONSE_PDU:
    220 	ND_PRINT((ndo, "%sSession ID: 0x%04x",
    221 	       indent_string(indent+2),
    222 	       EXTRACT_16BITS(pdu_header->u.session_id)));
    223 	break;
    224 
    225     case RPKI_RTR_IPV4_PREFIX_PDU:
    226 	{
    227 	    const rpki_rtr_pdu_ipv4_prefix *pdu;
    228 
    229 	    pdu = (const rpki_rtr_pdu_ipv4_prefix *)tptr;
    230 	    ND_PRINT((ndo, "%sIPv4 Prefix %s/%u-%u, origin-as %u, flags 0x%02x",
    231 		   indent_string(indent+2),
    232 		   ipaddr_string(ndo, pdu->prefix),
    233 		   pdu->prefix_length, pdu->max_length,
    234 		   EXTRACT_32BITS(pdu->as), pdu->flags));
    235 	}
    236 	break;
    237 
    238     case RPKI_RTR_IPV6_PREFIX_PDU:
    239 	{
    240 	    const rpki_rtr_pdu_ipv6_prefix *pdu;
    241 
    242 	    pdu = (const rpki_rtr_pdu_ipv6_prefix *)tptr;
    243 	    ND_PRINT((ndo, "%sIPv6 Prefix %s/%u-%u, origin-as %u, flags 0x%02x",
    244 		   indent_string(indent+2),
    245 		   ip6addr_string(ndo, pdu->prefix),
    246 		   pdu->prefix_length, pdu->max_length,
    247 		   EXTRACT_32BITS(pdu->as), pdu->flags));
    248 	}
    249 	break;
    250 
    251     case RPKI_RTR_ERROR_REPORT_PDU:
    252 	{
    253 	    const rpki_rtr_pdu_error_report *pdu;
    254 	    u_int encapsulated_pdu_length, text_length, tlen, error_code;
    255 
    256 	    pdu = (const rpki_rtr_pdu_error_report *)tptr;
    257 	    encapsulated_pdu_length = EXTRACT_32BITS(pdu->encapsulated_pdu_length);
    258 	    ND_TCHECK2(*tptr, encapsulated_pdu_length);
    259 	    tlen = pdu_len;
    260 
    261 	    error_code = EXTRACT_16BITS(pdu->pdu_header.u.error_code);
    262 	    ND_PRINT((ndo, "%sError code: %s (%u), Encapsulated PDU length: %u",
    263 		   indent_string(indent+2),
    264 		   tok2str(rpki_rtr_error_codes, "Unknown", error_code),
    265 		   error_code, encapsulated_pdu_length));
    266 
    267 	    tptr += sizeof(*pdu);
    268 	    tlen -= sizeof(*pdu);
    269 
    270 	    /*
    271 	     * Recurse if there is an encapsulated PDU.
    272 	     */
    273 	    if (encapsulated_pdu_length &&
    274 		(encapsulated_pdu_length <= tlen)) {
    275 		ND_PRINT((ndo, "%s-----encapsulated PDU-----", indent_string(indent+4)));
    276 		if (rpki_rtr_pdu_print(ndo, tptr, indent+2))
    277 			goto trunc;
    278 	    }
    279 
    280 	    tptr += encapsulated_pdu_length;
    281 	    tlen -= encapsulated_pdu_length;
    282 
    283 	    /*
    284 	     * Extract, trail-zero and print the Error message.
    285 	     */
    286 	    text_length = 0;
    287 	    if (tlen > 4) {
    288 		text_length = EXTRACT_32BITS(tptr);
    289 		tptr += 4;
    290 		tlen -= 4;
    291 	    }
    292 	    ND_TCHECK2(*tptr, text_length);
    293 	    if (text_length && (text_length <= tlen )) {
    294 		ND_PRINT((ndo, "%sError text: ", indent_string(indent+2)));
    295 		if (fn_printn(ndo, tptr, text_length, ndo->ndo_snapend))
    296 			goto trunc;
    297 	    }
    298 	}
    299 	break;
    300 
    301     default:
    302 
    303 	/*
    304 	 * Unknown data, please hexdump.
    305 	 */
    306 	hexdump = TRUE;
    307     }
    308 
    309     /* do we also want to see a hex dump ? */
    310     if (ndo->ndo_vflag > 1 || (ndo->ndo_vflag && hexdump)) {
    311 	print_unknown_data(ndo,tptr,"\n\t  ", pdu_len);
    312     }
    313     return 0;
    314 
    315 trunc:
    316     return 1;
    317 }
    318 
    319 void
    320 rpki_rtr_print(netdissect_options *ndo, register const u_char *pptr, register u_int len)
    321 {
    322     u_int tlen, pdu_type, pdu_len;
    323     const u_char *tptr;
    324     const rpki_rtr_pdu *pdu_header;
    325 
    326     tptr = pptr;
    327     tlen = len;
    328 
    329     if (!ndo->ndo_vflag) {
    330 	ND_PRINT((ndo, ", RPKI-RTR"));
    331 	return;
    332     }
    333 
    334     while (tlen >= sizeof(rpki_rtr_pdu)) {
    335 
    336         ND_TCHECK2(*tptr, sizeof(rpki_rtr_pdu));
    337 
    338 	pdu_header = (const rpki_rtr_pdu *)tptr;
    339         pdu_type = pdu_header->pdu_type;
    340         pdu_len = EXTRACT_32BITS(pdu_header->length);
    341         ND_TCHECK2(*tptr, pdu_len);
    342 
    343         /* infinite loop check */
    344         if (!pdu_type || !pdu_len) {
    345             break;
    346         }
    347 
    348         if (tlen < pdu_len) {
    349             goto trunc;
    350         }
    351 
    352 	/*
    353 	 * Print the PDU.
    354 	 */
    355 	if (rpki_rtr_pdu_print(ndo, tptr, 8))
    356 		goto trunc;
    357 
    358         tlen -= pdu_len;
    359         tptr += pdu_len;
    360     }
    361     return;
    362 trunc:
    363     ND_PRINT((ndo, "\n\t%s", tstr));
    364 }
    365 
    366 /*
    367  * Local Variables:
    368  * c-style: whitesmith
    369  * c-basic-offset: 4
    370  * End:
    371  */
    372