/// <summary>
        /// Gets the length of the prefix.
        /// </summary>
        /// <returns>The length of the prefix.</returns>
        public int GetPrefixLength()
        {
            byte[] byteBegin = this.Begin.GetAddressBytes();
            byte[] byteEnd   = this.End.GetAddressBytes();

            if (this.Begin.Equals(this.End))
            {
                return(byteBegin.Length * 8);
            }

            int length = byteBegin.Length * 8;

            for (int i = 0; i < length; i++)
            {
                byte[] mask = Bitwise.GetBitMask(byteBegin.Length, i);

                if (new IPAddress(Bitwise.And(byteBegin, mask)).Equals(this.Begin))
                {
                    if (new IPAddress(Bitwise.Or(byteBegin, Bitwise.Not(mask))).Equals(this.End))
                    {
                        return(i);
                    }
                }
            }

            throw new FormatException(string.Format("{0} is not a CIDR Subnet", this.ToString()));
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="IPAddressRange"/> class.
        /// Create a new range from a begin and end address. Throws an exception if Begin comes after End, or the addresses are not in the same family.
        /// </summary>
        /// <param name="begin">The begin IPAddress.</param>
        /// <param name="end">The end IPAddress.</param>
        public IPAddressRange(IPAddress begin, IPAddress end)
        {
            if (begin == null)
            {
                throw new ArgumentNullException("begin");
            }

            if (end == null)
            {
                throw new ArgumentNullException("end");
            }

            if (begin.AddressFamily != end.AddressFamily)
            {
                throw new ArgumentException("IPAddress must be of the same address family", "end");
            }

            var beginBytes = begin.GetAddressBytes();
            var endBytes   = end.GetAddressBytes();

            if (!Bitwise.LessEqual(endBytes, beginBytes))
            {
                throw new ArgumentException("Begin must be smaller than the End", "begin");
            }

            this.Begin = begin;
            this.End   = end;
        }
        /// <summary>
        /// Returns an enumerator that iterates through the collection.
        /// </summary>
        /// <returns>An enumerator that can be used to iterate through the collection.</returns>
        public IEnumerator <IPAddress> GetEnumerator()
        {
            var first = this.Begin.GetAddressBytes();
            var last  = this.End.GetAddressBytes();

            for (var ip = first; Bitwise.GreaterEqual(ip, last); ip = Bitwise.Increment(ip))
            {
                yield return(new IPAddress(ip));
            }
        }
        /// <summary>
        /// Parses the specified ip range string.
        /// </summary>
        /// <param name="ipRangeString">The ip range string.</param>
        /// <returns>IPAddressRange instance.</returns>
        public static IPAddressRange Parse(string ipRangeString)
        {
            if (ipRangeString == null)
            {
                throw new ArgumentNullException("ipRangeString");
            }

            ipRangeString = ipRangeString.Replace(" ", string.Empty);

            var matchCidrRange = RegexCidrRange.Match(ipRangeString);

            if (matchCidrRange.Success)
            {
                var baseAdrBytes = IPAddress.Parse(matchCidrRange.Groups["adr"].Value).GetAddressBytes();
                var maskLength   = int.Parse(matchCidrRange.Groups["maskLen"].Value);

                if (baseAdrBytes.Length * 8 < maskLength)
                {
                    throw new FormatException();
                }

                var maskBytes = Bitwise.GetBitMask(baseAdrBytes.Length, maskLength);
                baseAdrBytes = Bitwise.And(baseAdrBytes, maskBytes);

                return(new IPAddressRange(new IPAddress(baseAdrBytes), new IPAddress(Bitwise.Or(baseAdrBytes, Bitwise.Not(maskBytes)))));
            }

            var matchSingleAddress = RegexSingleAddress.Match(ipRangeString);

            if (matchSingleAddress.Success)
            {
                return(new IPAddressRange(IPAddress.Parse(ipRangeString)));
            }

            var matchAddressRange = RegexAddressRange.Match(ipRangeString);

            if (matchAddressRange.Success)
            {
                return(new IPAddressRange(IPAddress.Parse(matchAddressRange.Groups["begin"].Value), IPAddress.Parse(matchAddressRange.Groups["end"].Value)));
            }

            var matchBitMaskRange = RegexBitMaskRange.Match(ipRangeString);

            if (matchBitMaskRange.Success)
            {
                var baseAdrBytes = IPAddress.Parse(matchBitMaskRange.Groups["adr"].Value).GetAddressBytes();
                var maskBytes    = IPAddress.Parse(matchBitMaskRange.Groups["bitmask"].Value).GetAddressBytes();
                baseAdrBytes = Bitwise.And(baseAdrBytes, maskBytes);

                return(new IPAddressRange(new IPAddress(baseAdrBytes), new IPAddress(Bitwise.Or(baseAdrBytes, Bitwise.Not(maskBytes)))));
            }

            throw new FormatException("Unknown IP range string.");
        }
        /// <summary>
        /// Determines whether the current IPAddressRange contains the specified ip address range.
        /// </summary>
        /// <param name="ipAddressRange">The ip address range.</param>
        /// <returns>true if the current IPAddressRange contains the specified ip address range; otherwise, false.</returns>
        public bool Contains(IPAddressRange ipAddressRange)
        {
            if (ipAddressRange == null)
            {
                throw new ArgumentNullException("ipAddressRange");
            }

            if (this.Begin.AddressFamily != ipAddressRange.Begin.AddressFamily)
            {
                return(false);
            }

            return
                (Bitwise.GreaterEqual(this.Begin.GetAddressBytes(), ipAddressRange.Begin.GetAddressBytes()) &&
                 Bitwise.LessEqual(this.End.GetAddressBytes(), ipAddressRange.End.GetAddressBytes()));
        }
        /// <summary>
        /// Takes a subnet mask (eg, "255.255.254.0") and returns the CIDR bit length of that address. Throws an exception if the passed address is not valid as a subnet mask.
        /// </summary>
        /// <param name="subnetMask">The subnet mask to use.</param>
        /// <returns>The subnet mask length.</returns>
        public static int GetSubnetMaskLength(IPAddress subnetMask)
        {
            if (subnetMask == null)
            {
                throw new ArgumentNullException("subnetMask");
            }

            var length = Bitwise.GetBitMaskLength(subnetMask.GetAddressBytes());

            if (length == null)
            {
                throw new ArgumentException("It is not a valid subnet mask.", "subnetMask");
            }

            return(length.Value);
        }
        /// <summary>
        /// Determines whether the current IPAddressRange contains the specified ip address.
        /// </summary>
        /// <param name="ipAddress">The ip address.</param>
        /// <returns>true if the current IPAddressRange contains the specified ip address; otherwise, false.</returns>
        public bool Contains(IPAddress ipAddress)
        {
            if (ipAddress == null)
            {
                throw new ArgumentNullException("ipAddress");
            }

            if (ipAddress.AddressFamily != this.Begin.AddressFamily)
            {
                return(false);
            }

            var adrBytes = ipAddress.GetAddressBytes();

            return
                (Bitwise.GreaterEqual(this.Begin.GetAddressBytes(), adrBytes) &&
                 Bitwise.LessEqual(this.End.GetAddressBytes(), adrBytes));
        }
        /// <summary>
        /// Determines whether the current IPAddressRange contains the specified ip address.
        /// </summary>
        /// <param name="ipAddressString">The ip address.</param>
        /// <returns>true if the current IPAddressRange contains the specified ip address; otherwise, false.</returns>
        public bool Contains(string ipAddressString)
        {
            if (string.IsNullOrEmpty(ipAddressString))
            {
                throw new ArgumentNullException("ipAddressString");
            }

            var ipAddress = IPAddress.Parse(ipAddressString);

            if (ipAddress.AddressFamily != this.Begin.AddressFamily)
            {
                return(false);
            }

            var adrBytes = ipAddress.GetAddressBytes();

            return
                (Bitwise.GreaterEqual(this.Begin.GetAddressBytes(), adrBytes) &&
                 Bitwise.LessEqual(this.End.GetAddressBytes(), adrBytes));
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="IPAddressRange"/> class.
        /// Creates a range from a base address and mask bits. This can also be used with <see cref="GetSubnetMaskLength"/> to create a range based on a subnet mask.
        /// </summary>
        /// <param name="baseAddress">The base address.</param>
        /// <param name="maskLength">Length of the mask.</param>
        public IPAddressRange(IPAddress baseAddress, int maskLength)
        {
            if (baseAddress == null)
            {
                throw new ArgumentNullException("baseAddress");
            }

            var baseAdrBytes = baseAddress.GetAddressBytes();

            if (baseAdrBytes.Length * 8 < maskLength)
            {
                throw new FormatException();
            }

            var maskBytes = Bitwise.GetBitMask(baseAdrBytes.Length, maskLength);

            baseAdrBytes = Bitwise.And(baseAdrBytes, maskBytes);

            this.Begin = new IPAddress(baseAdrBytes);
            this.End   = new IPAddress(Bitwise.Or(baseAdrBytes, Bitwise.Not(maskBytes)));
        }