more consistent naming, example db file, ANY matching
This commit is contained in:
parent
0303ffee30
commit
5d3a6d30d7
121
README.md
121
README.md
|
@ -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
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
|
3
TESTS.md
3
TESTS.md
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
Loading…
Reference in New Issue