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>
82 #ifdef HAVE_LINUX_RTNETLINK_H
83 #include <linux/rtnetlink.h>
89 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
90 #define ifreq_len(ifr) \
91 max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
93 #define ifreq_len(ifr) sizeof(struct ifreq)
101 #define IF_NAMESIZE 16
105 #define INADDR_NONE (~0U)
108 #define INITIAL_INTERFACES_ASSUMED 4
112 static BOOL
isLoopbackInterface(int fd
, const char *name
)
119 lstrcpynA(ifr
.ifr_name
, name
, IFNAMSIZ
);
120 if (ioctl(fd
, SIOCGIFFLAGS
, &ifr
) == 0)
121 ret
= ifr
.ifr_flags
& IFF_LOOPBACK
;
126 /* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE
127 * bytes are necessary.
129 char *getInterfaceNameByIndex(IF_INDEX index
, char *name
)
131 return if_indextoname(index
, name
);
134 DWORD
getInterfaceIndexByName(const char *name
, IF_INDEX
*index
)
140 return ERROR_INVALID_PARAMETER
;
142 return ERROR_INVALID_PARAMETER
;
143 idx
= if_nametoindex(name
);
149 ret
= ERROR_INVALID_DATA
;
153 BOOL
isIfIndexLoopback(ULONG idx
)
159 getInterfaceNameByIndex(idx
, name
);
160 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
162 ret
= isLoopbackInterface(fd
, name
);
168 #ifdef HAVE_IF_NAMEINDEX
169 DWORD
get_interface_indices( BOOL skip_loopback
, InterfaceIndexTable
**table
)
172 struct if_nameindex
*p
, *indices
= if_nameindex();
173 InterfaceIndexTable
*ret
;
175 if (table
) *table
= NULL
;
176 if (!indices
) return 0;
178 for (p
= indices
; p
->if_name
; p
++)
180 if (skip_loopback
&& isIfIndexLoopback( p
->if_index
)) continue;
186 ret
= HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET(InterfaceIndexTable
, indexes
[count
]) );
192 for (p
= indices
, i
= 0; p
->if_name
&& i
< count
; p
++)
194 if (skip_loopback
&& isIfIndexLoopback( p
->if_index
)) continue;
195 ret
->indexes
[i
++] = p
->if_index
;
197 ret
->numIndexes
= count
= i
;
202 if_freenameindex( indices
);
206 #elif defined(HAVE_LINUX_RTNETLINK_H)
207 static int open_netlink( int *pid
)
209 int fd
= socket( AF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
210 struct sockaddr_nl addr
;
213 if (fd
< 0) return fd
;
215 memset( &addr
, 0, sizeof(addr
) );
216 addr
.nl_family
= AF_NETLINK
;
218 if (bind( fd
, (struct sockaddr
*)&addr
, sizeof(addr
) ) < 0)
222 if (getsockname( fd
, (struct sockaddr
*)&addr
, &len
) < 0)
232 static int send_netlink_req( int fd
, int pid
, int type
, int *seq_no
)
240 struct sockaddr_nl addr
;
242 req
.hdr
.nlmsg_len
= sizeof(req
);
243 req
.hdr
.nlmsg_type
= type
;
244 req
.hdr
.nlmsg_flags
= NLM_F_ROOT
| NLM_F_MATCH
| NLM_F_REQUEST
;
245 req
.hdr
.nlmsg_pid
= pid
;
246 req
.hdr
.nlmsg_seq
= InterlockedIncrement( &seq
);
247 req
.gen
.rtgen_family
= AF_UNSPEC
;
249 memset( &addr
, 0, sizeof(addr
) );
250 addr
.nl_family
= AF_NETLINK
;
251 if (sendto( fd
, &req
, sizeof(req
), 0, (struct sockaddr
*)&addr
, sizeof(addr
) ) != sizeof(req
))
253 *seq_no
= req
.hdr
.nlmsg_seq
;
259 struct netlink_reply
*next
;
261 struct nlmsghdr
*hdr
;
264 static void free_netlink_reply( struct netlink_reply
*data
)
266 struct netlink_reply
*ptr
;
270 HeapFree( GetProcessHeap(), 0, data
);
275 static int recv_netlink_reply( int fd
, int pid
, int seq
, struct netlink_reply
**data
)
277 int bufsize
= getpagesize();
281 struct sockaddr_nl addr
;
282 struct netlink_reply
*cur
, *last
= NULL
;
283 struct nlmsghdr
*hdr
;
287 buf
= HeapAlloc( GetProcessHeap(), 0, bufsize
);
292 left
= read
= recvfrom( fd
, buf
, bufsize
, 0, (struct sockaddr
*)&addr
, &sa_len
);
293 if (read
< 0) goto fail
;
294 if (addr
.nl_pid
!= 0) continue; /* not from kernel */
296 for (hdr
= (struct nlmsghdr
*)buf
; NLMSG_OK(hdr
, left
); hdr
= NLMSG_NEXT(hdr
, left
))
298 if (hdr
->nlmsg_pid
!= pid
|| hdr
->nlmsg_seq
!= seq
) continue;
299 if (hdr
->nlmsg_type
== NLMSG_DONE
)
306 cur
= HeapAlloc( GetProcessHeap(), 0, sizeof(*cur
) + read
);
310 cur
->hdr
= (struct nlmsghdr
*)(cur
+ 1);
311 memcpy( cur
->hdr
, buf
, read
);
312 if (last
) last
->next
= cur
;
317 HeapFree( GetProcessHeap(), 0, buf
);
321 free_netlink_reply( *data
);
322 HeapFree( GetProcessHeap(), 0, buf
);
327 static DWORD
get_indices_from_reply( struct netlink_reply
*reply
, int pid
, int seq
,
328 BOOL skip_loopback
, InterfaceIndexTable
*table
)
330 struct nlmsghdr
*hdr
;
331 struct netlink_reply
*r
;
334 for (r
= reply
; r
; r
= r
->next
)
337 for (hdr
= r
->hdr
; NLMSG_OK(hdr
, size
); hdr
= NLMSG_NEXT(hdr
, size
))
339 if (hdr
->nlmsg_pid
!= pid
|| hdr
->nlmsg_seq
!= seq
) continue;
340 if (hdr
->nlmsg_type
== NLMSG_DONE
) break;
342 if (hdr
->nlmsg_type
== RTM_NEWLINK
)
344 struct ifinfomsg
*info
= NLMSG_DATA(hdr
);
346 if (skip_loopback
&& (info
->ifi_flags
& IFF_LOOPBACK
)) continue;
347 if (table
) table
->indexes
[count
] = info
->ifi_index
;
355 DWORD
get_interface_indices( BOOL skip_loopback
, InterfaceIndexTable
**table
)
358 struct netlink_reply
*reply
= NULL
;
361 if (table
) *table
= NULL
;
362 fd
= open_netlink( &pid
);
363 if (fd
< 0) return 0;
365 if (send_netlink_req( fd
, pid
, RTM_GETLINK
, &seq
) < 0)
368 if (recv_netlink_reply( fd
, pid
, seq
, &reply
) < 0)
371 count
= get_indices_from_reply( reply
, pid
, seq
, skip_loopback
, NULL
);
375 InterfaceIndexTable
*ret
= HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET(InterfaceIndexTable
, indexes
[count
]) );
382 ret
->numIndexes
= count
;
383 get_indices_from_reply( reply
, pid
, seq
, skip_loopback
, ret
);
388 free_netlink_reply( reply
);
394 DWORD
get_interface_indices( BOOL skip_loopback
, InterfaceIndexTable
**table
)
396 if (table
) *table
= NULL
;
401 static DWORD
getInterfaceBCastAddrByName(const char *name
)
403 DWORD ret
= INADDR_ANY
;
406 int fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
411 lstrcpynA(ifr
.ifr_name
, name
, IFNAMSIZ
);
412 if (ioctl(fd
, SIOCGIFBRDADDR
, &ifr
) == 0)
413 memcpy(&ret
, ifr
.ifr_addr
.sa_data
+ 2, sizeof(DWORD
));
420 static DWORD
getInterfaceMaskByName(const char *name
)
422 DWORD ret
= INADDR_NONE
;
425 int fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
430 lstrcpynA(ifr
.ifr_name
, name
, IFNAMSIZ
);
431 if (ioctl(fd
, SIOCGIFNETMASK
, &ifr
) == 0)
432 memcpy(&ret
, ifr
.ifr_addr
.sa_data
+ 2, sizeof(DWORD
));
439 #if defined (SIOCGIFHWADDR) && defined (HAVE_STRUCT_IFREQ_IFR_HWADDR)
440 static DWORD
getInterfacePhysicalByName(const char *name
, PDWORD len
, PBYTE addr
,
446 if (!name
|| !len
|| !addr
|| !type
)
447 return ERROR_INVALID_PARAMETER
;
449 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
453 memset(&ifr
, 0, sizeof(struct ifreq
));
454 lstrcpynA(ifr
.ifr_name
, name
, IFNAMSIZ
);
455 if ((ioctl(fd
, SIOCGIFHWADDR
, &ifr
)))
456 ret
= ERROR_INVALID_DATA
;
458 unsigned int addrLen
;
460 switch (ifr
.ifr_hwaddr
.sa_family
)
462 #ifdef ARPHRD_LOOPBACK
463 case ARPHRD_LOOPBACK
:
465 *type
= MIB_IF_TYPE_LOOPBACK
;
471 *type
= MIB_IF_TYPE_ETHERNET
;
477 *type
= MIB_IF_TYPE_FDDI
;
480 #ifdef ARPHRD_IEEE802
481 case ARPHRD_IEEE802
: /* 802.2 Ethernet && Token Ring, guess TR? */
483 *type
= MIB_IF_TYPE_TOKENRING
;
486 #ifdef ARPHRD_IEEE802_TR
487 case ARPHRD_IEEE802_TR
: /* also Token Ring? */
489 *type
= MIB_IF_TYPE_TOKENRING
;
495 *type
= MIB_IF_TYPE_SLIP
;
501 *type
= MIB_IF_TYPE_PPP
;
505 addrLen
= min(MAX_INTERFACE_PHYSADDR
, sizeof(ifr
.ifr_hwaddr
.sa_data
));
506 *type
= MIB_IF_TYPE_OTHER
;
508 if (addrLen
> *len
) {
509 ret
= ERROR_INSUFFICIENT_BUFFER
;
514 memcpy(addr
, ifr
.ifr_hwaddr
.sa_data
, addrLen
);
515 /* zero out remaining bytes for broken implementations */
516 memset(addr
+ addrLen
, 0, *len
- addrLen
);
524 ret
= ERROR_NO_MORE_FILES
;
527 #elif defined (SIOCGARP)
528 static DWORD
getInterfacePhysicalByName(const char *name
, PDWORD len
, PBYTE addr
,
534 if (!name
|| !len
|| !addr
|| !type
)
535 return ERROR_INVALID_PARAMETER
;
537 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
539 if (isLoopbackInterface(fd
, name
)) {
540 *type
= MIB_IF_TYPE_LOOPBACK
;
541 memset(addr
, 0, *len
);
547 struct sockaddr_in
*saddr
;
551 lstrcpynA(ifr
.ifr_name
, name
, IFNAMSIZ
);
552 ioctl(fd
, SIOCGIFADDR
, &ifr
);
553 memset(&arp
, 0, sizeof(struct arpreq
));
554 arp
.arp_pa
.sa_family
= AF_INET
;
555 saddr
= (struct sockaddr_in
*)&arp
; /* proto addr is first member */
556 saddr
->sin_family
= AF_INET
;
557 memcpy(&saddr
->sin_addr
.s_addr
, ifr
.ifr_addr
.sa_data
+ 2, sizeof(DWORD
));
558 if ((ioctl(fd
, SIOCGARP
, &arp
)))
559 ret
= ERROR_INVALID_DATA
;
561 /* FIXME: heh: who said it was ethernet? */
562 int addrLen
= ETH_ALEN
;
564 if (addrLen
> *len
) {
565 ret
= ERROR_INSUFFICIENT_BUFFER
;
570 memcpy(addr
, &arp
.arp_ha
.sa_data
[0], addrLen
);
571 /* zero out remaining bytes for broken implementations */
572 memset(addr
+ addrLen
, 0, *len
- addrLen
);
574 *type
= MIB_IF_TYPE_ETHERNET
;
582 ret
= ERROR_NO_MORE_FILES
;
586 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
587 static DWORD
getInterfacePhysicalByName(const char *name
, PDWORD len
, PBYTE addr
,
591 struct if_msghdr
*ifm
;
592 struct sockaddr_dl
*sdl
;
595 int mib
[] = { CTL_NET
, AF_ROUTE
, 0, AF_LINK
, NET_RT_IFLIST
, 0 };
599 if (!name
|| !len
|| !addr
|| !type
)
600 return ERROR_INVALID_PARAMETER
;
602 if (sysctl(mib
, 6, NULL
, &mibLen
, NULL
, 0) < 0)
603 return ERROR_NO_MORE_FILES
;
605 buf
= HeapAlloc(GetProcessHeap(), 0, mibLen
);
607 return ERROR_NOT_ENOUGH_MEMORY
;
609 if (sysctl(mib
, 6, buf
, &mibLen
, NULL
, 0) < 0) {
610 HeapFree(GetProcessHeap(), 0, buf
);
611 return ERROR_NO_MORE_FILES
;
614 ret
= ERROR_INVALID_DATA
;
615 for (p
= buf
; !found
&& p
< buf
+ mibLen
; p
+= ifm
->ifm_msglen
) {
616 ifm
= (struct if_msghdr
*)p
;
617 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
619 if (ifm
->ifm_type
!= RTM_IFINFO
|| (ifm
->ifm_addrs
& RTA_IFP
) == 0)
622 if (sdl
->sdl_family
!= AF_LINK
|| sdl
->sdl_nlen
== 0 ||
623 memcmp(sdl
->sdl_data
, name
, max(sdl
->sdl_nlen
, strlen(name
))) != 0)
627 addrLen
= min(MAX_INTERFACE_PHYSADDR
, sdl
->sdl_alen
);
628 if (addrLen
> *len
) {
629 ret
= ERROR_INSUFFICIENT_BUFFER
;
634 memcpy(addr
, LLADDR(sdl
), addrLen
);
635 /* zero out remaining bytes for broken implementations */
636 memset(addr
+ addrLen
, 0, *len
- addrLen
);
638 #if defined(HAVE_NET_IF_TYPES_H)
639 switch (sdl
->sdl_type
)
642 *type
= MIB_IF_TYPE_ETHERNET
;
645 *type
= MIB_IF_TYPE_FDDI
;
647 case IFT_ISO88024
: /* Token Bus */
648 *type
= MIB_IF_TYPE_TOKENRING
;
650 case IFT_ISO88025
: /* Token Ring */
651 *type
= MIB_IF_TYPE_TOKENRING
;
654 *type
= MIB_IF_TYPE_PPP
;
657 *type
= MIB_IF_TYPE_SLIP
;
660 *type
= MIB_IF_TYPE_LOOPBACK
;
663 *type
= MIB_IF_TYPE_OTHER
;
666 /* default if we don't know */
667 *type
= MIB_IF_TYPE_ETHERNET
;
672 HeapFree(GetProcessHeap(), 0, buf
);
677 DWORD
getInterfacePhysicalByIndex(IF_INDEX index
, PDWORD len
, PBYTE addr
,
680 char nameBuf
[IF_NAMESIZE
];
681 char *name
= getInterfaceNameByIndex(index
, nameBuf
);
684 return getInterfacePhysicalByName(name
, len
, addr
, type
);
686 return ERROR_INVALID_DATA
;
689 DWORD
getInterfaceMtuByName(const char *name
, PDWORD mtu
)
695 return ERROR_INVALID_PARAMETER
;
697 return ERROR_INVALID_PARAMETER
;
699 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
703 lstrcpynA(ifr
.ifr_name
, name
, IFNAMSIZ
);
704 if ((ioctl(fd
, SIOCGIFMTU
, &ifr
)))
705 ret
= ERROR_INVALID_DATA
;
710 *mtu
= ifr
.ifr_metric
;
717 ret
= ERROR_NO_MORE_FILES
;
721 DWORD
getInterfaceStatusByName(const char *name
, INTERNAL_IF_OPER_STATUS
*status
)
727 return ERROR_INVALID_PARAMETER
;
729 return ERROR_INVALID_PARAMETER
;
731 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
735 lstrcpynA(ifr
.ifr_name
, name
, IFNAMSIZ
);
736 if ((ioctl(fd
, SIOCGIFFLAGS
, &ifr
)))
737 ret
= ERROR_INVALID_DATA
;
739 if (ifr
.ifr_flags
& IFF_UP
)
740 *status
= MIB_IF_OPER_STATUS_OPERATIONAL
;
742 *status
= MIB_IF_OPER_STATUS_NON_OPERATIONAL
;
748 ret
= ERROR_NO_MORE_FILES
;
752 DWORD
getInterfaceEntryByName(const char *name
, PMIB_IFROW entry
)
754 BYTE addr
[MAX_INTERFACE_PHYSADDR
];
755 DWORD ret
, len
= sizeof(addr
), type
;
758 return ERROR_INVALID_PARAMETER
;
760 return ERROR_INVALID_PARAMETER
;
762 if (getInterfacePhysicalByName(name
, &len
, addr
, &type
) == NO_ERROR
) {
766 memset(entry
, 0, sizeof(MIB_IFROW
));
767 for (assigner
= entry
->wszName
, walker
= name
; *walker
;
768 walker
++, assigner
++)
771 getInterfaceIndexByName(name
, &entry
->dwIndex
);
772 entry
->dwPhysAddrLen
= len
;
773 memcpy(entry
->bPhysAddr
, addr
, len
);
774 memset(entry
->bPhysAddr
+ len
, 0, sizeof(entry
->bPhysAddr
) - len
);
775 entry
->dwType
= type
;
776 /* FIXME: how to calculate real speed? */
777 getInterfaceMtuByName(name
, &entry
->dwMtu
);
778 /* lie, there's no "administratively down" here */
779 entry
->dwAdminStatus
= MIB_IF_ADMIN_STATUS_UP
;
780 getInterfaceStatusByName(name
, &entry
->dwOperStatus
);
781 /* punt on dwLastChange? */
782 entry
->dwDescrLen
= min(strlen(name
), MAX_INTERFACE_DESCRIPTION
- 1);
783 memcpy(entry
->bDescr
, name
, entry
->dwDescrLen
);
784 entry
->bDescr
[entry
->dwDescrLen
] = '\0';
789 ret
= ERROR_INVALID_DATA
;
793 static DWORD
getIPAddrRowByName(PMIB_IPADDRROW ipAddrRow
, const char *ifName
,
794 const struct sockaddr
*sa
)
798 ret
= getInterfaceIndexByName(ifName
, &ipAddrRow
->dwIndex
);
799 memcpy(&ipAddrRow
->dwAddr
, sa
->sa_data
+ 2, sizeof(DWORD
));
800 ipAddrRow
->dwMask
= getInterfaceMaskByName(ifName
);
801 /* the dwBCastAddr member isn't the broadcast address, it indicates whether
802 * the interface uses the 1's broadcast address (1) or the 0's broadcast
805 bcast
= getInterfaceBCastAddrByName(ifName
);
806 ipAddrRow
->dwBCastAddr
= (bcast
& ipAddrRow
->dwMask
) ? 1 : 0;
807 /* FIXME: hardcoded reasm size, not sure where to get it */
808 ipAddrRow
->dwReasmSize
= 65535;
809 ipAddrRow
->unused1
= 0;
810 /* wType is a bit field composed of MIB_IPADDR_* flags. Windows <= XP seems
811 * to like returning undocumented values 0x20 + 0x02 but for our current
812 * needs returning MIB_IPADDR_PRIMARY is enough.
814 ipAddrRow
->wType
= MIB_IPADDR_PRIMARY
;
818 #ifdef HAVE_IFADDRS_H
820 /* Counts the IPv4 addresses in the system using the return value from
821 * getifaddrs, returning the count.
823 static DWORD
countIPv4Addresses(struct ifaddrs
*ifa
)
825 DWORD numAddresses
= 0;
827 for (; ifa
; ifa
= ifa
->ifa_next
)
828 if (ifa
->ifa_addr
&& ifa
->ifa_addr
->sa_family
== AF_INET
)
833 DWORD
getNumIPAddresses(void)
835 DWORD numAddresses
= 0;
838 if (!getifaddrs(&ifa
))
840 numAddresses
= countIPv4Addresses(ifa
);
846 DWORD
getIPAddrTable(PMIB_IPADDRTABLE
*ppIpAddrTable
, HANDLE heap
, DWORD flags
)
851 ret
= ERROR_INVALID_PARAMETER
;
856 if (!getifaddrs(&ifa
))
858 DWORD size
= sizeof(MIB_IPADDRTABLE
);
859 DWORD numAddresses
= countIPv4Addresses(ifa
);
861 if (numAddresses
> 1)
862 size
+= (numAddresses
- 1) * sizeof(MIB_IPADDRROW
);
863 *ppIpAddrTable
= HeapAlloc(heap
, flags
, size
);
870 (*ppIpAddrTable
)->dwNumEntries
= numAddresses
;
871 for (ifp
= ifa
; !ret
&& ifp
; ifp
= ifp
->ifa_next
)
873 if (!ifp
->ifa_addr
|| ifp
->ifa_addr
->sa_family
!= AF_INET
)
876 ret
= getIPAddrRowByName(&(*ppIpAddrTable
)->table
[i
], ifp
->ifa_name
,
881 HeapFree(GetProcessHeap(), 0, *ppIpAddrTable
);
884 ret
= ERROR_OUTOFMEMORY
;
888 ret
= ERROR_INVALID_PARAMETER
;
893 ULONG
v6addressesFromIndex(IF_INDEX index
, SOCKET_ADDRESS
**addrs
, ULONG
*num_addrs
, SOCKET_ADDRESS
**masks
)
898 if (!getifaddrs(&ifa
))
904 getInterfaceNameByIndex(index
, name
);
905 for (p
= ifa
, n
= 0; p
; p
= p
->ifa_next
)
906 if (p
->ifa_addr
&& p
->ifa_addr
->sa_family
== AF_INET6
&&
907 !strcmp(name
, p
->ifa_name
))
911 *addrs
= HeapAlloc(GetProcessHeap(), 0, n
* (sizeof(SOCKET_ADDRESS
) +
912 sizeof(struct WS_sockaddr_in6
)));
913 *masks
= HeapAlloc(GetProcessHeap(), 0, n
* (sizeof(SOCKET_ADDRESS
) +
914 sizeof(struct WS_sockaddr_in6
)));
915 if (*addrs
&& *masks
)
917 struct WS_sockaddr_in6
*next_addr
= (struct WS_sockaddr_in6
*)(
918 (BYTE
*)*addrs
+ n
* sizeof(SOCKET_ADDRESS
));
919 struct WS_sockaddr_in6
*mask_addr
= (struct WS_sockaddr_in6
*)(
920 (BYTE
*)*masks
+ n
* sizeof(SOCKET_ADDRESS
));
922 for (p
= ifa
, n
= 0; p
; p
= p
->ifa_next
)
924 if (p
->ifa_addr
&& p
->ifa_addr
->sa_family
== AF_INET6
&&
925 !strcmp(name
, p
->ifa_name
))
927 struct sockaddr_in6
*addr
= (struct sockaddr_in6
*)p
->ifa_addr
;
928 struct sockaddr_in6
*mask
= (struct sockaddr_in6
*)p
->ifa_netmask
;
930 next_addr
->sin6_family
= WS_AF_INET6
;
931 next_addr
->sin6_port
= addr
->sin6_port
;
932 next_addr
->sin6_flowinfo
= addr
->sin6_flowinfo
;
933 memcpy(&next_addr
->sin6_addr
, &addr
->sin6_addr
,
934 sizeof(next_addr
->sin6_addr
));
935 next_addr
->sin6_scope_id
= addr
->sin6_scope_id
;
936 (*addrs
)[n
].lpSockaddr
= (LPSOCKADDR
)next_addr
;
937 (*addrs
)[n
].iSockaddrLength
= sizeof(struct WS_sockaddr_in6
);
940 mask_addr
->sin6_family
= WS_AF_INET6
;
941 mask_addr
->sin6_port
= mask
->sin6_port
;
942 mask_addr
->sin6_flowinfo
= mask
->sin6_flowinfo
;
943 memcpy(&mask_addr
->sin6_addr
, &mask
->sin6_addr
,
944 sizeof(mask_addr
->sin6_addr
));
945 mask_addr
->sin6_scope_id
= mask
->sin6_scope_id
;
946 (*masks
)[n
].lpSockaddr
= (LPSOCKADDR
)mask_addr
;
947 (*masks
)[n
].iSockaddrLength
= sizeof(struct WS_sockaddr_in6
);
957 HeapFree(GetProcessHeap(), 0, *addrs
);
958 HeapFree(GetProcessHeap(), 0, *masks
);
959 ret
= ERROR_OUTOFMEMORY
;
978 /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
979 * the count to you in *pcAddresses. It also returns to you the struct ifconf
980 * used by the call to ioctl, so that you may process the addresses further.
981 * Free ifc->ifc_buf using HeapFree.
982 * Returns NO_ERROR on success, something else on failure.
984 static DWORD
enumIPAddresses(PDWORD pcAddresses
, struct ifconf
*ifc
)
989 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
992 DWORD guessedNumAddresses
= 0, numAddresses
= 0;
999 /* there is no way to know the interface count beforehand,
1000 so we need to loop again and again upping our max each time
1001 until returned is constant across 2 calls */
1003 lastlen
= ifc
->ifc_len
;
1004 HeapFree(GetProcessHeap(), 0, ifc
->ifc_buf
);
1005 if (guessedNumAddresses
== 0)
1006 guessedNumAddresses
= INITIAL_INTERFACES_ASSUMED
;
1008 guessedNumAddresses
*= 2;
1009 ifc
->ifc_len
= sizeof(struct ifreq
) * guessedNumAddresses
;
1010 ifc
->ifc_buf
= HeapAlloc(GetProcessHeap(), 0, ifc
->ifc_len
);
1011 ioctlRet
= ioctl(fd
, SIOCGIFCONF
, ifc
);
1012 } while ((ioctlRet
== 0) && (ifc
->ifc_len
!= lastlen
));
1014 if (ioctlRet
== 0) {
1015 ifPtr
= ifc
->ifc_buf
;
1016 while (ifPtr
&& ifPtr
< ifc
->ifc_buf
+ ifc
->ifc_len
) {
1017 struct ifreq
*ifr
= (struct ifreq
*)ifPtr
;
1019 if (ifr
->ifr_addr
.sa_family
== AF_INET
)
1022 ifPtr
+= ifreq_len((struct ifreq
*)ifPtr
);
1026 ret
= ERROR_INVALID_PARAMETER
; /* FIXME: map from errno to Win32 */
1028 *pcAddresses
= numAddresses
;
1031 HeapFree(GetProcessHeap(), 0, ifc
->ifc_buf
);
1032 ifc
->ifc_buf
= NULL
;
1037 ret
= ERROR_NO_SYSTEM_RESOURCES
;
1041 DWORD
getNumIPAddresses(void)
1043 DWORD numAddresses
= 0;
1046 if (!enumIPAddresses(&numAddresses
, &ifc
))
1047 HeapFree(GetProcessHeap(), 0, ifc
.ifc_buf
);
1048 return numAddresses
;
1051 DWORD
getIPAddrTable(PMIB_IPADDRTABLE
*ppIpAddrTable
, HANDLE heap
, DWORD flags
)
1056 ret
= ERROR_INVALID_PARAMETER
;
1059 DWORD numAddresses
= 0;
1062 ret
= enumIPAddresses(&numAddresses
, &ifc
);
1065 DWORD size
= sizeof(MIB_IPADDRTABLE
);
1067 if (numAddresses
> 1)
1068 size
+= (numAddresses
- 1) * sizeof(MIB_IPADDRROW
);
1069 *ppIpAddrTable
= HeapAlloc(heap
, flags
, size
);
1070 if (*ppIpAddrTable
) {
1075 (*ppIpAddrTable
)->dwNumEntries
= numAddresses
;
1076 ifPtr
= ifc
.ifc_buf
;
1077 while (!ret
&& ifPtr
&& ifPtr
< ifc
.ifc_buf
+ ifc
.ifc_len
) {
1078 struct ifreq
*ifr
= (struct ifreq
*)ifPtr
;
1080 ifPtr
+= ifreq_len(ifr
);
1082 if (ifr
->ifr_addr
.sa_family
!= AF_INET
)
1085 ret
= getIPAddrRowByName(&(*ppIpAddrTable
)->table
[i
], ifr
->ifr_name
,
1090 HeapFree(GetProcessHeap(), 0, *ppIpAddrTable
);
1093 ret
= ERROR_OUTOFMEMORY
;
1094 HeapFree(GetProcessHeap(), 0, ifc
.ifc_buf
);
1100 ULONG
v6addressesFromIndex(IF_INDEX index
, SOCKET_ADDRESS
**addrs
, ULONG
*num_addrs
, SOCKET_ADDRESS
**masks
)
1105 return ERROR_SUCCESS
;
1110 char *toIPAddressString(unsigned int addr
, char string
[16])
1113 struct in_addr iAddr
;
1115 iAddr
.s_addr
= addr
;
1116 /* extra-anal, just to make auditors happy */
1117 lstrcpynA(string
, inet_ntoa(iAddr
), 16);