Home | History | Annotate | Line # | Download | only in map-mbone
mapper.c revision 1.11
      1 /*	$NetBSD: mapper.c,v 1.11 2002/08/09 02:17:26 itojun 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 #include <stdarg.h>
     43 
     44 #define DEFAULT_TIMEOUT	2	/* How long to wait before retrying requests */
     45 #define DEFAULT_RETRIES 1	/* How many times to ask each router */
     46 
     47 
     48 /* All IP addresses are stored in the data structure in NET order. */
     49 
     50 typedef struct neighbor {
     51     struct neighbor    *next;
     52     u_int32_t		addr;		/* IP address in NET order */
     53     u_char		metric;		/* TTL cost of forwarding */
     54     u_char		threshold;	/* TTL threshold to forward */
     55     u_short		flags;		/* flags on connection */
     56 #define NF_PRESENT 0x8000	/* True if flags are meaningful */
     57 } Neighbor;
     58 
     59 typedef struct interface {
     60     struct interface *next;
     61     u_int32_t	addr;		/* IP address of the interface in NET order */
     62     Neighbor   *neighbors;	/* List of neighbors' IP addresses */
     63 } Interface;
     64 
     65 typedef struct node {
     66     u_int32_t	addr;		/* IP address of this entry in NET order */
     67     u_int32_t	version;	/* which mrouted version is running */
     68     int		tries;		/* How many requests sent?  -1 for aliases */
     69     union {
     70 	struct node *alias;		/* If alias, to what? */
     71 	struct interface *interfaces;	/* Else, neighbor data */
     72     } u;
     73     struct node *left, *right;
     74 } Node;
     75 
     76 
     77 Node   *routers = 0;
     78 u_int32_t	our_addr, target_addr = 0;		/* in NET order */
     79 int	debug = 0;
     80 int	retries = DEFAULT_RETRIES;
     81 int	timeout = DEFAULT_TIMEOUT;
     82 int	show_names = TRUE;
     83 vifi_t  numvifs;		/* to keep loader happy */
     84 				/* (see COPY_TABLES macro called in kern.c) */
     85 
     86 Node *			find_node(u_int32_t addr, Node **ptr);
     87 Interface *		find_interface(u_int32_t addr, Node *node);
     88 Neighbor *		find_neighbor(u_int32_t addr, Node *node);
     89 int			main(int argc, char *argv[]);
     90 void			ask(u_int32_t dst);
     91 void			ask2(u_int32_t dst);
     92 int			retry_requests(Node *node);
     93 char *			inet_name(u_int32_t addr);
     94 void			print_map(Node *node);
     95 char *			graph_name(u_int32_t addr, char *buf);
     96 void			graph_edges(Node *node);
     97 void			elide_aliases(Node *node);
     98 void			graph_map(void);
     99 int			get_number(int *var, int deflt, char ***pargv,
    100 				   int *pargc);
    101 u_int32_t		host_addr(char *name);
    102 
    103 void log(int severity, int syserr, const char *format, ...)
    104 	__attribute__((__format__(__printf__, 3, 4)));
    105 
    106 Node *find_node(u_int32_t addr, Node **ptr)
    107 {
    108     Node *n = *ptr;
    109 
    110     if (!n) {
    111 	*ptr = n = (Node *) 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 = (Interface *) 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 log(int severity, int syserr, const 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 	    fmt[0] = '\0';
    178 	    if (severity == LOG_WARNING)
    179 		strcat(fmt, "warning - ");
    180 	    strncat(fmt, format, 80);
    181 	    format = fmt;
    182 	    va_start(ap, format);
    183 	    vfprintf(stderr, format, ap);
    184 	    va_end(ap);
    185 	    if (syserr == 0)
    186 		fprintf(stderr, "\n");
    187 	    else
    188 		fprintf(stderr, ": %s\n", strerror(syserr));
    189     }
    190 
    191     if (severity <= LOG_ERR)
    192 	exit(1);
    193 }
    194 
    195 
    196 /*
    197  * Send a neighbors-list request.
    198  */
    199 void ask(u_int32_t dst)
    200 {
    201     send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
    202 		htonl(MROUTED_LEVEL), 0);
    203 }
    204 
    205 void ask2(u_int32_t dst)
    206 {
    207     send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
    208 		htonl(MROUTED_LEVEL), 0);
    209 }
    210 
    211 
    212 /*
    213  * Process an incoming group membership report.
    214  */
    215 void accept_group_report(u_int32_t src, u_int32_t dst, u_int32_t group, int r_type)
    216 {
    217     log(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     log(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     log(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 	log(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 	log(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 	    log(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 				log(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 		log(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 			log(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 	    log(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 				log(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 		log(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 			log(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     log(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)
    675 {
    676     char *name;
    677 
    678     if (show_names  &&  (name = inet_name(addr)))
    679 	strcpy(buf, name);
    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[100];
    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),
    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 int get_number(int *var, int deflt, char ***pargv, int *pargc)
    768 {
    769     if ((*pargv)[0][2] == '\0') { /* Get the value from the next argument */
    770 	if (*pargc > 1  &&  isdigit((*pargv)[1][0])) {
    771 	    (*pargv)++, (*pargc)--;
    772 	    *var = atoi((*pargv)[0]);
    773 	    return 1;
    774 	} else if (deflt >= 0) {
    775 	    *var = deflt;
    776 	    return 1;
    777 	} else
    778 	    return 0;
    779     } else {			/* Get value from the rest of this argument */
    780 	if (isdigit((*pargv)[0][2])) {
    781 	    *var = atoi((*pargv)[0] + 2);
    782 	    return 1;
    783 	} else {
    784 	    return 0;
    785 	}
    786     }
    787 }
    788 
    789 
    790 u_int32_t host_addr(char *name)
    791 {
    792     struct hostent *e = gethostbyname(name);
    793     int addr;
    794 
    795     if (e)
    796 	memcpy(&addr, e->h_addr_list[0], e->h_length);
    797     else {
    798 	addr = inet_addr(name);
    799 	if (addr == -1)
    800 	    addr = 0;
    801     }
    802 
    803     return addr;
    804 }
    805 
    806 
    807 int main(int argc, char **argv)
    808 {
    809     int flood = FALSE, graph = FALSE;
    810 
    811     setlinebuf(stderr);
    812 
    813     if (geteuid() != 0) {
    814 	fprintf(stderr, "must be root\n");
    815 	exit(1);
    816     }
    817 
    818     argv++, argc--;
    819     while (argc > 0 && argv[0][0] == '-') {
    820 	switch (argv[0][1]) {
    821 	  case 'd':
    822 	    if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc))
    823 		goto usage;
    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 	    if (!get_number(&retries, -1, &argv, &argc))
    836 		goto usage;
    837 	    break;
    838 	  case 't':
    839 	    if (!get_number(&timeout, -1, &argv, &argc))
    840 		goto usage;
    841 	    break;
    842 	  default:
    843 	    goto usage;
    844 	}
    845 	argv++, argc--;
    846     }
    847 
    848     if (argc > 1) {
    849       usage:
    850 	fprintf(stderr,
    851 		"Usage: map-mbone [-f] [-g] [-n] [-t timeout] %s\n\n",
    852 		"[-r retries] [-d [debug-level]] [router]");
    853         fprintf(stderr, "\t-f  Flood the routing graph with queries\n");
    854         fprintf(stderr, "\t    (True by default unless `router' is given)\n");
    855         fprintf(stderr, "\t-g  Generate output in GraphEd format\n");
    856         fprintf(stderr, "\t-n  Don't look up DNS names for routers\n");
    857 	exit(1);
    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     {				/* Find a good local address for us. */
    869 	int udp;
    870 	struct sockaddr_in addr;
    871 	int addrlen = sizeof(addr);
    872 
    873 	memset(&addr, 0, sizeof(addr));
    874 	addr.sin_family = AF_INET;
    875 #if (defined(BSD) && (BSD >= 199103))
    876 	addr.sin_len = sizeof addr;
    877 #endif
    878 	addr.sin_addr.s_addr = dvmrp_group;
    879 	addr.sin_port = htons(2000); /* any port over 1024 will do... */
    880 	if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
    881 	    || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
    882 	    || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
    883 	    perror("Determining local address");
    884 	    exit(1);
    885 	}
    886 	close(udp);
    887 	our_addr = addr.sin_addr.s_addr;
    888     }
    889 
    890     /* Send initial seed message to all local routers */
    891     ask(target_addr ? target_addr : allhosts_group);
    892 
    893     if (target_addr) {
    894 	Node *n = find_node(target_addr, &routers);
    895 
    896 	n->tries = 1;
    897 
    898 	if (flood)
    899 	    target_addr = 0;
    900     }
    901 
    902     /* Main receive loop */
    903     for(;;) {
    904 	fd_set		fds;
    905 	struct timeval 	tv;
    906 	int 		count, recvlen, dummy = 0;
    907 
    908 	FD_ZERO(&fds);
    909 	if (igmp_socket >= FD_SETSIZE)
    910 	    log(LOG_ERR, 0, "descriptor too big");
    911 	FD_SET(igmp_socket, &fds);
    912 
    913 	tv.tv_sec = timeout;
    914 	tv.tv_usec = 0;
    915 
    916 	count = select(igmp_socket + 1, &fds, 0, 0, &tv);
    917 
    918 	if (count < 0) {
    919 	    if (errno != EINTR)
    920 		perror("select");
    921 	    continue;
    922 	} else if (count == 0) {
    923 	    log(LOG_DEBUG, 0, "Timed out receiving neighbor lists");
    924 	    if (retry_requests(routers))
    925 		continue;
    926 	    else
    927 		break;
    928 	}
    929 
    930 	recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
    931 			   0, NULL, &dummy);
    932 	if (recvlen >= 0)
    933 	    accept_igmp(recvlen);
    934 	else if (errno != EINTR)
    935 	    perror("recvfrom");
    936     }
    937 
    938     printf("\n");
    939 
    940     if (graph)
    941 	graph_map();
    942     else {
    943 	if (!target_addr)
    944 	    printf("Multicast Router Connectivity:\n\n");
    945 	print_map(routers);
    946     }
    947 
    948     exit(0);
    949 }
    950 
    951 /* dummies */
    952 void accept_prune(u_int32_t src, u_int32_t dst, char *p, int datalen)
    953 {
    954 }
    955 void accept_graft(u_int32_t src, u_int32_t dst, char *p, int datalen)
    956 {
    957 }
    958 void accept_g_ack(u_int32_t src, u_int32_t dst, char *p, int datalen)
    959 {
    960 }
    961 void add_table_entry(u_int32_t origin, u_int32_t mcastgrp)
    962 {
    963 }
    964 void accept_leave_message(u_int32_t src, u_int32_t dst, u_int32_t group)
    965 {
    966 }
    967 void accept_mtrace(u_int32_t src, u_int32_t dst, u_int32_t group, char *data,
    968 		   u_int no, int datalen)
    969 {
    970 }
    971 void accept_membership_query(u_int32_t src, u_int32_t dst, u_int32_t group,
    972 			     int tmo)
    973 {
    974 }
    975 void accept_info_request(u_int32_t src, u_int32_t dst, u_char *p, int datalen)
    976 {
    977 }
    978 void accept_info_reply(u_int32_t src, u_int32_t dst, u_char *p, int datalen)
    979 {
    980 }
    981