/* Copyright (C) 2003,2006,2011 Juan Lang * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #include <sys/types.h> #ifdef HAVE_SYS_PARAM_H #include <sys/param.h> #endif #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif #ifdef HAVE_NET_IF_H #include <net/if.h> #endif #ifdef HAVE_NET_IF_ARP_H #include <net/if_arp.h> #endif #ifdef HAVE_NET_ROUTE_H #include <net/route.h> #endif #ifdef HAVE_SYS_IOCTL_H #include <sys/ioctl.h> #endif #ifdef HAVE_SYS_SYSCTL_H #include <sys/sysctl.h> #endif #ifdef HAVE_SYS_SOCKIO_H #include <sys/sockio.h> #endif #ifdef HAVE_NET_IF_DL_H #include <net/if_dl.h> #endif #ifdef HAVE_NET_IF_TYPES_H #include <net/if_types.h> #endif #ifdef HAVE_IFADDRS_H #include <ifaddrs.h> #endif #include "ifenum.h" #include "ws2ipdef.h" #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN #define ifreq_len(ifr) \ max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len) #else #define ifreq_len(ifr) sizeof(struct ifreq) #endif #ifndef ETH_ALEN #define ETH_ALEN 6 #endif #ifndef IF_NAMESIZE #define IF_NAMESIZE 16 #endif #ifndef INADDR_NONE #define INADDR_NONE (~0U) #endif #define INITIAL_INTERFACES_ASSUMED 4 /* Functions */ static int isLoopbackInterface(int fd, const char *name) { int ret = 0; if (name) { struct ifreq ifr; lstrcpynA(ifr.ifr_name, name, IFNAMSIZ); if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0) ret = ifr.ifr_flags & IFF_LOOPBACK; } return ret; } /* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE * bytes are necessary. */ char *getInterfaceNameByIndex(IF_INDEX index, char *name) { return if_indextoname(index, name); } DWORD getInterfaceIndexByName(const char *name, IF_INDEX *index) { DWORD ret; unsigned int idx; if (!name) return ERROR_INVALID_PARAMETER; if (!index) return ERROR_INVALID_PARAMETER; idx = if_nametoindex(name); if (idx) { *index = idx; ret = NO_ERROR; } else ret = ERROR_INVALID_DATA; return ret; } BOOL isIfIndexLoopback(ULONG idx) { BOOL ret = FALSE; char name[IFNAMSIZ]; int fd; getInterfaceNameByIndex(idx, name); fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd != -1) { ret = isLoopbackInterface(fd, name); close(fd); } return ret; } DWORD getNumNonLoopbackInterfaces(void) { DWORD numInterfaces; int fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd != -1) { struct if_nameindex *indexes = if_nameindex(); if (indexes) { struct if_nameindex *p; for (p = indexes, numInterfaces = 0; p && p->if_name; p++) if (!isLoopbackInterface(fd, p->if_name)) numInterfaces++; if_freenameindex(indexes); } else numInterfaces = 0; close(fd); } else numInterfaces = 0; return numInterfaces; } DWORD getNumInterfaces(void) { DWORD numInterfaces; struct if_nameindex *indexes = if_nameindex(); if (indexes) { struct if_nameindex *p; for (p = indexes, numInterfaces = 0; p && p->if_name; p++) numInterfaces++; if_freenameindex(indexes); } else numInterfaces = 0; return numInterfaces; } InterfaceIndexTable *getInterfaceIndexTable(void) { DWORD numInterfaces; InterfaceIndexTable *ret; struct if_nameindex *indexes = if_nameindex(); if (indexes) { struct if_nameindex *p; DWORD size = sizeof(InterfaceIndexTable); for (p = indexes, numInterfaces = 0; p && p->if_name; p++) numInterfaces++; if (numInterfaces > 1) size += (numInterfaces - 1) * sizeof(DWORD); ret = HeapAlloc(GetProcessHeap(), 0, size); if (ret) { ret->numIndexes = 0; for (p = indexes; p && p->if_name; p++) ret->indexes[ret->numIndexes++] = p->if_index; } if_freenameindex(indexes); } else ret = NULL; return ret; } InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void) { DWORD numInterfaces; InterfaceIndexTable *ret; int fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd != -1) { struct if_nameindex *indexes = if_nameindex(); if (indexes) { struct if_nameindex *p; DWORD size = sizeof(InterfaceIndexTable); for (p = indexes, numInterfaces = 0; p && p->if_name; p++) if (!isLoopbackInterface(fd, p->if_name)) numInterfaces++; if (numInterfaces > 1) size += (numInterfaces - 1) * sizeof(DWORD); ret = HeapAlloc(GetProcessHeap(), 0, size); if (ret) { ret->numIndexes = 0; for (p = indexes; p && p->if_name; p++) if (!isLoopbackInterface(fd, p->if_name)) ret->indexes[ret->numIndexes++] = p->if_index; } if_freenameindex(indexes); } else ret = NULL; close(fd); } else ret = NULL; return ret; } static DWORD getInterfaceBCastAddrByName(const char *name) { DWORD ret = INADDR_ANY; if (name) { int fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd != -1) { struct ifreq ifr; lstrcpynA(ifr.ifr_name, name, IFNAMSIZ); if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0) memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD)); close(fd); } } return ret; } static DWORD getInterfaceMaskByName(const char *name) { DWORD ret = INADDR_NONE; if (name) { int fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd != -1) { struct ifreq ifr; lstrcpynA(ifr.ifr_name, name, IFNAMSIZ); if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0) memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD)); close(fd); } } return ret; } #if defined (SIOCGIFHWADDR) && defined (HAVE_STRUCT_IFREQ_IFR_HWADDR) static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr, PDWORD type) { DWORD ret; int fd; if (!name || !len || !addr || !type) return ERROR_INVALID_PARAMETER; fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd != -1) { struct ifreq ifr; memset(&ifr, 0, sizeof(struct ifreq)); lstrcpynA(ifr.ifr_name, name, IFNAMSIZ); if ((ioctl(fd, SIOCGIFHWADDR, &ifr))) ret = ERROR_INVALID_DATA; else { unsigned int addrLen; switch (ifr.ifr_hwaddr.sa_family) { #ifdef ARPHRD_LOOPBACK case ARPHRD_LOOPBACK: addrLen = 0; *type = MIB_IF_TYPE_LOOPBACK; break; #endif #ifdef ARPHRD_ETHER case ARPHRD_ETHER: addrLen = ETH_ALEN; *type = MIB_IF_TYPE_ETHERNET; break; #endif #ifdef ARPHRD_FDDI case ARPHRD_FDDI: addrLen = ETH_ALEN; *type = MIB_IF_TYPE_FDDI; break; #endif #ifdef ARPHRD_IEEE802 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */ addrLen = ETH_ALEN; *type = MIB_IF_TYPE_TOKENRING; break; #endif #ifdef ARPHRD_IEEE802_TR case ARPHRD_IEEE802_TR: /* also Token Ring? */ addrLen = ETH_ALEN; *type = MIB_IF_TYPE_TOKENRING; break; #endif #ifdef ARPHRD_SLIP case ARPHRD_SLIP: addrLen = 0; *type = MIB_IF_TYPE_SLIP; break; #endif #ifdef ARPHRD_PPP case ARPHRD_PPP: addrLen = 0; *type = MIB_IF_TYPE_PPP; break; #endif default: addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data)); *type = MIB_IF_TYPE_OTHER; } if (addrLen > *len) { ret = ERROR_INSUFFICIENT_BUFFER; *len = addrLen; } else { if (addrLen > 0) memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen); /* zero out remaining bytes for broken implementations */ memset(addr + addrLen, 0, *len - addrLen); *len = addrLen; ret = NO_ERROR; } } close(fd); } else ret = ERROR_NO_MORE_FILES; return ret; } #elif defined (SIOCGARP) static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr, PDWORD type) { DWORD ret; int fd; if (!name || !len || !addr || !type) return ERROR_INVALID_PARAMETER; fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd != -1) { if (isLoopbackInterface(fd, name)) { *type = MIB_IF_TYPE_LOOPBACK; memset(addr, 0, *len); *len = 0; ret=NOERROR; } else { struct arpreq arp; struct sockaddr_in *saddr; struct ifreq ifr; /* get IP addr */ lstrcpynA(ifr.ifr_name, name, IFNAMSIZ); ioctl(fd, SIOCGIFADDR, &ifr); memset(&arp, 0, sizeof(struct arpreq)); arp.arp_pa.sa_family = AF_INET; saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */ saddr->sin_family = AF_INET; memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD)); if ((ioctl(fd, SIOCGARP, &arp))) ret = ERROR_INVALID_DATA; else { /* FIXME: heh: who said it was ethernet? */ int addrLen = ETH_ALEN; if (addrLen > *len) { ret = ERROR_INSUFFICIENT_BUFFER; *len = addrLen; } else { if (addrLen > 0) memcpy(addr, &arp.arp_ha.sa_data[0], addrLen); /* zero out remaining bytes for broken implementations */ memset(addr + addrLen, 0, *len - addrLen); *len = addrLen; *type = MIB_IF_TYPE_ETHERNET; ret = NO_ERROR; } } } close(fd); } else ret = ERROR_NO_MORE_FILES; return ret; } #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H) static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr, PDWORD type) { DWORD ret; struct if_msghdr *ifm; struct sockaddr_dl *sdl; u_char *p, *buf; size_t mibLen; int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 }; unsigned addrLen; BOOL found = FALSE; if (!name || !len || !addr || !type) return ERROR_INVALID_PARAMETER; if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0) return ERROR_NO_MORE_FILES; buf = HeapAlloc(GetProcessHeap(), 0, mibLen); if (!buf) return ERROR_NOT_ENOUGH_MEMORY; if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) { HeapFree(GetProcessHeap(), 0, buf); return ERROR_NO_MORE_FILES; } ret = ERROR_INVALID_DATA; for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) { ifm = (struct if_msghdr *)p; sdl = (struct sockaddr_dl *)(ifm + 1); if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0) continue; if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 || memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0) continue; found = TRUE; addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen); if (addrLen > *len) { ret = ERROR_INSUFFICIENT_BUFFER; *len = addrLen; } else { if (addrLen > 0) memcpy(addr, LLADDR(sdl), addrLen); /* zero out remaining bytes for broken implementations */ memset(addr + addrLen, 0, *len - addrLen); *len = addrLen; #if defined(HAVE_NET_IF_TYPES_H) switch (sdl->sdl_type) { case IFT_ETHER: *type = MIB_IF_TYPE_ETHERNET; break; case IFT_FDDI: *type = MIB_IF_TYPE_FDDI; break; case IFT_ISO88024: /* Token Bus */ *type = MIB_IF_TYPE_TOKENRING; break; case IFT_ISO88025: /* Token Ring */ *type = MIB_IF_TYPE_TOKENRING; break; case IFT_PPP: *type = MIB_IF_TYPE_PPP; break; case IFT_SLIP: *type = MIB_IF_TYPE_SLIP; break; case IFT_LOOP: *type = MIB_IF_TYPE_LOOPBACK; break; default: *type = MIB_IF_TYPE_OTHER; } #else /* default if we don't know */ *type = MIB_IF_TYPE_ETHERNET; #endif ret = NO_ERROR; } } HeapFree(GetProcessHeap(), 0, buf); return ret; } #endif DWORD getInterfacePhysicalByIndex(IF_INDEX index, PDWORD len, PBYTE addr, PDWORD type) { char nameBuf[IF_NAMESIZE]; char *name = getInterfaceNameByIndex(index, nameBuf); if (name) return getInterfacePhysicalByName(name, len, addr, type); else return ERROR_INVALID_DATA; } DWORD getInterfaceMtuByName(const char *name, PDWORD mtu) { DWORD ret; int fd; if (!name) return ERROR_INVALID_PARAMETER; if (!mtu) return ERROR_INVALID_PARAMETER; fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd != -1) { struct ifreq ifr; lstrcpynA(ifr.ifr_name, name, IFNAMSIZ); if ((ioctl(fd, SIOCGIFMTU, &ifr))) ret = ERROR_INVALID_DATA; else { #ifndef __sun *mtu = ifr.ifr_mtu; #else *mtu = ifr.ifr_metric; #endif ret = NO_ERROR; } close(fd); } else ret = ERROR_NO_MORE_FILES; return ret; } DWORD getInterfaceStatusByName(const char *name, INTERNAL_IF_OPER_STATUS *status) { DWORD ret; int fd; if (!name) return ERROR_INVALID_PARAMETER; if (!status) return ERROR_INVALID_PARAMETER; fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd != -1) { struct ifreq ifr; lstrcpynA(ifr.ifr_name, name, IFNAMSIZ); if ((ioctl(fd, SIOCGIFFLAGS, &ifr))) ret = ERROR_INVALID_DATA; else { if (ifr.ifr_flags & IFF_UP) *status = MIB_IF_OPER_STATUS_OPERATIONAL; else *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL; ret = NO_ERROR; } close(fd); } else ret = ERROR_NO_MORE_FILES; return ret; } DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry) { BYTE addr[MAX_INTERFACE_PHYSADDR]; DWORD ret, len = sizeof(addr), type; if (!name) return ERROR_INVALID_PARAMETER; if (!entry) return ERROR_INVALID_PARAMETER; if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) { WCHAR *assigner; const char *walker; memset(entry, 0, sizeof(MIB_IFROW)); for (assigner = entry->wszName, walker = name; *walker; walker++, assigner++) *assigner = *walker; *assigner = 0; getInterfaceIndexByName(name, &entry->dwIndex); entry->dwPhysAddrLen = len; memcpy(entry->bPhysAddr, addr, len); memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len); entry->dwType = type; /* FIXME: how to calculate real speed? */ getInterfaceMtuByName(name, &entry->dwMtu); /* lie, there's no "administratively down" here */ entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP; getInterfaceStatusByName(name, &entry->dwOperStatus); /* punt on dwLastChange? */ entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1); memcpy(entry->bDescr, name, entry->dwDescrLen); entry->bDescr[entry->dwDescrLen] = '\0'; entry->dwDescrLen++; ret = NO_ERROR; } else ret = ERROR_INVALID_DATA; return ret; } static DWORD getIPAddrRowByName(PMIB_IPADDRROW ipAddrRow, const char *ifName, const struct sockaddr *sa) { DWORD ret, bcast; ret = getInterfaceIndexByName(ifName, &ipAddrRow->dwIndex); memcpy(&ipAddrRow->dwAddr, sa->sa_data + 2, sizeof(DWORD)); ipAddrRow->dwMask = getInterfaceMaskByName(ifName); /* the dwBCastAddr member isn't the broadcast address, it indicates whether * the interface uses the 1's broadcast address (1) or the 0's broadcast * address (0). */ bcast = getInterfaceBCastAddrByName(ifName); ipAddrRow->dwBCastAddr = (bcast & ipAddrRow->dwMask) ? 1 : 0; /* FIXME: hardcoded reasm size, not sure where to get it */ ipAddrRow->dwReasmSize = 65535; ipAddrRow->unused1 = 0; ipAddrRow->wType = 0; return ret; } #ifdef HAVE_IFADDRS_H /* Counts the IPv4 addresses in the system using the return value from * getifaddrs, returning the count. */ static DWORD countIPv4Addresses(struct ifaddrs *ifa) { DWORD numAddresses = 0; for (; ifa; ifa = ifa->ifa_next) if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) numAddresses++; return numAddresses; } DWORD getNumIPAddresses(void) { DWORD numAddresses = 0; struct ifaddrs *ifa; if (!getifaddrs(&ifa)) { numAddresses = countIPv4Addresses(ifa); freeifaddrs(ifa); } return numAddresses; } DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags) { DWORD ret; if (!ppIpAddrTable) ret = ERROR_INVALID_PARAMETER; else { struct ifaddrs *ifa; if (!getifaddrs(&ifa)) { DWORD size = sizeof(MIB_IPADDRTABLE); DWORD numAddresses = countIPv4Addresses(ifa); if (numAddresses > 1) size += (numAddresses - 1) * sizeof(MIB_IPADDRROW); *ppIpAddrTable = HeapAlloc(heap, flags, size); if (*ppIpAddrTable) { DWORD i = 0; struct ifaddrs *ifp; ret = NO_ERROR; (*ppIpAddrTable)->dwNumEntries = numAddresses; for (ifp = ifa; !ret && ifp; ifp = ifp->ifa_next) { if (!ifp->ifa_addr || ifp->ifa_addr->sa_family != AF_INET) continue; ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifp->ifa_name, ifp->ifa_addr); i++; } } else ret = ERROR_OUTOFMEMORY; freeifaddrs(ifa); } else ret = ERROR_INVALID_PARAMETER; } return ret; } ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs) { struct ifaddrs *ifa; ULONG ret; if (!getifaddrs(&ifa)) { struct ifaddrs *p; ULONG n; char name[IFNAMSIZ]; getInterfaceNameByIndex(index, name); for (p = ifa, n = 0; p; p = p->ifa_next) if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 && !strcmp(name, p->ifa_name)) n++; if (n) { *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) + sizeof(struct WS_sockaddr_in6))); if (*addrs) { struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)( (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS)); for (p = ifa, n = 0; p; p = p->ifa_next) { if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 && !strcmp(name, p->ifa_name)) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr; next_addr->sin6_family = WS_AF_INET6; next_addr->sin6_port = addr->sin6_port; next_addr->sin6_flowinfo = addr->sin6_flowinfo; memcpy(&next_addr->sin6_addr, &addr->sin6_addr, sizeof(next_addr->sin6_addr)); next_addr->sin6_scope_id = addr->sin6_scope_id; (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr; (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6); next_addr++; n++; } } *num_addrs = n; ret = ERROR_SUCCESS; } else ret = ERROR_OUTOFMEMORY; } else { *addrs = NULL; *num_addrs = 0; ret = ERROR_SUCCESS; } freeifaddrs(ifa); } else ret = ERROR_NO_DATA; return ret; } #else /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning * the count to you in *pcAddresses. It also returns to you the struct ifconf * used by the call to ioctl, so that you may process the addresses further. * Free ifc->ifc_buf using HeapFree. * Returns NO_ERROR on success, something else on failure. */ static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc) { DWORD ret; int fd; fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd != -1) { int ioctlRet = 0; DWORD guessedNumAddresses = 0, numAddresses = 0; caddr_t ifPtr; int lastlen; ret = NO_ERROR; ifc->ifc_len = 0; ifc->ifc_buf = NULL; /* there is no way to know the interface count beforehand, so we need to loop again and again upping our max each time until returned is constant across 2 calls */ do { lastlen = ifc->ifc_len; HeapFree(GetProcessHeap(), 0, ifc->ifc_buf); if (guessedNumAddresses == 0) guessedNumAddresses = INITIAL_INTERFACES_ASSUMED; else guessedNumAddresses *= 2; ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses; ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len); ioctlRet = ioctl(fd, SIOCGIFCONF, ifc); } while ((ioctlRet == 0) && (ifc->ifc_len != lastlen)); if (ioctlRet == 0) { ifPtr = ifc->ifc_buf; while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) { struct ifreq *ifr = (struct ifreq *)ifPtr; if (ifr->ifr_addr.sa_family == AF_INET) numAddresses++; ifPtr += ifreq_len((struct ifreq *)ifPtr); } } else ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */ if (!ret) *pcAddresses = numAddresses; else { HeapFree(GetProcessHeap(), 0, ifc->ifc_buf); ifc->ifc_buf = NULL; } close(fd); } else ret = ERROR_NO_SYSTEM_RESOURCES; return ret; } DWORD getNumIPAddresses(void) { DWORD numAddresses = 0; struct ifconf ifc; if (!enumIPAddresses(&numAddresses, &ifc)) HeapFree(GetProcessHeap(), 0, ifc.ifc_buf); return numAddresses; } DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags) { DWORD ret; if (!ppIpAddrTable) ret = ERROR_INVALID_PARAMETER; else { DWORD numAddresses = 0; struct ifconf ifc; ret = enumIPAddresses(&numAddresses, &ifc); if (!ret) { DWORD size = sizeof(MIB_IPADDRTABLE); if (numAddresses > 1) size += (numAddresses - 1) * sizeof(MIB_IPADDRROW); *ppIpAddrTable = HeapAlloc(heap, flags, size); if (*ppIpAddrTable) { DWORD i = 0; caddr_t ifPtr; ret = NO_ERROR; (*ppIpAddrTable)->dwNumEntries = numAddresses; ifPtr = ifc.ifc_buf; while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) { struct ifreq *ifr = (struct ifreq *)ifPtr; ifPtr += ifreq_len(ifr); if (ifr->ifr_addr.sa_family != AF_INET) continue; ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifr->ifr_name, &ifr->ifr_addr); i++; } } else ret = ERROR_OUTOFMEMORY; HeapFree(GetProcessHeap(), 0, ifc.ifc_buf); } } return ret; } ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs) { *addrs = NULL; *num_addrs = 0; return ERROR_SUCCESS; } #endif char *toIPAddressString(unsigned int addr, char string[16]) { if (string) { struct in_addr iAddr; iAddr.s_addr = addr; /* extra-anal, just to make auditors happy */ lstrcpynA(string, inet_ntoa(iAddr), 16); } return string; }