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