doh-js-client
Version:
DNS-over-HTTPS/DNS-over-TLS client for nodejs.
104 lines (97 loc) • 2.67 kB
text/typescript
import * as tls from 'tls'
import * as fs from 'fs'
import * as Packet from 'native-dns-packet'
import * as Util from './util'
function DoT (provider: string, keyPath: string, certPath: string) {
Object.defineProperties(this, {
providers: {
value: {
google: 'dns.google',
cloudflare: '1.1.1.1',
cleanbrowsing: '185.228.169.154',
quad9: 'dns.quad9.net'
},
writable: false
},
key: {
writable: true
},
cert: {
writable: true
},
})
if (typeof this.providers[provider] === 'undefined') {
throw new Error('We only support these provider: google, cleanbrowsing, cloudflare')
}
const key = fs.readFileSync(keyPath)
const cert = fs.readFileSync(certPath)
this.provider = provider
this.uri = this.providers[this.provider]
this.key = key
this.cert = cert
}
DoT.prototype.getProviders = function () {
return Object.keys(this.providers)
}
DoT.prototype.setProvider = function (provider :string) {
if (this.provider === provider) {
return
}
if (typeof this.providers[provider] === 'undefined') {
throw new Error('We only support these provider: ' + this.getProviders().join(', '))
}
this.provider = provider
this.uri = this.providers[this.provider]
}
// TODO: refactor socket and provider, multiple query and keepalive connection
DoT.prototype.resolve = function (domainName: string, domainType: string) {
let type = Util.getDomainType(domainType)
let dnsPacket = new Packet()
let dnsBuf = Util.newBuffer(128)
let msgBuf = Util.newBuffer(130)
dnsPacket.question.push({
name: domainName,
type: type,
class: 1
})
Packet.write(dnsBuf, dnsPacket)
msgBuf[1] = 128
// copy dns buffer to message buffer
dnsBuf.copy(msgBuf, 2, 0)
const uri = this.uri
const key = this.key
const cert = this.cert
return new Promise(function (resolve, reject) {
const options = {
key: key,
cert: cert,
// ca: [],
checkServerIdentity: () => {
return null
},
}
const socket = tls.connect(853, uri, options, () => {
if (socket.authorized) {
socket.write(msgBuf)
} else {
reject(new Error('socket authorized'))
}
})
socket.on('data', (data) => {
let sign = data[0] & (1 << 7)
let totalLength = (data & 0xFF) << 8 | data[1] & 0xFF
if (sign) {
totalLength = 0xFFFF0000 | totalLength
}
let result = Packet.parse(data.slice(2))
resolve(result.answer)
})
socket.on('error', (err) => {
reject(err)
})
socket.on('end', () => {
// finish query
})
})
}
module.exports = DoT