#include <net/if.h>
#endif
+#define SOCKET_WRAPPER_NOT_REPLACE
#include "interfaces.h"
+#include "../replace/replace.h"
/****************************************************************************
- Try the "standard" getifaddrs/freeifaddrs interfaces.
- Also gets IPv6 interfaces.
+ Utility functions.
****************************************************************************/
-#if HAVE_IFACE_GETIFADDRS
/****************************************************************************
- Get the netmask address for a local interface.
+ Create a struct sockaddr_storage with the netmask bits set to 1.
****************************************************************************/
-static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
+bool make_netmask(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ unsigned long masklen)
{
- struct ifaddrs *iflist = NULL;
- struct ifaddrs *ifptr = NULL;
- int total = 0;
- size_t copy_size;
-
- if (getifaddrs(&iflist) < 0) {
- return -1;
- }
-
- /* Loop through interfaces, looking for given IP address */
- for (ifptr = iflist, total = 0;
- ifptr != NULL && total < max_interfaces;
- ifptr = ifptr->ifa_next) {
-
- memset(&ifaces[total], '\0', sizeof(ifaces[total]));
-
- copy_size = sizeof(struct sockaddr_in);
-
- if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
- continue;
+ *pss_out = *pss_in;
+ /* Now apply masklen bits of mask. */
+#if defined(HAVE_IPV6)
+ if (pss_in->ss_family == AF_INET6) {
+ char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
+ unsigned int i;
+
+ if (masklen > 128) {
+ return false;
}
-
- ifaces[total].flags = ifptr->ifa_flags;
-
- /* Check the interface is up. */
- if (!(ifaces[total].flags & IFF_UP)) {
- continue;
+ for (i = 0; masklen >= 8; masklen -= 8, i++) {
+ *p++ = 0xff;
}
-
-#ifdef AF_INET6
- if (ifptr->ifa_addr->sa_family == AF_INET6) {
- copy_size = sizeof(struct sockaddr_in6);
+ /* Deal with the partial byte. */
+ *p++ &= (0xff & ~(0xff>>masklen));
+ i++;
+ for (;i < sizeof(struct in6_addr); i++) {
+ *p++ = '\0';
}
+ return true;
+ }
#endif
-
- memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size);
- memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size);
-
- if ((ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) &&
- ifptr->ifa_broadaddr) {
- memcpy(&ifaces[total].bcast,
- ifptr->ifa_broadaddr,
- copy_size);
- } else if ((ifaces[total].flags & IFF_POINTOPOINT) &&
- ifptr->ifa_dstaddr ) {
- memcpy(&ifaces[total].bcast,
- ifptr->ifa_dstaddr,
- copy_size);
- } else {
- continue;
+ if (pss_in->ss_family == AF_INET) {
+ if (masklen > 32) {
+ return false;
}
-
- strncpy(ifaces[total].name, ifptr->ifa_name,
- sizeof(ifaces[total].name)-1);
- ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
- total++;
+ ((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
+ htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
+ return true;
}
-
- freeifaddrs(iflist);
-
- return total;
+ return false;
}
-#define _FOUND_IFACE_ANY
-#endif /* HAVE_IFACE_GETIFADDRS */
-#if HAVE_IFACE_IFCONF
-
-/* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
- V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
-
- It probably also works on any BSD style system. */
-
/****************************************************************************
- Get the netmask address for a local interface.
+ Create a struct sockaddr_storage set to the broadcast or network adress from
+ an incoming sockaddr_storage.
****************************************************************************/
-static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
+static void make_bcast_or_net(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ const struct sockaddr_storage *nmask,
+ bool make_bcast_p)
{
- struct ifconf ifc;
- char buff[8192];
- int fd, i, n;
- struct ifreq *ifr=NULL;
- int total = 0;
-
- if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
- return -1;
+ unsigned int i = 0, len = 0;
+ char *pmask = NULL;
+ char *p = NULL;
+ *pss_out = *pss_in;
+
+ /* Set all zero netmask bits to 1. */
+#if defined(HAVE_IPV6)
+ if (pss_in->ss_family == AF_INET6) {
+ p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
+ pmask = (char *)&((struct sockaddr_in6 *)nmask)->sin6_addr;
+ len = 16;
}
-
- ifc.ifc_len = sizeof(buff);
- ifc.ifc_buf = buff;
-
- if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
- close(fd);
- return -1;
+#endif
+ if (pss_in->ss_family == AF_INET) {
+ p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
+ pmask = (char *)&((struct sockaddr_in *)nmask)->sin_addr;
+ len = 4;
}
- ifr = ifc.ifc_req;
-
- n = ifc.ifc_len / sizeof(struct ifreq);
-
- /* Loop through interfaces, looking for given IP address */
- for (i=n-1;i>=0 && total < max_interfaces;i--) {
-
- memset(&ifaces[total], '\0', sizeof(ifaces[total]));
-
- /* Check the interface is up. */
- if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
- continue;
- }
-
- ifaces[total].flags = ifr[i].ifr_flags;
-
- if (!(flags & IFF_UP)) {
- continue;
- }
-
- if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
- continue;
- }
-
- strncpy(ifaces[total].name, ifr[i].ifr_name,
- sizeof(ifaces[total].name)-1);
- ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
-
- memcpy(&ifaces[total].ip, &ifr[i].ifr_addr,
- sizeof(struct sockaddr_in));
-
- if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
- continue;
- }
-
- memcpy(&ifaces[total].netmask, &ifr[i].ifr_netmask,
- sizeof(struct sockaddr_in));
-
- if (ifaces[total].flags & IFF_BROADCAST) {
- if (ioctl(fd, SIOCGIFBRDADDR, &ifr[i]) != 0) {
- continue;
- }
- memcpy(&ifaces[total].bcast, &ifr[i].ifr_broadaddr,
- sizeof(struct sockaddr_in));
- } else if (ifaces[total].flags & IFF_POINTOPOINT) {
- if (ioctl(fd, SIOCGIFDSTADDR, &ifr[i]) != 0) {
- continue;
- }
- memcpy(&ifaces[total].bcast, &ifr[i].ifr_dstaddr,
- sizeof(struct sockaddr_in));
+ for (i = 0; i < len; i++, p++, pmask++) {
+ if (make_bcast_p) {
+ *p = (*p & *pmask) | (*pmask ^ 0xff);
} else {
- continue;
+ /* make_net */
+ *p = (*p & *pmask);
}
-
- total++;
}
+}
- close(fd);
-
- return total;
+void make_bcast(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ const struct sockaddr_storage *nmask)
+{
+ make_bcast_or_net(pss_out, pss_in, nmask, true);
}
-#define _FOUND_IFACE_ANY
-#endif /* HAVE_IFACE_IFCONF */
-#ifdef HAVE_IFACE_IFREQ
+void make_net(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ const struct sockaddr_storage *nmask)
+{
+ make_bcast_or_net(pss_out, pss_in, nmask, false);
+}
-#ifndef I_STR
-#include <sys/stropts.h>
-#endif
+/****************************************************************************
+ Try the "standard" getifaddrs/freeifaddrs interfaces.
+ Also gets IPv6 interfaces.
+****************************************************************************/
/****************************************************************************
- This should cover most of the streams based systems.
- Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code.
+ Get the netmask address for a local interface.
****************************************************************************/
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;
+ struct ifaddrs *iflist = NULL;
+ struct ifaddrs *ifptr = NULL;
int total = 0;
+ size_t copy_size;
- 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);
+ if (getifaddrs(&iflist) < 0) {
return -1;
}
- /* we can ignore the possible sizeof(int) here as the resulting
- number of interface structures won't change */
- n = strioctl.ic_len / sizeof(struct ifreq);
-
- /* we will assume that the kernel returns the length as an int
- at the start of the buffer if the offered size is a
- multiple of the structure size plus an int */
- if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
- ifr = (struct ifreq *)(buff + sizeof(int));
- } else {
- ifr = (struct ifreq *)buff;
- }
-
- /* Loop through interfaces */
-
- for (i = 0; i<n && total < max_interfaces; i++) {
+ /* Loop through interfaces, looking for given IP address */
+ for (ifptr = iflist, total = 0;
+ ifptr != NULL && total < max_interfaces;
+ ifptr = ifptr->ifa_next) {
memset(&ifaces[total], '\0', sizeof(ifaces[total]));
- ifreq = ifr[i];
+ copy_size = sizeof(struct sockaddr_in);
- strioctl.ic_cmd = SIOCGIFFLAGS;
- strioctl.ic_dp = (char *)&ifreq;
- strioctl.ic_len = sizeof(struct ifreq);
- if (ioctl(fd, I_STR, &strioctl) != 0) {
+ if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
continue;
}
- ifaces[total].flags = ifreq.ifr_flags;
+ ifaces[total].flags = ifptr->ifa_flags;
+ /* Check the interface is up. */
if (!(ifaces[total].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;
- }
-
- strncpy(ifaces[total].name, iname,
- sizeof(ifaces[total].name)-1);
- ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
-
- memcpy(&ifaces[total].ip, &ifreq.ifr_addr,
- sizeof(struct sockaddr_in));
-
- strioctl.ic_cmd = SIOCGIFNETMASK;
- strioctl.ic_dp = (char *)&ifreq;
- strioctl.ic_len = sizeof(struct ifreq);
- if (ioctl(fd, I_STR, &strioctl) != 0) {
- continue;
+#if defined(HAVE_IPV6)
+ if (ifptr->ifa_addr->sa_family == AF_INET6) {
+ copy_size = sizeof(struct sockaddr_in6);
}
+#endif
- memcpy(&ifaces[total].netmask, &ifreq.ifr_addr,
- sizeof(struct sockaddr_in));
+ memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size);
+ memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size);
- if (ifaces[total].flags & IFF_BROADCAST) {
- strioctl.ic_cmd = SIOCGIFBRDADDR;
- strioctl.ic_dp = (char *)&ifreq;
- strioctl.ic_len = sizeof(struct ifreq);
- if (ioctl(fd, I_STR, &strioctl) != 0) {
- continue;
- }
- memcpy(&ifaces[total].bcast, &ifreq.ifr_broadaddr,
- sizeof(struct sockaddr_in));
- } else if (ifaces[total].flags & IFF_POINTOPOINT) {
- strioctl.ic_cmd = SIOCGIFDSTADDR;
- strioctl.ic_dp = (char *)&ifreq;
- strioctl.ic_len = sizeof(struct ifreq);
- if (ioctl(fd, I_STR, &strioctl) != 0) {
- continue;
- }
- memcpy(&ifaces[total].bcast, &ifreq.ifr_dstaddr,
- sizeof(struct sockaddr_in));
+ if (ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) {
+ make_bcast(&ifaces[total].bcast,
+ &ifaces[total].ip,
+ &ifaces[total].netmask);
+ } else if ((ifaces[total].flags & IFF_POINTOPOINT) &&
+ ifptr->ifa_dstaddr ) {
+ memcpy(&ifaces[total].bcast,
+ ifptr->ifa_dstaddr,
+ copy_size);
} else {
continue;
}
+ strlcpy(ifaces[total].name, ifptr->ifa_name,
+ sizeof(ifaces[total].name));
total++;
}
- close(fd);
-
- return total;
-}
-
-#define _FOUND_IFACE_ANY
-#endif /* HAVE_IFACE_IFREQ */
-#ifdef HAVE_IFACE_AIX
-
-/****************************************************************************
- This one is for AIX (tested on 4.2).
-****************************************************************************/
-
-static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
-{
- char buff[8192];
- int fd, i;
- struct ifconf ifc;
- struct ifreq *ifr=NULL;
- 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;
-
- /* Loop through interfaces */
- i = ifc.ifc_len;
-
- while (i > 0 && total < max_interfaces) {
- uint_t inc;
-
- memset(&ifaces[total], '\0', sizeof(ifaces[total]));
-
- inc = ifr->ifr_addr.sa_len;
-
- if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
- goto next;
- }
-
- ifaces[total].flags = ifr->ifr_flags;
-
- if (!(ifaces[total].flags & IFF_UP)) {
- goto next;
- }
-
- if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
- goto next;
- }
-
- memcpy(&ifaces[total].ip, &ifr->ifr_addr,
- sizeof(struct sockaddr_in));
-
- strncpy(ifaces[total].name, ifr->ifr_name,
- sizeof(ifaces[total].name)-1);
- ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
-
- if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
- goto next;
- }
-
- memcpy(&ifaces[total].netmask, &ifr->ifr_addr,
- sizeof(struct sockaddr_in));
-
- if (ifaces[total].flags & IFF_BROADCAST) {
- if (ioctl(fd, SIOCGIFBRDADDR, &ifr[i]) != 0) {
- continue;
- }
- memcpy(&ifaces[total].bcast, &ifr[i].ifr_broadaddr,
- sizeof(struct sockaddr_in));
- } else if (ifaces[total].flags & IFF_POINTOPOINT) {
- if (ioctl(fd, SIOCGIFDSTADDR, &ifr[i]) != 0) {
- continue;
- }
- memcpy(&ifaces[total].bcast, &ifr[i].ifr_dstaddr,
- sizeof(struct sockaddr_in));
- } else {
- continue;
- }
-
-
- total++;
-
- next:
- /*
- * Patch from Archie Cobbs (archie@whistle.com). The
- * addresses in the SIOCGIFCONF interface list have a
- * minimum size. Usually this doesn't matter, but if
- * your machine has tunnel interfaces, etc. that have
- * a zero length "link address", this does matter. */
-
- if (inc < sizeof(ifr->ifr_addr))
- inc = sizeof(ifr->ifr_addr);
- inc += IFNAMSIZ;
-
- ifr = (struct ifreq*) (((char*) ifr) + inc);
- i -= inc;
- }
+ freeifaddrs(iflist);
- close(fd);
return total;
}
-#define _FOUND_IFACE_ANY
-#endif /* HAVE_IFACE_AIX */
-#ifndef _FOUND_IFACE_ANY
-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;
-#ifdef AF_INET6
+#if defined(HAVE_IPV6)
/*
* If we have IPv6 - sort these interfaces lower
* than any IPv4 ones.
}
#endif
- if (i1->ip.ss_family == AF_INET) {
+ /* AIX uses __ss_family instead of ss_family inside of
+ sockaddr_storage. Instead of trying to figure out which field to
+ use, we can just cast it to a sockaddr.
+ */
+
+ if (((struct sockaddr *)&i1->ip)->sa_family == AF_INET) {
struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip;
struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip;
return total;
}
-
-#ifdef AUTOCONF_TEST
-/* this is the autoconf driver to test get_interfaces() */
-
- 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++) {
- char addr[INET6_ADDRSTRLEN];
- int ret;
- printf("%-10s ", ifaces[i].name);
- addr[0] = '\0';
- ret = getnameinfo((struct sockaddr *)&ifaces[i].ip,
- sizeof(ifaces[i].ip),
- addr, sizeof(addr),
- NULL, 0, NI_NUMERICHOST);
- printf("IP=%s ", addr);
- addr[0] = '\0';
- ret = getnameinfo((struct sockaddr *)&ifaces[i].netmask,
- sizeof(ifaces[i].netmask),
- addr, sizeof(addr),
- NULL, 0, NI_NUMERICHOST);
- printf("NETMASK=%s ", addr);
- addr[0] = '\0';
- ret = getnameinfo((struct sockaddr *)&ifaces[i].bcast,
- sizeof(ifaces[i].bcast),
- addr, sizeof(addr),
- NULL, 0, NI_NUMERICHOST);
- printf("BCAST=%s\n", addr);
- }
- return 0;
-}
-#endif