Index: lib/rtl/network.c =================================================================== --- lib/rtl/network.c (revision 67125) +++ lib/rtl/network.c (working copy) @@ -28,6 +28,26 @@ /* network to host order conversion for little endian machines */ #define WN2H(w) (((w & 0xFF00) >> 8) | ((w & 0x00FF) << 8)) + +/* re-use an ipv4 parsing function instead of inline duplicating the same code. + the inline code has the same terminator behavior as windows in failure cases. */ +#if !defined(IPV6_TERMINATOR_ADDR_STRICT_IN_FAILURE) +#define IPV6_TERMINATOR_ADDR_STRICT_IN_FAILURE 1 +#endif + +/* in the case of the address ::0:a:b:c:d:e:f windows incorrectly cuts off the f. + define FOLLOW_INCORRECT_FIRSTZERO to 1 to follow this behavior, to 0 to disable this. */ +#if !defined(IPV6_FOLLOW_INCORRECT_FIRSTZERO) +#define IPV6_FOLLOW_INCORRECT_FIRSTZERO 1 +#endif + +/* windows does accept a group of the form 0xffff as the last group in an ipv6 address.. + the terminator points to the x in this case. */ +#if !defined(IPV6_ACCEPT_HEXNOTATION_LAST_DIGIT) +#define IPV6_ACCEPT_HEXNOTATION_LAST_DIGIT 1 +#endif + + /* PRIVATE FUNCTIONS **********************************************************/ /* decode a string with given Base (8, 10 or 16) */ @@ -46,7 +66,7 @@ while (1) { Digit = towlower(*String); - if (isdigit(Digit) && (Base >= 10 || Digit <= L'7')) + if ((Digit >= L'0' && Digit <= L'9' && Base >= 10) || (Digit >= L'0' && Digit <= L'7')) Digit -= L'0'; else if (Digit >= L'a' && Digit <= L'f' && Base >= 16) Digit -= (L'a' - 10); @@ -118,8 +138,7 @@ { ULONG Len = 0; *Base = 0; - for (Len = 0; S[Len]; ++Len) - { + for (Len = 0; S[Len]; ++Len ) { if (iswascii(S[Len]) && isdigit(S[Len])) *Base = max(*Base, 10); else if (iswascii(S[Len]) && isxdigit(S[Len])) @@ -130,72 +149,27 @@ return Len; } -/* Worker function to extract the ipv4 part of a string. */ -NTSTATUS -NTAPI -RtlpIpv4StringToAddressParserW( - _In_ PCWSTR String, - _In_ BOOLEAN Strict, - _Out_ PCWSTR *Terminator, - _Out_writes_(4) ULONG *Values, - _Out_ INT *Parts) -{ - NTSTATUS Status; - *Parts = 0; - do - { - Status = RtlpStringToUlong(String, Strict, &String, &Values[*Parts]); - (*Parts)++; - if (*String != L'.') - break; - - /* Already four parts, but a dot follows? */ - if (*Parts == 4) - { - Status = STATUS_INVALID_PARAMETER; - break; - } - /* Skip the dot */ - String++; - } while (NT_SUCCESS(Status)); - - *Terminator = String; - return Status; -} - /* PUBLIC FUNCTIONS ***********************************************************/ /* * @implemented */ -PSTR +LPSTR NTAPI -RtlIpv4AddressToStringA( - _In_ const struct in_addr *Addr, - _Out_writes_(IPV4_ADDR_STRING_MAX_LEN) PCHAR S) +RtlIpv4AddressToStringA(_In_ const struct in_addr *Addr, + _Out_writes_(IPV4_ADDR_STRING_MAX_LEN) PCHAR S) { - NTSTATUS Status; - PSTR End; - if (!S) - return (PSTR)~0; + return (LPSTR)~0; - Status = RtlStringCchPrintfExA(S, - IPV4_ADDR_STRING_MAX_LEN, - &End, - NULL, - 0, - "%u.%u.%u.%u", - Addr->S_un.S_un_b.s_b1, - Addr->S_un.S_un_b.s_b2, - Addr->S_un.S_un_b.s_b3, - Addr->S_un.S_un_b.s_b4); - ASSERT(Status == STATUS_SUCCESS); - if (!NT_SUCCESS(Status)) - return (PSTR)~0; + if (!NT_SUCCESS(RtlStringCchPrintfA(S, IPV4_ADDR_STRING_MAX_LEN, "%u.%u.%u.%u", Addr->S_un.S_un_b.s_b1, + Addr->S_un.S_un_b.s_b2, + Addr->S_un.S_un_b.s_b3, + Addr->S_un.S_un_b.s_b4))) + return (LPSTR)~0; - return End; + return S + strlen(S); } /* @@ -203,44 +177,39 @@ */ NTSTATUS NTAPI -RtlIpv4AddressToStringExA( - _In_ const struct in_addr *Address, - _In_ USHORT Port, - _Out_writes_to_(*AddressStringLength, *AddressStringLength) PCHAR AddressString, - _Inout_ PULONG AddressStringLength) +RtlIpv4AddressToStringExA(_In_ const struct in_addr *Address, + _In_ USHORT Port, + _Out_writes_to_(*AddressStringLength, *AddressStringLength) PCHAR AddressString, + _Inout_ PULONG AddressStringLength) { - CHAR Buffer[IPV4_ADDR_STRING_MAX_LEN + IPV4_PORT_STRING_MAX_LEN]; - NTSTATUS Status; + CHAR Buffer[IPV4_ADDR_STRING_MAX_LEN + IPV4_PORT_STRING_MAX_LEN] = { 0 }; + NTSTATUS Result; ULONG Length; - PSTR End; if (!Address || !AddressString || !AddressStringLength) return STATUS_INVALID_PARAMETER; - Status = RtlStringCchPrintfExA(Buffer, - RTL_NUMBER_OF(Buffer), - &End, - NULL, - 0, - Port ? "%u.%u.%u.%u:%u" - : "%u.%u.%u.%u", - Address->S_un.S_un_b.s_b1, - Address->S_un.S_un_b.s_b2, - Address->S_un.S_un_b.s_b3, - Address->S_un.S_un_b.s_b4, - WN2H(Port)); - ASSERT(Status == STATUS_SUCCESS); - if (!NT_SUCCESS(Status)) + Result = RtlStringCchPrintfA(Buffer, _countof(Buffer), "%u.%u.%u.%u", Address->S_un.S_un_b.s_b1, + Address->S_un.S_un_b.s_b2, + Address->S_un.S_un_b.s_b3, + Address->S_un.S_un_b.s_b4); + + if (!NT_SUCCESS(Result)) return STATUS_INVALID_PARAMETER; - Length = End - Buffer; + Length = strlen(Buffer); + if (Port) + { + Result = RtlStringCchPrintfA(Buffer + Length, _countof(Buffer) - Length, ":%u", WN2H(Port)); + if (!NT_SUCCESS(Result)) + return STATUS_INVALID_PARAMETER; + Length += strlen(Buffer+Length); + } + if (*AddressStringLength > Length) { - Status = RtlStringCchCopyA(AddressString, - *AddressStringLength, - Buffer); - ASSERT(Status == STATUS_SUCCESS); *AddressStringLength = Length + 1; + RtlStringCchCopyA(AddressString, IPV4_ADDR_STRING_MAX_LEN+IPV4_PORT_STRING_MAX_LEN, Buffer); return STATUS_SUCCESS; } @@ -251,33 +220,20 @@ /* * @implemented */ -PWSTR +LPWSTR NTAPI -RtlIpv4AddressToStringW( - _In_ const struct in_addr *Addr, - _Out_writes_(IPV4_ADDR_STRING_MAX_LEN) PWCHAR S) +RtlIpv4AddressToStringW(_In_ const struct in_addr *Addr, + _Out_writes_(IPV4_ADDR_STRING_MAX_LEN) PWCHAR S) { - NTSTATUS Status; - PWSTR End; - if (!S) - return (PWSTR)~0; + return (LPWSTR)~0; - Status = RtlStringCchPrintfExW(S, - IPV4_ADDR_STRING_MAX_LEN, - &End, - NULL, - 0, - L"%u.%u.%u.%u", - Addr->S_un.S_un_b.s_b1, - Addr->S_un.S_un_b.s_b2, - Addr->S_un.S_un_b.s_b3, - Addr->S_un.S_un_b.s_b4); - ASSERT(Status == STATUS_SUCCESS); - if (!NT_SUCCESS(Status)) - return (PWSTR)~0; - - return End; + if(!NT_SUCCESS(RtlStringCchPrintfW(S, IPV4_ADDR_STRING_MAX_LEN, L"%u.%u.%u.%u", Addr->S_un.S_un_b.s_b1, + Addr->S_un.S_un_b.s_b2, + Addr->S_un.S_un_b.s_b3, + Addr->S_un.S_un_b.s_b4))) + return (LPWSTR)~0; + return S + wcslen(S); } /* @@ -285,44 +241,39 @@ */ NTSTATUS NTAPI -RtlIpv4AddressToStringExW( - _In_ const struct in_addr *Address, - _In_ USHORT Port, - _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWCHAR AddressString, - _Inout_ PULONG AddressStringLength) +RtlIpv4AddressToStringExW(_In_ const struct in_addr *Address, + _In_ USHORT Port, + _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWCHAR AddressString, + _Inout_ PULONG AddressStringLength) { - WCHAR Buffer[IPV4_ADDR_STRING_MAX_LEN + IPV4_PORT_STRING_MAX_LEN]; - NTSTATUS Status; + WCHAR Buffer[IPV4_ADDR_STRING_MAX_LEN + IPV4_PORT_STRING_MAX_LEN] = { 0 }; + NTSTATUS Result; ULONG Length; - PWSTR End; if (!Address || !AddressString || !AddressStringLength) return STATUS_INVALID_PARAMETER; - Status = RtlStringCchPrintfExW(Buffer, - RTL_NUMBER_OF(Buffer), - &End, - NULL, - 0, - Port ? L"%u.%u.%u.%u:%u" - : L"%u.%u.%u.%u", - Address->S_un.S_un_b.s_b1, - Address->S_un.S_un_b.s_b2, - Address->S_un.S_un_b.s_b3, - Address->S_un.S_un_b.s_b4, - WN2H(Port)); - ASSERT(Status == STATUS_SUCCESS); - if (!NT_SUCCESS(Status)) + Result = RtlStringCchPrintfW(Buffer, _countof(Buffer), L"%u.%u.%u.%u", Address->S_un.S_un_b.s_b1, + Address->S_un.S_un_b.s_b2, + Address->S_un.S_un_b.s_b3, + Address->S_un.S_un_b.s_b4); + if (!NT_SUCCESS(Result)) return STATUS_INVALID_PARAMETER; - Length = End - AddressString; + Length = wcslen(Buffer); + + if (Port) + { + Result = RtlStringCchPrintfW(Buffer + Length, _countof(Buffer) - Length, L":%u", WN2H(Port)); + if (!NT_SUCCESS(Result)) + return STATUS_INVALID_PARAMETER; + Length += wcslen(Buffer + Length); + } + if (*AddressStringLength > Length) { - Status = RtlStringCchCopyW(AddressString, - *AddressStringLength, - Buffer); - ASSERT(Status == STATUS_SUCCESS); *AddressStringLength = Length + 1; + RtlStringCchCopyW(AddressString, IPV4_ADDR_STRING_MAX_LEN+IPV4_PORT_STRING_MAX_LEN, Buffer); return STATUS_SUCCESS; } @@ -414,16 +365,30 @@ INT Parts = 0; INT i; - Status = RtlpIpv4StringToAddressParserW(String, - Strict, - Terminator, - Values, - &Parts); + do + { + Status = RtlpStringToUlong(String, Strict, &String, &Values[Parts]); + Parts++; + + if (*String != L'.') + break; + + /* Already four parts, but a dot follows? */ + if (Parts == 4) + { + Status = STATUS_INVALID_PARAMETER; + goto Done; + } + + /* Skip the dot */ + String++; + } while (NT_SUCCESS(Status)); + if (Strict && Parts < 4) Status = STATUS_INVALID_PARAMETER; if (!NT_SUCCESS(Status)) - return Status; + goto Done; /* Combine the parts */ Result = Values[Parts - 1]; @@ -433,12 +398,16 @@ if (Values[i] > 0xFF || (Result & (0xFF << Shift)) != 0) { - return STATUS_INVALID_PARAMETER; + Status = STATUS_INVALID_PARAMETER; + goto Done; } Result |= Values[i] << Shift; } Addr->S_un.S_addr = RtlUlongByteSwap(Result); + +Done: + *Terminator = String; return Status; } @@ -494,47 +463,45 @@ /* * @implemented */ -PSTR +LPSTR NTAPI -RtlIpv6AddressToStringA( - _In_ const struct in6_addr *Addr, - _Out_writes_(RTLIPV6A2S_MAX_LEN) PSTR S) +RtlIpv6AddressToStringA(_In_ const struct in6_addr *Addr, + _Out_writes_(RTLIPV6A2S_MINLEN) PSTR S) { - WCHAR Buffer[RTLIPV6A2S_MAX_LEN]; + WCHAR Buffer[RTLIPV6A2S_MAX_LEN] = { 0 }; PWSTR Result; NTSTATUS Status; - if (!S) - return (PSTR)~0; + /* Win2k3 returns length offset from the nullptr.. */ + if (!S) return + (LPSTR)~0; Buffer[0] = 0; Result = RtlIpv6AddressToStringW(Addr, Buffer); - if (Result == (PWSTR)~0) - return (PSTR)~0; - ASSERT(Result >= Buffer); - ASSERT(Result < Buffer + RTL_NUMBER_OF(Buffer)); + if (!(Result >= Buffer && Result <= Buffer + _countof(Buffer))) + return (LPSTR)~0; - Status = RtlUnicodeToMultiByteN(S, RTLIPV6A2S_MAX_LEN, NULL, Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR)); + Status = RtlUnicodeToMultiByteN(S, RTLIPV6A2S_MAX_LEN, NULL, Buffer, (wcslen(Buffer)+1) * sizeof(Buffer[0])); if (!NT_SUCCESS(Status)) - return (PSTR)~0; + return (LPSTR)~0; return S + strlen(S); } + /* * @implemented */ NTSTATUS NTAPI -RtlIpv6AddressToStringExA( - _In_ const struct in6_addr *Address, - _In_ ULONG ScopeId, - _In_ USHORT Port, - _Out_writes_to_(*AddressStringLength, *AddressStringLength) PSTR AddressString, - _Inout_ PULONG AddressStringLength) +RtlIpv6AddressToStringExA(_In_ const struct in6_addr *Address, + _In_ ULONG ScopeId, + _In_ USHORT Port, + _Out_writes_to_(*AddressStringLength, *AddressStringLength) PSTR AddressString, + _Inout_ PULONG AddressStringLength) { - WCHAR Buffer[RTLIPV6A2SEX_MAX_LEN]; + WCHAR Buffer[RTLIPV6A2SEX_MAX_LEN] = { 0 }; NTSTATUS Status; if (!Address || !AddressString || !AddressStringLength) @@ -544,32 +511,31 @@ if (!NT_SUCCESS(Status)) return Status; - Status = RtlUnicodeToMultiByteN(AddressString, RTLIPV6A2SEX_MAX_LEN, NULL, Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR)); + Status = RtlUnicodeToMultiByteN(AddressString, RTLIPV6A2SEX_MAX_LEN, NULL, Buffer, (wcslen(Buffer)+1) * sizeof(Buffer[0])); if (!NT_SUCCESS(Status)) return STATUS_INVALID_PARAMETER; return STATUS_SUCCESS; } + /* * @implemented */ -PWSTR +LPWSTR NTAPI -RtlIpv6AddressToStringW( - _In_ const struct in6_addr *Addr, - _Out_writes_(RTLIPV6A2S_MAX_LEN) PWSTR S) +RtlIpv6AddressToStringW(_In_ const struct in6_addr *Addr, + _Out_writes_(RTLIPV6A2S_MAX_LEN) PWSTR S) { NTSTATUS Status; - UINT Parts = 8, n; - BOOLEAN SkipOnce = TRUE; - PWSTR End; - size_t Remaining; + INT Length = -1; + UINT Parts = 8; + UINT SkipOnce = 1, n; + + /* Win2k3 returns length offset from the nullptr.. */ + if (!S) return + (LPWSTR)~0; - if (!S) - return (PWSTR)~0; - - Remaining = RTLIPV6A2S_MAX_LEN; /* does it look like an ipv4 address contained in an ipv6? http://tools.ietf.org/html/rfc2765 */ if (!Addr->s6_words[0] && !Addr->s6_words[1] && !Addr->s6_words[2] && !Addr->s6_words[3] && Addr->s6_words[6]) { @@ -582,21 +548,14 @@ Prefix = L""; if (Prefix != NULL) { - Status = RtlStringCchPrintfExW(S, - Remaining, - &End, - NULL, - 0, - L"::%ls%u.%u.%u.%u", - Prefix, - Addr->s6_bytes[12], - Addr->s6_bytes[13], - Addr->s6_bytes[14], - Addr->s6_bytes[15]); - ASSERT(Status == STATUS_SUCCESS); + Status = RtlStringCchPrintfW(S, RTLIPV6A2S_MAX_LEN, L"::%s%u.%u.%u.%u", Prefix, + Addr->s6_bytes[12], + Addr->s6_bytes[13], + Addr->s6_bytes[14], + Addr->s6_bytes[15]); if (!NT_SUCCESS(Status)) - return (PWSTR)~0; - return End; + return (LPWSTR)~0; + return S + wcslen(S); } } @@ -608,132 +567,93 @@ { if (SkipOnce && ((n + 1) < Parts) && !Addr->s6_words[n] && !Addr->s6_words[n + 1]) { - SkipOnce = FALSE; - while (!Addr->s6_words[n + 1] && (n + 1) < Parts) + SkipOnce = 0; + while (!Addr->s6_words[n+1] && (n+1) < Parts) ++n; *S++ = ':'; - Remaining--; - if ((n + 1) >= Parts) - { + if ((n+1) >= Parts) *S++ = ':'; - Remaining--; - } } else { if (n) - { *S++ = ':'; - Remaining--; - } - Status = RtlStringCchPrintfExW(S, - Remaining, - &End, - &Remaining, - 0, - L"%x", - WN2H(Addr->s6_words[n])); - ASSERT(Status == STATUS_SUCCESS); + Status = RtlStringCchPrintfW(S, RTLIPV6A2S_MAX_LEN, L"%x", WN2H(Addr->s6_words[n])); if (!NT_SUCCESS(Status)) - return (PWSTR)~0; - S = End; + return (LPWSTR)~0; + S += wcslen(S); } } if (Parts < 8) { - Status = RtlStringCchPrintfExW(S, - Remaining, - &End, - NULL, - 0, - L":%u.%u.%u.%u", - Addr->s6_bytes[12], - Addr->s6_bytes[13], - Addr->s6_bytes[14], - Addr->s6_bytes[15]); - ASSERT(Status == STATUS_SUCCESS); + Status = RtlStringCchPrintfW(S, RTLIPV6A2S_MAX_LEN, L":%u.%u.%u.%u", + Addr->s6_bytes[12], + Addr->s6_bytes[13], + Addr->s6_bytes[14], + Addr->s6_bytes[15]); + if (!NT_SUCCESS(Status)) - return (PWSTR)~0; + return (LPWSTR)~0; - return End; + return S + wcslen(S); } - *S = UNICODE_NULL; + *S = 0; /* make sure we are null terminated */ return S; } + /* * @implemented */ NTSTATUS NTAPI -RtlIpv6AddressToStringExW( - _In_ const struct in6_addr *Address, - _In_ ULONG ScopeId, - _In_ USHORT Port, - _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWCHAR AddressString, - _Inout_ PULONG AddressStringLength) +RtlIpv6AddressToStringExW(_In_ const struct in6_addr *Address, + _In_ ULONG ScopeId, + _In_ USHORT Port, + _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWCHAR AddressString, + _Inout_ PULONG AddressStringLength) { - WCHAR Buffer[RTLIPV6A2SEX_MAX_LEN]; + WCHAR Buffer[RTLIPV6A2SEX_MAX_LEN] = { 0 }; PWCHAR S = Buffer; - NTSTATUS Status; - ULONG Length; - size_t Remaining; + NTSTATUS Result; + ULONG Len; if (!Address || !AddressString || !AddressStringLength) return STATUS_INVALID_PARAMETER; if (Port) - *S++ = L'['; + *S++ = '['; S = RtlIpv6AddressToStringW(Address, S); - ASSERT(S != (PCWSTR)~0); - if (S == (PCWSTR)~0) - return STATUS_INVALID_PARAMETER; + if ((LPCWSTR)~0 == S) + return STATUS_INVALID_PARAMETER; /* this should not be possible, but better check... */ - ASSERT(S >= Buffer); - ASSERT(S <= Buffer + RTLIPV6A2S_MAX_LEN + 1); - Remaining = RTL_NUMBER_OF(Buffer) - (S - Buffer); - ASSERT(Remaining >= RTLIPV6A2SEX_MAX_LEN - RTLIPV6A2S_MAX_LEN); - if (ScopeId) { - Status = RtlStringCchPrintfExW(S, - Remaining, - &S, - &Remaining, - 0, - L"%%%u", - ScopeId); - ASSERT(Status == STATUS_SUCCESS); - if (!NT_SUCCESS(Status)) + Result = RtlStringCchPrintfW(S, RTLIPV6A2SEX_MAX_LEN - (S-Buffer), L"%%%u", ScopeId); + if (!NT_SUCCESS(Result)) return STATUS_INVALID_PARAMETER; + S += wcslen(S); } if (Port) { - Status = RtlStringCchPrintfExW(S, - Remaining, - &S, - &Remaining, - 0, - L"]:%u", - WN2H(Port)); - ASSERT(Status == STATUS_SUCCESS); - if (!NT_SUCCESS(Status)) + Result = RtlStringCchPrintfW(S, RTLIPV6A2SEX_MAX_LEN - (S-Buffer), L"]:%u", WN2H(Port)); + if (!NT_SUCCESS(Result)) return STATUS_INVALID_PARAMETER; + S += wcslen(S); } - Length = S - Buffer; - ASSERT(Buffer[Length] == UNICODE_NULL); - if (*AddressStringLength > Length) + Len = (S - Buffer) + 1; + + if (Len < *AddressStringLength) { - Status = RtlStringCchCopyW(AddressString, *AddressStringLength, Buffer); - ASSERT(Status == STATUS_SUCCESS); - *AddressStringLength = Length + 1; + *AddressStringLength = Len; + memcpy(AddressString, Buffer, sizeof(Buffer[0])* Len); return STATUS_SUCCESS; } - *AddressStringLength = Length + 1; + *AddressStringLength = Len; return STATUS_INVALID_PARAMETER; } @@ -742,30 +662,29 @@ */ NTSTATUS NTAPI -RtlIpv6StringToAddressA( - _In_ PCSTR String, - _Out_ PCSTR *Terminator, - _Out_ struct in6_addr *Addr) +RtlIpv6StringToAddressA(_In_ PCSTR Name, + _Out_ PCSTR *Terminator, + _Out_ struct in6_addr *Addr) { NTSTATUS Status; - ANSI_STRING StringA; - UNICODE_STRING StringW; - PCWSTR TerminatorW = NULL; + ANSI_STRING NameA; + UNICODE_STRING NameW; + PWCHAR TerminatorW = NULL; - Status = RtlInitAnsiStringEx(&StringA, String); + Status = RtlInitAnsiStringEx(&NameA, Name); if (!NT_SUCCESS(Status)) return Status; - Status = RtlAnsiStringToUnicodeString(&StringW, &StringA, TRUE); + Status = RtlAnsiStringToUnicodeString(&NameW, &NameA, TRUE); if (!NT_SUCCESS(Status)) return Status; - Status = RtlIpv6StringToAddressW(StringW.Buffer, &TerminatorW, Addr); + Status = RtlIpv6StringToAddressW(NameW.Buffer, &TerminatorW, Addr); /* on windows the terminator is not always written, so we mimic that behavior. */ if (TerminatorW) - *Terminator = String + (TerminatorW - StringW.Buffer); + *Terminator = Name + (TerminatorW - NameW.Buffer); - RtlFreeUnicodeString(&StringW); + RtlFreeUnicodeString(&NameW); return Status; } @@ -774,11 +693,10 @@ */ NTSTATUS NTAPI -RtlIpv6StringToAddressExA( - _In_ PCSTR AddressString, - _Out_ struct in6_addr *Address, - _Out_ PULONG ScopeId, - _Out_ PUSHORT Port) +RtlIpv6StringToAddressExA(_In_ PCSTR AddressString, + _Out_ struct in6_addr *Address, + _Out_ PULONG ScopeId, + _Out_ PUSHORT Port) { NTSTATUS Status; ANSI_STRING AddressA; @@ -798,56 +716,60 @@ return Status; } + /* * @implemented */ NTSTATUS NTAPI -RtlIpv6StringToAddressW( - _In_ PCWSTR String, - _Out_ PCWSTR *Terminator, - _Out_ struct in6_addr *Addr) +RtlIpv6StringToAddressW(_In_ PCWSTR Name, + _Out_ PCWSTR *Terminator, + _Out_ struct in6_addr *Addr) { INT n, j; INT StartSkip = -1, Parts = 0; ULONG Base, Len; NTSTATUS Status = STATUS_SUCCESS; enum { None, Number, Colon, DoubleColon } Last = None; +#if IPV6_ACCEPT_HEXNOTATION_LAST_DIGIT BOOLEAN SkipoutLastHex = FALSE; +#endif - if (!String || !Terminator || !Addr) + if (!Name || !Terminator || !Addr) return STATUS_INVALID_PARAMETER; for (n = 0; n < 8;) { - Len = RtlpClassifyChars(String, &Base); + Len = RtlpClassifyChars(Name, &Base); if (Len == 0) { /* not a number, and no ':' or already encountered an ':' */ - if (String[0] != ':' || Last == Colon) + if (Name[0] != ':' || Last == Colon) break; /* double colon, 1 or more fields set to 0. mark the position, and move on. */ - if (StartSkip == -1 && String[1] == ':') + if (StartSkip == -1 && Name[1] == ':') { +#if IPV6_FOLLOW_INCORRECT_FIRSTZERO /* this case was observed in windows, but it does not seem correct. */ if (!n) { Addr->s6_words[n++] = 0; Addr->s6_words[n++] = 0; } +#endif /* IPV6_FOLLOW_INCORRECT_FIRSTZERO */ StartSkip = n; - String += 2; + Name += 2; Last = DoubleColon; } - else if (String[1] == ':' || Last != Number) + else if (Name[1] == ':' || Last != Number) { /* a double colon after we already encountered one, or a the last parsed item was not a number. */ break; } else { - ++String; + ++Name; Last = Colon; } } @@ -858,39 +780,53 @@ Status = STATUS_INVALID_PARAMETER; if (Last != DoubleColon) return Status; - String += Len; + Name += Len; break; } else { ULONG Value; - if (String[Len] == '.' && n <= 6) + if (Name[Len] == '.' && n <= 6) { - ULONG Values[4]; - INT PartsV4 = 0; /* this could be an ipv4 address inside an ipv6 address http://tools.ietf.org/html/rfc2765 */ Last = Number; - Status = RtlpIpv4StringToAddressParserW(String, TRUE, &String, Values, &PartsV4); - for(j = 0; j < PartsV4; ++j) +#if !IPV6_TERMINATOR_ADDR_STRICT_IN_FAILURE + Status = RtlIpv4StringToAddressW(Name, TRUE, &Name, &Addr->s6_words[n]); +#else + for (j = 0; j < 4 && Status != STATUS_INVALID_PARAMETER; ++j) { - if (Values[j] > 255) + if (Base != 10) + break; + Status = RtlpStringToUlongBase(Name, 10, &Name, &Value); + if (!NT_SUCCESS(Status) || Value > 255) { + /* and another case of windows bailing out immediately, without updating + the terminator to show where the problem occurred, except when failing on the last group... */ Status = STATUS_INVALID_PARAMETER; if (j != 3) return Status; break; } - if ((j == PartsV4 - 1) && - (j < 3 || - (*String == ':' && StartSkip == -1) || - (StartSkip == -1 && n < 6) || - Status == STATUS_INVALID_PARAMETER)) + if (j < 3) { - Status = STATUS_INVALID_PARAMETER; - break; + if (*Name != '.') + { + Status = STATUS_INVALID_PARAMETER; + break; + } + ++Name; + Len = RtlpClassifyChars(Name, &Base); + if (!Len || Base != 10) + Status = STATUS_INVALID_PARAMETER; } - Addr->s6_bytes[n * 2 + j] = Values[j] & 0xff; + else + { + if ((*Name == ':' && StartSkip == -1) || (StartSkip == -1 && n < 6)) + break; + } + Addr->s6_bytes[n*2 + j] = Value & 0xff; } +#endif /* TERMINATOR_STRICT_IN_FAILURE */ /* mark enough parts as converted in case we are the last item to be converted */ n += 2; /* mark 2 parts as converted in case we are not the last item, and we encountered a double colon. */ @@ -898,27 +834,29 @@ break; } - if (String[Len] != ':' && n < 7 && StartSkip == -1) + if (Name[Len] != ':' && n < 7 && StartSkip == -1) { /* if we decoded atleast some numbers, update the terminator to point to the first invalid char */ if (Base) - String += Len; + Name += Len; Status = STATUS_INVALID_PARAMETER; break; } - if (Len == 1 && towlower(String[Len]) == 'x' && String[0] == '0') +#if IPV6_ACCEPT_HEXNOTATION_LAST_DIGIT + if (Len == 1 && towlower(Name[Len]) == 'x' && Name[0] == '0') { - Len = RtlpClassifyChars(String + 2, &Base); + Len = RtlpClassifyChars(Name + 2, &Base); if (Len > 0 && Len <= 4) { - *Terminator = String + 1; - String += 2; + *Terminator = Name + 1; + Name += 2; SkipoutLastHex = TRUE; } } +#endif - Status = RtlpStringToUlongBase(String, 16, &String, &Value); + Status = RtlpStringToUlongBase(Name, 16, &Name, &Value); if (!NT_SUCCESS(Status)) break; @@ -926,8 +864,10 @@ Parts++; Addr->s6_words[n++] = WN2H(Value); Last = Number; +#if IPV6_ACCEPT_HEXNOTATION_LAST_DIGIT if (SkipoutLastHex) break; +#endif } } @@ -939,10 +879,12 @@ n = 8; } +#if IPV6_ACCEPT_HEXNOTATION_LAST_DIGIT /* we have already set the terminator */ if (SkipoutLastHex) return n < 8 ? STATUS_INVALID_PARAMETER : Status; - *Terminator = String; +#endif + *Terminator = Name; return n < 8 ? STATUS_INVALID_PARAMETER : Status; } @@ -951,53 +893,52 @@ */ NTSTATUS NTAPI -RtlIpv6StringToAddressExW( - _In_ PCWSTR AddressString, - _Out_ struct in6_addr *Address, - _Out_ PULONG ScopeId, - _Out_ PUSHORT Port) +RtlIpv6StringToAddressExW(_In_ PCWSTR AddressName, + _Out_ struct in6_addr *Address, + _Out_ PULONG ScopeId, + _Out_ PUSHORT Port) { NTSTATUS Status; ULONG ConvertedPort = 0, ConvertedScope = 0; - if (!AddressString || !Address || !ScopeId || !Port) + if (!AddressName || !Address || !ScopeId || !Port) return STATUS_INVALID_PARAMETER; - if (*AddressString == '[') + if (*AddressName == '[') { ConvertedPort = 1; - ++AddressString; + ++AddressName; } - Status = RtlIpv6StringToAddressW(AddressString, &AddressString, Address); + Status = RtlIpv6StringToAddressW(AddressName, &AddressName, Address); if (!NT_SUCCESS(Status)) return STATUS_INVALID_PARAMETER; - if (*AddressString == '%') + if (*AddressName == '%') { - ++AddressString; - Status = RtlpStringToUlongBase(AddressString, 10, &AddressString, &ConvertedScope); + ++AddressName; + Status = RtlpStringToUlongBase(AddressName, 10, &AddressName, &ConvertedScope); if (!NT_SUCCESS(Status)) return STATUS_INVALID_PARAMETER; } - else if (*AddressString && !(ConvertedPort && *AddressString == ']')) + else if (*AddressName && !(ConvertedPort && *AddressName == ']')) { return STATUS_INVALID_PARAMETER; } if (ConvertedPort) { - if (*AddressString++ !=']') + if ( *AddressName++ !=']' ) return STATUS_INVALID_PARAMETER; - if (*AddressString ==':') + if (*AddressName ==':') { ULONG Base = 10; - if (*++AddressString == '0') + if (*++AddressName == '0') { - if (towlower(*++AddressString) != 'x') + if (towlower(*++AddressName) != 'x') return STATUS_INVALID_PARAMETER; - ++AddressString; + ++AddressName; Base = 16; } - Status = RtlpStringToUlongBase(AddressString, Base, &AddressString, &ConvertedPort); + Status = RtlpStringToUlongBase(AddressName, Base, &AddressName, &ConvertedPort); if (!NT_SUCCESS(Status) || ConvertedPort > 0xffff) return STATUS_INVALID_PARAMETER; } @@ -1007,7 +948,7 @@ } } - if (*AddressString == 0) + if (*AddressName == 0) { *ScopeId = ConvertedScope; *Port = WN2H(ConvertedPort);