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