fix(ipintelligence): handle flat geolocation MMDB schema and clean up DNS client lifecycle
This commit is contained in:
@@ -2,7 +2,21 @@ import * as plugins from './smartnetwork.plugins.js';
|
||||
import { getLogger } from './logging.js';
|
||||
|
||||
// MaxMind types re-exported from mmdb-lib via maxmind
|
||||
import type { CityResponse, AsnResponse, Reader } from 'maxmind';
|
||||
import type { AsnResponse, Reader, Response } from 'maxmind';
|
||||
|
||||
/**
|
||||
* The @ip-location-db MMDB files use a flat schema instead of the standard MaxMind nested format.
|
||||
*/
|
||||
interface IIpLocationDbCityRecord {
|
||||
city?: string;
|
||||
country_code?: string;
|
||||
latitude?: number;
|
||||
longitude?: number;
|
||||
postcode?: string;
|
||||
state1?: string;
|
||||
state2?: string;
|
||||
timezone?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unified result from all IP intelligence layers
|
||||
@@ -70,7 +84,7 @@ export class IpIntelligence {
|
||||
private readonly timeout: number;
|
||||
|
||||
// MaxMind readers (lazily initialized)
|
||||
private cityReader: Reader<CityResponse> | null = null;
|
||||
private cityReader: Reader<IIpLocationDbCityRecord & Response> | null = null;
|
||||
private asnReader: Reader<AsnResponse> | null = null;
|
||||
private lastFetchTime = 0;
|
||||
private refreshPromise: Promise<void> | null = null;
|
||||
@@ -371,11 +385,12 @@ export class IpIntelligence {
|
||||
* Response: "ASN | prefix | CC | rir | date"
|
||||
*/
|
||||
private async queryTeamCymru(ip: string): Promise<{ asn: number; prefix: string; country: string } | null> {
|
||||
let dnsClient: InstanceType<typeof plugins.smartdns.dnsClientMod.Smartdns> | null = null;
|
||||
try {
|
||||
const reversed = ip.split('.').reverse().join('.');
|
||||
const queryName = `${reversed}.origin.asn.cymru.com`;
|
||||
|
||||
const dnsClient = new plugins.smartdns.dnsClientMod.Smartdns({
|
||||
dnsClient = new plugins.smartdns.dnsClientMod.Smartdns({
|
||||
strategy: 'prefer-system',
|
||||
allowDohFallback: true,
|
||||
timeoutMs: this.timeout,
|
||||
@@ -402,6 +417,10 @@ export class IpIntelligence {
|
||||
} catch (err: any) {
|
||||
this.logger.debug?.(`Team Cymru DNS query failed for ${ip}: ${err.message}`);
|
||||
return null;
|
||||
} finally {
|
||||
if (dnsClient) {
|
||||
dnsClient.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,7 +461,7 @@ export class IpIntelligence {
|
||||
this.fetchBuffer(ASN_MMDB_URL),
|
||||
]);
|
||||
|
||||
this.cityReader = new plugins.maxmind.Reader<CityResponse>(cityBuffer);
|
||||
this.cityReader = new plugins.maxmind.Reader<IIpLocationDbCityRecord & Response>(cityBuffer);
|
||||
this.asnReader = new plugins.maxmind.Reader<AsnResponse>(asnBuffer);
|
||||
this.lastFetchTime = Date.now();
|
||||
this.logger.info?.('MaxMind MMDB databases loaded into memory');
|
||||
@@ -495,17 +514,17 @@ export class IpIntelligence {
|
||||
let asn: number | null = null;
|
||||
let asnOrg: string | null = null;
|
||||
|
||||
// City lookup
|
||||
// City lookup — @ip-location-db uses flat schema: city, country_code, latitude, longitude, etc.
|
||||
try {
|
||||
const cityResult = this.cityReader.get(ip);
|
||||
if (cityResult) {
|
||||
country = cityResult.country?.names?.en || null;
|
||||
countryCode = cityResult.country?.iso_code || null;
|
||||
city = cityResult.city?.names?.en || null;
|
||||
latitude = cityResult.location?.latitude ?? null;
|
||||
longitude = cityResult.location?.longitude ?? null;
|
||||
accuracyRadius = cityResult.location?.accuracy_radius ?? null;
|
||||
timezone = cityResult.location?.time_zone || null;
|
||||
countryCode = cityResult.country_code || null;
|
||||
city = cityResult.city || null;
|
||||
latitude = cityResult.latitude ?? null;
|
||||
longitude = cityResult.longitude ?? null;
|
||||
timezone = cityResult.timezone || null;
|
||||
// @ip-location-db does not include country name or accuracy_radius
|
||||
// We leave country null (countryCode is available)
|
||||
}
|
||||
} catch (err: any) {
|
||||
this.logger.debug?.(`MaxMind city lookup failed for ${ip}: ${err.message}`);
|
||||
|
||||
Reference in New Issue
Block a user