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