I have a subnet in the format 10.132.0.0/20 and an IP address from the ASP.Net request object.
Is there a .NET framework function to check to see if the IP address is within the given subnet?
If not, how can it be done? Bit manipulation, I guess?
I have a subnet in the format 10.132.0.0/20 and an IP address from the ASP.Net request object.
Is there a .NET framework function to check to see if the IP address is within the given subnet?
If not, how can it be done? Bit manipulation, I guess?
Using the answers from Thomas and Chris together with Ciscos Subnetting Examples I finally got something to work for IPv4 and IPv6 if you use the CIDR notation (IPAddress/PrefixLength). My IPv6-Implementation might be a bit too straight forward but as there is no UInt128-datatype I couldn't adapt Thomas's solution. Here is the code that seems to work well:
public static bool IsInSubnet(this IPAddress address, string subnetMask)
{
var slashIdx = subnetMask.IndexOf("/");
if (slashIdx == -1)
{ // 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 (maskLength == 0)
{
return true;
}
if (maskLength < 0)
{
throw new NotSupportedException("A Subnetmask should not be less than 0.");
}
if (maskAddress.AddressFamily == AddressFamily.InterNetwork)
{
// Convert the mask address to an unsigned integer.
var maskAddressBits = BitConverter.ToUInt32(maskAddress.GetAddressBytes().Reverse().ToArray(), 0);
// And convert the IpAddress to an unsigned integer.
var ipAddressBits = BitConverter.ToUInt32(address.GetAddressBytes().Reverse().ToArray(), 0);
// Get the mask/network address as unsigned integer.
uint mask = uint.MaxValue << (32 - maskLength);
// https://mcmap.net/q/360451/-how-to-check-if-an-ip-address-is-within-a-particular-subnet
// 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) == (ipAddressBits & mask);
}
if (maskAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
// Convert the mask address to a BitArray. Reverse the BitArray to compare the bits of each byte in the right order.
var maskAddressBits = new BitArray(maskAddress.GetAddressBytes().Reverse().ToArray());
// And convert the IpAddress to a BitArray. Reverse the BitArray to compare the bits of each byte in the right order.
var ipAddressBits = new BitArray(address.GetAddressBytes().Reverse().ToArray());
var ipAddressLength = ipAddressBits.Length;
if (maskAddressBits.Length != ipAddressBits.Length)
{
throw new ArgumentException("Length of IP Address and Subnet Mask do not match.");
}
// Compare the prefix bits.
for (var i = ipAddressLength - 1; i >= ipAddressLength - maskLength; i--)
{
if (ipAddressBits[i] != maskAddressBits[i])
{
return false;
}
}
return true;
}
throw new NotSupportedException("Only InterNetworkV6 or InterNetwork address families are supported.");
}
And this are the XUnit tests I tested it with:
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")]
[InlineData("192.168.5.85/0", "0.0.0.0")]
[InlineData("192.168.5.85/0", "255.255.255.255")]
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")]
[InlineData("2001:db8:abcd:5678::0/53", "2001:0db8:abcd:5000:0000:0000:0000:0000")]
[InlineData("2001:db8:abcd:5678::0/53", "2001:0db8:abcd:57ff:ffff:ffff:ffff:ffff")]
[InlineData("2001:db8:abcd:0012::0/0", "::")]
[InlineData("2001:db8:abcd:0012::0/0", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")]
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")]
[InlineData("2001:db8:abcd:5678::0/53", "2001:0db8:abcd:4999:0000:0000:0000:0000")]
[InlineData("2001:db8:abcd:5678::0/53", "2001:0db8:abcd:5800:0000:0000:0000:0000")]
public void IpV6SubnetMaskDoesNotMatchInvalidIpAddress(string netMask, string ipAddress)
{
var ipAddressObj = IPAddress.Parse(ipAddress);
Assert.False(ipAddressObj.IsInSubnet(netMask));
}
}
As base for the tests I used Ciscos Subnetting Examples and IBMs IPV6 address examples.
I hope someone finds this helpful ;)
BitArray
are laid out correctly, but bits within them are reversed, making the for loop compare less significant bits of each byte first, which is wrong, but still works when prefix is aligned on a byte. Provided tests do not cover this! –
Flak BitArray
contructor - .GetAddressBytes().Reverse().ToArray()
and then for
loop over the BitArray
backwards, like this: for (int i = ipAddressBits.Length - 1; i >= ipAddressBits.Length - maskLength; i--)
–
Flak Take a look at IP Address Calculations with C# on MSDN blogs. It contains an extension method (IsInSameSubnet
) that should meet your needs as well as some other goodies.
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);
}
}
Using the answers from Thomas and Chris together with Ciscos Subnetting Examples I finally got something to work for IPv4 and IPv6 if you use the CIDR notation (IPAddress/PrefixLength). My IPv6-Implementation might be a bit too straight forward but as there is no UInt128-datatype I couldn't adapt Thomas's solution. Here is the code that seems to work well:
public static bool IsInSubnet(this IPAddress address, string subnetMask)
{
var slashIdx = subnetMask.IndexOf("/");
if (slashIdx == -1)
{ // 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 (maskLength == 0)
{
return true;
}
if (maskLength < 0)
{
throw new NotSupportedException("A Subnetmask should not be less than 0.");
}
if (maskAddress.AddressFamily == AddressFamily.InterNetwork)
{
// Convert the mask address to an unsigned integer.
var maskAddressBits = BitConverter.ToUInt32(maskAddress.GetAddressBytes().Reverse().ToArray(), 0);
// And convert the IpAddress to an unsigned integer.
var ipAddressBits = BitConverter.ToUInt32(address.GetAddressBytes().Reverse().ToArray(), 0);
// Get the mask/network address as unsigned integer.
uint mask = uint.MaxValue << (32 - maskLength);
// https://mcmap.net/q/360451/-how-to-check-if-an-ip-address-is-within-a-particular-subnet
// 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) == (ipAddressBits & mask);
}
if (maskAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
// Convert the mask address to a BitArray. Reverse the BitArray to compare the bits of each byte in the right order.
var maskAddressBits = new BitArray(maskAddress.GetAddressBytes().Reverse().ToArray());
// And convert the IpAddress to a BitArray. Reverse the BitArray to compare the bits of each byte in the right order.
var ipAddressBits = new BitArray(address.GetAddressBytes().Reverse().ToArray());
var ipAddressLength = ipAddressBits.Length;
if (maskAddressBits.Length != ipAddressBits.Length)
{
throw new ArgumentException("Length of IP Address and Subnet Mask do not match.");
}
// Compare the prefix bits.
for (var i = ipAddressLength - 1; i >= ipAddressLength - maskLength; i--)
{
if (ipAddressBits[i] != maskAddressBits[i])
{
return false;
}
}
return true;
}
throw new NotSupportedException("Only InterNetworkV6 or InterNetwork address families are supported.");
}
And this are the XUnit tests I tested it with:
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")]
[InlineData("192.168.5.85/0", "0.0.0.0")]
[InlineData("192.168.5.85/0", "255.255.255.255")]
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")]
[InlineData("2001:db8:abcd:5678::0/53", "2001:0db8:abcd:5000:0000:0000:0000:0000")]
[InlineData("2001:db8:abcd:5678::0/53", "2001:0db8:abcd:57ff:ffff:ffff:ffff:ffff")]
[InlineData("2001:db8:abcd:0012::0/0", "::")]
[InlineData("2001:db8:abcd:0012::0/0", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")]
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")]
[InlineData("2001:db8:abcd:5678::0/53", "2001:0db8:abcd:4999:0000:0000:0000:0000")]
[InlineData("2001:db8:abcd:5678::0/53", "2001:0db8:abcd:5800:0000:0000:0000:0000")]
public void IpV6SubnetMaskDoesNotMatchInvalidIpAddress(string netMask, string ipAddress)
{
var ipAddressObj = IPAddress.Parse(ipAddress);
Assert.False(ipAddressObj.IsInSubnet(netMask));
}
}
As base for the tests I used Ciscos Subnetting Examples and IBMs IPV6 address examples.
I hope someone finds this helpful ;)
BitArray
are laid out correctly, but bits within them are reversed, making the for loop compare less significant bits of each byte first, which is wrong, but still works when prefix is aligned on a byte. Provided tests do not cover this! –
Flak BitArray
contructor - .GetAddressBytes().Reverse().ToArray()
and then for
loop over the BitArray
backwards, like this: for (int i = ipAddressBits.Length - 1; i >= ipAddressBits.Length - maskLength; i--)
–
Flak Bit manipulation works. Stuff the IP into a 32-bits unsigned integer, do the same with the subnet's address, &
-mask both with 0xFFFFFFFF << (32-20)
and compare:
unsigned int net = ..., ip = ...;
int network_bits = 20;
unsigned int mask = 0xFFFFFFFF << (32 - network_bits);
if ((net & mask) == (ip & mask)) {
// ...
}
If you are working with ASP.NET Core there is a new class IPNetwork
which can be used to test if an IP Address is in a specific network.
For example the following code snippet checks if 192.168.1.1
is part of 192.168.1.0/6
IPNetwork ipnetwork = new IPNetwork(IPAddress.Parse("192.168.1.0"), 6);
bool isPartOfTheSubnet = ipnetwork.Contains(IPAddress.Parse("192.168.1.1"));
Since the MSDN blog code relies on a broadcast and IPv6 doesn't have one, I don't know if it works with IPv6.
I ended up with these methods (thanks to nu everest). You can get the subnet and mask from a CIDR notation ("1.2.3.4/5") and check whether an adress is within this network or not.
This works for IPv4 and IPv6:
public static class IpAddresses
{
public static Tuple<IPAddress, IPAddress> GetSubnetAndMaskFromCidr(string cidr)
{
var delimiterIndex = cidr.IndexOf('/');
string ipSubnet = cidr.Substring(0, delimiterIndex);
string mask = cidr.Substring(delimiterIndex + 1);
var subnetAddress = IPAddress.Parse(ipSubnet);
if (subnetAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
// ipv6
var ip = BigInteger.Parse("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", NumberStyles.HexNumber) << (128 - int.Parse(mask));
var maskBytes = new[]
{
(byte)((ip & BigInteger.Parse("00FF000000000000000000000000000000", NumberStyles.HexNumber)) >> 120),
(byte)((ip & BigInteger.Parse("0000FF0000000000000000000000000000", NumberStyles.HexNumber)) >> 112),
(byte)((ip & BigInteger.Parse("000000FF00000000000000000000000000", NumberStyles.HexNumber)) >> 104),
(byte)((ip & BigInteger.Parse("00000000FF000000000000000000000000", NumberStyles.HexNumber)) >> 96),
(byte)((ip & BigInteger.Parse("0000000000FF0000000000000000000000", NumberStyles.HexNumber)) >> 88),
(byte)((ip & BigInteger.Parse("000000000000FF00000000000000000000", NumberStyles.HexNumber)) >> 80),
(byte)((ip & BigInteger.Parse("00000000000000FF000000000000000000", NumberStyles.HexNumber)) >> 72),
(byte)((ip & BigInteger.Parse("0000000000000000FF0000000000000000", NumberStyles.HexNumber)) >> 64),
(byte)((ip & BigInteger.Parse("000000000000000000FF00000000000000", NumberStyles.HexNumber)) >> 56),
(byte)((ip & BigInteger.Parse("00000000000000000000FF000000000000", NumberStyles.HexNumber)) >> 48),
(byte)((ip & BigInteger.Parse("0000000000000000000000FF0000000000", NumberStyles.HexNumber)) >> 40),
(byte)((ip & BigInteger.Parse("000000000000000000000000FF00000000", NumberStyles.HexNumber)) >> 32),
(byte)((ip & BigInteger.Parse("00000000000000000000000000FF000000", NumberStyles.HexNumber)) >> 24),
(byte)((ip & BigInteger.Parse("0000000000000000000000000000FF0000", NumberStyles.HexNumber)) >> 16),
(byte)((ip & BigInteger.Parse("000000000000000000000000000000FF00", NumberStyles.HexNumber)) >> 8),
(byte)((ip & BigInteger.Parse("00000000000000000000000000000000FF", NumberStyles.HexNumber)) >> 0),
};
return Tuple.Create(subnetAddress, new IPAddress(maskBytes));
}
else
{
// ipv4
uint ip = 0xFFFFFFFF << (32 - int.Parse(mask));
var maskBytes = new[]
{
(byte)((ip & 0xFF000000) >> 24),
(byte)((ip & 0x00FF0000) >> 16),
(byte)((ip & 0x0000FF00) >> 8),
(byte)((ip & 0x000000FF) >> 0),
};
return Tuple.Create(subnetAddress, new IPAddress(maskBytes));
}
}
public static bool IsAddressOnSubnet(IPAddress address, IPAddress subnet, IPAddress mask)
{
byte[] addressOctets = address.GetAddressBytes();
byte[] subnetOctets = mask.GetAddressBytes();
byte[] networkOctets = subnet.GetAddressBytes();
// ensure that IPv4 isn't mixed with IPv6
if (addressOctets.Length != subnetOctets.Length
|| addressOctets.Length != networkOctets.Length)
{
return false;
}
for (int i = 0; i < addressOctets.Length; i += 1)
{
var addressOctet = addressOctets[i];
var subnetOctet = subnetOctets[i];
var networkOctet = networkOctets[i];
if (networkOctet != (addressOctet & subnetOctet))
{
return false;
}
}
return true;
}
}
Example usage:
var subnetAndMask = IpAddresses.GetSubnetAndMaskFromCidr("10.132.0.0/20");
bool result = IpAddresses.IsAddressOnSubnet(
IPAddress.Parse("10.132.12.34"),
subnetAndMask.Item1,
subnetAndMask.Item2);
if ((networkOctet & subnetOctet) != (addressOctet & subnetOctet))
and it started to return correct results. –
Trophoplasm The solution is to convert the IP Address into bytes using System.Net.IPAddress
and perform bitwise comparisons on the address, subnet, and mask octets.
The Binary AND Operator &
copies a bit to the result if it exists in both operands.
The code:
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;
}
}
Special thanks to Reference
I'm late to the party here, but had a similar need, and put together a quick package to do exactly this.
https://www.nuget.org/packages/IpMatcher/
and source:
https://github.com/jchristn/IpMatcher
Simple use:
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
Now in dotnet 8 you can use this
How to check if an IP address is within a particular subnet
IPAddress address = IPAddress.Parse("2001:0db8::1");
IPNetwork ipnetwork = IPNetwork.Parse("2001:0db8::1/128");
bool contains1 = ipnetwork.Contains(address);
I have also created a class which calculates the network and broadcast address and checks if the IP is neither broadcast nor network address.
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;
}
A little correction of Chris Shouts answer for the comments asking for IPV6 support:
public static IPAddress GetNetworkAddress(this IPAddress address, IPAddress subnetMask)
{
byte[] ipAdressBytes = address.GetAddressBytes();
byte[] subnetMaskBytes = subnetMask.GetAddressBytes();
if (ipAdressBytes.Length != subnetMaskBytes.Length)
subnetMaskBytes = subnetMask.MapToIPv6().GetAddressBytes();
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);
}
© 2022 - 2024 — McMap. All rights reserved.