more consistent naming, example db file, ANY matching

This commit is contained in:
AJ ONeal 2017-10-09 19:17:34 -06:00
parent 0303ffee30
commit 5d3a6d30d7
4 changed files with 164 additions and 36 deletions

121
README.md
View File

@ -37,13 +37,13 @@ Usage
----- -----
```bash ```bash
digd.js --input <path/to/file.json> digd.js --input <path/to/dns.json>
``` ```
**Example**: **Example**:
```bash ```bash
digd.js --input ./examples/example.com.json digd.js --input ./samples/db.json
``` ```
### Testing ### Testing
@ -64,7 +64,7 @@ Options
``` ```
--output <path/to/file> write query and response(s) to disk with this path prefix (ex: ./samples/dns) --output <path/to/file> write query and response(s) to disk with this path prefix (ex: ./samples/dns)
--input <path/to/file> input file to use for authoritative responses (ex: ./samples/zones.json) --input <path/to/file> input file to use for authoritative responses (ex: ./samples/db.json)
--mdns Use mDNS port (5353) and nameserver address (224.0.0.251) --mdns Use mDNS port (5353) and nameserver address (224.0.0.251)
@ -80,6 +80,121 @@ Options
--debug verbose output --debug verbose output
``` ```
JSON Database File
------------------
This DNS server is being created for use in the wild.
Although there will be a true database adapter later,
this JSON representation gives us an easy way to experiment with serving DNS and various record types.
There are 4 types of information in the file:
* Primary Nameservers `primaryNameservers`
* SOA Records `domains`
* devices
* All other records (A, AAAA, CAA, CNAME, MX, NS, PTR, SPF, SRV, TXT)
```js
module.exports = {
primaryNameservers: [ 'ns1.example.com', 'ns2.example.com' ]
// SOA records
, domains: [
// `primary` is chosen at random from `primaryNameservers` or `vanityNs`
// `serial` is generated from `updatedAt`
{ id: "publicsuffix.net", updatedAt: 1507594095118, ttl: 60
, admin: 'admin.publicsuffix.net', refresh: 1800, retry: 600
, expiration: 2419200, minimum: 5 }
, { id: "doe.publicsuffix.net", updatedAt: 1507594095118, ttl: 60
, admin: 'admin.doe.publicsuffix.net', refresh: 1800, retry: 600
, expiration: 2419200, minimum: 5 }
// default values will be used when left undefined
, { id: "doefam.net", updatedAt: 1507594095118
, vanityNs: [ 'ns1.awesome.com', 'ns2.awesome.com' ] }
]
, records: [
//
// Plain old boring A Records
//
{ name: "publicsuffix.net", zone: "publicsuffix.net"
, tld: "net", sld: "publicsuffix", sub: ""
, type: 'A', ttl: 300, address: '127.0.0.1' }
{ name: "www.publicsuffix.net", zone: "publicsuffix.net"
, tld: "net", sld: "publicsuffix", sub: "www"
, type: 'A', ttl: 300, address: '127.0.0.1' }
//
// Subdomain Delegation of a public suffix (treated as TLD)
//
{ name: "jane.doe.publicsuffix.net", zone: "doe.publicsuffix.net"
, tld: "publicsuffix.net", sld: "doe", sub: "john"
, type: 'NS', ttl: 300, data: 'ns1.other-dns.net'
}
//
// Example of all other record types
//
{ name: "john.doe.publicsuffix.net"
// The zone / SOA it belongs to (keep in mind that subdomains can be delegated to other users and/or nameservers)
, zone: "doe.publicsuffix.net"
// For indexing (note that we can treat delegated subdomains as if they were TLDs for delegation and resale)
, tld: "publicsuffix.net"
, sld: "doe"
, sub: "john"
, type: 'A' // for this example we specify a type even though we show all of the record data
, class: 'IN' // (default)
, ttl: 300
// A, AAAA
, address: '127.0.0.1'
// CAA
, flag: 0
, tag: 'issue'
, value: 'letsencrypt.org'
// CNAME, NS, PTR put 'name' here
// TXT puts an array here
, data: 'a.example.com'
// MX, SRV
, priority: 10
// MX
, exchange: 'mxa.example.org'
// SRV
, weight: 20
, port: 65065
, target: 'laptop1.devices.example.com'
}
]
};
```
The **Primary Nameservers** should be all of the nameservers that are in sync for these collections of records.
The **SOA** records represent that a domain or subdomain has be registered to or delegated to these nameservers.
The SOA records are separate from other record types because they are automatically generated as part of registering
a domain or updating its records.
The **other records** are in their own table for easy and fast lookup.
The **devices** are an abstraction that will be used in the future for ANAMEs and Dynamic DNS.
Note: Because it's possible to that delegated subdomains could have delegated subdomains that go right back to the
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.
Other Resources Other Resources
--------------- ---------------

View File

@ -21,3 +21,6 @@ Send malformed packets (both as queries and as answers):
- randomly twiddled bits - randomly twiddled bits
- forward compression pointers - forward compression pointers
- 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 A queries only return A records, not others matching the domain

