Browse Source

feat: analyse the data of qqwry

master
Dnomd343 4 years ago
parent
commit
d383b22f96
  1. 27
      backend/qqwry.php
  2. 9
      backend/qqwryFormat/areafix.js
  3. 86
      backend/qqwryFormat/countryfix.js
  4. 189
      backend/qqwryFormat/index.js
  5. 1674
      backend/qqwryFormat/iso3166.js
  6. 4
      backend/qqwryFormat/isp.js
  7. 91
      backend/qqwryFormat/owner.js
  8. 20
      backend/qqwryFormat/preformat.js
  9. 18
      backend/qqwryFormat/server.js
  10. 48
      backend/qqwryFormat/special.js
  11. 2
      backend/qqwryFormat/start.sh
  12. 38
      backend/queryInfo.php

27
backend/qqwry.php

@ -7,8 +7,13 @@
// {
// "beginIP": IP段起始点
// "endIP": IP段结束点
// "dataA": 国家名
// "dataB": 地区名
// "dataA": 数据段1
// "dataB": 数据段2
// "country": 国家
// "region": 行政区
// "city": 城市
// "domain": 所有者域名
// "isp": ISP信息
// }
//
// 请求版本:getVersion()
@ -19,6 +24,7 @@ class QQWry {
private $firstRecord; // 第一条记录的偏移地址
private $lastRecord; // 最后一条记录的偏移地址
private $recordNum; // 总记录条数
private $formatPort = '1602'; // 数据格式化分析接口
public function __construct($fileName) { // 构造函数
$this->fp = fopen($fileName, 'rb');
@ -92,6 +98,16 @@ class QQWry {
if ($detail['dataB'] == ' CZ88.NET') {
$detail['dataB'] = '';
}
$rawData = $this->formatData($detail['dataA'], $detail['dataB']);
if ($rawData['dataA'] != '' && $rawData['dataB'] != '') {
$detail['dataA'] = $rawData['dataA'];
$detail['dataB'] = $rawData['dataB'];
}
$detail['country'] = $rawData['country'];
$detail['region'] = $rawData['region'];
$detail['city'] = $rawData['city'];
$detail['domain'] = $rawData['domain'];
$detail['isp'] = $rawData['isp'];
return $detail;
}
@ -161,6 +177,11 @@ class QQWry {
return $this->readString();
}
}
private function formatData($dataA, $dataB) { // 从数据中提取国家、地区、城市、运营商等信息
$str_json = file_get_contents('http://127.0.0.1:' . $this->formatPort . '/?dataA=' . urlencode($dataA) . '&dataB=' . urlencode($dataB));
return json_decode($str_json, true); // 格式化为JSON
}
}
?>
?>

9
backend/qqwryFormat/areafix.js

@ -0,0 +1,9 @@
const list = {
'天津市河东区 /河北区联通': '天津市联通',
'北京市 广东盈世计算机科技有限公司联通节点': '北京市联通',
'江苏省南京市 驿站网吧(鼓楼区山西路虎啸花园后门)': '江苏省南京市',
}
module.exports.init = () => {
return list
}

86
backend/qqwryFormat/countryfix.js

