dns: add middleware property to root server to hijack queries
This commit is contained in:
parent
df16daf229
commit
55ee4679ea
2 changed files with 119 additions and 0 deletions
|
|
@ -109,6 +109,7 @@ class RootServer extends DNSServer {
|
|||
this.host = '127.0.0.1';
|
||||
this.port = 5300;
|
||||
this.lookup = null;
|
||||
this.middle = null;
|
||||
this.publicHost = '127.0.0.1';
|
||||
|
||||
// Plugins can add or remove items from
|
||||
|
|
@ -397,6 +398,27 @@ class RootServer extends DNSServer {
|
|||
const {name, type} = qs;
|
||||
const tld = util.from(name, -1);
|
||||
|
||||
// Plugins can insert middleware here and hijack the
|
||||
// lookup for special TLDs before checking Urkel tree.
|
||||
// We also pass the entire question in case a plugin
|
||||
// is able to return an authoritative (non-referral) answer.
|
||||
if (typeof this.middle === 'function') {
|
||||
let res;
|
||||
try {
|
||||
res = await this.middle(tld, req);
|
||||
} catch (e) {
|
||||
this.logger.warning(
|
||||
'Root server middleware resolution failed for name: %s',
|
||||
name
|
||||
);
|
||||
this.logger.debug(e.stack);
|
||||
}
|
||||
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
// Hit the cache first.
|
||||
const cache = this.cache.get(name, type);
|
||||
|
||||
|
|
@ -421,6 +443,11 @@ class RootServer extends DNSServer {
|
|||
return reserved.getByName(tld);
|
||||
}
|
||||
|
||||
// Intended to be called by plugin.
|
||||
signRRSet(rrset, type) {
|
||||
key.signZSK(rrset, type);
|
||||
}
|
||||
|
||||
resetCache() {
|
||||
this.cache.reset();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -175,3 +175,95 @@ describe('RootServer Blacklist', function() {
|
|||
assert.strictEqual(res.answer.length, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('RootServer Plugins', function() {
|
||||
const ns = new RootServer({
|
||||
port: 25349, // regtest
|
||||
lookup: (hash) => {
|
||||
// Normally an Urkel Tree goes here.
|
||||
// Blacklisted names should never get this far.
|
||||
if (hash.equals(rules.hashName('bit')))
|
||||
throw new Error('Blacklisted name!');
|
||||
|
||||
// For this test all other names have the same record
|
||||
const namestate = new NameState();
|
||||
namestate.data = Resource.fromJSON({
|
||||
records: [
|
||||
{
|
||||
type: 'NS',
|
||||
ns: 'ns1.handshake.'
|
||||
}
|
||||
]
|
||||
}).encode();
|
||||
return namestate.encode();
|
||||
}
|
||||
});
|
||||
|
||||
before(async () => {
|
||||
// Plugin inserts middleware before server is opened
|
||||
ns.middle = (tld, req) => {
|
||||
const [qs] = req.question;
|
||||
const name = qs.name.toLowerCase();
|
||||
const type = qs.type;
|
||||
|
||||
if (tld === 'bit.') {
|
||||
// This plugin runs an imaginary Namecoin full node.
|
||||
// It looks up records and returns an authoritative answer.
|
||||
// This makes it look like the complete record including
|
||||
// the subdomain is in the HNS root zone.
|
||||
const res = new wire.Message();
|
||||
res.aa = true;
|
||||
|
||||
// This plugin only returns A records,
|
||||
// and all Namecoin names have the same IP address.
|
||||
if (type !== wire.types.A)
|
||||
return null;
|
||||
|
||||
const rr = new wire.Record();
|
||||
const rd = new wire.ARecord();
|
||||
rr.name = name;
|
||||
rr.type = wire.types.A;
|
||||
rr.ttl = 518400;
|
||||
rr.data = rd;
|
||||
rd.address = '4.8.15.16';
|
||||
|
||||
res.answer.push(rr);
|
||||
ns.signRRSet(res.answer, wire.types.A);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Plugin doesn't care about this name
|
||||
return null;
|
||||
};
|
||||
|
||||
await ns.open();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await ns.close();
|
||||
});
|
||||
|
||||
it('should hijack lookup for blacklisted name', async () => {
|
||||
const name = 'decentralize.bit.';
|
||||
const req = {
|
||||
question: [{
|
||||
name,
|
||||
type: wire.types.A
|
||||
}]
|
||||
};
|
||||
|
||||
const res = await ns.resolve(req);
|
||||
assert.strictEqual(res.authority.length, 0);
|
||||
assert.strictEqual(res.answer.length, 2);
|
||||
|
||||
const rec = res.answer[0];
|
||||
assert.strictEqual(rec.name, name);
|
||||
assert.strictEqual(rec.type, wire.types.A);
|
||||
assert.strictEqual(rec.data.address, '4.8.15.16');
|
||||
|
||||
const sig = res.answer[1];
|
||||
assert.strictEqual(sig.name, name);
|
||||
assert.strictEqual(sig.type, wire.types.RRSIG);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue