You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
4.7 KiB
143 lines
4.7 KiB
using System;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace Znyc.Cloudcar.Admin.Commons.Net
|
|
{
|
|
/// <summary>
|
|
/// IP v4 and v6 range helper by jsakamoto
|
|
/// Fork from https://github.com/jsakamoto/ipaddressrange
|
|
/// </summary>
|
|
/// <example>
|
|
/// "192.168.0.0/24"
|
|
/// "fe80::/10"
|
|
/// "192.168.0.0/255.255.255.0"
|
|
/// "192.168.0.0-192.168.0.255"
|
|
/// </example>
|
|
public class IpAddressRange
|
|
{
|
|
public IPAddress Begin { get; set; }
|
|
|
|
public IPAddress End { get; set; }
|
|
|
|
public IpAddressRange()
|
|
{
|
|
Begin = new IPAddress(0L);
|
|
End = new IPAddress(0L);
|
|
}
|
|
|
|
public IpAddressRange(string ipRangeString)
|
|
{
|
|
// remove all spaces.
|
|
ipRangeString = ipRangeString.Replace(" ", "");
|
|
|
|
// Pattern 1. CIDR range: "192.168.0.0/24", "fe80::/10"
|
|
Match m1 = Regex.Match(ipRangeString, @"^(?<adr>[\da-f\.:]+)/(?<maskLen>\d+)$", RegexOptions.IgnoreCase);
|
|
if (m1.Success)
|
|
{
|
|
byte[] baseAdrBytes = IPAddress.Parse(m1.Groups["adr"].Value).GetAddressBytes();
|
|
byte[] maskBytes = Bits.GetBitMask(baseAdrBytes.Length, int.Parse(m1.Groups["maskLen"].Value));
|
|
baseAdrBytes = Bits.And(baseAdrBytes, maskBytes);
|
|
Begin = new IPAddress(baseAdrBytes);
|
|
End = new IPAddress(Bits.Or(baseAdrBytes, Bits.Not(maskBytes)));
|
|
return;
|
|
}
|
|
|
|
// Pattern 2. Uni address: "127.0.0.1", ":;1"
|
|
Match m2 = Regex.Match(ipRangeString, @"^(?<adr>[\da-f\.:]+)$", RegexOptions.IgnoreCase);
|
|
if (m2.Success)
|
|
{
|
|
Begin = End = IPAddress.Parse(ipRangeString);
|
|
return;
|
|
}
|
|
|
|
// Pattern 3. Begin end range: "169.258.0.0-169.258.0.255"
|
|
Match m3 = Regex.Match(ipRangeString, @"^(?<begin>[\da-f\.:]+)-(?<end>[\da-f\.:]+)$",
|
|
RegexOptions.IgnoreCase);
|
|
if (m3.Success)
|
|
{
|
|
Begin = IPAddress.Parse(m3.Groups["begin"].Value);
|
|
End = IPAddress.Parse(m3.Groups["end"].Value);
|
|
return;
|
|
}
|
|
|
|
// Pattern 4. Bit mask range: "192.168.0.0/255.255.255.0"
|
|
Match m4 = Regex.Match(ipRangeString, @"^(?<adr>[\da-f\.:]+)/(?<bitmask>[\da-f\.:]+)$",
|
|
RegexOptions.IgnoreCase);
|
|
if (m4.Success)
|
|
{
|
|
byte[] baseAdrBytes = IPAddress.Parse(m4.Groups["adr"].Value).GetAddressBytes();
|
|
byte[] maskBytes = IPAddress.Parse(m4.Groups["bitmask"].Value).GetAddressBytes();
|
|
baseAdrBytes = Bits.And(baseAdrBytes, maskBytes);
|
|
Begin = new IPAddress(baseAdrBytes);
|
|
End = new IPAddress(Bits.Or(baseAdrBytes, Bits.Not(maskBytes)));
|
|
return;
|
|
}
|
|
|
|
throw new FormatException("Unknown IP range string.");
|
|
}
|
|
|
|
public bool Contains(IPAddress ipaddress)
|
|
{
|
|
if (ipaddress.AddressFamily != Begin.AddressFamily)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
byte[] adrBytes = ipaddress.GetAddressBytes();
|
|
return Bits.GE(Begin.GetAddressBytes(), adrBytes) && Bits.LE(End.GetAddressBytes(), adrBytes);
|
|
}
|
|
}
|
|
|
|
internal static class Bits
|
|
{
|
|
internal static byte[] Not(byte[] bytes)
|
|
{
|
|
return bytes.Select(b => (byte)~b).ToArray();
|
|
}
|
|
|
|
internal static byte[] And(byte[] A, byte[] B)
|
|
{
|
|
return A.Zip(B, (a, b) => (byte)(a & b)).ToArray();
|
|
}
|
|
|
|
internal static byte[] Or(byte[] A, byte[] B)
|
|
{
|
|
return A.Zip(B, (a, b) => (byte)(a | b)).ToArray();
|
|
}
|
|
|
|
internal static bool GE(byte[] A, byte[] B)
|
|
{
|
|
return A.Zip(B, (a, b) => a == b ? 0 : a < b ? 1 : -1)
|
|
.SkipWhile(c => c == 0)
|
|
.FirstOrDefault() >= 0;
|
|
}
|
|
|
|
internal static bool LE(byte[] A, byte[] B)
|
|
{
|
|
return A.Zip(B, (a, b) => a == b ? 0 : a < b ? 1 : -1)
|
|
.SkipWhile(c => c == 0)
|
|
.FirstOrDefault() <= 0;
|
|
}
|
|
|
|
internal static byte[] GetBitMask(int sizeOfBuff, int bitLen)
|
|
{
|
|
byte[] maskBytes = new byte[sizeOfBuff];
|
|
int bytesLen = bitLen / 8;
|
|
int bitsLen = bitLen % 8;
|
|
for (int i = 0; i < bytesLen; i++)
|
|
{
|
|
maskBytes[i] = 0xff;
|
|
}
|
|
|
|
if (bitsLen > 0)
|
|
{
|
|
maskBytes[bytesLen] = (byte)~Enumerable.Range(1, 8 - bitsLen).Select(n => 1 << (n - 1))
|
|
.Aggregate((a, b) => a | b);
|
|
}
|
|
|
|
return maskBytes;
|
|
}
|
|
}
|
|
}
|