@ -0,0 +1,86 @@
const list = {
'IANA': '保留地址',
'欧盟': '欧洲地区',
'亚洲': '亚洲地区',
'欧洲': '欧洲地区',
'澳洲': '澳大利亚',
'东北三省': '中国',
'长江大学东校区': '中国/湖北荆州',
'沈阳市东陵区': '中国/辽宁沈阳',
'沈阳市皇姑区': '中国/辽宁沈阳',
'合肥工业大学': '中国/安徽合肥',
'宁波大学': '中国/浙江宁波',
'长江大学': '中国/湖北荆州',
'联合国': '美国',
'欧美地区': '美洲地区',
'运营商级NAT': '共享地址',
'电信': '中国/电信',
'印尼': '印度尼西亚',
'韩国首尔': '韩国/首尔',
'本地': '本地链路',
'广州市清远市清城区': '中国/广东省广州市清远市清城区',
'加勒比海地区': '库拉索',
'孟加拉国': '孟加拉',
'成都信息工程学院': '中国/四川成都',
'华东理工大学': '中国/上海',
'南开大学': '中国/天津',
'CoreLink骨干网': '骨干网/CoreLink',
'长春工业大学': '中国/吉林长春',
'西安石油大学(本部)计算机中心二楼(第五微机室)': '中国/陕西西安',
'西安石油大学': '中国/陕西西安',
'北方工业大学': '中国/北京',
'首都经贸大学东区7楼大机房': '中国/北京',
'首都经贸大学': '中国/北京',
'荷兰省': '荷兰/北荷兰省',
'南京大学鼓楼校区': '中国/江苏南京',
'南京大学': '中国/江苏南京',
'集美大学航海学院': '中国/福建厦门',
'华中农业大学': '中国/湖北武汉',
'首都师范大学': '中国/北京',
'成都理工大学': '中国/四川成都',
'哈尔滨工程大学': '中国/黑龙江哈尔滨',
'佳木斯大学': '中国/黑龙江佳木斯',
'太原科技大学': '中国/山西太原',
'中北大学': '中国/山西太原',
'青岛大学': '中国/山东青岛',
'华东师范大学': '中国/上海',
'南京理工大学': '中国/江苏南京',
'中南大学岳麓山校区': '中国/湖南长沙',
'中南大学': '中国/湖南长沙',
'华中农业大学学生宿舍': '中国/湖北武汉',
'中南财经政法大学': '中国/湖北武汉',
'武汉科技大学': '中国/湖北武汉',
'西安科技大学': '中国/陕西西安',
'东北农业大学': '中国/黑龙江哈尔滨',
'对外经济贸易大学学生公寓': '中国/广东广州',
'东华大学': '中国/上海',
'首都科技大学': '中国/北京',
'长沙理工大学': '中国/四川长沙',
'南昌理工学院': '中国/江西南昌',
'华南理工大学北区北十一': '中国/广东广州',
'华南理工大学北区B2': '中国/广东广州',
'华中科技大学韵苑公寓15栋': '中国/湖北武汉',
'华中科技大学韵苑公寓': '中国/湖北武汉',
'武汉大学医学部': '中国/湖北武汉',
'武汉大学信息学部': '中国/湖北武汉',
'武汉大学工学部': '中国/湖北武汉',
'大连理工大学': '中国/辽宁大连',
'西安建筑科技大学': '中国/陕西西安',
'西安思源学院': '中国/陕西西安',
'对外经济贸易大学': '中国/广东广州',
'IANA机构': '保留地址',
'IANA保留地址': '保留地址',
'新加披': '新加坡',
'苏格兰': '英国/苏格兰',
'美国加利福尼亚州费里蒙CodecCloud数据中心': '美国/加利福尼亚州费利蒙CodecCloud数据中心',
'美国弗吉尼亚州阿什本Amazon数据中心': '美国/弗吉尼亚州阿什本Amazon数据中心',
'美国新泽西州皮斯卡特维Choopa数据中心': '美国/新泽西州皮斯卡特维Choopa数据中心',
'天津市河北区': '中国/天津市',
}
module.exports.init = () => {
for (const [raw, regions] of Object.entries(list)) {
list[raw] = regions.split('/')
}
return list
}

189
backend/qqwryFormat/index.js

