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