WIP dns server

This commit is contained in:
AJ ONeal 2017-09-25 18:14:27 -06:00
parent 083df5755b
commit fcaafbf8b9
4 changed files with 106 additions and 32 deletions

View File

@ -4,10 +4,10 @@ var cli = require('cli');
var dig = require('../dns-request'); var dig = require('../dns-request');
var dgram = require('dgram'); var dgram = require('dgram');
var dnsjs = require('dns-suite'); var dnsjs = require('dns-suite');
var hexdump = require('hexdump.js').hexdump;
var crypto = require('crypto'); var crypto = require('crypto');
var common = require('../common'); var common = require('../common');
var defaultNameservers = require('dns').getServers(); var defaultNameservers = require('dns').getServers();
var hexdump;
cli.parse({ cli.parse({
// 'b': [ false, 'set source IP address (defaults to 0.0.0.0)', 'string' ] // 'b': [ false, 'set source IP address (defaults to 0.0.0.0)', 'string' ]
@ -81,18 +81,37 @@ cli.main(function (args, cli) {
handlers.onMessage = function (nb, rinfo) { handlers.onMessage = function (nb, rinfo) {
var queryAb = nb.buffer.slice(nb.byteOffset, nb.byteOffset + nb.byteLength); var queryAb = nb.buffer.slice(nb.byteOffset, nb.byteOffset + nb.byteLength);
var query = dnsjs.DNSPacket.parse(queryAb); var query;
var newQuery;
var count; var count;
try {
query = dnsjs.DNSPacket.parse(queryAb);
} catch(e) {
// TODO log bad queries (?)
console.error("Could not parse DNS query, ignoring.");
try {
hexdump = require('hexdump.js').hexdump;
console.error(hexdump(queryAb));
console.error('');
} catch(e) {
// ignore
}
return;
}
if (cli.debug) { if (cli.debug) {
console.log(''); console.log('');
console.log('DNS Question:'); console.log('DNS Question:');
console.log(''); console.log('');
console.log(query); console.log(query);
console.log(''); console.log('');
try {
hexdump = require('hexdump.js').hexdump;
console.log(hexdump(queryAb)); console.log(hexdump(queryAb));
console.log(''); console.log('');
} catch(e) {
// ignore
}
} }
dig.logQuestion(query); dig.logQuestion(query);
@ -138,17 +157,18 @@ cli.main(function (args, cli) {
//common.writeResponse(opts, query, nb, packet); //common.writeResponse(opts, query, nb, packet);
} }
function sendEmptyResponse(query) { function sendEmptyResponse(query, nx) {
var newQuery = { var newAb;
var emptyResp = {
header: { header: {
id: query.header.id // require('crypto').randomBytes(2).readUInt16BE(0) id: query.header.id // require('crypto').randomBytes(2).readUInt16BE(0)
, qr: 1 , qr: 1
, opcode: 0 , opcode: 0
, aa: 0 // TODO maybe , aa: 0 // TODO it may be authoritative
, tc: 0 , tc: 0
, rd: query.header.rd , rd: query.header.rd
, ra: cli.norecurse ? 0 : 1 , ra: cli.norecurse ? 0 : 1 // TODO is this bit dependent on the rd bit?
, rcode: 0 // no error , rcode: nx ? 3 : 0 // no error
} }
, question: [] , question: []
, answer: [] , answer: []
@ -156,7 +176,7 @@ cli.main(function (args, cli) {
, additional: [] , additional: []
}; };
query.question.forEach(function (q) { query.question.forEach(function (q) {
newQuery.question.push({ emptyResp.question.push({
name: q.name name: q.name
, type: q.type , type: q.type
, typeName: q.typeName , typeName: q.typeName
@ -164,26 +184,52 @@ cli.main(function (args, cli) {
, className: q.className , className: q.className
}); });
}); });
server.send(dnsjs.DNSPacket.write(newQuery), rinfo.port, rinfo.address, function () {
console.log('[DEV] response sent'); try {
newAb = dnsjs.DNSPacket.write(emptyResp);
} catch(e) {
console.error("Could not write DNS response");
console.error(emptyResp);
return;
}
server.send(newAb, rinfo.port, rinfo.address, function () {
console.log('[DEV] response sent (empty)');
});
}
function sendResponse(newPacket) {
var newAb;
try {
newAb = dnsjs.DNSPacket.write(newPacket);
} catch(e) {
console.error("Could not write DNS response");
console.error(newPacket);
return;
}
server.send(newAb, rinfo.port, rinfo.address, function () {
console.log('[DEV] response sent (local query)');
}); });
} }
function recurse() { function recurse() {
if (!query.header.rd) { if (!query.header.rd) {
console.log("[Could not answer. Sent empty response.]"); console.log("[Could not answer. Sent empty response.]");
sendEmptyResponse(query); sendEmptyResponse(query, true);
return; return;
} }
if (cli.norecurse) { if (cli.norecurse) {
console.log("[Could not answer. Sent empty response.]"); console.log("[Could not answer. Sent empty response.]");
sendEmptyResponse(query); sendEmptyResponse(query, true);
return; return;
} }
// ANY, A, AAAA, CNAME, MX, NAPTR, NS, PTR, SOA, SRV, TXT // TODO newQuery
newQuery = {
var newResponse = {
header: { header: {
id: query.header.id // require('crypto').randomBytes(2).readUInt16BE(0) id: query.header.id // require('crypto').randomBytes(2).readUInt16BE(0)
, qr: 0 , qr: 0
@ -200,7 +246,7 @@ cli.main(function (args, cli) {
, additional: [] , additional: []
}; };
query.question.forEach(function (q) { query.question.forEach(function (q) {
newQuery.question.push({ newResponse.question.push({
name: q.name name: q.name
, type: q.type , type: q.type
, typeName: q.typeName , typeName: q.typeName
@ -209,9 +255,19 @@ cli.main(function (args, cli) {
}); });
function updateCount() { function updateCount() {
var newAb;
count -= 1; count -= 1;
if (!count) { if (!count) {
server.send(dnsjs.DNSPacket.write(newQuery), rinfo.port, rinfo.address, function () { try {
newAb = dnsjs.DNSPacket.write(newResponse);
} catch(e) {
console.error("Could not write DNS response");
console.error(newResponse);
return;
}
server.send(newAb, rinfo.port, rinfo.address, function () {
console.log('[DEV] response sent'); console.log('[DEV] response sent');
}); });
} }
@ -225,29 +281,32 @@ cli.main(function (args, cli) {
(packet.answer||[]).forEach(function (a) { (packet.answer||[]).forEach(function (a) {
// TODO copy each relevant property // TODO copy each relevant property
console.log('ans', a); console.log('ans', JSON.stringify(a, null, 2));
newQuery.answer.push(a); newResponse.answer.push(a);
}); });
(packet.authority||[]).forEach(function (a) { (packet.authority||[]).forEach(function (a) {
// TODO copy each relevant property // TODO copy each relevant property
console.log('auth', a); console.log('auth', JSON.stringify(a, null, 2));
newQuery.authority.push(a); newResponse.authority.push(a);
}); });
(packet.additional||[]).forEach(function (a) { (packet.additional||[]).forEach(function (a) {
// TODO copy each relevant property // TODO copy each relevant property
console.log('add', a); console.log('add', JSON.stringify(a, null, 2));
newQuery.additional.push(a); newResponse.additional.push(a);
}); });
updateCount(); updateCount();
} }
, onListening: function () {} , onListening: function () {}
, onSent: function (res) { , onSent: function (/*res*/) {
/*
if (cli.debug) { if (cli.debug) {
console.log(''); console.log('');
console.log('request sent to', res.nameserver); console.log('request sent to', res.nameserver);
} }
*/
console.log('[DEV] response sent (recurse)');
} }
, onTimeout: function (res) { , onTimeout: function (res) {
console.log(";; [" + q.name + "] connection timed out; no servers could be reached"); console.log(";; [" + q.name + "] connection timed out; no servers could be reached");
@ -276,7 +335,11 @@ cli.main(function (args, cli) {
} }
// TODO get local answer first, if available // TODO get local answer first, if available
recurse(); require('../dns-store').query(query, function (err, resp) {
if (err) { recurse(); return; }
sendResponse(resp);
});
}; };

View File

@ -27,11 +27,10 @@ module.exports = {
, 'PTR': function (q) { , 'PTR': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.data); console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.data);
} }
/*
, 'SOA': function (q) { , 'SOA': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.data); // no ';' in authority section?
console.log('' + q.name + '.', q.ttl, q.className, q.typeName, q.name_server, q.email_addr, q.sn, q.ref, q.ret, q.ex, q.nx);
} }
*/
, 'SRV': function (q) { , 'SRV': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.priority + ' ' + q.weight + ' ' + q.port + ' ' + q.target); console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.priority + ' ' + q.weight + ' ' + q.port + ' ' + q.target);
} }

10
dns-store.js Normal file
View File

@ -0,0 +1,10 @@
(function () {
'use strict';
module.exports.query = function (query, cb) {
process.nextTick(function () {
cb(new Error('No local lookup method for DNS records defined.'));
});
};
}());

View File

@ -40,7 +40,9 @@
"homepage": "https://git.daplie.com/Daplie/dig.js", "homepage": "https://git.daplie.com/Daplie/dig.js",
"dependencies": { "dependencies": {
"cli": "^1.0.1", "cli": "^1.0.1",
"dns-suite": "git+https://git@git.daplie.com/Daplie/dns-suite#v1.1.0", "dns-suite": "git+https://git@git.daplie.com/Daplie/dns-suite#v1.1.0"
"hexdump.js": "^1.0.2" },
"optionalDependencies": {
"hexdump.js": "git+https://git@git.daplie.com/Daplie/hexdump.js#master"
} }
} }