Annotation of embedaddon/pimdd/config.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *  Copyright (c) 1998 by the University of Southern California.
                      3:  *  All rights reserved.
                      4:  *
                      5:  *  Permission to use, copy, modify, and distribute this software and
                      6:  *  its documentation in source and binary forms for lawful
                      7:  *  purposes and without fee is hereby granted, provided
                      8:  *  that the above copyright notice appear in all copies and that both
                      9:  *  the copyright notice and this permission notice appear in supporting
                     10:  *  documentation, and that any documentation, advertising materials,
                     11:  *  and other materials related to such distribution and use acknowledge
                     12:  *  that the software was developed by the University of Southern
                     13:  *  California and/or Information Sciences Institute.
                     14:  *  The name of the University of Southern California may not
                     15:  *  be used to endorse or promote products derived from this software
                     16:  *  without specific prior written permission.
                     17:  *
                     18:  *  THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
                     19:  *  ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS SOFTWARE IS
                     20:  *  PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
                     21:  *  INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
                     22:  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND 
                     23:  *  NON-INFRINGEMENT.
                     24:  *
                     25:  *  IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
                     26:  *  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
                     27:  *  TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
                     28:  *  THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     29:  *
                     30:  *  Other copyrights might apply to parts of this software and are so
                     31:  *  noted when applicable.
                     32:  */
                     33: /*
                     34:  *  Questions concerning this software should be directed to 
                     35:  *  Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
                     36:  *
                     37:  *  $Id: config.c,v 1.8 1998/12/22 21:50:16 kurtw Exp $
                     38:  */
                     39: /*
                     40:  * Part of this program has been derived from mrouted.
                     41:  * The mrouted program is covered by the license in the accompanying file
                     42:  * named "LICENSE.mrouted".
                     43:  *
                     44:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
                     45:  * Leland Stanford Junior University.
                     46:  *
                     47:  */
                     48: 
                     49: #include "defs.h"
                     50: 
                     51: 
                     52: /*
                     53:  * Forward declarations.
                     54:  */
                     55: static char *next_word  __P((char **));
                     56: static int parse_phyint __P((char *s));
                     57: 
                     58: 
                     59: /*
                     60:  * Query the kernel to find network interfaces that are multicast-capable
                     61:  * and install them in the uvifs array.
                     62:  */
                     63: void 
                     64: config_vifs_from_kernel()
                     65: {
                     66:     struct ifreq *ifrp, *ifend;
                     67:     register struct uvif *v;
                     68:     register vifi_t vifi;
                     69:     int n;
                     70:     u_int32 addr, mask, subnet;
                     71:     short flags;
                     72:     int num_ifreq = 32;
                     73:     struct ifconf ifc;
                     74: 
                     75:     total_interfaces = 0; /* The total number of physical interfaces */
                     76:     
                     77:     ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
                     78:     ifc.ifc_buf = calloc(ifc.ifc_len, sizeof(char));
                     79:     while (ifc.ifc_buf) {
                     80:        if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
                     81:            log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
                     82:        
                     83:        /*
                     84:         * If the buffer was large enough to hold all the addresses
                     85:         * then break out, otherwise increase the buffer size and
                     86:         * try again.
                     87:         *
                     88:         * The only way to know that we definitely had enough space
                     89:         * is to know that there was enough space for at least one
                     90:         * more struct ifreq. ???
                     91:         */
                     92:        if ((num_ifreq * sizeof(struct ifreq)) >=
                     93:            ifc.ifc_len + sizeof(struct ifreq))
                     94:            break;
                     95:        
                     96:        num_ifreq *= 2;
                     97:        ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
                     98:        ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);
                     99:     }
                    100:     if (ifc.ifc_buf == NULL)
                    101:        log(LOG_ERR, 0, "config_vifs_from_kernel: ran out of memory");
                    102:     
                    103:     ifrp = (struct ifreq *)ifc.ifc_buf;
                    104:     ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len);
                    105:     /*
                    106:      * Loop through all of the interfaces.
                    107:      */
                    108:     for (; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) {
                    109:        struct ifreq ifr;
                    110: #ifdef HAVE_SA_LEN
                    111:        n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
                    112:        if (n < sizeof(*ifrp))
                    113:            n = sizeof(*ifrp);
                    114: #else
                    115:        n = sizeof(*ifrp);
                    116: #endif /* HAVE_SA_LEN */
                    117:        
                    118:        /*
                    119:         * Ignore any interface for an address family other than IP.
                    120:         */
                    121:        if (ifrp->ifr_addr.sa_family != AF_INET) {
                    122:            total_interfaces++;  /* Eventually may have IP address later */
                    123:            continue;
                    124:        }
                    125:        
                    126:        addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr;
                    127:        
                    128:        /*
                    129:         * Need a template to preserve address info that is
                    130:         * used below to locate the next entry.  (Otherwise,
                    131:         * SIOCGIFFLAGS stomps over it because the requests
                    132:         * are returned in a union.)
                    133:         */
                    134:        bcopy(ifrp->ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
                    135:        
                    136:        /*
                    137:         * Ignore loopback interfaces and interfaces that do not
                    138:         * support multicast.
                    139:         */
                    140:        if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
                    141:            log(LOG_ERR, errno, "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
                    142:        flags = ifr.ifr_flags;
                    143:        if ((flags & (IFF_LOOPBACK | IFF_MULTICAST)) != IFF_MULTICAST)
                    144:            continue;
                    145:        
                    146:        /*
                    147:         * Everyone below is a potential vif interface.
                    148:         * We don't care if it has wrong configuration or not configured
                    149:         * at all.
                    150:         */       
                    151:        total_interfaces++;
                    152: 
                    153:        /*
                    154:         * Ignore any interface whose address and mask do not define a
                    155:         * valid subnet number, or whose address is of the form
                    156:         * {subnet,0} or {subnet,-1}.
                    157:         */
                    158:        if (ioctl(udp_socket, SIOCGIFNETMASK, (char *)&ifr) < 0)
                    159:            log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s",
                    160:                ifr.ifr_name);
                    161:        mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
                    162:        subnet = addr & mask;
                    163:        if ((!inet_valid_subnet(subnet, mask))
                    164:            || (addr == subnet) || addr == (subnet | ~mask)) {
                    165:            log(LOG_WARNING, 0,
                    166:                "ignoring %s, has invalid address (%s) and/or mask (%s)",
                    167:                ifr.ifr_name, inet_fmt(addr, s1), inet_fmt(mask, s2));
                    168:            continue;
                    169:        }
                    170:        
                    171:        /*
                    172:         * Ignore any interface that is connected to the same subnet as
                    173:         * one already installed in the uvifs array.
                    174:         */
                    175:        /*
                    176:         * TODO: XXX: bug or "feature" is to allow only one interface per
                    177:         * subnet?
                    178:         */
                    179:        
                    180:        for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
                    181:            if (strcmp(v->uv_name, ifr.ifr_name) == 0) {
                    182:                log(LOG_DEBUG, 0,
                    183:                    "skipping %s (%s on subnet %s) (alias for vif#%u?)",
                    184:                    v->uv_name, inet_fmt(addr, s1),
                    185:                    netname(subnet, mask), vifi);
                    186:                break;
                    187:            }
                    188:            if ((addr & v->uv_subnetmask) == v->uv_subnet ||
                    189:                (v->uv_subnet & mask) == subnet) {
                    190:                log(LOG_WARNING, 0, "ignoring %s, same subnet as %s",
                    191:                    ifr.ifr_name, v->uv_name);
                    192:                break;
                    193:            }
                    194:        }
                    195:        if (vifi != numvifs)
                    196:            continue;
                    197:        
                    198:        /*
                    199:         * If there is room in the uvifs array, install this interface.
                    200:         */
                    201:        if (numvifs == MAXVIFS) {
                    202:            log(LOG_WARNING, 0, "too many vifs, ignoring %s", ifr.ifr_name);
                    203:            continue;
                    204:        }
                    205:        v = &uvifs[numvifs];
                    206:        v->uv_flags             = 0;
                    207:        v->uv_metric            = DEFAULT_METRIC;
                    208:        v->uv_admetric          = 0;
                    209:        v->uv_threshold         = DEFAULT_THRESHOLD;
                    210:        v->uv_rate_limit        = DEFAULT_PHY_RATE_LIMIT;
                    211:        v->uv_lcl_addr          = addr;
                    212:        v->uv_rmt_addr          = INADDR_ANY_N;
                    213:        v->uv_dst_addr          = allpimrouters_group;
                    214:        v->uv_subnet            = subnet;
                    215:        v->uv_subnetmask        = mask;
                    216:        v->uv_subnetbcast       = subnet | ~mask;
                    217:        strncpy(v->uv_name, ifr.ifr_name, IFNAMSIZ);
                    218:        v->uv_groups            = (struct listaddr *)NULL;
                    219:        v->uv_dvmrp_neighbors   = (struct listaddr *)NULL;
                    220:        NBRM_CLRALL(v->uv_nbrmap);
                    221:        v->uv_querier           = (struct listaddr *)NULL;
                    222:        v->uv_igmpv1_warn       = 0;
                    223:        v->uv_prune_lifetime    = 0;
                    224:        v->uv_acl               = (struct vif_acl *)NULL;
                    225:        RESET_TIMER(v->uv_leaf_timer);
                    226:        v->uv_addrs             = (struct phaddr *)NULL;
                    227:        v->uv_filter            = (struct vif_filter *)NULL;
                    228:        RESET_TIMER(v->uv_pim_hello_timer);
                    229:        RESET_TIMER(v->uv_gq_timer);
                    230:        v->uv_pim_neighbors     = (struct pim_nbr_entry *)NULL;
                    231:        v->uv_local_pref        = default_source_preference;
                    232:        v->uv_local_metric      = default_source_metric;
                    233:        
                    234:        if (flags & IFF_POINTOPOINT)
                    235:            v->uv_flags |= (VIFF_REXMIT_PRUNES | VIFF_POINT_TO_POINT);
                    236:        log(LOG_INFO, 0,
                    237:            "installing %s (%s on subnet %s) as vif #%u - rate=%d",
                    238:            v->uv_name, inet_fmt(addr, s1), netname(subnet, mask),
                    239:            numvifs, v->uv_rate_limit);
                    240:        ++numvifs;
                    241:        
                    242:        /*
                    243:         * If the interface is not yet up, set the vifs_down flag to
                    244:         * remind us to check again later.
                    245:         */
                    246:        if (!(flags & IFF_UP)) {
                    247:            v->uv_flags |= VIFF_DOWN;
                    248:            vifs_down = TRUE;
                    249:        }
                    250:     }
                    251: }
                    252: 
                    253: 
                    254: #define UNKNOWN        -1
                    255: #define EMPTY           1
                    256: #define PHYINT          2
                    257: #define DEFAULT_SOURCE_METRIC     3
                    258: #define DEFAULT_SOURCE_PREFERENCE 4
                    259: 
                    260: /*
                    261:  * function name: wordToOption
                    262:  * input: char *word, a pointer to the word
                    263:  * output: int; a number corresponding to the code of the word
                    264:  * operation: converts the result of the string comparisons into numerics.
                    265:  * comments: called by config_vifs_from_file()
                    266:  */
                    267: int 
                    268: wordToOption(word)
                    269:     char *word;
                    270: {
                    271:     if (EQUAL(word, ""))
                    272:        return EMPTY;
                    273:     if (EQUAL(word, "phyint"))
                    274:        return PHYINT;
                    275:     if (EQUAL(word, "default_source_metric"))
                    276:         return DEFAULT_SOURCE_METRIC;
                    277:     if (EQUAL(word, "default_source_preference"))
                    278:         return DEFAULT_SOURCE_PREFERENCE;
                    279: 
                    280:     return UNKNOWN;
                    281: }
                    282: 
                    283: /*
                    284:  * function name: parse_phyint
                    285:  * input: char *s, pointing to the parsing point of the file
                    286:  * output: int (TRUE if the parsing was successful, o.w. FALSE)
                    287:  * operation: parses the physical interface file configurations, if any.
                    288:  * The general form is:
                    289:  *     phyint <local-addr> [disable]
                    290:  */
                    291: static int
                    292: parse_phyint(s)
                    293:     char *s;
                    294: {
                    295:     char *w, c;
                    296:     u_int32 local;
                    297:     vifi_t vifi;
                    298:     struct uvif *v;
                    299:     u_int n;
                    300:     
                    301:     if (EQUAL((w = next_word(&s)), "")) {
                    302:        log(LOG_WARNING, 0, "Missing phyint address in %s", configfilename);
                    303:        return(FALSE);
                    304:     }          /* if empty */
                    305:     
                    306:     local = inet_parse(w, 4);
                    307:     if (!inet_valid_host(local)) {
                    308:        log(LOG_WARNING, 0, "Invalid phyint address '%s' in %s", w,
                    309:            configfilename);
                    310:        return(FALSE);
                    311:     }          /* invalid address */
                    312:     
                    313:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
                    314:        if (vifi == numvifs) {
                    315:            log(LOG_WARNING, 0,
                    316:                "phyint %s in %s is not a configured interface",
                    317:                inet_fmt(local, s1), configfilename);
                    318:            return(FALSE);
                    319:        }       /* if vifi == numvifs */
                    320:        
                    321:        if (local != v->uv_lcl_addr)
                    322:            continue;
                    323:        
                    324:        while (!EQUAL((w = next_word(&s)), "")) {
                    325:            if (EQUAL(w, "disable"))
                    326:                v->uv_flags |= VIFF_DISABLED;
                    327:            else if(EQUAL(w, "preference")) 
                    328:                 if(EQUAL((w = next_word(&s)), "")) 
                    329:                     log(LOG_WARNING, 0,
                    330:                         "Missing preference for phyint %s in %s",
                    331:                         inet_fmt(local, s1), configfilename);
                    332:                 else if (sscanf(w, "%u%c", &n, &c) != 1 ||
                    333:                          n < 1 || n > 255 )
                    334:                     log(LOG_WARNING, 0,
                    335:                         "Invalid preference '%s' for phyint %s in %s",
                    336:                         w, inet_fmt(local, s1),
                    337:                         configfilename);
                    338:                else {
                    339:                    IF_DEBUG(DEBUG_ASSERT)
                    340:                        log(LOG_DEBUG, 0,
                    341:                            "Config setting default local preference on %s to %d.", 
                    342:                            inet_fmt(local, s1), n);
                    343:                    v->uv_local_pref = n;
                    344:                }
                    345:            
                    346:            else if(EQUAL(w, "metric")) 
                    347:                 if(EQUAL((w = next_word(&s)), "")) 
                    348:                     log(LOG_WARNING, 0,
                    349:                         "Missing metric for phyint %s in %s",
                    350:                         inet_fmt(local, s1), configfilename);
                    351:                 else if (sscanf(w, "%u%c", &n, &c) != 1 ||
                    352:                          n < 1 || n > 1024 )
                    353:                     log(LOG_WARNING, 0,
                    354:                         "Invalid metric '%s' for phyint %s in %s",
                    355:                         w, inet_fmt(local, s1),
                    356:                         configfilename);
                    357:                else {
                    358:                    IF_DEBUG(DEBUG_ASSERT)
                    359:                        log(LOG_DEBUG, 0,
                    360:                            "Config setting default local metric on %s to %d.", 
                    361:                            inet_fmt(local, s1), n);
                    362:                    v->uv_local_metric = n;
                    363:                }
                    364:            
                    365:        }               /* if not empty */
                    366:        break;
                    367:     }
                    368:     return(TRUE);
                    369: }
                    370: 
                    371: 
                    372: /*
                    373:  * function name: parse_default_source_metric
                    374:  * input: char *s
                    375:  * output: int
                    376:  * operation: reads and assigns the default source metric, if no reliable
                    377:  *            unicast routing information available.
                    378:  *            General form: 
                    379:  *              'default_source_metric <number>'.
                    380:  *            default pref and metric statements should precede all phyint
                    381:  *            statements in the config file.
                    382:  */
                    383: int
                    384: parse_default_source_metric(s)
                    385:     char *s;
                    386: {
                    387:     char *w;
                    388:     u_int value;
                    389:     vifi_t vifi;
                    390:     struct uvif *v;
                    391: 
                    392:     value = DEFAULT_LOCAL_METRIC;
                    393:     if (EQUAL((w = next_word(&s)), "")) {
                    394:         log(LOG_WARNING, 0,
                    395:             "Missing default source metric; set to default %u",
                    396:             DEFAULT_LOCAL_METRIC);
                    397:     } else if (sscanf(w, "%u", &value) != 1) {
                    398:         log(LOG_WARNING, 0,
                    399:             "Invalid default source metric; set to default %u",
                    400:             DEFAULT_LOCAL_METRIC);
                    401:         value = DEFAULT_LOCAL_METRIC;
                    402:     }
                    403:     default_source_metric = value;
                    404:     log(LOG_INFO, 0, "default_source_metric is %u", value);
                    405: 
                    406:     for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v) {
                    407:        v->uv_local_metric = default_source_metric;
                    408:     }
                    409:        
                    410:     return(TRUE);
                    411: }
                    412: 
                    413: 
                    414: /*
                    415:  * function name: parse_default_source_preference
                    416:  * input: char *s
                    417:  * output: int
                    418:  * operation: reads and assigns the default source preference, if no reliable
                    419:  *            unicast routing information available.
                    420:  *            General form: 
                    421:  *              'default_source_preference <number>'.
                    422:  *            default pref and metric statements should precede all phyint
                    423:  *            statements in the config file.
                    424: */
                    425: int
                    426: parse_default_source_preference(s)
                    427:     char *s;
                    428: {
                    429:     char *w;
                    430:     u_int value;
                    431:     vifi_t vifi;
                    432:     struct uvif *v;
                    433: 
                    434:     value = DEFAULT_LOCAL_PREF;
                    435:     if (EQUAL((w = next_word(&s)), "")) {
                    436:         log(LOG_WARNING, 0,
                    437:             "Missing default source preference; set to default %u",
                    438:             DEFAULT_LOCAL_PREF);
                    439:     } else if (sscanf(w, "%u", &value) != 1) {
                    440:         log(LOG_WARNING, 0,
                    441:             "Invalid default source preference; set to default %u",
                    442:             DEFAULT_LOCAL_PREF);
                    443:         value = DEFAULT_LOCAL_PREF;
                    444:     }
                    445:     default_source_preference = value;
                    446:     log(LOG_INFO, 0, "default_source_preference is %u", value);
                    447: 
                    448:     for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v) {
                    449:        v->uv_local_pref = default_source_preference;
                    450:     }
                    451: 
                    452:     return(TRUE);
                    453: }
                    454: 
                    455: 
                    456: 
                    457: 
                    458: void 
                    459: config_vifs_from_file()
                    460: {
                    461:     FILE *f;
                    462:     char linebuf[100];
                    463:     char *w, *s;
                    464:     struct ifconf ifc;
                    465:     int option;
                    466:     char ifbuf[BUFSIZ];
                    467:     
                    468:     if ((f = fopen(configfilename, "r")) == NULL) {
                    469:        if (errno != ENOENT) log(LOG_WARNING, errno, "can't open %s", 
                    470:                                 configfilename);
                    471:        return;
                    472:     }
                    473: 
                    474:     ifc.ifc_buf = ifbuf;
                    475:     ifc.ifc_len = sizeof(ifbuf);
                    476:     if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0) 
                    477:        log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
                    478:     
                    479:     while (fgets(linebuf, sizeof(linebuf), f) != NULL) {
                    480:        s = linebuf;
                    481:        w = next_word(&s);
                    482:        option = wordToOption(w);
                    483:        switch(option) {
                    484:        case EMPTY:
                    485:            continue;
                    486:            break;
                    487:        case PHYINT:
                    488:            parse_phyint(s);
                    489:            break;
                    490:        default:
                    491:            log(LOG_WARNING, 0, "unknown command '%s' in %s",
                    492:                w, configfilename);
                    493:        }
                    494:     }
                    495:     fclose(f);
                    496: }
                    497: 
                    498: 
                    499: static char *
                    500: next_word(s)
                    501:     char **s;
                    502: {
                    503:     char *w;
                    504:     
                    505:     w = *s;
                    506:     while (*w == ' ' || *w == '\t')
                    507:        w++;
                    508:     
                    509:     *s = w;
                    510:     for(;;) {
                    511:        switch (**s) {
                    512:        case ' '  :
                    513:        case '\t' :
                    514:            **s = '\0';
                    515:            (*s)++;
                    516:            return(w);
                    517:        case '\n' :
                    518:        case '#'  :
                    519:            **s = '\0';
                    520:            return(w);
                    521:        case '\0' :
                    522:            return(w);
                    523:        default   :
                    524:            if (isascii(**s) && isupper(**s))
                    525:                **s = tolower(**s);
                    526:            (*s)++;
                    527:        }
                    528:     }
                    529: }
                    530: 

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