@ -0,0 +1,189 @@
const iso3166 = require('./iso3166').init()
const china_keyword = Object.keys(iso3166['中国'])
const countryfix_list = require('./countryfix').init()
const areafix_list = require('./areafix').init()
const isp_list = require('./isp')
const owner_list = require('./owner').init()
const specialfix = require('./special')
const preformat = require('./preformat').init()
/**
* 进行市级粒度匹配
*/
const city_match = (result, country, area, citys) => {
if (citys.length) {
for (const city of citys) {
if (area.includes(city)) {
result.city_name = city
return result
}
}
} else {
const regions = iso3166[country]
for (let [region, value] of Object.entries(regions)) {
for (let city of value) {
if (area.includes(city)) {
result.region_name = region
result.city_name = city
return result
}
}
}
}
}
module.exports = (country, area) => {
const result = {
country,
area,
country_name: '',
region_name: '',
city_name: '',
owner_domain: '',
isp_domain: ''
}
/**
* 数据库预匹配
*/
if (preformat.has(`${country}|${area}`)) {
const info = preformat.get(`${country}|${area}`)
result.country_name = info.country_name
result.region_name = info.region_name
result.city_name = info.city_name
result.owner_domain = info.owner_domain
result.isp_domain = info.isp_domain
return result
}
/**
* 去除数据中存在的空格字符避免干扰判断
*
* { country: '马来西亚', area: ' CZ88.NET' } ->
* { country: '马来西亚', area: 'CZ88.NET' } ->
*/
country = country.trim()
area = area.trim()
/**
* 根据关键词修正中国地区标注
*
* { country: '内蒙古通辽市开鲁县', area: '联通' } ->
* { country: '中国', area: '内蒙古通辽市开鲁县 联通' }
*/
if (!iso3166[country]) {
for (const keyword of china_keyword) {
if (country.includes(keyword)) {
area = country + ' ' + area
country = '中国'
break
}
}
}
/**
* 修正国家字段命名不规范的数据
*
* { country: '华中科技大学韵苑公寓15栋', area: '623' } ->
* { country: '中国', area: '湖北省武汉市 华中科技大学韵苑公寓15栋 623' }
*/
if (countryfix_list[country]) {
let info = countryfix_list[country]
country = info[0]
if (info.length === 2) area = info[1] + ' ' + area
}
/**
* 处理高校教育网教育网
*
* { country: '中国', area: '湖北省宜昌市 三峡大学电子阅览室' } ->
* { country: '中国', area: '湖北省宜昌市 三峡大学电子阅览室(教育网)' } ->
*/
if (country === '中国' && area.includes('大学') && !area.includes('网吧')) {
area += '(教育网)'
}
/**
* 修正区域字段存在混淆的数据
*
* { country: '江苏省宿迁市沭阳县', area: '上海南路(农机校对面)凌云网吧' } ->
* { country: '江苏省宿迁市沭阳县', area: '凌云网吧' }
*/
if (areafix_list[area]) {
area = areafix_list[area]
}
/**
* 进行国家粒度匹配
*/
if (iso3166[country]) {
result.country_name = country
result.region_name = country
}
/**
* 进行省级粒度匹配
*/
let citys = []
if (iso3166[country]) {
const regions = iso3166[country]
for (const [region, value] of Object.entries(regions)) {
if (region !== country && area.includes(region)) {
result.region_name = region
citys = value
break
}
}
}
/**
* 进行市级粒度匹配深度匹配
*/
if (iso3166[country]) {
city_match(result, country, area, citys)
}
/**
* 进行特殊修正
*/
specialfix(result)
/**
* 进行运营商匹配
*/
const isps = isp_list[`${result.country_name}-${result.region_name}`]
|| isp_list[result.country_name]
|| []
for (const isp of isps) {
if (area.includes(isp)) {
result.isp_domain = isp
break
}
}
/**
* 进行服务持有方匹配
*/
let owners = owner_list[`${result.country_name}-${result.region_name}`]
|| owner_list[result.country_name]
|| []
owners = {...owners, ...owner_list['*']}
for (const [owner, value] of Object.entries(owners)) {
if (area.toLowerCase().includes(owner)) {
result.owner_domain = value
break
}
}
/**
* 数据兜底
*/
if (result.country_name === '') {
result.country_name = country
result.region_name = area
}
return result
}

1674
backend/qqwryFormat/iso3166.js

File diff suppressed because one or more lines are too long

4
backend/qqwryFormat/isp.js

@ -0,0 +1,4 @@
module.exports = {
'中国': ['教育网', '电信', '联通', '移动', '铁通', '广电网', '鹏博士', '长城'],
'中国-台湾': ['中华电信', '亚太电信', '远传电信'],
}

91
backend/qqwryFormat/owner.js

