1 /* 2 * Copyright (c) 2003 Bruce M. Simpson <bms@spc.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Bruce M. Simpson. 16 * 4. Neither the name of Bruce M. Simpson nor the names of co- 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY Bruce M. Simpson AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Bruce M. Simpson OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* \summary: Ad hoc On-Demand Distance Vector (AODV) Routing printer */ 34 35 #ifdef HAVE_CONFIG_H 36 #include "config.h" 37 #endif 38 39 #include <netdissect-stdinc.h> 40 41 #include "netdissect.h" 42 #include "addrtoname.h" 43 #include "extract.h" 44 45 /* 46 * RFC 3561 47 */ 48 struct aodv_rreq { 49 uint8_t rreq_type; /* AODV message type (1) */ 50 uint8_t rreq_flags; /* various flags */ 51 uint8_t rreq_zero0; /* reserved, set to zero */ 52 uint8_t rreq_hops; /* number of hops from originator */ 53 uint32_t rreq_id; /* request ID */ 54 uint32_t rreq_da; /* destination IPv4 address */ 55 uint32_t rreq_ds; /* destination sequence number */ 56 uint32_t rreq_oa; /* originator IPv4 address */ 57 uint32_t rreq_os; /* originator sequence number */ 58 }; 59 struct aodv_rreq6 { 60 uint8_t rreq_type; /* AODV message type (1) */ 61 uint8_t rreq_flags; /* various flags */ 62 uint8_t rreq_zero0; /* reserved, set to zero */ 63 uint8_t rreq_hops; /* number of hops from originator */ 64 uint32_t rreq_id; /* request ID */ 65 struct in6_addr rreq_da; /* destination IPv6 address */ 66 uint32_t rreq_ds; /* destination sequence number */ 67 struct in6_addr rreq_oa; /* originator IPv6 address */ 68 uint32_t rreq_os; /* originator sequence number */ 69 }; 70 struct aodv_rreq6_draft_01 { 71 uint8_t rreq_type; /* AODV message type (16) */ 72 uint8_t rreq_flags; /* various flags */ 73 uint8_t rreq_zero0; /* reserved, set to zero */ 74 uint8_t rreq_hops; /* number of hops from originator */ 75 uint32_t rreq_id; /* request ID */ 76 uint32_t rreq_ds; /* destination sequence number */ 77 uint32_t rreq_os; /* originator sequence number */ 78 struct in6_addr rreq_da; /* destination IPv6 address */ 79 struct in6_addr rreq_oa; /* originator IPv6 address */ 80 }; 81 82 #define RREQ_JOIN 0x80 /* join (reserved for multicast */ 83 #define RREQ_REPAIR 0x40 /* repair (reserved for multicast */ 84 #define RREQ_GRAT 0x20 /* gratuitous RREP */ 85 #define RREQ_DEST 0x10 /* destination only */ 86 #define RREQ_UNKNOWN 0x08 /* unknown destination sequence num */ 87 #define RREQ_FLAGS_MASK 0xF8 /* mask for rreq_flags */ 88 89 struct aodv_rrep { 90 uint8_t rrep_type; /* AODV message type (2) */ 91 uint8_t rrep_flags; /* various flags */ 92 uint8_t rrep_ps; /* prefix size */ 93 uint8_t rrep_hops; /* number of hops from o to d */ 94 uint32_t rrep_da; /* destination IPv4 address */ 95 uint32_t rrep_ds; /* destination sequence number */ 96 uint32_t rrep_oa; /* originator IPv4 address */ 97 uint32_t rrep_life; /* lifetime of this route */ 98 }; 99 struct aodv_rrep6 { 100 uint8_t rrep_type; /* AODV message type (2) */ 101 uint8_t rrep_flags; /* various flags */ 102 uint8_t rrep_ps; /* prefix size */ 103 uint8_t rrep_hops; /* number of hops from o to d */ 104 struct in6_addr rrep_da; /* destination IPv6 address */ 105 uint32_t rrep_ds; /* destination sequence number */ 106 struct in6_addr rrep_oa; /* originator IPv6 address */ 107 uint32_t rrep_life; /* lifetime of this route */ 108 }; 109 struct aodv_rrep6_draft_01 { 110 uint8_t rrep_type; /* AODV message type (17) */ 111 uint8_t rrep_flags; /* various flags */ 112 uint8_t rrep_ps; /* prefix size */ 113 uint8_t rrep_hops; /* number of hops from o to d */ 114 uint32_t rrep_ds; /* destination sequence number */ 115 struct in6_addr rrep_da; /* destination IPv6 address */ 116 struct in6_addr rrep_oa; /* originator IPv6 address */ 117 uint32_t rrep_life; /* lifetime of this route */ 118 }; 119 120 #define RREP_REPAIR 0x80 /* repair (reserved for multicast */ 121 #define RREP_ACK 0x40 /* acknowledgement required */ 122 #define RREP_FLAGS_MASK 0xC0 /* mask for rrep_flags */ 123 #define RREP_PREFIX_MASK 0x1F /* mask for prefix size */ 124 125 struct rerr_unreach { 126 uint32_t u_da; /* IPv4 address */ 127 uint32_t u_ds; /* sequence number */ 128 }; 129 struct rerr_unreach6 { 130 struct in6_addr u_da; /* IPv6 address */ 131 uint32_t u_ds; /* sequence number */ 132 }; 133 struct rerr_unreach6_draft_01 { 134 struct in6_addr u_da; /* IPv6 address */ 135 uint32_t u_ds; /* sequence number */ 136 }; 137 138 struct aodv_rerr { 139 uint8_t rerr_type; /* AODV message type (3 or 18) */ 140 uint8_t rerr_flags; /* various flags */ 141 uint8_t rerr_zero0; /* reserved, set to zero */ 142 uint8_t rerr_dc; /* destination count */ 143 }; 144 145 #define RERR_NODELETE 0x80 /* don't delete the link */ 146 #define RERR_FLAGS_MASK 0x80 /* mask for rerr_flags */ 147 148 struct aodv_rrep_ack { 149 uint8_t ra_type; 150 uint8_t ra_zero0; 151 }; 152 153 #define AODV_RREQ 1 /* route request */ 154 #define AODV_RREP 2 /* route response */ 155 #define AODV_RERR 3 /* error report */ 156 #define AODV_RREP_ACK 4 /* route response acknowledgement */ 157 158 #define AODV_V6_DRAFT_01_RREQ 16 /* IPv6 route request */ 159 #define AODV_V6_DRAFT_01_RREP 17 /* IPv6 route response */ 160 #define AODV_V6_DRAFT_01_RERR 18 /* IPv6 error report */ 161 #define AODV_V6_DRAFT_01_RREP_ACK 19 /* IPV6 route response acknowledgment */ 162 163 struct aodv_ext { 164 uint8_t type; /* extension type */ 165 uint8_t length; /* extension length */ 166 }; 167 168 struct aodv_hello { 169 struct aodv_ext eh; /* extension header */ 170 uint8_t interval[4]; /* expect my next hello in 171 * (n) ms 172 * NOTE: this is not aligned */ 173 }; 174 175 #define AODV_EXT_HELLO 1 176 177 static void 178 aodv_extension(netdissect_options *ndo, 179 const struct aodv_ext *ep, u_int length) 180 { 181 const struct aodv_hello *ah; 182 183 ND_TCHECK(*ep); 184 switch (ep->type) { 185 case AODV_EXT_HELLO: 186 ah = (const struct aodv_hello *)(const void *)ep; 187 ND_TCHECK(*ah); 188 if (length < sizeof(struct aodv_hello)) 189 goto trunc; 190 if (ep->length < 4) { 191 ND_PRINT((ndo, "\n\text HELLO - bad length %u", ep->length)); 192 break; 193 } 194 ND_PRINT((ndo, "\n\text HELLO %ld ms", 195 (unsigned long)EXTRACT_32BITS(&ah->interval))); 196 break; 197 198 default: 199 ND_PRINT((ndo, "\n\text %u %u", ep->type, ep->length)); 200 break; 201 } 202 return; 203 204 trunc: 205 ND_PRINT((ndo, " [|hello]")); 206 } 207 208 static void 209 aodv_rreq(netdissect_options *ndo, const u_char *dat, u_int length) 210 { 211 u_int i; 212 const struct aodv_rreq *ap = (const struct aodv_rreq *)dat; 213 214 ND_TCHECK(*ap); 215 if (length < sizeof(*ap)) 216 goto trunc; 217 ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n" 218 "\tdst %s seq %lu src %s seq %lu", length, 219 ap->rreq_type & RREQ_JOIN ? "[J]" : "", 220 ap->rreq_type & RREQ_REPAIR ? "[R]" : "", 221 ap->rreq_type & RREQ_GRAT ? "[G]" : "", 222 ap->rreq_type & RREQ_DEST ? "[D]" : "", 223 ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ", 224 ap->rreq_hops, 225 (unsigned long)EXTRACT_32BITS(&ap->rreq_id), 226 ipaddr_string(ndo, &ap->rreq_da), 227 (unsigned long)EXTRACT_32BITS(&ap->rreq_ds), 228 ipaddr_string(ndo, &ap->rreq_oa), 229 (unsigned long)EXTRACT_32BITS(&ap->rreq_os))); 230 i = length - sizeof(*ap); 231 if (i >= sizeof(struct aodv_ext)) 232 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 233 return; 234 235 trunc: 236 ND_PRINT((ndo, " [|rreq")); 237 } 238 239 static void 240 aodv_rrep(netdissect_options *ndo, const u_char *dat, u_int length) 241 { 242 u_int i; 243 const struct aodv_rrep *ap = (const struct aodv_rrep *)dat; 244 245 ND_TCHECK(*ap); 246 if (length < sizeof(*ap)) 247 goto trunc; 248 ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n" 249 "\tdst %s dseq %lu src %s %lu ms", length, 250 ap->rrep_type & RREP_REPAIR ? "[R]" : "", 251 ap->rrep_type & RREP_ACK ? "[A] " : " ", 252 ap->rrep_ps & RREP_PREFIX_MASK, 253 ap->rrep_hops, 254 ipaddr_string(ndo, &ap->rrep_da), 255 (unsigned long)EXTRACT_32BITS(&ap->rrep_ds), 256 ipaddr_string(ndo, &ap->rrep_oa), 257 (unsigned long)EXTRACT_32BITS(&ap->rrep_life))); 258 i = length - sizeof(*ap); 259 if (i >= sizeof(struct aodv_ext)) 260 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 261 return; 262 263 trunc: 264 ND_PRINT((ndo, " [|rreq")); 265 } 266 267 static void 268 aodv_rerr(netdissect_options *ndo, const u_char *dat, u_int length) 269 { 270 u_int i, dc; 271 const struct aodv_rerr *ap = (const struct aodv_rerr *)dat; 272 const struct rerr_unreach *dp; 273 274 ND_TCHECK(*ap); 275 if (length < sizeof(*ap)) 276 goto trunc; 277 ND_PRINT((ndo, " rerr %s [items %u] [%u]:", 278 ap->rerr_flags & RERR_NODELETE ? "[D]" : "", 279 ap->rerr_dc, length)); 280 dp = (const struct rerr_unreach *)(dat + sizeof(*ap)); 281 i = length - sizeof(*ap); 282 for (dc = ap->rerr_dc; dc != 0; dc--) { 283 ND_TCHECK(*dp); 284 if (i < sizeof(*dp)) 285 goto trunc; 286 ND_PRINT((ndo, " {%s}(%ld)", ipaddr_string(ndo, &dp->u_da), 287 (unsigned long)EXTRACT_32BITS(&dp->u_ds))); 288 dp++; 289 i -= sizeof(*dp); 290 } 291 return; 292 293 trunc: 294 ND_PRINT((ndo, "[|rerr]")); 295 } 296 297 static void 298 aodv_v6_rreq(netdissect_options *ndo, const u_char *dat, u_int length) 299 { 300 u_int i; 301 const struct aodv_rreq6 *ap = (const struct aodv_rreq6 *)dat; 302 303 ND_TCHECK(*ap); 304 if (length < sizeof(*ap)) 305 goto trunc; 306 ND_PRINT((ndo, " v6 rreq %u %s%s%s%s%shops %u id 0x%08lx\n" 307 "\tdst %s seq %lu src %s seq %lu", length, 308 ap->rreq_type & RREQ_JOIN ? "[J]" : "", 309 ap->rreq_type & RREQ_REPAIR ? "[R]" : "", 310 ap->rreq_type & RREQ_GRAT ? "[G]" : "", 311 ap->rreq_type & RREQ_DEST ? "[D]" : "", 312 ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ", 313 ap->rreq_hops, 314 (unsigned long)EXTRACT_32BITS(&ap->rreq_id), 315 ip6addr_string(ndo, &ap->rreq_da), 316 (unsigned long)EXTRACT_32BITS(&ap->rreq_ds), 317 ip6addr_string(ndo, &ap->rreq_oa), 318 (unsigned long)EXTRACT_32BITS(&ap->rreq_os))); 319 i = length - sizeof(*ap); 320 if (i >= sizeof(struct aodv_ext)) 321 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 322 return; 323 324 trunc: 325 ND_PRINT((ndo, " [|rreq")); 326 } 327 328 static void 329 aodv_v6_rrep(netdissect_options *ndo, const u_char *dat, u_int length) 330 { 331 u_int i; 332 const struct aodv_rrep6 *ap = (const struct aodv_rrep6 *)dat; 333 334 ND_TCHECK(*ap); 335 if (length < sizeof(*ap)) 336 goto trunc; 337 ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n" 338 "\tdst %s dseq %lu src %s %lu ms", length, 339 ap->rrep_type & RREP_REPAIR ? "[R]" : "", 340 ap->rrep_type & RREP_ACK ? "[A] " : " ", 341 ap->rrep_ps & RREP_PREFIX_MASK, 342 ap->rrep_hops, 343 ip6addr_string(ndo, &ap->rrep_da), 344 (unsigned long)EXTRACT_32BITS(&ap->rrep_ds), 345 ip6addr_string(ndo, &ap->rrep_oa), 346 (unsigned long)EXTRACT_32BITS(&ap->rrep_life))); 347 i = length - sizeof(*ap); 348 if (i >= sizeof(struct aodv_ext)) 349 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 350 return; 351 352 trunc: 353 ND_PRINT((ndo, " [|rreq")); 354 } 355 356 static void 357 aodv_v6_rerr(netdissect_options *ndo, const u_char *dat, u_int length) 358 { 359 u_int i, dc; 360 const struct aodv_rerr *ap = (const struct aodv_rerr *)dat; 361 const struct rerr_unreach6 *dp6; 362 363 ND_TCHECK(*ap); 364 if (length < sizeof(*ap)) 365 goto trunc; 366 ND_PRINT((ndo, " rerr %s [items %u] [%u]:", 367 ap->rerr_flags & RERR_NODELETE ? "[D]" : "", 368 ap->rerr_dc, length)); 369 dp6 = (const struct rerr_unreach6 *)(const void *)(ap + 1); 370 i = length - sizeof(*ap); 371 for (dc = ap->rerr_dc; dc != 0; dc--) { 372 ND_TCHECK(*dp6); 373 if (i < sizeof(*dp6)) 374 goto trunc; 375 ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da), 376 (unsigned long)EXTRACT_32BITS(&dp6->u_ds))); 377 dp6++; 378 i -= sizeof(*dp6); 379 } 380 return; 381 382 trunc: 383 ND_PRINT((ndo, "[|rerr]")); 384 } 385 386 static void 387 aodv_v6_draft_01_rreq(netdissect_options *ndo, const u_char *dat, u_int length) 388 { 389 u_int i; 390 const struct aodv_rreq6_draft_01 *ap = (const struct aodv_rreq6_draft_01 *)dat; 391 392 ND_TCHECK(*ap); 393 if (length < sizeof(*ap)) 394 goto trunc; 395 ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n" 396 "\tdst %s seq %lu src %s seq %lu", length, 397 ap->rreq_type & RREQ_JOIN ? "[J]" : "", 398 ap->rreq_type & RREQ_REPAIR ? "[R]" : "", 399 ap->rreq_type & RREQ_GRAT ? "[G]" : "", 400 ap->rreq_type & RREQ_DEST ? "[D]" : "", 401 ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ", 402 ap->rreq_hops, 403 (unsigned long)EXTRACT_32BITS(&ap->rreq_id), 404 ip6addr_string(ndo, &ap->rreq_da), 405 (unsigned long)EXTRACT_32BITS(&ap->rreq_ds), 406 ip6addr_string(ndo, &ap->rreq_oa), 407 (unsigned long)EXTRACT_32BITS(&ap->rreq_os))); 408 i = length - sizeof(*ap); 409 if (i >= sizeof(struct aodv_ext)) 410 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 411 return; 412 413 trunc: 414 ND_PRINT((ndo, " [|rreq")); 415 } 416 417 static void 418 aodv_v6_draft_01_rrep(netdissect_options *ndo, const u_char *dat, u_int length) 419 { 420 u_int i; 421 const struct aodv_rrep6_draft_01 *ap = (const struct aodv_rrep6_draft_01 *)dat; 422 423 ND_TCHECK(*ap); 424 if (length < sizeof(*ap)) 425 goto trunc; 426 ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n" 427 "\tdst %s dseq %lu src %s %lu ms", length, 428 ap->rrep_type & RREP_REPAIR ? "[R]" : "", 429 ap->rrep_type & RREP_ACK ? "[A] " : " ", 430 ap->rrep_ps & RREP_PREFIX_MASK, 431 ap->rrep_hops, 432 ip6addr_string(ndo, &ap->rrep_da), 433 (unsigned long)EXTRACT_32BITS(&ap->rrep_ds), 434 ip6addr_string(ndo, &ap->rrep_oa), 435 (unsigned long)EXTRACT_32BITS(&ap->rrep_life))); 436 i = length - sizeof(*ap); 437 if (i >= sizeof(struct aodv_ext)) 438 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 439 return; 440 441 trunc: 442 ND_PRINT((ndo, " [|rreq")); 443 } 444 445 static void 446 aodv_v6_draft_01_rerr(netdissect_options *ndo, const u_char *dat, u_int length) 447 { 448 u_int i, dc; 449 const struct aodv_rerr *ap = (const struct aodv_rerr *)dat; 450 const struct rerr_unreach6_draft_01 *dp6; 451 452 ND_TCHECK(*ap); 453 if (length < sizeof(*ap)) 454 goto trunc; 455 ND_PRINT((ndo, " rerr %s [items %u] [%u]:", 456 ap->rerr_flags & RERR_NODELETE ? "[D]" : "", 457 ap->rerr_dc, length)); 458 dp6 = (const struct rerr_unreach6_draft_01 *)(const void *)(ap + 1); 459 i = length - sizeof(*ap); 460 for (dc = ap->rerr_dc; dc != 0; dc--) { 461 ND_TCHECK(*dp6); 462 if (i < sizeof(*dp6)) 463 goto trunc; 464 ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da), 465 (unsigned long)EXTRACT_32BITS(&dp6->u_ds))); 466 dp6++; 467 i -= sizeof(*dp6); 468 } 469 return; 470 471 trunc: 472 ND_PRINT((ndo, "[|rerr]")); 473 } 474 475 void 476 aodv_print(netdissect_options *ndo, 477 const u_char *dat, u_int length, int is_ip6) 478 { 479 uint8_t msg_type; 480 481 /* 482 * The message type is the first byte; make sure we have it 483 * and then fetch it. 484 */ 485 ND_TCHECK(*dat); 486 msg_type = *dat; 487 ND_PRINT((ndo, " aodv")); 488 489 switch (msg_type) { 490 491 case AODV_RREQ: 492 if (is_ip6) 493 aodv_v6_rreq(ndo, dat, length); 494 else 495 aodv_rreq(ndo, dat, length); 496 break; 497 498 case AODV_RREP: 499 if (is_ip6) 500 aodv_v6_rrep(ndo, dat, length); 501 else 502 aodv_rrep(ndo, dat, length); 503 break; 504 505 case AODV_RERR: 506 if (is_ip6) 507 aodv_v6_rerr(ndo, dat, length); 508 else 509 aodv_rerr(ndo, dat, length); 510 break; 511 512 case AODV_RREP_ACK: 513 ND_PRINT((ndo, " rrep-ack %u", length)); 514 break; 515 516 case AODV_V6_DRAFT_01_RREQ: 517 aodv_v6_draft_01_rreq(ndo, dat, length); 518 break; 519 520 case AODV_V6_DRAFT_01_RREP: 521 aodv_v6_draft_01_rrep(ndo, dat, length); 522 break; 523 524 case AODV_V6_DRAFT_01_RERR: 525 aodv_v6_draft_01_rerr(ndo, dat, length); 526 break; 527 528 case AODV_V6_DRAFT_01_RREP_ACK: 529 ND_PRINT((ndo, " rrep-ack %u", length)); 530 break; 531 532 default: 533 ND_PRINT((ndo, " type %u %u", msg_type, length)); 534 } 535 return; 536 537 trunc: 538 ND_PRINT((ndo, " [|aodv]")); 539 } 540