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