diff --git a/packages/ui/certd-server/src/modules/monitor/service/dns-custom.ts b/packages/ui/certd-server/src/modules/monitor/service/dns-custom.ts index 39d321cb..29436b96 100644 --- a/packages/ui/certd-server/src/modules/monitor/service/dns-custom.ts +++ b/packages/ui/certd-server/src/modules/monitor/service/dns-custom.ts @@ -1,60 +1,134 @@ -import { LocalCache } from '@certd/basic'; -import dnsSdk from 'dns' +import {LocalCache, logger} from '@certd/basic'; +import dnsSdk, {AnyRecord} from 'dns' +import { LRUCache } from 'lru-cache'; +import {LookupAddress} from "node:dns"; const dns = dnsSdk.promises export class DnsCustom{ - resolver: any; + 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 resolve(hostname:string,options:any):Promise{ - // { family: undefined, hints: 0, all: true } - const cnames = await this.resolver.resolveCname(hostname) - let cnameIps = [] - // deep - if (cnames && cnames.length > 0) { - for (let cname of cnames) { - const cnameIp = await this.resolve(cname,options) - if (cnameIp && cnameIp.length > 0) { - cnameIps.push(...cnameIp) + 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 doLookup(hostname:string,options?:{ family: any, hints: number, all: boolean }):Promise{ + // { family: undefined, hints: 0, all: true } + let cnameIps:LookupAddress[] = [] + let v4:LookupAddress[] = [] + let v6:LookupAddress[] = [] + let errors = [] + const resolveCname = async ()=>{ + let cnames = [] + try{ + cnames = await this.resolver.resolveCname(hostname) + }catch (e) { + errors.push(e) + logger.warn("query cname error",e) + } + // deep + if (cnames && cnames.length > 0) { + for (let cname of cnames) { + try{ + const cnameIp = await this.lookup(cname,options) + if (cnameIp && cnameIp.length > 0) { + cnameIps.push(...cnameIp) + } + }catch (e) { + errors.push(e) + logger.warn("lookup cname error",e) + } } } } - let v4 = [] - let v6 = [] + 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[] = [resolveCname()] + const {family, all} = options - if(family === 6 && !all){ - v6= await this.resolver.resolve6(hostname) + if (all){ + queries.push(queryV6()) + queries.push(queryV4()) + }else{ + if(family === 6 ){ + queries.push(queryV6()) + } + if(family === 4 ){ + queries.push(queryV4()) + } } - if(family === 4 && !all){ - v4 = await this.resolver.resolve4(hostname) + await Promise.all(queries) + const res = [...v4,...v6,...cnameIps] + if(res.length === 0){ + if (errors.length > 0){ + const e = new Error(errors[0]) + // @ts-ignore + e.errors = errors + throw e + } } - - if(all){ - v4 = await this.resolver.resolve4(hostname) - v6 = await this.resolver.resolve6(hostname) - } - - return [...v4,...v6,...cnameIps] + return res } - async resolve4(hostname:string,options:any):Promise{ - return await this.resolver.resolve4(hostname,options) + async resolve4(hostname:string):Promise{ + return await this.resolver.resolve4(hostname) } - async resolve6(hostname:string,options:any):Promise{ - return await this.resolver.resolve6(hostname,options) + async resolve6(hostname:string):Promise{ + return await this.resolver.resolve6(hostname) } - async resolveAny(hostname:string,options:any):Promise{ - return await this.resolver.resolveAny(hostname,options) + async resolveAny(hostname:string):Promise{ + return await this.resolver.resolveAny(hostname) } - async resolveCname(hostname:string,options:any):Promise{ - return await this.resolver.resolveCname(hostname,options) + async resolveCname(hostname:string):Promise{ + return await this.resolver.resolveCname(hostname) } diff --git a/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts b/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts index c56df2bd..4f9f7f9f 100644 --- a/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts +++ b/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts @@ -112,9 +112,9 @@ export class SiteInfoService extends BaseService { const setting = await this.userSettingsService.getSetting(site.userId, UserSiteMonitorSetting); const dnsServer = setting.dnsServer - let resolver = null + let customDns = null if (dnsServer && dnsServer.length > 0) { - resolver = dnsContainer.getDns(dnsServer) as any + customDns = dnsContainer.getDns(dnsServer) as any } try { @@ -127,7 +127,7 @@ export class SiteInfoService extends BaseService { host: site.domain, port: site.httpsPort, retryTimes, - resolver + customDns }); const certi: PeerCertificate = res.certificate; @@ -154,7 +154,7 @@ export class SiteInfoService extends BaseService { error: null, checkStatus: "ok" }; - + logger.info(`测试站点成功:id=${updateData.id},site=${site.name},expiresTime=${updateData.certExpiresTime}`) if (site.ipCheck) { delete updateData.checkStatus } diff --git a/packages/ui/certd-server/src/modules/monitor/service/site-ip-service.ts b/packages/ui/certd-server/src/modules/monitor/service/site-ip-service.ts index f0427b18..3220b9ae 100644 --- a/packages/ui/certd-server/src/modules/monitor/service/site-ip-service.ts +++ b/packages/ui/certd-server/src/modules/monitor/service/site-ip-service.ts @@ -134,6 +134,7 @@ export class SiteIpService extends BaseService { if (!entity) { return; } + logger.info(`开始测试站点ip: id=${entity.id},ip=${entity.ipAddress}`) try { await this.update({ id: entity.id, @@ -173,7 +174,7 @@ export class SiteIpService extends BaseService { }; await this.update(updateData); - + logger.info(`测试站点ip成功: id=${updateData.id},ip=${entity.ipAddress},expiresTime=${updateData.certExpiresTime}`) return updateData } catch (e) { @@ -231,7 +232,7 @@ export class SiteIpService extends BaseService { try{ return await resolver.resolve4(domain); }catch (err) { - logger.error(`[${domain}] resolve4 error`, err) + logger.warn(`[${domain}] resolve4 error`, err) return [] } } @@ -239,7 +240,7 @@ export class SiteIpService extends BaseService { try{ return await resolver.resolve6(domain); }catch (err) { - logger.error(`[${domain}] resolve6 error`, err) + logger.warn(`[${domain}] resolve6 error`, err) return [] } } diff --git a/packages/ui/certd-server/src/modules/monitor/service/site-tester.ts b/packages/ui/certd-server/src/modules/monitor/service/site-tester.ts index a25e64ce..e2b99731 100644 --- a/packages/ui/certd-server/src/modules/monitor/service/site-tester.ts +++ b/packages/ui/certd-server/src/modules/monitor/service/site-tester.ts @@ -2,6 +2,7 @@ import { logger, safePromise, utils } from "@certd/basic"; import { merge } from "lodash-es"; import https from "https"; import { PeerCertificate } from "tls"; +import {DnsCustom} from "./dns-custom.js"; export type SiteTestReq = { host: string; // 只用域名部分 @@ -10,7 +11,7 @@ export type SiteTestReq = { retryTimes?: number; ipAddress?: string; - resolver?: any; + customDns?: DnsCustom; }; export type SiteTestRes = { @@ -19,7 +20,9 @@ export type SiteTestRes = { export class SiteTester { async test(req: SiteTestReq): Promise { - logger.info("测试站点:", JSON.stringify(req)); + const req_ = {...req} + delete req_.customDns + logger.info("测试站点:", JSON.stringify(req_)); const maxRetryTimes = req.retryTimes == null ? 3 : req.retryTimes; let tryCount = 0; let result: SiteTestRes = {}; @@ -61,15 +64,18 @@ export class SiteTester { servername: options.host }; options.host = ipAddress; - }else if (req.resolver ) { + }else if (req.customDns ) { // 非ip address 请求时 - const resolver = req.resolver + const customDns = req.customDns customLookup = async (hostname:string, options:any, callback)=> { console.log(hostname, options); // { family: undefined, hints: 0, all: true } - const res = await resolver.resolve(hostname, options) + const res = await customDns.lookup(hostname, options) console.log("custom lookup res:",res) + if (!res || res.length === 0) { + callback(new Error("没有解析到IP")); + } callback(null, res); } }