@ -0,0 +1,91 @@
const list = [
// 通用
['cloudflare.com', 'cloudflare', '*'],
['microsoft.com', ['microsoft', '微软'], '*'],
['akamai.com', 'akamai', '*'],
['amazon.com', 'amazon', '*'],
['amazon.com', 'cloudfront', '*'],
['digitalocean.com', 'digitalocean', '*'],
['choopa.com', 'choopa', '*'],
['ntt.com', ['ntt网络', 'ntt通信'], '*'],
['he.net', 'hurricane electric', '*'],
['level3.com', ['level3', 'level 3'], '*'],
['zenlayer.com', 'zenlayer', '*'],
['facebook.com', 'facebook', '*'],
['cogentco.com', 'cogent通信', '*'],
['godaddy.com', 'godaddy', '*'],
['starhub.com', 'starhub', '*'],
['ovh.com', 'ovh', '*'],
['fiber.google.com', 'google fiber', '*'],
['cloud.google.com', 'google云计算', '*'],
['sita.aero', '国际航空电讯集团公司(sita)', '*'],
['aliyun.com', '阿里云', '*'],
['cloud.tencent.com', '腾讯云', '*'],
['huawei.com', '华为', '*'],
['cloudinnovation.org', 'cloudinnovation', '*'],
['att.com', ['ATT用户', 'AT&T'], '*'],
['edgecast.com', 'EdgeCast', '*'],
['cdnetworks.com', 'CDNetworks', '*'],
['hp.com', '惠普HP', '*'],
['apple.com', 'apple', '*'],
['fastly.com', 'Fastly', '*'],
// 混合
['rixcloud.com', 'rixcloud', ['中国-香港', '美国', '日本', '英国', '俄罗斯', '巴西', '荷兰', '新加坡']],
['linode.com', 'linode', ['德国', '日本', '美国', '英国', '新加坡', '德国', '加拿大']],
['yandex.ru', 'yandex', ['俄罗斯', '荷兰', '美国', '乌克兰']],
['apnic.net', ['APNIC', '亚太互联网络信息中心'], ['澳大利亚', '马来西亚', '德国', '日本', '美国']],
// 中国
['qingcloud.com', ['青云数据中心', '青云电信节点'], '中国'],
['ksyun.com', '金山云', '中国'],
['netease.com', '网易', ['中国', '中国-香港']],
['shuim.net', 'shuiM Data Exchange Center', '中国'],
// 中国-台湾
['cht.com.tw', '中华电信', '中国-台湾'],
['so-net.net.tw', 'So-net', '中国-台湾'],
['tinp.net.tw', '台基科', '中国-台湾'],
// 中国-香港
['pccw.com', '电讯盈科', ['中国-香港', '美国']],
// 美国
['macstadium.com', 'macstadium', '美国'],
['riven.ee', 'rivencloud', ['美国', '中国-香港', '法国', '德国']],
['github.com', 'github', ['美国', '荷兰']],
['it7.net', 'it7', ['美国', '俄罗斯']],
['defense.gov', '国防部', '美国'],
['dod.com', 'DoD网络信息中心', '美国'],
['ibm.com', 'IBM公司', '美国'],
['comcast.com', 'Comcast通信公司', '美国'],
['rackspace.com', 'Rackspace Hosting公司', '美国'],
// 新西兰
['vocus.co.nz', 'vocus', '新西兰'],
// 越南
['hanelcom.vn', 'hanelcom', '越南'],
['vnpt.vn', 'VNPT', '越南'],
// 韩国
['kt.com', 'kt电信', '韩国'],
// 日本
['idcf.jp', 'idcf', '日本'],
['jcom.co.jp', 'j:com电信', '日本'],
['megaegg.jp', 'Energia通讯', '日本'],
// 英国
['gov.uk', '社会保险安全部', '英国'],
// 加拿大
['bell.ca', 'Bell', '加拿大'],
]
module.exports.init = () => {
const result = {}
for (const item of list) {
let name = item[0]
let keyword = item[1]
if (!Array.isArray(keyword)) keyword = [keyword]
let country = item[2]
if (!Array.isArray(country)) country = [country]
for (let t_keyword of keyword) {
for (let t_country of country) {
if (result[t_country] == undefined) result[t_country] = {}
result[t_country][t_keyword.toLowerCase()] = name.toLowerCase()
}
}
}
return result
}

20
backend/qqwryFormat/preformat.js

@ -0,0 +1,20 @@
const fs = require('fs')
module.exports.init = () => {
const map = new Map()
try {
const file = fs.readFileSync(__dirname + '/preformat.db', 'utf8')
const data = file.trim().split('\n').map(x => x.split('|'))
for (const item of data) {
map.set([item[0], item[1]].join('|'), {
country_name: item[2],
region_name: item[3],
city_name: item[4],
owner_domain: item[5],
isp_domain: item[6]
})
}
} catch (ignore) {}
return map
}

18
backend/qqwryFormat/server.js

@ -0,0 +1,18 @@
var http = require('http');
var url = require('url');
const format = require('./');
http.createServer(function(req, res){
var params = url.parse(req.url, true).query;
let info = format(params.dataA, params.dataB);
res.write("{");
res.write("\"dataA\": \"" + info['country'] + "\",");
res.write("\"dataB\": \"" + info['area'] + "\",");
res.write("\"country\": \"" + info['country_name'] + "\",");
res.write("\"region\": \"" + info['region_name'] + "\",");
res.write("\"city\": \"" + info['city_name'] + "\",");
res.write("\"domain\": \"" + info['owner_domain'] + "\",");
res.write("\"isp\": \"" + info['isp_domain'] + "\"");
res.write("}");
res.end();
}).listen(1602);

48
backend/qqwryFormat/special.js

