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