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 ;
2020-02-15 16:46:04 +00:00
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 ;
2020-02-15 16:46:04 +00:00
public dnsTypeMap : { [ key : string ] : number } = {
2020-02-15 16:41:37 +00:00
A : 1 ,
AAAA : 28 ,
CNAME : 5 ,
MX : 15 ,
2020-02-15 16:46:04 +00:00
TXT : 16
} ;
2020-02-15 16:41:37 +00:00
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-19 21:38:42 +00:00
const myRecordArray = await this . getRecordWithNodeDNS ( recordNameArg , recordTypeArg ) ;
2020-02-15 16:41:37 +00:00
const myRecord = myRecordArray [ 0 ] . value ;
2017-07-18 13:45:06 +00:00
if ( myRecord === expectedValue ) {
2020-02-19 21:38:42 +00:00
console . log ( ` smartdns: .checkUntilAvailable() verified that wanted >>> ${ recordTypeArg } <<< record exists for >>> ${ recordNameArg } <<< with value >>> ${ 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 {
2020-02-19 21:38:42 +00:00
console . log (
` smartdns: .checkUntilAvailable() failed permanently for ${ recordNameArg } with value ${ recordTypeArg } - ${ expectedValue } ... `
) ;
2018-05-13 13:51:04 +00:00
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'
} ) ;
2020-02-15 16:46:04 +00:00
const returnArray : plugins.tsclass.network.IDnsRecord [ ] = [ ] ;
2020-02-15 16:41:37 +00:00
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 [ ] > {
2020-02-19 21:38:42 +00:00
this . setNodeDnsProvider ( 'cloudflare' ) ;
2020-02-15 16:41:37 +00:00
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 ,
2020-02-19 21:38:42 +00:00
value : recordsArg [ recordKey ] [ 0 ] ,
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 ) {
2020-02-19 21:38:42 +00:00
if ( ! this . dnsServerIp ) {
console . log (
` Warning: Setting the nodejs dns authority to ${ dnsProvider } . Only do this if you know what you are doing. `
) ;
}
if ( dnsProvider === 'google' && this . dnsServerIp !== '8.8.8.8' ) {
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' ] ) ;
2020-02-19 21:38:42 +00:00
} else if ( dnsProvider === 'cloudflare' && this . dnsServerIp !== '1.1.1.1' ) {
2019-01-06 23:28:15 +00:00
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
2020-02-15 16:46:04 +00:00
public convertDnsTypeNameToTypeNumber ( dnsTypeNameArg : string ) : number {
2020-02-15 16:41:37 +00:00
return this . dnsTypeMap [ dnsTypeNameArg ] ;
}
2020-02-15 16:46:04 +00:00
public convertDnsTypeNumberToTypeName (
dnsTypeNumberArg : number
) : plugins . tsclass . network . TDnsRecordType {
2020-02-15 16:41:37 +00:00
for ( const key in this . dnsTypeMap ) {
if ( this . dnsTypeMap [ key ] === dnsTypeNumberArg ) {
return key as plugins . tsclass . network . TDnsRecordType ;
}
2020-02-15 16:46:04 +00:00
}
return null ;
2020-02-15 16:41:37 +00:00
}
2017-01-26 23:11:13 +00:00
}