nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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@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 | */ |