我有10.132.0.0/20格式的子网和ASP.Net请求对象的IP地址。
是否有.NET框架功能来检查IP地址是否在给定的子网内?
如果没有,怎么办?比特操纵,我猜?
答案 0 :(得分:28)
在MSDN博客上查看IP Address Calculations with C#。它包含一个扩展方法(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);
}
}
答案 1 :(得分:12)
位操作有效。将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)) {
// ...
}
答案 2 :(得分:2)
我在这里参加派对很晚,但有类似的需求,并整理了一个快速的方案来做到这一点。
https://www.nuget.org/packages/IpMatcher/
和来源:
https://github.com/jchristn/IpMatcher
简单使用:
using IpMatcher;
Matcher matcher = new Matcher();
matcher.Add("192.168.1.0", "255.255.255.0");
matcher.Add("192.168.2.0", "255.255.255.0");
matcher.Remove("192.168.2.0");
matcher.Exists("192.168.1.0", "255.255.255.0"); // true
matcher.Match("192.168.1.34"); // true
matcher.Match("10.10.10.10"); // false
答案 3 :(得分:1)
解决方案是使用System.Net.IPAddress
将IP地址转换为字节,并对地址,子网和掩码八位字节执行按位比较。
二进制AND运算符&
将一个位复制到结果中,如果它存在于两个操作数中。
代码:
using System.Net; // Used to access IPAddress
bool IsAddressOnSubnet(string address, string subnet, string mask)
{
try
{
IPAddress Address = IPAddress.Parse(address);
IPAddress Subnet = IPAddress.Parse(subnet);
IPAddress Mask = IPAddress.Parse(mask);
Byte[] addressOctets = Address.GetAddressBytes();
Byte[] subnetOctets = Mask.GetAddressBytes();
Byte[] networkOctets = Subnet.GetAddressBytes();
return
((networkOctets[0] & subnetOctets[0]) == (addressOctets[0] & subnetOctets[0])) &&
((networkOctets[1] & subnetOctets[1]) == (addressOctets[1] & subnetOctets[1])) &&
((networkOctets[2] & subnetOctets[2]) == (addressOctets[2] & subnetOctets[2])) &&
((networkOctets[3] & subnetOctets[3]) == (addressOctets[3] & subnetOctets[3]));
}
catch (System.Exception ex)
{
return false;
}
}
特别感谢Спасибо! Прекрасноерешение! Reference
答案 4 :(得分:1)
将答案from Thomas和Chris与Ciscos Subnetting Examples一起使用,如果您使用CIDR表示法(IPAddress / 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);
// https://stackoverflow.com/a/1499284/3085985
// 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));
}
}
作为测试的基础,我使用了Ciscos Subnetting Examples和IBMs IPV6 address examples。
我希望有人会觉得有用;)
答案 5 :(得分:0)
我还创建了一个类,用于计算网络和广播地址,并检查IP既不是广播地址也不是网络地址。
private static IPValidationFailedReason PerformIPRangeValidation(string ipAddress, string subnetMask)
{
IPValidationFailedReason ipValidationType = IPValidationFailedReason.None;
string networkaddress = string.Empty;
string broadcastAddress = string.Empty;
string networkAddressBinary = string.Empty;
string broadcastAddressBinary = string.Empty;
int zerosCountInSubnetMask = 0;
Array.ForEach(subnetMask.Split(SplitterChar), (eachOctet) => Array.ForEach(IPInterfaceHelper.GetOctetWithPadding(eachOctet).Where(c => c == CharZero).ToArray(), (k) => zerosCountInSubnetMask++));
if (zerosCountInSubnetMask == 0)
{
return ipValidationType;
}
string ipAddressBinary = IPInterfaceHelper.ToBinary(ipAddress);
networkAddressBinary = GetNetworkAddressInBinaryFormat(zerosCountInSubnetMask, ipAddressBinary);
broadcastAddressBinary = GetBroadcastAddressInBinaryFormat(zerosCountInSubnetMask, ipAddressBinary);
networkaddress = ToIPFromBinary(networkAddressBinary);
broadcastAddress = ToIPFromBinary(broadcastAddressBinary);
if (ipAddress == networkaddress)
{
ipValidationType = IPValidationFailedReason.NetworkAddressZero;
return ipValidationType;
}
if (ipAddress == broadcastAddress)
{
ipValidationType = IPValidationFailedReason.BroadcastAddressNotPermiited;
return ipValidationType;
}
return ipValidationType;
}
private static string GetNetworkAddressInBinaryFormat(int zeroCountInSubnetMask, string ipAddressBinary)
{
string networkAddressBinary = string.Empty;
int countOfOnesInSubnetMask = TotalBitCount - zeroCountInSubnetMask;
StringBuilder sb = new StringBuilder(ipAddressBinary);
//When Subnet is like 255.255.255.0
if (zeroCountInSubnetMask >= 1 && zeroCountInSubnetMask <= 8)
{
networkAddressBinary = sb.Replace(CharOne, CharZero, countOfOnesInSubnetMask + 3, zeroCountInSubnetMask).ToString();
}
//When Subnet is like 255.255.0.0
if (zeroCountInSubnetMask > 8 && zeroCountInSubnetMask <= 16)
{
networkAddressBinary = sb.Replace(CharOne, CharZero, countOfOnesInSubnetMask + 2, zeroCountInSubnetMask + 1).ToString();
}
//When Subnet is like 255.0.0.0
if (zeroCountInSubnetMask > 16 && zeroCountInSubnetMask <= 24)
{
networkAddressBinary = sb.Replace(CharOne, CharZero, countOfOnesInSubnetMask + 1, zeroCountInSubnetMask + 2).ToString();
}
//When Subnet is like 128.0.0.0
if (zeroCountInSubnetMask > 24 && zeroCountInSubnetMask < 32)
{
networkAddressBinary = sb.Replace(CharOne, CharZero, countOfOnesInSubnetMask , zeroCountInSubnetMask + 3).ToString();
}
return networkAddressBinary;
}
private static string GetBroadcastAddressInBinaryFormat(int zeroCountInSubnetMask, string ipAddressBinary)
{
string broadcastAddressBinary = string.Empty;
int countOfOnesInSubnetMask = TotalBitCount - zeroCountInSubnetMask;
StringBuilder sb = new StringBuilder(ipAddressBinary);
//When Subnet is like 255.255.255.0
if (zeroCountInSubnetMask >= 1 && zeroCountInSubnetMask <= 8)
{
broadcastAddressBinary = sb.Replace(CharZero, CharOne, countOfOnesInSubnetMask + 3, zeroCountInSubnetMask).ToString();
}
//When Subnet is like 255.255.0.0
if (zeroCountInSubnetMask > 8 && zeroCountInSubnetMask <= 16)
{
broadcastAddressBinary = sb.Replace(CharZero, CharOne, countOfOnesInSubnetMask + 2, zeroCountInSubnetMask + 1).ToString();
}
//When Subnet is like 255.0.0.0
if (zeroCountInSubnetMask > 16 && zeroCountInSubnetMask <= 24)
{
broadcastAddressBinary = sb.Replace(CharZero, CharOne, countOfOnesInSubnetMask + 1, zeroCountInSubnetMask + 2).ToString();
}
//When Subnet is like 128.0.0.0
if (zeroCountInSubnetMask > 24 && zeroCountInSubnetMask < 32)
{
broadcastAddressBinary = sb.Replace(CharZero, CharOne, countOfOnesInSubnetMask , zeroCountInSubnetMask + 3).ToString();
}
return broadcastAddressBinary;
}
private static string ToIPFromBinary(string ipAddressBinary)
{
string addrTemp = string.Empty;
string[] networkAddressBinaryOctets = ipAddressBinary.Split(SplitterChar);
foreach (var eachOctet in networkAddressBinaryOctets)
{
string temp = Convert.ToUInt32(eachOctet, 2).ToString(CultureInfo.InvariantCulture);
addrTemp += temp + SplitterChar;
}
// remove last '.'
string ipAddress = addrTemp.Substring(0, addrTemp.Length - 1);
return ipAddress;
}