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",
|
"three-trackballcontrols": "^0.9.0",
|
||||||
"ttag": "^1.7.24",
|
"ttag": "^1.7.24",
|
||||||
"url-search-params-polyfill": "^8.1.1",
|
"url-search-params-polyfill": "^8.1.1",
|
||||||
"whoiser": "^1.13.1",
|
|
||||||
"winston": "^3.8.2",
|
"winston": "^3.8.2",
|
||||||
"winston-daily-rotate-file": "^4.5.5",
|
"winston-daily-rotate-file": "^4.5.5",
|
||||||
"ws": "^8.4.0"
|
"ws": "^8.4.0"
|
||||||
|
@ -8641,6 +8640,7 @@
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
"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,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
|
@ -10874,14 +10874,6 @@
|
||||||
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
|
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
|
||||||
"dev": true
|
"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": {
|
"node_modules/wide-align": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
|
||||||
|
@ -17547,7 +17539,8 @@
|
||||||
"punycode": {
|
"punycode": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
"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": {
|
"qs": {
|
||||||
"version": "6.10.3",
|
"version": "6.10.3",
|
||||||
|
@ -19175,14 +19168,6 @@
|
||||||
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
|
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
|
||||||
"dev": true
|
"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": {
|
"wide-align": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
|
||||||
|
|
|
@ -61,7 +61,6 @@
|
||||||
"three-trackballcontrols": "^0.9.0",
|
"three-trackballcontrols": "^0.9.0",
|
||||||
"ttag": "^1.7.24",
|
"ttag": "^1.7.24",
|
||||||
"url-search-params-polyfill": "^8.1.1",
|
"url-search-params-polyfill": "^8.1.1",
|
||||||
"whoiser": "^1.13.1",
|
|
||||||
"winston": "^3.8.2",
|
"winston": "^3.8.2",
|
||||||
"winston-daily-rotate-file": "^4.5.5",
|
"winston-daily-rotate-file": "^4.5.5",
|
||||||
"ws": "^8.4.0"
|
"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_URL = process.env.BACKUP_URL || null;
|
||||||
export const BACKUP_DIR = process.env.BACKUP_DIR || null;
|
export const BACKUP_DIR = process.env.BACKUP_DIR || null;
|
||||||
|
|
||||||
|
export const OUTGOING_ADDRESS = process.env.OUTGOING_ADDRESS || null;
|
||||||
|
|
||||||
// Proxycheck
|
// Proxycheck
|
||||||
export const USE_PROXYCHECK = parseInt(process.env.USE_PROXYCHECK, 10) || false;
|
export const USE_PROXYCHECK = parseInt(process.env.USE_PROXYCHECK, 10) || false;
|
||||||
export const { PROXYCHECK_KEY } = process.env;
|
export const { PROXYCHECK_KEY } = process.env;
|
||||||
|
|
|
@ -2,10 +2,178 @@
|
||||||
* get information from ip
|
* get information from ip
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import whoiser from 'whoiser';
|
import net from 'net';
|
||||||
|
|
||||||
import { isIPv6, ip4InRangeToCIDR } from './ip';
|
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
|
* get CIDR of ip from whois return
|
||||||
|
@ -72,8 +240,8 @@ function parseWhois(ip, whoisData) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function whois(ip) {
|
export default async function whoiser(ip) {
|
||||||
const whoisData = await whoiser.ip(ip);
|
const whoisData = await whoisIp(ip);
|
||||||
if (whoisData.ReferralServer) {
|
if (whoisData.ReferralServer) {
|
||||||
let referral = whoisData.ReferralServer;
|
let referral = whoisData.ReferralServer;
|
||||||
const prot = referral.indexOf('://');
|
const prot = referral.indexOf('://');
|
||||||
|
@ -85,7 +253,7 @@ async function whois(ip) {
|
||||||
* if referral whois server produces any error
|
* if referral whois server produces any error
|
||||||
* fallback to initial one
|
* fallback to initial one
|
||||||
*/
|
*/
|
||||||
const refWhoisData = await whoiser.ip(ip, {
|
const refWhoisData = await whoisIp(ip, {
|
||||||
host: referral,
|
host: referral,
|
||||||
});
|
});
|
||||||
const refParsedData = parseWhois(ip, refWhoisData);
|
const refParsedData = parseWhois(ip, refWhoisData);
|
||||||
|
@ -96,7 +264,6 @@ async function whois(ip) {
|
||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.log(whoisData);
|
||||||
return parseWhois(ip, whoisData);
|
return parseWhois(ip, whoisData);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default whois;
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user