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