Skip to content

Instantly share code, notes, and snippets.

@brendanmckenzie brendanmckenzie/cidr.cs
Last active Aug 29, 2015

Embed
What would you like to do?
public enum CidrGroup
{
Local,
Australia,
NewZealand
}
/// <summary>
/// Provides an easy interface for determining whether CIDR blocks contain specified IP addresses
/// </summary>
/// <remarks>
/// The data for the CIDR files is sourced from http://www.ipaddresslocation.org/ip_ranges/get_ranges.php
/// The format of the file is just new-line delimited with a CIDR on each line
/// in the format of ip/mask (i.e., 14.192.177.0/24)
/// </remarks>
public class Cidr
{
#region Private Members
string _cidr;
IPAddress _start;
byte[] _startBytes;
IPAddress _end;
byte[] _endBytes;
#region Static
static Dictionary<CidrGroup, ICollection<Cidr>> _groups;
#endregion
#endregion
#region Constructors
private Cidr() { }
#endregion
#region Public Methods
#region Overrides
public override string ToString()
{
return string.Format("{0} ({1} - {2})", _cidr, _start, _end);
}
#endregion
#region Static
/// <summary>
/// Parses the specified CIDR and returns an instance if it's found to be valid.
/// </summary>
/// <param name="cidr">The string representation of the CIDR.</param>
/// <example>14.192.177.0/24</example>
/// <returns>An instance of the CIDR class if a valid CIDR is supplied.</returns>
/// <exception cref="System.ArgumentNullException">Thrown when the passed CIDR string is null.</exception>
/// <exception cref="System.FormatException">
/// Thrown when the CIDR is in the incorrect format
/// or when the IP address in the CIDR is invalid
/// or when the mask in the CIDR is invalid.
/// </exception>
public static Cidr Parse(string cidr)
{
if (cidr == null)
{
throw new ArgumentNullException("cidr");
}
var ret = new Cidr();
ret._cidr = cidr;
var parts = cidr.Trim().Split('/');
if (parts.Length != 2)
{
throw new FormatException("Invalid CIDR: " + cidr);
}
IPAddress ip;
if (!IPAddress.TryParse(parts[0], out ip))
{
throw new FormatException(string.Format("Invalid IP address: {0} ({1})", parts[0], cidr));
}
int mask;
if (!int.TryParse(parts[1], out mask))
{
throw new FormatException(string.Format("Invalid mask: {0} ({1})", parts[1], cidr));
}
var ipBytes = ip.GetAddressBytes();
var maskBytes = BitConverter.GetBytes(~(uint.MaxValue >> mask)).Reverse().ToArray();
ret._startBytes = new byte[ipBytes.Length];
ret._endBytes = new byte[ipBytes.Length];
for (var i = 0; i < ipBytes.Length; i++)
{
ret._startBytes[i] = (byte)(ipBytes[i] & maskBytes[i]);
ret._endBytes[i] = (byte)(ipBytes[i] | (~maskBytes[i]));
}
ret._start = new IPAddress(ret._startBytes);
ret._end = new IPAddress(ret._endBytes);
return ret;
}
/// <summary>
/// Loads a list of CIDRs from a file and marks them as the specified group.
/// </summary>
/// <param name="group">The group.</param>
/// <param name="file">The file.</param>
public static void LoadGroup(CidrGroup group, string file)
{
_groups = _groups ?? new Dictionary<CidrGroup, ICollection<Cidr>>();
var g = _groups.ContainsKey(group) ? new List<Cidr>(_groups[group]) : new List<Cidr>();
foreach (var cidr in File.ReadAllLines(file))
{
var element = Parse(cidr);
if (element != null)
{
g.Add(element);
}
}
if (_groups.ContainsKey(group))
{
_groups[group] = g.ToArray();
}
else
{
_groups.Add(group, g.ToArray());
}
}
/// <summary>
/// Gets the CIDR group name from the specified address.
/// </summary>
/// <param name="address">The address.</param>
/// <returns>The name of the group the specified address belongs to; or null if it does not belong to any known groups.</returns>
public static CidrGroup? GetGroupFromAddress(IPAddress address)
{
if (_groups == null) { return null; }
foreach (var group in _groups)
{
foreach (var cidr in group.Value)
{
if (cidr.Contains(address))
{
return group.Key;
}
}
}
return null;
}
/// <summary>
/// Parses the specified address and gets the associated CIDR group name.
/// </summary>
/// <param name="address">The string representation of the address.</param>
/// <returns>The name of the group the specified address belongs to; or null if it does not belong to any known groups.</returns>
public static CidrGroup? GetGroupFromAddress(string address)
{
return GetGroupFromAddress(IPAddress.Parse(address));
}
#endregion
/// <summary>
/// Determines whether this CIDR block contains the specified address.
/// </summary>
/// <param name="address">The address.</param>
/// <returns><c>true</c> if the address exists inside the CIDR block; otherwise <c>false</c>.</returns>
public bool Contains(IPAddress address)
{
var addressBytes = address.GetAddressBytes();
var lowerBoundary = true;
var upperBoundary = true;
for (var i = 0; i < _startBytes.Length && (lowerBoundary || upperBoundary); i++)
{
if ((lowerBoundary && addressBytes[i] < _startBytes[i]) ||
(upperBoundary && addressBytes[i] > _endBytes[i]))
{
return false;
}
lowerBoundary &= (addressBytes[i] == _startBytes[i]);
upperBoundary &= (addressBytes[i] == _endBytes[i]);
}
return true;
}
/// <summary>
/// Parses the supplied address and determines whether this CIDR block contains it.
/// </summary>
/// <param name="address">The string representation of the address.</param>
/// <returns><c>true</c> if the address exists inside the CIDR block; otherwise <c>false</c>.</returns>
public bool Contains(string address)
{
return Contains(IPAddress.Parse(address));
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.