@blueislandx/island-qqwry-database
Version:
Island (小蓝岛) 纯真 IP 数据库 qqwry.dat 解析
177 lines (154 loc) • 6.35 kB
text/typescript
import * as gbk from 'gbk.js';
import { AbstractBuffer } from '../common/abstract.buffer';
import { IPInfo, IPRangeInfo } from '../common/interfaces';
export class QQWryUtil {
static REDIRECT_MODE_1: number = 1;
static REDIRECT_MODE_2: number = 2;
static IP_RECORD_LENGTH: number = 7;
/**
* 使用二分法查找指定 IP 地址的偏移量
* @param buffer 实现 AbstractBuffer 的实例
* @param ip 数字形式的 IP 地址
* @param start 起始位置
* @param end 中止位置
* @returns
*/
static locateIP(buffer: InstanceType<typeof AbstractBuffer>, ip: number, start: number, end: number) {
var offset = -1;
for (var x = start, y = end; x < y;) {
offset = this.getCenterOffset(x, y, this.IP_RECORD_LENGTH);
const temp = buffer.readUIntLE(offset, 4);
if (ip > temp) {
x = offset;
} else if (ip < temp) {
if (offset === y) {
offset -= this.IP_RECORD_LENGTH;
break;
}
y = offset;
} else {
break;
}
}
return offset;
}
/**
* 通过 IP 地址偏移量查找 IP 详细信息
* @param buffer 实现 AbstractBuffer 的实例
* @param ip IP 地址偏移量
* @returns IP 详细信息
*/
static queryIPInfo(buffer: InstanceType<typeof AbstractBuffer>, ip: number) {
const ipInfo = {} as IPInfo;
var offset = buffer.readUIntLE(ip + 4, 3) + 4;
var mode = buffer.readUIntLE(offset, 1);
if (mode == this.REDIRECT_MODE_1) {
offset = buffer.readUIntLE(offset + 1, 3);
mode = buffer.readUIntLE(offset, 1);
if (mode == this.REDIRECT_MODE_2) {
const country = buffer.getStringByteArray(buffer.readUIntLE(offset + 1, 3));
ipInfo.country = gbk.decode(country);
offset += 4;
} else {
const country = buffer.getStringByteArray(offset);
ipInfo.country = gbk.decode(country);
offset += country.length + 1;
}
ipInfo.area = this.readArea(buffer, offset);
} else if (mode == this.REDIRECT_MODE_2) {
const country = buffer.getStringByteArray(buffer.readUIntLE(offset + 1, 3));
ipInfo.country = gbk.decode(country);
ipInfo.area = this.readArea(buffer, offset + 4);
} else {
const country = buffer.getStringByteArray(offset);
offset += country.length + 1;
ipInfo.country = gbk.decode(country);
ipInfo.area = this.readArea(buffer, offset);
}
return ipInfo;
}
/**
* 通过 IP 段偏移量查找 IP 段详细信息
* @param buffer 实现 AbstractBuffer 的实例
* @param ip1 IP 段起始偏移量
* @param ip2 IP 段终止偏移量
*/
static queryIPRangeInfo(buffer: InstanceType<typeof AbstractBuffer>, ip1: number, ip2: number) {
const ipRangeList : IPRangeInfo[] = [];
for (var i = ip1; i <= ip2; i += this.IP_RECORD_LENGTH) {
const ipInfo = this.queryIPInfo(buffer, i);
const ipRangeInfo = {} as IPRangeInfo;
ipRangeInfo.beginInt = buffer.readUIntLE(i, 4);
ipRangeInfo.endInt = buffer.readUIntLE(buffer.readUIntLE(i + 4, 3), 4);
ipRangeInfo.beginIP = this.int2IP(ipRangeInfo.beginInt);
ipRangeInfo.endIP = this.int2IP(ipRangeInfo.endInt);
ipRangeInfo.country = ipInfo.country;
ipRangeInfo.area = ipInfo.area;
ipRangeList.push(ipRangeInfo);
}
return ipRangeList;
}
/**
* 利用二分法获取中间的偏移量
* @param start 起始位置
* @param end 中止位置
* @param length 记录长度
* @returns
*/
static getCenterOffset(start: number, end: number, length: number) {
const records = (((end - start) / length) >> 1) * length + start;
return records ^ start ? records : records + length;
}
/**
* 从 Buffer 中读取 IP 地区信息
* @param buffer 实现 AbstractBuffer 的实例
* @param offset 偏移量
* @returns ByteArray 形式的字符
*/
static readArea(buffer: InstanceType<typeof AbstractBuffer>, offset: number) {
const mode = buffer.readUIntLE(offset, 1);
if (mode === 1 || mode === 2) {
const areaOffset = buffer.readUIntLE(offset + 1, 3);
if (areaOffset !== 0) {
return gbk.decode(buffer.getStringByteArray(areaOffset));
}
return '';
} else {
return gbk.decode(buffer.getStringByteArray(offset));
}
}
/**
* IP 地址转换为数值
* @param ip 字符形式的 IP 地址
* @returns 数字形式的 IP 地址
*/
static ip2Int(ip: string) {
const ipv4Regex = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
if (ipv4Regex.test(ip)) {
const array = ipv4Regex.exec(ip)!.slice(1);
return (parseInt(array[0]) << 24 | parseInt(array[1]) << 16 | parseInt(array[2]) << 8 | parseInt(array[3])) >>> 0;
} else {
throw `Invalid IP address >> ${ip}`;
}
}
/**
* 数值转换为 IP 地址
* @param int 数字形式的 IP 地址
* @returns 字符形式的 IP 地址
*/
static int2IP(int: number) {
if (int < 0 || int > 0xffffffff) {
throw `Invalid IP number! >> ${int}`;
}
return `${int >>> 24}.${(int >>> 16) & 0xff}.${(int >>> 8) & 0xff}.${(int >>> 0 & 0xff)}`;
}
/**
* 32位 Big Endian 与 Little Endian 数值互转
* @param int 32 位数值
* @returns 转换结果
*/
static convertEndian(int: number) {
int = int & 0xffffffff;
return ((int >>> 24) | ((int >> 8) & 0xff00) | ((int << 8) & 0xff0000) | (int << 24)) >>> 0;
}
}