Compare commits

...

44 Commits

Author SHA1 Message Date
AJ ONeal c0eb4225dc Update 'README.md' 2019-03-05 23:43:14 +00:00
AJ ONeal 6ef61a8674 don't let it die, duh!! 2018-05-04 16:05:59 +00:00
AJ ONeal d8ead3181d update installer with v1.2 2017-12-14 20:33:32 -07:00
AJ ONeal bc93b942ee v1.2.1 2017-12-14 20:29:02 -07:00
AJ ONeal c3934acb30 add tcp support 2017-12-14 20:26:28 -07:00
AJ ONeal bd8b57efd1 bump version 2017-11-05 09:17:55 -07:00
AJ ONeal 59980dfa60 making room for API 2017-11-05 09:16:27 -07:00
AJ ONeal b5ec1f7982 Merge branch 'master' of ssh://git.coolaj86.com:22042/coolaj86/digd.js 2017-11-04 21:13:16 -06:00
AJ ONeal 3fba17eb97 add standard files 2017-11-04 21:06:58 -06:00
AJ ONeal 028d5a4542 lengthen NS ttl, remove cruft, add missing records 2017-11-04 16:37:38 -06:00
AJ ONeal 2705f5ef65 note delay in updates / expected short-term failure 2017-11-03 16:40:17 -06:00
AJ ONeal 6cbb2d1741 Merge branch 'v1.1' of ssh://git.coolaj86.com:22042/coolaj86/digd.js into v1.1 2017-11-03 16:23:34 -06:00
AJ ONeal d5ab2d5a26 add --tld option (even though it's not usually necessary) 2017-11-03 16:23:30 -06:00
AJ ONeal c77053c39c show example of dns tools for self-hosted dns 2017-11-03 16:15:04 -06:00
AJ ONeal 42d3e8a072 Merge branch 'v1' 2017-11-03 15:42:17 -06:00
AJ ONeal 50b335aa61 update urls 2017-11-03 15:39:59 -06:00
AJ ONeal a1eca4f1a5 clarify (kinda) vanity nameserver comment 2017-11-03 12:23:56 -06:00
AJ ONeal 4ffdf5b59d Merge branch 'v1' 2017-11-03 12:19:51 -06:00
AJ ONeal 148bda8afc WIP changes for CNAME fix 2017-11-03 12:17:06 -06:00
AJ ONeal ad61360a22 update with latest sample db 2017-11-03 12:14:45 -06:00
AJ ONeal 93e5c80ab4 add tests for CNAME and CNAME return on A/AAAA 2017-11-03 11:53:50 -06:00
AJ ONeal b3ef27791e update description 2017-11-02 23:59:53 -06:00
AJ ONeal cfe5f4e818 add mdig.js to bar 2017-11-02 23:47:20 -06:00
AJ ONeal 81928adf3e file organization 2017-11-02 23:19:15 -06:00
AJ ONeal f3105971a4 fix vanity NS check 2017-11-02 13:08:23 -06:00
AJ ONeal 7a201e4d8a add real sample db file 2017-11-02 12:38:16 -06:00
AJ ONeal be91254190 Merge branch 'v1.1' of ssh://git.coolaj86.com:22042/coolaj86/digd.js into v1.1 2017-11-02 12:16:38 -06:00
AJ ONeal 49811bd321 fix and/or logic 2017-11-02 12:14:44 -06:00
AJ ONeal 5839451f20 add exchange 2017-11-02 11:56:57 -06:00
AJ ONeal f67788f9db Merge branch 'v1' of git.daplie.com:Daplie/digd.js into v1 2017-11-02 11:32:51 -06:00
AJ ONeal 5cf3a3b20f add simple parser/reformatter 2017-11-02 11:32:46 -06:00
AJ ONeal d4646dba06 fix path name 2017-11-01 23:32:57 -06:00
AJ ONeal 58a48a2877 fix npm paths 2017-11-01 23:31:21 -06:00
AJ ONeal a617eb176c fix chown 2017-11-01 23:26:38 -06:00
AJ ONeal 9d4489f36a remove node installer tmp file 2017-11-01 23:20:02 -06:00
AJ ONeal b1b43a6257 fix adduser options 2017-11-01 23:19:12 -06:00
AJ ONeal 718e41b71a add installer, bump to v1.1.9 2017-11-01 23:14:44 -06:00
AJ ONeal 8f34294c88 create installer with systemd service and example db 2017-11-01 22:56:44 -06:00
AJ ONeal 861ffa1b80 add systemd launch file 2017-11-01 22:15:17 -06:00
AJ ONeal c49c398c39 some examples 2017-11-01 00:09:30 -06:00
AJ ONeal 5af2cb51d6 print number of records 2017-10-29 02:26:38 -06:00
AJ ONeal d625115689 Note setting glue and ns records 2017-10-29 01:43:28 -06:00
AJ ONeal e9db7fc12e v1.1.8 2017-10-28 22:13:52 -06:00
AJ ONeal 901c31e7bf update urls 2017-10-28 22:13:32 -06:00
21 changed files with 890 additions and 208 deletions

4
CHANGELOG Normal file
View File

@ -0,0 +1,4 @@
v1.1.13 - Tested and working. Deployed to production with known bugs:
* vanity nameserver handling needs more testing
* delegated nameserver handling needs more testing
* malformed records in JSON may result in failure to respond

41
LICENSE Normal file
View File

@ -0,0 +1,41 @@
Copyright 2017 AJ ONeal
This is open source software; you can redistribute it and/or modify it under the
terms of either:
a) the "MIT License"
b) the "Apache-2.0 License"
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Apache-2.0 License Summary
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -3,16 +3,28 @@ digd.js
| [dns-suite.js](https://git.coolaj86.com/coolaj86/dns-suite.js)
| [dig.js](https://git.coolaj86.com/coolaj86/dig.js)
| [mdig.js](https://git.coolaj86.com/coolaj86/mdig.js)
| **digd.js**
| Sponsored by [Daplie](https://daplie.com).
| A [Root project](https://rootprojects.org).
A lightweight DNS / mDNS daemon (server) in node.js.
Although originally created for testing dns-suite.js
by creating and capturing to disk DNS and mDNS query
and response packets (as binary and/or JSON), digd.js
has grown into a full-blown nameserver.
A lightweight DNS / mDNS daemon (server) for creating and capturing DNS and mDNS
query and response packets to disk as binary and/or JSON.
Options are similar to the Unix dig command.
Install
-------
### systemd service
```bash
curl -L https://git.coolaj86.com/coolaj86/digd.js/raw/v1.2/install.sh | bash
```
### with git
```bash
@ -21,14 +33,13 @@ npm install -g 'git+https://git.coolaj86.com/coolaj86/digd.js.git#v1'
```
```bash
# Install exactly v1.0.0
npm install -g 'git+https://git.coolaj86.com/coolaj86/digd.js.git#v1.0.0'
# Install exactly v1.2.0
npm install -g 'git+https://git.coolaj86.com/coolaj86/digd.js.git#v1.2.0'
```
### without git
Don't have git? Well, you can also bow down to the gods of the centralized, monopolized, concentrated, *dictator*net
(as we like to call it here at Daplie Labs), if that's how you roll:
Don't have git? You can use npm's centralized repository:
```bash
npm install -g digd.js
@ -77,6 +88,8 @@ Options
+time=<seconds> Sets the timeout for a query in seconds.
+norecurse Set `ra` flag to 0. Do not perform recursion.
+aaonly Set `aa` flag to 1. Do not respond with non-authoritative responses.
+notcp Disable TCP server (default in v1.2)
+tcp Enable TCP server (default in v1.3)
--debug verbose output
```

View File

@ -5,9 +5,7 @@
var cli = require('cli');
var pkg = require('../package.json');
var dig = require('dig.js/dns-request');
var dgram = require('dgram');
var dnsjs = require('dns-suite');
var crypto = require('crypto');
var common = require('dig.js/common');
var defaultNameservers = require('dns').getServers();
var hexdump;
@ -49,8 +47,32 @@ cli.main(function (args, cli) {
cli.norecurse = true;
return;
}
if (arg === '+notcp') {
if (cli.notcp) {
console.error("'+notcp' was specified more than once");
process.exit(1);
return;
}
cli.notcp = true;
return;
}
if (arg === '+tcp') {
if (cli.tcp) {
console.error("'+tcp' was specified more than once");
process.exit(1);
return;
}
cli.tcp = true;
return;
}
});
if (!cli.tcp) {
if (!cli.notcp) {
console.info("[WARNING] Set '+notcp' to disable tcp connections. The default behavior changes to +tcp in v1.3");
}
}
if (cli.mdns) {
if (!cli.type) {
cli.type = cli.t = 'PTR';
@ -73,32 +95,10 @@ cli.main(function (args, cli) {
}
}
var handlers = {};
var server = dgram.createSocket({
type: cli.udp6 ? 'udp6' : 'udp4'
, reuseAddr: true
});
server.bind({
port: cli.port
, address: cli.address
});
handlers.onError = function (err) {
if ('EACCES' === err.code) {
console.error("");
console.error("EACCES: Couldn't bind to port. You probably need to use sudo, authbind, or setcap.");
console.error("");
process.exit(123);
return;
}
console.error("error:", err.stack);
server.close();
};
handlers.onMessage = function (nb, rinfo) {
console.log('[DEBUG] got a message');
var queryAb = nb.buffer.slice(nb.byteOffset, nb.byteOffset + nb.byteLength);
var dnsd = {};
dnsd.onMessage = function (nb, cb) {
var byteOffset = nb._dnsByteOffset || nb.byteOffset;
var queryAb = nb.buffer.slice(byteOffset, byteOffset + nb.byteLength);
var query;
var count;
@ -215,12 +215,11 @@ cli.main(function (args, cli) {
console.error("Could not write empty DNS response");
console.error(e);
console.error(emptyResp);
cb(e, null, '[DEV] response sent (empty)');
return;
}
server.send(newAb, rinfo.port, rinfo.address, function () {
console.log('[DEV] response sent (empty)', rinfo.port, rinfo.address);
});
cb(null, newAb, '[DEV] response sent (empty)');
}
function sendResponse(newPacket) {
@ -232,12 +231,11 @@ cli.main(function (args, cli) {
console.error("Could not write DNS response from local");
console.error(e);
console.error(newPacket);
cb(e, null, '[DEV] response sent (local query)');
return;
}
server.send(newAb, rinfo.port, rinfo.address, function () {
console.log('[DEV] response sent (local query)', rinfo.port, rinfo.address);
});
cb(null, newAb, '[DEV] response sent (local query)');
}
function recurse() {
@ -290,12 +288,11 @@ cli.main(function (args, cli) {
} catch(e) {
console.error("Could not write DNS response");
console.error(newResponse);
cb(e, null, '[DEV] response sent');
return;
}
server.send(newAb, rinfo.port, rinfo.address, function () {
console.log('[DEV] response sent', rinfo.port, rinfo.address);
});
cb(null, newAb, '[DEV] response sent');
}
}
@ -335,7 +332,8 @@ cli.main(function (args, cli) {
console.log('request sent to', res.nameserver);
}
*/
console.log('[DEV] query sent (recurse)', rinfo.port, rinfo.address);
//console.log('[DEV] query sent (recurse)', rinfo.port, rinfo.address);
//dnsd.onSent('[DEV] query sent (recurse)');
}
, onTimeout: function (res) {
console.log(";; [" + q.name + "] connection timed out; no servers could be reached");
@ -373,7 +371,7 @@ cli.main(function (args, cli) {
return;
}
require('../lib/dns-store').query(path.resolve(cli.input), query, function (err, resp) {
function respondWithResults(err, resp) {
if (err) { console.log('[DEV] answer not found in local db, recursing'); console.error(err); recurse(); return; }
@ -383,33 +381,34 @@ cli.main(function (args, cli) {
if (!cli.norecurse && query.header.rd) { resp.header.ra = 1; }
sendResponse(resp);
});
}
var engine;
try {
engine = require('../lib/store.json.js').create({ filepath: path.resolve(cli.input) });
} catch(e) {
respondWithResults(e);
return;
}
require('../lib/digd.js').query(engine, query, respondWithResults);
};
handlers.onListening = function () {
/*jshint validthis:true*/
var server = this;
cli.defaultNameservers = defaultNameservers;
require('../lib/udpd.js').create(cli, dnsd).on('listening', function () {
cli.chosenNameserver = cli.nameserver;
var index;
if (!cli.chosenNameserver) {
index = crypto.randomBytes(2).readUInt16BE(0) % defaultNameservers.length;
cli.chosenNameserver = defaultNameservers[index];
index = require('crypto').randomBytes(2).readUInt16BE(0) % cli.defaultNameservers.length;
cli.chosenNameserver = cli.defaultNameservers[index];
if (cli.debug) {
console.log('index, defaultNameservers', index, defaultNameservers);
console.log('index, defaultNameservers', index, cli.defaultNameservers);
}
}
if (cli.mdns || '224.0.0.251' === cli.nameserver) {
server.setBroadcast(true);
server.addMembership(cli.nameserver);
}
console.log('');
console.log('Bound and Listening:');
console.log(server.address().address + '#' + server.address().port + ' (' + server.type + ')');
};
});
if (cli.tcp /* TODO v1.3 !cli.notcp */) {
require('../lib/tcpd.js').create(cli, dnsd);
}
console.log('');
if (!cli.nocmd) {
@ -417,7 +416,4 @@ cli.main(function (args, cli) {
console.log(';; global options: +cmd');
}
server.on('error', handlers.onError);
server.on('message', handlers.onMessage);
server.on('listening', handlers.onListening);
});

61
dist/etc/systemd/system/digd.js.service vendored Normal file
View File

@ -0,0 +1,61 @@
[Unit]
Description=digd.js - A lightweight DNS server in node.js.
Documentation=https://git.coolaj86.com/coolaj86/digd.js
After=network-online.target
Wants=network-online.target systemd-networkd-wait-online.service
[Service]
# Restart on crash (bad signal), but not on 'clean' failure (error exit code)
# Allow up to 3 restarts within 10 seconds
# (it's unlikely that a user or properly-running script will do this)
Restart=always
StartLimitInterval=10
StartLimitBurst=3
# User and group the process will run as
# (git is the de facto standard on most systems)
User=digd
Group=digd
WorkingDirectory=/opt/digd.js
# TODO use --config instead of commandline params
ExecStart=/opt/digd.js/bin/node /opt/digd.js/bin/digd.js --port 53 --input /srv/digd.js/db.json +norecurse
ExecReload=/bin/kill -USR1 $MAINPID
# Limit the number of file descriptors and processes; see `man systemd.exec` for more limit settings.
# Unmodified digd.js is not expected to use more than this.
LimitNOFILE=1048576
LimitNPROC=64
# Use private /tmp and /var/tmp, which are discarded after digd.js stops.
PrivateTmp=true
# Use a minimal /dev
PrivateDevices=true
# Hide /home, /root, and /run/user. Nobody will steal your SSH-keys.
ProtectHome=true
# Make /usr, /boot, /etc and possibly some more folders read-only.
ProtectSystem=full
# ... except /srv/digd.js because we want a place for the database
# and /var/log/digd.js because we want a place where logs can go.
# This merely retains r/w access rights, it does not add any new.
# Must still be writable on the host!
ReadWriteDirectories=/opt/digd.js /srv/digd.js /var/log/digd.js
# Note: in v231 and above ReadWritePaths has been renamed to ReadWriteDirectories
; ReadWritePaths=/opt/digd.js /srv/digd.js /var/log/digd.js
# The following additional security directives only work with systemd v229 or later.
# They further retrict privileges that can be gained by digd.js.
# Note that you may have to add capabilities required by any plugins in use.
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
# Caveat: Some features may need additional capabilities.
# For example an "upload" may need CAP_LEASE
; CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_LEASE
; AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_LEASE
; NoNewPrivileges=true
[Install]
WantedBy=multi-user.target

35
install.sh Normal file
View File

@ -0,0 +1,35 @@
#!/bin/bash
sudo adduser --home /opt/digd.js --gecos '' --disabled-password digd
sudo mkdir -p /opt/digd.js/ /srv/digd.js /var/log/digd.js
sudo mkdir -p /opt/digd.js /srv/digd.js
#chown -R $(whoami):$(whoami) /opt/digd.js /srv/digd.js
chown -R digd:digd /opt/digd.js /srv/digd.js
echo "v8.9.3" > /tmp/NODEJS_VER
export NODE_PATH=/opt/digd.js/lib/node_modules
export NPM_CONFIG_PREFIX=/opt/digd.js
curl -fsSL https://git.coolaj86.com/coolaj86/node-installer.sh/raw/master/install.sh -o ./node-installer.sh.tmp
bash ./node-installer.sh.tmp
rm ./node-installer.sh.tmp
/opt/digd.js/bin/node /opt/digd.js/bin/npm install -g npm@4
git clone https://git.coolaj86.com/coolaj86/digd.js /opt/digd.js/lib/node_modules/digd.js
pushd /opt/digd.js/lib/node_modules/digd.js
git checkout v1.2
/opt/digd.js/bin/node /opt/digd.js/bin/npm install
popd
sudo rsync -v /opt/digd.js/lib/node_modules/digd.js/dist/etc/systemd/system/digd.js.service /etc/systemd/system/
sudo rsync -v /opt/digd.js/lib/node_modules/digd.js/samples/db.json /srv/digd.js/db.json
sudo ln -s /opt/digd.js/lib/node_modules/digd.js/bin/digd.js /opt/digd.js/bin/
sudo chown -R digd:digd /opt/digd.js/ /srv/digd.js /var/log/digd.js
sudo systemctl daemon-reload
sudo systemctl restart digd.js
dig @localhost -p 53 example.com
#sudo journalctl -xefu digd.js
sudo journalctl -xeu digd.js

View File

@ -10,110 +10,102 @@ var NOERROR = 0;
var NXDOMAIN = 3;
var REFUSED = 5;
function getRecords(db, qname, cb) {
function getRecords(engine, qname, cb) {
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) {
return false;
}
return engine.getRecords({ name: qname }, function (err, myRecords) {
if (err) { cb(err); return; }
// TODO use IN in masterquest (or implement OR)
// Only return single-level wildcard?
if (qname === r.name || ('*.' + qname.split('.').slice(1).join('.')) === r.name) {
return true;
}
});
function checkCount() {
var ready;
function checkCount() {
var ready;
count -= 1;
ready = count <= 0;
count -= 1;
ready = count <= 0;
if (!ready) {
return;
}
myRecords = myRecords.filter(function (r) {
return !delMe[r.id];
});
// There are a number of ways to interpret the wildcard rules
var hasWild = false;
var hasMatch = false;
myRecords.some(function (r) {
if (qname === r.name) {
hasMatch = true;
return true;
if (!ready) {
return;
}
if ('*' === r.name[0]) {
hasWild = true;
}
});
if (hasMatch) {
myRecords = myRecords.filter(function (r) {
if ('*' !== r.name[0]) { return true; }
return !delMe[r.id];
});
}
/*
// no need to filter out records if wildcard is used
else {
records = records.filter(function (r) {
if ('*' === r.name[0]) { return true; }
// There are a number of ways to interpret the wildcard rules
var hasWild = false;
var hasMatch = false;
myRecords.some(function (r) {
if (qname === r.name) {
hasMatch = true;
return true;
}
if ('*' === r.name[0]) {
hasWild = true;
}
});
}
*/
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];
if (hasMatch) {
myRecords = myRecords.filter(function (r) {
if ('*' !== r.name[0]) { return true; }
});
}
/*
// no need to filter out records if wildcard is used
else {
records = records.filter(function (r) {
if ('*' === r.name[0]) { return true; }
});
}
*/
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();
};
}
});
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;
}
if (!myRecords.length) {
checkCount();
}
checkCount();
});
if (!myRecords.length) {
checkCount();
}
}
function dbToResourceRecord(r) {
return {
name: r.name
, typeName: r.type // NS
, typeName: r.typeName || r.type // NS
, className: 'IN'
, ttl: r.ttl || 300
@ -147,7 +139,7 @@ function dbToResourceRecord(r) {
};
}
function getNs(db, ds, results, cb) {
function getNs(engine, ds, results, cb) {
console.log('[DEV] getNs entered with domains', ds);
var d = ds.shift();
@ -161,7 +153,7 @@ function getNs(db, ds, results, cb) {
var qn = d.id.toLowerCase();
return getRecords(db, qn, function (err, records) {
return getRecords(engine, qn, function (err, records) {
if (err) { cb(err); return; }
records.forEach(function (r) {
@ -187,16 +179,16 @@ function getNs(db, ds, results, cb) {
});
if (!results.authority.length) {
return getNs(db, ds, results, cb);
return getNs(engine, ds, results, cb);
}
// d.vanityNs should only be vanity nameservers (pointing to this same server)
if (d.vanityNs || results.authority.some(function (ns) {
console.log('[debug] ns', ns);
return -1 !== db.primaryNameservers.indexOf(ns.data.toLowerCase());
return -1 !== engine.primaryNameservers.indexOf(ns.data.toLowerCase());
})) {
results.authority.length = 0;
results.authority.push(domainToSoa(db, d));
results.authority.push(domainToSoa(engine.primaryNameservers, d));
results.header.rcode = NXDOMAIN;
}
cb(null, results);
@ -204,8 +196,8 @@ function getNs(db, ds, results, cb) {
});
}
function domainToSoa(db, domain) {
var nameservers = domain.vanityNs || db.primaryNameservers;
function domainToSoa(primaryNameservers, domain) {
var nameservers = domain.vanityNs || primaryNameservers;
var index = Math.floor(Math.random() * nameservers.length) % nameservers.length;
var nameserver = nameservers[index];
@ -245,20 +237,20 @@ function domainToSoa(db, domain) {
};
}
function getSoa(db, domain, results, cb, answerSoa) {
function getSoa(primaryNameservers, domain, results, cb, answerSoa) {
console.log('[DEV] getSoa entered');
if (!answerSoa) {
results.authority.push(domainToSoa(db, domain));
results.authority.push(domainToSoa(primaryNameservers, domain));
} else {
results.answer.push(domainToSoa(db, domain));
results.answer.push(domainToSoa(primaryNameservers, domain));
}
cb(null, results);
return;
}
module.exports.query = function (input, query, cb) {
module.exports.query = function (engine, query, cb) {
/*
var fs = require('fs');
@ -271,11 +263,7 @@ module.exports.query = function (input, query, cb) {
});
*/
var db;
var qname;
try {
db = require(input);
} catch(e) { cb(e); return; }
if (!Array.isArray(query.question) || query.question.length < 1) {
cb(new Error("query is missing question section"));
@ -337,46 +325,48 @@ module.exports.query = function (input, query, cb) {
console.log('[DEV] answerSoa?', answerSoa);
console.log('[DEV] qnames');
console.log(qnames);
var myDomains = db.domains.filter(function (d) {
return -1 !== qnames.indexOf(d.id.toLowerCase());
});
// this should result in a REFUSED status
if (!myDomains.length) {
// REFUSED will have no records, so we could still recursion, if enabled
results.header.rcode = REFUSED;
cb(null, results);
return;
}
return engine.getSoas({ names: qnames}, function (err, myDomains) {
console.log('[SOA] looking for', qnames, 'and proudly serving', err, myDomains);
if (err) { cb(err); return; }
myDomains.sort(function (d1, d2) {
if (d1.id.length > d2.id.length) {
return -1;
}
if (d1.id.length < d2.id.length) {
return 1;
}
return 0;
});
//console.log('sorted domains', myDomains);
if (!getNsAlso) {
return getSoa(db, myDomains[0], results, cb, answerSoa);
}
return getNs(db, /*myDomains.slice(0)*/qnames.map(function (qn) { return { id: qn }; }), results, function (err, results) {
//console.log('[DEV] getNs complete');
if (err) { cb(err, results); return; }
// has NS records (or SOA record if NS records match the server itself)
if (results.authority.length) {
console.log(results); cb(null, results); return;
// this should result in a REFUSED status
if (!myDomains.length) {
// REFUSED will have no records, so we could still recursion, if enabled
results.header.rcode = REFUSED;
cb(null, results);
return;
}
// myDomains was sorted such that the longest was first
return getSoa(db, myDomains[0], results, cb);
myDomains.sort(function (d1, d2) {
if (d1.id.length > d2.id.length) {
return -1;
}
if (d1.id.length < d2.id.length) {
return 1;
}
return 0;
});
//console.log('sorted domains', myDomains);
if (!getNsAlso) {
return getSoa(engine.primaryNameservers, myDomains[0], results, cb, answerSoa);
}
return getNs(engine, /*myDomains.slice(0)*/qnames.map(function (qn) { return { id: qn }; }), results, function (err, results) {
//console.log('[DEV] getNs complete');
if (err) { cb(err, results); return; }
// has NS records (or SOA record if NS records match the server itself)
if (results.authority.length) {
console.log(results); cb(null, results); return;
}
// myDomains was sorted such that the longest was first
return getSoa(engine.primaryNameservers, myDomains[0], results, cb);
});
});
}
@ -385,7 +375,7 @@ module.exports.query = function (input, query, cb) {
}
//console.log('[DEV] QUERY NAME', qname);
return getRecords(db, qname, function (err, someRecords) {
return getRecords(engine, qname, function (err, someRecords) {
var myRecords;
var nsRecords = [];
@ -395,7 +385,7 @@ module.exports.query = function (input, query, cb) {
// NS records are returned as ANSWER for NS and ANY, and as AUTHORITY when an externally-delegated domain would return an SOA (no records)
// SOA records are returned as ANSWER for SOA and ANY, and as AUTHORITY when no records are found, but the domain is controlled here
console.log("[DEV] has records");
console.log("[DEV] has", someRecords.length, "records");
// filter out NS (delegation) records, unless that is what is intended
someRecords = someRecords.filter(function (r) {
@ -407,7 +397,10 @@ module.exports.query = function (input, query, cb) {
console.log("It's NS");
// If it's a vanity NS, it's not a valid NS for lookup
if (-1 !== db.primaryNameservers.indexOf(r.data.toLowerCase())) {
// NOTE: I think that the issue here is EXTERNAL vs INTERNAL vanity NS
// We _should_ reply for EXTERNAL vanity NS... but not when it's listed on the SOA internally?
// It's surrounding the problem of what if I do sub domain delegation to the same server.
if (-1 === engine.primaryNameservers.indexOf(r.data.toLowerCase())) {
console.log("It's a vanity NS");
return false;
}
@ -422,14 +415,37 @@ module.exports.query = function (input, query, cb) {
});
myRecords = someRecords;
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)
// If we had an ANY query then we don't need to filter out results
if (255 !== query.question[0].type && 'ANY' !== query.question[0].typeName) {
var hasA = false;
var hasCname = false;
// We should only return the records that match the query,
// except in the case of A/AAAA in which case we should also collect the CNAME
myRecords = myRecords.filter(function (r) {
var passCnames = false;
if (!hasA && ('A' === query.question[0].typeName || 'AAAA' === query.question[0].typeName)) {
passCnames = ('CNAME' === r.type ||'CNAME' === r.typeName);
hasCname = hasCname || passCnames;
}
hasA = hasA || ('A' === r.type || 'A' === r.typeName || 'AAAA' === r.type || 'AAAA' === r.typeName);
return passCnames || ((r.type && r.type === query.question[0].type)
|| (r.type && r.type === query.question[0].typeName)
|| (r.typeName && r.typeName === query.question[0].typeName)
);
});
// A and AAAA will also return CNAME records
// but we filter out the CNAME records unless there are no A / AAAA records
if (hasA && hasCname && ('A' === query.question[0].typeName || 'AAAA' === query.question[0].typeName)) {
myRecords = myRecords.forEach(function (r) {
return 'CNAME' !== r.type && 'CNAME' !== r.typeName;
});
}
}
if (myRecords.length) {
@ -439,7 +455,7 @@ module.exports.query = function (input, query, cb) {
results.header.rcode = NOERROR;
//console.log('[DEV] ANSWER results', results);
if (255 === query.question[0].type && 'ANY' === query.question[0].typeName) {
if (255 === query.question[0].type || 'ANY' === query.question[0].typeName) {
getNsAndSoa(false, true);
return;
}

37
lib/store.json.js Normal file
View File

@ -0,0 +1,37 @@
'use strict';
module.exports.create = function (opts) {
// opts = { filepath };
var engine = { db: null };
var db = require(opts.filepath);
engine.primaryNameservers = db.primaryNameservers;
engine.getSoas = function (query, cb) {
var myDomains = db.domains.filter(function (d) {
return -1 !== query.names.indexOf(d.id.toLowerCase());
});
process.nextTick(function () {
cb(null, myDomains);
});
};
engine.getRecords = function (query, cb) {
var myRecords = db.records.slice(0).filter(function (r) {
if ('string' !== typeof r.name) {
return false;
}
// TODO use IN in masterquest (or implement OR)
// Only return single-level wildcard?
if (query.name === r.name || ('*.' + query.name.split('.').slice(1).join('.')) === r.name) {
return true;
}
});
process.nextTick(function () {
cb(null, myRecords);
});
};
return engine;
};

70
lib/tcpd.js Normal file
View File

@ -0,0 +1,70 @@
'use strict';
module.exports.create = function (cli, dnsd) {
function runTcp() {
var tcpServer = require('net').createServer({ }, function (c) {
c.on('error', function (err) {
console.warn("TCP Connection Error:");
console.warn(err);
});
c.on('data', function (nb) {
//console.log('TCP data.length:', nb.length);
//console.log(nb.toString('hex'));
// DNS packets include a 2-byte length header
var count = nb.length;
var length = nb[0] << 8;
length = length | nb[1];
count -= 2;
// TODO slice?
nb._dnsByteOffset = nb.byteOffset + 2;
if (length !== count) {
console.error("Handling TCP packets > 512 bytes not implemented.");
c.end();
return;
}
// TODO pad two bytes for lengths
dnsd.onMessage(nb, function (err, newAb, dbgmsg) {
var lenbuf = Buffer.from([ newAb.length >> 8, newAb.length & 255 ]);
// TODO XXX generate legit error packet
if (err) { console.error("Error", err); c.end(); return; }
console.log('TCP ' + dbgmsg);
c.write(lenbuf);
c.end(newAb);
});
});
c.on('end', function () {
console.log('TCP client disconnected from server');
});
});
tcpServer.on('error', function (err) {
if ('EADDRINUSE' === err.code) {
console.error("Port '" + cli.port + "' is already in use.");
tcpServer.close();
process.exit(0);
}
if ('EACCES' === err.code) {
console.error("Could not bind on port '" + cli.port + "': EACCESS (you probably need root permissions)");
tcpServer.close();
process.exit(0);
}
console.error("TCP Server Error:");
console.error(err);
tcpServer.close(function () {
setTimeout(runTcp, 1000);
});
});
tcpServer.listen(cli.port, function () {
console.log('TCP Server bound');
});
return tcpServer;
}
return runTcp();
};

58
lib/udpd.js Normal file
View File

@ -0,0 +1,58 @@
'use strict';
module.exports.create = function (cli, dnsd) {
var server = require('dgram').createSocket({
type: cli.udp6 ? 'udp6' : 'udp4'
, reuseAddr: true
});
server.bind({
port: cli.port
, address: cli.address
});
var handlers = {};
handlers.onError = function (err) {
if ('EACCES' === err.code) {
console.error("");
console.error("EACCES: Couldn't bind to port. You probably need to use sudo, authbind, or setcap.");
console.error("");
process.exit(123);
return;
}
console.error("error:", err.stack);
server.close();
};
handlers.onMessage = function (nb, rinfo) {
//console.log('[DEBUG] got a UDP message', nb.length);
//console.log(nb.toString('hex'));
dnsd.onMessage(nb, function (err, newAb, dbgmsg) {
// TODO send legit error message
if (err) { server.send(Buffer.from([0x00])); return; }
server.send(newAb, rinfo.port, rinfo.address, function () {
console.log(dbgmsg, rinfo.port, rinfo.address);
});
});
};
handlers.onListening = function () {
/*jshint validthis:true*/
var server = this;
if (cli.mdns || '224.0.0.251' === cli.nameserver) {
server.setBroadcast(true);
server.addMembership(cli.nameserver);
}
console.log('');
console.log('Bound and Listening:');
console.log(server.address().address + '#' + server.address().port + ' (' + server.type + ')');
};
server.on('error', handlers.onError);
server.on('message', handlers.onMessage);
server.on('listening', handlers.onListening);
return server;
};

View File

@ -1,9 +1,9 @@
{
"name": "digd.js",
"version": "1.1.7",
"version": "1.2.1",
"description": "A lightweight DNS / mDNS daemon (server) for creating and capturing DNS and mDNS query and response packets to disk as binary and/or JSON. Options are similar to the Unix dig command.",
"main": "bin/digd.js",
"homepage": "https://git.coolaj86.com:coolaj86/digd.js",
"homepage": "https://git.coolaj86.com/coolaj86/digd.js",
"bin": {
"digd.js": "bin/digd.js"
},

View File

@ -0,0 +1,60 @@
#!/bin/bash
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com ns:set -n hellabit.com --nameserver ns1.daplie.com,ns2.daplie.domains,ns3.hellabit.com
# glue setting is rate-limited, or so it would seem
echo "sleeping between setting glue for rate limit"
sleep 5
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com glue:set -a 45.55.1.122 -n ns1.daplie.com
sleep 5
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com glue:set -a 45.55.1.122 -n ns1.daplie.domains
sleep 5
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com glue:set -a 45.55.1.122 -n ns1.daplie.me --tld me
sleep 5
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com glue:set -a 45.55.1.122 -n ns1.hellabit.com --tld com
sleep 5
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com devices:attach -d ns1-do -a 45.55.1.122 -n ns1.daplie.com
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com devices:attach -d ns1-do -a 45.55.1.122 -n ns1.daplie.domains
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com devices:attach -d ns1-do -a 45.55.1.122 -n ns1.daplie.me --tld me
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com devices:attach -d ns1-do -a 45.55.1.122 -n ns1.hellabit.com --tld com
# glue setting is rate-limited, or so it would seem
echo "sleeping between setting glue for rate limit"
sleep 5
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com glue:set -a 45.55.254.197 -n ns2.daplie.com
sleep 5
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com glue:set -a 45.55.254.197 -n ns2.daplie.domains
sleep 5
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com glue:set -a 45.55.254.197 -n ns2.daplie.me --tld me
sleep 5
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com glue:set -a 45.55.254.197 -n ns2.hellabit.com --tld com
sleep 5
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com devices:attach -d ns2-do -a 45.55.254.197 -n ns2.daplie.com
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com devices:attach -d ns2-do -a 45.55.254.197 -n ns2.daplie.domains
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com devices:attach -d ns2-do -a 45.55.254.197 -n ns2.daplie.me --tld me
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com devices:attach -d ns2-do -a 45.55.254.197 -n ns2.hellabit.com --tld com
# glue setting is rate-limited, or so it would seem
echo "sleeping between setting glue for rate limit"
sleep 5
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com glue:set -a 159.203.25.112 -n ns3.daplie.com
sleep 5
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com glue:set -a 159.203.25.112 -n ns3.daplie.domains
sleep 5
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com glue:set -a 159.203.25.112 -n ns3.daplie.me --tld me
sleep 5
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com glue:set -a 159.203.25.112 -n ns3.hellabit.com --tld com
sleep 5
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com devices:attach -d ns3-do -a 159.203.25.112 -n ns3.daplie.com
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com devices:attach -d ns3-do -a 159.203.25.112 -n ns3.daplie.domains
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com devices:attach -d ns3-do -a 159.203.25.112 -n ns3.daplie.me --tld me
node bin/daplie.js --oauth3-config ~/.oauth3+domains@daplie.com devices:attach -d ns3-do -a 159.203.25.112 -n ns3.hellabit.com --tld com

7
samples/HOWTO-NS.md Normal file
View File

@ -0,0 +1,7 @@
```bash
# Create a glue record for the nameserver
daplie glue:set -n ns1.example.com -a 12.55.12.33
# Set the nameservers for a domain
daplie ns:set -n example.com --nameservers ns1.example.com
```

View File

@ -0,0 +1,86 @@
{ "primaryNameservers": [ "ns1.daplie.com", "ns2.daplie.com", "ns3.daplie.com" ]
, "domains": [
{ "id": "daplie.com", "revokedAt": 0 }
, { "id": "daplie.domains", "revokedAt": 0, "vanityNs": [ "ns1.daplie.domains", "ns2.daplie.domains", "ns3.daplie.domains" ] }
, { "id": "daplie.me", "revokedAt": 0, "vanityNs": [ "ns1.daplie.me", "ns2.daplie.me", "ns3.daplie.me" ] }
, { "id": "oauth3.org", "revokedAt": 0 }
]
, "records": [
{"zone":"daplie.com","name":"daplie.com","type":"NS","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"ns1","data":"ns1.daplie.com"}
, {"zone":"daplie.com","name":"daplie.com","type":"NS","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"ns2","data":"ns2.daplie.com"}
, {"zone":"daplie.com","name":"daplie.com","type":"NS","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"ns3","data":"ns3.daplie.com"}
, {"zone":"daplie.com","name":"ns1.daplie.com","type":"A","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"ns1","address":"45.55.1.122"}
, {"zone":"daplie.com","name":"ns2.daplie.com","type":"A","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"ns2","address":"45.55.254.197"}
, {"zone":"daplie.com","name":"ns3.daplie.com","type":"A","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"ns3","address":"159.203.25.112"}
, {"zone":"daplie.me","name":"daplie.me","type":"NS","class":"IN","ttl":43200,"tld":"me","sld":"daplie","sub":"ns1","data":"ns1.daplie.me"}
, {"zone":"daplie.me","name":"daplie.me","type":"NS","class":"IN","ttl":43200,"tld":"me","sld":"daplie","sub":"ns2","data":"ns2.daplie.me"}
, {"zone":"daplie.me","name":"daplie.me","type":"NS","class":"IN","ttl":43200,"tld":"me","sld":"daplie","sub":"ns3","data":"ns3.daplie.me"}
, {"zone":"daplie.me","name":"ns1.daplie.me","type":"A","class":"IN","ttl":5,"tld":"me","sld":"daplie","sub":"ns1","address":"45.55.1.122"}
, {"zone":"daplie.me","name":"ns2.daplie.me","type":"A","class":"IN","ttl":5,"tld":"me","sld":"daplie","sub":"ns2","address":"45.55.254.197"}
, {"zone":"daplie.me","name":"ns3.daplie.me","type":"A","class":"IN","ttl":5,"tld":"me","sld":"daplie","sub":"ns3","address":"159.203.25.112"}
, {"zone":"oauth3.org","name":"ns1.oauth3.org","type":"A","class":"IN","ttl":5,"tld":"org","sld":"oauth3","sub":"ns1","address":"45.55.1.122"}
, {"zone":"oauth3.org","name":"ns2.oauth3.org","type":"A","class":"IN","ttl":5,"tld":"org","sld":"oauth3","sub":"ns2","address":"45.55.254.197"}
, {"zone":"oauth3.org","name":"ns3.oauth3.org","type":"A","class":"IN","ttl":5,"tld":"org","sld":"oauth3","sub":"ns3","address":"159.203.25.112"}
, {"zone":"oauth3.org","name":"oauth3.org","type":"NS","class":"IN","ttl":43200,"tld":"me","sld":"oauth3","sub":"ns1","data":"ns1.oauth3.org"}
, {"zone":"oauth3.org","name":"oauth3.org","type":"NS","class":"IN","ttl":43200,"tld":"me","sld":"oauth3","sub":"ns2","data":"ns2.oauth3.org"}
, {"zone":"oauth3.org","name":"oauth3.org","type":"NS","class":"IN","ttl":43200,"tld":"me","sld":"oauth3","sub":"ns3","data":"ns3.oauth3.org"}
, {"zone":"daplie.com","name":"daplie.com","type":"A","class":"IN","ttl":43200,"tld":"com","sld":"daplie","address":"23.228.168.108"}
, {"zone":"daplie.com","name":"daplie.com","type":"TXT","class":"IN","ttl":43200,"tld":"com","sld":"daplie","data":["v=spf1 include:mailgun.org include:spf.mandrillapp.com include:_spf.google.com include:servers.mcsv.net include:mail.zendesk.com ~all"]}
, {"zone":"daplie.com","name":"www.daplie.com","type":"A","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"www","address":"23.228.168.108"}
, {"zone":"daplie.com","name":"daplie.com","type":"MX","class":"IN","ttl":43200,"tld":"com","sld":"daplie","exchange":"mxa.mailgun.org","priority":10}
, {"zone":"daplie.com","name":"daplie.com","type":"MX","class":"IN","ttl":43200,"tld":"com","sld":"daplie","exchange":"mxb.mailgun.org","priority":10}
, {"zone":"daplie.com","name":"email.daplie.com","type":"CNAME","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"email","data":"mailgun.org"}
, {"zone":"daplie.com","name":"k1._domainkey.daplie.com","type":"CNAME","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"k1._domainkey","data":"dkim.mcsv.net"}
, {"zone":"daplie.com","name":"smtp._domainkey.daplie.com","type":"TXT","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"smtp._domainkey","data":["k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdEzzYX8U31O5p5Uvyb1B50/JPMcKnsnIQcPDWWYkBUQxMt+FyD1SRZLCaVxWybZ8eFQUwxlh0qFeLd/mIIGhCazQ74a3AH+TJhz4gOAvNQHmWvS0Sv9ZZjGuDM/RdOAFSwZET8+WUpJfDADfijihj5KqMab13NDDLOQ96wObuwQIDAQAB"]}
, {"zone":"daplie.com","name":"mandrill._domainkey.daplie.com","type":"TXT","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"mandrill._domainkey","data":["v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrLHiExVd55zd/IQ/J/mRwSRMAocV/hMB3jXwaHH36d9NaVynQFYV8NaWi69c1veUtRzGt7yAioXqLj7Z4TeEUoOLgrKsn8YnckGs9i3B3tVFB+Ch/4mPhXWiNfNdynHWBcPcbJ8kjEQ2U8y78dHZj1YeRXXVvWob2OaKynO8/lQIDAQAB;"]}
, {"zone":"daplie.com","name":"iqqsuxwfyvyw.daplie.com","type":"CNAME","class":"IN","ttl":5,"tld":"com","sld":"daplie","sub":"iqqsuxwfyvyw","data":"gv-roynzijsoqayyg.dv.googlehosted.com"}
, {"zone":"daplie.com","name":"support.daplie.com","type":"CNAME","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"support","data":"daplie.zendesk.com"}
, {"zone":"daplie.com","name":"proxy.tardigrade.devices.daplie.com","type":"A","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"proxy.tardigrade.devices","address":"23.228.168.108"}
, {"zone":"daplie.com","name":"redleader.devices.daplie.com","type":"A","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"redleader.devices","address":"104.36.98.166"}
, {"zone":"daplie.com","name":"beast.devices.daplie.com","type":"A","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"beast.devices","address":"96.19.92.42"}
, {"zone":"daplie.com","name":"ossus.devices.daplie.com","type":"A","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"ossus.devices","address":"73.65.206.97"}
, {"zone":"daplie.com","name":"leo.devices.daplie.com","type":"A","class":"IN","ttl":3600,"tld":"com","sld":"daplie","sub":"leo.devices","address":"45.56.59.142"}
, {"zone":"daplie.com","name":"proxy.leo.devices.daplie.com","type":"A","class":"IN","ttl":3600,"tld":"com","sld":"daplie","sub":"proxy.leo.devices","address":"45.56.59.142"}
, {"zone":"daplie.com","name":"git.daplie.com","type":"A","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"git","address":"23.228.168.108"}
, {"zone":"daplie.com","name":"tunnel.daplie.com","type":"A","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"tunnel","address":"162.243.160.23"}
, {"zone":"daplie.com","name":"api.daplie.com","type":"A","class":"IN","ttl":43200,"tld":"com","sld":"daplie","sub":"api","address":"23.228.168.108"}
, {"zone":"daplie.com","name":"preorder.daplie.com","type":"CNAME","class":"IN","ttl":5,"tld":"com","sld":"daplie","sub":"preorder","data":"daplie.myshopify.com"}
, {"zone":"daplie.com","name":"rvpn.daplie.com","type":"A","class":"IN","ttl":5,"tld":"com","sld":"daplie","sub":"rvpn","address":"104.236.182.24"}
, {"zone":"daplie.com","name":"mailapp.daplie.com","type":"CNAME","class":"IN","ttl":5,"tld":"com","sld":"daplie","sub":"mailapp","data":"mandrillapp.com"}
, {"zone":"daplie.com","name":"hero.daplie.com","type":"A","class":"IN","ttl":5,"tld":"com","sld":"daplie","sub":"hero","address":"138.197.54.15"}
, {"zone":"daplie.com","name":"mattermost.daplie.com","type":"A","class":"IN","ttl":5,"tld":"com","sld":"daplie","sub":"mattermost","address":"23.228.168.108"}
, {"zone":"daplie.com","name":"china-ftp.daplie.com","type":"A","class":"IN","ttl":5,"tld":"com","sld":"daplie","sub":"china-ftp","address":"210.5.144.209"}
, {"zone":"daplie.com","name":"shop.daplie.com","type":"A","class":"IN","ttl":5,"tld":"com","sld":"daplie","sub":"shop","address":"23.227.38.32"}
, {"zone":"daplie.com","name":"shop.daplie.com","type":"CNAME","class":"IN","ttl":5,"tld":"com","sld":"daplie","sub":"shop","data":"shops.myshopify.com"}
, {"zone":"daplie.com","name":"new.daplie.com","type":"A","class":"IN","ttl":5,"tld":"com","sld":"daplie","sub":"new","address":"23.228.168.108"}
, {"zone":"daplie.com","name":"media.daplie.com","type":"A","class":"IN","ttl":5,"tld":"com","sld":"daplie","sub":"media","address":"45.56.59.142"}
, {"zone":"daplie.com","name":"domains.daplie.com","type":"A","class":"IN","ttl":5,"tld":"com","sld":"daplie","sub":"domains","address":"23.228.168.108"}
, {"zone":"daplie.com","name":"labs.daplie.com","type":"A","class":"IN","ttl":5,"tld":"com","sld":"daplie","sub":"labs","address":"23.228.168.108"}
, {"zone":"daplie.domains","name":"daplie.domains","type":"NS","class":"IN","ttl":5,"tld":"domains","sld":"daplie","sub":"ns1","data":"ns1.daplie.domains"}
, {"zone":"daplie.domains","name":"daplie.domains","type":"NS","class":"IN","ttl":5,"tld":"domains","sld":"daplie","sub":"ns2","data":"ns2.daplie.domains"}
, {"zone":"daplie.domains","name":"daplie.domains","type":"NS","class":"IN","ttl":5,"tld":"domains","sld":"daplie","sub":"ns3","data":"ns3.daplie.domains"}
, {"zone":"daplie.domains","name":"ns1.daplie.domains","type":"A","class":"IN","ttl":5,"tld":"domains","sld":"daplie","sub":"ns1","address":"45.55.1.122"}
, {"zone":"daplie.domains","name":"ns2.daplie.domains","type":"A","class":"IN","ttl":5,"tld":"domains","sld":"daplie","sub":"ns2","address":"45.55.254.197"}
, {"zone":"daplie.domains","name":"ns3.daplie.domains","type":"A","class":"IN","ttl":5,"tld":"domains","sld":"daplie","sub":"ns3","address":"159.203.25.112"}
, {"zone":"daplie.domains","name":"leo.devices.daplie.domains","type":"A","class":"IN","ttl":5,"tld":"domains","sld":"daplie","sub":"leo.devices","address":"45.56.59.142"}
, {"zone":"daplie.domains","name":"daplie.domains","type":"A","class":"IN","ttl":5,"tld":"domains","sld":"daplie","sub":"","address":"45.56.59.142","aname":"leo.devices.daplie.domains"}
, {"zone":"daplie.domains","name":"daplie.domains","type":"A","class":"IN","ttl":5,"tld":"domains","sld":"daplie","sub":"www","address":"45.56.59.142","aname":"leo.devices.daplie.domains"}
]
}

View File

@ -1,12 +1,13 @@
'use strict';
module.exports = {
"primaryNameservers": [ 'localhost' ] // 'ns1.vanity-dns.org'
module.exports =
{
"primaryNameservers": [ "localhost" ] // 'ns1.vanity-dns.org'
, "domains": [
{ "id": "example.com", "revokedAt": 0 }
, { "id": "smith.example.com", "revokedAt": 0 }
, { "id": "in-delegated.example.com", "revokedAt": 0 }
, { "id": "john.smith.example.com", "revokedAt": 0, "vanityNs": [ 'ns1.dns-server.net', 'ns2.dns-server.net' ] }
, { "id": "john.smith.example.com", "revokedAt": 0, "vanityNs": [ "ns1.dns-server.net", "ns2.dns-server.net" ] }
// test and probably remove
//, { "id": "out-delegated.example.com", "revokedAt": 0 }
]

98
samples/db.json Normal file
View File

@ -0,0 +1,98 @@
{
"primaryNameservers": [ "localhost" ]
, "domains": [
{ "id": "example.com", "revokedAt": 0 }
, { "id": "smith.example.com", "revokedAt": 0 }
, { "id": "in-delegated.example.com", "revokedAt": 0 }
, { "id": "john.smith.example.com", "revokedAt": 0, "vanityNs": [ "ns1.dns-server.net", "ns2.dns-server.net" ] }
]
, "records": [
{ "zone": "example.com", "name": "example.com", "tld": "com", "sld": "example", "sub": ""
, "type": "A", "address": "1.2.3.4", "aname": "fido.devices.example.com" }
, { "zone": "example.com", "name": "example.com", "tld": "com", "sld": "example", "sub": ""
, "type": "MX", "priority": 10, "exchange": "mxa.example.org" }
, { "zone": "example.com", "name": "example.com", "tld": "com", "sld": "example", "sub": ""
, "type": "MX", "priority": 10, "exchange": "mxb.example.org" }
, { "zone": "example.com", "name": "example.com", "tld": "com", "sld": "example", "sub": ""
, "type": "SRV", "priority": 10, "weight": 20, "port": 65065, "target": "spot.devices.example.com" }
, { "zone": "example.com", "name": "example.com", "tld": "com", "sld": "example", "sub": ""
, "type": "TXT", "data": [ "foo bar baz" ] }
, { "zone": "example.com", "name": "example.com", "tld": "com", "sld": "example", "sub": ""
, "type": "TXT", "data": [ "foo", "bar", "baz" ] }
, { "zone": "example.com", "name": "a.example.com", "tld": "com", "sld": "example", "sub": "a"
, "type": "A", "address": "4.3.2.1" }
, { "zone": "example.com", "name": "aaaa.example.com", "tld": "com", "sld": "example", "sub": "aaaa"
, "type": "AAAA", "address": "::1" }
, { "zone": "example.com", "name": "aname.example.com", "tld": "com", "sld": "example", "sub": "aname"
, "type": "A", "aname": "amazon.com" }
, { "zone": "example.com", "name": "devname.example.com", "tld": "com", "sld": "example", "sub": "devname"
, "type": "A", "address": "1.2.3.4", "aname": "fido.devices.example.com" }
, { "zone": "example.com", "name": "cname.example.com", "tld": "com", "sld": "example", "sub": "cname"
, "type": "CNAME", "data": "example.com" }
, { "zone": "example.com", "name": "mx.example.com", "tld": "com", "sld": "example", "sub": "mx"
, "type": "MX", "priority": 10, "exchange": "mxa.example.org" }
, { "zone": "example.com", "name": "mx.example.com", "tld": "com", "sld": "example", "sub": "mx"
, "type": "MX", "priority": 10, "exchange": "mxb.example.org" }
, { "zone": "example.com", "name": "srv.example.com", "tld": "com", "sld": "example", "sub": "srv"
, "type": "SRV", "priority": 10, "weight": 20, "port": 65065, "target": "spot.devices.example.com" }
, { "zone": "example.com", "name": "txt.example.com", "tld": "com", "sld": "example", "sub": "txt"
, "type": "TXT", "data": [ "foo bar baz" ] }
, { "zone": "example.com", "name": "mtxt.example.com", "tld": "com", "sld": "example", "sub": "mtxt"
, "type": "TXT", "data": [ "foo", "bar", "baz" ] }
, { "zone": "example.com", "type": "NS", "name": "ns.example.com"
, "tld": "com", "sld": "example", "sub": "ns", "data": "ns1.vanity-dns.org" }
, { "zone": "example.com", "type": "NS", "name": "ns.example.com"
, "tld": "com", "sld": "example", "sub": "ns", "data": "ns2.vanity-dns.org" }
, { "zone": "example.com", "name": "www.example.com", "tld": "com", "sld": "example", "sub": "www"
, "type": "A", "address": "1.2.3.4", "aname": "fido.devices.example.com" }
, { "zone": "example.com", "name": "email.example.com", "tld": "com", "sld": "example", "sub": "email"
, "type": "CNAME", "data": "mailgun.org" }
, { "zone": "example.com", "name": "*.wild.example.com", "tld": "com", "sld": "example", "sub": "*.wild"
, "type": "A", "address": "12.34.56.78" }
, { "zone": "example.com", "name": "exists.wild.example.com", "tld": "com", "sld": "example", "sub": "exists.wild"
, "type": "A", "address": "123.0.0.45" }
, { "zone": "example.com", "type": "NS", "name": "out-delegated.example.com"
, "tld": "com", "sld": "example", "sub": "out-delegated", "data": "ns1.vanity-dns.org" }
, { "zone": "example.com", "type": "NS", "name": "out-delegated.example.com"
, "tld": "com", "sld": "example", "sub": "out-delegated", "data": "ns2.vanity-dns.org" }
, { "zone": "example.com", "type": "NS", "name": "in-delegated.example.com"
, "tld": "com", "sld": "example", "sub": "in-delegated", "data": "localhost" }
, { "zone": "example.com", "name": "fido.devices.example.com", "tld": "com", "sld": "example", "sub": "fido.devices"
, "device": "abcdef123"
, "type": "ANAME", "address": "1.2.3.4" }
, { "zone": "example.com", "type": "NS", "name": "smith.example.com"
, "tld": "com", "sld": "example", "sub": "smith", "data": "ns1.vanity-dns.org" }
, { "zone": "example.com", "name": "smith.example.com", "tld": "com", "sld": "example", "sub": "smith"
, "type": "NS", "data": "ns2.vanity-dns.org" }
, { "zone": "smith.example.com", "name": "smith.example.com", "tld": "example.com", "sld": "smith", "sub": ""
, "type": "A", "address": "45.56.59.142", "aname": "rex.devices.smith.example.com" }
, { "zone": "smith.example.com", "name": "www.smith.example.com", "tld": "example.com", "sld": "smith", "sub": "www"
, "type": "CNAME", "data": "smith.example.com" }
, { "zone": "smith.example.com", "name": "john.smith.example.com", "tld": "example.com", "sld": "smith", "sub": "john"
, "type": "NS", "data": "ns1.vanity-dns.org" }
, { "zone": "smith.example.com", "name": "john.smith.example.com", "tld": "example.com", "sld": "smith", "sub": "john"
, "type": "NS", "data": "ns2.vanity-dns.org" }
, { "zone": "smith.example.com", "name": "*.smith.example.com", "tld": "example.com", "sld": "smith", "sub": "*"
, "type": "A", "address": "45.56.59.142", "aname": "rex.devices.smith.example.com" }
, { "zone": "smith.example.com", "name": "exception.john.smith.example.com", "tld": "example.com", "sld": "smith", "sub": "exception.john"
, "type": "A", "address": "45.56.59.142", "aname": "rex.devices.smith.example.com" }
, { "zone": "john.smith.example.com", "name": "john.smith.example.com", "tld": "smith.example.com", "sld": "john", "sub": ""
, "type": "A", "address": "45.56.59.142", "aname": "rex.devices.smith.example.com" }
]
}

23
samples/hellabit.enom.sh Normal file
View File

@ -0,0 +1,23 @@
daplie domains:list # shows hellabit.com in my list of domains
# for hellabit.com to lookup itself (chicken and egg problem),
# we must first set glue records
daplie glue:set -n ns1.hellabit.com --tld com -a 138.197.72.1
daplie glue:set -n ns2.hellabit.com --tld com -a 162.243.136.134
# now we can set hellabit.com to use nsx.hellabit.com nameservers
daplie ns:set -n hellabit.com --tld com --nameservers ns1.hellabit.com,ns2.hellabit.com
# now we can't use the dns tools because digd.js does not (yet) have oauth3 compatible apis
# these won't work
# daplie devices:set -d sfo2.devices.hellabit.com -a 138.197.216.176
# daplie devices:attach -d sfo2.devices.hellabit.com -n hellabit.com
# daplie devices:attach -d sfo2.devices.hellabit.com -n www.hellabit.com
# now you can test that your hard work worked
# < ==== NOTE ==== > It may take a few minutes before this starts to work as you'd expect
dig +trace ns1.hellabit.com
dig +trace ns2.hellabit.com
dig +trace hellabit.com
dig +trace www.hellabit.com

73
samples/parse-records.js Normal file
View File

@ -0,0 +1,73 @@
'use strict';
/*
* parses files in the format "type|domain|value|json\n"
*/
var filename = process.argv[2];
var fs = require('fs');
var file = fs.readFileSync(filename, 'utf8');
var zone = 'daplie.com';
file.trim().split(/\n/).forEach(function (line) {
var parts = line.split(/\|/);
var type = parts[0];
var name = parts[1] || zone;
var domain = name.split('.');
var thing = parts[2];
var json = JSON.parse(parts[3]);
var address; // A, AAAA
var flag, tag, value; // CAA
var data; // CNAME, NS, PTR, ... TXT (as array)
var priority; // MX, SRV
var exchange; // MX
var weight, port, target; // SRV
if (/^(A|AAAA)$/.test(type)) {
address = thing;
}
if (/^(CNAME|NS|PTR)$/.test(type)) {
data = thing;
}
if (/^(TXT)$/.test(type)) {
data = [ thing ];
}
if (/^(MX)$/.test(type)) {
exchange = thing;
}
if (/^(MX|SRV)$/.test(type)) {
priority = json.priority || 10;
}
var obj = {
zone: zone
, name: name
, type: type
, class: 'IN'
, ttl: 5 // 12 hours 43200 // 3 days 259200
, tld: domain.pop()
, sld: domain.pop()
, sub: domain.join('.') || undefined
, address: address
, aname: undefined
, flag: flag
, tag: tag
, value: value
, data: data
, exchange: exchange
, priority: priority
, weight: weight
, port: port
, target: target
};
console.log(",", JSON.stringify(obj));
});

View File

@ -83,6 +83,7 @@ $digcmd @$ns -p $port NS in-delegated.example.com
# should return records in ANSWER section, nothing else
$digcmd @$ns -p $port A example.com
$digcmd @$ns -p $port AAAA example.com
$digcmd @$ns -p $port CNAME example.com
$digcmd @$ns -p $port MX example.com
$digcmd @$ns -p $port SRV example.com
$digcmd @$ns -p $port TXT example.com
@ -101,6 +102,8 @@ $digcmd @$ns -p $port NS doesntexist.example.com
# should return record of correct type in ANSWER section, nothing else
$digcmd @$ns -p $port A a.example.com
$digcmd @$ns -p $port AAAA aaaa.example.com
$digcmd @$ns -p $port CNAME cname.example.com
$digcmd @$ns -p $port A cname.example.com # Special Case, should return CNAME record
$digcmd @$ns -p $port MX mx.example.com
$digcmd @$ns -p $port SRV srv.example.com
$digcmd @$ns -p $port TXT txt.example.com