Home | History | Annotate | Line # | Download | only in util
      1 /*	$NetBSD: inet_addr_local.c,v 1.4 2017/02/14 01:16:49 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	inet_addr_local 3
      6 /* SUMMARY
      7 /*	determine if IP address is local
      8 /* SYNOPSIS
      9 /*	#include <inet_addr_local.h>
     10 /*
     11 /*	int	inet_addr_local(addr_list, mask_list, addr_family_list)
     12 /*	INET_ADDR_LIST *addr_list;
     13 /*	INET_ADDR_LIST *mask_list;
     14 /*	unsigned *addr_family;
     15 /* DESCRIPTION
     16 /*	inet_addr_local() determines all active IP interface addresses
     17 /*	of the local system. Any address found is appended to the
     18 /*	specified address list. The result value is the number of
     19 /*	active interfaces found.
     20 /*
     21 /*	The mask_list is either a null pointer, or it is a list that
     22 /*	receives the netmasks of the interface addresses that were found.
     23 /*
     24 /*	The addr_family_list specifies one or more of AF_INET or AF_INET6.
     25 /* DIAGNOSTICS
     26 /*	Fatal errors: out of memory.
     27 /* SEE ALSO
     28 /*	inet_addr_list(3) address list management
     29 /* LICENSE
     30 /* .ad
     31 /* .fi
     32 /*	The Secure Mailer license must be distributed with this software.
     33 /* AUTHOR(S)
     34 /*	Wietse Venema
     35 /*	IBM T.J. Watson Research
     36 /*	P.O. Box 704
     37 /*	Yorktown Heights, NY 10598, USA
     38 /*
     39 /*	Dean C. Strik
     40 /*	Department ICT
     41 /*	Eindhoven University of Technology
     42 /*	P.O. Box 513
     43 /*	5600 MB  Eindhoven, Netherlands
     44 /*	E-mail: <dean (at) ipnet6.org>
     45 /*--*/
     46 
     47 /* System library. */
     48 
     49 #include <sys_defs.h>
     50 #include <sys/socket.h>
     51 #include <sys/time.h>
     52 #include <netinet/in.h>
     53 #include <net/if.h>
     54 #include <sys/ioctl.h>
     55 #include <arpa/inet.h>
     56 #include <unistd.h>
     57 #ifdef USE_SYS_SOCKIO_H
     58 #include <sys/sockio.h>
     59 #endif
     60 #include <errno.h>
     61 #include <string.h>
     62 #ifdef HAS_IPV6				/* Linux only? */
     63 #include <netdb.h>
     64 #include <stdio.h>
     65 #endif
     66 #ifdef HAVE_GETIFADDRS
     67 #include <ifaddrs.h>
     68 #endif
     69 
     70 /* Utility library. */
     71 
     72 #include <msg.h>
     73 #include <mymalloc.h>
     74 #include <vstring.h>
     75 #include <inet_addr_list.h>
     76 #include <inet_addr_local.h>
     77 #include <myaddrinfo.h>
     78 #include <sock_addr.h>
     79 #include <mask_addr.h>
     80 #include <hex_code.h>
     81 
     82  /*
     83   * Postfix needs its own interface address information to determine whether
     84   * or not it is an MX host for some destination; without this information,
     85   * mail would loop between MX hosts. Postfix also needs its interface
     86   * addresses to figure out whether or not it is final destination for
     87   * addresses of the form username@[ipaddress].
     88   *
     89   * Postfix needs its own interface netmask information when no explicit
     90   * mynetworks setting is given in main.cf, and "mynetworks_style = subnet".
     91   * The mynetworks parameter controls, among others, what mail clients are
     92   * allowed to relay mail through Postfix.
     93   *
     94   * Different systems have different ways to find out this information. We will
     95   * therefore use OS dependent methods. An overview:
     96   *
     97   * - Use getifaddrs() when available.  This supports both IPv4/IPv6 addresses.
     98   * The implementation however is not present in all major operating systems.
     99   *
    100   * - Use SIOCGLIFCONF when available. This supports both IPv4/IPv6 addresses.
    101   * With SIOCGLIFNETMASK we can obtain the netmask for either address family.
    102   * Again, this is not present in all major operating systems.
    103   *
    104   * - On Linux, glibc's getifaddrs(3) has returned IPv4 information for some
    105   * time, but IPv6 information was not returned until 2.3.3. With older Linux
    106   * versions we get IPv4 interface information with SIOCGIFCONF, and read
    107   * IPv6 address/prefix information from a file in the /proc filesystem.
    108   *
    109   * - On other systems we expect SIOCGIFCONF to return IPv6 addresses. Since
    110   * SIOCGIFNETMASK does not work reliably for IPv6 addresses, we always set
    111   * the prefix length to /128 (host), and expect the user to configure a more
    112   * appropriate mynetworks setting if needed.
    113   *
    114   * XXX: Each lookup method is implemented by its own function, so we duplicate
    115   * some code. In this case, I think this is better than really drowning in
    116   * the #ifdefs...
    117   *
    118   * -- Dean Strik (dcs)
    119   */
    120 
    121 #ifndef HAVE_GETIFADDRS
    122 
    123 /* ial_socket - make socket for ioctl() operations */
    124 
    125 static int ial_socket(int af)
    126 {
    127     const char *myname = "inet_addr_local[socket]";
    128     int     sock;
    129 
    130     /*
    131      * The host may not be actually configured with IPv6. When IPv6 support
    132      * is not actually in the kernel, don't consider failure to create an
    133      * IPv6 socket as fatal. This could be tuned better though. For other
    134      * families, the error is fatal.
    135      *
    136      * XXX Now that Postfix controls protocol support centrally with the
    137      * inet_proto(3) module, this workaround should no longer be needed.
    138      */
    139     if ((sock = socket(af, SOCK_DGRAM, 0)) < 0) {
    140 #ifdef HAS_IPV6
    141 	if (af == AF_INET6) {
    142 	    if (msg_verbose)
    143 		msg_warn("%s: socket: %m", myname);
    144 	    return (-1);
    145 	}
    146 #endif
    147 	msg_fatal("%s: socket: %m", myname);
    148     }
    149     return (sock);
    150 }
    151 
    152 #endif
    153 
    154 #ifdef HAVE_GETIFADDRS
    155 
    156 /*
    157  * The getifaddrs(3) function, introduced by BSD/OS, provides a
    158  * platform-independent way of requesting interface addresses,
    159  * including IPv6 addresses. The implementation however is not
    160  * present in all major operating systems.
    161  */
    162 
    163 /* ial_getifaddrs - determine IP addresses using getifaddrs(3) */
    164 
    165 static int ial_getifaddrs(INET_ADDR_LIST *addr_list,
    166 			          INET_ADDR_LIST *mask_list,
    167 			          int af)
    168 {
    169     const char *myname = "inet_addr_local[getifaddrs]";
    170     struct ifaddrs *ifap, *ifa;
    171     struct sockaddr *sa, *sam;
    172 
    173     if (getifaddrs(&ifap) < 0)
    174 	msg_fatal("%s: getifaddrs: %m", myname);
    175 
    176     /*
    177      * Get the address of each IP network interface. According to BIND we
    178      * must include interfaces that are down because the machine may still
    179      * receive packets for that address (yes, via some other interface).
    180      * Having no way to verify this claim on every machine, I will give them
    181      * the benefit of the doubt.
    182      *
    183      * FIX 200501: The IPv6 patch did not report NetBSD loopback interfaces;
    184      * fixed by replacing IFF_RUNNING by IFF_UP.
    185      *
    186      * FIX 200501: The IPV6 patch did not skip wild-card interface addresses
    187      * (tested on FreeBSD).
    188      */
    189     for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
    190 	if (!(ifa->ifa_flags & IFF_UP) || ifa->ifa_addr == 0)
    191 	    continue;
    192 	sa = ifa->ifa_addr;
    193 	if (af != AF_UNSPEC && sa->sa_family != af)
    194 	    continue;
    195 	sam = ifa->ifa_netmask;
    196 	if (sam == 0) {
    197 	    /* XXX In mynetworks, a null netmask would match everyone. */
    198 	    msg_warn("ignoring interface with null netmask, address family %d",
    199 		     sa->sa_family);
    200 	    continue;
    201 	}
    202 	switch (sa->sa_family) {
    203 	case AF_INET:
    204 	    if (SOCK_ADDR_IN_ADDR(sa).s_addr == INADDR_ANY)
    205 		continue;
    206 	    break;
    207 #ifdef HAS_IPV6
    208 	case AF_INET6:
    209 	    if (IN6_IS_ADDR_UNSPECIFIED(&SOCK_ADDR_IN6_ADDR(sa)))
    210 		continue;
    211 	    break;
    212 #endif
    213 	default:
    214 	    continue;
    215 	}
    216 
    217 	inet_addr_list_append(addr_list, sa);
    218 	if (mask_list != 0) {
    219 
    220 	    /*
    221 	     * Unfortunately, sa_len/sa_family may be broken in the netmask
    222 	     * sockaddr structure. We must fix this manually to have correct
    223 	     * addresses.   --dcs
    224 	     */
    225 #ifdef HAS_SA_LEN
    226 	    sam->sa_len = sa->sa_family == AF_INET6 ?
    227 		sizeof(struct sockaddr_in6) :
    228 		sizeof(struct sockaddr_in);
    229 #endif
    230 	    sam->sa_family = sa->sa_family;
    231 	    inet_addr_list_append(mask_list, sam);
    232 	}
    233     }
    234     freeifaddrs(ifap);
    235     return (0);
    236 }
    237 
    238 #elif defined(HAS_SIOCGLIF)		/* HAVE_GETIFADDRS */
    239 
    240 /*
    241  * The SIOCLIF* ioctls are the successors of SIOCGIF* on the Solaris
    242  * and HP/UX operating systems. The data is stored in sockaddr_storage
    243  * structure. Both IPv4 and IPv6 addresses are returned though these
    244  * calls.
    245  */
    246 #define NEXT_INTERFACE(lifr)	(lifr + 1)
    247 #define LIFREQ_SIZE(lifr)	sizeof(lifr[0])
    248 
    249 /* ial_siocglif - determine IP addresses using ioctl(SIOCGLIF*) */
    250 
    251 static int ial_siocglif(INET_ADDR_LIST *addr_list,
    252 			        INET_ADDR_LIST *mask_list,
    253 			        int af)
    254 {
    255     const char *myname = "inet_addr_local[siocglif]";
    256     struct lifconf lifc;
    257     struct lifreq *lifr;
    258     struct lifreq *lifr_mask;
    259     struct lifreq *the_end;
    260     struct sockaddr *sa;
    261     int     sock;
    262     VSTRING *buf;
    263 
    264     /*
    265      * See also comments in ial_siocgif()
    266      */
    267     if (af != AF_INET && af != AF_INET6)
    268 	msg_fatal("%s: address family was %d, must be AF_INET (%d) or "
    269 		  "AF_INET6 (%d)", myname, af, AF_INET, AF_INET6);
    270     sock = ial_socket(af);
    271     if (sock < 0)
    272 	return (0);
    273     buf = vstring_alloc(1024);
    274     for (;;) {
    275 	memset(&lifc, 0, sizeof(lifc));
    276 	lifc.lifc_family = AF_UNSPEC;		/* XXX Why??? */
    277 	lifc.lifc_len = vstring_avail(buf);
    278 	lifc.lifc_buf = vstring_str(buf);
    279 	if (ioctl(sock, SIOCGLIFCONF, (char *) &lifc) < 0) {
    280 	    if (errno != EINVAL)
    281 		msg_fatal("%s: ioctl SIOCGLIFCONF: %m", myname);
    282 	} else if (lifc.lifc_len < vstring_avail(buf) / 2)
    283 	    break;
    284 	VSTRING_SPACE(buf, vstring_avail(buf) * 2);
    285     }
    286 
    287     the_end = (struct lifreq *) (lifc.lifc_buf + lifc.lifc_len);
    288     for (lifr = lifc.lifc_req; lifr < the_end;) {
    289 	sa = (struct sockaddr *) &lifr->lifr_addr;
    290 	if (sa->sa_family != af) {
    291 	    lifr = NEXT_INTERFACE(lifr);
    292 	    continue;
    293 	}
    294 	if (af == AF_INET) {
    295 	    if (SOCK_ADDR_IN_ADDR(sa).s_addr == INADDR_ANY) {
    296 		lifr = NEXT_INTERFACE(lifr);
    297 		continue;
    298 	    }
    299 	}
    300 #ifdef HAS_IPV6
    301 	else if (af == AF_INET6) {
    302 	    if (IN6_IS_ADDR_UNSPECIFIED(&SOCK_ADDR_IN6_ADDR(sa))) {
    303 		lifr = NEXT_INTERFACE(lifr);
    304 		continue;
    305 	    }
    306 	}
    307 #endif
    308 	inet_addr_list_append(addr_list, sa);
    309 	if (mask_list) {
    310 	    lifr_mask = (struct lifreq *) mymalloc(sizeof(struct lifreq));
    311 	    memcpy((void *) lifr_mask, (void *) lifr, sizeof(struct lifreq));
    312 	    if (ioctl(sock, SIOCGLIFNETMASK, lifr_mask) < 0)
    313 		msg_fatal("%s: ioctl(SIOCGLIFNETMASK): %m", myname);
    314 	    /* XXX: Check whether sa_len/family are honoured --dcs */
    315 	    inet_addr_list_append(mask_list,
    316 				  (struct sockaddr *) &lifr_mask->lifr_addr);
    317 	    myfree((void *) lifr_mask);
    318 	}
    319 	lifr = NEXT_INTERFACE(lifr);
    320     }
    321     vstring_free(buf);
    322     (void) close(sock);
    323     return (0);
    324 }
    325 
    326 #else					/* HAVE_SIOCGLIF */
    327 
    328 /*
    329  * The classic SIOCGIF* ioctls. Modern BSD operating systems will
    330  * also return IPv6 addresses through these structure. Note however
    331  * that recent versions of these operating systems have getifaddrs.
    332  */
    333 #if defined(_SIZEOF_ADDR_IFREQ)
    334 #define NEXT_INTERFACE(ifr)	((struct ifreq *) \
    335 	((char *) ifr + _SIZEOF_ADDR_IFREQ(*ifr)))
    336 #define IFREQ_SIZE(ifr)	_SIZEOF_ADDR_IFREQ(*ifr)
    337 #elif defined(HAS_SA_LEN)
    338 #define NEXT_INTERFACE(ifr)	((struct ifreq *) \
    339 	((char *) ifr + sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len))
    340 #define IFREQ_SIZE(ifr)	(sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len)
    341 #else
    342 #define NEXT_INTERFACE(ifr)	(ifr + 1)
    343 #define IFREQ_SIZE(ifr)	sizeof(ifr[0])
    344 #endif
    345 
    346 /* ial_siocgif - determine IP addresses using ioctl(SIOCGIF*) */
    347 
    348 static int ial_siocgif(INET_ADDR_LIST *addr_list,
    349 		               INET_ADDR_LIST *mask_list,
    350 		               int af)
    351 {
    352     const char *myname = "inet_addr_local[siocgif]";
    353     struct in_addr addr;
    354     struct ifconf ifc;
    355     struct ifreq *ifr;
    356     struct ifreq *ifr_mask;
    357     struct ifreq *the_end;
    358     int     sock;
    359     VSTRING *buf;
    360 
    361     /*
    362      * Get the network interface list. XXX The socket API appears to have no
    363      * function that returns the number of network interfaces, so we have to
    364      * guess how much space is needed to store the result.
    365      *
    366      * On BSD-derived systems, ioctl SIOCGIFCONF returns as much information as
    367      * possible, leaving it up to the application to repeat the request with
    368      * a larger buffer if the result caused a tight fit.
    369      *
    370      * Other systems, such as Solaris 2.5, generate an EINVAL error when the
    371      * buffer is too small for the entire result. Workaround: ignore EINVAL
    372      * errors and repeat the request with a larger buffer. The downside is
    373      * that the program can run out of memory due to a non-memory problem,
    374      * making it more difficult than necessary to diagnose the real problem.
    375      */
    376     sock = ial_socket(af);
    377     if (sock < 0)
    378 	return (0);
    379     buf = vstring_alloc(1024);
    380     for (;;) {
    381 	ifc.ifc_len = vstring_avail(buf);
    382 	ifc.ifc_buf = vstring_str(buf);
    383 	if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) < 0) {
    384 	    if (errno != EINVAL)
    385 		msg_fatal("%s: ioctl SIOCGIFCONF: %m", myname);
    386 	} else if (ifc.ifc_len < vstring_avail(buf) / 2)
    387 	    break;
    388 	VSTRING_SPACE(buf, vstring_avail(buf) * 2);
    389     }
    390 
    391     the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
    392     for (ifr = ifc.ifc_req; ifr < the_end;) {
    393 	if (ifr->ifr_addr.sa_family != af) {
    394 	    ifr = NEXT_INTERFACE(ifr);
    395 	    continue;
    396 	}
    397 	if (af == AF_INET) {
    398 	    addr = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr;
    399 	    if (addr.s_addr != INADDR_ANY) {
    400 		inet_addr_list_append(addr_list, &ifr->ifr_addr);
    401 		if (mask_list) {
    402 		    ifr_mask = (struct ifreq *) mymalloc(IFREQ_SIZE(ifr));
    403 		    memcpy((void *) ifr_mask, (void *) ifr, IFREQ_SIZE(ifr));
    404 		    if (ioctl(sock, SIOCGIFNETMASK, ifr_mask) < 0)
    405 			msg_fatal("%s: ioctl SIOCGIFNETMASK: %m", myname);
    406 
    407 		    /*
    408 		     * Note that this SIOCGIFNETMASK has truly screwed up the
    409 		     * contents of sa_len/sa_family. We must fix this
    410 		     * manually to have correct addresses.   --dcs
    411 		     */
    412 		    ifr_mask->ifr_addr.sa_family = af;
    413 #ifdef HAS_SA_LEN
    414 		    ifr_mask->ifr_addr.sa_len = sizeof(struct sockaddr_in);
    415 #endif
    416 		    inet_addr_list_append(mask_list, &ifr_mask->ifr_addr);
    417 		    myfree((void *) ifr_mask);
    418 		}
    419 	    }
    420 	}
    421 #ifdef HAS_IPV6
    422 	else if (af == AF_INET6) {
    423 	    struct sockaddr *sa;
    424 
    425 	    sa = SOCK_ADDR_PTR(&ifr->ifr_addr);
    426 	    if (!(IN6_IS_ADDR_UNSPECIFIED(&SOCK_ADDR_IN6_ADDR(sa)))) {
    427 		inet_addr_list_append(addr_list, sa);
    428 		if (mask_list) {
    429 		    /* XXX Assume /128 for everything */
    430 		    struct sockaddr_in6 mask6;
    431 
    432 		    mask6 = *SOCK_ADDR_IN6_PTR(sa);
    433 		    memset((void *) &mask6.sin6_addr, ~0,
    434 			   sizeof(mask6.sin6_addr));
    435 		    inet_addr_list_append(mask_list, SOCK_ADDR_PTR(&mask6));
    436 		}
    437 	    }
    438 	}
    439 #endif
    440 	ifr = NEXT_INTERFACE(ifr);
    441     }
    442     vstring_free(buf);
    443     (void) close(sock);
    444     return (0);
    445 }
    446 
    447 #endif					/* HAVE_SIOCGLIF */
    448 
    449 #ifdef HAS_PROCNET_IFINET6
    450 
    451 /*
    452  * Older Linux versions lack proper calls to retrieve IPv6 interface
    453  * addresses. Instead, the addresses can be read from a file in the
    454  * /proc tree. The most important issue with this approach however
    455  * is that the /proc tree may not always be available, for example
    456  * in a chrooted environment or in "hardened" (sic) installations.
    457  */
    458 
    459 /* ial_procnet_ifinet6 - determine IPv6 addresses using /proc/net/if_inet6 */
    460 
    461 static int ial_procnet_ifinet6(INET_ADDR_LIST *addr_list,
    462 			               INET_ADDR_LIST *mask_list)
    463 {
    464     const char *myname = "inet_addr_local[procnet_ifinet6]";
    465     FILE   *fp;
    466     char    buf[BUFSIZ];
    467     unsigned plen;
    468     VSTRING *addrbuf;
    469     struct sockaddr_in6 addr;
    470     struct sockaddr_in6 mask;
    471 
    472     /*
    473      * Example: 00000000000000000000000000000001 01 80 10 80 lo
    474      *
    475      * Fields: address, interface index, prefix length, scope value
    476      * (net/ipv6.h), interface flags (linux/rtnetlink.h), device name.
    477      *
    478      * FIX 200501 The IPv6 patch used fscanf(), which will hang on unexpected
    479      * input. Use fgets() + sscanf() instead.
    480      */
    481     if ((fp = fopen(_PATH_PROCNET_IFINET6, "r")) != 0) {
    482 	addrbuf = vstring_alloc(MAI_V6ADDR_BYTES + 1);
    483 	memset((void *) &addr, 0, sizeof(addr));
    484 	addr.sin6_family = AF_INET6;
    485 #ifdef HAS_SA_LEN
    486 	addr.sin6_len = sizeof(addr);
    487 #endif
    488 	mask = addr;
    489 	while (fgets(buf, sizeof(buf), fp) != 0) {
    490 	    /* 200501 hex_decode() is light-weight compared to getaddrinfo(). */
    491 	    if (hex_decode(addrbuf, buf, MAI_V6ADDR_BYTES * 2) == 0
    492 		|| sscanf(buf + MAI_V6ADDR_BYTES * 2, " %*x %x", &plen) != 1
    493 		|| plen > MAI_V6ADDR_BITS) {
    494 		msg_warn("unexpected data in %s - skipping IPv6 configuration",
    495 			 _PATH_PROCNET_IFINET6);
    496 		break;
    497 	    }
    498 	    /* vstring_str(addrbuf) has worst-case alignment. */
    499 	    addr.sin6_addr = *(struct in6_addr *) vstring_str(addrbuf);
    500 	    inet_addr_list_append(addr_list, SOCK_ADDR_PTR(&addr));
    501 
    502 	    memset((void *) &mask.sin6_addr, ~0, sizeof(mask.sin6_addr));
    503 	    mask_addr((unsigned char *) &mask.sin6_addr,
    504 		      sizeof(mask.sin6_addr), plen);
    505 	    inet_addr_list_append(mask_list, SOCK_ADDR_PTR(&mask));
    506 	}
    507 	vstring_free(addrbuf);
    508 	fclose(fp);				/* FIX 200501 */
    509     } else {
    510 	msg_warn("can't open %s (%m) - skipping IPv6 configuration",
    511 		 _PATH_PROCNET_IFINET6);
    512     }
    513     return (0);
    514 }
    515 
    516 #endif					/* HAS_PROCNET_IFINET6 */
    517 
    518 /* inet_addr_local - find all IP addresses for this host */
    519 
    520 int     inet_addr_local(INET_ADDR_LIST *addr_list, INET_ADDR_LIST *mask_list,
    521 			        unsigned *addr_family_list)
    522 {
    523     const char *myname = "inet_addr_local";
    524     int     initial_count = addr_list->used;
    525     unsigned family;
    526     int     count;
    527 
    528     while ((family = *addr_family_list++) != 0) {
    529 
    530 	/*
    531 	 * IP Version 4
    532 	 */
    533 	if (family == AF_INET) {
    534 	    count = addr_list->used;
    535 #if defined(HAVE_GETIFADDRS)
    536 	    ial_getifaddrs(addr_list, mask_list, AF_INET);
    537 #elif defined (HAS_SIOCGLIF)
    538 	    ial_siocglif(addr_list, mask_list, AF_INET);
    539 #else
    540 	    ial_siocgif(addr_list, mask_list, AF_INET);
    541 #endif
    542 	    if (msg_verbose)
    543 		msg_info("%s: configured %d IPv4 addresses",
    544 			 myname, addr_list->used - count);
    545 	}
    546 
    547 	/*
    548 	 * IP Version 6
    549 	 */
    550 #ifdef HAS_IPV6
    551 	else if (family == AF_INET6) {
    552 	    count = addr_list->used;
    553 #if defined(HAVE_GETIFADDRS)
    554 	    ial_getifaddrs(addr_list, mask_list, AF_INET6);
    555 #elif defined(HAS_PROCNET_IFINET6)
    556 	    ial_procnet_ifinet6(addr_list, mask_list);
    557 #elif defined(HAS_SIOCGLIF)
    558 	    ial_siocglif(addr_list, mask_list, AF_INET6);
    559 #else
    560 	    ial_siocgif(addr_list, mask_list, AF_INET6);
    561 #endif
    562 	    if (msg_verbose)
    563 		msg_info("%s: configured %d IPv6 addresses", myname,
    564 			 addr_list->used - count);
    565 	}
    566 #endif
    567 
    568 	/*
    569 	 * Something's not right.
    570 	 */
    571 	else
    572 	    msg_panic("%s: unknown address family %d", myname, family);
    573     }
    574     return (addr_list->used - initial_count);
    575 }
    576 
    577 #ifdef TEST
    578 
    579 #include <string.h>
    580 #include <vstream.h>
    581 #include <msg_vstream.h>
    582 #include <inet_proto.h>
    583 
    584 int     main(int unused_argc, char **argv)
    585 {
    586     INET_ADDR_LIST addr_list;
    587     INET_ADDR_LIST mask_list;
    588     MAI_HOSTADDR_STR hostaddr;
    589     MAI_HOSTADDR_STR hostmask;
    590     struct sockaddr *sa;
    591     int     i;
    592     INET_PROTO_INFO *proto_info;
    593 
    594     msg_vstream_init(argv[0], VSTREAM_ERR);
    595     msg_verbose = 1;
    596 
    597     proto_info = inet_proto_init(argv[0],
    598 				 argv[1] ? argv[1] : INET_PROTO_NAME_ALL);
    599     inet_addr_list_init(&addr_list);
    600     inet_addr_list_init(&mask_list);
    601     inet_addr_local(&addr_list, &mask_list, proto_info->ai_family_list);
    602 
    603     if (addr_list.used == 0)
    604 	msg_fatal("cannot find any active network interfaces");
    605 
    606     if (addr_list.used == 1)
    607 	msg_warn("found only one active network interface");
    608 
    609     for (i = 0; i < addr_list.used; i++) {
    610 	sa = SOCK_ADDR_PTR(addr_list.addrs + i);
    611 	SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
    612 			     &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
    613 	sa = SOCK_ADDR_PTR(mask_list.addrs + i);
    614 	SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
    615 			     &hostmask, (MAI_SERVPORT_STR *) 0, 0);
    616 	vstream_printf("%s/%s\n", hostaddr.buf, hostmask.buf);
    617 	vstream_fflush(VSTREAM_OUT);
    618     }
    619     inet_addr_list_free(&addr_list);
    620     inet_addr_list_free(&mask_list);
    621     return (0);
    622 }
    623 
    624 #endif
    625