From c6240b3284e6941b2dd5c34cf1f23255834455c6 Mon Sep 17 00:00:00 2001 From: Mitch Valenta Date: Wed, 6 Nov 2019 10:14:33 -0800 Subject: [PATCH] PhysicalAddress.Parse case-insensitive and support new formats (dotnet/corefx#41696) * Add parsing support for PhysicalAddresses with colon delimiter and lowercasing * Address PR feedback Commit migrated from https://github.com/dotnet/corefx/commit/0d2969f69c36e8d131f4620cc172b6a7c3840fc8 --- .../Net/NetworkInformation/PhysicalAddress.cs | 115 +++++++++++++++------ .../tests/FunctionalTests/PhysicalAddressTest.cs | 26 ++++- 2 files changed, 105 insertions(+), 36 deletions(-) diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/PhysicalAddress.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/PhysicalAddress.cs index 3a738ee..5930946 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/PhysicalAddress.cs +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/PhysicalAddress.cs @@ -105,70 +105,90 @@ namespace System.Net.NetworkInformation public static PhysicalAddress Parse(string address) { - int validCount = 0; - bool hasDashes = false; - byte[] buffer = null; + int validSegmentLength; + char? delimiter = null; + byte[] buffer; if (address == null) { - return PhysicalAddress.None; + return None; } - // Has dashes? if (address.Contains('-')) { - hasDashes = true; - buffer = new byte[(address.Length + 1) / 3]; - if ((address.Length + 1) % 3 != 0) { - throw new FormatException(SR.Format(SR.net_bad_mac_address, address)); + ThrowBadAddressException(address); + } + + delimiter = '-'; + buffer = new byte[(address.Length + 1) / 3]; // allow any length that's a multiple of 3 + validSegmentLength = 2; + } + else if (address.Contains(':')) + { + delimiter = ':'; + validSegmentLength = GetValidSegmentLength(address, ':'); + if (validSegmentLength != 2 && validSegmentLength != 4) + { + ThrowBadAddressException(address); + } + buffer = new byte[6]; + } + else if (address.Contains('.')) + { + delimiter = '.'; + validSegmentLength = GetValidSegmentLength(address, '.'); + if (validSegmentLength != 4) + { + ThrowBadAddressException(address); } + buffer = new byte[6]; } else { if (address.Length % 2 > 0) { - throw new FormatException(SR.Format(SR.net_bad_mac_address, address)); + ThrowBadAddressException(address); } + validSegmentLength = address.Length; buffer = new byte[address.Length / 2]; } + int validCount = 0; int j = 0; for (int i = 0; i < address.Length; i++) { - int value = (int)address[i]; + int value = address[i]; - if (value >= 0x30 && value <= 0x39) + if (value >= '0' && value <= '9') + { + value -= '0'; + } + else if (value >= 'A' && value <= 'F') { - value -= 0x30; + value -= ('A' - 10); } - else if (value >= 0x41 && value <= 0x46) + else if (value >= 'a' && value <= 'f') { - value -= 0x37; + value -= ('a' - 10); } - else if (value == (int)'-') + else { - if (validCount == 2) + if (delimiter == value && validCount == validSegmentLength) { validCount = 0; continue; } - else - { - throw new FormatException(SR.Format(SR.net_bad_mac_address, address)); - } - } - else - { - throw new FormatException(SR.Format(SR.net_bad_mac_address, address)); + + ThrowBadAddressException(address); } - // we had too many characters after the last dash - if (hasDashes && validCount >= 2) + // we had too many characters after the last delimiter + if (validCount >= validSegmentLength) { - throw new FormatException(SR.Format(SR.net_bad_mac_address, address)); + ThrowBadAddressException(address); } if (validCount % 2 == 0) @@ -183,13 +203,46 @@ namespace System.Net.NetworkInformation validCount++; } - // we too few characters after the last dash - if (validCount < 2) + // we had too few characters after the last delimiter + if (validCount < validSegmentLength) { - throw new FormatException(SR.Format(SR.net_bad_mac_address, address)); + ThrowBadAddressException(address); } return new PhysicalAddress(buffer); + + static void ThrowBadAddressException(string address) => + throw new FormatException(SR.Format(SR.net_bad_mac_address, address)); + } + + private static int GetValidSegmentLength(string address, char delimiter) + { + int segments = 1; + int validSegmentLength = 0; + for (int i = 0; i < address.Length; i++) + { + if (address[i] == delimiter) + { + if (validSegmentLength == 0) + { + validSegmentLength = i; + } + else if ((i - (segments - 1)) % validSegmentLength != 0) + { + // segments - 1 = num of delimeters. Throw if new segment isn't the validSegmentLength + throw new FormatException(SR.Format(SR.net_bad_mac_address, address)); + } + + segments++; + } + } + + if (segments * validSegmentLength != 12) + { + throw new FormatException(SR.Format(SR.net_bad_mac_address, address)); + } + + return validSegmentLength; } } } diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/PhysicalAddressTest.cs b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/PhysicalAddressTest.cs index f663710..c4e7c99 100644 --- a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/PhysicalAddressTest.cs +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/PhysicalAddressTest.cs @@ -82,8 +82,12 @@ namespace System.Net.NetworkInformation.Tests yield return new object[] { "47-FB-74-41-3B", new byte[] { 0x47, 0xfb, 0x74, 0x41, 0x3B } }; yield return new object[] { "00-11-22-33-44-55", new byte[] { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 } }; yield return new object[] { "F0-E1-D2-C3-B4-A5", new byte[] { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5 } }; + yield return new object[] { "f0-e1-d2-c3-b4-a5", new byte[] { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5 } }; yield return new object[] { "54-0C-C4-7E-66-54", new byte[] { 0x54, 0x0c, 0xc4, 0x7e, 0x66, 0x54 } }; yield return new object[] { "001122334455", new byte[] { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 } }; + yield return new object[] { "00:11:22:33:44:55", new byte[] { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 } }; + yield return new object[] { "0011:2233:4455", new byte[] { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 } }; + yield return new object[] { "0011.2233.4455", new byte[] { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 } }; yield return new object[] { "00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F-10-11-12-13-14-15-16-17-18-19-1A-1B-1C-1D-1E-1F-" + @@ -128,10 +132,22 @@ namespace System.Net.NetworkInformation.Tests [InlineData("D2-C3-")] [InlineData("D2-A33")] [InlineData("B4-A5-F01")] - [InlineData("f0-e1-d2-c3-b4-a5")] - [InlineData("47:FB:74:41:66:3B")] - [InlineData("de84.1251.1c9d")] - [InlineData("AE88.D6EC.A720")] + [InlineData("00:111:22:33:44:55")] + [InlineData("0:1:22:33:44:55")] + [InlineData("0:0:1:1:22:33:44:55")] + [InlineData(":::00112233444")] + [InlineData("0011:2233")] + [InlineData("0011:2233:4455:6677")] + [InlineData("0011:2233:4455:6677:8899:0011")] + [InlineData("001:12233:4455")] + [InlineData("0011:2233:")] + [InlineData("0011:2233:44555")] + [InlineData("001.12233.4455")] + [InlineData("0011.2233.")] + [InlineData("0011.2233.44555")] + [InlineData("00.111.22.33.44.55")] + [InlineData("001.122.334.455")] + public void Parse_Invalid_ThrowsFormatException(string address) { FormatException ex = Assert.Throws(() => PhysicalAddress.Parse(address)); @@ -150,7 +166,7 @@ namespace System.Net.NetworkInformation.Tests [MemberData(nameof(RoundtripParseToString_String_Bytes))] public void ToString_ExpectedResult(string expectedAddress, byte[] inputBytes) { - Assert.Equal(expectedAddress.Replace("-", ""), new PhysicalAddress(inputBytes).ToString()); + Assert.Equal(expectedAddress.Replace("-", "").Replace(":", "").Replace(".", "").ToUpper(), new PhysicalAddress(inputBytes).ToString()); } [Theory] -- 2.7.4