#include "krb_locl.h"

RCSID("$Id: getaddrs.c,v 1.8 1996/03/28 11:10:50 bg Exp $");

#include <sys/ioctl.h>
#include <net/if.h>

#ifdef HAVE_SYS_SOCKIO_H
#include <sys/sockio.h>
#endif /* HAVE_SYS_SOCKIO_H */

/*
 * Return number and list of all local adresses.
 */

int
k_get_all_addrs (struct in_addr **l)
{
     int fd;
     char buf[BUFSIZ];
     struct ifreq *ifr, ifreq;
     struct ifconf ifconf;
     int num, j;
     char *p;

     fd = socket(AF_INET, SOCK_DGRAM, 0);
     if (fd < 0)
	  return -1;

     ifconf.ifc_len = sizeof(buf);
     ifconf.ifc_buf = buf;
     if(ioctl(fd, SIOCGIFCONF, &ifconf) < 0)
	  return -1;
     num = ifconf.ifc_len / sizeof(struct ifreq);
     *l = malloc(num * sizeof(struct in_addr));
     if(*l == NULL) {
	  close (fd);
	  return -1;
     }

     j = 0;
     ifreq.ifr_name[0] = '\0';
     for (p = ifconf.ifc_buf; p < ifconf.ifc_buf + ifconf.ifc_len;) {
#ifdef SOCKADDR_HAS_SA_LEN
	  size_t sz;
#endif

	  ifr = (struct ifreq *)p;
#ifdef SOCKADDR_HAS_SA_LEN
	  sz = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
#endif
	  if(strncmp(ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name))) {
	       if(ioctl(fd, SIOCGIFFLAGS, ifr) < 0) {
		    close (fd);
		    return -1;
	       }
	       if (ifr->ifr_flags & IFF_UP) {
		    if(ioctl(fd, SIOCGIFADDR, ifr) < 0) {
			 close (fd);
			 return -1;
		    }
		    (*l)[j++] = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
	       }
	       ifreq = *ifr;
	  }
#ifdef SOCKADDR_HAS_SA_LEN
	  p = p + sz;
#else
	  p = p + sizeof(*ifr);
#endif
     }
     if (j != num)
	  *l = realloc (*l, j * sizeof(struct in_addr));
     close (fd);
     return j;
}
