using System.Net; using System.Net.Sockets; namespace LumaTunnel.Client.Core.Routing; public readonly record struct IpCidr(IPAddress Network, int PrefixLength) { public static bool TryParse(string value, out IpCidr cidr) { cidr = default; var parts = value.Split('/', 2, StringSplitOptions.TrimEntries); if (parts.Length != 2 || !IPAddress.TryParse(parts[0], out var address) || !int.TryParse(parts[1], out var prefix)) return false; var max = address.AddressFamily == AddressFamily.InterNetwork ? 32 : 128; if (prefix < 0 || prefix > max) return false; cidr = new IpCidr(address, prefix); return true; } public bool Contains(IPAddress address) { if (address.AddressFamily != Network.AddressFamily) return false; var network = Network.GetAddressBytes(); var candidate = address.GetAddressBytes(); var wholeBytes = PrefixLength / 8; var remainingBits = PrefixLength % 8; if (!network.AsSpan(0, wholeBytes).SequenceEqual(candidate.AsSpan(0, wholeBytes))) return false; if (remainingBits == 0) return true; var mask = (byte)(0xFF << (8 - remainingBits)); return (network[wholeBytes] & mask) == (candidate[wholeBytes] & mask); } }