diff --git a/dlls/iphlpapi/ifenum.c b/dlls/iphlpapi/ifenum.c index 2dec193f49c..a12450e5477 100644 --- a/dlls/iphlpapi/ifenum.c +++ b/dlls/iphlpapi/ifenum.c @@ -886,7 +886,7 @@ DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags) return ret; } -ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs) +ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs, SOCKET_ADDRESS **masks) { struct ifaddrs *ifa; ULONG ret; @@ -906,10 +906,14 @@ ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_ad { *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) + sizeof(struct WS_sockaddr_in6))); - if (*addrs) + *masks = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) + + sizeof(struct WS_sockaddr_in6))); + if (*addrs && *masks) { struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)( (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS)); + struct WS_sockaddr_in6 *mask_addr = (struct WS_sockaddr_in6 *)( + (BYTE *)*masks + n * sizeof(SOCKET_ADDRESS)); for (p = ifa, n = 0; p; p = p->ifa_next) { @@ -917,6 +921,7 @@ ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_ad !strcmp(name, p->ifa_name)) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr; + struct sockaddr_in6 *mask = (struct sockaddr_in6 *)p->ifa_netmask; next_addr->sin6_family = WS_AF_INET6; next_addr->sin6_port = addr->sin6_port; @@ -927,6 +932,16 @@ ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_ad (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr; (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6); next_addr++; + + mask_addr->sin6_family = WS_AF_INET6; + mask_addr->sin6_port = mask->sin6_port; + mask_addr->sin6_flowinfo = mask->sin6_flowinfo; + memcpy(&mask_addr->sin6_addr, &mask->sin6_addr, + sizeof(mask_addr->sin6_addr)); + mask_addr->sin6_scope_id = mask->sin6_scope_id; + (*masks)[n].lpSockaddr = (LPSOCKADDR)mask_addr; + (*masks)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6); + mask_addr++; n++; } } @@ -934,12 +949,17 @@ ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_ad ret = ERROR_SUCCESS; } else + { + HeapFree(GetProcessHeap(), 0, *addrs); + HeapFree(GetProcessHeap(), 0, *masks); ret = ERROR_OUTOFMEMORY; + } } else { *addrs = NULL; *num_addrs = 0; + *masks = NULL; ret = ERROR_SUCCESS; } freeifaddrs(ifa); @@ -1073,10 +1093,11 @@ DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags) return ret; } -ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs) +ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs, SOCKET_ADDRESS **masks) { *addrs = NULL; *num_addrs = 0; + *masks = NULL; return ERROR_SUCCESS; } diff --git a/dlls/iphlpapi/ifenum.h b/dlls/iphlpapi/ifenum.h index 49b6e7bce17..c6bf9575759 100644 --- a/dlls/iphlpapi/ifenum.h +++ b/dlls/iphlpapi/ifenum.h @@ -106,7 +106,8 @@ DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags) /* Returns the IPv6 addresses for a particular interface index. * Returns NO_ERROR on success, something else on failure. */ -ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs) DECLSPEC_HIDDEN; +ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs, + SOCKET_ADDRESS **masks) DECLSPEC_HIDDEN; /* Converts the network-order bytes in addr to a printable string. Returns * string. diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c index 141dbd85892..e14538632be 100644 --- a/dlls/iphlpapi/iphlpapi_main.c +++ b/dlls/iphlpapi/iphlpapi_main.c @@ -623,7 +623,7 @@ static NET_IF_CONNECTION_TYPE connectionTypeFromMibType(DWORD mib_type) } } -static ULONG v4addressesFromIndex(IF_INDEX index, DWORD **addrs, ULONG *num_addrs) +static ULONG v4addressesFromIndex(IF_INDEX index, DWORD **addrs, ULONG *num_addrs, DWORD **masks) { ULONG ret, i, j; MIB_IPADDRTABLE *at; @@ -639,9 +639,20 @@ static ULONG v4addressesFromIndex(IF_INDEX index, DWORD **addrs, ULONG *num_addr HeapFree(GetProcessHeap(), 0, at); return ERROR_OUTOFMEMORY; } + if (!(*masks = HeapAlloc(GetProcessHeap(), 0, *num_addrs * sizeof(DWORD)))) + { + HeapFree(GetProcessHeap(), 0, *addrs); + HeapFree(GetProcessHeap(), 0, at); + return ERROR_OUTOFMEMORY; + } for (i = 0, j = 0; i < at->dwNumEntries; i++) { - if (at->table[i].dwIndex == index) (*addrs)[j++] = at->table[i].dwAddr; + if (at->table[i].dwIndex == index) + { + (*addrs)[j] = at->table[i].dwAddr; + (*masks)[j] = at->table[i].dwMask; + j++; + } } HeapFree(GetProcessHeap(), 0, at); return ERROR_SUCCESS; @@ -724,41 +735,35 @@ static PMIB_IPFORWARDROW findIPv4Gateway(DWORD index, static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index, IP_ADAPTER_ADDRESSES *aa, ULONG *size) { - ULONG ret = ERROR_SUCCESS, i, num_v4addrs = 0, num_v4_gateways = 0, num_v6addrs = 0, total_size; - DWORD *v4addrs = NULL; - SOCKET_ADDRESS *v6addrs = NULL; + ULONG ret = ERROR_SUCCESS, i, j, num_v4addrs = 0, num_v4_gateways = 0, num_v6addrs = 0, total_size; + DWORD *v4addrs = NULL, *v4masks = NULL; + SOCKET_ADDRESS *v6addrs = NULL, *v6masks = NULL; PMIB_IPFORWARDTABLE routeTable = NULL; if (family == WS_AF_INET) { - if (!(flags & GAA_FLAG_SKIP_UNICAST)) - ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs); + ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs, &v4masks); + if (!ret && flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS) { - ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE, - GetProcessHeap(), 0); - if (!ret) - num_v4_gateways = count_v4_gateways(index, routeTable); + ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE, GetProcessHeap(), 0); + if (!ret) num_v4_gateways = count_v4_gateways(index, routeTable); } } else if (family == WS_AF_INET6) { - if (!(flags & GAA_FLAG_SKIP_UNICAST)) - ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs); + ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs, &v6masks); } else if (family == WS_AF_UNSPEC) { - if (!(flags & GAA_FLAG_SKIP_UNICAST)) - ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs); + ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs, &v4masks); + if (!ret && flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS) { - ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE, - GetProcessHeap(), 0); - if (!ret) - num_v4_gateways = count_v4_gateways(index, routeTable); + ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE, GetProcessHeap(), 0); + if (!ret) num_v4_gateways = count_v4_gateways(index, routeTable); } - if (!ret && !(flags & GAA_FLAG_SKIP_UNICAST)) - ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs); + if (!ret) ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs, &v6masks); } else { @@ -768,6 +773,9 @@ static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index if (ret) { HeapFree(GetProcessHeap(), 0, v4addrs); + HeapFree(GetProcessHeap(), 0, v4masks); + HeapFree(GetProcessHeap(), 0, v6addrs); + HeapFree(GetProcessHeap(), 0, v6masks); HeapFree(GetProcessHeap(), 0, routeTable); return ret; } @@ -777,6 +785,14 @@ static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index total_size += IF_NAMESIZE * sizeof(WCHAR); if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME)) total_size += IF_NAMESIZE * sizeof(WCHAR); + if (flags & GAA_FLAG_INCLUDE_PREFIX) + { + total_size += sizeof(IP_ADAPTER_PREFIX) * num_v4addrs; + total_size += sizeof(IP_ADAPTER_PREFIX) * num_v6addrs; + total_size += sizeof(struct sockaddr_in) * num_v4addrs; + for (i = 0; i < num_v6addrs; i++) + total_size += v6masks[i].iSockaddrLength; + } total_size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) * num_v4addrs; total_size += sizeof(struct sockaddr_in) * num_v4addrs; total_size += (sizeof(IP_ADAPTER_GATEWAY_ADDRESS) + sizeof(SOCKADDR_IN)) * num_v4_gateways; @@ -841,7 +857,7 @@ static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index ptr += sizeof(SOCKADDR_IN); } } - if (num_v4addrs) + if (num_v4addrs && !(flags & GAA_FLAG_SKIP_UNICAST)) { IP_ADAPTER_UNICAST_ADDRESS *ua; struct WS_sockaddr_in *sa; @@ -871,7 +887,7 @@ static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index } } } - if (num_v6addrs) + if (num_v6addrs && !(flags & GAA_FLAG_SKIP_UNICAST)) { IP_ADAPTER_UNICAST_ADDRESS *ua; struct WS_sockaddr_in6 *sa; @@ -908,6 +924,99 @@ static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index } } } + if (num_v4addrs && (flags & GAA_FLAG_INCLUDE_PREFIX)) + { + IP_ADAPTER_PREFIX *prefix; + + prefix = aa->FirstPrefix = (IP_ADAPTER_PREFIX *)ptr; + for (i = 0; i < num_v4addrs; i++) + { + char addr_buf[16]; + struct WS_sockaddr_in *sa; + + prefix->u.s.Length = sizeof(*prefix); + prefix->u.s.Flags = 0; + prefix->Next = NULL; + prefix->Address.iSockaddrLength = sizeof(struct sockaddr_in); + prefix->Address.lpSockaddr = (SOCKADDR *)((char *)prefix + prefix->u.s.Length); + + sa = (struct WS_sockaddr_in *)prefix->Address.lpSockaddr; + sa->sin_family = WS_AF_INET; + sa->sin_addr.S_un.S_addr = v4addrs[i] & v4masks[i]; + sa->sin_port = 0; + + prefix->PrefixLength = 0; + for (j = 0; j < sizeof(*v4masks) * 8; j++) + { + if (v4masks[i] & 1 << j) prefix->PrefixLength++; + else break; + } + TRACE("IPv4 network: %s/%u\n", + debugstr_ipv4((const in_addr_t *)&sa->sin_addr.S_un.S_addr, addr_buf), + prefix->PrefixLength); + + ptr += prefix->u.s.Length + prefix->Address.iSockaddrLength; + if (i < num_v4addrs - 1) + { + prefix->Next = (IP_ADAPTER_PREFIX *)ptr; + prefix = prefix->Next; + } + } + } + if (num_v6addrs && (flags & GAA_FLAG_INCLUDE_PREFIX)) + { + IP_ADAPTER_PREFIX *prefix; + + if (aa->FirstPrefix) + { + for (prefix = aa->FirstPrefix; prefix->Next; prefix = prefix->Next) + ; + prefix->Next = (IP_ADAPTER_PREFIX *)ptr; + prefix = (IP_ADAPTER_PREFIX *)ptr; + } + else + prefix = aa->FirstPrefix = (IP_ADAPTER_PREFIX *)ptr; + for (i = 0; i < num_v6addrs; i++) + { + char addr_buf[46]; + struct WS_sockaddr_in6 *sa; + const IN6_ADDR *addr, *mask; + BOOL done = FALSE; + + prefix->u.s.Length = sizeof(*prefix); + prefix->u.s.Flags = 0; + prefix->Next = NULL; + prefix->Address.iSockaddrLength = sizeof(struct sockaddr_in6); + prefix->Address.lpSockaddr = (SOCKADDR *)((char *)prefix + prefix->u.s.Length); + + sa = (struct WS_sockaddr_in6 *)prefix->Address.lpSockaddr; + sa->sin6_family = WS_AF_INET6; + sa->sin6_port = 0; + sa->sin6_flowinfo = 0; + addr = &((struct WS_sockaddr_in6 *)v6addrs[i].lpSockaddr)->sin6_addr; + mask = &((struct WS_sockaddr_in6 *)v6masks[i].lpSockaddr)->sin6_addr; + for (j = 0; j < 8; j++) sa->sin6_addr.u.Word[j] = addr->u.Word[j] & mask->u.Word[j]; + sa->sin6_scope_id = 0; + + prefix->PrefixLength = 0; + for (i = 0; i < 8 && !done; i++) + { + for (j = 0; j < sizeof(WORD) * 8 && !done; j++) + { + if (mask->u.Word[i] & 1 << j) prefix->PrefixLength++; + else done = TRUE; + } + } + TRACE("IPv6 network: %s/%u\n", debugstr_ipv6(sa, addr_buf), prefix->PrefixLength); + + ptr += prefix->u.s.Length + prefix->Address.iSockaddrLength; + if (i < num_v6addrs - 1) + { + prefix->Next = (IP_ADAPTER_PREFIX *)ptr; + prefix = prefix->Next; + } + } + } buflen = MAX_INTERFACE_PHYSADDR; getInterfacePhysicalByIndex(index, &buflen, aa->PhysicalAddress, &type); @@ -925,7 +1034,9 @@ static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index *size = total_size; HeapFree(GetProcessHeap(), 0, routeTable); HeapFree(GetProcessHeap(), 0, v6addrs); + HeapFree(GetProcessHeap(), 0, v6masks); HeapFree(GetProcessHeap(), 0, v4addrs); + HeapFree(GetProcessHeap(), 0, v4masks); return ERROR_SUCCESS; }