WIP dns server
This commit is contained in:
parent
083df5755b
commit
fcaafbf8b9
117
bin/digd.js
117
bin/digd.js
|
@ -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('');
|
||||||
console.log(hexdump(queryAb));
|
try {
|
||||||
console.log('');
|
hexdump = require('hexdump.js').hexdump;
|
||||||
|
console.log(hexdump(queryAb));
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.'));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
}());
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue