feat(dnsserver): Return multiple matching records, improve DNSSEC RRset signing, add client resolution strategy and localhost handling, update tests
This commit is contained in:
@@ -15,6 +15,8 @@ export interface IDnsServerOptions {
|
||||
manualHttpsMode?: boolean;
|
||||
// Primary nameserver for SOA records (defaults to ns1.{dnssecZone})
|
||||
primaryNameserver?: string;
|
||||
// Local handling for RFC 6761 localhost (default: true)
|
||||
enableLocalhostHandling?: boolean;
|
||||
}
|
||||
|
||||
export interface DnsAnswer {
|
||||
@@ -569,6 +571,7 @@ export class DnsServer {
|
||||
console.log(`Query for ${question.name} of type ${question.type}`);
|
||||
|
||||
let answered = false;
|
||||
let shouldSignRrset = true; // skip DNSSEC signing for synthetic/local answers
|
||||
const recordsForQuestion: DnsAnswer[] = [];
|
||||
|
||||
// Handle DNSKEY queries if DNSSEC is requested
|
||||
@@ -582,9 +585,59 @@ export class DnsServer {
|
||||
};
|
||||
recordsForQuestion.push(dnskeyAnswer);
|
||||
answered = true;
|
||||
// DNSKEY is signable, keep shouldSignRrset true
|
||||
} else {
|
||||
// Built-in handling for localhost and reverse localhost (RFC 6761)
|
||||
const enableLocal = this.options.enableLocalhostHandling !== false;
|
||||
if (enableLocal) {
|
||||
const qnameLower = (question.name || '').toLowerCase();
|
||||
const qnameTrimmed = qnameLower.endsWith('.') ? qnameLower.slice(0, -1) : qnameLower;
|
||||
|
||||
// localhost forward lookups
|
||||
if (qnameTrimmed === 'localhost') {
|
||||
if (question.type === 'A') {
|
||||
recordsForQuestion.push({
|
||||
name: question.name,
|
||||
type: 'A',
|
||||
class: 'IN',
|
||||
ttl: 0,
|
||||
data: '127.0.0.1',
|
||||
});
|
||||
answered = true;
|
||||
shouldSignRrset = false;
|
||||
} else if (question.type === 'AAAA') {
|
||||
recordsForQuestion.push({
|
||||
name: question.name,
|
||||
type: 'AAAA',
|
||||
class: 'IN',
|
||||
ttl: 0,
|
||||
data: '::1',
|
||||
});
|
||||
answered = true;
|
||||
shouldSignRrset = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse lookup for 127.0.0.1
|
||||
if (!answered) {
|
||||
const reverseLocalhostV4 = '1.0.0.127.in-addr.arpa';
|
||||
if (qnameTrimmed === reverseLocalhostV4 && question.type === 'PTR') {
|
||||
recordsForQuestion.push({
|
||||
name: question.name,
|
||||
type: 'PTR',
|
||||
class: 'IN',
|
||||
ttl: 0,
|
||||
data: 'localhost.',
|
||||
});
|
||||
answered = true;
|
||||
shouldSignRrset = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all matching records from handlers
|
||||
for (const handlerEntry of this.handlers) {
|
||||
if (!answered) {
|
||||
for (const handlerEntry of this.handlers) {
|
||||
if (
|
||||
plugins.minimatch.minimatch(question.name, handlerEntry.domainPattern) &&
|
||||
handlerEntry.recordTypes.includes(question.type)
|
||||
@@ -602,6 +655,7 @@ export class DnsServer {
|
||||
// Continue processing other handlers to allow multiple records
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -612,7 +666,7 @@ export class DnsServer {
|
||||
}
|
||||
|
||||
// Group records by type for DNSSEC signing
|
||||
if (dnssecRequested) {
|
||||
if (dnssecRequested && shouldSignRrset) {
|
||||
const rrsetKey = `${question.name}:${question.type}`;
|
||||
rrsetMap.set(rrsetKey, recordsForQuestion);
|
||||
}
|
||||
@@ -1019,7 +1073,9 @@ export class DnsServer {
|
||||
}
|
||||
|
||||
private nameToBuffer(name: string): Buffer {
|
||||
const labels = name.split('.');
|
||||
// Trim trailing dot to avoid double-root
|
||||
const trimmed = name.endsWith('.') ? name.slice(0, -1) : name;
|
||||
const labels = trimmed.split('.').filter(l => l.length > 0);
|
||||
const buffers = labels.map(label => {
|
||||
const len = Buffer.byteLength(label, 'utf8');
|
||||
const buf = Buffer.alloc(1 + len);
|
||||
@@ -1027,6 +1083,7 @@ export class DnsServer {
|
||||
buf.write(label, 1);
|
||||
return buf;
|
||||
});
|
||||
return Buffer.concat([...buffers, Buffer.from([0])]); // Add root label
|
||||
// Append exactly one root label
|
||||
return Buffer.concat([...buffers, Buffer.from([0])]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user