diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c index 69ebca26dd6..26474489ae2 100644 --- a/dlls/iphlpapi/iphlpapi_main.c +++ b/dlls/iphlpapi/iphlpapi_main.c @@ -278,26 +278,140 @@ DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex) return ERROR_NOT_SUPPORTED; } +static char *debugstr_ipv6(const struct WS_sockaddr_in6 *sin, char *buf) +{ + const IN6_ADDR *addr = &sin->sin6_addr; + char *p = buf; + int i; + BOOL in_zero = FALSE; + + for (i = 0; i < 7; i++) + { + if (!addr->u.Word[i]) + { + if (i == 0) + *p++ = ':'; + if (!in_zero) + { + *p++ = ':'; + in_zero = TRUE; + } + } + else + { + p += sprintf(p, "%x:", ntohs(addr->u.Word[i])); + in_zero = FALSE; + } + } + sprintf(p, "%x", ntohs(addr->u.Word[7])); + return buf; +} + +static BOOL map_address_6to4( SOCKADDR_IN6 *addr6, SOCKADDR_IN *addr4 ) +{ + ULONG i; + + if (addr6->sin6_family != WS_AF_INET6) return FALSE; + + for (i = 0; i < 5; i++) + if (addr6->sin6_addr.u.Word[i]) return FALSE; + + if (addr6->sin6_addr.u.Word[5] != 0xffff) return FALSE; + + addr4->sin_family = AF_INET; + addr4->sin_port = addr6->sin6_port; + addr4->sin_addr.S_un.S_addr = addr6->sin6_addr.u.Word[6] << 16 | addr6->sin6_addr.u.Word[7]; + memset( &addr4->sin_zero, 0, sizeof(addr4->sin_zero) ); + + return TRUE; +} + +static BOOL find_src_address( MIB_IPADDRTABLE *table, SOCKADDR_IN *dst, SOCKADDR_IN6 *src ) +{ + MIB_IPFORWARDROW row; + DWORD i, j; + + if (GetBestRoute( dst->sin_addr.S_un.S_addr, 0, &row )) return FALSE; + + for (i = 0; i < table->dwNumEntries; i++) + { + /* take the first address */ + if (table->table[i].dwIndex == row.dwForwardIfIndex) + { + src->sin6_family = WS_AF_INET6; + src->sin6_port = 0; + src->sin6_flowinfo = 0; + for (j = 0; j < 5; j++) src->sin6_addr.u.Word[j] = 0; + src->sin6_addr.u.Word[5] = 0xffff; + src->sin6_addr.u.Word[6] = table->table[i].dwAddr & 0xffff; + src->sin6_addr.u.Word[7] = table->table[i].dwAddr >> 16; + return TRUE; + } + } + + return FALSE; +} /****************************************************************** * CreateSortedAddressPairs (IPHLPAPI.@) */ -DWORD WINAPI CreateSortedAddressPairs(const PSOCKADDR_IN6 source, DWORD sourcecount, - const PSOCKADDR_IN6 destination, DWORD destinationcount, - DWORD sortoptions, - PSOCKADDR_IN6_PAIR *sortedaddr, DWORD *sortedcount) +DWORD WINAPI CreateSortedAddressPairs( const PSOCKADDR_IN6 src_list, DWORD src_count, + const PSOCKADDR_IN6 dst_list, DWORD dst_count, + DWORD options, PSOCKADDR_IN6_PAIR *pair_list, + DWORD *pair_count ) { - FIXME("(source %p, sourcecount %d, destination %p, destcount %d, sortoptions %x," - " sortedaddr %p, sortedcount %p): stub\n", source, sourcecount, destination, - destinationcount, sortoptions, sortedaddr, sortedcount); + DWORD i, size, ret; + SOCKADDR_IN6_PAIR *pairs; + SOCKADDR_IN6 *ptr; + SOCKADDR_IN addr4; + MIB_IPADDRTABLE *table; - if (source || sourcecount || !destination || !sortedaddr || !sortedcount || destinationcount > 500) - return ERROR_INVALID_PARAMETER; + FIXME( "(src_list %p src_count %u dst_list %p dst_count %u options %x pair_list %p pair_count %p): stub\n", + src_list, src_count, dst_list, dst_count, options, pair_list, pair_count ); - /* Returning not supported tells the client we don't have IPv6 support - * so applications can fallback to IPv4. - */ - return ERROR_NOT_SUPPORTED; + if (src_list || src_count || !dst_list || !pair_list || !pair_count || dst_count > 500) + return ERROR_INVALID_PARAMETER; + + for (i = 0; i < dst_count; i++) + { + if (!map_address_6to4( &dst_list[i], &addr4 )) + { + FIXME("only mapped IPv4 addresses are supported\n"); + return ERROR_NOT_SUPPORTED; + } + } + + size = dst_count * sizeof(*pairs); + size += dst_count * sizeof(SOCKADDR_IN6) * 2; /* source address + destination address */ + if (!(pairs = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_NOT_ENOUGH_MEMORY; + ptr = (SOCKADDR_IN6 *)(char *)pairs + dst_count * sizeof(*pairs); + + if ((ret = getIPAddrTable( &table, GetProcessHeap(), 0 ))) + { + HeapFree( GetProcessHeap(), 0, pairs ); + return ret; + } + + for (i = 0; i < dst_count; i++) + { + pairs[i].SourceAddress = ptr++; + if (!map_address_6to4( &dst_list[i], &addr4 ) || + !find_src_address( table, &addr4, pairs[i].SourceAddress )) + { + char buf[46]; + FIXME( "source address for %s not found\n", debugstr_ipv6(&dst_list[i], buf) ); + memset( pairs[i].SourceAddress, 0, sizeof(*pairs[i].SourceAddress) ); + pairs[i].SourceAddress->sin6_family = WS_AF_INET6; + } + + pairs[i].DestinationAddress = ptr++; + memcpy( pairs[i].DestinationAddress, &dst_list[i], sizeof(*pairs[i].DestinationAddress) ); + } + *pair_list = pairs; + *pair_count = dst_count; + + HeapFree( GetProcessHeap(), 0, table ); + return NO_ERROR; } @@ -727,35 +841,6 @@ static char *debugstr_ipv4(const in_addr_t *in_addr, char *buf) return buf; } -static char *debugstr_ipv6(const struct WS_sockaddr_in6 *sin, char *buf) -{ - const IN6_ADDR *addr = &sin->sin6_addr; - char *p = buf; - int i; - BOOL in_zero = FALSE; - - for (i = 0; i < 7; i++) - { - if (!addr->u.Word[i]) - { - if (i == 0) - *p++ = ':'; - if (!in_zero) - { - *p++ = ':'; - in_zero = TRUE; - } - } - else - { - p += sprintf(p, "%x:", ntohs(addr->u.Word[i])); - in_zero = FALSE; - } - } - sprintf(p, "%x", ntohs(addr->u.Word[7])); - return buf; -} - static ULONG count_v4_gateways(DWORD index, PMIB_IPFORWARDTABLE routeTable) { DWORD i, num_gateways = 0; diff --git a/dlls/iphlpapi/tests/iphlpapi.c b/dlls/iphlpapi/tests/iphlpapi.c index db965d31c83..3594b3b36b2 100644 --- a/dlls/iphlpapi/tests/iphlpapi.c +++ b/dlls/iphlpapi/tests/iphlpapi.c @@ -38,6 +38,7 @@ #include "winsock2.h" #include "windef.h" #include "winbase.h" +#include "ws2tcpip.h" #include "iphlpapi.h" #include "iprtrmib.h" #include "wine/test.h" @@ -77,6 +78,9 @@ static DWORD (WINAPI *pGetExtendedUdpTable)(PVOID,PDWORD,BOOL,ULONG,UDP_TABLE_CL static DWORD (WINAPI *pSetTcpEntry)(PMIB_TCPROW); static HANDLE(WINAPI *pIcmpCreateFile)(VOID); static DWORD (WINAPI *pIcmpSendEcho)(HANDLE,IPAddr,LPVOID,WORD,PIP_OPTION_INFORMATION,LPVOID,DWORD,DWORD); +static DWORD (WINAPI *pCreateSortedAddressPairs)(const PSOCKADDR_IN6,ULONG,const PSOCKADDR_IN6,ULONG,ULONG, + PSOCKADDR_IN6_PAIR*,ULONG*); +static void (WINAPI *pFreeMibTable)(void*); static void loadIPHlpApi(void) { @@ -111,6 +115,8 @@ static void loadIPHlpApi(void) pSetTcpEntry = (void *)GetProcAddress(hLibrary, "SetTcpEntry"); pIcmpCreateFile = (void *)GetProcAddress(hLibrary, "IcmpCreateFile"); pIcmpSendEcho = (void *)GetProcAddress(hLibrary, "IcmpSendEcho"); + pCreateSortedAddressPairs = (void *)GetProcAddress(hLibrary, "CreateSortedAddressPairs"); + pFreeMibTable = (void *)GetProcAddress(hLibrary, "FreeMibTable"); } } @@ -1562,6 +1568,65 @@ static void test_GetExtendedUdpTable(void) HeapFree( GetProcessHeap(), 0, table_module ); } +static void test_CreateSortedAddressPairs(void) +{ + SOCKADDR_IN6 dst[2]; + SOCKADDR_IN6_PAIR *pair; + ULONG pair_count; + DWORD ret; + + if (!pCreateSortedAddressPairs) + { + win_skip( "CreateSortedAddressPairs not available\n" ); + return; + } + + memset( dst, 0, sizeof(dst) ); + dst[0].sin6_family = AF_INET6; + dst[0].sin6_addr.u.Word[5] = 0xffff; + dst[0].sin6_addr.u.Word[6] = 0x0808; + dst[0].sin6_addr.u.Word[7] = 0x0808; + + pair_count = 0xdeadbeef; + ret = pCreateSortedAddressPairs( NULL, 0, dst, 1, 0, NULL, &pair_count ); + ok( ret == ERROR_INVALID_PARAMETER, "got %u\n", ret ); + ok( pair_count == 0xdeadbeef, "got %u\n", pair_count ); + + pair = (SOCKADDR_IN6_PAIR *)0xdeadbeef; + pair_count = 0xdeadbeef; + ret = pCreateSortedAddressPairs( NULL, 0, NULL, 1, 0, &pair, &pair_count ); + ok( ret == ERROR_INVALID_PARAMETER, "got %u\n", ret ); + ok( pair == (SOCKADDR_IN6_PAIR *)0xdeadbeef, "got %p\n", pair ); + ok( pair_count == 0xdeadbeef, "got %u\n", pair_count ); + + pair = NULL; + pair_count = 0xdeadbeef; + ret = pCreateSortedAddressPairs( NULL, 0, dst, 1, 0, &pair, &pair_count ); + ok( ret == NO_ERROR, "got %u\n", ret ); + ok( pair != NULL, "pair not set\n" ); + ok( pair_count == 1, "got %u\n", pair_count ); + ok( pair[0].SourceAddress != NULL, "src address not set\n" ); + ok( pair[0].DestinationAddress != NULL, "dst address not set\n" ); + pFreeMibTable( pair ); + + dst[1].sin6_family = AF_INET6; + dst[1].sin6_addr.u.Word[5] = 0xffff; + dst[1].sin6_addr.u.Word[6] = 0x0404; + dst[1].sin6_addr.u.Word[7] = 0x0808; + + pair = NULL; + pair_count = 0xdeadbeef; + ret = pCreateSortedAddressPairs( NULL, 0, dst, 2, 0, &pair, &pair_count ); + ok( ret == NO_ERROR, "got %u\n", ret ); + ok( pair != NULL, "pair not set\n" ); + ok( pair_count == 2, "got %u\n", pair_count ); + ok( pair[0].SourceAddress != NULL, "src address not set\n" ); + ok( pair[0].DestinationAddress != NULL, "dst address not set\n" ); + ok( pair[1].SourceAddress != NULL, "src address not set\n" ); + ok( pair[1].DestinationAddress != NULL, "dst address not set\n" ); + pFreeMibTable( pair ); +} + START_TEST(iphlpapi) { @@ -1581,6 +1646,7 @@ START_TEST(iphlpapi) test_GetAdaptersAddresses(); test_GetExtendedTcpTable(); test_GetExtendedUdpTable(); + test_CreateSortedAddressPairs(); freeIPHlpApi(); } }