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