import {LocalCache, logger} from '@certd/basic'; import dnsSdk, {AnyRecord} from 'dns' import {LookupAddress} from "node:dns"; const dns = dnsSdk.promises export class DnsCustom{ private resolver: dnsSdk.promises.Resolver; // private cache = new LRUCache({ // max: 1000, // ttl: 1000 * 60 * 5, // }); constructor(dnsServers:string[]) { const resolver = new dns.Resolver(); resolver.setServers(dnsServers); this.resolver = resolver; } // async lookup(hostname:string,options?:{ family: any, hints: number, all: boolean }):Promise{ // const cacheKey = hostname + JSON.stringify(options) // let res = this.cache.get(cacheKey) // if (res){ // return res // } // res = await this.doLookup(hostname,options) // this.cache.set(cacheKey,res) // return res // } async lookup(hostname:string,options?:{ family: any, hints: number, all: boolean }):Promise{ // { family: undefined, hints: 0, all: true } let v4:LookupAddress[] = [] let v6:LookupAddress[] = [] let errors = [] const queryV6 = async ()=>{ try{ const list = await this.resolver.resolve6(hostname) if (list && list.length > 0) { v6 = list.map(item=>{ return { address: item, family: 6 } }) } }catch (e) { logger.warn("query v6 error",e) errors.push(e) } } const queryV4 = async ()=>{ try{ const list =await this.resolver.resolve4(hostname) if (list && list.length > 0) { v4 = list.map(item=>{ return { address: item, family: 4 } }) } }catch (e) { logger.warn("query v4 error",e) errors.push(e) } } const queries:Promise[] = [] const {family, all} = options if (all){ queries.push(queryV6()) queries.push(queryV4()) }else{ if(family === 6 ){ queries.push(queryV6()) } if(family === 4 ){ queries.push(queryV4()) } } await Promise.all(queries) const res = [...v4,...v6] if(res.length === 0){ if (errors.length > 0){ const e = new Error(errors[0]) // @ts-ignore e.errors = errors throw e } } return res } async resolve4(hostname:string):Promise{ return await this.resolver.resolve4(hostname) } async resolve6(hostname:string):Promise{ return await this.resolver.resolve6(hostname) } async resolveAny(hostname:string):Promise{ return await this.resolver.resolveAny(hostname) } async resolveCname(hostname:string):Promise{ return await this.resolver.resolveCname(hostname) } } export class DnsContainer{ bucket: LocalCache = new LocalCache() constructor() {} getDns(server:string[]){ const key = server.join(',') let dns = this.bucket.get(key) if (dns){ return dns } dns = new DnsCustom(server) this.bucket.set(key,dns) return dns } } export const dnsContainer = new DnsContainer()