forked from ppfun/pixelplanet
use own whois
This commit is contained in:
parent
ffc93fdcd0
commit
94c04ba53a
21
package-lock.json
generated
21
package-lock.json
generated
|
@ -47,7 +47,6 @@
|
|||
"three-trackballcontrols": "^0.9.0",
|
||||
"ttag": "^1.7.24",
|
||||
"url-search-params-polyfill": "^8.1.1",
|
||||
"whoiser": "^1.13.1",
|
||||
"winston": "^3.8.2",
|
||||
"winston-daily-rotate-file": "^4.5.5",
|
||||
"ws": "^8.4.0"
|
||||
|
@ -8641,6 +8640,7 @@
|
|||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
|
@ -10874,14 +10874,6 @@
|
|||
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/whoiser": {
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/whoiser/-/whoiser-1.13.1.tgz",
|
||||
"integrity": "sha512-4MF0LoIsSdM7R9rs9A+PxbCXMDRmRdF7eZb8IC8pGethCrSizqMLcbJCXZO5iZGqOKovQlRhpSFGGUlwUPzoQA==",
|
||||
"dependencies": {
|
||||
"punycode": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/wide-align": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
|
||||
|
@ -17547,7 +17539,8 @@
|
|||
"punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
|
||||
"dev": true
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.10.3",
|
||||
|
@ -19175,14 +19168,6 @@
|
|||
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"whoiser": {
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/whoiser/-/whoiser-1.13.1.tgz",
|
||||
"integrity": "sha512-4MF0LoIsSdM7R9rs9A+PxbCXMDRmRdF7eZb8IC8pGethCrSizqMLcbJCXZO5iZGqOKovQlRhpSFGGUlwUPzoQA==",
|
||||
"requires": {
|
||||
"punycode": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"wide-align": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
|
||||
|
|
|
@ -61,7 +61,6 @@
|
|||
"three-trackballcontrols": "^0.9.0",
|
||||
"ttag": "^1.7.24",
|
||||
"url-search-params-polyfill": "^8.1.1",
|
||||
"whoiser": "^1.13.1",
|
||||
"winston": "^3.8.2",
|
||||
"winston-daily-rotate-file": "^4.5.5",
|
||||
"ws": "^8.4.0"
|
||||
|
|
|
@ -25,6 +25,8 @@ export const USE_XREALIP = !!process.env.USE_XREALIP;
|
|||
export const BACKUP_URL = process.env.BACKUP_URL || null;
|
||||
export const BACKUP_DIR = process.env.BACKUP_DIR || null;
|
||||
|
||||
export const OUTGOING_ADDRESS = process.env.OUTGOING_ADDRESS || null;
|
||||
|
||||
// Proxycheck
|
||||
export const USE_PROXYCHECK = parseInt(process.env.USE_PROXYCHECK, 10) || false;
|
||||
export const { PROXYCHECK_KEY } = process.env;
|
||||
|
|
|
@ -2,10 +2,178 @@
|
|||
* get information from ip
|
||||
*/
|
||||
|
||||
import whoiser from 'whoiser';
|
||||
import net from 'net';
|
||||
|
||||
import { isIPv6, ip4InRangeToCIDR } from './ip';
|
||||
import { OUTGOING_ADDRESS } from '../core/config';
|
||||
|
||||
const WHOIS_PORT = 43;
|
||||
const QUERY_SUFFIX = '\r\n';
|
||||
const WHOIS_TIMEOUT = 30000;
|
||||
|
||||
function splitStringBy(string, by) {
|
||||
return [string.slice(0, by), string.slice(by + 1)];
|
||||
}
|
||||
|
||||
function parseSimpleWhois(whois) {
|
||||
const data = {};
|
||||
const text = [];
|
||||
|
||||
const renameLabels = {
|
||||
NetRange: 'range',
|
||||
inetnum: 'range',
|
||||
CIDR: 'route',
|
||||
origin: 'asn',
|
||||
OriginAS: 'asn',
|
||||
};
|
||||
const lineToGroup = {
|
||||
contact: 'contact',
|
||||
OrgName: 'organisation',
|
||||
organisation: 'organisation',
|
||||
OrgAbuseHandle: 'contactAbuse',
|
||||
irt: 'contactAbuse',
|
||||
RAbuseHandle: 'contactAbuse',
|
||||
OrgTechHandle: 'contactTechnical',
|
||||
RTechHandle: 'contactTechnical',
|
||||
OrgNOCHandle: 'contactNoc',
|
||||
RNOCHandle: 'contactNoc',
|
||||
};
|
||||
|
||||
if (whois.includes('returned 0 objects') || whois.includes('No match found')) {
|
||||
return data;
|
||||
}
|
||||
|
||||
let resultNum = 0;
|
||||
const groups = [{}];
|
||||
let lastLabel;
|
||||
|
||||
whois.split('\n').forEach((line) => {
|
||||
// catch comment lines
|
||||
if (line.startsWith('%') || line.startsWith('#')) {
|
||||
// detect if an ASN or IP has multiple WHOIS results
|
||||
if (line.includes('# start')) {
|
||||
// nothing
|
||||
} else if (line.includes('# end')) {
|
||||
resultNum++;
|
||||
} else {
|
||||
text.push(line);
|
||||
}
|
||||
} else if (resultNum === 0) {
|
||||
// for the moment, parse only first WHOIS result
|
||||
|
||||
if (line) {
|
||||
if (line.includes(':')) {
|
||||
const [label, value] = splitStringBy(line, line.indexOf(':')).map((info) => info.trim());
|
||||
lastLabel = label;
|
||||
|
||||
// 1) Filter out unnecessary info, 2) then detect if the label is already added to group
|
||||
if (value.includes('---')) {
|
||||
// do nothing with useless data
|
||||
} else if (groups[groups.length - 1][label]) {
|
||||
groups[groups.length - 1][label] += `\n${value}`;
|
||||
} else {
|
||||
groups[groups.length - 1][label] = value;
|
||||
}
|
||||
} else {
|
||||
groups[groups.length - 1][lastLabel] += `\n${line.trim()}`;
|
||||
}
|
||||
} else if (Object.keys(groups[groups.length - 1]).length) {
|
||||
// if empty line, means another info group starts
|
||||
groups.push({});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
groups
|
||||
.filter((group) => Object.keys(group).length)
|
||||
.forEach((group) => {
|
||||
const groupLabels = Object.keys(group);
|
||||
let isGroup = false;
|
||||
|
||||
// check if a label is marked as group
|
||||
groupLabels.forEach((groupLabel) => {
|
||||
if (!isGroup && Object.keys(lineToGroup).includes(groupLabel)) {
|
||||
isGroup = lineToGroup[groupLabel];
|
||||
}
|
||||
});
|
||||
|
||||
// check if a info group is a Contact in APNIC result
|
||||
// @Link https://www.apnic.net/manage-ip/using-whois/guide/role/
|
||||
if (!isGroup && groupLabels.includes('role')) {
|
||||
isGroup = `Contact ${group.role.split(' ')[1]}`;
|
||||
} else if (!isGroup && groupLabels.includes('person')) {
|
||||
isGroup = `Contact ${group['nic-hdl']}`;
|
||||
}
|
||||
|
||||
if (isGroup === 'contact') {
|
||||
data.contacts = data.contacts || {};
|
||||
data.contacts[group.contact] = group;
|
||||
} else if (isGroup) {
|
||||
data[isGroup] = group;
|
||||
} else {
|
||||
groupLabels.forEach((key) => {
|
||||
const label = renameLabels[key] || key;
|
||||
data[label] = group[key];
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Append the WHOIS comments
|
||||
data.text = text;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function whoisQuery(
|
||||
host = null,
|
||||
query = '',
|
||||
) {
|
||||
console.log('whois with query', query, 'for host', host);
|
||||
return new Promise((resolve, reject) => {
|
||||
let data = '';
|
||||
const socket = net.createConnection({
|
||||
host,
|
||||
port: WHOIS_PORT,
|
||||
localAddress: OUTGOING_ADDRESS,
|
||||
timeout: WHOIS_TIMEOUT,
|
||||
}, () => socket.write(query + QUERY_SUFFIX));
|
||||
socket.on('data', (chunk) => { data += chunk; });
|
||||
socket.on('close', () => resolve(data));
|
||||
socket.on('timeout', () => socket.destroy(new Error('Timeout')));
|
||||
socket.on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
async function whoisIp(query) {
|
||||
query = String(query);
|
||||
|
||||
// find WHOIS server for IP
|
||||
let whoisResult = await whoisQuery('whois.iana.org', query);
|
||||
whoisResult = parseSimpleWhois(whoisResult);
|
||||
const host = whoisResult.whois;
|
||||
|
||||
if (!host) {
|
||||
throw new Error(`No WHOIS server for "${query}"`);
|
||||
}
|
||||
|
||||
// hardcoded custom queries..
|
||||
console.log('HOST', host);
|
||||
if (host === 'whois.arin.net') {
|
||||
query = `+ n ${query}`;
|
||||
} else if (host === 'whois.ripe.net') {
|
||||
/*
|
||||
* flag to not return personal informations, otherwise
|
||||
* RIPE is gonne rate limit and ban
|
||||
*/
|
||||
query = `-r ${query}`;
|
||||
}
|
||||
|
||||
const rawResult = await whoisQuery(host, query);
|
||||
console.log(rawResult);
|
||||
const data = parseSimpleWhois(rawResult);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* get CIDR of ip from whois return
|
||||
|
@ -72,8 +240,8 @@ function parseWhois(ip, whoisData) {
|
|||
};
|
||||
}
|
||||
|
||||
async function whois(ip) {
|
||||
const whoisData = await whoiser.ip(ip);
|
||||
export default async function whoiser(ip) {
|
||||
const whoisData = await whoisIp(ip);
|
||||
if (whoisData.ReferralServer) {
|
||||
let referral = whoisData.ReferralServer;
|
||||
const prot = referral.indexOf('://');
|
||||
|
@ -85,7 +253,7 @@ async function whois(ip) {
|
|||
* if referral whois server produces any error
|
||||
* fallback to initial one
|
||||
*/
|
||||
const refWhoisData = await whoiser.ip(ip, {
|
||||
const refWhoisData = await whoisIp(ip, {
|
||||
host: referral,
|
||||
});
|
||||
const refParsedData = parseWhois(ip, refWhoisData);
|
||||
|
@ -96,7 +264,6 @@ async function whois(ip) {
|
|||
// nothing
|
||||
}
|
||||
}
|
||||
console.log(whoisData);
|
||||
return parseWhois(ip, whoisData);
|
||||
}
|
||||
|
||||
export default whois;
|
||||
|
|
Loading…
Reference in New Issue
Block a user