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