Created
April 17, 2015 08:22
-
-
Save mikaelnet/de9b7bf62e15f6b8c74d to your computer and use it in GitHub Desktop.
Extension methods for handling IPv4 addresses
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
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