Annotation of embedaddon/pimdd/config.c, revision 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>