Annotation of embedaddon/mrouted/mapper.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>