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