<sys/posix4.h>: Clean up a bit.
[dragonfly.git] / usr.sbin / mrouted / mapper.c
blob94463b3194c8c23ccb1c610c958084dcfabb15fe
1 /* Mapper for connections between MRouteD multicast routers.
2 * Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
4 * mapper.c,v 3.8.4.3 1998/01/06 01:57:47 fenner Exp
6 * $FreeBSD: src/usr.sbin/mrouted/mapper.c,v 1.15.2.1 2002/09/12 16:27:49 nectar Exp $
7 */
9 /*
10 * Copyright (c) Xerox Corporation 1992. All rights reserved.
12 * License is granted to copy, to use, and to make and to use derivative
13 * works for research and evaluation purposes, provided that Xerox is
14 * acknowledged in all documentation pertaining to any such copy or derivative
15 * work. Xerox grants no other licenses expressed or implied. The Xerox trade
16 * name should not be used in any advertising without its written permission.
18 * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
19 * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
20 * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
21 * express or implied warranty of any kind.
23 * These notices must be retained in any copies of any part of this software.
26 #include <err.h>
27 #include <string.h>
28 #include <netdb.h>
29 #include <sys/time.h>
30 #include "defs.h"
31 #include <arpa/inet.h>
32 #include <stdarg.h>
34 #define DEFAULT_TIMEOUT 2 /* How long to wait before retrying requests */
35 #define DEFAULT_RETRIES 1 /* How many times to ask each router */
38 /* All IP addresses are stored in the data structure in NET order. */
40 typedef struct neighbor {
41 struct neighbor *next;
42 u_int32 addr; /* IP address in NET order */
43 u_char metric; /* TTL cost of forwarding */
44 u_char threshold; /* TTL threshold to forward */
45 u_short flags; /* flags on connection */
46 #define NF_PRESENT 0x8000 /* True if flags are meaningful */
47 } Neighbor;
49 typedef struct interface {
50 struct interface *next;
51 u_int32 addr; /* IP address of the interface in NET order */
52 Neighbor *neighbors; /* List of neighbors' IP addresses */
53 } Interface;
55 typedef struct node {
56 u_int32 addr; /* IP address of this entry in NET order */
57 u_int32 version; /* which mrouted version is running */
58 int tries; /* How many requests sent? -1 for aliases */
59 union {
60 struct node *alias; /* If alias, to what? */
61 struct interface *interfaces; /* Else, neighbor data */
62 } u;
63 struct node *left, *right;
64 } Node;
67 Node *routers = NULL;
68 u_int32 our_addr, target_addr = 0; /* in NET order */
69 int debug = 0;
70 int retries = DEFAULT_RETRIES;
71 int timeout = DEFAULT_TIMEOUT;
72 int show_names = TRUE;
73 vifi_t numvifs; /* to keep loader happy */
74 /* (see COPY_TABLES macro called in kern.c) */
76 Node * find_node(u_int32 addr, Node **ptr);
77 Interface * find_interface(u_int32 addr, Node *node);
78 Neighbor * find_neighbor(u_int32 addr, Node *node);
79 void ask(u_int32 dst);
80 void ask2(u_int32 dst);
81 int retry_requests(Node *node);
82 char * inet_name(u_int32 addr);
83 void print_map(Node *node);
84 char * graph_name(u_int32 addr, char *buf, int len);
85 void graph_edges(Node *node);
86 void elide_aliases(Node *node);
87 void graph_map(void);
88 int get_number(int *var, int deflt, char ***pargv,
89 int *pargc);
90 u_int32 host_addr(char *name);
91 static void usage(void);
93 Node *
94 find_node(u_int32 addr, Node **ptr)
96 Node *n = *ptr;
98 if (!n) {
99 *ptr = n = (Node *) malloc(sizeof(Node));
100 n->addr = addr;
101 n->version = 0;
102 n->tries = 0;
103 n->u.interfaces = NULL;
104 n->left = n->right = NULL;
105 return n;
106 } else if (addr == n->addr)
107 return n;
108 else if (addr < n->addr)
109 return find_node(addr, &(n->left));
110 else
111 return find_node(addr, &(n->right));
114 Interface *
115 find_interface(u_int32 addr, Node *node)
117 Interface *ifc;
119 for (ifc = node->u.interfaces; ifc; ifc = ifc->next)
120 if (ifc->addr == addr)
121 return ifc;
123 ifc = (Interface *) malloc(sizeof(Interface));
124 ifc->addr = addr;
125 ifc->next = node->u.interfaces;
126 node->u.interfaces = ifc;
127 ifc->neighbors = NULL;
129 return ifc;
132 Neighbor *
133 find_neighbor(u_int32 addr, Node *node)
135 Interface *ifc;
137 for (ifc = node->u.interfaces; ifc; ifc = ifc->next) {
138 Neighbor *nb;
140 for (nb = ifc->neighbors; nb; nb = nb->next)
141 if (nb->addr == addr)
142 return nb;
145 return 0;
150 * Log errors and other messages to stderr, according to the severity of the
151 * message and the current debug level. For errors of severity LOG_ERR or
152 * worse, terminate the program.
154 void
155 dolog(int severity, int syserr, char *format, ...)
157 va_list ap;
158 char fmt[100];
160 va_start(ap, format);
162 switch (debug) {
163 case 0: if (severity > LOG_WARNING) return;
164 case 1: if (severity > LOG_NOTICE ) return;
165 case 2: if (severity > LOG_INFO ) return;
166 default:
167 fmt[0] = '\0';
168 if (severity == LOG_WARNING)
169 strcpy(fmt, "warning - ");
170 strncat(fmt, format, sizeof(fmt)-strlen(fmt));
171 fmt[sizeof(fmt)-1]='\0';
172 vfprintf(stderr, fmt, ap);
173 if (syserr == 0)
174 fprintf(stderr, "\n");
175 else if (syserr < sys_nerr)
176 fprintf(stderr, ": %s\n", sys_errlist[syserr]);
177 else
178 fprintf(stderr, ": errno %d\n", syserr);
181 if (severity <= LOG_ERR)
182 exit(1);
187 * Send a neighbors-list request.
189 void
190 ask(u_int32 dst)
193 send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
194 htonl(MROUTED_LEVEL), 0);
197 void
198 ask2(u_int32 dst)
201 send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
202 htonl(MROUTED_LEVEL), 0);
207 * Process an incoming group membership report.
209 void
210 accept_group_report(u_int32 src, u_int32 dst, u_int32 group, int r_type)
213 dolog(LOG_INFO, 0, "ignoring IGMP group membership report from %s to %s",
214 inet_fmt(src, s1), inet_fmt(dst, s2));
219 * Process an incoming neighbor probe message.
221 void
222 accept_probe(u_int32 src, u_int32 dst, char *p, int datalen, u_int32 level)
224 dolog(LOG_INFO, 0, "ignoring DVMRP probe from %s to %s",
225 inet_fmt(src, s1), inet_fmt(dst, s2));
230 * Process an incoming route report message.
232 void
233 accept_report(u_int32 src, u_int32 dst, char *p, int datalen, u_int32 level)
235 dolog(LOG_INFO, 0, "ignoring DVMRP routing report from %s to %s",
236 inet_fmt(src, s1), inet_fmt(dst, s2));
241 * Process an incoming neighbor-list request message.
243 void
244 accept_neighbor_request(u_int32 src, u_int32 dst)
246 if (src != our_addr) {
247 dolog(LOG_INFO, 0,
248 "ignoring spurious DVMRP neighbor request from %s to %s",
249 inet_fmt(src, s1), inet_fmt(dst, s2));
253 void
254 accept_neighbor_request2(u_int32 src, u_int32 dst)
256 if (src != our_addr) {
257 dolog(LOG_INFO, 0,
258 "ignoring spurious DVMRP neighbor request2 from %s to %s",
259 inet_fmt(src, s1), inet_fmt(dst, s2));
264 * Process an incoming neighbor-list message.
266 void
267 accept_neighbors(u_int32 src, u_int32 dst, u_char *p, int datalen,
268 u_int32 level)
270 Node *node = find_node(src, &routers);
272 if (node->tries == 0) /* Never heard of 'em; must have hit them at */
273 node->tries = 1; /* least once, though...*/
274 else if (node->tries == -1) /* follow alias link */
275 node = node->u.alias;
277 #define GET_ADDR(a) (a = ((u_int32)*p++ << 24), a += ((u_int32)*p++ << 16),\
278 a += ((u_int32)*p++ << 8), a += *p++)
280 /* if node is running a recent mrouted, ask for additional info */
281 if (level != 0) {
282 node->version = level;
283 node->tries = 1;
284 ask2(src);
285 return;
288 if (debug > 3) {
289 int i;
291 fprintf(stderr, " datalen = %d\n", datalen);
292 for (i = 0; i < datalen; i++) {
293 if ((i & 0xF) == 0)
294 fprintf(stderr, " ");
295 fprintf(stderr, " %02x", p[i]);
296 if ((i & 0xF) == 0xF)
297 fprintf(stderr, "\n");
299 if ((datalen & 0xF) != 0xF)
300 fprintf(stderr, "\n");
303 while (datalen > 0) { /* loop through interfaces */
304 u_int32 ifc_addr;
305 u_char metric, threshold, ncount;
306 Node *ifc_node;
307 Interface *ifc;
308 Neighbor *old_neighbors;
310 if (datalen < 4 + 3) {
311 dolog(LOG_WARNING, 0, "received truncated interface record from %s",
312 inet_fmt(src, s1));
313 return;
316 GET_ADDR(ifc_addr);
317 ifc_addr = htonl(ifc_addr);
318 metric = *p++;
319 threshold = *p++;
320 ncount = *p++;
321 datalen -= 4 + 3;
323 /* Fix up any alias information */
324 ifc_node = find_node(ifc_addr, &routers);
325 if (ifc_node->tries == 0) { /* new node */
326 ifc_node->tries = -1;
327 ifc_node->u.alias = node;
328 } else if (ifc_node != node
329 && (ifc_node->tries > 0 || ifc_node->u.alias != node)) {
330 /* must merge two hosts' nodes */
331 Interface *ifc_i, *next_ifc_i;
333 if (ifc_node->tries == -1) {
334 Node *tmp = ifc_node->u.alias;
336 ifc_node->u.alias = node;
337 ifc_node = tmp;
340 /* Merge ifc_node (foo_i) into node (foo_n) */
342 if (ifc_node->tries > node->tries)
343 node->tries = ifc_node->tries;
345 for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) {
346 Neighbor *nb_i, *next_nb_i, *nb_n;
347 Interface *ifc_n = find_interface(ifc_i->addr, node);
349 old_neighbors = ifc_n->neighbors;
350 for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) {
351 next_nb_i = nb_i->next;
352 for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next)
353 if (nb_i->addr == nb_n->addr) {
354 if (nb_i->metric != nb_n->metric
355 || nb_i->threshold != nb_n->threshold)
356 dolog(LOG_WARNING, 0,
357 "inconsistent %s for neighbor %s of %s",
358 "metric/threshold",
359 inet_fmt(nb_i->addr, s1),
360 inet_fmt(node->addr, s2));
361 free(nb_i);
362 break;
364 if (!nb_n) { /* no match for this neighbor yet */
365 nb_i->next = ifc_n->neighbors;
366 ifc_n->neighbors = nb_i;
370 next_ifc_i = ifc_i->next;
371 free(ifc_i);
374 ifc_node->tries = -1;
375 ifc_node->u.alias = node;
378 ifc = find_interface(ifc_addr, node);
379 old_neighbors = ifc->neighbors;
381 /* Add the neighbors for this interface */
382 while (ncount--) {
383 u_int32 neighbor;
384 Neighbor *nb;
385 Node *n_node;
387 if (datalen < 4) {
388 dolog(LOG_WARNING, 0, "received truncated neighbor list from %s",
389 inet_fmt(src, s1));
390 return;
393 GET_ADDR(neighbor);
394 neighbor = htonl(neighbor);
395 datalen -= 4;
397 for (nb = old_neighbors; nb; nb = nb->next)
398 if (nb->addr == neighbor) {
399 if (metric != nb->metric || threshold != nb->threshold)
400 dolog(LOG_WARNING, 0,
401 "inconsistent %s for neighbor %s of %s",
402 "metric/threshold",
403 inet_fmt(nb->addr, s1), inet_fmt(node->addr, s2));
404 goto next_neighbor;
407 nb = (Neighbor *) malloc(sizeof(Neighbor));
408 nb->next = ifc->neighbors;
409 ifc->neighbors = nb;
410 nb->addr = neighbor;
411 nb->metric = metric;
412 nb->threshold = threshold;
413 nb->flags = 0;
415 n_node = find_node(neighbor, &routers);
416 if (n_node->tries == 0 && !target_addr) { /* it's a new router */
417 ask(neighbor);
418 n_node->tries = 1;
421 next_neighbor: ;
426 void
427 accept_neighbors2(u_int32 src, u_int32 dst, u_char *p, int datalen,
428 u_int32 level)
430 Node *node = find_node(src, &routers);
431 u_int broken_cisco = ((level & 0xffff) == 0x020a); /* 10.2 */
432 /* well, only possibly_broken_cisco, but that's too long to type. */
434 if (node->tries == 0) /* Never heard of 'em; must have hit them at */
435 node->tries = 1; /* least once, though...*/
436 else if (node->tries == -1) /* follow alias link */
437 node = node->u.alias;
439 while (datalen > 0) { /* loop through interfaces */
440 u_int32 ifc_addr;
441 u_char metric, threshold, ncount, flags;
442 Node *ifc_node;
443 Interface *ifc;
444 Neighbor *old_neighbors;
446 if (datalen < 4 + 4) {
447 dolog(LOG_WARNING, 0, "received truncated interface record from %s",
448 inet_fmt(src, s1));
449 return;
452 ifc_addr = *(u_int32*)p;
453 p += 4;
454 metric = *p++;
455 threshold = *p++;
456 flags = *p++;
457 ncount = *p++;
458 datalen -= 4 + 4;
460 if (broken_cisco && ncount == 0) /* dumb Ciscos */
461 ncount = 1;
462 if (broken_cisco && ncount > 15) /* dumb Ciscos */
463 ncount = ncount & 0xf;
465 /* Fix up any alias information */
466 ifc_node = find_node(ifc_addr, &routers);
467 if (ifc_node->tries == 0) { /* new node */
468 ifc_node->tries = -1;
469 ifc_node->u.alias = node;
470 } else if (ifc_node != node
471 && (ifc_node->tries > 0 || ifc_node->u.alias != node)) {
472 /* must merge two hosts' nodes */
473 Interface *ifc_i, *next_ifc_i;
475 if (ifc_node->tries == -1) {
476 Node *tmp = ifc_node->u.alias;
478 ifc_node->u.alias = node;
479 ifc_node = tmp;
482 /* Merge ifc_node (foo_i) into node (foo_n) */
484 if (ifc_node->tries > node->tries)
485 node->tries = ifc_node->tries;
487 for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) {
488 Neighbor *nb_i, *next_nb_i, *nb_n;
489 Interface *ifc_n = find_interface(ifc_i->addr, node);
491 old_neighbors = ifc_n->neighbors;
492 for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) {
493 next_nb_i = nb_i->next;
494 for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next)
495 if (nb_i->addr == nb_n->addr) {
496 if (nb_i->metric != nb_n->metric
497 || nb_i->threshold != nb_n->threshold)
498 dolog(LOG_WARNING, 0,
499 "inconsistent %s for neighbor %s of %s",
500 "metric/threshold",
501 inet_fmt(nb_i->addr, s1),
502 inet_fmt(node->addr, s2));
503 free(nb_i);
504 break;
506 if (!nb_n) { /* no match for this neighbor yet */
507 nb_i->next = ifc_n->neighbors;
508 ifc_n->neighbors = nb_i;
512 next_ifc_i = ifc_i->next;
513 free(ifc_i);
516 ifc_node->tries = -1;
517 ifc_node->u.alias = node;
520 ifc = find_interface(ifc_addr, node);
521 old_neighbors = ifc->neighbors;
523 /* Add the neighbors for this interface */
524 while (ncount-- && datalen > 0) {
525 u_int32 neighbor;
526 Neighbor *nb;
527 Node *n_node;
529 if (datalen < 4) {
530 dolog(LOG_WARNING, 0, "received truncated neighbor list from %s",
531 inet_fmt(src, s1));
532 return;
535 neighbor = *(u_int32*)p;
536 p += 4;
537 datalen -= 4;
538 if (neighbor == 0)
539 /* make leaf nets point to themselves */
540 neighbor = ifc_addr;
542 for (nb = old_neighbors; nb; nb = nb->next)
543 if (nb->addr == neighbor) {
544 if (metric != nb->metric || threshold != nb->threshold)
545 dolog(LOG_WARNING, 0,
546 "inconsistent %s for neighbor %s of %s",
547 "metric/threshold",
548 inet_fmt(nb->addr, s1), inet_fmt(node->addr, s2));
549 goto next_neighbor;
552 nb = (Neighbor *) malloc(sizeof(Neighbor));
553 nb->next = ifc->neighbors;
554 ifc->neighbors = nb;
555 nb->addr = neighbor;
556 nb->metric = metric;
557 nb->threshold = threshold;
558 nb->flags = flags | NF_PRESENT;
560 n_node = find_node(neighbor, &routers);
561 if (n_node->tries == 0 && !target_addr) { /* it's a new router */
562 ask(neighbor);
563 n_node->tries = 1;
566 next_neighbor: ;
571 void
572 check_vif_state(void)
574 dolog(LOG_NOTICE, 0, "network marked down...");
578 retry_requests(Node *node)
580 int result;
582 if (node) {
583 result = retry_requests(node->left);
584 if (node->tries > 0 && node->tries < retries) {
585 if (node->version)
586 ask2(node->addr);
587 else
588 ask(node->addr);
589 node->tries++;
590 result = 1;
592 return retry_requests(node->right) || result;
593 } else
594 return 0;
597 char *
598 inet_name(u_int32 addr)
600 struct hostent *e;
602 e = gethostbyaddr(&addr, sizeof(addr), AF_INET);
604 return e ? e->h_name : 0;
607 void
608 print_map(Node *node)
610 if (node) {
611 char *name, *addr;
613 print_map(node->left);
615 addr = inet_fmt(node->addr, s1);
616 if (!target_addr
617 || (node->tries >= 0 && node->u.interfaces)
618 || (node->tries == -1
619 && node->u.alias->tries >= 0
620 && node->u.alias->u.interfaces)) {
621 if (show_names && (name = inet_name(node->addr)))
622 printf("%s (%s):", addr, name);
623 else
624 printf("%s:", addr);
625 if (node->tries < 0)
626 printf(" alias for %s\n\n", inet_fmt(node->u.alias->addr, s1));
627 else if (!node->u.interfaces)
628 printf(" no response to query\n\n");
629 else {
630 Interface *ifc;
632 if (node->version)
633 printf(" <v%d.%d>", node->version & 0xff,
634 (node->version >> 8) & 0xff);
635 printf("\n");
636 for (ifc = node->u.interfaces; ifc; ifc = ifc->next) {
637 Neighbor *nb;
638 char *ifc_name = inet_fmt(ifc->addr, s1);
639 int ifc_len = strlen(ifc_name);
640 int count = 0;
642 printf(" %s:", ifc_name);
643 for (nb = ifc->neighbors; nb; nb = nb->next) {
644 if (count > 0)
645 printf("%*s", ifc_len + 5, "");
646 printf(" %s", inet_fmt(nb->addr, s1));
647 if (show_names && (name = inet_name(nb->addr)))
648 printf(" (%s)", name);
649 printf(" [%d/%d", nb->metric, nb->threshold);
650 if (nb->flags) {
651 u_short flags = nb->flags;
652 if (flags & DVMRP_NF_TUNNEL)
653 printf("/tunnel");
654 if (flags & DVMRP_NF_SRCRT)
655 printf("/srcrt");
656 if (flags & DVMRP_NF_QUERIER)
657 printf("/querier");
658 if (flags & DVMRP_NF_DISABLED)
659 printf("/disabled");
660 if (flags & DVMRP_NF_DOWN)
661 printf("/down");
663 printf("]\n");
664 count++;
667 printf("\n");
670 print_map(node->right);
674 char *
675 graph_name(u_int32 addr, char *buf, int len)
677 char *name;
679 if (len < sizeof("255.255.255.255")) {
680 fprintf(stderr,
681 "Buffer too small in graph_name, provided %d bytes, but needed %zd.\n",
682 len, sizeof("255.255.255.255"));
683 return NULL;
685 if (show_names && (name = inet_name(addr))) {
686 strncpy(buf, name, len - 1);
687 buf[len - 1] = '\0';
688 } else
689 inet_fmt(addr, buf);
691 return buf;
694 void
695 graph_edges(Node *node)
697 Interface *ifc;
698 Neighbor *nb;
699 char name[100];
701 if (node) {
702 graph_edges(node->left);
703 if (node->tries >= 0) {
704 printf(" %d {$ NP %d0 %d0 $} \"%s%s\" \n",
705 (int) node->addr,
706 node->addr & 0xFF, (node->addr >> 8) & 0xFF,
707 graph_name(node->addr, name, sizeof(name)),
708 node->u.interfaces ? "" : "*");
709 for (ifc = node->u.interfaces; ifc; ifc = ifc->next)
710 for (nb = ifc->neighbors; nb; nb = nb->next) {
711 Node *nb_node = find_node(nb->addr, &routers);
712 Neighbor *nb2;
714 if (nb_node->tries < 0)
715 nb_node = nb_node->u.alias;
717 if (node != nb_node &&
718 (!(nb2 = find_neighbor(node->addr, nb_node))
719 || node->addr < nb_node->addr)) {
720 printf(" %d \"%d/%d",
721 nb_node->addr, nb->metric, nb->threshold);
722 if (nb2 && (nb2->metric != nb->metric
723 || nb2->threshold != nb->threshold))
724 printf(",%d/%d", nb2->metric, nb2->threshold);
725 if (nb->flags & NF_PRESENT)
726 printf("%s%s",
727 nb->flags & DVMRP_NF_SRCRT ? "" :
728 nb->flags & DVMRP_NF_TUNNEL ? "E" : "P",
729 nb->flags & DVMRP_NF_DOWN ? "D" : "");
730 printf("\"\n");
733 printf(" ;\n");
735 graph_edges(node->right);
739 void
740 elide_aliases(Node *node)
742 if (node) {
743 elide_aliases(node->left);
744 if (node->tries >= 0) {
745 Interface *ifc;
747 for (ifc = node->u.interfaces; ifc; ifc = ifc->next) {
748 Neighbor *nb;
750 for (nb = ifc->neighbors; nb; nb = nb->next) {
751 Node *nb_node = find_node(nb->addr, &routers);
753 if (nb_node->tries < 0)
754 nb->addr = nb_node->u.alias->addr;
758 elide_aliases(node->right);
762 void
763 graph_map(void)
765 time_t now;
766 char *nowstr;
768 now = time(0);
769 nowstr = ctime(&now);
770 nowstr[24] = '\0'; /* Kill the newline at the end */
771 elide_aliases(routers);
772 printf("GRAPH \"Multicast Router Connectivity: %s\" = UNDIRECTED\n",
773 nowstr);
774 graph_edges(routers);
775 printf("END\n");
779 get_number(int *var, int deflt, char ***pargv, int *pargc)
781 if ((*pargv)[0][2] == '\0') { /* Get the value from the next argument */
782 if (*pargc > 1 && isdigit((*pargv)[1][0])) {
783 (*pargv)++, (*pargc)--;
784 *var = atoi((*pargv)[0]);
785 return 1;
786 } else if (deflt >= 0) {
787 *var = deflt;
788 return 1;
789 } else
790 return 0;
791 } else { /* Get value from the rest of this argument */
792 if (isdigit((*pargv)[0][2])) {
793 *var = atoi((*pargv)[0] + 2);
794 return 1;
795 } else {
796 return 0;
801 u_int32
802 host_addr(char *name)
804 struct hostent *e = gethostbyname(name);
805 int addr;
807 if (e && e->h_length == sizeof(addr))
808 memcpy(&addr, e->h_addr_list[0], e->h_length);
809 else {
810 addr = inet_addr(name);
811 if (addr == -1)
812 addr = 0;
815 return addr;
818 int
819 main(int argc, char **argv)
821 int flood = FALSE, graph = FALSE;
823 if (geteuid() != 0)
824 errx(1, "must be root");
826 init_igmp();
827 setuid(getuid());
829 setlinebuf(stderr);
831 argv++, argc--;
832 while (argc > 0 && argv[0][0] == '-') {
833 switch (argv[0][1]) {
834 case 'd':
835 if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc))
836 usage();
837 break;
838 case 'f':
839 flood = TRUE;
840 break;
841 case 'g':
842 graph = TRUE;
843 break;
844 case 'n':
845 show_names = FALSE;
846 break;
847 case 'r':
848 if (!get_number(&retries, -1, &argv, &argc))
849 usage();
850 break;
851 case 't':
852 if (!get_number(&timeout, -1, &argv, &argc))
853 usage();
854 break;
855 default:
856 usage();
858 argv++, argc--;
861 if (argc > 1) {
862 usage();
863 } else if (argc == 1 && !(target_addr = host_addr(argv[0])))
864 errx(2, "unknown host: %s", argv[0]);
866 if (debug)
867 fprintf(stderr, "Debug level %u\n", debug);
869 { /* Find a good local address for us. */
870 int udp;
871 struct sockaddr_in addr;
872 int addrlen = sizeof(addr);
874 addr.sin_family = AF_INET;
875 #ifdef HAVE_SA_LEN
876 addr.sin_len = sizeof addr;
877 #endif
878 addr.sin_addr.s_addr = dvmrp_group;
879 addr.sin_port = htons(2000); /* any port over 1024 will do... */
880 if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
881 || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
882 || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0)
883 err(-1, "determining local address");
884 close(udp);
885 our_addr = addr.sin_addr.s_addr;
888 /* Send initial seed message to all local routers */
889 ask(target_addr ? target_addr : allhosts_group);
891 if (target_addr) {
892 Node *n = find_node(target_addr, &routers);
894 n->tries = 1;
896 if (flood)
897 target_addr = 0;
900 /* Main receive loop */
901 for(;;) {
902 fd_set fds;
903 struct timeval tv;
904 int count, recvlen, dummy = 0;
906 if (igmp_socket >= FD_SETSIZE)
907 dolog(LOG_ERR, 0, "descriptor too big");
908 FD_ZERO(&fds);
909 FD_SET(igmp_socket, &fds);
911 tv.tv_sec = timeout;
912 tv.tv_usec = 0;
914 count = select(igmp_socket + 1, &fds, 0, 0, &tv);
916 if (count < 0) {
917 if (errno != EINTR)
918 warn("select");
919 continue;
920 } else if (count == 0) {
921 dolog(LOG_DEBUG, 0, "Timed out receiving neighbor lists");
922 if (retry_requests(routers))
923 continue;
924 else
925 break;
928 recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
929 0, NULL, &dummy);
930 if (recvlen >= 0)
931 accept_igmp(recvlen);
932 else if (errno != EINTR)
933 warn("recvfrom");
936 printf("\n");
938 if (graph)
939 graph_map();
940 else {
941 if (!target_addr)
942 printf("Multicast Router Connectivity:\n\n");
943 print_map(routers);
946 exit(0);
949 static void
950 usage(void)
952 fprintf(stderr, "%s\n%s\n",
953 "usage: map-mbone [-f] [-g] [-n] [-t timeout] [-r retries]",
954 " [-d [debug-level]] [router]");
955 exit(1);
958 /* dummies */
959 void
960 accept_prune(u_int32 src, u_int32 dst, char *p, int datalen)
964 void
965 accept_graft(u_int32 src, u_int32 dst, char *p, int datalen)
969 void
970 accept_g_ack(u_int32 src, u_int32 dst, char *p, int datalen)
974 void
975 add_table_entry(u_int32 origin, u_int32 mcastgrp)
979 void
980 accept_leave_message(u_int32 src, u_int32 dst, u_int32 group)
984 void
985 accept_mtrace(u_int32 src, u_int32 dst, u_int32 group,
986 char *data, u_int no, int datalen)
990 void
991 accept_membership_query(u_int32 src, u_int32 dst, u_int32 group, int tmo)
995 void
996 accept_info_request(u_int32 src, u_int32 dst, u_char *p, int datalen)
1000 void
1001 accept_info_reply(u_int32 src, u_int32 dst, u_char *p, int datalen)