wine-staging/patches/ntdll-RtlIpv4StringToAddress/0001-ntdll-Implement-RtlIpv6StringToAddress-Ex-AW.patch

332 lines
12 KiB
Diff
Raw Normal View History

From 816aa308b6a808839760e69679f38498cdd0f4df Mon Sep 17 00:00:00 2001
From: Alex Henrie <alexhenrie24@gmail.com>
Date: Mon, 27 Jan 2020 23:08:43 -0700
Subject: [PATCH 1/5] ntdll: Implement RtlIpv6StringToAddress(Ex)[AW]
Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
---
dlls/ntdll/ntdll.spec | 6 +-
dlls/ntdll/rtl.c | 245 +++++++++++++++++++++++++++++++++++++-----
2 files changed, 222 insertions(+), 29 deletions(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index fe36235bda..bcd9950a76 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -778,10 +778,10 @@
# @ stub RtlIpv6AddressToStringExA
# @ stub RtlIpv6AddressToStringExW
# @ stub RtlIpv6AddressToStringW
-# @ stub RtlIpv6StringToAddressA
-# @ stub RtlIpv6StringToAddressExA
+@ stdcall RtlIpv6StringToAddressA(str ptr ptr)
+@ stdcall RtlIpv6StringToAddressExA(str ptr ptr)
@ stdcall RtlIpv6StringToAddressExW(wstr ptr ptr ptr)
-# @ stub RtlIpv6StringToAddressW
+@ stdcall RtlIpv6StringToAddressW(wstr ptr ptr ptr)
@ stdcall RtlIsActivationContextActive(ptr)
@ stdcall RtlIsCriticalSectionLocked(ptr)
@ stdcall RtlIsCriticalSectionLockedByThread(ptr)
diff --git a/dlls/ntdll/rtl.c b/dlls/ntdll/rtl.c
index 15ff037fef..12c0ed430d 100644
--- a/dlls/ntdll/rtl.c
+++ b/dlls/ntdll/rtl.c
@@ -98,6 +98,21 @@ static const DWORD CRC_table[256] =
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
+static const int hex_table[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0F */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1F */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2F */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0x30-0x3F */
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4F */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5F */
+ -1, 10, 11, 12, 13, 14, 15 /* 0x60-0x66 */
+};
+
+static BOOL is_hex(WCHAR c)
+{
+ return c < ARRAY_SIZE(hex_table) && hex_table[c] != -1;
+}
+
/*
* resource functions
*/
@@ -884,18 +899,9 @@ void WINAPI RtlCopyLuidAndAttributesArray(
for (i = 0; i < Count; i++) Dest[i] = Src[i];
}
-static BOOL parse_ipv4_component(const WCHAR **str, BOOL strict, ULONG *value)
+static BOOL parse_ip_component(const WCHAR **str, int base, BOOL strict, ULONG *value)
{
- static const int hex_table[] = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2F */
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0x30-0x3F */
- -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5F */
- -1, 10, 11, 12, 13, 14, 15 /* 0x60-0x66 */
- };
- int base = 10, d;
+ int d;
WCHAR c;
ULONG cur_value, prev_value = 0;
BOOL success = FALSE;
@@ -906,19 +912,23 @@ static BOOL parse_ipv4_component(const WCHAR **str, BOOL strict, ULONG *value)
return FALSE;
}
- if ((*str)[0] == '0')
+ if (!base)
{
- if ((*str)[1] == 'x' || (*str)[1] == 'X')
+ base = 10;
+ if ((*str)[0] == '0')
{
- *str += 2;
- if (strict) return FALSE;
- base = 16;
- }
- else if ((*str)[1] >= '0' && (*str)[1] <= '9')
- {
- *str += 1;
- if (strict) return FALSE;
- base = 8;
+ if ((*str)[1] == 'x' || (*str)[1] == 'X')
+ {
+ *str += 2;
+ if (strict) return FALSE;
+ base = 16;
+ }
+ else if ((*str)[1] >= '0' && (*str)[1] <= '9')
+ {
+ *str += 1;
+ if (strict) return FALSE;
+ base = 8;
+ }
}
}
@@ -946,7 +956,7 @@ static NTSTATUS ipv4_string_to_address(const WCHAR *str, BOOL strict,
for (;;)
{
- if (!parse_ipv4_component(&str, strict, &fields[n]))
+ if (!parse_ip_component(&str, 0, strict, &fields[n]))
goto error;
n++;
if (*str != '.')
@@ -1000,7 +1010,7 @@ static NTSTATUS ipv4_string_to_address(const WCHAR *str, BOOL strict,
if (*str == ':')
{
str++;
- if (!parse_ipv4_component(&str, FALSE, &fields[0]))
+ if (!parse_ip_component(&str, 0, FALSE, &fields[0]))
goto error;
if (!fields[0] || fields[0] > 0xFFFF || *str)
goto error;
@@ -1074,13 +1084,196 @@ NTSTATUS WINAPI RtlIpv4StringToAddressA(const char *str, BOOLEAN strict, const c
return ret;
}
+static NTSTATUS ipv6_string_to_address(const WCHAR *str, BOOL ex,
+ const WCHAR **terminator, IN6_ADDR *address, ULONG *scope, USHORT *port)
+{
+ static const WCHAR hex_digits[] = {
+ '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','A','B','C','D','E','F',0
+ };
+ BOOL expecting_port = FALSE, ipv4_in_hex = FALSE;
+ int n_bytes = 0, n_ipv4_bytes = 0, gap = -1;
+ ULONG ip_component, scope_component = 0, port_component = 0;
+ const WCHAR *component_terminator;
+
+ size_t component_len;
+ WCHAR delimiter;
+
+ if (str[0] == '[')
+ {
+ if (!ex) goto error;
+ expecting_port = TRUE;
+ str++;
+ }
+
+ if (str[0] == ':')
+ {
+ if (str[1] != ':') goto error;
+ /* Windows bug: a double colon at the beginning is treated as 4 bytes of zeros instead of 2 */
+ address->u.Word[0] = 0;
+ address->u.Word[1] = 0;
+ n_bytes += 4;
+ str++;
+ }
+
+ for (;;)
+ {
+ component_len = strspnW(str, hex_digits);
+ delimiter = str[component_len];
+ if (terminator && delimiter != ':' && delimiter != '.') *terminator = str + component_len;
+ if (!n_ipv4_bytes && str[0] == '0' && (str[1] == 'x' || str[1] == 'X') && is_hex(str[2]))
+ {
+ /* IPv4 address as single hex value */
+ if (n_bytes > 12) goto error;
+ component_terminator = str + 2;
+ if (!parse_ip_component(&component_terminator, 16, TRUE, &ip_component)) goto error;
+ if (terminator) *terminator = str + 1; /* Windows bug: terminator is off by 1 */
+ if (gap == -1 && *component_terminator == ':') return STATUS_INVALID_PARAMETER;
+ address->u.Byte[n_bytes++] = (ip_component & 0xFF000000) >> 24;
+ address->u.Byte[n_bytes++] = (ip_component & 0x00FF0000) >> 16;
+ address->u.Byte[n_bytes++] = (ip_component & 0x0000FF00) >> 8;
+ address->u.Byte[n_bytes++] = (ip_component & 0x000000FF);
+ str = component_terminator;
+ ipv4_in_hex = TRUE;
+ goto fill_gap;
+ }
+ if (!n_ipv4_bytes && delimiter == '.' && n_bytes <= 12) n_ipv4_bytes = 1;
+ if (n_ipv4_bytes)
+ {
+ /* dotted IPv4 address */
+ if (!parse_ip_component(&str, 0, TRUE, &ip_component)) goto error;
+ if (ip_component > 255) return STATUS_INVALID_PARAMETER;
+ if (delimiter != '.' && (n_ipv4_bytes < 4 || (n_bytes < 15 && gap == -1))) goto error;
+ address->u.Byte[n_bytes] = ip_component;
+ n_bytes++;
+ if (n_ipv4_bytes == 4) break;
+ n_ipv4_bytes++;
+ }
+ else
+ {
+ /* IPv6 */
+ if (*str == ':')
+ {
+ gap = n_bytes;
+ if (!is_hex(str[1]))
+ {
+ str++;
+ break;
+ }
+ }
+ else
+ {
+ if (!parse_ip_component(&str, 16, TRUE, &ip_component)) goto error;
+ if (component_len > 4) return STATUS_INVALID_PARAMETER;
+ if (delimiter != ':' && n_bytes < 14 && gap == -1) goto error;
+ address->u.Word[n_bytes/2] = htons(ip_component);
+ n_bytes += 2;
+ }
+ }
+ if (n_bytes == 16 || *str != delimiter || (delimiter != ':' && delimiter != '.')) break;
+ if (gap != -1 && str[0] == ':' && str[1] == ':') break;
+ str++;
+ }
+
+ if (terminator) *terminator = str;
+
+fill_gap:
+ if (gap == -1)
+ {
+ if (n_bytes < 16) goto error;
+ }
+ else
+ {
+ memmove(address->u.Byte + 16 - (n_bytes - gap), address->u.Byte + gap, n_bytes - gap);
+ memset(address->u.Byte + gap, 0, 16 - n_bytes);
+ }
+
+ if (ex)
+ {
+ if (ipv4_in_hex) goto error;
+
+ if (*str == '%')
+ {
+ str++;
+ if (!parse_ip_component(&str, 10, TRUE, &scope_component)) goto error;
+ }
+
+ if (expecting_port)
+ {
+ if (*str != ']') goto error;
+ str++;
+ if (*str == ':')
+ {
+ str++;
+ if (!parse_ip_component(&str, 0, FALSE, &port_component)) goto error;
+ if (!port_component || port_component > 0xFFFF || *str) goto error;
+ port_component = htons(port_component);
+ }
+ }
+ }
+
+ if (!terminator && *str) return STATUS_INVALID_PARAMETER;
+
+ if (scope) *scope = scope_component;
+ if (port) *port = port_component;
+
+ return STATUS_SUCCESS;
+
+error:
+ if (terminator) *terminator = str;
+ return STATUS_INVALID_PARAMETER;
+}
+
/***********************************************************************
* RtlIpv6StringToAddressExW [NTDLL.@]
*/
NTSTATUS NTAPI RtlIpv6StringToAddressExW(const WCHAR *str, IN6_ADDR *address, ULONG *scope, USHORT *port)
{
- FIXME("(%s, %p, %p, %p): stub\n", debugstr_w(str), address, scope, port);
- return STATUS_NOT_IMPLEMENTED;
+ TRACE("(%s, %p, %p, %p)\n", debugstr_w(str), address, scope, port);
+ return ipv6_string_to_address(str, TRUE, NULL, address, scope, port);
+}
+
+/***********************************************************************
+ * RtlIpv6StringToAddressW [NTDLL.@]
+ */
+NTSTATUS WINAPI RtlIpv6StringToAddressW(const WCHAR *str, const WCHAR **terminator, IN6_ADDR *address)
+{
+ TRACE("(%s, %p, %p)\n", debugstr_w(str), terminator, address);
+ return ipv6_string_to_address(str, FALSE, terminator, address, NULL, NULL);
+}
+
+/***********************************************************************
+ * RtlIpv6StringToAddressExA [NTDLL.@]
+ */
+NTSTATUS WINAPI RtlIpv6StringToAddressExA(const char *str, IN6_ADDR *address, ULONG *scope, USHORT *port)
+{
+ WCHAR wstr[64];
+
+ TRACE("(%s, %p, %p, %p)\n", debugstr_a(str), address, scope, port);
+
+ if (!str || !address || !scope || !port)
+ return STATUS_INVALID_PARAMETER;
+
+ RtlMultiByteToUnicodeN(wstr, sizeof(wstr), NULL, str, strlen(str) + 1);
+ wstr[ARRAY_SIZE(wstr) - 1] = 0;
+ return ipv6_string_to_address(wstr, TRUE, NULL, address, scope, port);
+}
+
+/***********************************************************************
+ * RtlIpv6StringToAddressA [NTDLL.@]
+ */
+NTSTATUS WINAPI RtlIpv6StringToAddressA(const char *str, const char **terminator, IN6_ADDR *address)
+{
+ WCHAR wstr[64];
+ const WCHAR *wterminator = NULL;
+ NTSTATUS ret;
+
+ TRACE("(%s, %p, %p)\n", debugstr_a(str), terminator, address);
+
+ RtlMultiByteToUnicodeN(wstr, sizeof(wstr), NULL, str, strlen(str) + 1);
+ wstr[ARRAY_SIZE(wstr) - 1] = 0;
+ ret = ipv6_string_to_address(wstr, FALSE, &wterminator, address, NULL, NULL);
+ if (terminator && wterminator) *terminator = str + (wterminator - wstr);
+ return ret;
}
/***********************************************************************
--
2.24.1