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