2022-07-11 17:52:38 +02:00
|
|
|
import * as net from 'net';
|
2022-07-23 23:33:13 +02:00
|
|
|
import maxmind, { CityResponse, AsnResponse, IspResponse } from 'maxmind';
|
2022-07-11 17:52:38 +02:00
|
|
|
import nodesApi from '../../../api/explorer/nodes.api';
|
|
|
|
|
import config from '../../../config';
|
|
|
|
|
import DB from '../../../database';
|
|
|
|
|
import logger from '../../../logger';
|
2022-08-24 15:39:52 +02:00
|
|
|
import { ResultSetHeader } from 'mysql2';
|
2022-08-29 23:36:18 +02:00
|
|
|
import * as IPCheck from '../../../utils/ipcheck.js';
|
2022-11-20 15:35:03 +09:00
|
|
|
import { Reader } from 'mmdb-lib';
|
2022-07-11 17:52:38 +02:00
|
|
|
|
|
|
|
|
export async function $lookupNodeLocation(): Promise<void> {
|
2022-08-08 09:00:11 +02:00
|
|
|
let loggerTimer = new Date().getTime() / 1000;
|
|
|
|
|
let progress = 0;
|
2022-08-24 15:39:52 +02:00
|
|
|
let nodesUpdated = 0;
|
|
|
|
|
let geoNamesInserted = 0;
|
2022-08-08 09:00:11 +02:00
|
|
|
|
2022-12-01 15:52:06 +01:00
|
|
|
logger.debug(`Running node location updater using Maxmind`, logger.tags.ln);
|
2022-07-11 17:52:38 +02:00
|
|
|
try {
|
|
|
|
|
const nodes = await nodesApi.$getAllNodes();
|
|
|
|
|
const lookupCity = await maxmind.open<CityResponse>(config.MAXMIND.GEOLITE2_CITY);
|
|
|
|
|
const lookupAsn = await maxmind.open<AsnResponse>(config.MAXMIND.GEOLITE2_ASN);
|
2022-11-20 15:35:03 +09:00
|
|
|
let lookupIsp: Reader<IspResponse> | null = null;
|
|
|
|
|
try {
|
|
|
|
|
lookupIsp = await maxmind.open<IspResponse>(config.MAXMIND.GEOIP2_ISP);
|
|
|
|
|
} catch (e) { }
|
2022-07-11 17:52:38 +02:00
|
|
|
|
|
|
|
|
for (const node of nodes) {
|
|
|
|
|
const sockets: string[] = node.sockets.split(',');
|
|
|
|
|
for (const socket of sockets) {
|
|
|
|
|
const ip = socket.substring(0, socket.lastIndexOf(':')).replace('[', '').replace(']', '');
|
|
|
|
|
const hasClearnet = [4, 6].includes(net.isIP(ip));
|
2022-08-08 09:00:11 +02:00
|
|
|
|
2022-07-11 17:52:38 +02:00
|
|
|
if (hasClearnet && ip !== '127.0.1.1' && ip !== '127.0.0.1') {
|
|
|
|
|
const city = lookupCity.get(ip);
|
|
|
|
|
const asn = lookupAsn.get(ip);
|
2022-11-20 15:35:03 +09:00
|
|
|
let isp: IspResponse | null = null;
|
|
|
|
|
if (lookupIsp) {
|
|
|
|
|
isp = lookupIsp.get(ip);
|
|
|
|
|
}
|
2022-07-23 23:33:13 +02:00
|
|
|
|
2022-08-30 17:06:48 +02:00
|
|
|
let asOverwrite: any | undefined;
|
2022-08-29 23:36:18 +02:00
|
|
|
if (asn && (IPCheck.match(ip, '170.75.160.0/20') || IPCheck.match(ip, '172.81.176.0/21'))) {
|
2022-08-30 17:06:48 +02:00
|
|
|
asOverwrite = {
|
|
|
|
|
asn: 394745,
|
|
|
|
|
name: 'Lunanode',
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
else if (asn && (IPCheck.match(ip, '50.7.0.0/16') || IPCheck.match(ip, '66.90.64.0/18'))) {
|
|
|
|
|
asOverwrite = {
|
|
|
|
|
asn: 30058,
|
|
|
|
|
name: 'FDCservers.net',
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
else if (asn && asn.autonomous_system_number === 174) {
|
|
|
|
|
asOverwrite = {
|
|
|
|
|
asn: 174,
|
|
|
|
|
name: 'Cogent Communications',
|
|
|
|
|
};
|
2022-08-29 23:36:18 +02:00
|
|
|
}
|
|
|
|
|
|
2022-07-23 23:33:13 +02:00
|
|
|
if (city && (asn || isp)) {
|
2022-08-08 09:00:11 +02:00
|
|
|
const query = `
|
|
|
|
|
UPDATE nodes SET
|
|
|
|
|
as_number = ?,
|
|
|
|
|
city_id = ?,
|
|
|
|
|
country_id = ?,
|
|
|
|
|
subdivision_id = ?,
|
|
|
|
|
longitude = ?,
|
|
|
|
|
latitude = ?,
|
|
|
|
|
accuracy_radius = ?
|
|
|
|
|
WHERE public_key = ?
|
|
|
|
|
`;
|
2022-07-23 23:33:13 +02:00
|
|
|
|
|
|
|
|
const params = [
|
2022-08-30 17:06:48 +02:00
|
|
|
asOverwrite?.asn ?? isp?.autonomous_system_number ?? asn?.autonomous_system_number,
|
2022-07-23 23:33:13 +02:00
|
|
|
city.city?.geoname_id,
|
|
|
|
|
city.country?.geoname_id,
|
|
|
|
|
city.subdivisions ? city.subdivisions[0].geoname_id : null,
|
|
|
|
|
city.location?.longitude,
|
|
|
|
|
city.location?.latitude,
|
|
|
|
|
city.location?.accuracy_radius,
|
|
|
|
|
node.public_key
|
|
|
|
|
];
|
2022-08-24 15:39:52 +02:00
|
|
|
let result = await DB.query<ResultSetHeader>(query, params);
|
|
|
|
|
if (result[0].changedRows ?? 0 > 0) {
|
|
|
|
|
++nodesUpdated;
|
|
|
|
|
}
|
2022-07-11 17:52:38 +02:00
|
|
|
|
2022-08-08 09:00:11 +02:00
|
|
|
// Store Continent
|
|
|
|
|
if (city.continent?.geoname_id) {
|
2022-08-24 15:39:52 +02:00
|
|
|
result = await DB.query<ResultSetHeader>(
|
2022-07-11 17:52:38 +02:00
|
|
|
`INSERT IGNORE INTO geo_names (id, type, names) VALUES (?, 'continent', ?)`,
|
|
|
|
|
[city.continent?.geoname_id, JSON.stringify(city.continent?.names)]);
|
2022-08-24 15:39:52 +02:00
|
|
|
if (result[0].changedRows ?? 0 > 0) {
|
|
|
|
|
++geoNamesInserted;
|
|
|
|
|
}
|
2022-08-08 09:00:11 +02:00
|
|
|
}
|
2022-07-11 17:52:38 +02:00
|
|
|
|
2022-08-08 09:00:11 +02:00
|
|
|
// Store Country
|
|
|
|
|
if (city.country?.geoname_id) {
|
2022-08-24 15:39:52 +02:00
|
|
|
result = await DB.query<ResultSetHeader>(
|
2022-07-11 17:52:38 +02:00
|
|
|
`INSERT IGNORE INTO geo_names (id, type, names) VALUES (?, 'country', ?)`,
|
|
|
|
|
[city.country?.geoname_id, JSON.stringify(city.country?.names)]);
|
2022-08-24 15:39:52 +02:00
|
|
|
if (result[0].changedRows ?? 0 > 0) {
|
|
|
|
|
++geoNamesInserted;
|
|
|
|
|
}
|
2022-08-08 09:00:11 +02:00
|
|
|
}
|
2022-07-11 17:52:38 +02:00
|
|
|
|
2022-07-17 09:53:02 +02:00
|
|
|
// Store Country ISO code
|
|
|
|
|
if (city.country?.iso_code) {
|
2022-08-24 15:39:52 +02:00
|
|
|
result = await DB.query<ResultSetHeader>(
|
2022-08-08 09:00:11 +02:00
|
|
|
`INSERT IGNORE INTO geo_names (id, type, names) VALUES (?, 'country_iso_code', ?)`,
|
|
|
|
|
[city.country?.geoname_id, city.country?.iso_code]);
|
2022-08-24 15:39:52 +02:00
|
|
|
if (result[0].changedRows ?? 0 > 0) {
|
|
|
|
|
++geoNamesInserted;
|
|
|
|
|
}
|
2022-07-17 09:53:02 +02:00
|
|
|
}
|
|
|
|
|
|
2022-07-11 17:52:38 +02:00
|
|
|
// Store Division
|
|
|
|
|
if (city.subdivisions && city.subdivisions[0]) {
|
2022-08-24 15:39:52 +02:00
|
|
|
result = await DB.query<ResultSetHeader>(
|
2022-07-11 17:52:38 +02:00
|
|
|
`INSERT IGNORE INTO geo_names (id, type, names) VALUES (?, 'division', ?)`,
|
|
|
|
|
[city.subdivisions[0].geoname_id, JSON.stringify(city.subdivisions[0]?.names)]);
|
2022-08-24 15:39:52 +02:00
|
|
|
if (result[0].changedRows ?? 0 > 0) {
|
|
|
|
|
++geoNamesInserted;
|
|
|
|
|
}
|
2022-07-11 17:52:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Store City
|
|
|
|
|
if (city.city?.geoname_id) {
|
2022-08-24 15:39:52 +02:00
|
|
|
result = await DB.query<ResultSetHeader>(
|
2022-07-11 17:52:38 +02:00
|
|
|
`INSERT IGNORE INTO geo_names (id, type, names) VALUES (?, 'city', ?)`,
|
|
|
|
|
[city.city?.geoname_id, JSON.stringify(city.city?.names)]);
|
2022-08-24 15:39:52 +02:00
|
|
|
if (result[0].changedRows ?? 0 > 0) {
|
|
|
|
|
++geoNamesInserted;
|
|
|
|
|
}
|
2022-07-11 17:52:38 +02:00
|
|
|
}
|
2022-07-12 12:12:10 +02:00
|
|
|
|
|
|
|
|
// Store AS name
|
2022-07-23 23:33:13 +02:00
|
|
|
if (isp?.autonomous_system_organization ?? asn?.autonomous_system_organization) {
|
2022-08-24 15:39:52 +02:00
|
|
|
result = await DB.query<ResultSetHeader>(
|
2022-07-12 12:12:10 +02:00
|
|
|
`INSERT IGNORE INTO geo_names (id, type, names) VALUES (?, 'as_organization', ?)`,
|
2022-08-30 17:06:48 +02:00
|
|
|
[
|
|
|
|
|
asOverwrite?.asn ?? isp?.autonomous_system_number ?? asn?.autonomous_system_number,
|
|
|
|
|
JSON.stringify(asOverwrite?.name ?? isp?.isp ?? asn?.autonomous_system_organization)
|
|
|
|
|
]);
|
2022-08-24 15:39:52 +02:00
|
|
|
if (result[0].changedRows ?? 0 > 0) {
|
|
|
|
|
++geoNamesInserted;
|
|
|
|
|
}
|
2022-07-12 12:12:10 +02:00
|
|
|
}
|
2022-07-11 17:52:38 +02:00
|
|
|
}
|
2022-08-08 09:00:11 +02:00
|
|
|
|
|
|
|
|
++progress;
|
|
|
|
|
const elapsedSeconds = Math.round((new Date().getTime() / 1000) - loggerTimer);
|
2022-12-01 15:52:06 +01:00
|
|
|
if (elapsedSeconds > config.LIGHTNING.LOGGER_UPDATE_INTERVAL) {
|
|
|
|
|
logger.debug(`Updating node location data ${progress}/${nodes.length}`);
|
2022-08-08 09:00:11 +02:00
|
|
|
loggerTimer = new Date().getTime() / 1000;
|
|
|
|
|
}
|
2022-07-11 17:52:38 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-08-24 15:39:52 +02:00
|
|
|
|
|
|
|
|
if (nodesUpdated > 0) {
|
2022-12-01 15:52:06 +01:00
|
|
|
logger.debug(`${nodesUpdated} nodes maxmind data updated, ${geoNamesInserted} geo names inserted`, logger.tags.ln);
|
2022-08-24 15:39:52 +02:00
|
|
|
}
|
2022-07-11 17:52:38 +02:00
|
|
|
} catch (e) {
|
|
|
|
|
logger.err('$lookupNodeLocation() error: ' + (e instanceof Error ? e.message : e));
|
|
|
|
|
}
|
2022-07-23 23:53:28 +02:00
|
|
|
}
|