#include <sys_defs.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <unistd.h>
#ifdef USE_SYS_SOCKIO_H
#include <sys/sockio.h>
#endif
#include <errno.h>
#include <string.h>
#include <msg.h>
#include <mymalloc.h>
#include <vstring.h>
#include <inet_addr_list.h>
#include <inet_addr_local.h>
#ifdef _SIZEOF_ADDR_IFREQ
#define NEXT_INTERFACE(ifr) ((struct ifreq *) \
((char *) ifr + _SIZEOF_ADDR_IFREQ(*ifr)))
#define IFREQ_SIZE(ifr) _SIZEOF_ADDR_IFREQ(*ifr)
#else
#ifdef HAS_SA_LEN
#define NEXT_INTERFACE(ifr) ((struct ifreq *) \
((char *) ifr + sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len))
#define IFREQ_SIZE(ifr) (sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len)
#else
#define NEXT_INTERFACE(ifr) (ifr + 1)
#define IFREQ_SIZE(ifr) sizeof(ifr[0])
#endif
#endif
int inet_addr_local(INET_ADDR_LIST *addr_list, INET_ADDR_LIST *mask_list)
{
char *myname = "inet_addr_local";
struct ifconf ifc;
struct ifreq *ifr;
struct ifreq *the_end;
int sock;
VSTRING *buf = vstring_alloc(1024);
int initial_count = addr_list->used;
struct in_addr addr;
struct ifreq *ifr_mask;
if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
msg_fatal("%s: socket: %m", myname);
for (;;) {
ifc.ifc_len = vstring_avail(buf);
ifc.ifc_buf = vstring_str(buf);
if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) < 0) {
if (errno != EINVAL)
msg_fatal("%s: ioctl SIOCGIFCONF: %m", myname);
} else if (ifc.ifc_len < vstring_avail(buf) / 2)
break;
VSTRING_SPACE(buf, vstring_avail(buf) * 2);
}
the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
for (ifr = ifc.ifc_req; ifr < the_end;) {
if (ifr->ifr_addr.sa_family == AF_INET) {
addr = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr;
if (addr.s_addr != INADDR_ANY) {
inet_addr_list_append(addr_list, &addr);
if (mask_list) {
ifr_mask = (struct ifreq *) mymalloc(IFREQ_SIZE(ifr));
memcpy((char *) ifr_mask, (char *) ifr, IFREQ_SIZE(ifr));
if (ioctl(sock, SIOCGIFNETMASK, ifr_mask) < 0)
msg_fatal("%s: ioctl SIOCGIFNETMASK: %m", myname);
addr = ((struct sockaddr_in *) & ifr_mask->ifr_addr)->sin_addr;
inet_addr_list_append(mask_list, &addr);
myfree((char *) ifr_mask);
}
}
}
ifr = NEXT_INTERFACE(ifr);
}
vstring_free(buf);
(void) close(sock);
return (addr_list->used - initial_count);
}
#ifdef TEST
#include <vstream.h>
#include <msg_vstream.h>
int main(int unused_argc, char **argv)
{
INET_ADDR_LIST addr_list;
INET_ADDR_LIST mask_list;
int i;
msg_vstream_init(argv[0], VSTREAM_ERR);
inet_addr_list_init(&addr_list);
inet_addr_list_init(&mask_list);
inet_addr_local(&addr_list, &mask_list);
if (addr_list.used == 0)
msg_fatal("cannot find any active network interfaces");
if (addr_list.used == 1)
msg_warn("found only one active network interface");
for (i = 0; i < addr_list.used; i++) {
vstream_printf("%s/", inet_ntoa(addr_list.addrs[i]));
vstream_printf("%s\n", inet_ntoa(mask_list.addrs[i]));
}
vstream_fflush(VSTREAM_OUT);
inet_addr_list_free(&addr_list);
inet_addr_list_free(&mask_list);
}
#endif