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