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