@ -0,0 +1,48 @@
const rules = [
[
['country_name', '美国', 'region_name', '俄克拉荷马州', 'city_name', '俄克拉荷马城'],
['region_name', '奥克拉荷马州', 'city_name', '奥克拉荷马城'],
],
[
['country_name', '美国', 'region_name', '乔治亚州'],
['region_name', '佐治亚州'],
],
[
['country_name', '美国', 'region_name', '得克萨斯州'],
['region_name', '德克萨斯州'],
],
[
['country_name', '美国', 'region_name', '俄克拉荷马州'],
['region_name', '奥克拉荷马州'],
],
[
['country_name', '美国', 'region_name', '罗德岛州'],
['region_name', '罗得岛州'],
],
[
['country_name', '俄罗斯', 'region_name', '伊尔库州'],
['region_name', '伊尔库茨克州'],
],
[
['country_name', '韩国', 'region_name', '首尔'],
['region_name', '首尔特别市'],
],
]
module.exports = (result) => {
for (let [rule, change] of rules) {
let flag = true
for (let i = 0; i < rule.length; i += 2) {
if (result[rule[i]] !== rule[i + 1]) {
flag = false
break
}
}
if (flag) {
for (let i = 0; i < change.length; i += 2) {
result[change[i]] = change[i + 1]
}
return
}
}
}

2
backend/qqwryFormat/start.sh

@ -0,0 +1,2 @@
#!/bin/bash
node server&

38
backend/queryInfo.php

@ -7,7 +7,7 @@ include("ipip.php");
include("city.php");
function getIPInfo($ip) {
$specialInfo = checkSpecial($ip);
$specialInfo = checkSpecial($ip); // 检查是否为特殊IP段
if (is_string($specialInfo)) {
$info['ip'] = $ip;
$info['as'] = null;
@ -19,9 +19,11 @@ function getIPInfo($ip) {
$info['isp'] = $specialInfo;
} else {
$IPIP = new IPDB('ipipfree.ipdb');
$addr = $IPIP->getDistrict($ip);
$data = IPinfo::getInfo($ip);
$country = getCountry($data['country']);
$addr = $IPIP->getDistrict($ip); // 获取IPIP.net数据
$data = IPinfo::getInfo($ip); // 获取ipinfo.io数据
$country = getCountry($data['country']); // 解析国家2位编码
$qqwry = new QQWry('qqwry.dat');
$detail = $qqwry->getDetail($ip); // 获取纯真IP数据
$info['ip'] = $data['ip'];
$info['as'] = $data['as'];
$info['city'] = $data['city'];
@ -31,21 +33,27 @@ function getIPInfo($ip) {
$info['timezone'] = $data['timezone'];
$info['loc'] = $data['loc'];
$info['isp'] = $data['isp'];
if ($addr[0] == '中国') {
if ($addr[0] == '中国' || $detail['country'] == '中国') {
$info['country'] = 'CN - China(中国)';
$info['timezone'] = 'Asia/Shanghai';
if ($addr[1] == '') {
$addr[1] = '北京';
$flagErr = false;
if ($addr[1] == '' || $addr[2] == '') {
if ($detail['region'] != '' && $detail['city'] != '') {
$addr[1] = $detail['region']; // 修正IPIP.net数据
$addr[2] = $detail['city'];
} else {
$flagErr = true; // 国内数据不全
}
}
if (!$flagErr) { // 国内数据可用
$cityLoc = getLoc($addr[1], $addr[2]); // 获取城市经纬度
$info['region'] = $cityLoc['region'];
$info['city'] = $cityLoc['city'];
$info['loc'] = $cityLoc['lat'] . ',' . $cityLoc['lon'];
}
$cityLoc = getLoc($addr[1], $addr[2]);
$info['region'] = $cityLoc['region'];
$info['city'] = $cityLoc['city'];
$info['loc'] = $cityLoc['lat'] . ',' . $cityLoc['lon'];
}
}
if (filter_var($ip, \FILTER_VALIDATE_IP,\FILTER_FLAG_IPV4)) {
$qqwry = new QQWry('qqwry.dat');
$detail = $qqwry->getDetail($ip);
if (filter_var($ip, \FILTER_VALIDATE_IP,\FILTER_FLAG_IPV4)) { // 录入纯真库数据
$info['scope'] = tryCIDR($detail['beginIP'], $detail['endIP']);
$info['detail'] = $detail['dataA'] . $detail['dataB'];
} else {
@ -107,7 +115,7 @@ function tryCIDR($beginIP, $endIP) { // 给定IP范围,尝试计算CIDR
function main() {
$ip = $_GET['ip'];
if (!filter_var($ip, \FILTER_VALIDATE_IP)) {
if (!filter_var($ip, \FILTER_VALIDATE_IP)) { // 输入IP不合法
echo "Illegal IP format".PHP_EOL;
exit;
}

Loading…
Cancel
Save