GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/map-mbone/mapper.c Lines: 0 438 0.0 %
Date: 2017-11-13 Branches: 0 321 0.0 %

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