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