From 92aae8d482f8e273cbec586aaa7115aa5f315385 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Sat, 19 Dec 2020 00:27:39 -0800 Subject: [PATCH] fix(core): Adds IPv6 support (#348) ## Breaking Change * IP Matching no longer supports `?` (e.g. you cannot do: "192.16?.0.1") * IP Matching no longer supports `*` and other values in the same section (e.g. you cannot do "192.1\*.0.1") * To do "192.1\*.0.1", you should use the range option with three separate entries: "192.100-199.0.1", "192.1.0.1", "192.10-19.0.1" ## Non-Breaking Changes - [X] Adds IPv6 support (not for servers though, just clients) - [X] Adds interning support for IPv4 mapped to IPv6 - [X] Updates IPv4ToAddress (don't use this unless you know it is IPv4 or IPv4 mapped to IPv6) ## Note: UO Does not support IPv6 for the server. To support an IPv6 server IP you will need to use CUO or some kind of custom client and probably modify it accordingly. Bumps release version --- .gitignore | 1 + .../Packets/Outgoing/AccountPackets.cs | 5 +- .../Server.Tests/Tests/Network/PipeTests.cs | 2 +- .../Tests/Utility/HexStringConverterTest.cs | 2 +- .../Tests/Utility/IPAddressTests.cs | 78 ++ .../Network/Packets/OutgoingAccountPackets.cs | 6 +- Projects/Server/Network/ServerInfo.cs | 23 +- Projects/Server/Serialization/BufferReader.cs | 9 +- Projects/Server/Server.csproj | 2 + Projects/Server/Utilities/Utility.cs | 719 ++++++++++-------- Projects/UOContent/Accounting/Account.cs | 2 +- Projects/UOContent/Accounting/Firewall.cs | 20 - 12 files changed, 527 insertions(+), 342 deletions(-) create mode 100644 Projects/Server.Tests/Tests/Utility/IPAddressTests.cs diff --git a/.gitignore b/.gitignore index fc94d87a4..5db3887f9 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ /Distribution/libz.dylib /Distribution/libz.so /Distribution/ZLib.Bindings.dll +/Distribution/Microsoft.Toolkit.HighPerformance.dll /Distribution/runtimes /Distribution/nohup.out /Distribution/ref diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/AccountPackets.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/AccountPackets.cs index a2f9d6aab..bba17d8af 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/AccountPackets.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/AccountPackets.cs @@ -338,7 +338,8 @@ namespace Server.Tests.Network Stream.WriteAsciiFixed(si.Name, 32); Stream.Write((byte)si.FullPercent); Stream.Write((sbyte)si.TimeZone); - Stream.Write(Utility.GetAddressValue(si.Address.Address)); + // UO Doesn't support IPv6 + Stream.Write(si.RawAddress); } } } @@ -347,7 +348,7 @@ namespace Server.Tests.Network { public PlayServerAck(ServerInfo si, int authId) : base(0x8C, 11) { - var addr = Utility.GetAddressValue(si.Address.Address); + var addr = si.RawAddress; Stream.Write((byte)addr); Stream.Write((byte)(addr >> 8)); diff --git a/Projects/Server.Tests/Tests/Network/PipeTests.cs b/Projects/Server.Tests/Tests/Network/PipeTests.cs index b89c1b1d6..20e2fafe5 100644 --- a/Projects/Server.Tests/Tests/Network/PipeTests.cs +++ b/Projects/Server.Tests/Tests/Network/PipeTests.cs @@ -10,7 +10,7 @@ namespace Server.Tests.Network { private async void DelayedExecute(Action action) { - await Task.Delay(5); + await Task.Delay(5).ConfigureAwait(false); action(); } diff --git a/Projects/Server.Tests/Tests/Utility/HexStringConverterTest.cs b/Projects/Server.Tests/Tests/Utility/HexStringConverterTest.cs index e0eca4301..05d0d9ddd 100644 --- a/Projects/Server.Tests/Tests/Utility/HexStringConverterTest.cs +++ b/Projects/Server.Tests/Tests/Utility/HexStringConverterTest.cs @@ -1,7 +1,7 @@ using System; using Xunit; -namespace Server.Tests.Accounting +namespace Server.Tests { public class HexStringConverterTest { diff --git a/Projects/Server.Tests/Tests/Utility/IPAddressTests.cs b/Projects/Server.Tests/Tests/Utility/IPAddressTests.cs new file mode 100644 index 000000000..2766899ed --- /dev/null +++ b/Projects/Server.Tests/Tests/Utility/IPAddressTests.cs @@ -0,0 +1,78 @@ +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Net; +using Xunit; + +namespace Server.Tests +{ + public class IPAddressTests + { + [Theory] + [InlineData("192.168.100.254", "192.168.100.1", 16, true)] + [InlineData("192.168.100.254", "192.168.50.1", 24, false)] + [InlineData("192.168.100.1", "192.168.50.1", 32, false)] + [InlineData("192.168.50.1", "192.168.50.1", 32, true)] + [InlineData("192.168.50.4", "192.168.50.7", 30, true)] + [InlineData("192.168.50.4", "192.168.50.9", 30, false)] + [InlineData("::ffff:192.168.100.254", "192.168.100.1", 112, true)] + [InlineData("::ffff:192.168.100.254", "192.168.50.1", 104, true)] + [InlineData("::ffff:192.168.100.254", "192.168.50.1", 120, false)] + [InlineData("1234:5678:9ABC:1234:5678:9ABC:1234:5678", "1234:5677:0:0:0:0:0:0", 16, true)] + [InlineData("1234:5678:9ABC:1234:5678:9ABC:1234:5678", "1234:5677:0:0:0:0:0:0", 64, false)] + [InlineData("::1234:5678", "1234:5677::", 64, false)] + [InlineData("::1234:5678", "::9ABC:5677", 112, false)] + [InlineData("::1234:5678", "::1234:66AA", 112, true)] + [InlineData("::1234:5678", "::1235:FFFF", 109, true)] + [InlineData("::1234:5678", "::1238:ABAC", 109, false)] + public void TestIPvCIDR(string cidr, string addr, int cidrLength, bool shouldMatch) + { + var cidrAddress = IPAddress.Parse(cidr); + var address = IPAddress.Parse(addr); + + Assert.Equal(shouldMatch, Utility.IPMatchCIDR(cidrAddress, address, cidrLength)); + } + + [Theory] + [InlineData("192.168.1.*", "192.168.1.1", true, true)] + [InlineData("192.168.1.100", "192.168.1.1", false, true)] + [InlineData("192.168.*.100", "192.168.1.100", true, true)] + [InlineData("192.168.20-60.100", "192.168.37.100", true, true)] + [InlineData("192.168.20-60.100", "192.168.85.100", false, true)] + [InlineData("192.168.-.100", "192.168.85.100", false, false)] + [InlineData("192.168.x-.100", "192.168.85.100", false, false)] + [InlineData("192.168.x*.100", "192.168.85.100", false, false)] + [InlineData("192.168.**.100", "192.168.85.100", false, false)] + [InlineData("::1234:*", "::1234:5678", true, true)] + [InlineData("::1234-1238:1000", "::1236:1000", true, true)] + [InlineData("::1234-1238:1000", "::1239:1000", false, true)] + [InlineData("::10:*:1234-1238:1000", "::10:55A1:1235:1000", true, true)] + [InlineData("1024:*:1234::", "1024:8A13:1234::", true, true)] + [InlineData("::1024:*:1234::", "1024:8A13:1234::", false, false)] + [InlineData("::1024:*:1234:-", "::1024:8A13:1234", false, false)] + [InlineData("::1024:*1:1234", "::1024:8A13:1234", false, false)] + [InlineData("::1024:*-:1234", "::1024:8A13:1234", false, false)] + [InlineData("::1024:?1:1234", "::1024:8A13:1234", false, false)] + [InlineData("::1024:1_2:1234", "::1024:8A13:1234", false, false)] + public void TestIPMatch(string val, string addr, bool shouldMatch, bool shouldBeValid) + { + var address = IPAddress.Parse(addr); + bool match = Utility.IPMatch(val, address, out var valid); + + Assert.Equal(shouldMatch, match); + Assert.Equal(shouldBeValid, valid); + } + + [Fact] + public void TestMixedIPv4Address() + { + var ip = IPAddress.Parse("::ffff:192.168.1.1"); + var expected = IPAddress.Parse("192.168.1.1"); + + Span integer = stackalloc byte[4]; + expected.TryWriteBytes(integer, out _); + + Assert.Equal(BinaryPrimitives.ReadUInt32BigEndian(integer), Utility.IPv4ToAddress(ip)); + } + } +} diff --git a/Projects/Server/Network/Packets/OutgoingAccountPackets.cs b/Projects/Server/Network/Packets/OutgoingAccountPackets.cs index af923be39..7ec723d7c 100644 --- a/Projects/Server/Network/Packets/OutgoingAccountPackets.cs +++ b/Projects/Server/Network/Packets/OutgoingAccountPackets.cs @@ -454,7 +454,8 @@ namespace Server.Network writer.WriteAscii(si.Name, 32); writer.Write((byte)si.FullPercent); writer.Write((sbyte)si.TimeZone); - writer.Write(Utility.GetAddressValue(si.Address.Address)); + // UO only supports IPv4 + writer.Write(si.RawAddress); } writer.WritePacketLength(); @@ -477,8 +478,7 @@ namespace Server.Network var writer = new CircularBufferWriter(buffer); writer.Write((byte)0x8C); // Packet ID - var addr = Utility.GetAddressValue(si.Address.Address); - writer.WriteLE(addr); + writer.WriteLE(si.RawAddress); writer.Write((short)si.Address.Port); writer.Write(authId); diff --git a/Projects/Server/Network/ServerInfo.cs b/Projects/Server/Network/ServerInfo.cs index 939cdb841..53f6e7a2f 100644 --- a/Projects/Server/Network/ServerInfo.cs +++ b/Projects/Server/Network/ServerInfo.cs @@ -14,12 +14,15 @@ *************************************************************************/ using System; +using System.Buffers.Binary; using System.Net; namespace Server.Network { public sealed class ServerInfo { + private IPEndPoint m_Address; + public ServerInfo(string name, int fullPercent, TimeZoneInfo tz, IPEndPoint address) { Name = name; @@ -34,6 +37,24 @@ namespace Server.Network public int TimeZone { get; set; } - public IPEndPoint Address { get; set; } + public IPEndPoint Address + { + get => m_Address; + set + { + m_Address = value; + Span integer = stackalloc byte[4]; + value.Address.MapToIPv4().TryWriteBytes(integer, out var bytesWritten); + if (bytesWritten != 4) + { + throw new InvalidOperationException("IP Address could not be serialized to an integer"); + } + + RawAddress = BinaryPrimitives.ReadUInt32LittleEndian(integer); + } + } + + // UO doesn't support IPv6 servers + public uint RawAddress { get; private set; } } } diff --git a/Projects/Server/Serialization/BufferReader.cs b/Projects/Server/Serialization/BufferReader.cs index f0f72fbd7..1255537e9 100644 --- a/Projects/Server/Serialization/BufferReader.cs +++ b/Projects/Server/Serialization/BufferReader.cs @@ -158,7 +158,14 @@ namespace Server return v; } - public IPAddress ReadIPAddress() => new(ReadLong()); + public IPAddress ReadIPAddress() + { + byte length = ReadByte(); + // Either 2 ushorts, or 8 ushorts + Span integer = stackalloc byte[length]; + Read(integer); + return new IPAddress(integer); + } public Point3D ReadPoint3D() => new(ReadInt(), ReadInt(), ReadInt()); diff --git a/Projects/Server/Server.csproj b/Projects/Server/Server.csproj index 0a8e5c9e4..ed620140d 100644 --- a/Projects/Server/Server.csproj +++ b/Projects/Server/Server.csproj @@ -17,6 +17,7 @@ + @@ -27,6 +28,7 @@ + diff --git a/Projects/Server/Utilities/Utility.cs b/Projects/Server/Utilities/Utility.cs index 28dba9de0..16c1bd2d1 100644 --- a/Projects/Server/Utilities/Utility.cs +++ b/Projects/Server/Utilities/Utility.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers.Binary; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -9,6 +10,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Xml; +using Microsoft.Toolkit.HighPerformance.Extensions; using Server.Random; namespace Server @@ -183,6 +185,11 @@ namespace Server return null; } + if (ipAddress.IsIPv4MappedToIPv6) + { + ipAddress = ipAddress.MapToIPv4(); + } + _ipAddressTable ??= new Dictionary(); if (!_ipAddressTable.TryGetValue(ipAddress, out var interned)) @@ -199,15 +206,412 @@ namespace Server ipAddress = Intern(ipAddress); } - public static bool IsValidIP(string text) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint IPv4ToAddress(IPAddress ipAddress) { - IPMatch(text, IPAddress.None, out var valid); + if (ipAddress.IsIPv4MappedToIPv6) + { + ipAddress = ipAddress.MapToIPv4(); + } + else if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6) + { + return 0; + } - return valid; + Span integer = stackalloc byte[4]; + ipAddress.TryWriteBytes(integer, out var bytesWritten); + return bytesWritten != 4 ? 0 : BinaryPrimitives.ReadUInt32BigEndian(integer); } + public static bool IPMatchClassC(IPAddress ip1, IPAddress ip2) + { + var a = IPv4ToAddress(ip1); + var b = IPv4ToAddress(ip2); + + return a == 0 || b == 0 ? ip1.Equals(ip2) : (a & 0xFFFFFF) == (b & 0xFFFFFF); + } + + public static bool IPMatchCIDR(IPAddress cidrAddress, IPAddress address, int cidrLength) + { + if (cidrAddress.AddressFamily == AddressFamily.InterNetwork) + { + if (address.AddressFamily == AddressFamily.InterNetworkV6) + { + return false; + } + + cidrLength += 96; + } + + cidrAddress = cidrAddress.MapToIPv6(); + address = address.MapToIPv6(); + + cidrLength = Math.Clamp(cidrLength, 0, 128); + + Span cidrBytes = stackalloc byte[16]; + cidrAddress.TryWriteBytes(cidrBytes, out var _); + + Span addrBytes = stackalloc byte[16]; + address.TryWriteBytes(addrBytes, out var _); + + var i = 0; + int offset; + + if (cidrLength < 32) + { + offset = cidrLength; + } + else + { + var index = Math.DivRem(cidrLength, 32, out offset); + while (index > 0) + { + if ( + BinaryPrimitives.ReadInt32BigEndian(cidrBytes.Slice(i, 4)) != + BinaryPrimitives.ReadInt32BigEndian(addrBytes.Slice(i, 4)) + ) + { + return false; + } + + i += 4; + --index; + } + } + + if (offset == 0) + { + return true; + } + + var c = BinaryPrimitives.ReadInt32BigEndian(cidrBytes.Slice(i, 4)); + var a = BinaryPrimitives.ReadInt32BigEndian(addrBytes.Slice(i, 4)); + + var mask = (1 << (32 - offset)) - 1; + var min = ~mask & c; + var max = c | mask; + + return a >= min && a <= max; + } + + public static bool IsValidIP(string val) => IPMatch(val, IPAddress.Any, out var valid) || valid; + public static bool IPMatch(string val, IPAddress ip) => IPMatch(val, ip, out _); + public static bool IPMatch(string val, IPAddress ip, out bool valid) + { + var family = ip.AddressFamily; + var useIPv6 = family == AddressFamily.InterNetworkV6 || val.Contains(':', StringComparison.Ordinal); + + ip = useIPv6 ? ip.MapToIPv6() : ip.MapToIPv4(); + + Span ipBytes = stackalloc byte[useIPv6 ? 16 : 4]; + ip.TryWriteBytes(ipBytes, out _); + + return useIPv6 ? IPv6Match(val, ipBytes, out valid) : IPv4Match(val, ipBytes, out valid); + } + + public static bool IPv4Match(ReadOnlySpan val, ReadOnlySpan ip, out bool valid) + { + var match = true; + valid = true; + var end = val.Length; + var byteIndex = 0; + var section = 0; + var number = 0; + var isRange = false; + var intBase = 10; + var endOfSection = false; + var sectionStart = 0; + + var num = ip[byteIndex++]; + + for (var i = 0; i < end; i++) + { + var chr = val[i]; + if (section >= 4) + { + valid = false; + return false; + } + + switch (chr) + { + default: + { + if (!Uri.IsHexDigit(chr)) + { + valid = false; + return false; + } + + number = number * intBase + Uri.FromHex(chr); + break; + } + case 'x': + case 'X': + { + if (i == sectionStart) + { + intBase = 16; + break; + } + + valid = false; + return false; + } + case '-': + { + if (i == sectionStart || i + 1 == end || val[i + 1] == '.') + { + valid = false; + return false; + } + + // Only allows a single range in a section + if (isRange) + { + valid = false; + return false; + } + + isRange = true; + match = match && num > number; + number = 0; + break; + } + case '*': + { + if (i != sectionStart || i + 1 < end && val[i + 1] != '.') + { + valid = false; + return false; + } + + isRange = true; + number = 255; + break; + } + case '.': + { + endOfSection = true; + break; + } + } + + if (endOfSection || i + 1 == end) + { + if (number < 0 || number > 255) + { + valid = false; + return false; + } + + match = match && (isRange ? num <= number : number == num); + + if (++section < 4) + { + num = ip[byteIndex++]; + } + + intBase = 10; + number = 0; + endOfSection = false; + sectionStart = i + 1; + isRange = false; + } + } + + return match; + } + + public static bool IPv6Match(ReadOnlySpan val, ReadOnlySpan ip, out bool valid) + { + valid = true; + + // Start must be two `::` or a number + if (val[0] == ':' && val[1] != ':') + { + valid = false; + return false; + } + + var match = true; + var end = val.Length; + var byteIndex = 2; + var section = 0; + var number = 0; + var isRange = false; + var endOfSection = false; + var sectionStart = 0; + var hasCompressor = false; + + var num = BinaryPrimitives.ReadUInt16BigEndian(ip.Slice(0, 2)); + + for (int i = 0; i < end; i++) + { + if (section > 7) + { + valid = false; + return false; + } + + var chr = val[i]; + // We are starting a new sequence, check the previous one then continue + switch (chr) + { + default: + { + if (!Uri.IsHexDigit(chr)) + { + valid = false; + return false; + } + + number = number * 16 + Uri.FromHex(chr); + break; + } + case '?': + { + Console.WriteLine("IP Match '?' character is not supported."); + valid = false; + return false; + } + // Range + case '-': + { + if (i == sectionStart || i + 1 == end || val[i + 1] == ':') + { + valid = false; + return false; + } + + // Only allows a single range in a section + if (isRange) + { + valid = false; + return false; + } + + isRange = true; + + // Check low part of the range + match = match && num >= number; + number = 0; + break; + } + // Wild section + case '*': + { + if (i != sectionStart || i + 1 < end && val[i + 1] != ':') + { + valid = false; + return false; + } + + isRange = true; + number = 65535; + break; + } + case ':': + { + endOfSection = true; + break; + } + } + + if (!endOfSection && i + 1 != end) + { + continue; + } + + if (++i == end || val[i] != ':' || section > 0) + { + match = match && (isRange ? num <= number : number == num); + + // IPv4 matching at the end + if (section == 6 && num == 0xFFFF) + { + var ipv4 = val.Slice(i + 1); + if (ipv4.Contains('.')) + { + return IPv4Match(ipv4, ip.Slice(ip.Length - 4), out valid); + } + } + + if (i == end) + { + break; + } + + + num = BinaryPrimitives.ReadUInt16BigEndian(ip.Slice(byteIndex, 2)); + byteIndex += 2; + + ++section; + } + + if (i < end && val[i] == ':') + { + if (hasCompressor) + { + valid = false; + return false; + } + + int newSection; + + if (i + 1 < end) + { + var remainingColons = val.Slice(i + 1).Count(':'); + // double colon must be at least 2 sections + // we need at least 1 section remaining out of 8 + // This means 8 - 2 would be 6 sections (5 colons) + newSection = section + 2 + (5 - remainingColons); + if (newSection > 7) + { + valid = false; + return false; + } + } + else + { + newSection = 7; + } + + var zeroEnd = (newSection + 1) * 2; + do + { + if (match) + { + if (num != 0) + { + match = false; + } + + num = BinaryPrimitives.ReadUInt16BigEndian(ip.Slice(byteIndex, 2)); + } + + byteIndex += 2; + } while (byteIndex < zeroEnd); + + section = newSection; + hasCompressor = true; + } + else + { + i--; + } + + number = 0; + endOfSection = false; + sectionStart = i + 1; + isRange = false; + } + + return match; + } + public static string FixHtml(string str) { if (str == null) @@ -244,311 +648,6 @@ namespace Server return sb.ToString(); } - public static bool IPMatchCIDR(string cidr, IPAddress ip) - { - if (ip == null || ip.AddressFamily == AddressFamily.InterNetworkV6) - { - return false; // Just worry about IPv4 for now - } - - var bytes = new byte[4]; - var split = cidr.Split('.'); - var cidrBits = false; - var cidrLength = 0; - - for (var i = 0; i < 4; i++) - { - var part = 0; - - var partBase = 10; - - var pattern = split[i]; - - for (var j = 0; j < pattern.Length; j++) - { - var c = pattern[j]; - - if (c == 'x' || c == 'X') - { - partBase = 16; - } - else if (c >= '0' && c <= '9') - { - var offset = c - '0'; - - if (cidrBits) - { - cidrLength *= partBase; - cidrLength += offset; - } - else - { - part *= partBase; - part += offset; - } - } - else if (c >= 'a' && c <= 'f') - { - var offset = 10 + (c - 'a'); - - if (cidrBits) - { - cidrLength *= partBase; - cidrLength += offset; - } - else - { - part *= partBase; - part += offset; - } - } - else if (c >= 'A' && c <= 'F') - { - var offset = 10 + (c - 'A'); - - if (cidrBits) - { - cidrLength *= partBase; - cidrLength += offset; - } - else - { - part *= partBase; - part += offset; - } - } - else if (c == '/') - { - if (cidrBits || i != 3) // If there's two '/' or the '/' isn't in the last byte - { - return false; - } - - partBase = 10; - cidrBits = true; - } - else - { - return false; - } - } - - bytes[i] = (byte)part; - } - - return IPMatchCIDR(OrderedAddressValue(bytes), ip, cidrLength); - } - - public static bool IPMatchCIDR(IPAddress cidrPrefix, IPAddress ip, int cidrLength) - { - // Ignore IPv6 for now - if (cidrPrefix == null || ip == null || cidrPrefix.AddressFamily == AddressFamily.InterNetworkV6) - { - return false; - } - - var cidrValue = SwapUnsignedInt((uint)GetLongAddressValue(cidrPrefix)); - var ipValue = SwapUnsignedInt((uint)GetLongAddressValue(ip)); - - return IPMatchCIDR(cidrValue, ipValue, cidrLength); - } - - public static bool IPMatchCIDR(uint cidrPrefixValue, IPAddress ip, int cidrLength) - { - if (ip == null || ip.AddressFamily == AddressFamily.InterNetworkV6) - { - return false; - } - - var ipValue = SwapUnsignedInt((uint)GetLongAddressValue(ip)); - - return IPMatchCIDR(cidrPrefixValue, ipValue, cidrLength); - } - - public static bool IPMatchCIDR(uint cidrPrefixValue, uint ipValue, int cidrLength) - { - if (cidrLength <= 0 || cidrLength >= 32) // if invalid cidr Length, just compare IPs - { - return cidrPrefixValue == ipValue; - } - - var mask = uint.MaxValue << (32 - cidrLength); - - return (cidrPrefixValue & mask) == (ipValue & mask); - } - - private static uint OrderedAddressValue(byte[] bytes) - { - if (bytes.Length != 4) - { - return 0; - } - - return (uint)((bytes[0] << 0x18) | (bytes[1] << 0x10) | (bytes[2] << 8) | bytes[3]) & 0xffffffff; - } - - private static uint SwapUnsignedInt(uint source) => - ((source & 0x000000FF) << 0x18) - | ((source & 0x0000FF00) << 8) - | ((source & 0x00FF0000) >> 8) - | ((source & 0xFF000000) >> 0x18); - - public static bool TryConvertIPv6toIPv4(ref IPAddress address) - { - if (!Socket.OSSupportsIPv6 || address.AddressFamily == AddressFamily.InterNetwork) - { - return true; - } - - var addr = address.GetAddressBytes(); - if (addr.Length == 16) // sanity 0 - 15 //10 11 //12 13 14 15 - { - if (addr[10] != 0xFF || addr[11] != 0xFF) - { - return false; - } - - for (var i = 0; i < 10; i++) - { - if (addr[i] != 0) - { - return false; - } - } - - var v4Addr = new byte[4]; - - for (var i = 0; i < 4; i++) - { - v4Addr[i] = addr[12 + i]; - } - - address = new IPAddress(v4Addr); - return true; - } - - return false; - } - - public static bool IPMatch(string val, IPAddress ip, out bool valid) - { - valid = true; - - var split = val.Split('.'); - - for (var i = 0; i < 4; ++i) - { - int lowPart, highPart; - - if (i >= split.Length) - { - lowPart = 0; - highPart = 255; - } - else - { - var pattern = split[i]; - - if (pattern == "*") - { - lowPart = 0; - highPart = 255; - } - else - { - lowPart = 0; - highPart = 0; - - var highOnly = false; - var lowBase = 10; - var highBase = 10; - - for (var j = 0; j < pattern.Length; ++j) - { - var c = pattern[j]; - - if (c == '?') - { - if (!highOnly) - { - lowPart *= lowBase; - lowPart += 0; - } - - highPart *= highBase; - highPart += highBase - 1; - } - else if (c == '-') - { - highOnly = true; - highPart = 0; - } - else if (c == 'x' || c == 'X') - { - lowBase = 16; - highBase = 16; - } - else if (c >= '0' && c <= '9') - { - var offset = c - '0'; - - if (!highOnly) - { - lowPart *= lowBase; - lowPart += offset; - } - - highPart *= highBase; - highPart += offset; - } - else if (c >= 'a' && c <= 'f') - { - var offset = 10 + (c - 'a'); - - if (!highOnly) - { - lowPart *= lowBase; - lowPart += offset; - } - - highPart *= highBase; - highPart += offset; - } - else if (c >= 'A' && c <= 'F') - { - var offset = 10 + (c - 'A'); - - if (!highOnly) - { - lowPart *= lowBase; - lowPart += offset; - } - - highPart *= highBase; - highPart += offset; - } - else - { - valid = false; // high & lowp art would be 0 if it got to here. - } - } - } - } - - int b = (byte)(GetAddressValue(ip) >> (i * 8)); - - if (b < lowPart || b > highPart) - { - return false; - } - } - - return true; - } - - public static bool IPMatchClassC(IPAddress ip1, IPAddress ip2) => - (GetAddressValue(ip1) & 0xFFFFFF) == (GetAddressValue(ip2) & 0xFFFFFF); - public static int InsensitiveCompare(string first, string second) => Insensitive.Compare(first, second); public static bool InsensitiveStartsWith(string first, string second) => Insensitive.StartsWith(first, second); @@ -1055,10 +1154,6 @@ namespace Server public static string GetText(XmlElement node, string defaultValue) => node?.InnerText ?? defaultValue; - public static int GetAddressValue(IPAddress address) => BitConverter.ToInt32(address.GetAddressBytes(), 0); - - public static long GetLongAddressValue(IPAddress address) => BitConverter.ToInt64(address.GetAddressBytes(), 0); - public static bool InRange(Point3D p1, Point3D p2, int range) => p1.m_X >= p2.m_X - range && p1.m_X <= p2.m_X + range diff --git a/Projects/UOContent/Accounting/Account.cs b/Projects/UOContent/Accounting/Account.cs index 3a234cfb7..904c702d1 100644 --- a/Projects/UOContent/Accounting/Account.cs +++ b/Projects/UOContent/Accounting/Account.cs @@ -1004,7 +1004,7 @@ namespace Server.Accounting for (var i = 0; !accessAllowed && i < IPRestrictions.Length; ++i) { - accessAllowed = Utility.IPMatch(IPRestrictions[i], ipAddress); + accessAllowed = IPAddress.Parse(IPRestrictions[i]).Equals(ipAddress); } return accessAllowed; diff --git a/Projects/UOContent/Accounting/Firewall.cs b/Projects/UOContent/Accounting/Firewall.cs index ae6fbb310..a0ea62f34 100644 --- a/Projects/UOContent/Accounting/Firewall.cs +++ b/Projects/UOContent/Accounting/Firewall.cs @@ -170,26 +170,6 @@ namespace Server } return false; - /* - bool contains = false; - - for ( int i = 0; !contains && i < m_Blocked.Count; ++i ) - { - if (m_Blocked[i] is IPAddress) - contains = ip.Equals( m_Blocked[i] ); - else if (m_Blocked[i] is String) - { - string s = (string)m_Blocked[i]; - - contains = Utility.IPMatchCIDR( s, ip ); - - if (!contains) - contains = Utility.IPMatch( s, ip ); - } - } - - return contains; - * */ } public interface IFirewallEntry