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 | ||||
| digd.js --input <path/to/file.json> | ||||
| digd.js --input <path/to/dns.json> | ||||
| ``` | ||||
| 
 | ||||
| **Example**: | ||||
| 
 | ||||
| ```bash | ||||
| digd.js --input ./examples/example.com.json | ||||
| digd.js --input ./samples/db.json | ||||
| ``` | ||||
| 
 | ||||
| ### Testing | ||||
| @ -64,7 +64,7 @@ Options | ||||
| 
 | ||||
| ``` | ||||
| --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) | ||||
| 
 | ||||
| @ -80,6 +80,121 @@ Options | ||||
| --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 | ||||
| --------------- | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										3
									
								
								TESTS.md
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								TESTS.md
									
									
									
									
									
								
							| @ -21,3 +21,6 @@ Send malformed packets (both as queries and as answers): | ||||
|   - randomly twiddled bits | ||||
|   - forward compression pointers | ||||
|   - 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) { | ||||
|   var myRecords = db.records.filter(function (r) { | ||||
|     if ('string' !== typeof r.domain) { | ||||
|     if ('string' !== typeof r.name) { | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|     // TODO use IN in masterquest (or implement OR)
 | ||||
|     // 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; | ||||
|     } | ||||
|   }); | ||||
| @ -30,7 +30,7 @@ function getRecords(db, qname, cb) { | ||||
| 
 | ||||
| function dbToResourceRecord(r) { | ||||
|   return { | ||||
|     name: r.domain | ||||
|     name: r.name | ||||
|   , typeName: r.type // NS
 | ||||
|   , className: 'IN' | ||||
|   , ttl: r.ttl || 300 | ||||
| @ -50,7 +50,7 @@ function dbToResourceRecord(r) { | ||||
|   , address: -1 !== [ 'A', 'AAAA' ].indexOf(r.type) ? (r.address || r.value) : undefined | ||||
| 
 | ||||
|     // 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
 | ||||
|   , priority: r.priority | ||||
| @ -87,11 +87,11 @@ function getNs(db, ds, results, cb) { | ||||
|       } | ||||
| 
 | ||||
|       var ns = { | ||||
|         name: r.domain | ||||
|         name: r.name | ||||
|       , typeName: r.type // NS
 | ||||
|       , className: 'IN' | ||||
|       , className: r.class || 'IN' | ||||
|       , ttl: r.ttl || 300 | ||||
|       , data: r.address || r.value || r.data | ||||
|       , data: r.data || r.value || r.address | ||||
|       }; | ||||
| 
 | ||||
|       console.log('got NS record:'); | ||||
| @ -225,6 +225,15 @@ module.exports.query = function (input, query, cb) { | ||||
|   return getRecords(db, qname, function (err, myRecords) { | ||||
|     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) { | ||||
|       myRecords.forEach(function (r) { | ||||
|         results.answer.push(dbToResourceRecord(r)); | ||||
|  | ||||
| @ -9,57 +9,58 @@ module.exports = { | ||||
|   ] | ||||
| , "records": [ | ||||
|     // zone daplie.me should be able to have some records on its own
 | ||||
|     { "zone": "daplie.me", "type": "A", "domain": "daplie.me" | ||||
|     , "tld": "me", "sld": "daplie", "sub": "", "value": "23.228.168.108", "aname": "tardigrade.devices.daplie.me" } | ||||
|     { "zone": "daplie.me", "name": "daplie.me", "tld": "me", "sld": "daplie", "sub": "" | ||||
|     , "type": "A", "address": "23.228.168.108", "aname": "tardigrade.devices.daplie.me" } | ||||
| 
 | ||||
|   , { "zone": "daplie.me", "type": "A", "domain": "www.daplie.me" | ||||
|     , "tld": "me", "sld": "daplie", "sub": "www", "value": "23.228.168.108", "aname": "tardigrade.devices.daplie.me" } | ||||
|   , { "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" } | ||||
| 
 | ||||
|   , { "zone": "daplie.me", "type": "CNAME", "domain": "email.daplie.me" | ||||
|     , "tld": "me", "sld": "daplie", "sub": "email", "value": "mailgun.org" } | ||||
|   , { "zone": "daplie.me", "name": "email.daplie.me", "tld": "me", "sld": "daplie", "sub": "email" | ||||
|     , "type": "CNAME", "data": "mailgun.org" } | ||||
| 
 | ||||
|   , { "zone": "daplie.me", "type": "ANAME", "domain": "tardigrade.devices.daplie.me", "device": "abcdef123" | ||||
|     , "tld": "me", "sld": "daplie", "sub": "tardigrade.devices", "value": "23.228.168.108" } | ||||
|   , { "zone": "daplie.me", "name": "tardigrade.devices.daplie.me", "tld": "me", "sld": "daplie", "sub": "tardigrade.devices" | ||||
|     , "device": "abcdef123" | ||||
|     , "type": "ANAME", "address": "23.228.168.108" } | ||||
| 
 | ||||
|     // 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)
 | ||||
|     // 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?
 | ||||
|   , { "zone": "daplie.me", "type": "NS", "domain": "oneal.daplie.me" | ||||
|     , "tld": "me", "sld": "daplie", "sub": "oneal", "value": "ns1.redirect-www.org" } | ||||
|   , { "zone": "daplie.me", "type": "NS", "name": "oneal.daplie.me" | ||||
|     , "tld": "me", "sld": "daplie", "sub": "oneal", "data": "ns1.redirect-www.org" } | ||||
| 
 | ||||
|   , { "zone": "daplie.me", "type": "NS", "domain": "oneal.daplie.me" | ||||
|     , "tld": "me", "sld": "daplie", "sub": "oneal", "value": "ns2.redirect-www.org" } | ||||
|   , { "zone": "daplie.me", "name": "oneal.daplie.me", "tld": "me", "sld": "daplie", "sub": "oneal" | ||||
|     , "type": "NS", "data": "ns2.redirect-www.org" } | ||||
| 
 | ||||
|     //
 | ||||
|     // now the zone "oneal.daplie.me" can be independently owned (and delegated)
 | ||||
|     // ... but what about email for aj@daplie.me with aj@daplie.me?
 | ||||
|   , { "zone": "oneal.daplie.me", "type": "A", "domain": "oneal.daplie.me" | ||||
|     , "tld": "daplie.me", "sld": "oneal", "sub": "", "value": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" } | ||||
|   , { "zone": "oneal.daplie.me", "name": "oneal.daplie.me", "tld": "daplie.me", "sld": "oneal", "sub": "" | ||||
|     , "type": "A", "address": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" } | ||||
| 
 | ||||
|   , { "zone": "oneal.daplie.me", "type": "CNAME", "domain": "www.oneal.daplie.me" | ||||
|     , "tld": "daplie.me", "sld": "oneal", "sub": "www", "value": "oneal.daplie.me" } | ||||
|   , { "zone": "oneal.daplie.me", "name": "www.oneal.daplie.me", "tld": "daplie.me", "sld": "oneal", "sub": "www" | ||||
|     , "type": "CNAME", "data": "oneal.daplie.me" } | ||||
| 
 | ||||
|   , { "zone": "oneal.daplie.me", "type": "NS", "domain": "aj.oneal.daplie.me" | ||||
|     , "tld": "daplie.me", "sld": "oneal", "sub": "aj", "value": "ns1.redirect-www.org" } | ||||
|   , { "zone": "oneal.daplie.me", "name": "aj.oneal.daplie.me", "tld": "daplie.me", "sld": "oneal", "sub": "aj" | ||||
|     , "type": "NS", "data": "ns1.redirect-www.org" } | ||||
| 
 | ||||
|   , { "zone": "oneal.daplie.me", "type": "NS", "domain": "aj.oneal.daplie.me" | ||||
|     , "tld": "daplie.me", "sld": "oneal", "sub": "aj", "value": "ns2.redirect-www.org" } | ||||
|   , { "zone": "oneal.daplie.me", "name": "aj.oneal.daplie.me", "tld": "daplie.me", "sld": "oneal", "sub": "aj" | ||||
|     , "type": "NS", "data": "ns2.redirect-www.org" } | ||||
| 
 | ||||
|     // there can be a wildcard, to which a delegation is the exception
 | ||||
|   , { "zone": "oneal.daplie.me", "type": "A", "domain": "*.oneal.daplie.me" | ||||
|     , "tld": "daplie.me", "sld": "oneal", "sub": "*", "value": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" } | ||||
|   , { "zone": "oneal.daplie.me", "name": "*.oneal.daplie.me", "tld": "daplie.me", "sld": "oneal", "sub": "*" | ||||
|     , "type": "A", "address": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" } | ||||
| 
 | ||||
|     // there can be an exception to the delegation
 | ||||
|   , { "zone": "oneal.daplie.me", "type": "A", "domain": "exception.aj.oneal.daplie.me" | ||||
|     , "tld": "daplie.me", "sld": "oneal", "sub": "exception.aj", "value": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" } | ||||
|   , { "zone": "oneal.daplie.me", "name": "exception.aj.oneal.daplie.me", "tld": "daplie.me", "sld": "oneal", "sub": "exception.aj" | ||||
|     , "type": "A", "address": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" } | ||||
| 
 | ||||
| 
 | ||||
|     //
 | ||||
|     // aj.oneal.daplie.me
 | ||||
|     //
 | ||||
|   , { "zone": "aj.oneal.daplie.me", "type": "A", "domain": "aj.oneal.daplie.me" | ||||
|     , "tld": "oneal.daplie.me", "sld": "aj", "sub": "", "value": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" } | ||||
|   , { "zone": "aj.oneal.daplie.me", "name": "aj.oneal.daplie.me", "tld": "oneal.daplie.me", "sld": "aj", "sub": "" | ||||
|    , "type": "A", "address": "45.56.59.142", "aname": "leo.devices.oneal.daplie.me" } | ||||
|   ] | ||||
| } | ||||
| ; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user