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 nd_uint8_t rreq_type; /* AODV message type (1) */ 50 nd_uint8_t rreq_flags; /* various flags */ 51 nd_uint8_t rreq_zero0; /* reserved, set to zero */ 52 nd_uint8_t rreq_hops; /* number of hops from originator */ 53 nd_uint32_t rreq_id; /* request ID */ 54 nd_ipv4 rreq_da; /* destination IPv4 address */ 55 nd_uint32_t rreq_ds; /* destination sequence number */ 56 nd_ipv4 rreq_oa; /* originator IPv4 address */ 57 nd_uint32_t rreq_os; /* originator sequence number */ 58 }; 59 struct aodv_rreq6 { 60 nd_uint8_t rreq_type; /* AODV message type (1) */ 61 nd_uint8_t rreq_flags; /* various flags */ 62 nd_uint8_t rreq_zero0; /* reserved, set to zero */ 63 nd_uint8_t rreq_hops; /* number of hops from originator */ 64 nd_uint32_t rreq_id; /* request ID */ 65 nd_ipv6 rreq_da; /* destination IPv6 address */ 66 nd_uint32_t rreq_ds; /* destination sequence number */ 67 nd_ipv6 rreq_oa; /* originator IPv6 address */ 68 nd_uint32_t rreq_os; /* originator sequence number */ 69 }; 70 struct aodv_rreq6_draft_01 { 71 nd_uint8_t rreq_type; /* AODV message type (16) */ 72 nd_uint8_t rreq_flags; /* various flags */ 73 nd_uint8_t rreq_zero0; /* reserved, set to zero */ 74 nd_uint8_t rreq_hops; /* number of hops from originator */ 75 nd_uint32_t rreq_id; /* request ID */ 76 nd_uint32_t rreq_ds; /* destination sequence number */ 77 nd_uint32_t rreq_os; /* originator sequence number */ 78 nd_ipv6 rreq_da; /* destination IPv6 address */ 79 nd_ipv6 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 nd_uint8_t rrep_type; /* AODV message type (2) */ 91 nd_uint8_t rrep_flags; /* various flags */ 92 nd_uint8_t rrep_ps; /* prefix size */ 93 nd_uint8_t rrep_hops; /* number of hops from o to d */ 94 nd_ipv4 rrep_da; /* destination IPv4 address */ 95 nd_uint32_t rrep_ds; /* destination sequence number */ 96 nd_ipv4 rrep_oa; /* originator IPv4 address */ 97 nd_uint32_t rrep_life; /* lifetime of this route */ 98 }; 99 struct aodv_rrep6 { 100 nd_uint8_t rrep_type; /* AODV message type (2) */ 101 nd_uint8_t rrep_flags; /* various flags */ 102 nd_uint8_t rrep_ps; /* prefix size */ 103 nd_uint8_t rrep_hops; /* number of hops from o to d */ 104 nd_ipv6 rrep_da; /* destination IPv6 address */ 105 nd_uint32_t rrep_ds; /* destination sequence number */ 106 nd_ipv6 rrep_oa; /* originator IPv6 address */ 107 nd_uint32_t rrep_life; /* lifetime of this route */ 108 }; 109 struct aodv_rrep6_draft_01 { 110 nd_uint8_t rrep_type; /* AODV message type (17) */ 111 nd_uint8_t rrep_flags; /* various flags */ 112 nd_uint8_t rrep_ps; /* prefix size */ 113 nd_uint8_t rrep_hops; /* number of hops from o to d */ 114 nd_uint32_t rrep_ds; /* destination sequence number */ 115 nd_ipv6 rrep_da; /* destination IPv6 address */ 116 nd_ipv6 rrep_oa; /* originator IPv6 address */ 117 nd_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 nd_ipv4 u_da; /* IPv4 address */ 127 nd_uint32_t u_ds; /* sequence number */ 128 }; 129 struct rerr_unreach6 { 130 nd_ipv6 u_da; /* IPv6 address */ 131 nd_uint32_t u_ds; /* sequence number */ 132 }; 133 struct rerr_unreach6_draft_01 { 134 nd_ipv6 u_da; /* IPv6 address */ 135 nd_uint32_t u_ds; /* sequence number */ 136 }; 137 138 struct aodv_rerr { 139 nd_uint8_t rerr_type; /* AODV message type (3 or 18) */ 140 nd_uint8_t rerr_flags; /* various flags */ 141 nd_uint8_t rerr_zero0; /* reserved, set to zero */ 142 nd_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 nd_uint8_t ra_type; 150 nd_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 nd_uint8_t type; /* extension type */ 165 nd_uint8_t length; /* extension length */ 166 }; 167 168 struct aodv_hello { 169 struct aodv_ext eh; /* extension header */ 170 nd_uint32_t interval; /* 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_SIZE(ep); 184 switch (GET_U_1(ep->type)) { 185 case AODV_EXT_HELLO: 186 ah = (const struct aodv_hello *)(const void *)ep; 187 ND_TCHECK_SIZE(ah); 188 if (length < sizeof(struct aodv_hello)) 189 goto trunc; 190 if (GET_U_1(ep->length) < 4) { 191 ND_PRINT("\n\text HELLO - bad length %u", 192 GET_U_1(ep->length)); 193 break; 194 } 195 ND_PRINT("\n\text HELLO %u ms", 196 GET_BE_U_4(ah->interval)); 197 break; 198 199 default: 200 ND_PRINT("\n\text %u %u", GET_U_1(ep->type), 201 GET_U_1(ep->length)); 202 break; 203 } 204 return; 205 206 trunc: 207 nd_print_trunc(ndo); 208 } 209 210 static void 211 aodv_rreq(netdissect_options *ndo, const u_char *dat, u_int length) 212 { 213 u_int i; 214 const struct aodv_rreq *ap = (const struct aodv_rreq *)dat; 215 216 ND_TCHECK_SIZE(ap); 217 if (length < sizeof(*ap)) 218 goto trunc; 219 ND_PRINT(" rreq %u %s%s%s%s%shops %u id 0x%08x\n" 220 "\tdst %s seq %u src %s seq %u", length, 221 GET_U_1(ap->rreq_type) & RREQ_JOIN ? "[J]" : "", 222 GET_U_1(ap->rreq_type) & RREQ_REPAIR ? "[R]" : "", 223 GET_U_1(ap->rreq_type) & RREQ_GRAT ? "[G]" : "", 224 GET_U_1(ap->rreq_type) & RREQ_DEST ? "[D]" : "", 225 GET_U_1(ap->rreq_type) & RREQ_UNKNOWN ? "[U] " : " ", 226 GET_U_1(ap->rreq_hops), 227 GET_BE_U_4(ap->rreq_id), 228 GET_IPADDR_STRING(ap->rreq_da), 229 GET_BE_U_4(ap->rreq_ds), 230 GET_IPADDR_STRING(ap->rreq_oa), 231 GET_BE_U_4(ap->rreq_os)); 232 i = length - sizeof(*ap); 233 if (i >= sizeof(struct aodv_ext)) 234 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 235 return; 236 237 trunc: 238 nd_print_trunc(ndo); 239 } 240 241 static void 242 aodv_rrep(netdissect_options *ndo, const u_char *dat, u_int length) 243 { 244 u_int i; 245 const struct aodv_rrep *ap = (const struct aodv_rrep *)dat; 246 247 ND_TCHECK_SIZE(ap); 248 if (length < sizeof(*ap)) 249 goto trunc; 250 ND_PRINT(" rrep %u %s%sprefix %u hops %u\n" 251 "\tdst %s dseq %u src %s %u ms", length, 252 GET_U_1(ap->rrep_type) & RREP_REPAIR ? "[R]" : "", 253 GET_U_1(ap->rrep_type) & RREP_ACK ? "[A] " : " ", 254 GET_U_1(ap->rrep_ps) & RREP_PREFIX_MASK, 255 GET_U_1(ap->rrep_hops), 256 GET_IPADDR_STRING(ap->rrep_da), 257 GET_BE_U_4(ap->rrep_ds), 258 GET_IPADDR_STRING(ap->rrep_oa), 259 GET_BE_U_4(ap->rrep_life)); 260 i = length - sizeof(*ap); 261 if (i >= sizeof(struct aodv_ext)) 262 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 263 return; 264 265 trunc: 266 nd_print_trunc(ndo); 267 } 268 269 static void 270 aodv_rerr(netdissect_options *ndo, const u_char *dat, u_int length) 271 { 272 u_int i, dc; 273 const struct aodv_rerr *ap = (const struct aodv_rerr *)dat; 274 const struct rerr_unreach *dp; 275 276 ND_TCHECK_SIZE(ap); 277 if (length < sizeof(*ap)) 278 goto trunc; 279 ND_PRINT(" rerr %s [items %u] [%u]:", 280 GET_U_1(ap->rerr_flags) & RERR_NODELETE ? "[D]" : "", 281 GET_U_1(ap->rerr_dc), length); 282 dp = (const struct rerr_unreach *)(dat + sizeof(*ap)); 283 i = length - sizeof(*ap); 284 for (dc = GET_U_1(ap->rerr_dc); dc != 0; dc--) { 285 ND_TCHECK_SIZE(dp); 286 if (i < sizeof(*dp)) 287 goto trunc; 288 ND_PRINT(" {%s}(%u)", GET_IPADDR_STRING(dp->u_da), 289 GET_BE_U_4(dp->u_ds)); 290 dp++; 291 i -= sizeof(*dp); 292 } 293 return; 294 295 trunc: 296 nd_print_trunc(ndo); 297 } 298 299 static void 300 aodv_v6_rreq(netdissect_options *ndo, const u_char *dat, u_int length) 301 { 302 u_int i; 303 const struct aodv_rreq6 *ap = (const struct aodv_rreq6 *)dat; 304 305 ND_TCHECK_SIZE(ap); 306 if (length < sizeof(*ap)) 307 goto trunc; 308 ND_PRINT(" v6 rreq %u %s%s%s%s%shops %u id 0x%08x\n" 309 "\tdst %s seq %u src %s seq %u", length, 310 GET_U_1(ap->rreq_type) & RREQ_JOIN ? "[J]" : "", 311 GET_U_1(ap->rreq_type) & RREQ_REPAIR ? "[R]" : "", 312 GET_U_1(ap->rreq_type) & RREQ_GRAT ? "[G]" : "", 313 GET_U_1(ap->rreq_type) & RREQ_DEST ? "[D]" : "", 314 GET_U_1(ap->rreq_type) & RREQ_UNKNOWN ? "[U] " : " ", 315 GET_U_1(ap->rreq_hops), 316 GET_BE_U_4(ap->rreq_id), 317 GET_IP6ADDR_STRING(ap->rreq_da), 318 GET_BE_U_4(ap->rreq_ds), 319 GET_IP6ADDR_STRING(ap->rreq_oa), 320 GET_BE_U_4(ap->rreq_os)); 321 i = length - sizeof(*ap); 322 if (i >= sizeof(struct aodv_ext)) 323 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 324 return; 325 326 trunc: 327 nd_print_trunc(ndo); 328 } 329 330 static void 331 aodv_v6_rrep(netdissect_options *ndo, const u_char *dat, u_int length) 332 { 333 u_int i; 334 const struct aodv_rrep6 *ap = (const struct aodv_rrep6 *)dat; 335 336 ND_TCHECK_SIZE(ap); 337 if (length < sizeof(*ap)) 338 goto trunc; 339 ND_PRINT(" rrep %u %s%sprefix %u hops %u\n" 340 "\tdst %s dseq %u src %s %u ms", length, 341 GET_U_1(ap->rrep_type) & RREP_REPAIR ? "[R]" : "", 342 GET_U_1(ap->rrep_type) & RREP_ACK ? "[A] " : " ", 343 GET_U_1(ap->rrep_ps) & RREP_PREFIX_MASK, 344 GET_U_1(ap->rrep_hops), 345 GET_IP6ADDR_STRING(ap->rrep_da), 346 GET_BE_U_4(ap->rrep_ds), 347 GET_IP6ADDR_STRING(ap->rrep_oa), 348 GET_BE_U_4(ap->rrep_life)); 349 i = length - sizeof(*ap); 350 if (i >= sizeof(struct aodv_ext)) 351 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 352 return; 353 354 trunc: 355 nd_print_trunc(ndo); 356 } 357 358 static void 359 aodv_v6_rerr(netdissect_options *ndo, const u_char *dat, u_int length) 360 { 361 u_int i, dc; 362 const struct aodv_rerr *ap = (const struct aodv_rerr *)dat; 363 const struct rerr_unreach6 *dp6; 364 365 ND_TCHECK_SIZE(ap); 366 if (length < sizeof(*ap)) 367 goto trunc; 368 ND_PRINT(" rerr %s [items %u] [%u]:", 369 GET_U_1(ap->rerr_flags) & RERR_NODELETE ? "[D]" : "", 370 GET_U_1(ap->rerr_dc), length); 371 dp6 = (const struct rerr_unreach6 *)(const void *)(ap + 1); 372 i = length - sizeof(*ap); 373 for (dc = GET_U_1(ap->rerr_dc); dc != 0; dc--) { 374 ND_TCHECK_SIZE(dp6); 375 if (i < sizeof(*dp6)) 376 goto trunc; 377 ND_PRINT(" {%s}(%u)", GET_IP6ADDR_STRING(dp6->u_da), 378 GET_BE_U_4(dp6->u_ds)); 379 dp6++; 380 i -= sizeof(*dp6); 381 } 382 return; 383 384 trunc: 385 nd_print_trunc(ndo); 386 } 387 388 static void 389 aodv_v6_draft_01_rreq(netdissect_options *ndo, const u_char *dat, u_int length) 390 { 391 u_int i; 392 const struct aodv_rreq6_draft_01 *ap = (const struct aodv_rreq6_draft_01 *)dat; 393 394 ND_TCHECK_SIZE(ap); 395 if (length < sizeof(*ap)) 396 goto trunc; 397 ND_PRINT(" rreq %u %s%s%s%s%shops %u id 0x%08x\n" 398 "\tdst %s seq %u src %s seq %u", length, 399 GET_U_1(ap->rreq_type) & RREQ_JOIN ? "[J]" : "", 400 GET_U_1(ap->rreq_type) & RREQ_REPAIR ? "[R]" : "", 401 GET_U_1(ap->rreq_type) & RREQ_GRAT ? "[G]" : "", 402 GET_U_1(ap->rreq_type) & RREQ_DEST ? "[D]" : "", 403 GET_U_1(ap->rreq_type) & RREQ_UNKNOWN ? "[U] " : " ", 404 GET_U_1(ap->rreq_hops), 405 GET_BE_U_4(ap->rreq_id), 406 GET_IP6ADDR_STRING(ap->rreq_da), 407 GET_BE_U_4(ap->rreq_ds), 408 GET_IP6ADDR_STRING(ap->rreq_oa), 409 GET_BE_U_4(ap->rreq_os)); 410 i = length - sizeof(*ap); 411 if (i >= sizeof(struct aodv_ext)) 412 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 413 return; 414 415 trunc: 416 nd_print_trunc(ndo); 417 } 418 419 static void 420 aodv_v6_draft_01_rrep(netdissect_options *ndo, const u_char *dat, u_int length) 421 { 422 u_int i; 423 const struct aodv_rrep6_draft_01 *ap = (const struct aodv_rrep6_draft_01 *)dat; 424 425 ND_TCHECK_SIZE(ap); 426 if (length < sizeof(*ap)) 427 goto trunc; 428 ND_PRINT(" rrep %u %s%sprefix %u hops %u\n" 429 "\tdst %s dseq %u src %s %u ms", length, 430 GET_U_1(ap->rrep_type) & RREP_REPAIR ? "[R]" : "", 431 GET_U_1(ap->rrep_type) & RREP_ACK ? "[A] " : " ", 432 GET_U_1(ap->rrep_ps) & RREP_PREFIX_MASK, 433 GET_U_1(ap->rrep_hops), 434 GET_IP6ADDR_STRING(ap->rrep_da), 435 GET_BE_U_4(ap->rrep_ds), 436 GET_IP6ADDR_STRING(ap->rrep_oa), 437 GET_BE_U_4(ap->rrep_life)); 438 i = length - sizeof(*ap); 439 if (i >= sizeof(struct aodv_ext)) 440 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); 441 return; 442 443 trunc: 444 nd_print_trunc(ndo); 445 } 446 447 static void 448 aodv_v6_draft_01_rerr(netdissect_options *ndo, const u_char *dat, u_int length) 449 { 450 u_int i, dc; 451 const struct aodv_rerr *ap = (const struct aodv_rerr *)dat; 452 const struct rerr_unreach6_draft_01 *dp6; 453 454 ND_TCHECK_SIZE(ap); 455 if (length < sizeof(*ap)) 456 goto trunc; 457 ND_PRINT(" rerr %s [items %u] [%u]:", 458 GET_U_1(ap->rerr_flags) & RERR_NODELETE ? "[D]" : "", 459 GET_U_1(ap->rerr_dc), length); 460 dp6 = (const struct rerr_unreach6_draft_01 *)(const void *)(ap + 1); 461 i = length - sizeof(*ap); 462 for (dc = GET_U_1(ap->rerr_dc); dc != 0; dc--) { 463 ND_TCHECK_SIZE(dp6); 464 if (i < sizeof(*dp6)) 465 goto trunc; 466 ND_PRINT(" {%s}(%u)", GET_IP6ADDR_STRING(dp6->u_da), 467 GET_BE_U_4(dp6->u_ds)); 468 dp6++; 469 i -= sizeof(*dp6); 470 } 471 return; 472 473 trunc: 474 nd_print_trunc(ndo); 475 } 476 477 void 478 aodv_print(netdissect_options *ndo, 479 const u_char *dat, u_int length, int is_ip6) 480 { 481 uint8_t msg_type; 482 483 ndo->ndo_protocol = "aodv"; 484 /* 485 * The message type is the first byte; make sure we have it 486 * and then fetch it. 487 */ 488 msg_type = GET_U_1(dat); 489 ND_PRINT(" aodv"); 490 491 switch (msg_type) { 492 493 case AODV_RREQ: 494 if (is_ip6) 495 aodv_v6_rreq(ndo, dat, length); 496 else 497 aodv_rreq(ndo, dat, length); 498 break; 499 500 case AODV_RREP: 501 if (is_ip6) 502 aodv_v6_rrep(ndo, dat, length); 503 else 504 aodv_rrep(ndo, dat, length); 505 break; 506 507 case AODV_RERR: 508 if (is_ip6) 509 aodv_v6_rerr(ndo, dat, length); 510 else 511 aodv_rerr(ndo, dat, length); 512 break; 513 514 case AODV_RREP_ACK: 515 ND_PRINT(" rrep-ack %u", length); 516 break; 517 518 case AODV_V6_DRAFT_01_RREQ: 519 aodv_v6_draft_01_rreq(ndo, dat, length); 520 break; 521 522 case AODV_V6_DRAFT_01_RREP: 523 aodv_v6_draft_01_rrep(ndo, dat, length); 524 break; 525 526 case AODV_V6_DRAFT_01_RERR: 527 aodv_v6_draft_01_rerr(ndo, dat, length); 528 break; 529 530 case AODV_V6_DRAFT_01_RREP_ACK: 531 ND_PRINT(" rrep-ack %u", length); 532 break; 533 534 default: 535 ND_PRINT(" type %u %u", msg_type, length); 536 } 537 } 538