File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mrouted / mapper.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:10:48 2012 UTC (12 years, 3 months ago) by misho
Branches: mrouted, MAIN
CVS tags: v3_9_6p0, v3_9_6, v3_9_5, HEAD
mrouted

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>