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