/* $Id: bsd-getifaddrs.c,v 1.1 2005/07/06 07:53:50 dtucker Exp $ */
/*
* A minimal getifaddrs replacement for OpenNTPD
* This only implements the components that ntpd uses (ie ifa_addr for
* INET and INET6 interfaces). It is not suitable for any other purpose.
*/
/*
* Copyright (c) 2005 Darren Tucker <dtucker at zip com au>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#ifndef HAVE_GETIFADDRS
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <errno.h>
#ifdef HAVE_SYS_SOCKIO_H
#include <sys/sockio.h>
#endif
#define MAX_INTERFACES 128
#define STEPSZ 8
# if !defined(IF_NAMESIZE) && defined(IFNAMSIZ)
# define IF_NAMESIZE IFNAMSIZ
# endif
# ifdef GETIFADDRS_VIA_SIOCGIFCONF
static void *
xrealloc(void *old, size_t size) {
if (old == NULL)
return malloc(size);
else
return realloc(old, size);
}
static void
add_interface(struct ifaddrs **ifa, struct ifreq *ifr, struct sockaddr *sa)
{
struct ifaddrs *ifa_new = NULL;
size_t sasize;
int family = ifr->ifr_addr.sa_family;
if (family != AF_INET && family != AF_INET6)
return;
sasize = SA_LEN(sa);
if ((ifa_new = malloc(sizeof(*ifa_new))) == NULL)
goto fail;
memset(ifa_new, 0, sizeof(*ifa_new));
if ((ifa_new->ifa_name = strdup(ifr->ifr_name)) == NULL)
goto fail;
if ((ifa_new->ifa_addr = malloc(sasize)) == NULL)
goto fail;
if (memcpy(ifa_new->ifa_addr, sa, sasize) == NULL)
goto fail;
ifa_new->ifa_next = *ifa;
*ifa = ifa_new;
return;
fail:
if (ifa_new->ifa_name != NULL)
free(ifa_new->ifa_name);
if (ifa_new->ifa_addr != NULL)
free(ifa_new->ifa_addr);
if (ifa_new != NULL)
free(ifa_new);
}
# endif
int
getifaddrs(struct ifaddrs **ifa)
{
# ifdef GETIFADDRS_VIA_SIOCGIFCONF
int fd, i, oldlen = 0;
size_t buflen = 0;
char *oldbuf = NULL, *buf = NULL;
struct ifconf ifc;
struct ifreq *ifr;
struct sockaddr *sa;
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
return -1;
*ifa = NULL;
/*
* We iterate until the buffer returned by the ioctl stops growing.
* Yes, this is ugly.
*/
for (i = STEPSZ; i < MAX_INTERFACES; i += STEPSZ) {
buflen = i * sizeof(struct ifreq);
oldbuf = buf;
if ((buf = xrealloc(buf, buflen)) == NULL)
goto fail;
ifc.ifc_buf = buf;
ifc.ifc_len = buflen;
if (ioctl(fd, SIOCGIFCONF, &ifc) < 0)
goto fail;
if (oldlen == ifc.ifc_len)
break;
oldlen = ifc.ifc_len;
# ifdef DEBUG_GETIFADDRS
log_info("%s: i %d len %d oldlen %d", __func__, i, buflen,
oldlen);
# endif
}
/* walk the device list, add the inet and inet6 ones to the list */
for (oldbuf = buf; buf < oldbuf + ifc.ifc_len;) {
ifr = (struct ifreq *)buf;
sa = (struct sockaddr *)&ifr->ifr_addr;
# if defined(HAVE_SOCKADDR_SA_LEN)
buf += IF_NAMESIZE + SA_LEN(sa);
# else
buf += sizeof(struct ifreq);
# endif
# ifdef DEBUG_GETIFADDRS
log_info("%s: if %s family %d", __func__, ifr->ifr_name,
ifr->ifr_addr.sa_family);
# endif
add_interface(ifa, ifr, sa);
}
return 0;
fail:
if (oldbuf != NULL)
free(oldbuf);
if (*ifa != NULL) {
freeifaddrs(*ifa);
*ifa = NULL;
}
close(fd);
return -1;
# else
fprintf(stderr, "\"listen on *\" not supported on this "
"platform, interface address required\n");
errno = ENOSYS;
return -1;
# endif
}
void
freeifaddrs(struct ifaddrs *ifap)
{
# ifdef GETIFADDRS_VIA_SIOCGIFCONF
struct ifaddrs *tmpifa = ifap;
while (ifap != NULL) {
if (ifap->ifa_name != NULL)
free(ifap->ifa_name);
if (ifap->ifa_addr != NULL)
free(ifap->ifa_addr);
tmpifa = ifap->ifa_next;
free(ifap);
ifap = tmpifa;
}
return;
# endif
}
#endif /* HAVE_GETIFADDRS */
syntax highlighted by Code2HTML, v. 0.9.1