Skip to content

Instantly share code, notes, and snippets.

@wfjsw
Created October 29, 2017 14:34
Show Gist options
  • Save wfjsw/9f8682dda26522d22edcd7be2d89066e to your computer and use it in GitHub Desktop.
Save wfjsw/9f8682dda26522d22edcd7be2d89066e to your computer and use it in GitHub Desktop.
const rp = require('request-promise-native')
// const dns = require('dns2')
const dns = require('native-dns')
const {
port,
proxy
} = require('./config.json')
let edns_subset, server, server_t
server = dns.createServer()
server_t = dns.createTCPServer()
async function getMyIP() {
let resp = await rp({
url: 'http://ip.cn',
headers: {
'User-Agent': 'curl/7.52.1'
}
})
return resp.match(/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/)[0]
}
function cutToC(ip) {
let ips = ip.split('.')
ips[3] = '0/24'
return ips.join('.')
}
async function resolve(name, type) {
let resp = await rp({
url: 'https://dns.google.com/resolve',
proxy,
qs: {
name,
type,
edns_subset
},
json: true
})
return resp
}
function formatAnswer(ans) {
let answer = {
name: ans.name,
ttl: ans.TTL
}
switch (ans.type) {
case 1:
answer.address = ans.data
answer = dns.A(answer)
break
case 2:
answer.data = ans.data
answer = dns.NS(answer)
break
case 5:
answer.data = ans.data
answer = dns.CNAME(answer)
break
case 6:
[answer.primary, answer.admin, answer.port, answer.serial, answer.refresh, answer.retry, answer.expiration, answer.minimum] = ans.data.split(' ')
answer.serial = parseInt(answer.serial)
answer.refresh = parseInt(answer.refresh)
answer.retry = parseInt(answer.retry)
answer.expiration = parseInt(answer.expiration)
answer.minimum = parseInt(answer.minimum)
answer = dns.SOA(answer)
break
case 12:
answer.data = ans.data
answer = dns.PTR(answer)
break
case 15:
[answer.priority, answer.exchange] = ans.data.split(' ')
answer.priority = parseInt(answer.priority)
answer = dns.MX(answer)
break
case 16:
answer.data = [ans.data]
answer = dns.TXT(answer)
break
case 33:
[answer.priority, answer.weight, answer.port, answer.target] = ans.data.split(' ')
answer.priority = parseInt(answer.priority)
answer.weight = parseInt(answer.weight)
answer.port = parseInt(answer.port)
answer = dns.SRV(answer)
break
default:
answer = false
}
return answer
}
async function processDNSRequest(request, resp) {
try {
// let resp = new dns.Packet(request)
for (let question of request.question) {
console.log('> request %s', question.name);
try {
let res = await resolve(question.name, question.type)
if (res.Status == 0) {
resp.header.qr = 1
resp.header.tc = res.TC ? 1 : 0
resp.header.ra = res.RA ? 1 : 0
resp.header.rd = res.RD ? 1 : 0
resp.header.ad = res.AD ? 1 : 0
if (res.Answer) {
for (let ans of res.Answer) {
let answer = formatAnswer(ans)
if (!answer) continue
resp.answer.push(answer)
}
}
if (res.Authority) {
for (let ans of res.Authority) {
let answer = formatAnswer(ans)
if (!answer) continue
resp.authority.push(answer)
}
}
if (res.Additional) {
for (let ans of res.Additional) {
let answer = formatAnswer(ans)
if (!answer) continue
resp.additional.push(answer)
}
}
} else {
resp.header.rcode = res.Status
resp.header.qr = 1
resp.header.tc = res.TC ? 1 : 0
resp.header.ra = res.RA ? 1 : 0
resp.header.rd = res.RD ? 1 : 0
resp.header.ad = res.AD ? 1 : 0
}
} catch (e) {
console.error(e.stack)
resp.header.rcode = 2
resp.header.qr = 1
resp.header.tc = res.TC ? 1 : 0
resp.header.ra = res.RA ? 1 : 0
resp.header.rd = res.RD ? 1 : 0
resp.header.ad = res.AD ? 1 : 0
}
}
resp.send()
} catch (e) {
console.error(e.stack)
}
}
server.on('request', processDNSRequest)
server_t.on('request', processDNSRequest)
server.on('error', function (err, buff, req, res) {
console.log(err.stack)
})
async function init() {
let ip = await getMyIP()
console.log('Your IP: ', ip)
edns_subset = cutToC(ip)
console.log('Your EDNS Subset: ', edns_subset)
server.serve(port)
server_t.serve(port)
console.log('Google Public DNS listen on', port)
}
init()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment