#include <stdio.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#if OS_FREEBSD
#   include <stdlib.h>
#else
#   include <malloc.h>
#endif

#if __linux__
#   include <linux/if.h>
#   include <linux/in.h>
#endif

struct in_addr *
local_if_list()
{
    /* need to worry about endian issues! */
    static struct in_addr localhost[2] = { 0x0100007f, 0 };

#if __linux__
    struct in_addr *res = 0;
    int szres = 0,
	maxres= 0;

    char bfr[1024];
    int left;
    int eth = socket(AF_INET, SOCK_DGRAM, 0);
    struct ifconf ask;
    struct ifreq *dev;
    struct in_addr ip;

    ask.ifc_buf = bfr;
    ask.ifc_len = sizeof bfr;

    if (ioctl(eth, SIOCGIFCONF, &ask) != -1) {
	dev = (struct ifreq*) ask.ifc_req;
	left = ask.ifc_len / sizeof *dev;

	for (; left-- > 0; dev++) {
	    struct ifreq cur;

	    strcpy(cur.ifr_name, dev->ifr_name);
	    if (ioctl(eth, SIOCGIFADDR, &cur) == -1)
		continue;

	    if (strcmp(dev->ifr_name, "lo") == 0) {
		unsigned int *p = (int*) &(dev->ifr_addr);

		ip = *(struct in_addr*)(p+1);
	    }
	    else if (cur.ifr_addr.sa_family == AF_INET) { 
		struct sockaddr_in *p = (struct sockaddr_in*)&cur.ifr_addr;

		ip = p->sin_addr;
	    }
	    else
		continue;

	    if ( (szres + 2) >= maxres ) {
		maxres += 10;
		res = res ? realloc(res, maxres*sizeof(ip))
			  : malloc(maxres*sizeof(ip));
	    }
	    if (res == 0)
		break;

	    res[szres++] = ip;
	}
    }
    close(eth);

    if (res) {
	res[szres].s_addr = 0;
	return res;
    }

#endif

    return &localhost;
}


#ifdef DEBUG
main()
{
    struct in_addr *ip = local_if_list();

    for (; ip->s_addr; ip++)
	puts(inet_ntoa(*ip));
}
#endif
