From 4e0a37c0f5d01573724584db0ff7e68e3cdc63f5 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Mon, 2 Oct 2017 16:43:58 -0600 Subject: [PATCH] check dns0x20 support by default --- README.md | 5 ++++- bin/dig.js | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++-- package.json | 2 ++ 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4763caf..6374fe2 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ dig.js | [dns-suite](https://git.daplie.com/Daplie/dns-suite) | **dig.js** | [digd.js](https://git.daplie.com/Daplie/digd.js) | Create and capture DNS and mDNS query and response packets to disk as binary and/or JSON. -Options are similar to the Unix `dig` command. +Options are similar to the Unix `dig` command. Supports dns0x20 security checking. Install ------- @@ -85,5 +85,8 @@ Options +norecurse Set `rd` flag to 0. Do not request recursion +aaonly Set `aa` flag to 1. +--norecase Disable dns0x20 security checking (mixed casing). See https://dyn.com/blog/use-of-bit-0x20-in-dns-labels/ +--recase Print the dns0x20 casing as-is rather than converting it back to lowercase. This is the default when explicitly using mixed case. + --debug verbose output ``` diff --git a/bin/dig.js b/bin/dig.js index bf99fdf..97f97fc 100755 --- a/bin/dig.js +++ b/bin/dig.js @@ -22,6 +22,8 @@ cli.parse({ //, 'serve': [ 's', 'path to json file with array of responses to issue for given queries', 'string' ] , 'type': [ 't', 'type (defaults to ANY for dns and PTR for mdns)', 'string' ] , 'query': [ 'q', 'a superfluous explicit option to set the query as a command line flag' ] +, 'norecase': [ false, 'Disable dns0x20 security checking (mixed casing). See https://dyn.com/blog/use-of-bit-0x20-in-dns-labels/' ] +, 'recase': [ false, "Print the dns0x20 casing as-is rather than converting it back to lowercase. This is the default when explicitly using mixed case." ] }); var common = require('../common.js'); @@ -109,6 +111,20 @@ cli.main(function (args, cli) { } } + if (cli.query !== cli.query.toLowerCase()) { + cli.norecase = true; + } + + if (!cli.norecase) { + cli.casedQuery = cli.query.split('').map(function (ch) { + // dns0x20 takes advantage of the fact that the binary operation for toUpperCase is + // ch = ch | 0x20; + return Math.round(Math.random()) % 2 ? ch : ch.toUpperCase(); + }).join(''); + } else { + cli.casedQuery = cli.query; + } + if (!cli.type) { cli.type = cli.t = 'ANY'; } @@ -141,7 +157,7 @@ cli.main(function (args, cli) { , rcode: 0 // NA } , question: [ - { name: cli.query + { name: cli.casedQuery , typeName: cli.type , className: cli.class } @@ -181,6 +197,40 @@ cli.main(function (args, cli) { console.log(packet); } + packet.question.forEach(function (q) { + // if (-1 === q.name.indexOf(cli.casedQuery)) + if (q.name !== cli.casedQuery) { + console.log(";; Warning: DNS 0x20 security not implemented (or packet spoofed). Queried '" + cli.casedQuery + "' but got response for '" + q.name + "'."); + } + }); + if (!cli.norecase && !cli.recase) { + [ 'question', 'answer', 'authority', 'additional' ].forEach(function (group) { + (packet[group]||[]).forEach(function (a) { + var an = a.name; + var i = cli.query.toLowerCase().indexOf(a.name.toLowerCase()); // answer is something like ExAMPle.cOM and query was wWw.ExAMPle.cOM + var j = a.name.toLowerCase().indexOf(cli.query.toLowerCase()); // answer is something like www.ExAMPle.cOM and query was ExAMPle.cOM + + // it's important to note that these should only relpace changes in casing that we expected + // any abnormalities should be left intact to go "huh?" about + // TODO detect abnormalities? + if (-1 !== i) { + // "EXamPLE.cOm".replace("wWw.EXamPLE.cOm".substr(4), "www.example.com".substr(4)) + a.name = a.name.replace(cli.casedQuery.substr(i), cli.query.substr(i)); + } else { + // "www.example.com".replace("EXamPLE.cOm", "example.com") + a.name = a.name.substr(0, j) + a.name.substr(j).replace(cli.casedQuery, cli.query); + } + + // NOTE: right now this assumes that anything matching the query matches all the way to the end + // it does not handle the case of a record for example.com.uk being returned in response to a query for www.example.com correctly + // (but I don't think it should need to) + if (a.name.length !== an.length) { + console.error("[ERROR] '" + an + "' != '" + a.length + "'"); + } + }); + }); + } + console.log(';; Got answer:'); dig.logQuestion(packet); @@ -236,7 +286,7 @@ cli.main(function (args, cli) { console.log(''); if (!cli.nocmd) { - console.log('; <<>> dig.js ' + 'v0.0.0' + ' <<>> ' + process.argv.slice(2).join(' ')); + console.log('; <<>> dig.js ' + 'v0.0.0' + ' <<>> ' + process.argv.slice(2).join(' ').replace(cli.query, cli.casedQuery)); console.log(';; global options: +cmd'); } diff --git a/package.json b/package.json index be5266f..9525f51 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,8 @@ "dig", "dns", "mdns", + "dns0x20", + "0x20", "lint", "capture", "create",