smartdns/ts_server/classes.dnsserver.ts

121 lines
3.4 KiB
TypeScript
Raw Permalink Normal View History

import * as plugins from './plugins.js';
interface IDnsServerOptions {
httpsKey: string;
httpsCert: string;
httpsPort: number;
udpPort: number;
}
class DnsServer {
private udpServer: plugins.dgram.Socket;
private httpsServer: plugins.https.Server;
constructor(private options: IDnsServerOptions) {
this.udpServer = plugins.dgram.createSocket('udp4');
this.setupUdpServer();
this.httpsServer = plugins.https.createServer(
{
key: plugins.fs.readFileSync(options.httpsKey),
cert: plugins.fs.readFileSync(options.httpsCert)
},
this.handleHttpsRequest.bind(this)
);
}
private setupUdpServer(): void {
this.udpServer.on('message', (msg, rinfo) => {
const request = plugins.dnsPacket.decode(msg);
const response = {
type: 'response' as const,
id: request.id,
flags: plugins.dnsPacket.RECURSION_DESIRED | plugins.dnsPacket.RECURSION_AVAILABLE,
questions: request.questions,
answers: [] as plugins.dnsPacket.Answer[]
};
const question = request.questions[0];
console.log(`UDP query for ${question.name} of type ${question.type}`);
if (question.type === 'A') {
response.answers.push({
name: question.name,
type: 'A',
class: 'IN',
ttl: 300,
data: '127.0.0.1'
});
}
const responseData = plugins.dnsPacket.encode(response);
this.udpServer.send(responseData, rinfo.port, rinfo.address);
});
this.udpServer.on('error', (err) => {
console.error(`UDP Server error:\n${err.stack}`);
this.udpServer.close();
});
this.udpServer.bind(this.options.udpPort, '0.0.0.0', () => {
console.log(`UDP DNS server running on port ${this.options.udpPort}`);
});
}
private handleHttpsRequest(req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse): void {
if (req.method === 'POST' && req.url === '/dns-query') {
let body: Buffer[] = [];
req.on('data', chunk => {
body.push(chunk);
}).on('end', () => {
const msg = Buffer.concat(body);
const request = plugins.dnsPacket.decode(msg);
const response = {
type: 'response' as const,
id: request.id,
flags: plugins.dnsPacket.RECURSION_DESIRED | plugins.dnsPacket.RECURSION_AVAILABLE,
questions: request.questions,
answers: [] as plugins.dnsPacket.Answer[]
};
const question = request.questions[0];
console.log(`DoH query for ${question.name} of type ${question.type}`);
if (question.type === 'A') {
response.answers.push({
name: question.name,
type: 'A',
class: 'IN',
ttl: 300,
data: '127.0.0.1'
});
}
const responseData = plugins.dnsPacket.encode(response);
res.writeHead(200, { 'Content-Type': 'application/dns-message' });
res.end(responseData);
});
} else {
res.writeHead(404);
res.end();
}
}
public start(): void {
this.httpsServer.listen(this.options.httpsPort, () => {
console.log(`DoH server running on port ${this.options.httpsPort}`);
});
}
public stop(): void {
this.udpServer.close(() => {
console.log('UDP DNS server stopped');
});
this.httpsServer.close(() => {
console.log('HTTPS DNS server stopped');
});
}
}