#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <net/if.h>
#ifdef AUTOCONF_TEST
struct iface_struct {
char name[16];
struct in_addr ip;
struct in_addr netmask;
};
#else
#include "config.h"
#include "interfaces.h"
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifndef SIOCGIFCONF
#ifdef HAVE_SYS_SOCKIO_H
#include <sys/sockio.h>
#endif
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#ifdef __COMPAR_FN_T
#define QSORT_CAST (__compar_fn_t)
#endif
#ifndef QSORT_CAST
#define QSORT_CAST (int (*)(const void *, const void *))
#endif
#if HAVE_IFACE_IFCONF
static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
{
struct ifconf ifc;
char buff[8192];
int fd, i, n;
struct ifreq *ifr=NULL;
int total = 0;
struct in_addr ipaddr;
struct in_addr nmask;
char *iname;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
return -1;
}
ifc.ifc_len = sizeof(buff);
ifc.ifc_buf = buff;
if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
close(fd);
return -1;
}
ifr = ifc.ifc_req;
n = ifc.ifc_len / sizeof(struct ifreq);
for (i=n-1;i>=0 && total < max_interfaces;i--) {
if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
continue;
}
iname = ifr[i].ifr_name;
ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr;
if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
continue;
}
if (!(ifr[i].ifr_flags & IFF_UP)) {
continue;
}
if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
continue;
}
nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr;
strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
ifaces[total].ip = ipaddr;
ifaces[total].netmask = nmask;
total++;
}
close(fd);
return total;
}
#elif HAVE_IFACE_IFREQ
#ifndef I_STR
#include <sys/stropts.h>
#endif
static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
{
struct ifreq ifreq;
struct strioctl strioctl;
char buff[8192];
int fd, i, n;
struct ifreq *ifr=NULL;
int total = 0;
struct in_addr ipaddr;
struct in_addr nmask;
char *iname;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
return -1;
}
strioctl.ic_cmd = SIOCGIFCONF;
strioctl.ic_dp = buff;
strioctl.ic_len = sizeof(buff);
if (ioctl(fd, I_STR, &strioctl) < 0) {
close(fd);
return -1;
}
n = strioctl.ic_len / sizeof(struct ifreq);
if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
ifr = (struct ifreq *)(buff + sizeof(int));
} else {
ifr = (struct ifreq *)buff;
}
for (i = 0; i<n && total < max_interfaces; i++) {
ifreq = ifr[i];
strioctl.ic_cmd = SIOCGIFFLAGS;
strioctl.ic_dp = (char *)&ifreq;
strioctl.ic_len = sizeof(struct ifreq);
if (ioctl(fd, I_STR, &strioctl) != 0) {
continue;
}
if (!(ifreq.ifr_flags & IFF_UP)) {
continue;
}
strioctl.ic_cmd = SIOCGIFADDR;
strioctl.ic_dp = (char *)&ifreq;
strioctl.ic_len = sizeof(struct ifreq);
if (ioctl(fd, I_STR, &strioctl) != 0) {
continue;
}
ipaddr = (*(struct sockaddr_in *) &ifreq.ifr_addr).sin_addr;
iname = ifreq.ifr_name;
strioctl.ic_cmd = SIOCGIFNETMASK;
strioctl.ic_dp = (char *)&ifreq;
strioctl.ic_len = sizeof(struct ifreq);
if (ioctl(fd, I_STR, &strioctl) != 0) {
continue;
}
nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
ifaces[total].ip = ipaddr;
ifaces[total].netmask = nmask;
total++;
}
close(fd);
return total;
}
#elif HAVE_IFACE_AIX
static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
{
char buff[8192];
int fd, i;
struct ifconf ifc;
struct ifreq *ifr=NULL;
struct in_addr ipaddr;
struct in_addr nmask;
char *iname;
int total = 0;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
return -1;
}
ifc.ifc_len = sizeof(buff);
ifc.ifc_buf = buff;
if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
close(fd);
return -1;
}
ifr = ifc.ifc_req;
i = ifc.ifc_len;
while (i > 0 && total < max_interfaces) {
unsigned inc;
inc = ifr->ifr_addr.sa_len;
if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
goto next;
}
ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
iname = ifr->ifr_name;
if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
goto next;
}
if (!(ifr->ifr_flags & IFF_UP)) {
goto next;
}
if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
goto next;
}
nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
ifaces[total].ip = ipaddr;
ifaces[total].netmask = nmask;
total++;
next:
if (inc < sizeof(ifr->ifr_addr))
inc = sizeof(ifr->ifr_addr);
inc += IFNAMSIZ;
ifr = (struct ifreq*) (((char*) ifr) + inc);
i -= inc;
}
close(fd);
return total;
}
#else
static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
{
return -1;
}
#endif
static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
{
int r;
r = strcmp(i1->name, i2->name);
if (r) return r;
r = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr);
if (r) return r;
r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr);
return r;
}
int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
{
int total, i, j;
total = _get_interfaces(ifaces, max_interfaces);
if (total <= 0) return total;
qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
for (i=1;i<total;) {
if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
for (j=i-1;j<total-1;j++) {
ifaces[j] = ifaces[j+1];
}
total--;
} else {
i++;
}
}
return total;
}
#ifdef AUTOCONF_TEST
#define MAX_INTERFACES 128
int main()
{
struct iface_struct ifaces[MAX_INTERFACES];
int total = get_interfaces(ifaces, MAX_INTERFACES);
int i;
printf("got %d interfaces:\n", total);
if (total <= 0) exit(1);
for (i=0;i<total;i++) {
printf("%-10s ", ifaces[i].name);
printf("IP=%s ", inet_ntoa(ifaces[i].ip));
printf("NETMASK=%s\n", inet_ntoa(ifaces[i].netmask));
}
return 0;
}
#endif