File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / src / net_ifs.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:23:02 2012 UTC (12 years, 4 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_3p2, HEAD
sudo

    1: /*
    2:  * Copyright (c) 1996, 1998-2005, 2007-2010
    3:  *	Todd C. Miller <Todd.Miller@courtesan.com>
    4:  *
    5:  * Permission to use, copy, modify, and distribute this software for any
    6:  * purpose with or without fee is hereby granted, provided that the above
    7:  * copyright notice and this permission notice appear in all copies.
    8:  *
    9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   16:  *
   17:  * Sponsored in part by the Defense Advanced Research Projects
   18:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
   19:  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
   20:  */
   21: 
   22: /*
   23:  * Suppress a warning w/ gcc on Digital UN*X.
   24:  * The system headers should really do this....
   25:  */
   26: #if defined(__osf__) && !defined(__cplusplus)
   27: struct mbuf;
   28: struct rtentry;
   29: #endif
   30: 
   31: #include <config.h>
   32: 
   33: #include <sys/types.h>
   34: #include <sys/socket.h>
   35: #include <sys/param.h>
   36: #include <sys/time.h>
   37: #include <sys/ioctl.h>
   38: #if defined(HAVE_SYS_SOCKIO_H) && !defined(SIOCGIFCONF)
   39: # include <sys/sockio.h>
   40: #endif
   41: #include <stdio.h>
   42: #ifdef STDC_HEADERS
   43: # include <stdlib.h>
   44: # include <stddef.h>
   45: #else
   46: # ifdef HAVE_STDLIB_H
   47: #  include <stdlib.h>
   48: # endif
   49: #endif /* STDC_HEADERS */
   50: #ifdef HAVE_STRING_H
   51: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
   52: #  include <memory.h>
   53: # endif
   54: # include <string.h>
   55: #endif /* HAVE_STRING_H */
   56: #ifdef HAVE_STRINGS_H
   57: # include <strings.h>
   58: #endif /* HAVE_STRINGS_H */
   59: #ifdef HAVE_UNISTD_H
   60: # include <unistd.h>
   61: #endif /* HAVE_UNISTD_H */
   62: #include <netdb.h>
   63: #include <errno.h>
   64: #ifdef _ISC
   65: # include <sys/stream.h>
   66: # include <sys/sioctl.h>
   67: # include <sys/stropts.h>
   68: # define STRSET(cmd, param, len) {strioctl.ic_cmd=(cmd);\
   69: 				 strioctl.ic_dp=(param);\
   70: 				 strioctl.ic_timout=0;\
   71: 				 strioctl.ic_len=(len);}
   72: #endif /* _ISC */
   73: #ifdef _MIPS
   74: # include <net/soioctl.h>
   75: #endif /* _MIPS */
   76: #include <netinet/in.h>
   77: #include <arpa/inet.h>
   78: #include <net/if.h>
   79: #ifdef HAVE_GETIFADDRS
   80: # include <ifaddrs.h>
   81: #endif
   82: 
   83: #include "missing.h"
   84: #include "alloc.h"
   85: #include "error.h"
   86: 
   87: #define DEFAULT_TEXT_DOMAIN	"sudo"
   88: #include "gettext.h"
   89: 
   90: /* Minix apparently lacks IFF_LOOPBACK */
   91: #ifndef IFF_LOOPBACK
   92: # define IFF_LOOPBACK	0
   93: #endif
   94: 
   95: #ifndef INET6_ADDRSTRLEN
   96: # define INET6_ADDRSTRLEN 46
   97: #endif
   98: 
   99: #ifdef HAVE_GETIFADDRS
  100: 
  101: /*
  102:  * Fill in the interfaces string with the machine's ip addresses and netmasks
  103:  * and return the number of interfaces found.
  104:  */
  105: int
  106: get_net_ifs(char **addrinfo)
  107: {
  108:     struct ifaddrs *ifa, *ifaddrs;
  109:     struct sockaddr_in *sin;
  110: #ifdef HAVE_IN6_ADDR
  111:     struct sockaddr_in6 *sin6;
  112:     char addrbuf[INET6_ADDRSTRLEN];
  113: #endif
  114:     int ailen, i, len, num_interfaces = 0;
  115:     char *cp;
  116: 
  117:     if (getifaddrs(&ifaddrs))
  118: 	return 0;
  119: 
  120:     /* Allocate space for the interfaces info string. */
  121:     for (ifa = ifaddrs; ifa != NULL; ifa = ifa -> ifa_next) {
  122: 	/* Skip interfaces marked "down" and "loopback". */
  123: 	if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL ||
  124: 	    !ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK))
  125: 	    continue;
  126: 
  127: 	switch (ifa->ifa_addr->sa_family) {
  128: 	    case AF_INET:
  129: #ifdef HAVE_IN6_ADDR
  130: 	    case AF_INET6:
  131: #endif
  132: 		num_interfaces++;
  133: 		break;
  134: 	}
  135:     }
  136:     if (num_interfaces == 0)
  137: 	return 0;
  138:     ailen = num_interfaces * 2 * INET6_ADDRSTRLEN;
  139:     *addrinfo = cp = emalloc(ailen);
  140: 
  141:     /* Store the IP addr/netmask pairs. */
  142:     for (ifa = ifaddrs, i = 0; ifa != NULL; ifa = ifa -> ifa_next) {
  143: 	/* Skip interfaces marked "down" and "loopback". */
  144: 	if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL ||
  145: 	    !ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK))
  146: 		continue;
  147: 
  148: 	switch (ifa->ifa_addr->sa_family) {
  149: 	    case AF_INET:
  150: 		sin = (struct sockaddr_in *)ifa->ifa_addr;
  151: 		len = snprintf(cp, ailen - (*addrinfo - cp),
  152: 		    "%s%s/", cp == *addrinfo ? "" : " ",
  153: 		    inet_ntoa(sin->sin_addr));
  154: 		if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
  155: 		    warningx(_("load_interfaces: overflow detected"));
  156: 		    goto done;
  157: 		}
  158: 		cp += len;
  159: 
  160: 		sin = (struct sockaddr_in *)ifa->ifa_netmask;
  161: 		len = snprintf(cp, ailen - (*addrinfo - cp),
  162: 		    "%s", inet_ntoa(sin->sin_addr));
  163: 		if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
  164: 		    warningx(_("load_interfaces: overflow detected"));
  165: 		    goto done;
  166: 		}
  167: 		cp += len;
  168: 		break;
  169: #ifdef HAVE_IN6_ADDR
  170: 	    case AF_INET6:
  171: 		sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
  172: 		inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf));
  173: 		len = snprintf(cp, ailen - (*addrinfo - cp),
  174: 		    "%s%s/", cp == *addrinfo ? "" : " ", addrbuf);
  175: 		if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
  176: 		    warningx(_("load_interfaces: overflow detected"));
  177: 		    goto done;
  178: 		}
  179: 		cp += len;
  180: 
  181: 		sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask;
  182: 		inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf));
  183: 		len = snprintf(cp, ailen - (*addrinfo - cp), "%s", addrbuf);
  184: 		if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
  185: 		    warningx(_("load_interfaces: overflow detected"));
  186: 		    goto done;
  187: 		}
  188: 		cp += len;
  189: 		break;
  190: #endif /* HAVE_IN6_ADDR */
  191: 	}
  192:     }
  193: 
  194: done:
  195: #ifdef HAVE_FREEIFADDRS
  196:     freeifaddrs(ifaddrs);
  197: #else
  198:     efree(ifaddrs);
  199: #endif
  200:     return num_interfaces;
  201: }
  202: 
  203: #elif defined(SIOCGIFCONF) && !defined(STUB_LOAD_INTERFACES)
  204: 
  205: /*
  206:  * Allocate and fill in the interfaces global variable with the
  207:  * machine's ip addresses and netmasks.
  208:  */
  209: int
  210: get_net_ifs(char **addrinfo)
  211: {
  212:     struct ifconf *ifconf;
  213:     struct ifreq *ifr, ifr_tmp;
  214:     struct sockaddr_in *sin;
  215:     int ailen, i, len, n, sock, num_interfaces = 0;
  216:     size_t buflen = sizeof(struct ifconf) + BUFSIZ;
  217:     char *cp, *previfname = "", *ifconf_buf = NULL;
  218: #ifdef _ISC
  219:     struct strioctl strioctl;
  220: #endif /* _ISC */
  221: 
  222:     sock = socket(AF_INET, SOCK_DGRAM, 0);
  223:     if (sock < 0)
  224: 	error(1, _("unable to open socket"));
  225: 
  226:     /*
  227:      * Get interface configuration or return.
  228:      */
  229:     for (;;) {
  230: 	ifconf_buf = emalloc(buflen);
  231: 	ifconf = (struct ifconf *) ifconf_buf;
  232: 	ifconf->ifc_len = buflen - sizeof(struct ifconf);
  233: 	ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf));
  234: 
  235: #ifdef _ISC
  236: 	STRSET(SIOCGIFCONF, (caddr_t) ifconf, buflen);
  237: 	if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0)
  238: #else
  239: 	/* Note that some kernels return EINVAL if the buffer is too small */
  240: 	if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0 && errno != EINVAL)
  241: #endif /* _ISC */
  242: 	    goto done;
  243: 
  244: 	/* Break out of loop if we have a big enough buffer. */
  245: 	if (ifconf->ifc_len + sizeof(struct ifreq) < buflen)
  246: 	    break;
  247: 	buflen += BUFSIZ;
  248: 	efree(ifconf_buf);
  249:     }
  250: 
  251:     /* Allocate space for the maximum number of interfaces that could exist. */
  252:     if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0)
  253: 	return 0;
  254:     ailen = n * 2 * INET6_ADDRSTRLEN;
  255:     *addrinfo = cp = emalloc(ailen);
  256: 
  257:     /* For each interface, store the ip address and netmask. */
  258:     for (i = 0; i < ifconf->ifc_len; ) {
  259: 	/* Get a pointer to the current interface. */
  260: 	ifr = (struct ifreq *) &ifconf->ifc_buf[i];
  261: 
  262: 	/* Set i to the subscript of the next interface. */
  263: 	i += sizeof(struct ifreq);
  264: #ifdef HAVE_SA_LEN
  265: 	if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
  266: 	    i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
  267: #endif /* HAVE_SA_LEN */
  268: 
  269: 	/* Skip duplicates and interfaces with NULL addresses. */
  270: 	sin = (struct sockaddr_in *) &ifr->ifr_addr;
  271: 	if (sin->sin_addr.s_addr == 0 ||
  272: 	    strncmp(previfname, ifr->ifr_name, sizeof(ifr->ifr_name) - 1) == 0)
  273: 	    continue;
  274: 
  275: 	if (ifr->ifr_addr.sa_family != AF_INET)
  276: 		continue;
  277: 
  278: #ifdef SIOCGIFFLAGS
  279: 	memset(&ifr_tmp, 0, sizeof(ifr_tmp));
  280: 	strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
  281: 	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr_tmp) < 0)
  282: #endif
  283: 	    ifr_tmp = *ifr;
  284: 	
  285: 	/* Skip interfaces marked "down" and "loopback". */
  286: 	if (!ISSET(ifr_tmp.ifr_flags, IFF_UP) ||
  287: 	    ISSET(ifr_tmp.ifr_flags, IFF_LOOPBACK))
  288: 		continue;
  289: 
  290: 	sin = (struct sockaddr_in *) &ifr->ifr_addr;
  291: 	len = snprintf(cp, ailen - (*addrinfo - cp),
  292: 	    "%s%s/", cp == *addrinfo ? "" : " ",
  293: 	    inet_ntoa(sin->sin_addr));
  294: 	if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
  295: 	    warningx(_("load_interfaces: overflow detected"));
  296: 	    goto done;
  297: 	}
  298: 	cp += len;
  299: 
  300: 	/* Stash the name of the interface we saved. */
  301: 	previfname = ifr->ifr_name;
  302: 
  303: 	/* Get the netmask. */
  304: 	memset(&ifr_tmp, 0, sizeof(ifr_tmp));
  305: 	strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
  306: #ifdef _ISC
  307: 	STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp));
  308: 	if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) {
  309: #else
  310: 	if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) < 0) {
  311: #endif /* _ISC */
  312: 	    sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
  313: 	    sin->sin_addr.s_addr = htonl(IN_CLASSC_NET);
  314: 	}
  315: 	sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
  316: 	len = snprintf(cp, ailen - (*addrinfo - cp),
  317: 	    "%s", inet_ntoa(sin->sin_addr));
  318: 	if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
  319: 	    warningx(_("load_interfaces: overflow detected"));
  320: 	    goto done;
  321: 	}
  322: 	cp += len;
  323: 	num_interfaces++;
  324:     }
  325: 
  326: done:
  327:     efree(ifconf_buf);
  328:     (void) close(sock);
  329: 
  330:     return num_interfaces;
  331: }
  332: 
  333: #else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */
  334: 
  335: /*
  336:  * Stub function for those without SIOCGIFCONF or getifaddrs()
  337:  */
  338: int
  339: get_net_ifs(char **addrinfo)
  340: {
  341:     return 0;
  342: }
  343: 
  344: #endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */

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