diff --git a/src/resolver.ts b/src/resolver.ts index 493a22c..756948d 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -69,10 +69,6 @@ export default class Handshake extends AbstractResolverModule { return resolverEmptyResponse(); } - if (options?.options && "subquery" in options.options) { - return resolverEmptyResponse(); - } - const chainRecords = await this.query(tld); if (chainRecords.error) { return resolverError(chainRecords.error); @@ -84,51 +80,48 @@ export default class Handshake extends AbstractResolverModule { let records: DNSRecord[] = []; - for (const record of chainRecords.result?.records) { - switch (record.type) { - case "NS": { - await this.processNs( - domain, - record, - records, - chainRecords.result?.records, - options, - bypassCache, + const hnsRecords = chainRecords.result?.records; + const nsServer = this.findNameserver(hnsRecords, options); + + if (!nsServer) { + const ns = this.findRecordsByType(hnsRecords, "NS"); + + if (ns && this.isNSHip5(ns[0], options)) { + let result = await this.resolver.resolve( + ns[0].ns, + { + ...options, + options: { + domain, + }, + }, + bypassCache, + ); + + if (result.records.length) { + records.push.apply(records, result.records); + } + } else { + const content = this.findRecordsByType(hnsRecords, "TXT"); + if (content && [DNS_RECORD_TYPE.CONTENT].includes(options.type)) { + content.forEach((record) => + records.push({ + type: DNS_RECORD_TYPE.CONTENT, + value: record.txt.slice().pop() as string, + }), ); - break; } - case "GLUE4": { - await this.processGlue(domain, record, records, options, bypassCache); - break; - } - case "TXT": { - await this.processTxt(record, records, options); - break; - } - case "SYNTH6": { - if ( - options.type === DNS_RECORD_TYPE.A && - "ipv6" in options.options && - options.options.ipv6 - ) { + } + } else { + for (const type of [DNS_RECORD_TYPE.A, DNS_RECORD_TYPE.CNAME]) { + if (type === options.type) { + const ret = await this.dnsQuery(domain, type); + if (ret.length) { records.push({ - type: options.type, - value: record.address, + type, + value: ret.slice().shift().data.address, }); } - break; - } - case "SYNTH4": { - if (options.type === DNS_RECORD_TYPE.A) { - records.push({ - type: options.type, - value: record.address, - }); - } - break; - } - default: { - break; } } } @@ -142,155 +135,71 @@ export default class Handshake extends AbstractResolverModule { return resolverEmptyResponse(); } - // @ts-ignore - private async processNs( - domain: string, - record: HnsRecord, - records: DNSRecord[], - hnsRecords: HnsRecord[], - options: ResolverOptions, - bypassCache: boolean, - ) { - if ( - ![DNS_RECORD_TYPE.A, DNS_RECORD_TYPE.CNAME, DNS_RECORD_TYPE.NS].includes( - options.type, - ) - ) { - return; - } - // @ts-ignore - const glue = hnsRecords.slice().find( - (item: object) => - // @ts-ignore - ["GLUE4", "GLUE6"].includes(item.type) && item.ns === record.ns, - ); - - if (glue && options.type !== DNS_RECORD_TYPE.NS) { - return this.processGlue(domain, glue, records, options, bypassCache); - } - - if (options.type === DNS_RECORD_TYPE.NS) { - records.push({ type: options.type, value: record.ns }); - return; - } - - const foundDomain = normalizeDomain(record.ns); - - let isIcann = false; - let isHip5 = false; - - let hip5Parts = foundDomain.split("."); - - if ( - hip5Parts.length >= 2 && - [...(options.options?.hip5 ?? []), ...HIP5_EXTENSIONS].includes( - hip5Parts[hip5Parts.length - 1], - ) - ) { - isHip5 = true; - } - - if ( - (isDomain(foundDomain) || /[a-zA-Z0-9\-]+/.test(foundDomain)) && - !isHip5 - ) { - if (foundDomain.includes(".")) { - const tld = foundDomain.split(".")[foundDomain.split(".").length - 1]; - - isIcann = tldEnum.list.includes(tld); - } - - if (!isIcann) { - const hnsNs = await this.resolver.resolve(foundDomain, options); - - if (hnsNs.records.length) { - let icannRecords = await this.resolver.resolve(domain, { - ...options, - options: { - subquery: true, - nameserver: hnsNs.records.pop()?.value, - }, - }); - if (icannRecords.records.length) { - records.push.apply(records, icannRecords.records); - } - } - - return resolverEmptyResponse(); - } - - let icannRecords = await this.resolver.resolve(domain, { - ...options, - options: { subquery: true, nameserver: foundDomain }, - }); - if (icannRecords.records.length) { - records.push.apply(records, icannRecords.records); - return; - } - - return resolverEmptyResponse(); - } - - let result = await this.resolver.resolve(record.ns, options, bypassCache); - - if (!result.records.length) { - result.records.push({ type: DNS_RECORD_TYPE.NS, value: record.ns }); - return; - } - - records.push.apply(records, result.records); - } - - private async processGlue( - domain: string, - record: HnsRecord, - records: DNSRecord[], - options: ResolverOptions, - bypassCache: boolean, - ) { - if (![DNS_RECORD_TYPE.A, DNS_RECORD_TYPE.CNAME].includes(options.type)) { - return; - } - if (isDomain(record.ns) && isIp(record.address)) { - let results = await this.resolver.resolve( - domain, - { - ...options, - options: { - subquery: true, - nameserver: record.address, - }, - }, - bypassCache, - ); - if (results.records.length) { - records.push.apply(records, results.records); - } - } - } - private async query(tld: string): Promise { return client.query("getnameresource", [tld, true]); } - private async processTxt( - record: HnsRecord, - records: DNSRecord[], - options: ResolverOptions, - ) { - const content = record.txt.slice().pop() as string; - - if ( - [DNS_RECORD_TYPE.TEXT, DNS_RECORD_TYPE.CONTENT].includes(options.type) - ) { - records.push({ - type: DNS_RECORD_TYPE.TEXT, - value: content, - }); - } + private async dnsQuery(domain: string, type: string): Promise { + return client.dnsQuery(domain, type); } async ready() { - return ((await client.status()) as any)?.ready; + return ((await client.status()) as any)?.ready; + } + + private findNameserver( + records: HnsRecord[], + options: ResolverOptions, + ): HnsRecord | false { + const synth4 = this.findRecordsByType(records, "SYNTH4"); + const synth6 = this.findRecordsByType(records, "SYNTH6"); + const synth = synth4 || synth6; + const glue4 = this.findRecordsByType(records, "GLUE4"); + const glue6 = this.findRecordsByType(records, "GLUE6"); + const glue = glue4 || glue6; + + const ns = this.findRecordsByType(records, "NS"); + + if (synth) { + return synth[0]; + } + + if (glue) { + return glue[0]; + } + + if (ns) { + if (!this.isNSHip5(ns[0], options)) { + return ns[0]; + } + } + + return false; + } + + private findRecordsByType( + records: HnsRecord[], + type: "NS" | "SYNTH4" | "SYNTH6" | "GLUE4" | "GLUE6" | "TXT", + ) { + const ret = records.filter((item) => item.type === type); + + if (!ret.length) { + return false; + } + + return ret; + } + + private isNSHip5(record: HnsRecord, options: ResolverOptions) { + const foundDomain = normalizeDomain(record.ns); + + let hip5Parts = foundDomain.split("."); + + return ( + hip5Parts.length >= 2 && + [...(options.options?.hip5 ?? []), ...HIP5_EXTENSIONS].includes( + hip5Parts[hip5Parts.length - 1], + ) + ); } }