add ANAME resolution

This commit is contained in:
AJ ONeal 2017-10-12 12:48:09 -06:00
parent d32dba2a75
commit a089bfc8e5
5 changed files with 78 additions and 4 deletions

View File

@ -155,6 +155,7 @@ module.exports = {
// A, AAAA // A, AAAA
, address: '127.0.0.1' , address: '127.0.0.1'
, aname: 'some-device.example.com' // See "A Note on ANAMEs" below
// CAA // CAA
, flag: 0 , flag: 0
@ -194,6 +195,14 @@ Note: Because it's possible to that delegated subdomains could have delegated su
original nameserver, **NS** records will be replaced with an SOA record if any of the NS records match any of original nameserver, **NS** records will be replaced with an SOA record if any of the NS records match any of
the server's primary nameservers or if vanity nameservers are used. the server's primary nameservers or if vanity nameservers are used.
### A Note on ANAMES
ANAMEs serve two purposes in this system:
1. Traditional ANAME. Just a CNAME that is automatically resolved to an A record for the "bare domain" problem, and efficiency.
2. Dynamic DNS. When a record on the system is updated, any records that match it by ANAME are also updated
TODO: use dns0x20 for ANAME resolutions
Other Resources Other Resources
--------------- ---------------

View File

@ -23,8 +23,16 @@ Send malformed packets (both as queries and as answers):
- compression pointers to wrong bits (throw error on non-ascii / unsafe chars) - compression pointers to wrong bits (throw error on non-ascii / unsafe chars)
Test that ANY queries return records of all types matching the domain Test that ANY queries return records of all types matching the domain
Test that A queries only return A records, not others matching the domain Test that A queries only return A records, not others matching the domain
Test that A queries for ANAME-enabled records (but no address) recurse (regardless of general recursion settings).
* 0-anames.example.com
* 1-aname.example.com
* 2-anames.example.com
Generally speaking test the cases of 0, 1, and 2 records of any given type (null case, single case, multi case)
``` ```
# Sample Data: # Sample Data:

View File

@ -367,6 +367,12 @@ cli.main(function (args, cli) {
// TODO get local answer first, if available // TODO get local answer first, if available
var path = require('path'); var path = require('path');
if (!cli.input) {
console.warn('[WARN] no db path given, must recurse if enabled');
recurse();
return;
}
require('../lib/dns-store').query(path.resolve(cli.input), query, function (err, resp) { require('../lib/dns-store').query(path.resolve(cli.input), query, function (err, resp) {
if (err) { console.log('[DEV] answer not found in local db, recursing'); console.error(err); recurse(); return; } if (err) { console.log('[DEV] answer not found in local db, recursing'); console.error(err); recurse(); return; }

View File

@ -11,7 +11,12 @@ var NXDOMAIN = 3;
var REFUSED = 5; var REFUSED = 5;
function getRecords(db, qname, cb) { function getRecords(db, qname, cb) {
var myRecords = db.records.filter(function (r) { var delMe = {};
var dns = require('dns');
// SECURITY XXX TODO var dig = require('dig.js/dns-request');
var count;
var myRecords = db.records.slice(0).filter(function (r) {
if ('string' !== typeof r.name) { if ('string' !== typeof r.name) {
return false; return false;
} }
@ -23,9 +28,52 @@ function getRecords(db, qname, cb) {
} }
}); });
process.nextTick(function () { function checkCount() {
cb(null, myRecords); count -= 1;
if (count <= 0) {
myRecords = myRecords.filter(function (r) {
return !delMe[r.id];
});
cb(null, myRecords);
}
}
function getRecord(r) {
// TODO allow multiple records to be returned(?)
return function (err, addresses) {
if (err || !addresses.length) {
r.id = r.id || Math.random();
delMe[r.id] = true;
} else if (addresses.length > 1) {
r._address = addresses[Math.floor(Math.random() * addresses.length)];
} else {
r._address = addresses[0];
}
checkCount();
};
}
count = myRecords.length;
myRecords.forEach(function (r) {
if (r.aname && !r.address) {
if ('A' === r.type) {
// SECURITY XXX TODO dig.resolveJson(query, opts);
dns.resolve4(r.aname, getRecord(r));
return;
}
if ('AAAA' === r.type) {
// SECURITY XXX TODO dig.resolveJson(query, opts);
dns.resolve6(r.aname, getRecord(r));
return;
}
}
checkCount();
}); });
if (!myRecords.length) {
checkCount();
}
} }
function dbToResourceRecord(r) { function dbToResourceRecord(r) {
@ -47,7 +95,7 @@ function dbToResourceRecord(r) {
*/ */
// A, AAAA // A, AAAA
, address: -1 !== [ 'A', 'AAAA' ].indexOf(r.type) ? (r.address || r.value) : undefined , address: -1 !== [ 'A', 'AAAA' ].indexOf(r.type) ? (r._address || r.address || r.value) : undefined
// CNAME, NS, PTR || TXT // CNAME, NS, PTR || TXT
, data: -1 !== [ 'CNAME', 'NS', 'PTR', 'TXT' ].indexOf(r.type) ? (r.data || r.value || r.values) : undefined , data: -1 !== [ 'CNAME', 'NS', 'PTR', 'TXT' ].indexOf(r.type) ? (r.data || r.value || r.values) : undefined

View File

@ -15,6 +15,9 @@ module.exports = {
, { "zone": "daplie.me", "name": "www.daplie.me", "tld": "me", "sld": "daplie", "sub": "www" , { "zone": "daplie.me", "name": "www.daplie.me", "tld": "me", "sld": "daplie", "sub": "www"
, "type": "A", "address": "23.228.168.108", "aname": "tardigrade.devices.daplie.me" } , "type": "A", "address": "23.228.168.108", "aname": "tardigrade.devices.daplie.me" }
, { "zone": "daplie.me", "name": "aname.daplie.me", "tld": "me", "sld": "daplie", "sub": "aname"
, "type": "A", "aname": "google.com" }
, { "zone": "daplie.me", "name": "email.daplie.me", "tld": "me", "sld": "daplie", "sub": "email" , { "zone": "daplie.me", "name": "email.daplie.me", "tld": "me", "sld": "daplie", "sub": "email"
, "type": "CNAME", "data": "mailgun.org" } , "type": "CNAME", "data": "mailgun.org" }