296 lines
11 KiB
C#
296 lines
11 KiB
C#
using System.Globalization;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using JNPF.DependencyInjection;
|
|
|
|
namespace JNPF.Common.Net
|
|
{
|
|
/// <summary>
|
|
/// IP位置查找操作类.
|
|
/// </summary>
|
|
[SuppressSniffer]
|
|
public class IpLocator
|
|
{
|
|
private readonly byte[] _data;
|
|
private readonly long _firstStartIpOffset;
|
|
private static readonly Regex Regex = new Regex(@"^(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))$");
|
|
|
|
/// <summary>
|
|
/// 初始化一个IP位置查找操作类的实例.
|
|
/// </summary>
|
|
/// <param name="dataPath"> IP信息数据文件路径.</param>
|
|
/// <exception cref="ArgumentException"></exception>
|
|
public IpLocator(string dataPath)
|
|
{
|
|
using (FileStream fs = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
|
{
|
|
_data = new byte[fs.Length];
|
|
fs.Read(_data, 0, _data.Length);
|
|
}
|
|
|
|
byte[] buffer = new byte[8];
|
|
Array.Copy(_data, 0, buffer, 0, 8);
|
|
_firstStartIpOffset = ((buffer[0] + (buffer[1] * 0x100)) + ((buffer[2] * 0x100) * 0x100)) + (((buffer[3] * 0x100) * 0x100) * 0x100);
|
|
long lastStartIpOffset = ((buffer[4] + (buffer[5] * 0x100)) + ((buffer[6] * 0x100) * 0x100)) + (((buffer[7] * 0x100) * 0x100) * 0x100);
|
|
Count = Convert.ToInt64((lastStartIpOffset - _firstStartIpOffset) / 7.0);
|
|
|
|
if (Count <= 1L)
|
|
throw new ArgumentException("IP信息数据文件异常。");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 数据文件中信息数量.
|
|
/// </summary>
|
|
public long Count { get; private set; }
|
|
|
|
/// <summary>
|
|
/// IP地址转化成整数.
|
|
/// </summary>
|
|
/// <param name="ip"></param>
|
|
/// <returns></returns>
|
|
public static long IpToInt(string ip)
|
|
{
|
|
char[] separator = new[] { '.' };
|
|
if (ip.Split(separator).Length == 3)
|
|
{
|
|
ip = ip + ".0";
|
|
}
|
|
|
|
if (!Regex.Match(ip).Success)
|
|
throw new ArgumentException("IP格式错误");
|
|
string[] nums = ip.Split(separator);
|
|
long num1 = ((long.Parse(nums[0]) * 0x100L) * 0x100L) * 0x100L;
|
|
long num2 = (long.Parse(nums[1]) * 0x100L) * 0x100L;
|
|
long num3 = long.Parse(nums[2]) * 0x100L;
|
|
long num4 = long.Parse(nums[3]);
|
|
return ((num1 + num2) + num3) + num4;
|
|
}
|
|
|
|
/// <summary>
|
|
/// IP地址从整数类型转化为正常IP类型.
|
|
/// </summary>
|
|
/// <param name="ipInt"></param>
|
|
/// <returns></returns>
|
|
public static string IntToIp(long ipInt)
|
|
{
|
|
long num1 = (ipInt & 0xff000000L) >> 0x18;
|
|
if (num1 < 0L)
|
|
num1 += 0x100L;
|
|
long num2 = (ipInt & 0xff0000L) >> 0x10;
|
|
if (num2 < 0L)
|
|
num2 += 0x100L;
|
|
long num3 = (ipInt & 0xff00L) >> 8;
|
|
if (num3 < 0L)
|
|
num3 += 0x100L;
|
|
long num4 = ipInt & 0xffL;
|
|
if (num4 < 0L)
|
|
num4 += 0x100L;
|
|
string ip = string.Concat(new[]
|
|
{
|
|
num1.ToString(CultureInfo.InvariantCulture),
|
|
".",
|
|
num2.ToString(CultureInfo.InvariantCulture),
|
|
".",
|
|
num3.ToString(CultureInfo.InvariantCulture),
|
|
".",
|
|
num4.ToString(CultureInfo.InvariantCulture)
|
|
});
|
|
|
|
if (!Regex.Match(ip).Success)
|
|
throw new ArgumentException("IP格式错误");
|
|
return ip;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 由IP地址查找对应的位置信息.
|
|
/// </summary>
|
|
/// <param name="ip"> 要查找的IP地址. </param>
|
|
/// <returns> </returns>
|
|
/// <exception cref="ArgumentException"></exception>
|
|
public IpLocation Query(string ip)
|
|
{
|
|
if (ip == "::1")
|
|
ip = "127.0.0.1";
|
|
if (!Regex.Match(ip).Success)
|
|
throw new ArgumentException("IP格式错误");
|
|
IpLocation ipLocation = new IpLocation { Ip = ip };
|
|
long intIp = IpToInt(ip);
|
|
if (intIp >= IpToInt("127.0.0.1") && (intIp <= IpToInt("127.255.255.255")))
|
|
{
|
|
ipLocation.Country = "本机内部环回地址";
|
|
ipLocation.Local = string.Empty;
|
|
}
|
|
else
|
|
{
|
|
if (((intIp >= IpToInt("0.0.0.0")) && (intIp <= IpToInt("2.255.255.255"))) ||
|
|
((intIp >= IpToInt("64.0.0.0")) && (intIp <= IpToInt("126.255.255.255"))) ||
|
|
((intIp >= IpToInt("58.0.0.0")) && (intIp <= IpToInt("60.255.255.255"))))
|
|
{
|
|
ipLocation.Country = "网络保留地址";
|
|
ipLocation.Local = string.Empty;
|
|
}
|
|
}
|
|
|
|
long right = Count;
|
|
long left = 0L;
|
|
long startIp;
|
|
long endIpOff;
|
|
int countryFlag;
|
|
while (left < (right - 1L))
|
|
{
|
|
long middle = (right + left) / 2L;
|
|
startIp = GetStartIp(middle, out endIpOff);
|
|
if (intIp == startIp)
|
|
{
|
|
left = middle;
|
|
break;
|
|
}
|
|
|
|
if (intIp > startIp)
|
|
{
|
|
left = middle;
|
|
}
|
|
else
|
|
{
|
|
right = middle;
|
|
}
|
|
}
|
|
|
|
startIp = GetStartIp(left, out endIpOff);
|
|
long endIp = GetEndIp(endIpOff, out countryFlag);
|
|
if ((startIp <= intIp) && (endIp >= intIp))
|
|
{
|
|
string local;
|
|
ipLocation.Country = GetCountry(endIpOff, countryFlag, out local);
|
|
ipLocation.Local = local.Replace("(我们一定要解放台湾!!!)", string.Empty);
|
|
}
|
|
else
|
|
{
|
|
ipLocation.Country = "未知";
|
|
ipLocation.Local = string.Empty;
|
|
}
|
|
|
|
return ipLocation;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 由IP地址查找对应的位置信息的字符串.
|
|
/// </summary>
|
|
public string Query2(string ip)
|
|
{
|
|
IpLocation result = Query(ip);
|
|
return (result.Country + result.Local).Replace("CZ88.NET", string.Empty);
|
|
}
|
|
|
|
private long GetStartIp(long left, out long endIpOff)
|
|
{
|
|
long leftOffset = _firstStartIpOffset + (left * 7L);
|
|
byte[] buffer = new byte[7];
|
|
Array.Copy(_data, leftOffset, buffer, 0, 7);
|
|
endIpOff = (Convert.ToInt64(buffer[4].ToString(CultureInfo.InvariantCulture)) +
|
|
(Convert.ToInt64(buffer[5].ToString(CultureInfo.InvariantCulture)) * 0x100L)) +
|
|
((Convert.ToInt64(buffer[6].ToString(CultureInfo.InvariantCulture)) * 0x100L) * 0x100L);
|
|
return ((Convert.ToInt64(buffer[0].ToString(CultureInfo.InvariantCulture)) +
|
|
(Convert.ToInt64(buffer[1].ToString(CultureInfo.InvariantCulture)) * 0x100L)) +
|
|
((Convert.ToInt64(buffer[2].ToString(CultureInfo.InvariantCulture)) * 0x100L) * 0x100L)) +
|
|
(((Convert.ToInt64(buffer[3].ToString(CultureInfo.InvariantCulture)) * 0x100L) * 0x100L) * 0x100L);
|
|
}
|
|
|
|
private long GetEndIp(long endIpOff, out int countryFlag)
|
|
{
|
|
byte[] buffer = new byte[5];
|
|
Array.Copy(_data, endIpOff, buffer, 0, 5);
|
|
countryFlag = buffer[4];
|
|
return ((Convert.ToInt64(buffer[0].ToString(CultureInfo.InvariantCulture)) +
|
|
(Convert.ToInt64(buffer[1].ToString(CultureInfo.InvariantCulture)) * 0x100L)) +
|
|
((Convert.ToInt64(buffer[2].ToString(CultureInfo.InvariantCulture)) * 0x100L) * 0x100L)) +
|
|
(((Convert.ToInt64(buffer[3].ToString(CultureInfo.InvariantCulture)) * 0x100L) * 0x100L) * 0x100L);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the country.
|
|
/// </summary>
|
|
/// <param name="endIpOff"> The end ip off. </param>
|
|
/// <param name="countryFlag"> The country flag. </param>
|
|
/// <param name="local"> The local. </param>
|
|
/// <returns> country.</returns>
|
|
private string GetCountry(long endIpOff, int countryFlag, out string local)
|
|
{
|
|
string country;
|
|
long offset = endIpOff + 4L;
|
|
switch (countryFlag)
|
|
{
|
|
case 1:
|
|
case 2:
|
|
country = GetFlagStr(ref offset, ref countryFlag, ref endIpOff);
|
|
offset = endIpOff + 8L;
|
|
local = (countryFlag == 1) ? string.Empty : GetFlagStr(ref offset, ref countryFlag, ref endIpOff);
|
|
break;
|
|
default:
|
|
country = GetFlagStr(ref offset, ref countryFlag, ref endIpOff);
|
|
local = GetFlagStr(ref offset, ref countryFlag, ref endIpOff);
|
|
break;
|
|
}
|
|
|
|
return country;
|
|
}
|
|
|
|
private string GetFlagStr(ref long offset, ref int countryFlag, ref long endIpOff)
|
|
{
|
|
byte[] buffer = new byte[3];
|
|
|
|
while (true)
|
|
{
|
|
// 用于向前累加偏移量
|
|
long forwardOffset = offset;
|
|
int flag = _data[forwardOffset++];
|
|
|
|
// 没有重定向
|
|
if (flag != 1 && flag != 2)
|
|
break;
|
|
Array.Copy(_data, forwardOffset, buffer, 0, 3);
|
|
if (flag == 2)
|
|
{
|
|
countryFlag = 2;
|
|
endIpOff = offset - 4L;
|
|
}
|
|
|
|
offset = (Convert.ToInt64(buffer[0].ToString()) + (Convert.ToInt64(buffer[1].ToString()) * 0x100L)) +
|
|
((Convert.ToInt64(buffer[2].ToString()) * 0x100L) * 0x100L);
|
|
}
|
|
|
|
if (offset < 12L)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
return GetStr(ref offset);
|
|
}
|
|
|
|
private string GetStr(ref long offset)
|
|
{
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
byte[] bytes = new byte[2];
|
|
Encoding encoding = Encoding.GetEncoding("GB2312");
|
|
while (true)
|
|
{
|
|
byte lowByte = _data[offset++];
|
|
if (lowByte == 0)
|
|
return stringBuilder.ToString();
|
|
if (lowByte > 0x7f)
|
|
{
|
|
byte highByte = _data[offset++];
|
|
bytes[0] = lowByte;
|
|
bytes[1] = highByte;
|
|
if (highByte == 0)
|
|
return stringBuilder.ToString();
|
|
stringBuilder.Append(encoding.GetString(bytes));
|
|
}
|
|
else
|
|
{
|
|
stringBuilder.Append((char)lowByte);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |