Skip to content

Instantly share code, notes, and snippets.

@mikaelnet
Created April 17, 2015 08:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikaelnet/de9b7bf62e15f6b8c74d to your computer and use it in GitHub Desktop.
Save mikaelnet/de9b7bf62e15f6b8c74d to your computer and use it in GitHub Desktop.
Extension methods for handling IPv4 addresses
public static class IPAddressExtensions
{
/// <summary>
/// Tests if a given IPv4 address is within any of the private
/// IP address ranges, 10.0.0.0/8, 172.16.0.0/12 or 192.168.0.0/16
/// </summary>
/// <param name="address"></param>
/// <returns>True if the address is private, otherwise false.
/// Note: IPv6 address always returns false</returns>
/// <exception cref="NotSupportedException">For unknown address families (other than IPv4 and IPv6)</exception>
public static bool IsPrivateAddress(this IPAddress address)
{
if (address.AddressFamily == AddressFamily.InterNetwork)
{
byte[] addressBytes = address.GetAddressBytes();
if (addressBytes[0] == 10)
return true; // 10.0.0.0/8
if (addressBytes[0] == 172 && addressBytes[1] >= 16 && addressBytes[1] <= 31)
return true; // 172.16.0.0/12
if (addressBytes[0] == 192 && addressBytes[1] == 168)
return true; // 192.168.0.0/16
return false;
}
if (address.AddressFamily == AddressFamily.InterNetworkV6)
return false;
throw new NotSupportedException("Unsupported address family");
}
/// <summary>
/// Tests if a given IP address is referencing localhost
/// </summary>
/// <param name="address"></param>
/// <returns>True for 127.0.0.0/8 and ::1, otherwise false</returns>
/// <exception cref="NotSupportedException">For unknown address families (other than IPv4 and IPv6)</exception>
public static bool IsLocalhost(this IPAddress address)
{
if (address.AddressFamily == AddressFamily.InterNetwork)
{
byte[] addressBytes = address.GetAddressBytes();
if (addressBytes[0] == 127)
return true; // 127.0.0.0/8
return false;
}
if (address.AddressFamily == AddressFamily.InterNetworkV6)
{
return address.IsIPv6SiteLocal;
}
throw new NotSupportedException("Unsupported address family");
}
/// <summary>
/// Gets the broadcast address for a given address and network mask
/// </summary>
/// <param name="address">An IPv4 address</param>
/// <param name="subnetMask">The network mask</param>
/// <returns>The broadcast IP address for the given address</returns>
/// <exception cref="NotSupportedException">For other address families than IPv4</exception>
public static IPAddress GetBroadcastAddress(this IPAddress address, IPAddress subnetMask)
{
if (address.AddressFamily != AddressFamily.InterNetwork)
throw new NotSupportedException("Unsupported address family. Only IPv4 suppored");
byte[] ipAddressBytes = address.GetAddressBytes();
byte[] subnetMaskBytes = subnetMask.GetAddressBytes();
if (ipAddressBytes.Length != subnetMaskBytes.Length)
throw new ArgumentException("Lengths of IP address and subnet mask do not match");
var broadcastAddressBytes = new byte[ipAddressBytes.Length];
for (int i = 0; i < broadcastAddressBytes.Length; i++)
{
broadcastAddressBytes[i] = (byte) (ipAddressBytes[i] | (subnetMaskBytes[i] ^ 255));
}
return new IPAddress(broadcastAddressBytes);
}
/// <summary>
/// Gets the network address for a given address and network mask
/// </summary>
/// <param name="address">An IPv4 address</param>
/// <param name="subnetMask">The network mask</param>
/// <returns>The network IP address for the given address</returns>
/// <exception cref="NotSupportedException">For other address families than IPv4</exception>
public static IPAddress GetNetworkAddress(this IPAddress address, IPAddress subnetMask)
{
if (address.AddressFamily != AddressFamily.InterNetwork)
throw new NotSupportedException("Unsupported address family. Only IPv4 suppored");
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.");
var broadcastAddress = new byte[ipAdressBytes.Length];
for (int i = 0; i < broadcastAddress.Length; i++)
{
broadcastAddress[i] = (byte)(ipAdressBytes[i] & (subnetMaskBytes[i]));
}
return new IPAddress(broadcastAddress);
}
/// <summary>
/// Tests if two addresses are within the same network
/// </summary>
/// <param name="address2"></param>
/// <param name="address"></param>
/// <param name="subnetMask"></param>
/// <returns>True if the two given addresses are within the same subnet</returns>
/// <exception cref="NotSupportedException">For other address families than IPv4</exception>
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);
}
/// <summary>
/// Tests if a given address is within a given subnet.
/// </summary>
/// <param name="address"></param>
/// <param name="network">A subnet in the form n.n.n.n/n</param>
/// <returns></returns>
/// <exception cref="NotSupportedException">For other address families than IPv4</exception>
public static bool IsInSameSubnet(this IPAddress address, string network)
{
IPAddress networkAddress;
IPAddress subnetMask;
ParseNetworkAddress(network, out networkAddress, out subnetMask);
return IsInSameSubnet(address, networkAddress, subnetMask);
}
/// <summary>
/// Tests if a given address is within any of the given subnets
/// </summary>
/// <param name="address"></param>
/// <param name="networks">A list of subnets in the form n.n.n.n/n</param>
/// <returns></returns>
/// <exception cref="NotSupportedException">For other address families than IPv4</exception>
public static bool IsInAnySubnet(this IPAddress address, IEnumerable<string> networks)
{
return networks.Any(address.IsInSameSubnet);
}
private static readonly Regex _networkRegex = new Regex(@"^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/([0-9]{1,2})$");
/// <summary>
/// Parses a network in the format of n.n.n.n/n into a network address and subnet mask
/// </summary>
/// <param name="network"></param>
/// <param name="networkAddress"></param>
/// <param name="subnetMask"></param>
/// <exception cref="ArgumentException">If the network parameter is not in the n.n.n.n/n format</exception>
public static void ParseNetworkAddress(string network, out IPAddress networkAddress, out IPAddress subnetMask)
{
var match = _networkRegex.Match(network);
if (!match.Success)
throw new ArgumentException("Network is not in the n.n.n.n/n format");
var baseAddress = IPAddress.Parse(match.Groups[1].Value);
var bits = int.Parse(match.Groups[2].Value);
if (bits < 0 || bits > 32)
throw new ArgumentException("Network mask is not between 0-31");
networkAddress = baseAddress;
long mask = 0;
for (int i = 0; i < 32; i++)
{
mask <<= 1;
mask |= i < bits ? 1 : 0;
}
var subnetMaskBytes = new byte[4];
subnetMaskBytes[0] = (byte) ((mask >> 24) & 0xFF);
subnetMaskBytes[1] = (byte) ((mask >> 16) & 0xFF);
subnetMaskBytes[2] = (byte) ((mask >> 8) & 0xFF);
subnetMaskBytes[3] = (byte) (mask & 0xFF);
subnetMask = new IPAddress(subnetMaskBytes);
var appliedBaseAddress = networkAddress.GetNetworkAddress(subnetMask);
if (!baseAddress.Equals(appliedBaseAddress))
throw new ArgumentException(string.Format("{0} is not the base address of {1}", baseAddress, network));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment