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