From 0af08318b75bd31928c31c875239c0f863ab4e0d Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Mon, 25 May 2020 22:36:23 -0600 Subject: [PATCH] ntdll: Implement RtlIpv6AddressToString(Ex)[AW]. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46788 Signed-off-by: Alex Henrie Signed-off-by: Alexandre Julliard --- dlls/ntdll/ntdll.spec | 8 +- dlls/ntdll/rtl.c | 129 ++++++++++++++++++++++++++++ dlls/ntdll/tests/rtl.c | 14 +-- dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 8 +- include/ip2string.h | 7 ++ 5 files changed, 147 insertions(+), 19 deletions(-) diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 7ae8a6071dc..6bd0a599a90 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -784,10 +784,10 @@ @ stdcall RtlIpv4StringToAddressExA(str long ptr ptr) @ stdcall RtlIpv4StringToAddressExW(wstr long ptr ptr) @ stdcall RtlIpv4StringToAddressW(wstr long ptr ptr) -# @ stub RtlIpv6AddressToStringA -# @ stub RtlIpv6AddressToStringExA -# @ stub RtlIpv6AddressToStringExW -# @ stub RtlIpv6AddressToStringW +@ stdcall RtlIpv6AddressToStringA(ptr ptr) +@ stdcall RtlIpv6AddressToStringExA(ptr long long ptr ptr) +@ stdcall RtlIpv6AddressToStringExW(ptr long long ptr ptr) +@ stdcall RtlIpv6AddressToStringW(ptr ptr) @ stdcall RtlIpv6StringToAddressA(str ptr ptr) @ stdcall RtlIpv6StringToAddressExA(str ptr ptr ptr) @ stdcall RtlIpv6StringToAddressExW(wstr ptr ptr ptr) diff --git a/dlls/ntdll/rtl.c b/dlls/ntdll/rtl.c index 003e4a1b3ba..bf91423eba9 100644 --- a/dlls/ntdll/rtl.c +++ b/dlls/ntdll/rtl.c @@ -1412,6 +1412,135 @@ CHAR * WINAPI RtlIpv4AddressToStringA(const IN_ADDR *pin, LPSTR buffer) return buffer + size - 1; } +static BOOL is_ipv4_in_ipv6(const IN6_ADDR *address) +{ + if (address->s6_words[5] == htons(0x5efe) && (address->s6_words[4] & ~htons(0x200)) == 0) + return TRUE; + if (*(UINT64 *)address != 0) + return FALSE; + if (address->s6_words[4] != 0 && address->s6_words[4] != 0xffff) + return FALSE; + if (address->s6_words[4] == 0 && address->s6_words[5] != 0 && address->s6_words[5] != 0xffff) + return FALSE; + if (address->s6_words[4] == 0xffff && address->s6_words[5] != 0) + return FALSE; + if (address->s6_words[6] == 0) + return FALSE; + return TRUE; +} + +/*********************************************************************** + * RtlIpv6AddressToStringExA [NTDLL.@] + */ +NTSTATUS WINAPI RtlIpv6AddressToStringExA(const IN6_ADDR *address, ULONG scope, USHORT port, char *str, ULONG *size) +{ + char buffer[64], *p = buffer; + int i, len, gap = -1, gap_len = 1, ipv6_end = 8; + ULONG needed; + NTSTATUS ret; + + TRACE("(%p %u %u %p %p)\n", address, scope, port, str, size); + + if (!address || !str || !size) + return STATUS_INVALID_PARAMETER; + + if (is_ipv4_in_ipv6(address)) + ipv6_end = 6; + + for (i = 0; i < ipv6_end; i++) + { + len = 0; + while (!address->s6_words[i] && i < ipv6_end) + { + i++; + len++; + } + if (len > gap_len) + { + gap = i - len; + gap_len = len; + } + } + + if (port) p += sprintf(p, "["); + + i = 0; + while (i < ipv6_end) + { + if (i == gap) + { + p += sprintf(p, ":"); + i += gap_len; + if (i == ipv6_end) p += sprintf(p, ":"); + continue; + } + if (i > 0) p += sprintf(p, ":"); + p += sprintf(p, "%x", ntohs(address->s6_words[i])); + i++; + } + + if (ipv6_end == 6) + { + if (p[-1] != ':') p += sprintf(p, ":"); + p = RtlIpv4AddressToStringA((IN_ADDR *)(address->s6_words + 6), p); + } + + if (scope) p += sprintf(p, "%%%u", scope); + + if (port) p += sprintf(p, "]:%u", ntohs(port)); + + needed = p - buffer + 1; + + if (*size >= needed) + { + strcpy(str, buffer); + ret = STATUS_SUCCESS; + } + else + { + ret = STATUS_INVALID_PARAMETER; + } + + *size = needed; + return ret; +} + +/*********************************************************************** + * RtlIpv6AddressToStringA [NTDLL.@] + */ +char * WINAPI RtlIpv6AddressToStringA(const IN6_ADDR *address, char *str) +{ + ULONG size = 46; + if (!address || !str) return str - 1; + str[45] = 0; /* this byte is set even though the string is always shorter */ + RtlIpv6AddressToStringExA(address, 0, 0, str, &size); + return str + size - 1; +} + +/*********************************************************************** + * RtlIpv6AddressToStringExW [NTDLL.@] + */ +NTSTATUS WINAPI RtlIpv6AddressToStringExW(const IN6_ADDR *address, ULONG scope, USHORT port, WCHAR *str, ULONG *size) +{ + char cstr[64]; + NTSTATUS ret = RtlIpv6AddressToStringExA(address, scope, port, cstr, size); + if (ret == STATUS_SUCCESS) RtlMultiByteToUnicodeN(str, *size * sizeof(WCHAR), NULL, cstr, *size); + return ret; +} + +/*********************************************************************** + * RtlIpv6AddressToStringW [NTDLL.@] + */ +WCHAR * WINAPI RtlIpv6AddressToStringW(const IN6_ADDR *address, WCHAR *str) +{ + ULONG size = 46; + if (!address || !str) return str; + str[45] = 0; /* this word is set even though the string is always shorter */ + if (RtlIpv6AddressToStringExW(address, 0, 0, str, &size) != STATUS_SUCCESS) + return str; + return str + size - 1; +} + /*********************************************************************** * get_pointer_obfuscator (internal) */ diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index f83031b4905..94c6b582f36 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -73,7 +73,6 @@ static DWORD (WINAPI *pRtlGetThreadErrorMode)(void); static NTSTATUS (WINAPI *pRtlSetThreadErrorMode)(DWORD, LPDWORD); static NTSTATUS (WINAPI *pRtlIpv4AddressToStringExA)(const IN_ADDR *, USHORT, LPSTR, PULONG); static NTSTATUS (WINAPI *pRtlIpv4StringToAddressExA)(PCSTR, BOOLEAN, IN_ADDR *, PUSHORT); -static CHAR * (WINAPI *pRtlIpv6AddressToStringA)(struct in6_addr *, PSTR); static NTSTATUS (WINAPI *pRtlIpv6AddressToStringExA)(struct in6_addr *, ULONG, USHORT, PCHAR, PULONG); static NTSTATUS (WINAPI *pRtlIpv6StringToAddressExA)(PCSTR, struct in6_addr *, PULONG, PUSHORT); static NTSTATUS (WINAPI *pRtlIpv6StringToAddressExW)(PCWSTR, struct in6_addr *, PULONG, PUSHORT); @@ -114,7 +113,6 @@ static void InitFunctionPtrs(void) pRtlSetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlSetThreadErrorMode"); pRtlIpv4AddressToStringExA = (void *)GetProcAddress(hntdll, "RtlIpv4AddressToStringExA"); pRtlIpv4StringToAddressExA = (void *)GetProcAddress(hntdll, "RtlIpv4StringToAddressExA"); - pRtlIpv6AddressToStringA = (void *)GetProcAddress(hntdll, "RtlIpv6AddressToStringA"); pRtlIpv6AddressToStringExA = (void *)GetProcAddress(hntdll, "RtlIpv6AddressToStringExA"); pRtlIpv6StringToAddressExA = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressExA"); pRtlIpv6StringToAddressExW = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressExW"); @@ -1801,22 +1799,16 @@ static void test_RtlIpv6AddressToString(void) }; unsigned int i; - if (!pRtlIpv6AddressToStringA) - { - skip("RtlIpv6AddressToStringA not available\n"); - return; - } - memset(buffer, '#', sizeof(buffer)); buffer[sizeof(buffer)-1] = 0; memset(&ip, 0, sizeof(ip)); - result = pRtlIpv6AddressToStringA(&ip, buffer); + result = RtlIpv6AddressToStringA(&ip, buffer); len = strlen(buffer); ok(result == (buffer + len) && !strcmp(buffer, "::"), "got %p with '%s' (expected %p with '::')\n", result, buffer, buffer + len); - result = pRtlIpv6AddressToStringA(&ip, NULL); + result = RtlIpv6AddressToStringA(&ip, NULL); ok(result == (LPCSTR)~0 || broken(result == (LPCSTR)len) /* WinXP / Win2k3 */, "got %p, expected %p\n", result, (LPCSTR)~0); @@ -1826,7 +1818,7 @@ static void test_RtlIpv6AddressToString(void) memset(buffer, '#', sizeof(buffer)); buffer[sizeof(buffer)-1] = 0; - result = pRtlIpv6AddressToStringA(&ip, buffer); + result = RtlIpv6AddressToStringA(&ip, buffer); len = strlen(buffer); ok(result == (buffer + len) && !strcmp(buffer, tests[i].address), "got %p with '%s' (expected %p with '%s')\n", result, buffer, buffer + len, tests[i].address); diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index f25ab9c5e01..f80709a9a0f 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -1134,10 +1134,10 @@ @ stdcall RtlIpv4StringToAddressExA(str long ptr ptr) @ stdcall RtlIpv4StringToAddressExW(wstr long ptr ptr) @ stdcall RtlIpv4StringToAddressW(wstr long ptr ptr) -@ stub RtlIpv6AddressToStringA -@ stub RtlIpv6AddressToStringExA -@ stub RtlIpv6AddressToStringExW -@ stub RtlIpv6AddressToStringW +@ stdcall RtlIpv6AddressToStringA(ptr ptr) +@ stdcall RtlIpv6AddressToStringExA(ptr long long ptr ptr) +@ stdcall RtlIpv6AddressToStringExW(ptr long long ptr ptr) +@ stdcall RtlIpv6AddressToStringW(ptr ptr) @ stdcall RtlIpv6StringToAddressA(str ptr ptr) @ stdcall RtlIpv6StringToAddressExA(str ptr ptr ptr) @ stdcall RtlIpv6StringToAddressExW(wstr ptr ptr ptr) diff --git a/include/ip2string.h b/include/ip2string.h index 4c5f36c15f6..84835d45933 100644 --- a/include/ip2string.h +++ b/include/ip2string.h @@ -30,6 +30,13 @@ NTSTATUS WINAPI RtlIpv4AddressToStringExA(const IN_ADDR *address, USHORT port, c NTSTATUS WINAPI RtlIpv4AddressToStringExW(const IN_ADDR *address, USHORT port, WCHAR *str, ULONG *size); #define RtlIpv4AddressToStringEx WINELIB_NAME_AW(RtlIpv4AddressToStringEx) +char * WINAPI RtlIpv6AddressToStringA(const IN6_ADDR *address, char *str); +WCHAR * WINAPI RtlIpv6AddressToStringW(const IN6_ADDR *address, WCHAR *str); +#define RtlIpv6AddressToString WINELIB_NAME_AW(RtlIpv6AddressToString) +NTSTATUS WINAPI RtlIpv6AddressToStringExA(const IN6_ADDR *address, LONG scope, USHORT port, char *str, ULONG *size); +NTSTATUS WINAPI RtlIpv6AddressToStringExW(const IN6_ADDR *address, LONG scope, USHORT port, WCHAR *str, ULONG *size); +#define RtlIpv6AddressToStringEx WINELIB_NAME_AW(RtlIpv6AddressToStringEx) + NTSTATUS WINAPI RtlIpv4StringToAddressA(const char *str, BOOLEAN strict, const char **terminator, IN_ADDR *address); NTSTATUS WINAPI RtlIpv4StringToAddressW(const WCHAR *str, BOOLEAN strict, const WCHAR **terminator, IN_ADDR *address); #define RtlIpv4StringToAddress WINELIB_NAME_AW(RtlIpv4StringToAddress)