use own whois

This commit is contained in:
HF 2022-09-19 02:12:21 +02:00
parent ffc93fdcd0
commit 94c04ba53a
4 changed files with 178 additions and 25 deletions

21
package-lock.json generated
View File

@ -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",

View File

@ -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"

View File

@ -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;

View File

@ -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;