2018-05-13 13:51:04 +00:00
|
|
|
import * as plugins from './dnsly.plugins';
|
2016-11-15 20:39:21 +00:00
|
|
|
|
2019-01-06 23:28:15 +00:00
|
|
|
export type TDnsProvider = 'google' | 'cloudflare';
|
2020-02-15 16:41:37 +00:00
|
|
|
|
|
|
|
export interface ISmartDnsConstructorOptions {}
|
|
|
|
|
|
|
|
export interface IGoogleDNSHTTPSResponse {
|
|
|
|
Status: number;
|
|
|
|
TC: boolean;
|
|
|
|
RD: boolean;
|
|
|
|
RA: boolean;
|
|
|
|
AD: boolean;
|
|
|
|
CD: boolean;
|
|
|
|
Question: Array< { name: string, type: number }>;
|
|
|
|
Answer: Array<
|
|
|
|
{ name: string, type: number, TTL: number, data: string }
|
|
|
|
>,
|
|
|
|
Additional: [],
|
|
|
|
Comment: string
|
2017-01-26 23:11:13 +00:00
|
|
|
}
|
|
|
|
|
2016-11-15 20:39:21 +00:00
|
|
|
/**
|
|
|
|
* class dnsly offers methods for working with dns from a dns provider like Google DNS
|
|
|
|
*/
|
2018-05-13 13:51:04 +00:00
|
|
|
export class Smartdns {
|
2020-02-15 16:41:37 +00:00
|
|
|
public dnsServerIp: string;
|
|
|
|
public dnsServerPort: number;
|
|
|
|
|
|
|
|
public dnsTypeMap: {[key: string]: number} = {
|
|
|
|
A: 1,
|
|
|
|
AAAA: 28,
|
|
|
|
CNAME: 5,
|
|
|
|
MX: 15,
|
|
|
|
TXT: 16,
|
|
|
|
}
|
|
|
|
|
2017-07-18 13:45:06 +00:00
|
|
|
/**
|
|
|
|
* constructor for class dnsly
|
|
|
|
*/
|
2020-02-15 16:41:37 +00:00
|
|
|
constructor(optionsArg: ISmartDnsConstructorOptions) {}
|
2016-11-15 20:39:21 +00:00
|
|
|
|
2018-05-13 14:43:46 +00:00
|
|
|
/**
|
|
|
|
* check a dns record until it has propagated to Google DNS
|
|
|
|
* should be considerably fast
|
2019-01-06 23:21:15 +00:00
|
|
|
* @param recordNameArg
|
|
|
|
* @param recordTypeArg
|
|
|
|
* @param expectedValue
|
2018-05-13 14:43:46 +00:00
|
|
|
*/
|
2020-02-15 16:41:37 +00:00
|
|
|
public async checkUntilAvailable(
|
2018-05-13 13:51:04 +00:00
|
|
|
recordNameArg: string,
|
2020-02-15 16:41:37 +00:00
|
|
|
recordTypeArg: plugins.tsclass.network.TDnsRecordType,
|
2019-01-06 23:53:04 +00:00
|
|
|
expectedValue: string,
|
|
|
|
cyclesArg: number = 50,
|
|
|
|
intervalArg: number = 500
|
2018-05-13 13:51:04 +00:00
|
|
|
) {
|
2019-01-06 23:53:04 +00:00
|
|
|
let runCycles = 0;
|
2020-02-15 16:41:37 +00:00
|
|
|
const doCheck = async () => {
|
2019-01-06 23:53:04 +00:00
|
|
|
if (runCycles < cyclesArg) {
|
|
|
|
runCycles++;
|
2017-07-18 13:45:06 +00:00
|
|
|
try {
|
2020-02-15 16:41:37 +00:00
|
|
|
const myRecordArray = await this.getRecord(recordNameArg, recordTypeArg);
|
|
|
|
const myRecord = myRecordArray[0].value;
|
2017-07-18 13:45:06 +00:00
|
|
|
if (myRecord === expectedValue) {
|
2018-05-13 13:51:04 +00:00
|
|
|
return true;
|
2017-07-18 13:45:06 +00:00
|
|
|
} else {
|
2019-01-06 23:53:04 +00:00
|
|
|
await plugins.smartdelay.delayFor(intervalArg);
|
2018-05-13 13:51:04 +00:00
|
|
|
return await doCheck();
|
2017-07-18 13:45:06 +00:00
|
|
|
}
|
|
|
|
} catch (err) {
|
2019-01-06 23:53:04 +00:00
|
|
|
await plugins.smartdelay.delayFor(intervalArg);
|
2018-05-13 13:51:04 +00:00
|
|
|
return await doCheck();
|
2017-01-26 23:11:13 +00:00
|
|
|
}
|
2017-07-18 13:45:06 +00:00
|
|
|
} else {
|
2018-05-13 13:51:04 +00:00
|
|
|
console.log('failed permanently...');
|
|
|
|
return false;
|
2017-07-18 13:45:06 +00:00
|
|
|
}
|
2018-05-13 13:51:04 +00:00
|
|
|
};
|
|
|
|
return await doCheck();
|
2017-07-18 13:45:06 +00:00
|
|
|
}
|
2017-01-26 23:11:13 +00:00
|
|
|
|
2017-07-18 13:45:06 +00:00
|
|
|
/**
|
|
|
|
* get A Dns Record
|
|
|
|
*/
|
2020-02-15 16:41:37 +00:00
|
|
|
public async getRecordA(recordNameArg: string): Promise<plugins.tsclass.network.IDnsRecord[]> {
|
2018-05-13 13:51:04 +00:00
|
|
|
return await this.getRecord(recordNameArg, 'A');
|
2017-07-18 13:45:06 +00:00
|
|
|
}
|
2017-01-26 23:11:13 +00:00
|
|
|
|
2017-07-18 13:45:06 +00:00
|
|
|
/**
|
|
|
|
* get AAAA Record
|
|
|
|
*/
|
2020-02-15 16:41:37 +00:00
|
|
|
public async getRecordAAAA(recordNameArg: string) {
|
2018-05-13 13:51:04 +00:00
|
|
|
return await this.getRecord(recordNameArg, 'AAAA');
|
2017-07-18 13:45:06 +00:00
|
|
|
}
|
2017-01-26 23:11:13 +00:00
|
|
|
|
2017-07-18 13:45:06 +00:00
|
|
|
/**
|
|
|
|
* gets a txt record
|
|
|
|
*/
|
2020-02-15 16:41:37 +00:00
|
|
|
public async getRecordTxt(recordNameArg: string): Promise<plugins.tsclass.network.IDnsRecord[]> {
|
|
|
|
return await this.getRecord(recordNameArg, 'TXT');
|
|
|
|
}
|
|
|
|
|
|
|
|
public async getRecord(
|
|
|
|
recordNameArg: string,
|
|
|
|
recordTypeArg: plugins.tsclass.network.TDnsRecordType
|
|
|
|
): Promise<plugins.tsclass.network.IDnsRecord[]> {
|
|
|
|
const requestUrl = `https://dns.google/resolve?name=${recordNameArg}&type=${recordTypeArg}&do=1`;
|
|
|
|
const response = await plugins.smartrequest.request(requestUrl, {
|
|
|
|
method: 'GET'
|
|
|
|
});
|
|
|
|
const returnArray: plugins.tsclass.network.IDnsRecord[] = [];
|
|
|
|
const responseBody: IGoogleDNSHTTPSResponse = response.body;
|
|
|
|
for (const dnsEntry of responseBody.Answer) {
|
|
|
|
if (dnsEntry.data.startsWith('"') && dnsEntry.data.endsWith('"')) {
|
|
|
|
dnsEntry.data = dnsEntry.data.replace(/^"(.*)"$/, '$1');
|
2017-07-18 13:45:06 +00:00
|
|
|
}
|
2020-02-15 16:41:37 +00:00
|
|
|
if (dnsEntry.name.endsWith('.')) {
|
|
|
|
dnsEntry.name = dnsEntry.name.substring(0, dnsEntry.name.length - 1);
|
2017-07-18 13:45:06 +00:00
|
|
|
}
|
2020-02-15 16:41:37 +00:00
|
|
|
returnArray.push({
|
|
|
|
name: dnsEntry.name,
|
|
|
|
type: this.convertDnsTypeNumberToTypeName(dnsEntry.type),
|
|
|
|
dnsSecEnabled: responseBody.AD,
|
|
|
|
value: dnsEntry.data
|
|
|
|
});
|
|
|
|
}
|
|
|
|
// console.log(responseBody);
|
|
|
|
return returnArray;
|
2017-07-18 13:45:06 +00:00
|
|
|
}
|
2017-01-26 23:11:13 +00:00
|
|
|
|
2017-07-18 13:45:06 +00:00
|
|
|
/**
|
2020-02-15 16:41:37 +00:00
|
|
|
* gets a record using nodejs dns resolver
|
2017-07-18 13:45:06 +00:00
|
|
|
*/
|
2020-02-15 16:41:37 +00:00
|
|
|
public async getRecordWithNodeDNS(
|
|
|
|
recordNameArg: string,
|
|
|
|
recordTypeArg: plugins.tsclass.network.TDnsRecordType
|
|
|
|
): Promise<plugins.tsclass.network.IDnsRecord[]> {
|
|
|
|
const done = plugins.smartpromise.defer<plugins.tsclass.network.IDnsRecord[]>();
|
2017-07-18 13:45:06 +00:00
|
|
|
plugins.dns.resolve(recordNameArg, recordTypeArg, (err, recordsArg) => {
|
|
|
|
if (err) {
|
2018-05-13 13:51:04 +00:00
|
|
|
done.reject(err);
|
|
|
|
return;
|
2017-07-18 13:45:06 +00:00
|
|
|
}
|
2020-02-15 16:41:37 +00:00
|
|
|
const returnArray: plugins.tsclass.network.IDnsRecord[] = [];
|
|
|
|
for (const recordKey in recordsArg) {
|
|
|
|
returnArray.push({
|
2017-07-18 13:45:06 +00:00
|
|
|
name: recordNameArg,
|
|
|
|
value: recordsArg[recordKey],
|
2020-02-15 16:41:37 +00:00
|
|
|
type: recordTypeArg,
|
|
|
|
dnsSecEnabled: false
|
2018-05-13 13:51:04 +00:00
|
|
|
});
|
|
|
|
}
|
2020-02-15 16:41:37 +00:00
|
|
|
done.resolve(returnArray);
|
2018-05-13 13:51:04 +00:00
|
|
|
});
|
|
|
|
return done.promise;
|
|
|
|
}
|
|
|
|
|
2020-02-15 16:41:37 +00:00
|
|
|
public async getNameServer(domainNameArg: string): Promise<string[]> {
|
|
|
|
const done = plugins.smartpromise.defer<string[]>();
|
2018-05-13 13:51:04 +00:00
|
|
|
plugins.dns.resolveNs(domainNameArg, (err, result) => {
|
|
|
|
if (!err) {
|
|
|
|
done.resolve(result);
|
|
|
|
} else {
|
|
|
|
console.log(err);
|
|
|
|
done.reject(err);
|
2017-07-18 13:45:06 +00:00
|
|
|
}
|
2018-05-13 13:51:04 +00:00
|
|
|
});
|
2020-02-15 16:41:37 +00:00
|
|
|
return await done.promise;
|
2017-07-18 13:45:06 +00:00
|
|
|
}
|
2016-11-15 20:39:21 +00:00
|
|
|
|
2017-07-18 13:45:06 +00:00
|
|
|
/**
|
|
|
|
* set the DNS provider
|
|
|
|
*/
|
2020-02-15 16:41:37 +00:00
|
|
|
public setNodeDnsProvider(dnsProvider: TDnsProvider) {
|
|
|
|
console.log(
|
|
|
|
`Warning: Setting the nodejs dns authority to ${dnsProvider}. Only do this if you know what you are doing.`
|
|
|
|
);
|
2017-07-18 13:45:06 +00:00
|
|
|
if (dnsProvider === 'google') {
|
2018-05-13 13:51:04 +00:00
|
|
|
this.dnsServerIp = '8.8.8.8';
|
|
|
|
this.dnsServerPort = 53;
|
|
|
|
plugins.dns.setServers(['8.8.8.8', '8.8.4.4']);
|
2019-01-06 23:28:15 +00:00
|
|
|
} else if (dnsProvider === 'cloudflare') {
|
|
|
|
this.dnsServerIp = '1.1.1.1';
|
|
|
|
this.dnsServerPort = 53;
|
|
|
|
plugins.dns.setServers(['1.1.1.1', '1.0.0.1']);
|
2017-07-18 13:45:06 +00:00
|
|
|
} else {
|
2018-05-13 13:51:04 +00:00
|
|
|
throw new Error('unknown dns provider');
|
2016-11-15 20:39:21 +00:00
|
|
|
}
|
2017-07-18 13:45:06 +00:00
|
|
|
}
|
2020-02-15 16:41:37 +00:00
|
|
|
|
|
|
|
public convertDnsTypeNameToTypeNumber (dnsTypeNameArg: string): number {
|
|
|
|
return this.dnsTypeMap[dnsTypeNameArg];
|
|
|
|
}
|
|
|
|
|
|
|
|
public convertDnsTypeNumberToTypeName (dnsTypeNumberArg: number): plugins.tsclass.network.TDnsRecordType {
|
|
|
|
for (const key in this.dnsTypeMap) {
|
|
|
|
if (this.dnsTypeMap[key] === dnsTypeNumberArg) {
|
|
|
|
return key as plugins.tsclass.network.TDnsRecordType;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
return null
|
|
|
|
}
|
2017-01-26 23:11:13 +00:00
|
|
|
}
|