Signed-off-by: Alex Henrie alexhenrie24@gmail.com --- The Windows header only defines NET_ADDRESS_FORMAT and NET_ADDRESS_INFO if windns.h is included before iphlpapi.h. --- include/iphlpapi.h | 47 ++++++++++++++++++++++++++++++++++++++++++++++ include/windns.h | 1 + 2 files changed, 48 insertions(+)
diff --git a/include/iphlpapi.h b/include/iphlpapi.h index f52387a1ca..a087d7fd69 100644 --- a/include/iphlpapi.h +++ b/include/iphlpapi.h @@ -26,6 +26,26 @@ extern "C" { #include <ipexport.h> #include <iptypes.h>
+#define NET_STRING_IPV4_ADDRESS 0x00000001 +#define NET_STRING_IPV4_SERVICE 0x00000002 +#define NET_STRING_IPV4_NETWORK 0x00000004 +#define NET_STRING_IPV6_ADDRESS 0x00000008 +#define NET_STRING_IPV6_ADDRESS_NO_SCOPE 0x00000010 +#define NET_STRING_IPV6_SERVICE 0x00000020 +#define NET_STRING_IPV6_SERVICE_NO_SCOPE 0x00000040 +#define NET_STRING_IPV6_NETWORK 0x00000080 +#define NET_STRING_NAMED_ADDRESS 0x00000100 +#define NET_STRING_NAMED_SERVICE 0x00000200 +#define NET_STRING_IP_ADDRESS (NET_STRING_IPV4_ADDRESS|NET_STRING_IPV6_ADDRESS) +#define NET_STRING_IP_ADDRESS_NO_SCOPE (NET_STRING_IPV4_ADDRESS|NET_STRING_IPV6_ADDRESS_NO_SCOPE) +#define NET_STRING_IP_SERVICE (NET_STRING_IPV4_SERVICE|NET_STRING_IPV6_SERVICE) +#define NET_STRING_IP_SERVICE_NO_SCOPE (NET_STRING_IPV4_SERVICE|NET_STRING_IPV6_SERVICE_NO_SCOPE) +#define NET_STRING_IP_NETWORK (NET_STRING_IPV4_NETWORK|NET_STRING_IPV6_NETWORK) +#define NET_STRING_ANY_ADDRESS (NET_STRING_NAMED_ADDRESS|NET_STRING_IP_ADDRESS) +#define NET_STRING_ANY_ADDRESS_NO_SCOPE (NET_STRING_NAMED_ADDRESS|NET_STRING_IP_ADDRESS_NO_SCOPE) +#define NET_STRING_ANY_SERVICE (NET_STRING_NAMED_SERVICE|NET_STRING_IP_SERVICE) +#define NET_STRING_ANY_SERVICE_NO_SCOPE (NET_STRING_NAMED_SERVICE|NET_STRING_IP_SERVICE_NO_SCOPE) + DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder, ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved);
@@ -162,6 +182,33 @@ DWORD WINAPI AllocateAndGetTcpExTableFromStack(VOID **ppTcpTable, BOOL bOrder, H DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder, HANDLE heap, DWORD flags); DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder, HANDLE heap, DWORD flags);
+#ifdef __WINE_WINDNS_H + +typedef enum NET_ADDRESS_FORMAT_ { + NET_ADDRESS_FORMAT_UNSPECIFIED, + NET_ADDRESS_DNS_NAME, + NET_ADDRESS_IPV4, + NET_ADDRESS_IPV6, +} NET_ADDRESS_FORMAT; + +typedef struct NET_ADDRESS_INFO_ +{ + NET_ADDRESS_FORMAT Format; + union + { + struct + { + WCHAR Address[DNS_MAX_NAME_BUFFER_LENGTH]; + WCHAR Port[6]; + } NamedAddress; + SOCKADDR_IN Ipv4Address; + SOCKADDR_IN6 Ipv6Address; + SOCKADDR IpAddress; + } DUMMYUNIONNAME; +} NET_ADDRESS_INFO, *PNET_ADDRESS_INFO; + +#endif /* __WINE_WINDNS_H */ + #ifdef __cplusplus } #endif diff --git a/include/windns.h b/include/windns.h index d9a4b9adb0..9a31fac604 100644 --- a/include/windns.h +++ b/include/windns.h @@ -177,6 +177,7 @@ typedef struct #define DNS_ADDRESS_STRING_LENGTH IP6_ADDRESS_STRING_LENGTH #define IP4_ADDRESS_STRING_BUFFER_LENGTH IP4_ADDRESS_STRING_LENGTH #define IP6_ADDRESS_STRING_BUFFER_LENGTH IP6_ADDRESS_STRING_LENGTH +#define DNS_MAX_NAME_BUFFER_LENGTH 256
typedef struct _IP4_ARRAY {
Signed-off-by: Alex Henrie alexhenrie24@gmail.com --- dlls/iphlpapi/tests/iphlpapi.c | 111 +++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+)
diff --git a/dlls/iphlpapi/tests/iphlpapi.c b/dlls/iphlpapi/tests/iphlpapi.c index a2be8622e5..d4b1100af6 100644 --- a/dlls/iphlpapi/tests/iphlpapi.c +++ b/dlls/iphlpapi/tests/iphlpapi.c @@ -39,6 +39,7 @@ #include "windef.h" #include "winbase.h" #include "ws2tcpip.h" +#include "windns.h" #include "iphlpapi.h" #include "iprtrmib.h" #include "netioapi.h" @@ -98,6 +99,7 @@ static DWORD (WINAPI *pConvertInterfaceLuidToNameA)(const NET_LUID*,char*,SIZE_T static DWORD (WINAPI *pConvertInterfaceNameToLuidA)(const char*,NET_LUID*); static DWORD (WINAPI *pConvertInterfaceNameToLuidW)(const WCHAR*,NET_LUID*); static DWORD (WINAPI *pConvertLengthToIpv4Mask)(ULONG,ULONG*); +static DWORD (WINAPI *pParseNetworkString)(const WCHAR*,DWORD,NET_ADDRESS_INFO*,USHORT*,BYTE*);
static PCHAR (WINAPI *pif_indextoname)(NET_IFINDEX,PCHAR); static NET_IFINDEX (WINAPI *pif_nametoindex)(const char*); @@ -153,6 +155,7 @@ static void loadIPHlpApi(void) pConvertInterfaceNameToLuidA = (void *)GetProcAddress(hLibrary, "ConvertInterfaceNameToLuidA"); pConvertInterfaceNameToLuidW = (void *)GetProcAddress(hLibrary, "ConvertInterfaceNameToLuidW"); pConvertLengthToIpv4Mask = (void *)GetProcAddress(hLibrary, "ConvertLengthToIpv4Mask"); + pParseNetworkString = (void *)GetProcAddress(hLibrary, "ParseNetworkString"); pif_indextoname = (void *)GetProcAddress(hLibrary, "if_indextoname"); pif_nametoindex = (void *)GetProcAddress(hLibrary, "if_nametoindex"); } @@ -2271,6 +2274,113 @@ static void test_GetUdp6Table(void) } }
+static void test_ParseNetworkString(void) +{ + struct + { + char str[32]; + IN_ADDR addr; + DWORD ret; + } + ipv4_address_tests[] = + { + {"1.2.3.4", {{{1, 2, 3, 4}}}}, + {"1.2.3.4a", {}, ERROR_INVALID_PARAMETER}, + {"1.2.3.0x4a", {}, ERROR_INVALID_PARAMETER}, + {"1.2.3", {}, ERROR_INVALID_PARAMETER}, + {"a1.2.3.4", {}, ERROR_INVALID_PARAMETER}, + {"0xdeadbeef", {}, ERROR_INVALID_PARAMETER}, + {"1.2.3.4:22", {}, ERROR_INVALID_PARAMETER}, + {"::1", {}, ERROR_INVALID_PARAMETER}, + {"winehq.org", {}, ERROR_INVALID_PARAMETER}, + }; + struct + { + char str[32]; + IN_ADDR addr; + DWORD port; + DWORD ret; + } + ipv4_service_tests[] = + { + {"1.2.3.4:22", {{{1, 2, 3, 4}}}, 22}, + {"winehq.org:22", {}, 0, ERROR_INVALID_PARAMETER}, + {"1.2.3.4", {}, 0, ERROR_INVALID_PARAMETER}, + {"1.2.3.4:0", {}, 0, ERROR_INVALID_PARAMETER}, + {"1.2.3.4:65536", {}, 0, ERROR_INVALID_PARAMETER}, + }; + WCHAR wstr[IP6_ADDRESS_STRING_BUFFER_LENGTH] = {'1','2','7','.','0','.','0','.','1',':','2','2',0}; + NET_ADDRESS_INFO info; + USHORT port; + BYTE prefix_len; + DWORD ret; + int i; + + if (!pParseNetworkString) + { + skip("ParseNetworkString not available\n"); + return; + } + + ret = pParseNetworkString(wstr, -1, NULL, NULL, NULL); + ok(ret == ERROR_SUCCESS, "expected success, got %d\n", ret); + + ret = pParseNetworkString(NULL, NET_STRING_IPV4_SERVICE, &info, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", ret); + + for (i = 0; i < ARRAY_SIZE(ipv4_address_tests); i++) + { + MultiByteToWideChar(CP_ACP, 0, ipv4_address_tests[i].str, sizeof(ipv4_address_tests[i].str), + wstr, sizeof(wstr)); + memset(&info, 0x99, sizeof(info)); + port = 0x9999; + prefix_len = 0x99; + + ret = pParseNetworkString(wstr, NET_STRING_IPV4_ADDRESS, &info, &port, &prefix_len); + + ok(ret == ipv4_address_tests[i].ret, + "%s gave error %d\n", ipv4_address_tests[i].str, ret); + ok(info.Format == ret ? NET_ADDRESS_FORMAT_UNSPECIFIED : NET_ADDRESS_IPV4, + "%s gave format %d\n", ipv4_address_tests[i].str, info.Format); + ok(info.Ipv4Address.sin_addr.S_un.S_addr == (ret ? 0x99999999 : ipv4_address_tests[i].addr.S_un.S_addr), + "%s gave address %d.%d.%d.%d\n", ipv4_address_tests[i].str, + info.Ipv4Address.sin_addr.S_un.S_un_b.s_b1, info.Ipv4Address.sin_addr.S_un.S_un_b.s_b2, + info.Ipv4Address.sin_addr.S_un.S_un_b.s_b3, info.Ipv4Address.sin_addr.S_un.S_un_b.s_b4); + ok(info.Ipv4Address.sin_port == (ret ? 0x9999 : 0), + "%s gave port %d\n", ipv4_service_tests[i].str, ntohs(info.Ipv4Address.sin_port)); + ok(port == (ret ? 0x9999 : 0), + "%s gave port %d\n", ipv4_service_tests[i].str, port); + ok(prefix_len == (ret ? 0x99 : 255), + "%s gave prefix length %d\n", ipv4_service_tests[i].str, prefix_len); + } + + for (i = 0; i < ARRAY_SIZE(ipv4_service_tests); i++) + { + MultiByteToWideChar(CP_ACP, 0, ipv4_service_tests[i].str, sizeof(ipv4_service_tests[i].str), + wstr, sizeof(wstr)); + memset(&info, 0x99, sizeof(info)); + port = 0x9999; + prefix_len = 0x99; + + ret = pParseNetworkString(wstr, NET_STRING_IPV4_SERVICE, &info, &port, &prefix_len); + + ok(ret == ipv4_service_tests[i].ret, + "%s gave error %d\n", ipv4_service_tests[i].str, ret); + ok(info.Format == ret ? NET_ADDRESS_FORMAT_UNSPECIFIED : NET_ADDRESS_IPV4, + "%s gave format %d\n", ipv4_address_tests[i].str, info.Format); + ok(info.Ipv4Address.sin_addr.S_un.S_addr == (ret ? 0x99999999 : ipv4_service_tests[i].addr.S_un.S_addr), + "%s gave address %d.%d.%d.%d\n", ipv4_service_tests[i].str, + info.Ipv4Address.sin_addr.S_un.S_un_b.s_b1, info.Ipv4Address.sin_addr.S_un.S_un_b.s_b2, + info.Ipv4Address.sin_addr.S_un.S_un_b.s_b3, info.Ipv4Address.sin_addr.S_un.S_un_b.s_b4); + ok(ntohs(info.Ipv4Address.sin_port) == (ret ? 0x9999 : ipv4_service_tests[i].port), + "%s gave port %d\n", ipv4_service_tests[i].str, ntohs(info.Ipv4Address.sin_port)); + ok(port == (ret ? 0x9999 : ipv4_service_tests[i].port), + "%s gave port %d\n", ipv4_service_tests[i].str, port); + ok(prefix_len == (ret ? 0x99 : 255), + "%s gave prefix length %d\n", ipv4_service_tests[i].str, prefix_len); + } +} + START_TEST(iphlpapi) {
@@ -2300,6 +2410,7 @@ START_TEST(iphlpapi) test_GetUnicastIpAddressTable(); test_ConvertLengthToIpv4Mask(); test_GetUdp6Table(); + test_ParseNetworkString(); freeIPHlpApi(); } }
Signed-off-by: Alex Henrie alexhenrie24@gmail.com --- include/ip2string.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 include/ip2string.h
diff --git a/include/ip2string.h b/include/ip2string.h new file mode 100644 index 0000000000..390ac7efd6 --- /dev/null +++ b/include/ip2string.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2019 Alex Henrie + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +NTSTATUS WINAPI RtlIpv4StringToAddressA(const char *str, BOOLEAN strict, const char **terminator, IN_ADDR *address); +NTSTATUS WINAPI RtlIpv4StringToAddressExA(const char *str, BOOLEAN strict, IN_ADDR *address, USHORT *port); +NTSTATUS WINAPI RtlIpv4StringToAddressExW(const WCHAR *str, BOOLEAN strict, IN_ADDR *address, USHORT *port); +NTSTATUS WINAPI RtlIpv4StringToAddressW(const WCHAR *str, BOOLEAN strict, const WCHAR **terminator, IN_ADDR *address);
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45560 Signed-off-by: Alex Henrie alexhenrie24@gmail.com --- dlls/iphlpapi/iphlpapi.spec | 2 +- dlls/iphlpapi/iphlpapi_main.c | 61 +++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-)
diff --git a/dlls/iphlpapi/iphlpapi.spec b/dlls/iphlpapi/iphlpapi.spec index abc7152b6b..c5857f2831 100644 --- a/dlls/iphlpapi/iphlpapi.spec +++ b/dlls/iphlpapi/iphlpapi.spec @@ -243,7 +243,7 @@ @ stdcall NotifyUnicastIpAddressChange(long ptr ptr long ptr) #@ stub NTPTimeToNTFileTime #@ stub NTTimeToNTPTime -#@ stub ParseNetworkString +@ stdcall ParseNetworkString(wstr long ptr ptr ptr) @ stub _PfAddFiltersToInterface@24 @ stub _PfAddGlobalFilterToInterface@8 @ stdcall _PfBindInterfaceToIPAddress@12(long long ptr) PfBindInterfaceToIPAddress diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c index f1aa0d1e04..1f823b401d 100644 --- a/dlls/iphlpapi/iphlpapi_main.c +++ b/dlls/iphlpapi/iphlpapi_main.c @@ -46,6 +46,7 @@ #include "winsock2.h" #include "winternl.h" #include "ws2ipdef.h" +#include "windns.h" #include "iphlpapi.h" #include "ifenum.h" #include "ipstats.h" @@ -54,6 +55,7 @@ #include "ifdef.h" #include "netioapi.h" #include "tcpestats.h" +#include "ip2string.h"
#include "wine/debug.h" #include "wine/unicode.h" @@ -3333,3 +3335,62 @@ DWORD WINAPI GetBestRoute2(NET_LUID *luid, NET_IFINDEX index,
return ERROR_NOT_SUPPORTED; } + +/****************************************************************** + * ParseNetworkString (IPHLPAPI.@) + */ +DWORD WINAPI ParseNetworkString(const WCHAR *str, DWORD type, + NET_ADDRESS_INFO *info, USHORT *port, BYTE *prefix_len) +{ + IN_ADDR temp_addr4; + USHORT temp_port = 0; + NTSTATUS status; + + TRACE("(%s, %d, %p, %p, %p)\n", debugstr_w(str), type, info, port, prefix_len); + + if (!str) + return ERROR_INVALID_PARAMETER; + + if (type & NET_STRING_IPV4_ADDRESS) + { + status = RtlIpv4StringToAddressExW(str, TRUE, &temp_addr4, &temp_port); + if (SUCCEEDED(status) && !temp_port) + { + if (info) + { + info->Format = NET_ADDRESS_IPV4; + info->u.Ipv4Address.sin_addr = temp_addr4; + info->u.Ipv4Address.sin_port = 0; + } + if (port) *port = 0; + if (prefix_len) *prefix_len = 255; + return ERROR_SUCCESS; + } + } + if (type & NET_STRING_IPV4_SERVICE) + { + status = RtlIpv4StringToAddressExW(str, TRUE, &temp_addr4, &temp_port); + if (SUCCEEDED(status) && temp_port) + { + if (info) + { + info->Format = NET_ADDRESS_IPV4; + info->u.Ipv4Address.sin_addr = temp_addr4; + info->u.Ipv4Address.sin_port = temp_port; + } + if (port) *port = ntohs(temp_port); + if (prefix_len) *prefix_len = 255; + return ERROR_SUCCESS; + } + } + + if (info) info->Format = NET_ADDRESS_FORMAT_UNSPECIFIED; + + if (type & ~(NET_STRING_IPV4_ADDRESS|NET_STRING_IPV4_SERVICE)) + { + FIXME("Unimplemented type 0x%x\n", type); + return ERROR_NOT_SUPPORTED; + } + + return ERROR_INVALID_PARAMETER; +}