Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 64 additions & 1 deletion lib/resolver/recursive.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ class RecursiveResolver extends DNSResolver {
return this.hints.getAuthority(this.inet6);
}

/**
* @param {wire.Question} qs
* @param {Authority} auth
* @returns {Promise<[wire.Message, boolean]>}
*/
async ask(qs, auth) {
const cache = this.cache.hit(qs, auth.zone);

Expand Down Expand Up @@ -354,6 +359,62 @@ class RecursiveResolver extends DNSResolver {
}
}

/**
* A single nameserver may host multiple zones.
* When an RRSIG does not match the current zone,
* we switch zones first before handling trust.
* @param {ResolveContext} rc
*/
async handleDifferentRRSIGZone(rc) {
if (!rc.res.isAnswer())
return;

const rrsigs = extractSet(rc.res.answer, '', types.RRSIG);
if (rrsigs.length === 0)
return;

const signerNames = new Set(rrsigs.map(rrsig => rrsig.data.signerName));
if (signerNames.has(rc.auth.zone))
return;

// There is a zone cut,
// this is the zone we switch to
const [signerName] = signerNames;

// Get the NS and DS for new zone
const [nsRes] = await this.ask(new Question(signerName, types.NS), rc.auth);
if (!nsRes.isAnswer()) {
this.log('Trust chain broken due to lack of NS record.');
return;
}
const [dsRes] = await this.ask(new Question(signerName, types.DS), rc.auth);
if (!dsRes.isAnswer()) {
this.log('Trust chain broken due to lack of DS record.');
return;
}

// Switch authority/zone
const auth = await this.pickAuthority(rc, nsRes.answer, nsRes.additional);
this.insert(rc);

if (!auth)
return;

this.log('Switching authority: %s', auth.name);
this.log('Switching zone: [%s->%s]', rc.auth.zone, auth.zone);

// Grab DS records for the _next_ zone.
rc.ds = extractSet(dsRes.answer, auth.zone, types.DS);

if (rc.ds.length === 0) {
rc.chain = false;
this.log('Trust chain broken due to zone change.');
}

rc.switchZone(auth);
rc.hop();
}

async handleTrust(rc) {
assert(rc.chain);

Expand Down Expand Up @@ -485,8 +546,10 @@ class RecursiveResolver extends DNSResolver {
async next(rc) {
await this.lookupNext(rc);

if (rc.chain)
if (rc.chain) {
await this.handleDifferentRRSIGZone(rc);
await this.handleTrust(rc);
}

if (rc.chain && rc.res.code === codes.NXDOMAIN) {
const nsec = extractSet(rc.res.authority, '', types.NSEC3);
Expand Down