Skip to content

Commit 20901cb

Browse files
authored
Fix IPAddress & Uri octal parsing inconsistencies (#121962)
1 parent eeaef45 commit 20901cb

File tree

4 files changed

+17
-16
lines changed

4 files changed

+17
-16
lines changed

src/libraries/Common/src/System/Net/IPv4AddressHelper.Common.cs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ internal static bool IsValidCanonical<TChar>(ReadOnlySpan<TChar> name, out int e
133133
int dots = 0;
134134
long number = 0;
135135
bool haveNumber = false;
136-
bool firstCharIsZero = false;
137136
int start = 0;
138137

139138
while (start < name.Length)
@@ -161,16 +160,11 @@ internal static bool IsValidCanonical<TChar>(ReadOnlySpan<TChar> name, out int e
161160

162161
if (parsedCharacter < IPv4AddressHelper.Decimal)
163162
{
164-
// A number starting with zero should be interpreted in base 8 / octal
165-
if (!haveNumber && parsedCharacter == 0)
163+
if (!haveNumber && parsedCharacter == 0 &&
164+
(uint)(start + 1) < (uint)name.Length && char.IsAsciiDigit((char)ToUShort(name[start + 1])))
166165
{
167-
if ((start + 1 < name.Length) && name[start + 1] == TChar.CreateTruncating('0'))
168-
{
169-
// 00 is not allowed as a prefix.
170-
return false;
171-
}
172-
173-
firstCharIsZero = true;
166+
// Octal is not allowed in canonical format.
167+
return false;
174168
}
175169

176170
haveNumber = true;
@@ -184,15 +178,14 @@ internal static bool IsValidCanonical<TChar>(ReadOnlySpan<TChar> name, out int e
184178
{
185179
// If the current character is not an integer, it may be the IPv4 component separator ('.')
186180

187-
if (!haveNumber || (number > 0 && firstCharIsZero))
181+
if (!haveNumber)
188182
{
189-
// 0 is not allowed to prefix a number.
190183
return false;
191184
}
185+
192186
++dots;
193187
haveNumber = false;
194188
number = 0;
195-
firstCharIsZero = false;
196189
}
197190
else
198191
{

src/libraries/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ public void ParseIPv4_ValidAddress_Success(string address, string expected)
264264
new object[] { "12.+1.1.4" }, // plus sign in section
265265
new object[] { "12.1.-1.5" }, // minus sign in section
266266
new object[] { "12.1.abc.5" }, // text in section
267+
new object[] { "0.0.0.089" }, // octal with digits over 7
268+
new object[] { "0.0.08.0" }, // octal with digits over 7
267269
};
268270

269271
public static readonly object[][] InvalidIpv4AddressesStandalone = // but valid as part of IPv6 addresses
@@ -438,7 +440,6 @@ public void ParseIPv4_InvalidAddress_ThrowsFormatExceptionWithInnerException(str
438440
new object[] { "::FFFF:0:192.168.0.1", "::ffff:0:192.168.0.1" }, // SIIT
439441
new object[] { "::5EFE:192.168.0.1", "::5efe:192.168.0.1" }, // ISATAP
440442
new object[] { "1::5EFE:192.168.0.1", "1::5efe:192.168.0.1" }, // ISATAP
441-
new object[] { "::192.168.0.010", "::192.168.0.10" }, // Embedded IPv4 octal, read as decimal
442443
};
443444

444445
[Theory]
@@ -570,6 +571,9 @@ public static IEnumerable<object[]> InvalidIpv6Addresses()
570571
yield return new object[] { ":%12" }; // colon scope
571572
yield return new object[] { "[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:443/" }; // errneous ending slash after ignored port
572573

574+
yield return new object[] { "::192.168.01.10" }; // Embedded IPv4 with octal
575+
yield return new object[] { "::192.168.0.010" }; // Embedded IPv4 with octal
576+
573577
yield return new object[] { "e3fff:ffff:ffff:ffff:ffff:ffff:ffff:abcd" }; // 1st number too long
574578
yield return new object[] { "3fff:effff:ffff:ffff:ffff:ffff:ffff:abcd" }; // 2nd number too long
575579
yield return new object[] { "3fff:ffff:effff:ffff:ffff:ffff:ffff:abcd" }; // 3rd number too long

src/libraries/System.Net.Primitives/tests/FunctionalTests/IPEndPointParsing.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,6 @@ private void InvalidPortHelper(string addressAndPort)
301301
new object[] { "::FFFF:0:192.168.0.1", "::ffff:0:192.168.0.1" }, // SIIT
302302
new object[] { "::5EFE:192.168.0.1", "::5efe:192.168.0.1" }, // ISATAP
303303
new object[] { "1::5EFE:192.168.0.1", "1::5efe:192.168.0.1" }, // ISATAP
304-
new object[] { "::192.168.0.010", "::192.168.0.10" }, // Embedded IPv4 octal, read as decimal
305304
};
306305

307306
public static readonly object[][] ValidIpv4Andv6AddressesWithAndWithoutPort =

src/libraries/System.Private.Uri/tests/FunctionalTests/UriIpHostTest.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,11 @@ private void ParseBadIPv4Address(string badIpv4String)
219219
{
220220
Assert.NotEqual(UriHostNameType.IPv4, testUri.HostNameType);
221221
}
222+
223+
if (Uri.TryCreate($"custom://{badIpv4String}/", UriKind.Absolute, out testUri))
224+
{
225+
Assert.NotEqual(UriHostNameType.IPv4, testUri.HostNameType);
226+
}
222227
}
223228

224229
#endregion Helpers
@@ -314,7 +319,6 @@ public void UriIPv6Host_ScopeId_Success(string address)
314319
[InlineData("::FFFF:0:192.168.0.1", "::ffff:0:192.168.0.1")] // SIIT
315320
[InlineData("::5EFE:192.168.0.1", "::5efe:192.168.0.1")] // ISATAP
316321
[InlineData("1::5EFE:192.168.0.1", "1::5efe:192.168.0.1")] // ISATAP
317-
[InlineData("::192.168.0.010", "::192.168.0.10")] // Embedded IPv4 octal, read as decimal
318322
public void UriIPv6Host_EmbeddedIPv4_Success(string address, string expected)
319323
{
320324
ParseIPv6Address(address, expected);
@@ -461,6 +465,7 @@ private void ParseBadIPv6Address(string badIpv6String)
461465

462466
// TryCreate
463467
Assert.False(Uri.TryCreate($"http://[{badIpv6String}]/", UriKind.Absolute, out _), badIpv6String);
468+
Assert.False(Uri.TryCreate($"custom://[{badIpv6String}]/", UriKind.Absolute, out _), badIpv6String);
464469
}
465470

466471
#endregion Helpers

0 commit comments

Comments
 (0)