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