1 /* $NetBSD: mapper.c,v 1.22 2004/10/30 08:46:12 dsl Exp $ */ 2 3 /* Mapper for connections between MRouteD multicast routers. 4 * Written by Pavel Curtis <Pavel@PARC.Xerox.Com> 5 */ 6 7 /* 8 * Copyright (c) 1992, 2001 Xerox Corporation. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without modification, 11 * are permitted provided that the following conditions are met: 12 * 13 * Redistributions of source code must retain the above copyright notice, 14 * this list of conditions and the following disclaimer. 15 * 16 * Redistributions in binary form must reproduce the above copyright notice, 17 * this list of conditions and the following disclaimer in the documentation 18 * and/or other materials provided with the distribution. 19 * 20 * Neither name of the Xerox, PARC, nor the names of its contributors may be used 21 * to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 26 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE XEROX CORPORATION OR CONTRIBUTORS 28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 31 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 33 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 34 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 #include <string.h> 38 #include <netdb.h> 39 #include <sys/time.h> 40 #include <poll.h> 41 #include "defs.h" 42 #include <arpa/inet.h> 43 #include <stdarg.h> 44 45 #define DEFAULT_TIMEOUT 2 /* How long to wait before retrying requests */ 46 #define DEFAULT_RETRIES 1 /* How many times to ask each router */ 47 48 49 /* All IP addresses are stored in the data structure in NET order. */ 50 51 typedef struct neighbor { 52 struct neighbor *next; 53 u_int32_t addr; /* IP address in NET order */ 54 u_char metric; /* TTL cost of forwarding */ 55 u_char threshold; /* TTL threshold to forward */ 56 u_short flags; /* flags on connection */ 57 #define NF_PRESENT 0x8000 /* True if flags are meaningful */ 58 } Neighbor; 59 60 typedef struct interface { 61 struct interface *next; 62 u_int32_t addr; /* IP address of the interface in NET order */ 63 Neighbor *neighbors; /* List of neighbors' IP addresses */ 64 } Interface; 65 66 typedef struct node { 67 u_int32_t addr; /* IP address of this entry in NET order */ 68 u_int32_t version; /* which mrouted version is running */ 69 int tries; /* How many requests sent? -1 for aliases */ 70 union { 71 struct node *alias; /* If alias, to what? */ 72 struct interface *interfaces; /* Else, neighbor data */ 73 } u; 74 struct node *left, *right; 75 } Node; 76 77 78 Node *routers = 0; 79 u_int32_t our_addr, target_addr = 0; /* in NET order */ 80 int debug = 0; 81 int retries = DEFAULT_RETRIES; 82 int timeout = DEFAULT_TIMEOUT; 83 int show_names = TRUE; 84 vifi_t numvifs; /* to keep loader happy */ 85 /* (see COPY_TABLES macro called in kern.c) */ 86 87 Node * find_node(u_int32_t addr, Node **ptr); 88 Interface * find_interface(u_int32_t addr, Node *node); 89 Neighbor * find_neighbor(u_int32_t addr, Node *node); 90 int main(int argc, char *argv[]); 91 void ask(u_int32_t dst); 92 void ask2(u_int32_t dst); 93 int retry_requests(Node *node); 94 char * inet_name(u_int32_t addr); 95 void print_map(Node *node); 96 char * graph_name(u_int32_t addr, char *buf, size_t); 97 void graph_edges(Node *node); 98 void elide_aliases(Node *node); 99 void graph_map(void); 100 int get_number(int *var, int deflt, char ***pargv, 101 int *pargc); 102 u_int32_t host_addr(char *name); 103 104 void logit(int severity, int syserr, const char *format, ...) 105 __attribute__((__format__(__printf__, 3, 4))); 106 107 Node *find_node(u_int32_t addr, Node **ptr) 108 { 109 Node *n = *ptr; 110 111 if (!n) { 112 *ptr = n = (Node *) malloc(sizeof(Node)); 113 n->addr = addr; 114 n->version = 0; 115 n->tries = 0; 116 n->u.interfaces = 0; 117 n->left = n->right = 0; 118 return n; 119 } else if (addr == n->addr) 120 return n; 121 else if (addr < n->addr) 122 return find_node(addr, &(n->left)); 123 else 124 return find_node(addr, &(n->right)); 125 } 126 127 128 Interface *find_interface(u_int32_t addr, Node *node) 129 { 130 Interface *ifc; 131 132 for (ifc = node->u.interfaces; ifc; ifc = ifc->next) 133 if (ifc->addr == addr) 134 return ifc; 135 136 ifc = (Interface *) malloc(sizeof(Interface)); 137 ifc->addr = addr; 138 ifc->next = node->u.interfaces; 139 node->u.interfaces = ifc; 140 ifc->neighbors = 0; 141 142 return ifc; 143 } 144 145 146 Neighbor *find_neighbor(u_int32_t addr, Node *node) 147 { 148 Interface *ifc; 149 150 for (ifc = node->u.interfaces; ifc; ifc = ifc->next) { 151 Neighbor *nb; 152 153 for (nb = ifc->neighbors; nb; nb = nb->next) 154 if (nb->addr == addr) 155 return nb; 156 } 157 158 return 0; 159 } 160 161 162 /* 163 * Log errors and other messages to stderr, according to the severity of the 164 * message and the current debug level. For errors of severity LOG_ERR or 165 * worse, terminate the program. 166 */ 167 void 168 logit(int severity, int syserr, const char *format, ...) 169 { 170 va_list ap; 171 char fmt[100]; 172 173 switch (debug) { 174 case 0: if (severity > LOG_WARNING) return; 175 case 1: if (severity > LOG_NOTICE ) return; 176 case 2: if (severity > LOG_INFO ) return; 177 default: 178 fmt[0] = '\0'; 179 if (severity == LOG_WARNING) 180 strlcat(fmt, "warning - ", sizeof(fmt)); 181 strlcat(fmt, format, sizeof(fmt)); 182 format = fmt; 183 va_start(ap, format); 184 vfprintf(stderr, format, ap); 185 va_end(ap); 186 if (syserr == 0) 187 fprintf(stderr, "\n"); 188 else 189 fprintf(stderr, ": %s\n", strerror(syserr)); 190 } 191 192 if (severity <= LOG_ERR) 193 exit(1); 194 } 195 196 197 /* 198 * Send a neighbors-list request. 199 */ 200 void ask(u_int32_t dst) 201 { 202 send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS, 203 htonl(MROUTED_LEVEL), 0); 204 } 205 206 void ask2(u_int32_t dst) 207 { 208 send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 209 htonl(MROUTED_LEVEL), 0); 210 } 211 212 213 /* 214 * Process an incoming group membership report. 215 */ 216 void accept_group_report(u_int32_t src, u_int32_t dst, u_int32_t group, int r_type) 217 { 218 logit(LOG_INFO, 0, "ignoring IGMP group membership report from %s to %s", 219 inet_fmt(src), inet_fmt(dst)); 220 } 221 222 223 /* 224 * Process an incoming neighbor probe message. 225 */ 226 void accept_probe(u_int32_t src, u_int32_t dst, char *p, int datalen, 227 u_int32_t level) 228 { 229 logit(LOG_INFO, 0, "ignoring DVMRP probe from %s to %s", 230 inet_fmt(src), inet_fmt(dst)); 231 } 232 233 234 /* 235 * Process an incoming route report message. 236 */ 237 void accept_report(u_int32_t src, u_int32_t dst, char *p, int datalen, 238 u_int32_t level) 239 { 240 logit(LOG_INFO, 0, "ignoring DVMRP routing report from %s to %s", 241 inet_fmt(src), inet_fmt(dst)); 242 } 243 244 245 /* 246 * Process an incoming neighbor-list request message. 247 */ 248 void accept_neighbor_request(u_int32_t src, u_int32_t dst) 249 { 250 if (src != our_addr) 251 logit(LOG_INFO, 0, 252 "ignoring spurious DVMRP neighbor request from %s to %s", 253 inet_fmt(src), inet_fmt(dst)); 254 } 255 256 void accept_neighbor_request2(u_int32_t src, u_int32_t dst) 257 { 258 if (src != our_addr) 259 logit(LOG_INFO, 0, 260 "ignoring spurious DVMRP neighbor request2 from %s to %s", 261 inet_fmt(src), inet_fmt(dst)); 262 } 263 264 265 /* 266 * Process an incoming neighbor-list message. 267 */ 268 void accept_neighbors(u_int32_t src, u_int32_t dst, u_char *p, int datalen, 269 u_int32_t level) 270 { 271 Node *node = find_node(src, &routers); 272 273 if (node->tries == 0) /* Never heard of 'em; must have hit them at */ 274 node->tries = 1; /* least once, though...*/ 275 else if (node->tries == -1) /* follow alias link */ 276 node = node->u.alias; 277 278 #define GET_ADDR(a) (a = ((u_int32_t)*p++ << 24), a += ((u_int32_t)*p++ << 16),\ 279 a += ((u_int32_t)*p++ << 8), a += *p++) 280 281 /* if node is running a recent mrouted, ask for additional info */ 282 if (level != 0) { 283 node->version = level; 284 node->tries = 1; 285 ask2(src); 286 return; 287 } 288 289 if (debug > 3) { 290 int i; 291 292 fprintf(stderr, " datalen = %d\n", datalen); 293 for (i = 0; i < datalen; i++) { 294 if ((i & 0xF) == 0) 295 fprintf(stderr, " "); 296 fprintf(stderr, " %02x", p[i]); 297 if ((i & 0xF) == 0xF) 298 fprintf(stderr, "\n"); 299 } 300 if ((datalen & 0xF) != 0xF) 301 fprintf(stderr, "\n"); 302 } 303 304 while (datalen > 0) { /* loop through interfaces */ 305 u_int32_t ifc_addr; 306 u_char metric, threshold, ncount; 307 Node *ifc_node; 308 Interface *ifc; 309 Neighbor *old_neighbors; 310 311 if (datalen < 4 + 3) { 312 logit(LOG_WARNING, 0, "received truncated interface record from %s", 313 inet_fmt(src)); 314 return; 315 } 316 317 GET_ADDR(ifc_addr); 318 ifc_addr = htonl(ifc_addr); 319 metric = *p++; 320 threshold = *p++; 321 ncount = *p++; 322 datalen -= 4 + 3; 323 324 /* Fix up any alias information */ 325 ifc_node = find_node(ifc_addr, &routers); 326 if (ifc_node->tries == 0) { /* new node */ 327 ifc_node->tries = -1; 328 ifc_node->u.alias = node; 329 } else if (ifc_node != node 330 && (ifc_node->tries > 0 || ifc_node->u.alias != node)) { 331 /* must merge two hosts' nodes */ 332 Interface *ifc_i, *next_ifc_i; 333 334 if (ifc_node->tries == -1) { 335 Node *tmp = ifc_node->u.alias; 336 337 ifc_node->u.alias = node; 338 ifc_node = tmp; 339 } 340 341 /* Merge ifc_node (foo_i) into node (foo_n) */ 342 343 if (ifc_node->tries > node->tries) 344 node->tries = ifc_node->tries; 345 346 for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) { 347 Neighbor *nb_i, *next_nb_i, *nb_n; 348 Interface *ifc_n = find_interface(ifc_i->addr, node); 349 350 old_neighbors = ifc_n->neighbors; 351 for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) { 352 next_nb_i = nb_i->next; 353 for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next) 354 if (nb_i->addr == nb_n->addr) { 355 if (nb_i->metric != nb_n->metric 356 || nb_i->threshold != nb_n->threshold) 357 logit(LOG_WARNING, 0, 358 "inconsistent %s for neighbor %s of %s", 359 "metric/threshold", 360 inet_fmt(nb_i->addr), 361 inet_fmt(node->addr)); 362 free(nb_i); 363 break; 364 } 365 if (!nb_n) { /* no match for this neighbor yet */ 366 nb_i->next = ifc_n->neighbors; 367 ifc_n->neighbors = nb_i; 368 } 369 } 370 371 next_ifc_i = ifc_i->next; 372 free(ifc_i); 373 } 374 375 ifc_node->tries = -1; 376 ifc_node->u.alias = node; 377 } 378 379 ifc = find_interface(ifc_addr, node); 380 old_neighbors = ifc->neighbors; 381 382 /* Add the neighbors for this interface */ 383 while (ncount--) { 384 u_int32_t neighbor; 385 Neighbor *nb; 386 Node *n_node; 387 388 if (datalen < 4) { 389 logit(LOG_WARNING, 0, "received truncated neighbor list from %s", 390 inet_fmt(src)); 391 return; 392 } 393 394 GET_ADDR(neighbor); 395 neighbor = htonl(neighbor); 396 datalen -= 4; 397 398 for (nb = old_neighbors; nb; nb = nb->next) 399 if (nb->addr == neighbor) { 400 if (metric != nb->metric || threshold != nb->threshold) 401 logit(LOG_WARNING, 0, 402 "inconsistent %s for neighbor %s of %s", 403 "metric/threshold", 404 inet_fmt(nb->addr), inet_fmt(node->addr)); 405 goto next_neighbor; 406 } 407 408 nb = (Neighbor *) malloc(sizeof(Neighbor)); 409 nb->next = ifc->neighbors; 410 ifc->neighbors = nb; 411 nb->addr = neighbor; 412 nb->metric = metric; 413 nb->threshold = threshold; 414 nb->flags = 0; 415 416 n_node = find_node(neighbor, &routers); 417 if (n_node->tries == 0 && !target_addr) { /* it's a new router */ 418 ask(neighbor); 419 n_node->tries = 1; 420 } 421 422 next_neighbor: ; 423 } 424 } 425 } 426 427 void accept_neighbors2(u_int32_t src, u_int32_t dst, u_char *p, int datalen, 428 u_int32_t level) 429 { 430 Node *node = find_node(src, &routers); 431 u_int broken_cisco = ((level & 0xffff) == 0x020a); /* 10.2 */ 432 /* well, only possibly_broken_cisco, but that's too long to type. */ 433 434 if (node->tries == 0) /* Never heard of 'em; must have hit them at */ 435 node->tries = 1; /* least once, though...*/ 436 else if (node->tries == -1) /* follow alias link */ 437 node = node->u.alias; 438 439 while (datalen > 0) { /* loop through interfaces */ 440 u_int32_t ifc_addr; 441 u_char metric, threshold, ncount, flags; 442 Node *ifc_node; 443 Interface *ifc; 444 Neighbor *old_neighbors; 445 446 if (datalen < 4 + 4) { 447 logit(LOG_WARNING, 0, "received truncated interface record from %s", 448 inet_fmt(src)); 449 return; 450 } 451 452 ifc_addr = *(u_int32_t*)p; 453 p += 4; 454 metric = *p++; 455 threshold = *p++; 456 flags = *p++; 457 ncount = *p++; 458 datalen -= 4 + 4; 459 460 if (broken_cisco && ncount == 0) /* dumb Ciscos */ 461 ncount = 1; 462 if (broken_cisco && ncount > 15) /* dumb Ciscos */ 463 ncount = ncount & 0xf; 464 465 /* Fix up any alias information */ 466 ifc_node = find_node(ifc_addr, &routers); 467 if (ifc_node->tries == 0) { /* new node */ 468 ifc_node->tries = -1; 469 ifc_node->u.alias = node; 470 } else if (ifc_node != node 471 && (ifc_node->tries > 0 || ifc_node->u.alias != node)) { 472 /* must merge two hosts' nodes */ 473 Interface *ifc_i, *next_ifc_i; 474 475 if (ifc_node->tries == -1) { 476 Node *tmp = ifc_node->u.alias; 477 478 ifc_node->u.alias = node; 479 ifc_node = tmp; 480 } 481 482 /* Merge ifc_node (foo_i) into node (foo_n) */ 483 484 if (ifc_node->tries > node->tries) 485 node->tries = ifc_node->tries; 486 487 for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) { 488 Neighbor *nb_i, *next_nb_i, *nb_n; 489 Interface *ifc_n = find_interface(ifc_i->addr, node); 490 491 old_neighbors = ifc_n->neighbors; 492 for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) { 493 next_nb_i = nb_i->next; 494 for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next) 495 if (nb_i->addr == nb_n->addr) { 496 if (nb_i->metric != nb_n->metric 497 || nb_i->threshold != nb_i->threshold) 498 logit(LOG_WARNING, 0, 499 "inconsistent %s for neighbor %s of %s", 500 "metric/threshold", 501 inet_fmt(nb_i->addr), 502 inet_fmt(node->addr)); 503 free(nb_i); 504 break; 505 } 506 if (!nb_n) { /* no match for this neighbor yet */ 507 nb_i->next = ifc_n->neighbors; 508 ifc_n->neighbors = nb_i; 509 } 510 } 511 512 next_ifc_i = ifc_i->next; 513 free(ifc_i); 514 } 515 516 ifc_node->tries = -1; 517 ifc_node->u.alias = node; 518 } 519 520 ifc = find_interface(ifc_addr, node); 521 old_neighbors = ifc->neighbors; 522 523 /* Add the neighbors for this interface */ 524 while (ncount-- && datalen > 0) { 525 u_int32_t neighbor; 526 Neighbor *nb; 527 Node *n_node; 528 529 if (datalen < 4) { 530 logit(LOG_WARNING, 0, "received truncated neighbor list from %s", 531 inet_fmt(src)); 532 return; 533 } 534 535 neighbor = *(u_int32_t*)p; 536 p += 4; 537 datalen -= 4; 538 if (neighbor == 0) 539 /* make leaf nets point to themselves */ 540 neighbor = ifc_addr; 541 542 for (nb = old_neighbors; nb; nb = nb->next) 543 if (nb->addr == neighbor) { 544 if (metric != nb->metric || threshold != nb->threshold) 545 logit(LOG_WARNING, 0, 546 "inconsistent %s for neighbor %s of %s", 547 "metric/threshold", 548 inet_fmt(nb->addr), inet_fmt(node->addr)); 549 goto next_neighbor; 550 } 551 552 nb = (Neighbor *) malloc(sizeof(Neighbor)); 553 nb->next = ifc->neighbors; 554 ifc->neighbors = nb; 555 nb->addr = neighbor; 556 nb->metric = metric; 557 nb->threshold = threshold; 558 nb->flags = flags | NF_PRESENT; 559 560 n_node = find_node(neighbor, &routers); 561 if (n_node->tries == 0 && !target_addr) { /* it's a new router */ 562 ask(neighbor); 563 n_node->tries = 1; 564 } 565 566 next_neighbor: ; 567 } 568 } 569 } 570 571 572 void check_vif_state(void) 573 { 574 logit(LOG_NOTICE, 0, "network marked down..."); 575 } 576 577 578 int retry_requests(Node *node) 579 { 580 int result; 581 582 if (node) { 583 result = retry_requests(node->left); 584 if (node->tries > 0 && node->tries < retries) { 585 if (node->version) 586 ask2(node->addr); 587 else 588 ask(node->addr); 589 node->tries++; 590 result = 1; 591 } 592 return retry_requests(node->right) || result; 593 } else 594 return 0; 595 } 596 597 598 char *inet_name(u_int32_t addr) 599 { 600 struct hostent *e; 601 602 e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET); 603 604 return e ? e->h_name : 0; 605 } 606 607 608 void print_map(Node *node) 609 { 610 if (node) { 611 char *name, *addr; 612 613 print_map(node->left); 614 615 addr = inet_fmt(node->addr); 616 if (!target_addr 617 || (node->tries >= 0 && node->u.interfaces) 618 || (node->tries == -1 619 && node->u.alias->tries >= 0 620 && node->u.alias->u.interfaces)) { 621 if (show_names && (name = inet_name(node->addr))) 622 printf("%s (%s):", addr, name); 623 else 624 printf("%s:", addr); 625 if (node->tries < 0) 626 printf(" alias for %s\n\n", inet_fmt(node->u.alias->addr)); 627 else if (!node->u.interfaces) 628 printf(" no response to query\n\n"); 629 else { 630 Interface *ifc; 631 632 if (node->version) 633 printf(" <v%d.%d>", node->version & 0xff, 634 (node->version >> 8) & 0xff); 635 printf("\n"); 636 for (ifc = node->u.interfaces; ifc; ifc = ifc->next) { 637 Neighbor *nb; 638 char *ifc_name = inet_fmt(ifc->addr); 639 int ifc_len = strlen(ifc_name); 640 int count = 0; 641 642 printf(" %s:", ifc_name); 643 for (nb = ifc->neighbors; nb; nb = nb->next) { 644 if (count > 0) 645 printf("%*s", ifc_len + 5, ""); 646 printf(" %s", inet_fmt(nb->addr)); 647 if (show_names && (name = inet_name(nb->addr))) 648 printf(" (%s)", name); 649 printf(" [%d/%d", nb->metric, nb->threshold); 650 if (nb->flags) { 651 u_short flags = nb->flags; 652 if (flags & DVMRP_NF_TUNNEL) 653 printf("/tunnel"); 654 if (flags & DVMRP_NF_SRCRT) 655 printf("/srcrt"); 656 if (flags & DVMRP_NF_QUERIER) 657 printf("/querier"); 658 if (flags & DVMRP_NF_DISABLED) 659 printf("/disabled"); 660 if (flags & DVMRP_NF_DOWN) 661 printf("/down"); 662 } 663 printf("]\n"); 664 count++; 665 } 666 } 667 printf("\n"); 668 } 669 } 670 print_map(node->right); 671 } 672 } 673 674 675 char *graph_name(u_int32_t addr, char *buf, size_t l) 676 { 677 char *name; 678 679 if (show_names && (name = inet_name(addr))) 680 strlcpy(buf, name, l); 681 else 682 inet_fmt(addr); 683 684 return buf; 685 } 686 687 688 void graph_edges(Node *node) 689 { 690 Interface *ifc; 691 Neighbor *nb; 692 char name[100]; 693 694 if (node) { 695 graph_edges(node->left); 696 if (node->tries >= 0) { 697 printf(" %d {$ NP %d0 %d0 $} \"%s%s\" \n", 698 (int) node->addr, 699 node->addr & 0xFF, (node->addr >> 8) & 0xFF, 700 graph_name(node->addr, name, sizeof(name)), 701 node->u.interfaces ? "" : "*"); 702 for (ifc = node->u.interfaces; ifc; ifc = ifc->next) 703 for (nb = ifc->neighbors; nb; nb = nb->next) { 704 Node *nb_node = find_node(nb->addr, &routers); 705 Neighbor *nb2; 706 707 if (nb_node->tries < 0) 708 nb_node = nb_node->u.alias; 709 710 if (node != nb_node && 711 (!(nb2 = find_neighbor(node->addr, nb_node)) 712 || node->addr < nb_node->addr)) { 713 printf(" %d \"%d/%d", 714 nb_node->addr, nb->metric, nb->threshold); 715 if (nb2 && (nb2->metric != nb->metric 716 || nb2->threshold != nb->threshold)) 717 printf(",%d/%d", nb2->metric, nb2->threshold); 718 if (nb->flags & NF_PRESENT) 719 printf("%s%s", 720 nb->flags & DVMRP_NF_SRCRT ? "" : 721 nb->flags & DVMRP_NF_TUNNEL ? "E" : "P", 722 nb->flags & DVMRP_NF_DOWN ? "D" : ""); 723 printf("\"\n"); 724 } 725 } 726 printf(" ;\n"); 727 } 728 graph_edges(node->right); 729 } 730 } 731 732 void elide_aliases(Node *node) 733 { 734 if (node) { 735 elide_aliases(node->left); 736 if (node->tries >= 0) { 737 Interface *ifc; 738 739 for (ifc = node->u.interfaces; ifc; ifc = ifc->next) { 740 Neighbor *nb; 741 742 for (nb = ifc->neighbors; nb; nb = nb->next) { 743 Node *nb_node = find_node(nb->addr, &routers); 744 745 if (nb_node->tries < 0) 746 nb->addr = nb_node->u.alias->addr; 747 } 748 } 749 } 750 elide_aliases(node->right); 751 } 752 } 753 754 void graph_map(void) 755 { 756 time_t now = time(0); 757 char *nowstr = ctime(&now); 758 759 nowstr[24] = '\0'; /* Kill the newline at the end */ 760 elide_aliases(routers); 761 printf("GRAPH \"Multicast Router Connectivity: %s\" = UNDIRECTED\n", 762 nowstr); 763 graph_edges(routers); 764 printf("END\n"); 765 } 766 767 768 int get_number(int *var, int deflt, char ***pargv, int *pargc) 769 { 770 if ((*pargv)[0][2] == '\0') { /* Get the value from the next argument */ 771 if (*pargc > 1 && isdigit((unsigned char)(*pargv)[1][0])) { 772 (*pargv)++, (*pargc)--; 773 *var = atoi((*pargv)[0]); 774 return 1; 775 } else if (deflt >= 0) { 776 *var = deflt; 777 return 1; 778 } else 779 return 0; 780 } else { /* Get value from the rest of this argument */ 781 if (isdigit((unsigned char)(*pargv)[0][2])) { 782 *var = atoi((*pargv)[0] + 2); 783 return 1; 784 } else { 785 return 0; 786 } 787 } 788 } 789 790 791 u_int32_t host_addr(char *name) 792 { 793 struct hostent *e = gethostbyname(name); 794 int addr; 795 796 if (e) 797 memcpy(&addr, e->h_addr_list[0], e->h_length); 798 else { 799 addr = inet_addr(name); 800 if (addr == -1) 801 addr = 0; 802 } 803 804 return addr; 805 } 806 807 808 int main(int argc, char **argv) 809 { 810 int flood = FALSE, graph = FALSE; 811 struct pollfd set[1]; 812 813 setlinebuf(stderr); 814 815 if (geteuid() != 0) { 816 fprintf(stderr, "must be root\n"); 817 exit(1); 818 } 819 820 argv++, argc--; 821 while (argc > 0 && argv[0][0] == '-') { 822 switch (argv[0][1]) { 823 case 'd': 824 if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc)) 825 goto usage; 826 break; 827 case 'f': 828 flood = TRUE; 829 break; 830 case 'g': 831 graph = TRUE; 832 break; 833 case 'n': 834 show_names = FALSE; 835 break; 836 case 'r': 837 if (!get_number(&retries, -1, &argv, &argc)) 838 goto usage; 839 break; 840 case 't': 841 if (!get_number(&timeout, -1, &argv, &argc)) 842 goto usage; 843 break; 844 default: 845 goto usage; 846 } 847 argv++, argc--; 848 } 849 850 if (argc > 1) { 851 usage: 852 fprintf(stderr, 853 "usage: map-mbone [-f] [-g] [-n] [-t timeout] %s\n\n", 854 "[-r retries] [-d [debug-level]] [router]"); 855 fprintf(stderr, "\t-f Flood the routing graph with queries\n"); 856 fprintf(stderr, "\t (True by default unless `router' is given)\n"); 857 fprintf(stderr, "\t-g Generate output in GraphEd format\n"); 858 fprintf(stderr, "\t-n Don't look up DNS names for routers\n"); 859 exit(1); 860 } else if (argc == 1 && !(target_addr = host_addr(argv[0]))) { 861 fprintf(stderr, "Unknown host: %s\n", argv[0]); 862 exit(2); 863 } 864 865 if (debug) 866 fprintf(stderr, "Debug level %u\n", debug); 867 868 init_igmp(); 869 870 { /* Find a good local address for us. */ 871 int udp; 872 struct sockaddr_in addr; 873 int addrlen = sizeof(addr); 874 875 memset(&addr, 0, sizeof(addr)); 876 addr.sin_family = AF_INET; 877 #if (defined(BSD) && (BSD >= 199103)) 878 addr.sin_len = sizeof addr; 879 #endif 880 addr.sin_addr.s_addr = dvmrp_group; 881 addr.sin_port = htons(2000); /* any port over 1024 will do... */ 882 if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0 883 || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0 884 || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) { 885 perror("Determining local address"); 886 exit(1); 887 } 888 close(udp); 889 our_addr = addr.sin_addr.s_addr; 890 } 891 892 /* Send initial seed message to all local routers */ 893 ask(target_addr ? target_addr : allhosts_group); 894 895 if (target_addr) { 896 Node *n = find_node(target_addr, &routers); 897 898 n->tries = 1; 899 900 if (flood) 901 target_addr = 0; 902 } 903 904 /* Main receive loop */ 905 set[0].fd = igmp_socket; 906 set[0].events = POLLIN; 907 for(;;) { 908 int count, recvlen, dummy = 0; 909 910 count = poll(set, 1, timeout * 1000); 911 912 if (count < 0) { 913 if (errno != EINTR) 914 perror("poll"); 915 continue; 916 } else if (count == 0) { 917 logit(LOG_DEBUG, 0, "Timed out receiving neighbor lists"); 918 if (retry_requests(routers)) 919 continue; 920 else 921 break; 922 } 923 924 recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE, 925 0, NULL, &dummy); 926 if (recvlen >= 0) 927 accept_igmp(recvlen); 928 else if (errno != EINTR) 929 perror("recvfrom"); 930 } 931 932 printf("\n"); 933 934 if (graph) 935 graph_map(); 936 else { 937 if (!target_addr) 938 printf("Multicast Router Connectivity:\n\n"); 939 print_map(routers); 940 } 941 942 exit(0); 943 } 944 945 /* dummies */ 946 void accept_prune(u_int32_t src, u_int32_t dst, char *p, int datalen) 947 { 948 } 949 void accept_graft(u_int32_t src, u_int32_t dst, char *p, int datalen) 950 { 951 } 952 void accept_g_ack(u_int32_t src, u_int32_t dst, char *p, int datalen) 953 { 954 } 955 void add_table_entry(u_int32_t origin, u_int32_t mcastgrp) 956 { 957 } 958 void accept_leave_message(u_int32_t src, u_int32_t dst, u_int32_t group) 959 { 960 } 961 void accept_mtrace(u_int32_t src, u_int32_t dst, u_int32_t group, char *data, 962 u_int no, int datalen) 963 { 964 } 965 void accept_membership_query(u_int32_t src, u_int32_t dst, u_int32_t group, 966 int tmo) 967 { 968 } 969 void accept_info_request(u_int32_t src, u_int32_t dst, u_char *p, int datalen) 970 { 971 } 972 void accept_info_reply(u_int32_t src, u_int32_t dst, u_char *p, int datalen) 973 { 974 } 975