@push.rocks/smartdns
Version:
A robust TypeScript library providing advanced DNS management and resolution capabilities including support for DNSSEC, custom DNS servers, and integration with various DNS providers.
285 lines • 21.3 kB
JavaScript
import * as plugins from './plugins.js';
import { RustDnsClientBridge } from './classes.rustdnsclientbridge.js';
export const makeNodeProcessUseDnsProvider = (providerArg) => {
const nodeDns = plugins.dns;
if (!nodeDns) {
throw new Error('Node DNS module is not available in this runtime');
}
switch (providerArg) {
case 'cloudflare':
nodeDns.setServers([
'1.1.1.1',
'1.0.0.1',
'[2606:4700:4700::1111]',
'[2606:4700:4700::1001]',
]);
break;
case 'google':
nodeDns.setServers([
'8.8.8.8',
'8.8.4.4',
'[2001:4860:4860::8888]',
'[2606:4700:4700::1001]',
]);
}
};
/**
* Smartdns offers methods for working with DNS resolution.
* Supports system resolver, UDP wire-format, and DoH (DNS-over-HTTPS) via a Rust binary.
*/
export class Smartdns {
constructor(optionsArg) {
this.strategy = 'prefer-system';
this.allowDohFallback = true;
this.rustBridge = null;
this.dnsTypeMap = {
A: 1,
NS: 2,
CNAME: 5,
SOA: 6,
PTR: 12,
MX: 15,
TXT: 16,
AAAA: 28,
SRV: 33,
};
this.strategy = optionsArg?.strategy || 'prefer-system';
this.allowDohFallback =
optionsArg?.allowDohFallback === undefined ? true : optionsArg.allowDohFallback;
this.timeoutMs = optionsArg?.timeoutMs;
}
getRustBridge() {
if (!this.rustBridge) {
this.rustBridge = new RustDnsClientBridge();
}
return this.rustBridge;
}
/**
* check a dns record until it has propagated
*/
async checkUntilAvailable(recordNameArg, recordTypeArg, expectedValue, cyclesArg = 50, intervalArg = 500) {
let runCycles = 0;
const doCheck = async () => {
if (runCycles < cyclesArg) {
runCycles++;
try {
let myRecordArray;
if (runCycles % 2 === 0 || !plugins.dns) {
myRecordArray = await this.getRecords(recordNameArg, recordTypeArg, 0);
}
else {
myRecordArray = await this.getRecordWithNodeDNS(recordNameArg, recordTypeArg);
}
const myRecord = myRecordArray[0].value;
if (myRecord === expectedValue) {
console.log(`smartdns: .checkUntilAvailable() verified that wanted >>>${recordTypeArg}<<< record exists for >>>${recordNameArg}<<< with value >>>${expectedValue}<<<`);
return true;
}
else {
await plugins.smartdelay.delayFor(intervalArg);
return await doCheck();
}
}
catch (err) {
await plugins.smartdelay.delayFor(intervalArg);
return await doCheck();
}
}
else {
console.log(`smartdns: .checkUntilAvailable() failed permanently for ${recordNameArg} with value ${recordTypeArg} - ${expectedValue}...`);
return false;
}
};
return await doCheck();
}
/**
* get A Dns Record
*/
async getRecordsA(recordNameArg) {
return await this.getRecords(recordNameArg, 'A');
}
/**
* get AAAA Record
*/
async getRecordsAAAA(recordNameArg) {
return await this.getRecords(recordNameArg, 'AAAA');
}
/**
* gets a txt record
*/
async getRecordsTxt(recordNameArg) {
return await this.getRecords(recordNameArg, 'TXT');
}
async getRecords(recordNameArg, recordTypeArg, retriesCounterArg = 20) {
const trySystem = async () => {
const nodeDns = plugins.dns;
if (!nodeDns) {
throw new Error('Node DNS module is not available in this runtime');
}
// Prefer dns.lookup for A/AAAA so hosts file and OS resolver are honored
if (recordTypeArg === 'A' || recordTypeArg === 'AAAA') {
const family = recordTypeArg === 'A' ? 4 : 6;
const addresses = await new Promise((resolve, reject) => {
const timer = this.timeoutMs
? setTimeout(() => reject(new Error('system lookup timeout')), this.timeoutMs)
: null;
nodeDns.lookup(recordNameArg, { family, all: true }, (err, result) => {
if (timer)
clearTimeout(timer);
if (err)
return reject(err);
resolve(result || []);
});
});
return addresses.map((a) => ({
name: recordNameArg,
type: recordTypeArg,
dnsSecEnabled: false,
value: a.address,
}));
}
if (recordTypeArg === 'TXT') {
const records = await new Promise((resolve, reject) => {
const timer = this.timeoutMs
? setTimeout(() => reject(new Error('system resolveTxt timeout')), this.timeoutMs)
: null;
nodeDns.resolveTxt(recordNameArg, (err, res) => {
if (timer)
clearTimeout(timer);
if (err)
return reject(err);
resolve(res || []);
});
});
return records.map((chunks) => ({
name: recordNameArg,
type: 'TXT',
dnsSecEnabled: false,
value: chunks.join(''),
}));
}
return [];
};
const tryRust = async (protocol) => {
const bridge = this.getRustBridge();
const result = await bridge.resolve(recordNameArg, recordTypeArg, protocol, undefined, undefined, this.timeoutMs);
return result.answers.map((answer) => ({
name: answer.name,
type: this.convertDnsTypeNameToCanonical(answer.type) || recordTypeArg,
dnsSecEnabled: result.adFlag,
value: answer.value,
}));
};
try {
if (this.strategy === 'system') {
return await trySystem();
}
if (this.strategy === 'doh') {
return await tryRust('doh');
}
if (this.strategy === 'udp') {
return await tryRust('udp');
}
if (this.strategy === 'prefer-udp') {
try {
const udpRes = await tryRust('udp');
if (udpRes.length > 0)
return udpRes;
return await tryRust('doh');
}
catch (err) {
return await tryRust('doh');
}
}
// prefer-system (default)
try {
const sysRes = await trySystem();
if (sysRes.length > 0)
return sysRes;
return this.allowDohFallback ? await tryRust('doh') : [];
}
catch (err) {
return this.allowDohFallback ? await tryRust('doh') : [];
}
}
catch (finalErr) {
return [];
}
}
/**
* gets a record using nodejs dns resolver
*/
async getRecordWithNodeDNS(recordNameArg, recordTypeArg) {
const nodeDns = plugins.dns;
if (!nodeDns) {
throw new Error('Node DNS module is not available in this runtime');
}
const done = plugins.smartpromise.defer();
nodeDns.resolve(recordNameArg, recordTypeArg, (err, recordsArg) => {
if (err) {
done.reject(err);
return;
}
const returnArray = [];
for (const record of recordsArg) {
const value = Array.isArray(record) ? record.join('') : String(record);
returnArray.push({
name: recordNameArg,
value,
type: recordTypeArg,
dnsSecEnabled: false,
});
}
done.resolve(returnArray);
});
return done.promise;
}
async getNameServers(domainNameArg) {
const nodeDns = plugins.dns;
if (!nodeDns) {
throw new Error('Node DNS module is not available in this runtime');
}
const done = plugins.smartpromise.defer();
nodeDns.resolveNs(domainNameArg, (err, result) => {
if (!err) {
done.resolve(result);
}
else {
console.log(err);
done.reject(err);
}
});
return await done.promise;
}
convertDnsTypeNameToTypeNumber(dnsTypeNameArg) {
return this.dnsTypeMap[dnsTypeNameArg];
}
convertDnsTypeNumberToTypeName(dnsTypeNumberArg) {
for (const key in this.dnsTypeMap) {
if (this.dnsTypeMap[key] === dnsTypeNumberArg) {
return key;
}
}
return null;
}
/**
* Convert a DNS type string from Rust (e.g. "A", "AAAA") to the canonical TDnsRecordType.
*/
convertDnsTypeNameToCanonical(typeName) {
const upper = typeName.toUpperCase();
if (upper in this.dnsTypeMap) {
return upper;
}
return null;
}
/**
* Destroy the Rust client bridge and free resources.
*/
destroy() {
if (this.rustBridge) {
this.rustBridge.kill();
this.rustBridge = null;
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5kbnNjbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19jbGllbnQvY2xhc3Nlcy5kbnNjbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFJdkUsTUFBTSxDQUFDLE1BQU0sNkJBQTZCLEdBQUcsQ0FBQyxXQUF5QixFQUFFLEVBQUU7SUFDekUsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQztJQUM1QixJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDYixNQUFNLElBQUksS0FBSyxDQUFDLGtEQUFrRCxDQUFDLENBQUM7SUFDdEUsQ0FBQztJQUNELFFBQVEsV0FBVyxFQUFFLENBQUM7UUFDcEIsS0FBSyxZQUFZO1lBQ2YsT0FBTyxDQUFDLFVBQVUsQ0FBQztnQkFDakIsU0FBUztnQkFDVCxTQUFTO2dCQUNULHdCQUF3QjtnQkFDeEIsd0JBQXdCO2FBQ3pCLENBQUMsQ0FBQztZQUNILE1BQU07UUFDUixLQUFLLFFBQVE7WUFDWCxPQUFPLENBQUMsVUFBVSxDQUFDO2dCQUNqQixTQUFTO2dCQUNULFNBQVM7Z0JBQ1Qsd0JBQXdCO2dCQUN4Qix3QkFBd0I7YUFDekIsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztBQUNILENBQUMsQ0FBQztBQVVGOzs7R0FHRztBQUNILE1BQU0sT0FBTyxRQUFRO0lBa0JuQixZQUFZLFVBQXVDO1FBakIzQyxhQUFRLEdBQXdCLGVBQWUsQ0FBQztRQUNoRCxxQkFBZ0IsR0FBRyxJQUFJLENBQUM7UUFFeEIsZUFBVSxHQUErQixJQUFJLENBQUM7UUFFL0MsZUFBVSxHQUE4QjtZQUM3QyxDQUFDLEVBQUUsQ0FBQztZQUNKLEVBQUUsRUFBRSxDQUFDO1lBQ0wsS0FBSyxFQUFFLENBQUM7WUFDUixHQUFHLEVBQUUsQ0FBQztZQUNOLEdB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