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