iphlpapi: Implement retrieving IPv4 addresses using getifaddrs, when available.
[wine] / dlls / iphlpapi / ifenum.c
1 /* Copyright (C) 2003,2006 Juan Lang
2  *
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.
7  *
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.
12  *
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
16  *
17  * Implementation notes
18  * FIXME:
19  * - I don't support IPv6 addresses here, since SIOCGIFCONF can't return them
20  *
21  * There are three implemented methods for determining the MAC address of an
22  * interface:
23  * - a specific IOCTL (Linux)
24  * - looking in the ARP cache (at least Solaris)
25  * - using the sysctl interface (FreeBSD and Mac OS X)
26  * Solaris and some others have SIOCGENADDR, but I haven't gotten that to work
27  * on the Solaris boxes at SourceForge's compile farm, whereas SIOCGARP does.
28  */
29
30 #include "config.h"
31
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40
41 #include <sys/types.h>
42 #ifdef HAVE_SYS_PARAM_H
43 #include <sys/param.h>
44 #endif
45
46 #ifdef HAVE_SYS_SOCKET_H
47 #include <sys/socket.h>
48 #endif
49
50 #ifdef HAVE_NETINET_IN_H
51 #include <netinet/in.h>
52 #endif
53
54 #ifdef HAVE_ARPA_INET_H
55 #include <arpa/inet.h>
56 #endif
57
58 #ifdef HAVE_NET_IF_H
59 #include <net/if.h>
60 #endif
61
62 #ifdef HAVE_NET_IF_ARP_H
63 #include <net/if_arp.h>
64 #endif
65
66 #ifdef HAVE_NET_ROUTE_H
67 #include <net/route.h>
68 #endif
69
70 #ifdef HAVE_SYS_IOCTL_H
71 #include <sys/ioctl.h>
72 #endif
73
74 #ifdef HAVE_SYS_SYSCTL_H
75 #include <sys/sysctl.h>
76 #endif
77
78 #ifdef HAVE_SYS_SOCKIO_H
79 #include <sys/sockio.h>
80 #endif
81
82 #ifdef HAVE_NET_IF_DL_H
83 #include <net/if_dl.h>
84 #endif
85
86 #ifdef HAVE_NET_IF_TYPES_H
87 #include <net/if_types.h>
88 #endif
89
90 #ifdef HAVE_IFADDRS_H
91 #include <ifaddrs.h>
92 #endif
93
94 #include "ifenum.h"
95 #include "ws2ipdef.h"
96
97 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
98 #define ifreq_len(ifr) \
99  max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
100 #else
101 #define ifreq_len(ifr) sizeof(struct ifreq)
102 #endif
103
104 #ifndef ETH_ALEN
105 #define ETH_ALEN 6
106 #endif
107
108 #ifndef IF_NAMESIZE
109 #define IF_NAMESIZE 16
110 #endif
111
112 #ifndef INADDR_NONE
113 #define INADDR_NONE (~0U)
114 #endif
115
116 #define INITIAL_INTERFACES_ASSUMED 4
117
118 /* Functions */
119
120 static int isLoopbackInterface(int fd, const char *name)
121 {
122   int ret = 0;
123
124   if (name) {
125     struct ifreq ifr;
126
127     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
128     if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
129       ret = ifr.ifr_flags & IFF_LOOPBACK;
130   }
131   return ret;
132 }
133
134 /* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE
135  * bytes are necessary.
136  */
137 char *getInterfaceNameByIndex(DWORD index, char *name)
138 {
139   return if_indextoname(index, name);
140 }
141
142 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
143 {
144   DWORD ret;
145   unsigned int idx;
146
147   if (!name)
148     return ERROR_INVALID_PARAMETER;
149   if (!index)
150     return ERROR_INVALID_PARAMETER;
151   idx = if_nametoindex(name);
152   if (idx) {
153     *index = idx;
154     ret = NO_ERROR;
155   }
156   else
157     ret = ERROR_INVALID_DATA;
158   return ret;
159 }
160
161 BOOL isIfIndexLoopback(ULONG idx)
162 {
163   BOOL ret = FALSE;
164   char name[IFNAMSIZ];
165   int fd;
166
167   getInterfaceNameByIndex(idx, name);
168   fd = socket(PF_INET, SOCK_DGRAM, 0);
169   if (fd != -1) {
170     ret = isLoopbackInterface(fd, name);
171     close(fd);
172   }
173   return ret;
174 }
175
176 DWORD getNumNonLoopbackInterfaces(void)
177 {
178   DWORD numInterfaces;
179   int fd = socket(PF_INET, SOCK_DGRAM, 0);
180
181   if (fd != -1) {
182     struct if_nameindex *indexes = if_nameindex();
183
184     if (indexes) {
185       struct if_nameindex *p;
186
187       for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
188         if (!isLoopbackInterface(fd, p->if_name))
189           numInterfaces++;
190       if_freenameindex(indexes);
191     }
192     else
193       numInterfaces = 0;
194     close(fd);
195   }
196   else
197     numInterfaces = 0;
198   return numInterfaces;
199 }
200
201 DWORD getNumInterfaces(void)
202 {
203   DWORD numInterfaces;
204   struct if_nameindex *indexes = if_nameindex();
205
206   if (indexes) {
207     struct if_nameindex *p;
208
209     for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
210       numInterfaces++;
211     if_freenameindex(indexes);
212   }
213   else
214     numInterfaces = 0;
215   return numInterfaces;
216 }
217
218 InterfaceIndexTable *getInterfaceIndexTable(void)
219 {
220   DWORD numInterfaces;
221   InterfaceIndexTable *ret;
222   struct if_nameindex *indexes = if_nameindex();
223
224   if (indexes) {
225     struct if_nameindex *p;
226     DWORD size = sizeof(InterfaceIndexTable);
227
228     for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
229       numInterfaces++;
230     if (numInterfaces > 1)
231       size += (numInterfaces - 1) * sizeof(DWORD);
232     ret = HeapAlloc(GetProcessHeap(), 0, size);
233     if (ret) {
234       ret->numIndexes = 0;
235       for (p = indexes; p && p->if_name; p++)
236         ret->indexes[ret->numIndexes++] = p->if_index;
237     }
238     if_freenameindex(indexes);
239   }
240   else
241     ret = NULL;
242   return ret;
243 }
244
245 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
246 {
247   DWORD numInterfaces;
248   InterfaceIndexTable *ret;
249   int fd = socket(PF_INET, SOCK_DGRAM, 0);
250
251   if (fd != -1) {
252     struct if_nameindex *indexes = if_nameindex();
253
254     if (indexes) {
255       struct if_nameindex *p;
256       DWORD size = sizeof(InterfaceIndexTable);
257
258       for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
259         if (!isLoopbackInterface(fd, p->if_name))
260           numInterfaces++;
261       if (numInterfaces > 1)
262         size += (numInterfaces - 1) * sizeof(DWORD);
263       ret = HeapAlloc(GetProcessHeap(), 0, size);
264       if (ret) {
265         ret->numIndexes = 0;
266         for (p = indexes; p && p->if_name; p++)
267           if (!isLoopbackInterface(fd, p->if_name))
268             ret->indexes[ret->numIndexes++] = p->if_index;
269       }
270       if_freenameindex(indexes);
271     }
272     else
273       ret = NULL;
274     close(fd);
275   }
276   else
277     ret = NULL;
278   return ret;
279 }
280
281 static DWORD getInterfaceBCastAddrByName(const char *name)
282 {
283   DWORD ret = INADDR_ANY;
284
285   if (name) {
286     int fd = socket(PF_INET, SOCK_DGRAM, 0);
287
288     if (fd != -1) {
289       struct ifreq ifr;
290
291       lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
292       if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
293         memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
294       close(fd);
295     }
296   }
297   return ret;
298 }
299
300 static DWORD getInterfaceMaskByName(const char *name)
301 {
302   DWORD ret = INADDR_NONE;
303
304   if (name) {
305     int fd = socket(PF_INET, SOCK_DGRAM, 0);
306
307     if (fd != -1) {
308       struct ifreq ifr;
309
310       lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
311       if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
312         memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
313       close(fd);
314     }
315   }
316   return ret;
317 }
318
319 #if defined (SIOCGIFHWADDR) && defined (HAVE_STRUCT_IFREQ_IFR_HWADDR)
320 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
321  PDWORD type)
322 {
323   DWORD ret;
324   int fd;
325
326   if (!name || !len || !addr || !type)
327     return ERROR_INVALID_PARAMETER;
328
329   fd = socket(PF_INET, SOCK_DGRAM, 0);
330   if (fd != -1) {
331     struct ifreq ifr;
332
333     memset(&ifr, 0, sizeof(struct ifreq));
334     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
335     if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
336       ret = ERROR_INVALID_DATA;
337     else {
338       unsigned int addrLen;
339
340       switch (ifr.ifr_hwaddr.sa_family)
341       {
342 #ifdef ARPHRD_LOOPBACK
343         case ARPHRD_LOOPBACK:
344           addrLen = 0;
345           *type = MIB_IF_TYPE_LOOPBACK;
346           break;
347 #endif
348 #ifdef ARPHRD_ETHER
349         case ARPHRD_ETHER:
350           addrLen = ETH_ALEN;
351           *type = MIB_IF_TYPE_ETHERNET;
352           break;
353 #endif
354 #ifdef ARPHRD_FDDI
355         case ARPHRD_FDDI:
356           addrLen = ETH_ALEN;
357           *type = MIB_IF_TYPE_FDDI;
358           break;
359 #endif
360 #ifdef ARPHRD_IEEE802
361         case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
362           addrLen = ETH_ALEN;
363           *type = MIB_IF_TYPE_TOKENRING;
364           break;
365 #endif
366 #ifdef ARPHRD_IEEE802_TR
367         case ARPHRD_IEEE802_TR: /* also Token Ring? */
368           addrLen = ETH_ALEN;
369           *type = MIB_IF_TYPE_TOKENRING;
370           break;
371 #endif
372 #ifdef ARPHRD_SLIP
373         case ARPHRD_SLIP:
374           addrLen = 0;
375           *type = MIB_IF_TYPE_SLIP;
376           break;
377 #endif
378 #ifdef ARPHRD_PPP
379         case ARPHRD_PPP:
380           addrLen = 0;
381           *type = MIB_IF_TYPE_PPP;
382           break;
383 #endif
384         default:
385           addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
386           *type = MIB_IF_TYPE_OTHER;
387       }
388       if (addrLen > *len) {
389         ret = ERROR_INSUFFICIENT_BUFFER;
390         *len = addrLen;
391       }
392       else {
393         if (addrLen > 0)
394           memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
395         /* zero out remaining bytes for broken implementations */
396         memset(addr + addrLen, 0, *len - addrLen);
397         *len = addrLen;
398         ret = NO_ERROR;
399       }
400     }
401     close(fd);
402   }
403   else
404     ret = ERROR_NO_MORE_FILES;
405   return ret;
406 }
407 #elif defined (SIOCGARP)
408 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
409  PDWORD type)
410 {
411   DWORD ret;
412   int fd;
413
414   if (!name || !len || !addr || !type)
415     return ERROR_INVALID_PARAMETER;
416
417   fd = socket(PF_INET, SOCK_DGRAM, 0);
418   if (fd != -1) {
419     if (isLoopbackInterface(fd, name)) {
420       *type = MIB_IF_TYPE_LOOPBACK;
421       memset(addr, 0, *len);
422       *len = 0;
423       ret=NOERROR;
424     }
425     else {
426       struct arpreq arp;
427       struct sockaddr_in *saddr;
428       struct ifreq ifr;
429
430       /* get IP addr */
431       lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
432       ioctl(fd, SIOCGIFADDR, &ifr);
433       memset(&arp, 0, sizeof(struct arpreq));
434       arp.arp_pa.sa_family = AF_INET;
435       saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
436       saddr->sin_family = AF_INET;
437       memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
438       if ((ioctl(fd, SIOCGARP, &arp)))
439         ret = ERROR_INVALID_DATA;
440       else {
441         /* FIXME:  heh:  who said it was ethernet? */
442         int addrLen = ETH_ALEN;
443
444         if (addrLen > *len) {
445           ret = ERROR_INSUFFICIENT_BUFFER;
446           *len = addrLen;
447         }
448         else {
449           if (addrLen > 0)
450             memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
451           /* zero out remaining bytes for broken implementations */
452           memset(addr + addrLen, 0, *len - addrLen);
453           *len = addrLen;
454           *type = MIB_IF_TYPE_ETHERNET;
455           ret = NO_ERROR;
456         }
457       }
458     }
459     close(fd);
460   }
461     else
462       ret = ERROR_NO_MORE_FILES;
463
464   return ret;
465 }
466 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
467 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
468  PDWORD type)
469 {
470   DWORD ret;
471   struct if_msghdr *ifm;
472   struct sockaddr_dl *sdl;
473   u_char *p, *buf;
474   size_t mibLen;
475   int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
476   unsigned addrLen;
477   BOOL found = FALSE;
478
479   if (!name || !len || !addr || !type)
480     return ERROR_INVALID_PARAMETER;
481
482   if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
483     return ERROR_NO_MORE_FILES;
484
485   buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
486   if (!buf)
487     return ERROR_NOT_ENOUGH_MEMORY;
488
489   if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
490     HeapFree(GetProcessHeap(), 0, buf);
491     return ERROR_NO_MORE_FILES;
492   }
493
494   ret = ERROR_INVALID_DATA;
495   for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
496     ifm = (struct if_msghdr *)p;
497     sdl = (struct sockaddr_dl *)(ifm + 1);
498
499     if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
500       continue;
501
502     if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
503      memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
504       continue;
505
506     found = TRUE;
507     addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
508     if (addrLen > *len) {
509       ret = ERROR_INSUFFICIENT_BUFFER;
510       *len = addrLen;
511     }
512     else {
513       if (addrLen > 0)
514         memcpy(addr, LLADDR(sdl), addrLen);
515       /* zero out remaining bytes for broken implementations */
516       memset(addr + addrLen, 0, *len - addrLen);
517       *len = addrLen;
518 #if defined(HAVE_NET_IF_TYPES_H)
519       switch (sdl->sdl_type)
520       {
521         case IFT_ETHER:
522           *type = MIB_IF_TYPE_ETHERNET;
523           break;
524         case IFT_FDDI:
525           *type = MIB_IF_TYPE_FDDI;
526           break;
527         case IFT_ISO88024: /* Token Bus */
528           *type = MIB_IF_TYPE_TOKENRING;
529           break;
530         case IFT_ISO88025: /* Token Ring */
531           *type = MIB_IF_TYPE_TOKENRING;
532           break;
533         case IFT_PPP:
534           *type = MIB_IF_TYPE_PPP;
535           break;
536         case IFT_SLIP:
537           *type = MIB_IF_TYPE_SLIP;
538           break;
539         case IFT_LOOP:
540           *type = MIB_IF_TYPE_LOOPBACK;
541           break;
542         default:
543           *type = MIB_IF_TYPE_OTHER;
544       }
545 #else
546       /* default if we don't know */
547       *type = MIB_IF_TYPE_ETHERNET;
548 #endif
549       ret = NO_ERROR;
550     }
551   }
552   HeapFree(GetProcessHeap(), 0, buf);
553   return ret;
554 }
555 #endif
556
557 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
558  PDWORD type)
559 {
560   char nameBuf[IF_NAMESIZE];
561   char *name = getInterfaceNameByIndex(index, nameBuf);
562
563   if (name)
564     return getInterfacePhysicalByName(name, len, addr, type);
565   else
566     return ERROR_INVALID_DATA;
567 }
568
569 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
570 {
571   DWORD ret;
572   int fd;
573
574   if (!name)
575     return ERROR_INVALID_PARAMETER;
576   if (!mtu)
577     return ERROR_INVALID_PARAMETER;
578
579   fd = socket(PF_INET, SOCK_DGRAM, 0);
580   if (fd != -1) {
581     struct ifreq ifr;
582
583     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
584     if ((ioctl(fd, SIOCGIFMTU, &ifr)))
585       ret = ERROR_INVALID_DATA;
586     else {
587 #ifndef __sun
588       *mtu = ifr.ifr_mtu;
589 #else
590       *mtu = ifr.ifr_metric;
591 #endif
592       ret = NO_ERROR;
593     }
594     close(fd);
595   }
596   else
597     ret = ERROR_NO_MORE_FILES;
598   return ret;
599 }
600
601 DWORD getInterfaceStatusByName(const char *name, PDWORD status)
602 {
603   DWORD ret;
604   int fd;
605
606   if (!name)
607     return ERROR_INVALID_PARAMETER;
608   if (!status)
609     return ERROR_INVALID_PARAMETER;
610
611   fd = socket(PF_INET, SOCK_DGRAM, 0);
612   if (fd != -1) {
613     struct ifreq ifr;
614
615     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
616     if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
617       ret = ERROR_INVALID_DATA;
618     else {
619       if (ifr.ifr_flags & IFF_UP)
620         *status = MIB_IF_OPER_STATUS_OPERATIONAL;
621       else
622         *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
623       ret = NO_ERROR;
624     }
625     close(fd);
626   }
627   else
628     ret = ERROR_NO_MORE_FILES;
629   return ret;
630 }
631
632 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
633 {
634   BYTE addr[MAX_INTERFACE_PHYSADDR];
635   DWORD ret, len = sizeof(addr), type;
636
637   if (!name)
638     return ERROR_INVALID_PARAMETER;
639   if (!entry)
640     return ERROR_INVALID_PARAMETER;
641
642   if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
643     WCHAR *assigner;
644     const char *walker;
645
646     memset(entry, 0, sizeof(MIB_IFROW));
647     for (assigner = entry->wszName, walker = name; *walker; 
648      walker++, assigner++)
649       *assigner = *walker;
650     *assigner = 0;
651     getInterfaceIndexByName(name, &entry->dwIndex);
652     entry->dwPhysAddrLen = len;
653     memcpy(entry->bPhysAddr, addr, len);
654     memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
655     entry->dwType = type;
656     /* FIXME: how to calculate real speed? */
657     getInterfaceMtuByName(name, &entry->dwMtu);
658     /* lie, there's no "administratively down" here */
659     entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
660     getInterfaceStatusByName(name, &entry->dwOperStatus);
661     /* punt on dwLastChange? */
662     entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
663     memcpy(entry->bDescr, name, entry->dwDescrLen);
664     entry->bDescr[entry->dwDescrLen] = '\0';
665     entry->dwDescrLen++;
666     ret = NO_ERROR;
667   }
668   else
669     ret = ERROR_INVALID_DATA;
670   return ret;
671 }
672
673 static DWORD getIPAddrRowByName(PMIB_IPADDRROW ipAddrRow, const char *ifName,
674  const struct sockaddr *sa)
675 {
676   DWORD ret, bcast;
677
678   ret = getInterfaceIndexByName(ifName, &ipAddrRow->dwIndex);
679   memcpy(&ipAddrRow->dwAddr, sa->sa_data + 2, sizeof(DWORD));
680   ipAddrRow->dwMask = getInterfaceMaskByName(ifName);
681   /* the dwBCastAddr member isn't the broadcast address, it indicates whether
682    * the interface uses the 1's broadcast address (1) or the 0's broadcast
683    * address (0).
684    */
685   bcast = getInterfaceBCastAddrByName(ifName);
686   ipAddrRow->dwBCastAddr = (bcast & ipAddrRow->dwMask) ? 1 : 0;
687   /* FIXME: hardcoded reasm size, not sure where to get it */
688   ipAddrRow->dwReasmSize = 65535;
689   ipAddrRow->unused1 = 0;
690   ipAddrRow->wType = 0;
691   return ret;
692 }
693
694 #ifdef HAVE_IFADDRS_H
695
696 /* Counts the IPv4 addresses in the system using the return value from
697  * getifaddrs, returning the count.
698  */
699 static DWORD countIPv4Addresses(struct ifaddrs *ifa)
700 {
701   DWORD numAddresses = 0;
702
703   for (; ifa; ifa = ifa->ifa_next)
704     if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET)
705       numAddresses++;
706   return numAddresses;
707 }
708
709 DWORD getNumIPAddresses(void)
710 {
711   DWORD numAddresses = 0;
712   struct ifaddrs *ifa;
713
714   if (!getifaddrs(&ifa))
715   {
716     numAddresses = countIPv4Addresses(ifa);
717     freeifaddrs(ifa);
718   }
719   return numAddresses;
720 }
721
722 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
723 {
724   DWORD ret;
725
726   if (!ppIpAddrTable)
727     ret = ERROR_INVALID_PARAMETER;
728   else
729   {
730     struct ifaddrs *ifa;
731
732     if (!getifaddrs(&ifa))
733     {
734       DWORD size = sizeof(MIB_IPADDRTABLE);
735       DWORD numAddresses = countIPv4Addresses(ifa);
736
737       if (numAddresses > 1)
738         size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
739       *ppIpAddrTable = HeapAlloc(heap, flags, size);
740       if (*ppIpAddrTable)
741       {
742         DWORD i = 0;
743         struct ifaddrs *ifp;
744
745         ret = NO_ERROR;
746         (*ppIpAddrTable)->dwNumEntries = numAddresses;
747         for (ifp = ifa; !ret && ifp; ifp = ifp->ifa_next)
748         {
749           if (!ifp->ifa_addr || ifp->ifa_addr->sa_family != AF_INET)
750             continue;
751
752           ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifp->ifa_name,
753            ifp->ifa_addr);
754           i++;
755         }
756       }
757       else
758         ret = ERROR_OUTOFMEMORY;
759       freeifaddrs(ifa);
760     }
761     else
762       ret = ERROR_INVALID_PARAMETER;
763   }
764   return ret;
765 }
766
767 #else
768
769 /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
770  * the count to you in *pcAddresses.  It also returns to you the struct ifconf
771  * used by the call to ioctl, so that you may process the addresses further.
772  * Free ifc->ifc_buf using HeapFree.
773  * Returns NO_ERROR on success, something else on failure.
774  */
775 static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
776 {
777   DWORD ret;
778   int fd;
779
780   fd = socket(PF_INET, SOCK_DGRAM, 0);
781   if (fd != -1) {
782     int ioctlRet = 0;
783     DWORD guessedNumAddresses = 0, numAddresses = 0;
784     caddr_t ifPtr;
785     int lastlen;
786
787     ret = NO_ERROR;
788     ifc->ifc_len = 0;
789     ifc->ifc_buf = NULL;
790     /* there is no way to know the interface count beforehand,
791        so we need to loop again and again upping our max each time
792        until returned is constant across 2 calls */
793     do {
794       lastlen = ifc->ifc_len;
795       HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
796       if (guessedNumAddresses == 0)
797         guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
798       else
799         guessedNumAddresses *= 2;
800       ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
801       ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
802       ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
803     } while ((ioctlRet == 0) && (ifc->ifc_len != lastlen));
804
805     if (ioctlRet == 0) {
806       ifPtr = ifc->ifc_buf;
807       while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) {
808         struct ifreq *ifr = (struct ifreq *)ifPtr;
809
810         if (ifr->ifr_addr.sa_family == AF_INET)
811           numAddresses++;
812
813         ifPtr += ifreq_len((struct ifreq *)ifPtr);
814       }
815     }
816     else
817       ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
818     if (!ret)
819       *pcAddresses = numAddresses;
820     else
821     {
822       HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
823       ifc->ifc_buf = NULL;
824     }
825     close(fd);
826   }
827   else
828     ret = ERROR_NO_SYSTEM_RESOURCES;
829   return ret;
830 }
831
832 DWORD getNumIPAddresses(void)
833 {
834   DWORD numAddresses = 0;
835   struct ifconf ifc;
836
837   if (!enumIPAddresses(&numAddresses, &ifc))
838     HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
839   return numAddresses;
840 }
841
842 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
843 {
844   DWORD ret;
845
846   if (!ppIpAddrTable)
847     ret = ERROR_INVALID_PARAMETER;
848   else
849   {
850     DWORD numAddresses = 0;
851     struct ifconf ifc;
852
853     ret = enumIPAddresses(&numAddresses, &ifc);
854     if (!ret)
855     {
856       DWORD size = sizeof(MIB_IPADDRTABLE);
857
858       if (numAddresses > 1)
859         size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
860       *ppIpAddrTable = HeapAlloc(heap, flags, size);
861       if (*ppIpAddrTable) {
862         DWORD i = 0;
863         caddr_t ifPtr;
864
865         ret = NO_ERROR;
866         (*ppIpAddrTable)->dwNumEntries = numAddresses;
867         ifPtr = ifc.ifc_buf;
868         while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
869           struct ifreq *ifr = (struct ifreq *)ifPtr;
870
871           ifPtr += ifreq_len(ifr);
872
873           if (ifr->ifr_addr.sa_family != AF_INET)
874              continue;
875
876           ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifr->ifr_name,
877            &ifr->ifr_addr);
878           i++;
879         }
880       }
881       else
882         ret = ERROR_OUTOFMEMORY;
883       HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
884     }
885   }
886   return ret;
887 }
888
889 #endif
890
891 #ifdef HAVE_IFADDRS_H
892 ULONG v6addressesFromIndex(DWORD index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
893 {
894   struct ifaddrs *ifa;
895   ULONG ret;
896
897   if (!getifaddrs(&ifa))
898   {
899     struct ifaddrs *p;
900     ULONG n;
901     char name[IFNAMSIZ];
902
903     getInterfaceNameByIndex(index, name);
904     for (p = ifa, n = 0; p; p = p->ifa_next)
905       if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
906           !strcmp(name, p->ifa_name))
907         n++;
908     if (n)
909     {
910       *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
911                          sizeof(struct WS_sockaddr_in6)));
912       if (*addrs)
913       {
914         struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)(
915             (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS));
916
917         for (p = ifa, n = 0; p; p = p->ifa_next)
918         {
919           if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
920               !strcmp(name, p->ifa_name))
921           {
922             struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr;
923
924             next_addr->sin6_family = WS_AF_INET6;
925             next_addr->sin6_port = addr->sin6_port;
926             next_addr->sin6_flowinfo = addr->sin6_flowinfo;
927             memcpy(&next_addr->sin6_addr, &addr->sin6_addr,
928              sizeof(next_addr->sin6_addr));
929             next_addr->sin6_scope_id = addr->sin6_scope_id;
930             (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr;
931             (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
932             next_addr++;
933             n++;
934           }
935         }
936         *num_addrs = n;
937         ret = ERROR_SUCCESS;
938       }
939       else
940         ret = ERROR_OUTOFMEMORY;
941     }
942     else
943     {
944       *addrs = NULL;
945       *num_addrs = 0;
946       ret = ERROR_SUCCESS;
947     }
948     freeifaddrs(ifa);
949   }
950   else
951     ret = ERROR_NO_DATA;
952   return ret;
953 }
954 #else
955 ULONG v6addressesFromIndex(DWORD index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
956 {
957   *addrs = NULL;
958   *num_addrs = 0;
959   return ERROR_SUCCESS;
960 }
961 #endif
962
963 char *toIPAddressString(unsigned int addr, char string[16])
964 {
965   if (string) {
966     struct in_addr iAddr;
967
968     iAddr.s_addr = addr;
969     /* extra-anal, just to make auditors happy */
970     lstrcpynA(string, inet_ntoa(iAddr), 16);
971   }
972   return string;
973 }