Skip to content

Instantly share code, notes, and snippets.

@KerryRitter
Created October 30, 2015 19:09
Show Gist options
  • Save KerryRitter/124833500ccc6872b694 to your computer and use it in GitHub Desktop.
Save KerryRitter/124833500ccc6872b694 to your computer and use it in GitHub Desktop.
Does calculations and math on IP Addresses, CIDR ranges, subnet masks
/// <summary>
/// Class for doing IP Address and network calculations
/// </summary>
public class IpRangeCalculator
{
public readonly Dictionary<string, string> CidrSuffixesForMask = new Dictionary<string, string>
{
{ "255.255.255.255", "32" },
{ "255.255.255.254", "31" },
{ "255.255.255.252", "30" },
{ "255.255.255.248", "29" },
{ "255.255.255.240", "28" },
{ "255.255.255.224", "27" },
{ "255.255.255.192", "26" },
{ "255.255.255.128", "25" },
{ "255.255.255.0", "24" },
{ "255.255.254.0", "23" },
{ "255.255.252.0", "22" },
{ "255.255.248.0", "21" },
{ "255.255.240.0", "20" },
{ "255.255.224.0", "19" },
{ "255.255.192.0", "18" },
{ "255.255.128.0", "17" },
{ "255.255.0.0", "16" },
{ "255.254.0.0", "15" },
{ "255.252.0.0", "14" },
{ "255.248.0.0", "13" },
{ "255.240.0.0", "12" },
{ "255.224.0.0", "11" },
{ "255.192.0.0", "10" },
{ "255.128.0.0", "9" },
{ "255.0.0.0", "8" },
{ "254.0.0.0", "7" },
{ "252.0.0.0", "6" },
{ "248.0.0.0", "5" },
{ "240.0.0.0", "4" },
{ "224.0.0.0", "3" },
{ "192.0.0.0", "2" },
{ "128.0.0.0", "1" },
{ "0.0.0.0", "0" }
};
/// <summary>
/// Gets the CIDR suffix for the subnet mask.
/// </summary>
/// <param name="subnetMask">The subnet mask.</param>
/// <returns></returns>
public string GetCidrSuffixForSubnetMask(string subnetMask)
{
if (CidrSuffixesForMask.ContainsKey(subnetMask))
{
return CidrSuffixesForMask[subnetMask];
}
return null;
}
/// <summary>
/// Calculates the ip range for subnet mask.
/// </summary>
/// <param name="ip">The ip.</param>
/// <param name="mask">The mask.</param>
/// <returns>The starting IP, the Ending IP address.</returns>
public Tuple<IPAddress, IPAddress> CalculateIpRangeForSubnetMask(string ip, string mask)
{
var prefix = GetCidrSuffixForSubnetMask(mask);
if (prefix == null)
{
throw new Exception($"Could not parse subnet mask value of {mask}");
}
var cidr = $"{ip.Trim()}/{prefix}";
return CalculateIpRangeForCidrSubnet(cidr);
}
/// <summary>
/// Calculates the ip range for cidr subnet.
/// </summary>
/// <param name="cidrNetwork">The cidr network.</param>
/// <returns>The starting IP, the Ending IP address.</returns>
/// <exception cref="System.Exception">The CIDR Range input is invalid. Example: 10.10.10.10/24</exception>
public Tuple<IPAddress, IPAddress> CalculateIpRangeForCidrSubnet(string cidrNetwork)
{
var parts = cidrNetwork.Split('/');
if (parts.Length != 2)
{
throw new Exception("The CIDR Range input is invalid. Example: 10.10.10.10/24");
}
var ipBytes = IPAddress.Parse(parts[0]).GetAddressBytes();
var bits = Convert.ToInt32(parts[1], 10);
var mask = ~(uint.MaxValue >> bits);
// BitConverter gives bytes in opposite order to GetAddressBytes().
var maskBytes = BitConverter.GetBytes(mask).Reverse().ToArray();
var startIpBytes = new byte[ipBytes.Length];
var endIpBytes = new byte[ipBytes.Length];
// Calculate the bytes of the start and end IP addresses.
for (var i = 0; i < ipBytes.Length; i++)
{
startIpBytes[i] = (byte)(ipBytes[i] & maskBytes[i]);
endIpBytes[i] = (byte)(ipBytes[i] | ~maskBytes[i]);
}
// Convert the bytes to IP addresses.
var startIp = new IPAddress(startIpBytes);
var endIp = new IPAddress(endIpBytes);
return new Tuple<IPAddress, IPAddress>(startIp, endIp);
}
/// <summary>
/// Determines whether the IP addresses are the same.
/// </summary>
/// <param name="address">The address.</param>
/// <param name="address2">The address2.</param>
/// <returns></returns>
public bool AreAddressesEqual(string address, string address2)
{
return AreAddressesEqual(IPAddress.Parse(address), IPAddress.Parse(address2));
}
/// <summary>
/// Determines whether the IP addresses are the same.
/// </summary>
/// <param name="address">The address.</param>
/// <param name="address2">The address2.</param>
/// <returns></returns>
public bool AreAddressesEqual(IPAddress address, IPAddress address2)
{
var address1Bytes = BitConverter.ToInt32(address.GetAddressBytes().Reverse().ToArray(), 0);
var address2Bytes = BitConverter.ToInt32(address2.GetAddressBytes().Reverse().ToArray(), 0);
return address1Bytes == address2Bytes;
}
/// <summary>
/// Determines whether the address falls within a given range
/// </summary>
/// <param name="address">The address.</param>
/// <param name="ipRangeStart">The ip range start.</param>
/// <param name="ipRangeEnd">The ip range end.</param>
/// <returns></returns>
public bool IsAddressInRange(string address, string ipRangeStart, string ipRangeEnd)
{
return IsAddressInRange(IPAddress.Parse(address), IPAddress.Parse(ipRangeStart), IPAddress.Parse(ipRangeEnd));
}
/// <summary>
/// Determines whether the address falls within a given range
/// </summary>
/// <param name="address">The address.</param>
/// <param name="ipRangeStart">The ip range start.</param>
/// <param name="ipRangeEnd">The ip range end.</param>
/// <returns></returns>
public bool IsAddressInRange(IPAddress address, IPAddress ipRangeStart, IPAddress ipRangeEnd)
{
var addressFamily = ipRangeStart.AddressFamily;
var lowerBytes = ipRangeStart.GetAddressBytes();
var upperBytes = ipRangeEnd.GetAddressBytes();
if (address.AddressFamily != addressFamily)
{
return false;
}
var addressBytes = address.GetAddressBytes();
bool lowerBoundary = true, upperBoundary = true;
for (var i = 0; i < lowerBytes.Length &&
(lowerBoundary || upperBoundary); i++)
{
if ((lowerBoundary && addressBytes[i] < lowerBytes[i]) ||
(upperBoundary && addressBytes[i] > upperBytes[i]))
{
return false;
}
lowerBoundary &= (addressBytes[i] == lowerBytes[i]);
upperBoundary &= (addressBytes[i] == upperBytes[i]);
}
return true;
}
/// <summary>
/// Determines whether the address falls the given network and CIDR
/// </summary>
/// <param name="address">The address.</param>
/// <param name="network">The network.</param>
/// <returns></returns>
public bool IsAddressInCidrRange(string address, string network)
{
throw new NotImplementedException();
}
/// <summary>
/// Determines whether the address falls the given network and CIDR
/// </summary>
/// <param name="address">The address.</param>
/// <param name="network">The network.</param>
/// <returns></returns>
public bool IsAddressInCidrRange(IPAddress address, string network)
{
var ipsForCidrNetwork = CalculateIpRangeForCidrSubnet(network);
return IsAddressInRange(address, ipsForCidrNetwork.Item1, ipsForCidrNetwork.Item2);
}
/// <summary>
/// Determines whether the address is within the given network with its mask
/// </summary>
/// <param name="address">The address.</param>
/// <param name="networkAddress">The network address.</param>
/// <param name="mask">The mask.</param>
/// <returns></returns>
public bool IsAddressInSubnetRange(string address, string networkAddress, string mask)
{
return IsAddressInSubnetRange(IPAddress.Parse(address), IPAddress.Parse(networkAddress), IPAddress.Parse(mask));
}
/// <summary>
/// Determines whether the address is within the given network with its mask
/// </summary>
/// <param name="address">The address.</param>
/// <param name="networkAddress">The network address.</param>
/// <param name="mask">The mask.</param>
/// <returns></returns>
public bool IsAddressInSubnetRange(IPAddress address, IPAddress networkAddress, IPAddress mask)
{
if (address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork)
{
return false;
}
if (address.Equals(networkAddress))
{
return true;
}
var ipsForSubnetNetwork = CalculateIpRangeForSubnetMask(networkAddress.ToString(), mask.ToString());
return IsAddressInRange(address, ipsForSubnetNetwork.Item1, ipsForSubnetNetwork.Item2);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment