-
Notifications
You must be signed in to change notification settings - Fork 0
/
dnsProxy.js
106 lines (89 loc) · 3 KB
/
dnsProxy.js
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
/*
* A custom dns proxy implementation
* doesn't support custom dns records
* made to stop ads (inspired from pi-hole)
*
*/
const dgram = require('node:dgram');
const { dnsQuestion } = require('./lib/dnsQuestion.js');
const { dnsForward } = require('./lib/dnsForward.js');
const { blackList } = require('./lib/blacklist.js');
const { createClient } = require('redis');
const { metricServer } = require('./services/metricService.js');
const { Signale } = require('signale');
const signaleOptions = {
types: {
success: {
badge: '++',
label: 'Accepted'
},
error: {
badge: '--',
label: 'Blocked'
}
}
};
const logger = new Signale(signaleOptions);
class dnsProxy {
constructor(ip, port, blacklist, fwdServer, fwdPort, metricServerPort) {
this.ip = ip;
this.port = port;
this.socket = new dgram.createSocket('udp4');
this.forwarder = new dnsForward(fwdServer, fwdPort);
this.mServer = new metricServer(metricServerPort || 8080);
this.blacklist = new blackList();
this.blacklist.ropen(blacklist || 'blacklist.txt');
this.client = createClient({
url: process.env.YES_ITS_NODE_DOCKER ?'redis://dnsproxy-redis' : 'redis://localhost'
});
this.client.connect();
}
send(data, rinfo) {
this.socket.send(data, 0, data.length, rinfo.port, rinfo.address);
}
async getResponse(req, rinfo) {
const question = dnsQuestion.getQuestionFromBuffer(req, 12);
const isIn = await this.blacklist.rcontain(question.QNAME);
const log = `${question.QNAME} from ${rinfo.address}:${rinfo.port}`;
if ( isIn ) {
logger.error(log);
this.client.ZINCRBY("blacklist", 1, question.QNAME);
return req;
}
logger.success(log);
const {val, isCached} = await this.isCached(question.QNAME);
if (isCached) {
return val
}
const res = await this.forwarder.forward(req);
this.cache(question.QNAME, res);
return res;
}
cache(qname, resp) {
this.client.set(qname, JSON.stringify(resp));
this.client.expire(qname, 120); //Live for 120 sec (2 min)
}
async isCached(qname) {
const a = await this.client.get(qname);
if (a) {
const res = new Buffer.from(JSON.parse(a));
return (res, true);
}
return (null, false);
}
start() {
this.socket.on('message', (msg, rinfo) => {
this.getResponse(msg, rinfo)
.then(res => {
this.send(res, rinfo);})
.catch(err => {
console.log(err);
this.send(req, rinfo);
});//Again just send it back
});
this.socket.bind(this.port, this.ip);
logger.info(`dnsProxy is listening on ${this.ip}:${this.port}`);
this.mServer.listen();
}
}
module.exports = { dnsProxy }