|
@@ -1,6 +1,7 @@
|
|
|
import tldts from 'tldts-experimental';
|
|
import tldts from 'tldts-experimental';
|
|
|
import { looseTldtsOpt } from '../constants/loose-tldts-opt';
|
|
import { looseTldtsOpt } from '../constants/loose-tldts-opt';
|
|
|
import picocolors from 'picocolors';
|
|
import picocolors from 'picocolors';
|
|
|
|
|
+import { pickRandom, pickOne } from 'foxts/pick-random';
|
|
|
|
|
|
|
|
import DNS2 from 'dns2';
|
|
import DNS2 from 'dns2';
|
|
|
import asyncRetry from 'async-retry';
|
|
import asyncRetry from 'async-retry';
|
|
@@ -82,32 +83,27 @@ const domesticDohServers: Array<[string, DNS2.DnsResolver]> = ([
|
|
|
})
|
|
})
|
|
|
] as const);
|
|
] as const);
|
|
|
|
|
|
|
|
-function createResolve(server: Array<[string, DNS2.DnsResolver]>): DNS2.DnsResolver<DnsResponse> {
|
|
|
|
|
- return async (...args) => {
|
|
|
|
|
- try {
|
|
|
|
|
- return await asyncRetry(async () => {
|
|
|
|
|
- const [dohServer, dohClient] = server[Math.floor(Math.random() * server.length)];
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- return {
|
|
|
|
|
- ...await dohClient(...args),
|
|
|
|
|
- dns: dohServer
|
|
|
|
|
- } satisfies DnsResponse;
|
|
|
|
|
- } catch (e) {
|
|
|
|
|
- // console.error(e);
|
|
|
|
|
- throw new DnsError((e as Error).message, dohServer);
|
|
|
|
|
- }
|
|
|
|
|
- }, { retries: 5 });
|
|
|
|
|
- } catch (e) {
|
|
|
|
|
- console.log('[doh error]', ...args, e);
|
|
|
|
|
- throw e;
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
|
|
+async function $resolve(name: string, type: DNS2.PacketQuestion, server: [string, DNS2.DnsResolver]) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ return await asyncRetry(async () => {
|
|
|
|
|
+ const [dohServer, dohClient] = server;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ return {
|
|
|
|
|
+ ...await dohClient(name, type),
|
|
|
|
|
+ dns: dohServer
|
|
|
|
|
+ } satisfies DnsResponse;
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ // console.error(e);
|
|
|
|
|
+ throw new DnsError((e as Error).message, dohServer);
|
|
|
|
|
+ }
|
|
|
|
|
+ }, { retries: 5 });
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.log('[doh error]', name, type, e);
|
|
|
|
|
+ throw e;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const resolve = createResolve(dohServers);
|
|
|
|
|
-const domesticResolve = createResolve(domesticDohServers);
|
|
|
|
|
-
|
|
|
|
|
async function getWhois(domain: string) {
|
|
async function getWhois(domain: string) {
|
|
|
return asyncRetry(() => whoiser.domain(domain, { raw: true }), { retries: 5 });
|
|
return asyncRetry(() => whoiser.domain(domain, { raw: true }), { retries: 5 });
|
|
|
}
|
|
}
|
|
@@ -147,9 +143,10 @@ export async function isDomainAlive(domain: string, isSuffix: boolean): Promise<
|
|
|
const aaaaDns: string[] = [];
|
|
const aaaaDns: string[] = [];
|
|
|
|
|
|
|
|
// test 2 times before make sure record is empty
|
|
// test 2 times before make sure record is empty
|
|
|
|
|
+ const servers = pickRandom(dohServers, 3);
|
|
|
for (let i = 0; i < 2; i++) {
|
|
for (let i = 0; i < 2; i++) {
|
|
|
// eslint-disable-next-line no-await-in-loop -- sequential
|
|
// eslint-disable-next-line no-await-in-loop -- sequential
|
|
|
- const aRecords = (await resolve($domain, 'A'));
|
|
|
|
|
|
|
+ const aRecords = (await $resolve($domain, 'A', servers[i]));
|
|
|
if (aRecords.answers.length > 0) {
|
|
if (aRecords.answers.length > 0) {
|
|
|
return onDomainAlive(domain);
|
|
return onDomainAlive(domain);
|
|
|
}
|
|
}
|
|
@@ -158,7 +155,7 @@ export async function isDomainAlive(domain: string, isSuffix: boolean): Promise<
|
|
|
}
|
|
}
|
|
|
for (let i = 0; i < 2; i++) {
|
|
for (let i = 0; i < 2; i++) {
|
|
|
// eslint-disable-next-line no-await-in-loop -- sequential
|
|
// eslint-disable-next-line no-await-in-loop -- sequential
|
|
|
- const aaaaRecords = (await resolve($domain, 'AAAA'));
|
|
|
|
|
|
|
+ const aaaaRecords = (await $resolve($domain, 'AAAA', servers[i]));
|
|
|
if (aaaaRecords.answers.length > 0) {
|
|
if (aaaaRecords.answers.length > 0) {
|
|
|
return onDomainAlive(domain);
|
|
return onDomainAlive(domain);
|
|
|
}
|
|
}
|
|
@@ -167,13 +164,13 @@ export async function isDomainAlive(domain: string, isSuffix: boolean): Promise<
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// only then, let's test once with domesticDohServers
|
|
// only then, let's test once with domesticDohServers
|
|
|
- const aRecords = (await domesticResolve($domain, 'A'));
|
|
|
|
|
|
|
+ const aRecords = (await $resolve($domain, 'A', pickOne(domesticDohServers)));
|
|
|
if (aRecords.answers.length > 0) {
|
|
if (aRecords.answers.length > 0) {
|
|
|
return onDomainAlive(domain);
|
|
return onDomainAlive(domain);
|
|
|
}
|
|
}
|
|
|
aDns.push(aRecords.dns);
|
|
aDns.push(aRecords.dns);
|
|
|
|
|
|
|
|
- const aaaaRecords = (await domesticResolve($domain, 'AAAA'));
|
|
|
|
|
|
|
+ const aaaaRecords = (await $resolve($domain, 'AAAA', pickOne(domesticDohServers)));
|
|
|
if (aaaaRecords.answers.length > 0) {
|
|
if (aaaaRecords.answers.length > 0) {
|
|
|
return onDomainAlive(domain);
|
|
return onDomainAlive(domain);
|
|
|
}
|
|
}
|
|
@@ -194,7 +191,7 @@ async function isApexDomainAlive(apexDomain: string): Promise<[string, boolean]>
|
|
|
if (apexDomainNsResolvePromiseMap.has(apexDomain)) {
|
|
if (apexDomainNsResolvePromiseMap.has(apexDomain)) {
|
|
|
resp = await apexDomainNsResolvePromiseMap.get(apexDomain)!;
|
|
resp = await apexDomainNsResolvePromiseMap.get(apexDomain)!;
|
|
|
} else {
|
|
} else {
|
|
|
- const promise = resolve(apexDomain, 'NS');
|
|
|
|
|
|
|
+ const promise = $resolve(apexDomain, 'NS', pickOne(dohServers));
|
|
|
apexDomainNsResolvePromiseMap.set(apexDomain, promise);
|
|
apexDomainNsResolvePromiseMap.set(apexDomain, promise);
|
|
|
resp = await promise;
|
|
resp = await promise;
|
|
|
}
|
|
}
|