diff --git a/bin/digd.js b/bin/digd.js index 8c90a2d..bb67ffb 100644 --- a/bin/digd.js +++ b/bin/digd.js @@ -4,10 +4,10 @@ var cli = require('cli'); var dig = require('../dns-request'); var dgram = require('dgram'); var dnsjs = require('dns-suite'); -var hexdump = require('hexdump.js').hexdump; var crypto = require('crypto'); var common = require('../common'); var defaultNameservers = require('dns').getServers(); +var hexdump; cli.parse({ // '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) { var queryAb = nb.buffer.slice(nb.byteOffset, nb.byteOffset + nb.byteLength); - var query = dnsjs.DNSPacket.parse(queryAb); - var newQuery; + var query; 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) { console.log(''); console.log('DNS Question:'); console.log(''); console.log(query); console.log(''); - console.log(hexdump(queryAb)); - console.log(''); + try { + hexdump = require('hexdump.js').hexdump; + console.log(hexdump(queryAb)); + console.log(''); + } catch(e) { + // ignore + } } dig.logQuestion(query); @@ -138,17 +157,18 @@ cli.main(function (args, cli) { //common.writeResponse(opts, query, nb, packet); } - function sendEmptyResponse(query) { - var newQuery = { + function sendEmptyResponse(query, nx) { + var newAb; + var emptyResp = { header: { id: query.header.id // require('crypto').randomBytes(2).readUInt16BE(0) , qr: 1 , opcode: 0 - , aa: 0 // TODO maybe + , aa: 0 // TODO it may be authoritative , tc: 0 , rd: query.header.rd - , ra: cli.norecurse ? 0 : 1 - , rcode: 0 // no error + , ra: cli.norecurse ? 0 : 1 // TODO is this bit dependent on the rd bit? + , rcode: nx ? 3 : 0 // no error } , question: [] , answer: [] @@ -156,7 +176,7 @@ cli.main(function (args, cli) { , additional: [] }; query.question.forEach(function (q) { - newQuery.question.push({ + emptyResp.question.push({ name: q.name , type: q.type , typeName: q.typeName @@ -164,26 +184,52 @@ cli.main(function (args, cli) { , 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() { if (!query.header.rd) { console.log("[Could not answer. Sent empty response.]"); - sendEmptyResponse(query); + sendEmptyResponse(query, true); return; } if (cli.norecurse) { console.log("[Could not answer. Sent empty response.]"); - sendEmptyResponse(query); + sendEmptyResponse(query, true); return; } - // ANY, A, AAAA, CNAME, MX, NAPTR, NS, PTR, SOA, SRV, TXT - newQuery = { + // TODO newQuery + + var newResponse = { header: { id: query.header.id // require('crypto').randomBytes(2).readUInt16BE(0) , qr: 0 @@ -200,7 +246,7 @@ cli.main(function (args, cli) { , additional: [] }; query.question.forEach(function (q) { - newQuery.question.push({ + newResponse.question.push({ name: q.name , type: q.type , typeName: q.typeName @@ -209,9 +255,19 @@ cli.main(function (args, cli) { }); function updateCount() { + var newAb; count -= 1; + 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'); }); } @@ -225,29 +281,32 @@ cli.main(function (args, cli) { (packet.answer||[]).forEach(function (a) { // TODO copy each relevant property - console.log('ans', a); - newQuery.answer.push(a); + console.log('ans', JSON.stringify(a, null, 2)); + newResponse.answer.push(a); }); (packet.authority||[]).forEach(function (a) { // TODO copy each relevant property - console.log('auth', a); - newQuery.authority.push(a); + console.log('auth', JSON.stringify(a, null, 2)); + newResponse.authority.push(a); }); (packet.additional||[]).forEach(function (a) { // TODO copy each relevant property - console.log('add', a); - newQuery.additional.push(a); + console.log('add', JSON.stringify(a, null, 2)); + newResponse.additional.push(a); }); updateCount(); } , onListening: function () {} - , onSent: function (res) { + , onSent: function (/*res*/) { + /* if (cli.debug) { console.log(''); console.log('request sent to', res.nameserver); } + */ + console.log('[DEV] response sent (recurse)'); } , onTimeout: function (res) { 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 - recurse(); + require('../dns-store').query(query, function (err, resp) { + if (err) { recurse(); return; } + + sendResponse(resp); + }); }; diff --git a/common.js b/common.js index 2d663ec..4910f0e 100644 --- a/common.js +++ b/common.js @@ -27,11 +27,10 @@ module.exports = { , 'PTR': function (q) { console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.data); } - /* , '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) { console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.priority + ' ' + q.weight + ' ' + q.port + ' ' + q.target); } diff --git a/dns-store.js b/dns-store.js new file mode 100644 index 0000000..1387edd --- /dev/null +++ b/dns-store.js @@ -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.')); + }); +}; + +}()); diff --git a/package.json b/package.json index f2c2249..a9e2bd8 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,9 @@ "homepage": "https://git.daplie.com/Daplie/dig.js", "dependencies": { "cli": "^1.0.1", - "dns-suite": "git+https://git@git.daplie.com/Daplie/dns-suite#v1.1.0", - "hexdump.js": "^1.0.2" + "dns-suite": "git+https://git@git.daplie.com/Daplie/dns-suite#v1.1.0" + }, + "optionalDependencies": { + "hexdump.js": "git+https://git@git.daplie.com/Daplie/hexdump.js#master" } }