The issue I am facing:
When i query for a ns then an a record i get nodata.
My setup is like this:
dnsmim > pihole > unbound > stubby > nextdns
When i do the same using pihole port everything works.
But when i use the dnsmim's port the error happens.
(dnsmim is there to modify blocked requests ip from 0.0.0.0 to x.x.x.x)
(i know pihole has the same ability and i am using it, sadly nextdns doesn't have it)
Here is my code, i have no idea what could be the problem:
const dnsPacket = require('dns-packet');
const dgram = require('dgram');
const net = require('net');
const { RateLimiterMemory } = require('rate-limiter-flexible');
const qmodule = require('q');
const upstreamDNSServer = '127.0.0.1';
const upstreamDNSPort = 5053;
const listenPort = 53;
const listenIp = '0.0.0.0'
const modifiedIP = 'xxx.xxx.xxx.xxx';
const debug = false //Should we send logs to console?
const basicdebug = true //Send basic logs to console?
const onlyLocal = false; //Only log local request. (localhost)
const generalRateLimiter = new RateLimiterMemory({
points: 600, // Number of requests allowed within the duration
duration: 60, // Duration in seconds
});
const localRateLimiter = new RateLimiterMemory({
points: 2000, // Number of requests allowed within the duration
duration: 60, // Duration in seconds
});
const outputRateLimiter = new RateLimiterMemory({
points: 5000, // Number of requests allowed within the duration
duration: 60, // Duration in seconds
});
// UDP DNS server
const udpServer = dgram.createSocket('udp4');
udpServer.on('message', async (message, rinfo) => {
if (debug || basicdebug) {
if (!onlyLocal) {
console.log('Received UDP DNS query from:', rinfo.address);
} else if (onlyLocal) {
if (rinfo.address=="127.0.0.1") {
console.log('Received UDP DNS query from:', rinfo.address);
}
}
}
let clientIp;
await getClientIp(rinfo.address, null).then(clientIpFunction => {
clientIp = clientIpFunction
})
try {
await outputRateLimiter.consume(1);
if (clientIp=="127.0.0.1") {
await localRateLimiter.consume(clientIp); // Apply rate limiting
if (debug || basicdebug) console.log("Using local rate-limit.")
} else {
await generalRateLimiter.consume(clientIp); // Apply rate limiting
}
const query = dnsPacket.decode(message);
if (debug) {
if (!onlyLocal) {
console.log('Received DNS query:', query);
} else if (onlyLocal) {
if (clientIp=="127.0.0.1") {
console.log('Received DNS query:', query);
}
}
}
const question = query.questions[0];
if (debug) {
if (!onlyLocal) {
console.log('DNS question:', question);
} else if (onlyLocal) {
if (clientIp=="127.0.0.1") {
console.log('DNS question:', question);
}
}
}
const upstreamDNSMessage = {
type: 'query',
id: query.id,
questions: [question],
};
const upstreamDNSRequest = dgram.createSocket('udp4');
upstreamDNSRequest.on('error', (err) => {
console.error('Error in upstream DNS request:', err);
upstreamDNSRequest.close();
});
upstreamDNSRequest.send(
dnsPacket.encode(upstreamDNSMessage),
upstreamDNSPort,
upstreamDNSServer,
(err) => {
if (err) {
console.error('Error sending DNS request:', err);
upstreamDNSRequest.close();
return;
}
if (debug || basicdebug) {
if (!onlyLocal) {
console.log('Sent DNS request to upstream DNS server:', upstreamDNSServer, upstreamDNSPort);
} else if (onlyLocal) {
if (clientIp=="127.0.0.1") {
console.log('Sent DNS request to upstream DNS server:', upstreamDNSServer, upstreamDNSPort);
}
}
}
}
);
upstreamDNSRequest.on('message', (upstreamDNSResponse) => {
if (debug || basicdebug) {
if (!onlyLocal) {
console.log('Received DNS response from upstream DNS server:', upstreamDNSServer, upstreamDNSPort);
} else if (onlyLocal) {
if (clientIp=="127.0.0.1") {
console.log('Received DNS response from upstream DNS server:', upstreamDNSServer, upstreamDNSPort);
}
}
}
const response = dnsPacket.decode(upstreamDNSResponse);
if (debug) {
if (!onlyLocal) {
console.log('Upstream DNS response:', response);
} else if (onlyLocal) {
if (clientIp=="127.0.0.1") {
console.log('Upstream DNS response:', response);
}
}
}
if (response.answers.length > 0) {
const answer = response.answers[0];
if (answer.data === '0.0.0.0' || answer.data === '127.0.0.1') {
// Modify the response IP address
answer.data = modifiedIP;
if (debug || basicdebug) {
if (!onlyLocal) {
console.log('Modified DNS response:', answer);
} else if (onlyLocal) {
if (clientIp=="127.0.0.1") {
console.log('Modified DNS response:', answer);
}
}
}
}
}
const modifiedResponse = dnsPacket.encode(response);
udpServer.send(modifiedResponse, rinfo.port, rinfo.address, (err) => {
if (err) {
console.error('Error sending DNS response:', err);
}
if (debug || basicdebug) {
if (!onlyLocal) {
console.log('Sent DNS response to the client:', rinfo.address, rinfo.port);
} else if (onlyLocal) {
if (clientIp=="127.0.0.1") {
console.log('Sent DNS response to the client:', rinfo.address, rinfo.port);
}
}
}
});
upstreamDNSRequest.close();
});
upstreamDNSRequest.on('error', (err) => {
console.error('Error in upstream DNS request:', err);
upstreamDNSRequest.close();
});
} catch (error) {
console.error('Rate limit exceeded for UDP request:', error);
udpServer.send('Rate limit exceeded', rinfo.port, rinfo.address);
}
});
udpServer.on('error', (err) => {
console.error('UDP server error:', err);
udpServer.close();
});
udpServer.bind(listenPort, listenIp, () => {
/*if (debug || basicdebug)*/ console.log(`UDP server listening on ${listenIp}:${listenPort}`);
const Monitor = require('ping-monitor');
const myMonitor2 = new Monitor({
website: 'https://uptime.betterstack.com/api/v1/heartbeat/gbk2vg4RKVkeUxYjWkfCV7F4',
title: 'Raging Flame2',
interval: 10 // minutes
});
myMonitor2.on('up', function (res, state) {
console.log('Yay!! ' + res.website + ' is up.'); //console.log('Yay!! ' + state.address + ' is up.');
});
myMonitor2.on('down', function (res, state) {
console.log('Oh Snap!! ' + res.website + ' is down! ' + res.statusMessage); //console.log('Oh Snap!! ' + state.address + ' is down! ' + state.statusMessage);
});
myMonitor2.on('stop', function (res, state) {
console.log(website + ' monitor has stopped.'); //console.log(state.address + ' monitor has stopped.');
});
myMonitor2.on('error', function (error) {
console.log(error);
});
});
// Helper function to parse headers from the DNS message
function parseHeaders(message) {
const headers = {};
const lines = message.split('\n');
for (const line of lines) {
const [key, value] = line.split(':');
if (key && value) {
headers[key.toLowerCase().trim()] = value.trim();
}
}
return headers;
}
// TCP DNS server
const tcpServer = net.createServer((socket) => {
if (debug || basicdebug) console.log('TCP DNS query received from:', socket.remoteAddress);
socket.on('data', async (data) => {
if (debug) console.log('Received TCP DNS query:', data.toString('hex'));
let clientIp;
await getClientIp(socket.remoteAddress, null).then(clientIpFunction => {
clientIp = clientIpFunction
})
try {
await outputRateLimiter.consume(1);
if (clientIp=="127.0.0.1") {
await localRateLimiter.consume(clientIp); // Apply rate limiting
if (debug || basicdebug) console.log("Using local rate-limit.")
} else {
await generalRateLimiter.consume(clientIp); // Apply rate limiting
}
try {
const query = dnsPacket.streamDecode(data, 'tcp');
if (debug) console.log('Received DNS query:', query);
const question = query.questions[0];
if (debug) console.log('DNS question:', question);
const upstreamDNSMessage = {
type: 'query',
id: query.id,
questions: [question],
};
const upstreamDNSRequest = dgram.createSocket('udp4');
upstreamDNSRequest.on('error', (err) => {
console.error('Error in upstream DNS request:', err);
upstreamDNSRequest.close();
socket.end();
});
upstreamDNSRequest.send(
dnsPacket.encode(upstreamDNSMessage),
upstreamDNSPort,
upstreamDNSServer,
(err) => {
if (err) {
console.error('Error sending DNS request:', err);
upstreamDNSRequest.close();
socket.end();
return;
}
if (debug || basicdebug) console.log('Sent DNS request to upstream DNS server:', upstreamDNSServer, upstreamDNSPort);
}
);
upstreamDNSRequest.on('message', (upstreamDNSResponse) => {
if (debug || basicdebug) console.log('Received DNS response from upstream DNS server:', upstreamDNSServer, upstreamDNSPort);
const response = dnsPacket.decode(upstreamDNSResponse);
if (debug) console.log('Upstream DNS response:', response);
if (response.answers.length > 0) {
const answer = response.answers[0];
if (answer.data === '0.0.0.0' || answer.data === '127.0.0.1') {
// Modify the response IP address
answer.data = modifiedIP;
if (debug || basicdebug) console.log('Modified DNS response:', answer);
}
}
const modifiedResponse = dnsPacket.streamEncode(response);
socket.write(modifiedResponse, (err) => {
if (err) {
console.error('Error sending DNS response:', err);
}
if (debug || basicdebug) console.log('Sent DNS response to the client:', socket.remoteAddress);
socket.end();
});
upstreamDNSRequest.close();
});
upstreamDNSRequest.on('error', (err) => {
console.error('Error in upstream DNS request:', err);
upstreamDNSRequest.close();
socket.end();
});
} catch (error) {
console.error('Error decoding DNS query:', error);
}
} catch (error) {
console.error('Rate limit exceeded for TCP request:', error);
socket.write('Rate limit exceeded');
socket.end();
}
});
socket.on('error', (err) => {
console.error('TCP socket error:', err);
socket.destroy();
});
socket.on('timeout', () => {
console.error('TCP socket request timed out');
socket.destroy();
});
});
tcpServer.on('error', (err) => {
console.error('TCP server error:', err);
tcpServer.close();
});
tcpServer.listen(listenPort, listenIp, () => {
/*if (debug || basicdebug)*/ console.log(`TCP server listening on ${listenIp}:${listenPort}`);
});
function getClientIp(address51, message) {
if (debug) console.log("ip detect begin")
const deferred = qmodule.defer();
if (address51 === '127.0.0.1') {
// Step 2: Check for X-Forwarded-For header
let xForwardedFor = null
if (message) {
const headers = parseHeaders(message.toString());
if (debug) if (headers[0]) console.log(headers)
xForwardedFor = headers['x-forwarded-for'];
} else if (!message) {
xForwardedFor = null
}
if (xForwardedFor) {
clientIp = xForwardedFor;
if (debug) console.log("Forwarded request", clientIp)
deferred.resolve(clientIp)
} else {
clientIp = address51;
if (debug) console.log("Non-forwarded request", clientIp)
deferred.resolve(clientIp)
}
} else {
clientIp = address51;
if (debug) console.log("Forward not allowed", clientIp)
deferred.resolve(clientIp)
}
return deferred.promise;
}