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