View File

@ -12,13 +12,13 @@ var REFUSED = 5;
function getRecords(db, qname, cb) { function getRecords(db, qname, cb) {
var myRecords = db.records.filter(function (r) { var myRecords = db.records.filter(function (r) {
if ('string' !== typeof r.domain) { if ('string' !== typeof r.name) {
return false; return false;
} }
// TODO use IN in masterquest (or implement OR) // TODO use IN in masterquest (or implement OR)
// Only return single-level wildcard? // Only return single-level wildcard?
if (qname === r.domain || ('*.' + qname.split('.').slice(1).join('.')) === r.domain) { if (qname === r.name || ('*.' + qname.split('.').slice(1).join('.')) === r.name) {
return true; return true;
} }
}); });
@ -30,7 +30,7 @@ function getRecords(db, qname, cb) {
function dbToResourceRecord(r) { function dbToResourceRecord(r) {
return { return {
name: r.domain name: r.name
, typeName: r.type // NS , typeName: r.type // NS
, className: 'IN' , className: 'IN'
, ttl: r.ttl || 300 , ttl: r.ttl || 300
@ -50,7 +50,7 @@ function dbToResourceRecord(r) {
, address: -1 !== [ 'A', 'AAAA' ].indexOf(r.type) ? (r.address || r.value) : undefined , address: -1 !== [ 'A', 'AAAA' ].indexOf(r.type) ? (r.address || r.value) : undefined
// CNAME, NS, PTR || TXT // CNAME, NS, PTR || TXT
, data: -1 !== [ 'CNAME', 'NS', 'PTR', 'TXT' ].indexOf(r.type) ? (r.value || r.values) : undefined , data: -1 !== [ 'CNAME', 'NS', 'PTR', 'TXT' ].indexOf(r.type) ? (r.data || r.value || r.values) : undefined
// MX, SRV // MX, SRV
, priority: r.priority , priority: r.priority
@ -87,11 +87,11 @@ function getNs(db, ds, results, cb) {
} }
var ns = { var ns = {
name: r.domain name: r.name
, typeName: r.type // NS , typeName: r.type // NS
, className: 'IN' , className: r.class || 'IN'
, ttl: r.ttl || 300 , ttl: r.ttl || 300
, data: r.address || r.value || r.data , data: r.data || r.value || r.address
}; };
console.log('got NS record:'); console.log('got NS record:');
@ -225,6 +225,15 @@ module.exports.query = function (input, query, cb) {
return getRecords(db, qname, function (err, myRecords) { return getRecords(db, qname, function (err, myRecords) {
if (err) { cb(err); return; } if (err) { cb(err); return; }
if (255 !== query.question[0].type && 'ANY' !== query.question[0].typeName) {
myRecords = myRecords.filter(function (r) {
return ((r.type && r.type === query.question[0].type)
|| (r.type && r.type === query.question[0].typeName)
|| (r.typeName && r.typeName === query.question[0].typeName)
);
});
}
if (myRecords.length) { if (myRecords.length) {
myRecords.forEach(function (r) { myRecords.forEach(function (r) {
results.answer.push(dbToResourceRecord(r)); results.answer.push(dbToResourceRecord(r));

View File

@ -9,57 +9,58 @@ module.exports = {
] ]
, "records": [ , "records": [
// zone daplie.me should be able to have some records on its own // zone daplie.me should be able to have some records on its own
{ "zone": "daplie.me", "type": "A", "domain": "daplie.me" { "zone": "daplie.me", "name": "daplie.me", "tld": "me", "sld": "daplie", "sub": ""
, "tld": "me", "sld": "daplie", "sub": "", "value": "23.228.168.108", "aname": "tardigrade.devices.daplie.me" } , "type": "A", "address": "23.228.168.108", "aname": "tardigrade.devices.daplie.me" }
, { "zone": "daplie.me", "type": "A", "domain": "www.daplie.me" , { "zone": "daplie.me", "name": "www.daplie.me", "tld": "me", "sld": "daplie", "sub": "www"
, "tld": "me", "sld": "daplie", "sub": "www", "value": "23.228.168.108", "aname": "tardigrade.devices.daplie.me" } , "type": "A", "address": "23.228.168.108", "aname": "tardigrade.devices.daplie.me" }
, { "zone": "daplie.me", "type": "CNAME", "domain": "email.daplie.me" , { "zone": "daplie.me", "name": "email.daplie.me", "tld": "me", "sld": "daplie", "sub": "email"
, "tld": "me", "sld": "daplie", "sub": "email", "value": "mailgun.org" } , "type": "CNAME", "data": "mailgun.org" }
, { "zone": "daplie.me", "type": "ANAME", "domain": "tardigrade.devices.daplie.me", "device": "abcdef123" , { "zone": "daplie.me", "name": "tardigrade.devices.daplie.me", "tld": "me", "sld": "daplie", "sub": "tardigrade.devices"
, "tld": "me", "sld": "daplie", "sub": "tardigrade.devices", "value": "23.228.168.108" } , "device": "abcdef123"
, "type": "ANAME", "address": "23.228.168.108" }
// zone daplie.me can delegate oneal.daplie.me to the same nameserver // zone daplie.me can delegate oneal.daplie.me to the same nameserver
// (it's probably programmatically and politically simplest to always delegate from a parent zone) // (it's probably programmatically and politically simplest to always delegate from a parent zone)
// Thought Experiment: could we delegate the root to a child? i.e. daplie.me -> www.daplie.me // Thought Experiment: could we delegate the root to a child? i.e. daplie.me -> www.daplie.me
// to let someone exclusively "own" the root domain, but none of the children? // to let someone exclusively "own" the root domain, but none of the children?
, { "zone": "daplie.me", "type": "NS", "domain": "oneal.daplie.me" , { "zone": "daplie.me", "type": "NS", "name": "oneal.daplie.me"
, "tld": "me", "sld": "daplie", "sub": "oneal", "value": "ns1.redirect-www.org" } , "tld": "me", "sld": "daplie", "sub": "oneal", "data": "ns1.redirect-www.org" }
, { "zone": "daplie.me", "type": "NS", "domain": "oneal.daplie.me" , { "zone": "daplie.me", "name": "oneal.daplie.me", "tld": "me", "sld": "daplie", "sub": "oneal"
, "tld": "me", "sld": "daplie", "sub": "oneal", "value": "ns2.redirect-www.org" } , "type": "NS", "data": "ns2.redirect-www.org" }
// //
// now the zone "oneal.daplie.me" can be independently owned (and delegated) // now the zone "oneal.daplie.me" can be independently owned (and delegated)
// ... but what about email for aj@daplie.me with aj@daplie.me? // ... but what about email for aj@daplie.me with aj@daplie.me?
, { "zone": "oneal.daplie.me", "type": "A", "domain": "oneal.daplie.me" , { "zone": "oneal.daplie.me", "name": "oneal.daplie.me", "tld": "daplie.me", "sld": "oneal", "sub": ""
, "tld": "daplie.me", "sld": "oneal", "sub": "", "value": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" } , "type": "A", "address": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" }
, { "zone": "oneal.daplie.me", "type": "CNAME", "domain": "www.oneal.daplie.me" , { "zone": "oneal.daplie.me", "name": "www.oneal.daplie.me", "tld": "daplie.me", "sld": "oneal", "sub": "www"
, "tld": "daplie.me", "sld": "oneal", "sub": "www", "value": "oneal.daplie.me" } , "type": "CNAME", "data": "oneal.daplie.me" }
, { "zone": "oneal.daplie.me", "type": "NS", "domain": "aj.oneal.daplie.me" , { "zone": "oneal.daplie.me", "name": "aj.oneal.daplie.me", "tld": "daplie.me", "sld": "oneal", "sub": "aj"
, "tld": "daplie.me", "sld": "oneal", "sub": "aj", "value": "ns1.redirect-www.org" } , "type": "NS", "data": "ns1.redirect-www.org" }
, { "zone": "oneal.daplie.me", "type": "NS", "domain": "aj.oneal.daplie.me" , { "zone": "oneal.daplie.me", "name": "aj.oneal.daplie.me", "tld": "daplie.me", "sld": "oneal", "sub": "aj"
, "tld": "daplie.me", "sld": "oneal", "sub": "aj", "value": "ns2.redirect-www.org" } , "type": "NS", "data": "ns2.redirect-www.org" }
// there can be a wildcard, to which a delegation is the exception // there can be a wildcard, to which a delegation is the exception
, { "zone": "oneal.daplie.me", "type": "A", "domain": "*.oneal.daplie.me" , { "zone": "oneal.daplie.me", "name": "*.oneal.daplie.me", "tld": "daplie.me", "sld": "oneal", "sub": "*"
, "tld": "daplie.me", "sld": "oneal", "sub": "*", "value": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" } , "type": "A", "address": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" }
// there can be an exception to the delegation // there can be an exception to the delegation
, { "zone": "oneal.daplie.me", "type": "A", "domain": "exception.aj.oneal.daplie.me" , { "zone": "oneal.daplie.me", "name": "exception.aj.oneal.daplie.me", "tld": "daplie.me", "sld": "oneal", "sub": "exception.aj"
, "tld": "daplie.me", "sld": "oneal", "sub": "exception.aj", "value": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" } , "type": "A", "address": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" }
// //
// aj.oneal.daplie.me // aj.oneal.daplie.me
// //
, { "zone": "aj.oneal.daplie.me", "type": "A", "domain": "aj.oneal.daplie.me" , { "zone": "aj.oneal.daplie.me", "name": "aj.oneal.daplie.me", "tld": "oneal.daplie.me", "sld": "aj", "sub": ""
, "tld": "oneal.daplie.me", "sld": "aj", "sub": "", "value": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" } , "type": "A", "address": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" }
] ]
} }
; ;