Created
October 30, 2015 19:09
-
-
Save KerryRitter/124833500ccc6872b694 to your computer and use it in GitHub Desktop.
Does calculations and math on IP Addresses, CIDR ranges, subnet masks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <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