-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathindex.js
More file actions
115 lines (105 loc) · 2.96 KB
/
Copy pathindex.js
File metadata and controls
115 lines (105 loc) · 2.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// The regular expression keyword in domain name.
const domain = /hursing/
// When keyword matched, resolve to this IP.
const targetIp = '127.0.0.1'
// When keyword not matched, use the fallback dns server to resolve.
const fallbackServer = '10.0.0.1'
const dgram = require('dgram')
const server = dgram.createSocket('udp4')
function copyBuffer(src, offset, dst) {
for (let i = 0; i < src.length; ++i) {
dst.writeUInt8(src.readUInt8(i), offset + i)
}
}
function resolve(msg, rinfo) {
const queryInfo = msg.slice(12)
const response = Buffer.alloc(28 + queryInfo.length)
let offset = 0
const id = msg.slice(0, 2)
copyBuffer(id, 0, response) // Transaction ID
offset += id.length
response.writeUInt16BE(0x8180, offset) // Flags
offset += 2
response.writeUInt16BE(1, offset) // Questions
offset += 2
response.writeUInt16BE(1, offset) // Answer RRs
offset += 2
response.writeUInt32BE(0, offset) // Authority RRs & Additional RRs
offset += 4
copyBuffer(queryInfo, offset, response)
offset += queryInfo.length
response.writeUInt16BE(0xC00C, offset) // offset to domain name
offset += 2
const typeAndClass = msg.slice(msg.length - 4)
copyBuffer(typeAndClass, offset, response)
offset += typeAndClass.length
response.writeUInt32BE(600, offset) // TTL, in seconds
offset += 4
response.writeUInt16BE(4, offset) // Length of IP
offset += 2
targetIp.split('.').forEach(value => {
response.writeUInt8(parseInt(value), offset)
offset += 1
})
// console.log(response.toString('hex'))
server.send(response, rinfo.port, rinfo.address, (err) => {
if (err) {
console.log(err)
server.close()
}
})
}
function forward(msg, rinfo) {
const client = dgram.createSocket('udp4')
client.on('error', (err) => {
console.log(`client error:\n${err.stack}`)
client.close()
})
client.on('message', (fbMsg, fbRinfo) => {
server.send(fbMsg, rinfo.port, rinfo.address, (err) => {
err && console.log(err)
})
client.close()
})
client.send(msg, 53, fallbackServer, (err) => {
if (err) {
console.log(err)
client.close()
}
})
}
function parseHost(msg) {
let num = msg.readUInt8(0)
let offset = 1
let host = ""
while (num !== 0) {
host += msg.slice(offset, offset + num).toString()
offset += num
num = msg.readUInt8(offset)
offset += 1
if (num !== 0) {
host += '.'
}
}
return host
}
server.on('message', (msg, rinfo) => {
// console.log(msg.toString('hex'))
const host = parseHost(msg.slice(12))
console.log(`receive query: ${host}`)
if (domain.test(host)) {
resolve(msg, rinfo)
} else {
forward(msg, rinfo)
}
})
server.on('error', (err) => {
console.log(`server error:\n${err.stack}`)
server.close()
})
server.on('listening', () => {
const address = server.address()
console.log(`server listening ${address.address}:${address.port}`)
})
// On linux or Mac, run node with sudo. Because port 53 is lower then 1024.
server.bind(53)