1 /* Copyright (C) 2003,2006,2011 Juan Lang
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_PARAM_H
31 #include <sys/param.h>
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
50 #ifdef HAVE_NET_IF_ARP_H
51 #include <net/if_arp.h>
54 #ifdef HAVE_NET_ROUTE_H
55 #include <net/route.h>
58 #ifdef HAVE_SYS_IOCTL_H
59 #include <sys/ioctl.h>
62 #ifdef HAVE_SYS_SYSCTL_H
63 #include <sys/sysctl.h>
66 #ifdef HAVE_SYS_SOCKIO_H
67 #include <sys/sockio.h>
70 #ifdef HAVE_NET_IF_DL_H
71 #include <net/if_dl.h>
74 #ifdef HAVE_NET_IF_TYPES_H
75 #include <net/if_types.h>
85 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
86 #define ifreq_len(ifr) \
87 max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
89 #define ifreq_len(ifr) sizeof(struct ifreq)
97 #define IF_NAMESIZE 16
101 #define INADDR_NONE (~0U)
104 #define INITIAL_INTERFACES_ASSUMED 4
108 static int isLoopbackInterface(int fd, const char *name)
115 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
116 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
117 ret = ifr.ifr_flags & IFF_LOOPBACK;
122 /* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE
123 * bytes are necessary.
125 char *getInterfaceNameByIndex(DWORD index, char *name)
127 return if_indextoname(index, name);
130 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
136 return ERROR_INVALID_PARAMETER;
138 return ERROR_INVALID_PARAMETER;
139 idx = if_nametoindex(name);
145 ret = ERROR_INVALID_DATA;
149 BOOL isIfIndexLoopback(ULONG idx)
155 getInterfaceNameByIndex(idx, name);
156 fd = socket(PF_INET, SOCK_DGRAM, 0);
158 ret = isLoopbackInterface(fd, name);
164 DWORD getNumNonLoopbackInterfaces(void)
167 int fd = socket(PF_INET, SOCK_DGRAM, 0);
170 struct if_nameindex *indexes = if_nameindex();
173 struct if_nameindex *p;
175 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
176 if (!isLoopbackInterface(fd, p->if_name))
178 if_freenameindex(indexes);
186 return numInterfaces;
189 DWORD getNumInterfaces(void)
192 struct if_nameindex *indexes = if_nameindex();
195 struct if_nameindex *p;
197 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
199 if_freenameindex(indexes);
203 return numInterfaces;
206 InterfaceIndexTable *getInterfaceIndexTable(void)
209 InterfaceIndexTable *ret;
210 struct if_nameindex *indexes = if_nameindex();
213 struct if_nameindex *p;
214 DWORD size = sizeof(InterfaceIndexTable);
216 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
218 if (numInterfaces > 1)
219 size += (numInterfaces - 1) * sizeof(DWORD);
220 ret = HeapAlloc(GetProcessHeap(), 0, size);
223 for (p = indexes; p && p->if_name; p++)
224 ret->indexes[ret->numIndexes++] = p->if_index;
226 if_freenameindex(indexes);
233 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
236 InterfaceIndexTable *ret;
237 int fd = socket(PF_INET, SOCK_DGRAM, 0);
240 struct if_nameindex *indexes = if_nameindex();
243 struct if_nameindex *p;
244 DWORD size = sizeof(InterfaceIndexTable);
246 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
247 if (!isLoopbackInterface(fd, p->if_name))
249 if (numInterfaces > 1)
250 size += (numInterfaces - 1) * sizeof(DWORD);
251 ret = HeapAlloc(GetProcessHeap(), 0, size);
254 for (p = indexes; p && p->if_name; p++)
255 if (!isLoopbackInterface(fd, p->if_name))
256 ret->indexes[ret->numIndexes++] = p->if_index;
258 if_freenameindex(indexes);
269 static DWORD getInterfaceBCastAddrByName(const char *name)
271 DWORD ret = INADDR_ANY;
274 int fd = socket(PF_INET, SOCK_DGRAM, 0);
279 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
280 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
281 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
288 static DWORD getInterfaceMaskByName(const char *name)
290 DWORD ret = INADDR_NONE;
293 int fd = socket(PF_INET, SOCK_DGRAM, 0);
298 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
299 if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
300 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
307 #if defined (SIOCGIFHWADDR) && defined (HAVE_STRUCT_IFREQ_IFR_HWADDR)
308 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
314 if (!name || !len || !addr || !type)
315 return ERROR_INVALID_PARAMETER;
317 fd = socket(PF_INET, SOCK_DGRAM, 0);
321 memset(&ifr, 0, sizeof(struct ifreq));
322 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
323 if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
324 ret = ERROR_INVALID_DATA;
326 unsigned int addrLen;
328 switch (ifr.ifr_hwaddr.sa_family)
330 #ifdef ARPHRD_LOOPBACK
331 case ARPHRD_LOOPBACK:
333 *type = MIB_IF_TYPE_LOOPBACK;
339 *type = MIB_IF_TYPE_ETHERNET;
345 *type = MIB_IF_TYPE_FDDI;
348 #ifdef ARPHRD_IEEE802
349 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
351 *type = MIB_IF_TYPE_TOKENRING;
354 #ifdef ARPHRD_IEEE802_TR
355 case ARPHRD_IEEE802_TR: /* also Token Ring? */
357 *type = MIB_IF_TYPE_TOKENRING;
363 *type = MIB_IF_TYPE_SLIP;
369 *type = MIB_IF_TYPE_PPP;
373 addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
374 *type = MIB_IF_TYPE_OTHER;
376 if (addrLen > *len) {
377 ret = ERROR_INSUFFICIENT_BUFFER;
382 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
383 /* zero out remaining bytes for broken implementations */
384 memset(addr + addrLen, 0, *len - addrLen);
392 ret = ERROR_NO_MORE_FILES;
395 #elif defined (SIOCGARP)
396 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
402 if (!name || !len || !addr || !type)
403 return ERROR_INVALID_PARAMETER;
405 fd = socket(PF_INET, SOCK_DGRAM, 0);
407 if (isLoopbackInterface(fd, name)) {
408 *type = MIB_IF_TYPE_LOOPBACK;
409 memset(addr, 0, *len);
415 struct sockaddr_in *saddr;
419 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
420 ioctl(fd, SIOCGIFADDR, &ifr);
421 memset(&arp, 0, sizeof(struct arpreq));
422 arp.arp_pa.sa_family = AF_INET;
423 saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
424 saddr->sin_family = AF_INET;
425 memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
426 if ((ioctl(fd, SIOCGARP, &arp)))
427 ret = ERROR_INVALID_DATA;
429 /* FIXME: heh: who said it was ethernet? */
430 int addrLen = ETH_ALEN;
432 if (addrLen > *len) {
433 ret = ERROR_INSUFFICIENT_BUFFER;
438 memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
439 /* zero out remaining bytes for broken implementations */
440 memset(addr + addrLen, 0, *len - addrLen);
442 *type = MIB_IF_TYPE_ETHERNET;
450 ret = ERROR_NO_MORE_FILES;
454 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
455 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
459 struct if_msghdr *ifm;
460 struct sockaddr_dl *sdl;
463 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
467 if (!name || !len || !addr || !type)
468 return ERROR_INVALID_PARAMETER;
470 if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
471 return ERROR_NO_MORE_FILES;
473 buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
475 return ERROR_NOT_ENOUGH_MEMORY;
477 if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
478 HeapFree(GetProcessHeap(), 0, buf);
479 return ERROR_NO_MORE_FILES;
482 ret = ERROR_INVALID_DATA;
483 for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
484 ifm = (struct if_msghdr *)p;
485 sdl = (struct sockaddr_dl *)(ifm + 1);
487 if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
490 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
491 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
495 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
496 if (addrLen > *len) {
497 ret = ERROR_INSUFFICIENT_BUFFER;
502 memcpy(addr, LLADDR(sdl), addrLen);
503 /* zero out remaining bytes for broken implementations */
504 memset(addr + addrLen, 0, *len - addrLen);
506 #if defined(HAVE_NET_IF_TYPES_H)
507 switch (sdl->sdl_type)
510 *type = MIB_IF_TYPE_ETHERNET;
513 *type = MIB_IF_TYPE_FDDI;
515 case IFT_ISO88024: /* Token Bus */
516 *type = MIB_IF_TYPE_TOKENRING;
518 case IFT_ISO88025: /* Token Ring */
519 *type = MIB_IF_TYPE_TOKENRING;
522 *type = MIB_IF_TYPE_PPP;
525 *type = MIB_IF_TYPE_SLIP;
528 *type = MIB_IF_TYPE_LOOPBACK;
531 *type = MIB_IF_TYPE_OTHER;
534 /* default if we don't know */
535 *type = MIB_IF_TYPE_ETHERNET;
540 HeapFree(GetProcessHeap(), 0, buf);
545 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
548 char nameBuf[IF_NAMESIZE];
549 char *name = getInterfaceNameByIndex(index, nameBuf);
552 return getInterfacePhysicalByName(name, len, addr, type);
554 return ERROR_INVALID_DATA;
557 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
563 return ERROR_INVALID_PARAMETER;
565 return ERROR_INVALID_PARAMETER;
567 fd = socket(PF_INET, SOCK_DGRAM, 0);
571 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
572 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
573 ret = ERROR_INVALID_DATA;
578 *mtu = ifr.ifr_metric;
585 ret = ERROR_NO_MORE_FILES;
589 DWORD getInterfaceStatusByName(const char *name, PDWORD status)
595 return ERROR_INVALID_PARAMETER;
597 return ERROR_INVALID_PARAMETER;
599 fd = socket(PF_INET, SOCK_DGRAM, 0);
603 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
604 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
605 ret = ERROR_INVALID_DATA;
607 if (ifr.ifr_flags & IFF_UP)
608 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
610 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
616 ret = ERROR_NO_MORE_FILES;
620 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
622 BYTE addr[MAX_INTERFACE_PHYSADDR];
623 DWORD ret, len = sizeof(addr), type;
626 return ERROR_INVALID_PARAMETER;
628 return ERROR_INVALID_PARAMETER;
630 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
634 memset(entry, 0, sizeof(MIB_IFROW));
635 for (assigner = entry->wszName, walker = name; *walker;
636 walker++, assigner++)
639 getInterfaceIndexByName(name, &entry->dwIndex);
640 entry->dwPhysAddrLen = len;
641 memcpy(entry->bPhysAddr, addr, len);
642 memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
643 entry->dwType = type;
644 /* FIXME: how to calculate real speed? */
645 getInterfaceMtuByName(name, &entry->dwMtu);
646 /* lie, there's no "administratively down" here */
647 entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
648 getInterfaceStatusByName(name, &entry->dwOperStatus);
649 /* punt on dwLastChange? */
650 entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
651 memcpy(entry->bDescr, name, entry->dwDescrLen);
652 entry->bDescr[entry->dwDescrLen] = '\0';
657 ret = ERROR_INVALID_DATA;
661 static DWORD getIPAddrRowByName(PMIB_IPADDRROW ipAddrRow, const char *ifName,
662 const struct sockaddr *sa)
666 ret = getInterfaceIndexByName(ifName, &ipAddrRow->dwIndex);
667 memcpy(&ipAddrRow->dwAddr, sa->sa_data + 2, sizeof(DWORD));
668 ipAddrRow->dwMask = getInterfaceMaskByName(ifName);
669 /* the dwBCastAddr member isn't the broadcast address, it indicates whether
670 * the interface uses the 1's broadcast address (1) or the 0's broadcast
673 bcast = getInterfaceBCastAddrByName(ifName);
674 ipAddrRow->dwBCastAddr = (bcast & ipAddrRow->dwMask) ? 1 : 0;
675 /* FIXME: hardcoded reasm size, not sure where to get it */
676 ipAddrRow->dwReasmSize = 65535;
677 ipAddrRow->unused1 = 0;
678 ipAddrRow->wType = 0;
682 #ifdef HAVE_IFADDRS_H
684 /* Counts the IPv4 addresses in the system using the return value from
685 * getifaddrs, returning the count.
687 static DWORD countIPv4Addresses(struct ifaddrs *ifa)
689 DWORD numAddresses = 0;
691 for (; ifa; ifa = ifa->ifa_next)
692 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET)
697 DWORD getNumIPAddresses(void)
699 DWORD numAddresses = 0;
702 if (!getifaddrs(&ifa))
704 numAddresses = countIPv4Addresses(ifa);
710 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
715 ret = ERROR_INVALID_PARAMETER;
720 if (!getifaddrs(&ifa))
722 DWORD size = sizeof(MIB_IPADDRTABLE);
723 DWORD numAddresses = countIPv4Addresses(ifa);
725 if (numAddresses > 1)
726 size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
727 *ppIpAddrTable = HeapAlloc(heap, flags, size);
734 (*ppIpAddrTable)->dwNumEntries = numAddresses;
735 for (ifp = ifa; !ret && ifp; ifp = ifp->ifa_next)
737 if (!ifp->ifa_addr || ifp->ifa_addr->sa_family != AF_INET)
740 ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifp->ifa_name,
746 ret = ERROR_OUTOFMEMORY;
750 ret = ERROR_INVALID_PARAMETER;
755 ULONG v6addressesFromIndex(DWORD index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
760 if (!getifaddrs(&ifa))
766 getInterfaceNameByIndex(index, name);
767 for (p = ifa, n = 0; p; p = p->ifa_next)
768 if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
769 !strcmp(name, p->ifa_name))
773 *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
774 sizeof(struct WS_sockaddr_in6)));
777 struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)(
778 (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS));
780 for (p = ifa, n = 0; p; p = p->ifa_next)
782 if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
783 !strcmp(name, p->ifa_name))
785 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr;
787 next_addr->sin6_family = WS_AF_INET6;
788 next_addr->sin6_port = addr->sin6_port;
789 next_addr->sin6_flowinfo = addr->sin6_flowinfo;
790 memcpy(&next_addr->sin6_addr, &addr->sin6_addr,
791 sizeof(next_addr->sin6_addr));
792 next_addr->sin6_scope_id = addr->sin6_scope_id;
793 (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr;
794 (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
803 ret = ERROR_OUTOFMEMORY;
820 /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
821 * the count to you in *pcAddresses. It also returns to you the struct ifconf
822 * used by the call to ioctl, so that you may process the addresses further.
823 * Free ifc->ifc_buf using HeapFree.
824 * Returns NO_ERROR on success, something else on failure.
826 static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
831 fd = socket(PF_INET, SOCK_DGRAM, 0);
834 DWORD guessedNumAddresses = 0, numAddresses = 0;
841 /* there is no way to know the interface count beforehand,
842 so we need to loop again and again upping our max each time
843 until returned is constant across 2 calls */
845 lastlen = ifc->ifc_len;
846 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
847 if (guessedNumAddresses == 0)
848 guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
850 guessedNumAddresses *= 2;
851 ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
852 ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
853 ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
854 } while ((ioctlRet == 0) && (ifc->ifc_len != lastlen));
857 ifPtr = ifc->ifc_buf;
858 while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) {
859 struct ifreq *ifr = (struct ifreq *)ifPtr;
861 if (ifr->ifr_addr.sa_family == AF_INET)
864 ifPtr += ifreq_len((struct ifreq *)ifPtr);
868 ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
870 *pcAddresses = numAddresses;
873 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
879 ret = ERROR_NO_SYSTEM_RESOURCES;
883 DWORD getNumIPAddresses(void)
885 DWORD numAddresses = 0;
888 if (!enumIPAddresses(&numAddresses, &ifc))
889 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
893 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
898 ret = ERROR_INVALID_PARAMETER;
901 DWORD numAddresses = 0;
904 ret = enumIPAddresses(&numAddresses, &ifc);
907 DWORD size = sizeof(MIB_IPADDRTABLE);
909 if (numAddresses > 1)
910 size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
911 *ppIpAddrTable = HeapAlloc(heap, flags, size);
912 if (*ppIpAddrTable) {
917 (*ppIpAddrTable)->dwNumEntries = numAddresses;
919 while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
920 struct ifreq *ifr = (struct ifreq *)ifPtr;
922 ifPtr += ifreq_len(ifr);
924 if (ifr->ifr_addr.sa_family != AF_INET)
927 ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifr->ifr_name,
933 ret = ERROR_OUTOFMEMORY;
934 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
940 ULONG v6addressesFromIndex(DWORD index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
944 return ERROR_SUCCESS;
949 char *toIPAddressString(unsigned int addr, char string[16])
952 struct in_addr iAddr;
955 /* extra-anal, just to make auditors happy */
956 lstrcpynA(string, inet_ntoa(iAddr), 16);