我有10.132.0.0/20格式的子网和ASP.Net请求对象的IP地址.
是否有.NET框架功能来检查IP地址是否在给定的子网内?
如果没有,怎么办呢?比特操纵,我猜?
在MSDN博客上查看使用C#的IP地址计算.它包含一个扩展方法(IsInSameSubnet
),它应该满足您的需求以及其他一些好东西.
public static class IPAddressExtensions
{
public static IPAddress GetBroadcastAddress(this IPAddress address, IPAddress subnetMask)
{
byte[] ipAdressBytes = address.GetAddressBytes();
byte[] subnetMaskBytes = subnetMask.GetAddressBytes();
if (ipAdressBytes.Length != subnetMaskBytes.Length)
throw new ArgumentException("Lengths of IP address and subnet mask do not match.");
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
for (int i = 0; i < broadcastAddress.Length; i++)
{
broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255));
}
return new IPAddress(broadcastAddress);
}
public static IPAddress GetNetworkAddress(this IPAddress address, IPAddress subnetMask)
{
byte[] ipAdressBytes = address.GetAddressBytes();
byte[] subnetMaskBytes = subnetMask.GetAddressBytes();
if (ipAdressBytes.Length != subnetMaskBytes.Length)
throw new ArgumentException("Lengths of IP address and subnet mask do not match.");
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
for (int i = 0; i < broadcastAddress.Length; i++)
{
broadcastAddress[i] = (byte)(ipAdressBytes[i] & (subnetMaskBytes[i]));
}
return new IPAddress(broadcastAddress);
}
public static bool IsInSameSubnet(this IPAddress address2, IPAddress address, IPAddress subnetMask)
{
IPAddress network1 = address.GetNetworkAddress(subnetMask);
IPAddress network2 = address2.GetNetworkAddress(subnetMask);
return network1.Equals(network2);
}
}
位操作有效.将IP填充为32位无符号整数,对子网的地址执行相同操作,&
使用0xFFFFFFFF << (32-20)
和比较掩码:
unsigned int net = ..., ip = ...; int network_bits = 20; unsigned int mask = 0xFFFFFFFF << (32 - network_bits); if ((net & mask) == (ip & mask)) { // ... }
使用的答案从托马斯和克里斯一起思科子网划分的例子,如果你使用CIDR标记(ip地址/ PrefixLength)我终于得到了一些为IPv4和IPv6的工作。我的IPv6实施可能有点太简单了,但是由于没有UInt128数据类型,我无法适应Thomas的解决方案。以下代码似乎运行良好:
public static bool IsInSubnet(this IPAddress address, string subnetMask) { var slashIdx = subnetMask.IndexOf("/"); if (!subnetMask.Contains("/")) { // We only handle netmasks in format "IP/PrefixLength". throw new NotSupportedException("Only SubNetMasks with a given prefix length are supported."); } // First parse the address of the netmask before the prefix length. var maskAddress = IPAddress.Parse(subnetMask.Substring(0, slashIdx)); if (maskAddress.AddressFamily != address.AddressFamily) { // We got something like an IPV4-Address for an IPv6-Mask. This is not valid. return false; } // Now find out how long the prefix is. int maskLength = int.Parse(subnetMask.Substring(slashIdx + 1)); if (maskAddress.AddressFamily == AddressFamily.InterNetwork) { // Convert the mask address to an unsigned integer. var maskAddressBits = BitConverter.ToUInt32(maskAddress.GetAddressBytes().Reverse().ToArray()); // And convert the IpAddress to an unsigned integer. var ipAdressBits = BitConverter.ToUInt32(address.GetAddressBytes().Reverse().ToArray()); // Get the mask/network address as unsigned integer. uint mask = uint.MaxValue << (32 - maskLength); // /sf/ask/17360801/ // Bitwise AND mask and MaskAddress, this should be the same as mask and IpAddress // as the end of the mask is 0000 which leads to both addresses to end with 0000 // and to start with the prefix. return (maskAddressBits & mask) == (ipAdressBits & mask); } if (maskAddress.AddressFamily == AddressFamily.InterNetworkV6) { // Convert the mask address to a BitArray. var maskAddressBits = new BitArray(maskAddress.GetAddressBytes()); // And convert the IpAddress to a BitArray. var ipAdressBits = new BitArray(address.GetAddressBytes()); if (maskAddressBits.Length != ipAdressBits.Length) { throw new ArgumentException("Length of IP Address and Subnet Mask do not match."); } // Compare the prefix bits. for (int i = 0; i < maskLength; i++) { if (ipAdressBits[i] != maskAddressBits[i]) { return false; } } return true; } throw new NotSupportedException("Only InterNetworkV6 or InterNetwork address families are supported."); }
这是我用以下方法测试过的XUnit测试:
public class IpAddressExtensionsTests { [Theory] [InlineData("192.168.5.85/24", "192.168.5.1")] [InlineData("192.168.5.85/24", "192.168.5.254")] [InlineData("10.128.240.50/30", "10.128.240.48")] [InlineData("10.128.240.50/30", "10.128.240.49")] [InlineData("10.128.240.50/30", "10.128.240.50")] [InlineData("10.128.240.50/30", "10.128.240.51")] public void IpV4SubnetMaskMatchesValidIpAddress(string netMask, string ipAddress) { var ipAddressObj = IPAddress.Parse(ipAddress); Assert.True(ipAddressObj.IsInSubnet(netMask)); } [Theory] [InlineData("192.168.5.85/24", "192.168.4.254")] [InlineData("192.168.5.85/24", "191.168.5.254")] [InlineData("10.128.240.50/30", "10.128.240.47")] [InlineData("10.128.240.50/30", "10.128.240.52")] [InlineData("10.128.240.50/30", "10.128.239.50")] [InlineData("10.128.240.50/30", "10.127.240.51")] public void IpV4SubnetMaskDoesNotMatchInvalidIpAddress(string netMask, string ipAddress) { var ipAddressObj = IPAddress.Parse(ipAddress); Assert.False(ipAddressObj.IsInSubnet(netMask)); } [Theory] [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:0000:0000:0000:0000")] [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:FFFF:FFFF:FFFF:FFFF")] [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:0001:0000:0000:0000")] [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:FFFF:FFFF:FFFF:FFF0")] [InlineData("2001:db8:abcd:0012::0/128", "2001:0DB8:ABCD:0012:0000:0000:0000:0000")] public void IpV6SubnetMaskMatchesValidIpAddress(string netMask, string ipAddress) { var ipAddressObj = IPAddress.Parse(ipAddress); Assert.True(ipAddressObj.IsInSubnet(netMask)); } [Theory] [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0011:FFFF:FFFF:FFFF:FFFF")] [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0013:0000:0000:0000:0000")] [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0013:0001:0000:0000:0000")] [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0011:FFFF:FFFF:FFFF:FFF0")] [InlineData("2001:db8:abcd:0012::0/128", "2001:0DB8:ABCD:0012:0000:0000:0000:0001")] public void IpV6SubnetMaskDoesNotMatchInvalidIpAddress(string netMask, string ipAddress) { var ipAddressObj = IPAddress.Parse(ipAddress); Assert.False(ipAddressObj.IsInSubnet(netMask)); } }
作为测试的基础,我使用了Cisco的子网划分示例和IBM的IPV6地址示例。
我希望有人会觉得有用;)