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 #include <config.h> 36 37 #include "netdissect-stdinc.h" 38 39 #include "netdissect.h" 40 #include "addrtoname.h" 41 #include "extract.h" 42 43 /* 44 * RFC 3561 45 */ 46 struct aodv_rreq { 47 nd_uint8_t rreq_type; /* AODV message type (1) */ 48 nd_uint8_t rreq_flags; /* various flags */ 49 nd_uint8_t rreq_zero0; /* reserved, set to zero */ 50 nd_uint8_t rreq_hops; /* number of hops from originator */ 51 nd_uint32_t rreq_id; /* request ID */ 52 nd_ipv4 rreq_da; /* destination IPv4 address */ 53 nd_uint32_t rreq_ds; /* destination sequence number */ 54 nd_ipv4 rreq_oa; /* originator IPv4 address */ 55 nd_uint32_t rreq_os; /* originator sequence number */ 56 }; 57 struct aodv_rreq6 { 58 nd_uint8_t rreq_type; /* AODV message type (1) */ 59 nd_uint8_t rreq_flags; /* various flags */ 60 nd_uint8_t rreq_zero0; /* reserved, set to zero */ 61 nd_uint8_t rreq_hops; /* number of hops from originator */ 62 nd_uint32_t rreq_id; /* request ID */ 63 nd_ipv6 rreq_da; /* destination IPv6 address */ 64 nd_uint32_t rreq_ds; /* destination sequence number */ 65 nd_ipv6 rreq_oa; /* originator IPv6 address */ 66 nd_uint32_t rreq_os; /* originator sequence number */ 67 }; 68 struct aodv_rreq6_draft_01 { 69 nd_uint8_t rreq_type; /* AODV message type (16) */ 70 nd_uint8_t rreq_flags; /* various flags */ 71 nd_uint8_t rreq_zero0; /* reserved, set to zero */ 72 nd_uint8_t rreq_hops; /* number of hops from originator */ 73 nd_uint32_t rreq_id; /* request ID */ 74 nd_uint32_t rreq_ds; /* destination sequence number */ 75 nd_uint32_t rreq_os; /* originator sequence number */ 76 nd_ipv6 rreq_da; /* destination IPv6 address */ 77 nd_ipv6 rreq_oa; /* originator IPv6 address */ 78 }; 79 80 #define RREQ_JOIN 0x80 /* join (reserved for multicast */ 81 #define RREQ_REPAIR 0x40 /* repair (reserved for multicast */ 82 #define RREQ_GRAT 0x20 /* gratuitous RREP */ 83 #define RREQ_DEST 0x10 /* destination only */ 84 #define RREQ_UNKNOWN 0x08 /* unknown destination sequence num */ 85 #define RREQ_FLAGS_MASK 0xF8 /* mask for rreq_flags */ 86 87 struct aodv_rrep { 88 nd_uint8_t rrep_type; /* AODV message type (2) */ 89 nd_uint8_t rrep_flags; /* various flags */ 90 nd_uint8_t rrep_ps; /* prefix size */ 91 nd_uint8_t rrep_hops; /* number of hops from o to d */ 92 nd_ipv4 rrep_da; /* destination IPv4 address */ 93 nd_uint32_t rrep_ds; /* destination sequence number */ 94 nd_ipv4 rrep_oa; /* originator IPv4 address */ 95 nd_uint32_t rrep_life; /* lifetime of this route */ 96 }; 97 struct aodv_rrep6 { 98 nd_uint8_t rrep_type; /* AODV message type (2) */ 99 nd_uint8_t rrep_flags; /* various flags */ 100 nd_uint8_t rrep_ps; /* prefix size */ 101 nd_uint8_t rrep_hops; /* number of hops from o to d */ 102 nd_ipv6 rrep_da; /* destination IPv6 address */ 103 nd_uint32_t rrep_ds; /* destination sequence number */ 104 nd_ipv6 rrep_oa; /* originator IPv6 address */ 105 nd_uint32_t rrep_life; /* lifetime of this route */ 106 }; 107 struct aodv_rrep6_draft_01 { 108 nd_uint8_t rrep_type; /* AODV message type (17) */ 109 nd_uint8_t rrep_flags; /* various flags */ 110 nd_uint8_t rrep_ps; /* prefix size */ 111 nd_uint8_t rrep_hops; /* number of hops from o to d */ 112 nd_uint32_t rrep_ds; /* destination sequence number */ 113 nd_ipv6 rrep_da; /* destination IPv6 address */ 114 nd_ipv6 rrep_oa; /* originator IPv6 address */ 115 nd_uint32_t rrep_life; /* lifetime of this route */ 116 }; 117 118 #define RREP_REPAIR 0x80 /* repair (reserved for multicast */ 119 #define RREP_ACK 0x40 /* acknowledgement required */ 120 #define RREP_FLAGS_MASK 0xC0 /* mask for rrep_flags */ 121 #define RREP_PREFIX_MASK 0x1F /* mask for prefix size */ 122 123 struct rerr_unreach { 124 nd_ipv4 u_da; /* IPv4 address */ 125 nd_uint32_t u_ds; /* sequence number */ 126 }; 127 struct rerr_unreach6 { 128 nd_ipv6 u_da; /* IPv6 address */ 129 nd_uint32_t u_ds; /* sequence number */ 130 }; 131 struct rerr_unreach6_draft_01 { 132 nd_ipv6 u_da; /* IPv6 address */ 133 nd_uint32_t u_ds; /* sequence number */ 134 }; 135 136 struct aodv_rerr { 137 nd_uint8_t rerr_type; /* AODV message type (3 or 18) */ 138 nd_uint8_t rerr_flags; /* various flags */ 139 nd_uint8_t rerr_zero0; /* reserved, set to zero */ 140 nd_uint8_t rerr_dc; /* destination count */ 141 }; 142 143 #define RERR_NODELETE 0x80 /* don't delete the link */ 144 #define RERR_FLAGS_MASK 0x80 /* mask for rerr_flags */ 145 146 struct aodv_rrep_ack { 147 nd_uint8_t ra_type; 148 nd_uint8_t ra_zero0; 149 }; 150 151 #define AODV_RREQ 1 /* route request */ 152 #define AODV_RREP 2 /* route response */ 153 #define AODV_RERR 3 /* error report */ 154 #define AODV_RREP_ACK 4 /* route response acknowledgement */ 155 156 #define AODV_V6_DRAFT_01_RREQ 16 /* IPv6 route request */ 157 #define AODV_V6_DRAFT_01_RREP 17 /* IPv6 route response */ 158 #define AODV_V6_DRAFT_01_RERR 18 /* IPv6 error report */ 159 #define AODV_V6_DRAFT_01_RREP_ACK 19 /* IPV6 route response acknowledgment */ 160 161 struct aodv_ext { 162 nd_uint8_t type; /* extension type */ 163 nd_uint8_t length; /* extension length */ 164 }; 165 166 struct aodv_hello { 167 struct aodv_ext eh; /* extension header */ 168 nd_uint32_t interval; /* expect my next hello in 169 * (n) ms 170 * NOTE: this is not aligned */ 171 }; 172 173 #define AODV_EXT_HELLO 1 174 175 static void 176 aodv_extension(netdissect_options *ndo, 177 const struct aodv_ext *ep, u_int length) 178 { 179 const struct aodv_hello *ah; 180 181 ND_TCHECK_SIZE(ep); 182 switch (GET_U_1(ep->type)) { 183 case AODV_EXT_HELLO: 184 ah = (const struct aodv_hello *)(const void *)ep; 185 ND_TCHECK_SIZE(ah); 186 if (length < sizeof(struct aodv_hello)) 187 goto trunc; 188 if (GET_U_1(ep->length) < 4) { 189 ND_PRINT("\n\text HELLO - bad length %u", 190 GET_U_1(ep->length)); 191 break; 192 } 193 ND_PRINT("\n\text HELLO %u ms", 194 GET_BE_U_4(ah->interval)); 195 break; 196 197 default: 198 ND_PRINT("\n\text %u %u", GET_U_1(ep->type), 199 GET_U_1(ep->length)); 200 break; 201 } 202 return; 203 204 trunc: 205 nd_print_trunc(ndo); 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_SIZE(ap); 215 if (length < sizeof(*ap)) 216 goto trunc; 217 ND_PRINT(" rreq %u %s%s%s%s%shops %u id 0x%08x\n" 218 "\tdst %s seq %u src %s seq %u", length, 219 GET_U_1(ap->rreq_type) & RREQ_JOIN ? "[J]" : "", 220 GET_U_1(ap->rreq_type) & RREQ_REPAIR ? "[R]" : "", 221 GET_U_1(ap->rreq_type) & RREQ_GRAT ? "[G]" : "", 222 GET_U_1(ap->rreq_type) & RREQ_DEST ? "[D]" : "", 223 GET_U_1(ap->rreq_type) & RREQ_UNKNOWN ? "[U] " : " ", 224 GET_U_1(ap->rreq_hops), 225 GET_BE_U_4(ap->rreq_id), 226 GET_IPADDR_STRING(ap->rreq_da), 227 GET_BE_U_4(ap->rreq_ds), 228 GET_IPADDR_STRING(ap->rreq_oa), 229 GET_BE_U_4(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_trunc(ndo); 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_SIZE(ap); 246 if (length < sizeof(*ap)) 247 goto trunc; 248 ND_PRINT(" rrep %u %s%sprefix %u hops %u\n" 249 "\tdst %s dseq %u src %s %u ms", length, 250 GET_U_1(ap->rrep_type) & RREP_REPAIR ? "[R]" : "", 251 GET_U_1(ap->rrep_type) & RREP_ACK ? "[A] " : " ", 252 GET_U_1(ap->rrep_ps) & RREP_PREFIX_MASK, 253 GET_U_1(ap->rrep_hops), 254 GET_IPADDR_STRING(ap->rrep_da), 255 GET_BE_U_4(ap->rrep_ds), 256 GET_IPADDR_STRING(ap->rrep_oa), 257 GET_BE_U_4(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_trunc(ndo); 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_SIZE(ap); 275 if (length < sizeof(*ap)) 276 goto trunc; 277 ND_PRINT(" rerr %s [items %u] [%u]:", 278 GET_U_1(ap->rerr_flags) & RERR_NODELETE ? "[D]" : "", 279 GET_U_1(ap->rerr_dc), length); 280 dp = (const struct rerr_unreach *)(dat + sizeof(*ap)); 281 i = length - sizeof(*ap); 282 for (dc = GET_U_1(ap->rerr_dc); dc != 0; dc--) { 283 ND_TCHECK_SIZE(dp); 284 if (i < sizeof(*dp)) 285 goto trunc; 286 ND_PRINT(" {%s}(%u)", GET_IPADDR_STRING(dp->u_da), 287 GET_BE_U_4(dp->u_ds)); 288 dp++; 289 i -= sizeof(*dp); 290 } 291 return; 292 293 trunc: 294 nd_print_trunc(ndo); 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_SIZE(ap); 304 if (length < sizeof(*ap)) 305 goto trunc; 306 ND_PRINT(" v6 rreq %u %s%s%s%s%shops %u id 0x%08x\n" 307 "\tdst %s seq %u src %s seq %u", length, 308 GET_U_1(ap->rreq_type) & RREQ_JOIN ? "[J]" : "", 309 GET_U_1(ap->rreq_type) & RREQ_REPAIR ? "[R]" : "", 310 GET_U_1(ap->rreq_type) & RREQ_GRAT ? "[G]" : "", 311 GET_U_1(ap->rreq_type) & RREQ_DEST ? "[D]" : "", 312 GET_U_1(ap->rreq_type) & RREQ_UNKNOWN ? "[U] " : " ", 313 GET_U_1(ap->rreq_hops), 314 GET_BE_U_4(ap->rreq_id), 315 GET_IP6ADDR_STRING(ap->rreq_da), 316 GET_BE_U_4(ap->rreq_ds), 317 GET_IP6ADDR_STRING(ap->rreq_oa), 318 GET_BE_U_4(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_trunc(ndo); 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_SIZE(ap); 335 if (length < sizeof(*ap)) 336 goto trunc; 337 ND_PRINT(" rrep %u %s%sprefix %u hops %u\n" 338 "\tdst %s dseq %u src %s %u ms", length, 339 GET_U_1(ap->rrep_type) & RREP_REPAIR ? "[R]" : "", 340 GET_U_1(ap->rrep_type) & RREP_ACK ? "[A] " : " ", 341 GET_U_1(ap->rrep_ps) & RREP_PREFIX_MASK, 342 GET_U_1(ap->rrep_hops), 343 GET_IP6ADDR_STRING(ap->rrep_da), 344 GET_BE_U_4(ap->rrep_ds), 345 GET_IP6ADDR_STRING(ap->rrep_oa), 346 GET_BE_U_4(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_trunc(ndo); 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_SIZE(ap); 364 if (length < sizeof(*ap)) 365 goto trunc; 366 ND_PRINT(" rerr %s [items %u] [%u]:", 367 GET_U_1(ap->rerr_flags) & RERR_NODELETE ? "[D]" : "", 368 GET_U_1(ap->rerr_dc), length); 369 dp6 = (const struct rerr_unreach6 *)(const void *)(ap + 1); 370 i = length - sizeof(*ap); 371 for (dc = GET_U_1(ap->rerr_dc); dc != 0; dc--) { 372 ND_TCHECK_SIZE(dp6); 373 if (i < sizeof(*dp6)) 374 goto trunc; 375 ND_PRINT(" {%s}(%u)", GET_IP6ADDR_STRING(dp6->u_da), 376 GET_BE_U_4(dp6->u_ds)); 377 dp6++; 378 i -= sizeof(*dp6); 379 } 380 return; 381 382 trunc: 383 nd_print_trunc(ndo); 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_SIZE(ap); 393 if (length < sizeof(*ap)) 394 goto trunc; 395 ND_PRINT(" rreq %u %s%s%s%s%shops %u id 0x%08x\n" 396 "\tdst %s seq %u src %s seq %u", length, 397 GET_U_1(ap->rreq_type) & RREQ_JOIN ? "[J]" : "", 398 GET_U_1(ap->rreq_type) & RREQ_REPAIR ? "[R]" : "", 399 GET_U_1(ap->rreq_type) & RREQ_GRAT ? "[G]" : "", 400 GET_U_1(ap->rreq_type) & RREQ_DEST ? "[D]" : "", 401 GET_U_1(ap->rreq_type) & RREQ_UNKNOWN ? "[U] " : " ", 402 GET_U_1(ap->rreq_hops), 403 GET_BE_U_4(ap->rreq_id), 404 GET_IP6ADDR_STRING(ap->rreq_da), 405 GET_BE_U_4(ap->rreq_ds), 406 GET_IP6ADDR_STRING(ap->rreq_oa), 407 GET_BE_U_4(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_trunc(ndo); 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_SIZE(ap); 424 if (length < sizeof(*ap)) 425 goto trunc; 426 ND_PRINT(" rrep %u %s%sprefix %u hops %u\n" 427 "\tdst %s dseq %u src %s %u ms", length, 428 GET_U_1(ap->rrep_type) & RREP_REPAIR ? "[R]" : "", 429 GET_U_1(ap->rrep_type) & RREP_ACK ? "[A] " : " ", 430 GET_U_1(ap->rrep_ps) & RREP_PREFIX_MASK, 431 GET_U_1(ap->rrep_hops), 432 GET_IP6ADDR_STRING(ap->rrep_da), 433 GET_BE_U_4(ap->rrep_ds), 434 GET_IP6ADDR_STRING(ap->rrep_oa), 435 GET_BE_U_4(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_trunc(ndo); 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_SIZE(ap); 453 if (length < sizeof(*ap)) 454 goto trunc; 455 ND_PRINT(" rerr %s [items %u] [%u]:", 456 GET_U_1(ap->rerr_flags) & RERR_NODELETE ? "[D]" : "", 457 GET_U_1(ap->rerr_dc), length); 458 dp6 = (const struct rerr_unreach6_draft_01 *)(const void *)(ap + 1); 459 i = length - sizeof(*ap); 460 for (dc = GET_U_1(ap->rerr_dc); dc != 0; dc--) { 461 ND_TCHECK_SIZE(dp6); 462 if (i < sizeof(*dp6)) 463 goto trunc; 464 ND_PRINT(" {%s}(%u)", GET_IP6ADDR_STRING(dp6->u_da), 465 GET_BE_U_4(dp6->u_ds)); 466 dp6++; 467 i -= sizeof(*dp6); 468 } 469 return; 470 471 trunc: 472 nd_print_trunc(ndo); 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 ndo->ndo_protocol = "aodv"; 482 /* 483 * The message type is the first byte; make sure we have it 484 * and then fetch it. 485 */ 486 msg_type = GET_U_1(dat); 487 ND_PRINT(" 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(" 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(" rrep-ack %u", length); 530 break; 531 532 default: 533 ND_PRINT(" type %u %u", msg_type, length); 534 } 535 } 536