File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimdd / config.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:58:55 2017 UTC (7 years ago) by misho
Branches: pimdd, MAIN
CVS tags: v0_2_1p0, v0_2_1, HEAD
pimdd-dense 0.2.1.0_2

    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.1.1.1 2017/06/12 07:58:55 misho 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>