Compare commits

..

58 Commits
v1.0 ... master

Author SHA1 Message Date
AJ ONeal 25d150de07 update 2018-03-20 20:12:32 -06:00
AJ ONeal 90ed10c129 update 2018-03-20 20:11:57 -06:00
AJ ONeal 3bf715998d v1.3.8 2017-12-15 01:58:30 -07:00
AJ ONeal 6e7a0c57c8 allow empty string for query 2017-12-15 01:54:39 -07:00
AJ ONeal 22f5297582 bump 2017-11-04 21:19:58 -06:00
AJ ONeal 79154b093d add standard files 2017-11-04 21:12:20 -06:00
AJ ONeal 9ad274a0bb add mdig.js to bar 2017-11-02 23:47:58 -06:00
AJ ONeal 56048ad5d2 v1.3.6 2017-10-28 22:03:12 -06:00
AJ ONeal 39ba065ce0 Merge branch 'master' of ssh://git.coolaj86.com:22042/coolaj86/dig.js 2017-10-28 22:03:04 -06:00
AJ ONeal d5f5267c18 v1.3.5 2017-10-28 22:02:40 -06:00
AJ ONeal 3323379194 update urls 2017-10-28 22:02:27 -06:00
AJ ONeal 6ef8c7a475 Update 'README.md' 2017-10-29 03:40:05 +00:00
AJ ONeal f441c0cfc5 v1.3.4 2017-10-28 02:14:47 -06:00
AJ ONeal 7bba8f18e9 Merge branch 'master' into v1.3 2017-10-27 23:50:55 -06:00
AJ ONeal 875d288db3 whitespace 2017-10-27 23:50:37 -06:00
AJ ONeal c6ba3ccde6 update urls 2017-10-27 23:43:59 -06:00
AJ ONeal 1b79eb262f update urls 2017-10-27 23:41:34 -06:00
AJ ONeal 9373336675 add BUGS 2017-10-23 22:39:15 -06:00
AJ ONeal e279f753f8 v1.3.3 2017-10-23 20:53:19 -06:00
AJ ONeal 17b4d6d57f update git dependencies 2017-10-23 20:53:00 -06:00
AJ ONeal 44b4801ef6 use status codes by name 2017-10-18 15:26:07 -06:00
AJ ONeal 893574a3c2 Merge branch 'master' into v1 2017-10-09 15:11:42 -06:00
AJ ONeal 4c85be0ebf catch and report parse / pack errors 2017-10-09 15:11:32 -06:00
AJ ONeal aba58292ee Merge branch 'v1' of git.daplie.com:Daplie/dig.js into v1 2017-10-09 14:46:54 -06:00
AJ ONeal b6bc592e56 add type<num> support, fix recasing bug 2017-10-09 14:45:07 -06:00
AJ ONeal b3d7408db4 fix security check on id, note security concerns 2017-10-06 18:42:37 -06:00
AJ ONeal 6287f13f2b fix #4 don't force login in url 2017-10-06 10:25:29 -06:00
AJ ONeal 1533576023 v1.3.2 2017-10-02 17:11:03 -06:00
AJ ONeal 76fee917ea use lastIndexOf 2017-10-02 17:06:15 -06:00
AJ ONeal a7ebc7ce86 v1.3.1 2017-10-02 16:56:39 -06:00
AJ ONeal f8b2fb7ff8 fix false positive on 0x20 failure 2017-10-02 16:56:31 -06:00
AJ ONeal e1d0322ed2 v1.3.0 2017-10-02 16:50:47 -06:00
AJ ONeal 08c3791bec v1.2.3 2017-10-02 16:50:31 -06:00
AJ ONeal 510f8b93e7 made dns0x20 warning more prominent 2017-10-02 16:50:22 -06:00
AJ ONeal 4e0a37c0f5 check dns0x20 support by default 2017-10-02 16:43:58 -06:00
AJ ONeal 7bb2e84486 v1.2.2 2017-10-02 12:49:28 -06:00
AJ ONeal 0bf55e7589 move digd.js to own repo 2017-10-02 12:49:20 -06:00
AJ ONeal 51b05e9860 Update README.md 2017-10-02 11:52:50 -06:00
AJ ONeal 1b182f7c2f Update README.md 2017-10-02 11:50:02 -06:00
AJ ONeal 09d95fd88c Update README.md 2017-10-02 11:46:55 -06:00
AJ ONeal 0c71c39dc1 Update README.md 2017-10-02 11:30:32 -06:00
AJ ONeal fcaafbf8b9 WIP dns server 2017-09-25 18:14:27 -06:00
AJ ONeal 083df5755b small refactor 2017-09-25 15:12:58 -06:00
AJ ONeal 6d0f9b1588 WIP dns server, mov hexdump.js to own repo, add aaonly flag 2017-09-25 14:43:21 -06:00
AJ ONeal cdd490ec42 factor out printing of header and query 2017-09-20 13:27:53 -06:00
AJ ONeal 57ced95c0d add onClose event 2017-09-20 12:50:32 -06:00
AJ ONeal f979638090 Merge branch 'master' of git.daplie.com:Daplie/dig.js 2017-09-20 12:29:54 -06:00
AJ ONeal 03e3e527dc WIP recursively resolve 2017-09-20 12:29:43 -06:00
AJ ONeal de6fe5039b copy dig timeout message 2017-09-20 12:18:25 -06:00
AJ ONeal 36d7aaccbb udp6 and timeout fix 2017-09-18 18:06:27 -06:00
AJ ONeal 2f318607a1 factor out dns query 2017-09-18 17:40:11 -06:00
AJ ONeal 5dae97b60d add .jshintrc 2017-09-15 18:43:18 -06:00
AJ ONeal 01e753996a [WIP] began dns server 2017-09-15 18:43:02 -06:00
AJ ONeal 51daf2378d updated formatting, small refactoring 2017-09-15 18:42:32 -06:00
Tim Caswell 0cabe30b88 Fix dependency syntax and bump last version digit 2017-08-15 16:04:31 -05:00
Tim Caswell c7668e7381 Bump minor version to v1.2.0 and update dns-suite dependency 2017-04-13 15:28:42 -05:00
Tim Caswell f65cd74ea3 Add CAA to printer 2017-04-12 13:11:55 -05:00
AJ ONeal e3ccb16e42 v1.1.0 2017-03-31 00:08:51 -06:00
11 changed files with 614 additions and 635 deletions

16
.jshintrc Normal file
View File

@ -0,0 +1,16 @@
{ "node": true
, "browser": true
, "jquery": true
, "strict": true
, "indent": 2
, "onevar": true
, "laxcomma": true
, "laxbreak": true
, "eqeqeq": true
, "immed": true
, "undef": true
, "unused": true
, "latedef": true
, "curly": true
, "trailing": true
}

1
BUGS.txt Normal file
View File

@ -0,0 +1 @@
Currently allows labels to be terminated by rdata length. This was a mistake. They should always be terminated by a null character.

6
CHANGELOG Normal file
View File

@ -0,0 +1,6 @@
v1.3.6 - A suitable replacement for most of my uses for big
* Can capture dns packets in binary and JSON
* Parses common record types including:
* A,AAAA,CAA,CNAME,MX,NS,PTR,SOA,SRV,TXT
* Arbitrary TYPExxx support
* Known Bug: should error when label in rdata is not null terminated

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

@ -1,27 +1,34 @@
dig.js dig.js
====== ======
Create and capture DNS and mDNS query and response packets to disk as binary and/or JSON. | [dns-suite](https://git.coolaj86.com/coolaj86/dns-suite)
Options are similar to the Unix `dig` command. | **dig.js**
| [mdig.js](https://git.coolaj86.com/coolaj86/mdig.js)
| [digd.js](https://git.coolaj86.com/coolaj86/digd.js)
| Sponsored by [ppl](https://ppl.family)[.](https://dapliefounder.com)
Install with git 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. Supports dns0x20 security checking.
Install
------- -------
### with git
```bash ```bash
# Install the latest of v1.x # Install the latest of v1.x
npm install -g 'git+https://git@git.daplie.com/Daplie/dig.js.git#v1' npm install -g 'git+https://git.coolaj86.com/coolaj86/dig.js.git#v1'
``` ```
```bash ```bash
# Install exactly v1.0.0 # Install exactly v1.0.0
npm install -g 'git+https://git@git.daplie.com/Daplie/dig.js.git#v1.0.0' npm install -g 'git+https://git.coolaj86.com/coolaj86/dig.js.git#v1.0.0'
``` ```
Install without git ### without git
-------
Don't have git? Well, you can also bow down to the gods of the centralized, monopolized, concentrated, *dictator*net 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: (as we like to call it here at ppl Labs), if that's how you roll:
```bash ```bash
npm install -g dig.js npm install -g dig.js
@ -30,16 +37,14 @@ npm install -g dig.js
Usage Usage
----- -----
### Format
```bash ```bash
dig.js [TYPE] <domainname> dig.js [TYPE] <domainname>
``` ```
### Example **Example**:
```bash ```bash
dig.js daplie.com dig.js coolaj86.com
``` ```
### mDNS Browser Example ### mDNS Browser Example
@ -59,24 +64,40 @@ dig.js -p 5353 @224.0.0.251 PTR _services._dns-sd._udp.local +time=3
### Moar Examples ### Moar Examples
```bash ```bash
dig.js A daplie.com dig.js A coolaj86.com
dig.js -t A daplie.com dig.js @8.8.8.8 A coolaj86.com
dig.js @8.8.8.8 A daplie.com
``` ```
Options Options
------- -------
``` ```
--debug
--mdns
--output <path/to/file> write query and response(s) to disk with this path prefix (ex: ./samples/dns) --output <path/to/file> write query and response(s) to disk with this path prefix (ex: ./samples/dns)
-t <type> (superfluous) default ANY (mdns default: PTR)
--mdns Use mDNS port and nameserver address, and listen for multiple packets
-t <type> (superfluous) A, CNAME, MX, etc. Also supports -t type<decimal> for "unsupported" types. default ANY (mdns default: PTR)
-c <class> default IN -c <class> default IN
-p <port> default 53 (mdns default: 5353) (listener is random for DNS and 5353 for mDNS) -p <port> default 53 (mdns default: 5353) (listener is random for DNS and 5353 for mDNS)
-q <query> (superfluous) required (ex: daplie.com) -q <query> (superfluous) required (ex: coolaj86.com)
--nameserver <ns> alias of @<nameserver>
--timeout <ms> alias of +time=<seconds>, but in milliseconds
@<nameserver> specify the nameserver to use for DNS resolution (defaults to system defaults)
+time=<seconds> Sets the timeout for a query in seconds. +time=<seconds> Sets the timeout for a query in seconds.
+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
``` ```
Security Concerns
-----------------
The 16-bit `id` of the query must match that of the response.
Extra entropy is added by using `dns0x20`, the de facto standard for RanDOmCASiNg on the query which must be matched in the response.

View File

@ -1,10 +1,11 @@
#!/usr/bin/env node #!/usr/bin/env node
'use strict'; 'use strict';
var dnsjs = require('dns-suite'); var dig = require('../dns-request');
var cli = require('cli'); var cli = require('cli');
var hexdump = require('../hexdump'); var defaultNameservers = require('dns').getServers();
var crypto = require('crypto'); var typeRe = /^type\d+$/i;
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' ]
'class': [ 'c', 'class (defaults to IN)', 'string', 'IN' ] 'class': [ 'c', 'class (defaults to IN)', 'string', 'IN' ]
@ -15,243 +16,50 @@ cli.parse({
//, 'json': [ false, 'output results as json', 'string' ] //, 'json': [ false, 'output results as json', 'string' ]
//, 'lint': [ false, 'attack (in the metaphorical sense) a nameserver with all sorts of queries to test for correct responses', 'string', false ] //, 'lint': [ false, 'attack (in the metaphorical sense) a nameserver with all sorts of queries to test for correct responses', 'string', false ]
, 'mdns': [ false, "Alias for setting defaults to -p 5353 @224.0.0.251 -t PTR -q _services._dns-sd._udp.local and waiting for multiple responses", 'boolean', false ] , 'mdns': [ false, "Alias for setting defaults to -p 5353 @224.0.0.251 -t PTR -q _services._dns-sd._udp.local and waiting for multiple responses", 'boolean', false ]
, 'timeout': [ false, "Alias for setting defaults to -p 5353 @224.0.0.251 -t PTR -q _services._dns-sd._udp.local and waiting for multiple responses", 'boolean', false ] , 'timeout': [ false, "How long, in milliseconds, to wait for a response. Alias of +time=", 'int', false ]
, 'output': [ 'o', 'output prefix to use for writing query and response(s) to disk', 'file' ] , 'output': [ 'o', 'output prefix to use for writing query and response(s) to disk', 'file' ]
, 'port': [ 'p', 'port (defaults to 53 for dns and 5353 for mdns)', 'int' ] , 'port': [ 'p', 'port (defaults to 53 for dns and 5353 for mdns)', 'int' ]
, 'nameserver': [ false, 'the nameserver to use for DNS resolution (defaults to ' + defaultNameservers.join(',') + ')', 'string' ]
//, 'serve': [ 's', 'path to json file with array of responses to issue for given queries', 'string' ] //, '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' ] , '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' ] , 'query': [ 'q', 'a superfluous explicit option to set the query as a command line flag', 'string' ]
, '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 fs = require('fs'); var common = require('../common.js');
var dgram = require('dgram');
var commonTypes = [ 'A', 'AAAA', 'CNAME', 'MX', 'NS', 'PTR', 'SOA', 'SRV', 'TXT' ];
var commonPrinters = {
'ANY': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.data || q.rdata || 'unknown record type');
}
, 'A': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.address);
}
, 'AAAA': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.address);
}
, 'CNAME': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.data + '.');
}
, 'MX': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.priority + ' ' + q.exchange + '.');
}
, 'NS': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.data);
}
, '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);
}
*/
, 'SRV': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.priority + ' ' + q.weight + ' ' + q.port + ' ' + q.target);
}
, 'TXT': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, '"' + q.data.join('" "') + '"');
}
};
function writeQuery(opts, query, queryAb) {
var path = require('path');
var binname = query.question[0].name + '.' + query.question[0].typeName.toLowerCase() + '.query.bin';
var jsonname = query.question[0].name + '.' + query.question[0].typeName.toLowerCase() + '.query.json';
var binpath = opts.output + '.' + binname;
var jsonpath = opts.output + '.' + jsonname;
var json = JSON.stringify(query, null, 2);
if (-1 !== ['.', '/', '\\' ].indexOf(opts.output[opts.output.length -1])) {
binpath = path.join(opts.output, binname);
jsonpath = path.join(opts.output, jsonname);
}
fs.writeFile(binpath, Buffer.from(queryAb), null, function () {
console.log('wrote ' + queryAb.byteLength + ' bytes to ' + binpath);
});
fs.writeFile(jsonpath, json, null, function () {
console.log('wrote ' + json.length + ' bytes to ' + jsonpath);
});
}
var count = 0;
function writeResponse(opts, query, nb, packet) {
var path = require('path');
var binname = query.question[0].name + '.' + query.question[0].typeName.toLowerCase() + '.' + count + '.bin';
var jsonname = query.question[0].name + '.' + query.question[0].typeName.toLowerCase() + '.' + count + '.json';
var binpath = opts.output + '.' + binname;
var jsonpath = opts.output + '.' + jsonname;
var json = JSON.stringify(packet, null, 2);
if (-1 !== ['.', '/', '\\' ].indexOf(opts.output[opts.output.length -1])) {
binpath = path.join(opts.output, binname);
jsonpath = path.join(opts.output, jsonname);
}
count += 1;
fs.writeFile(binpath, nb, null, function () {
console.log('wrote ' + nb.byteLength + ' bytes to ' + binpath);
});
fs.writeFile(jsonpath, json, null, function () {
console.log('wrote ' + json.length + ' bytes to ' + jsonpath);
});
}
function request(query, opts) {
var queryAb = dnsjs.DNSPacket.write(query);
if (opts.debug) {
console.log('');
console.log('DNS Question:');
console.log('');
console.log(query);
console.log('');
console.log(hexdump(queryAb));
console.log('');
console.log(dnsjs.DNSPacket.parse(queryAb));
console.log('');
}
var handlers = {};
var server = dgram.createSocket({
type: 'udp4'
, reuseAddr: true
});
handlers.onError = function (err) {
console.error("error:", err.stack);
server.close();
};
handlers.onMessage = function (nb) {
var packet = dnsjs.DNSPacket.parse(nb.buffer.slice(nb.byteOffset, nb.byteOffset + nb.byteLength));
if (packet.id !== query.id) {
console.log('ignoring packet for ', packet.question[0].name);
}
if (!opts.mdns) {
server.close();
}
if (opts.debug) {
console.log('');
console.log('DNS Response:');
console.log(packet);
}
console.log('');
console.log('; <<>> dig.js ' + 'v0.0.0' + ' <<>> ' + query.question[0].name);
console.log(';; Got answer:');
console.log(';; ->>HEADER<<-');
console.log(JSON.stringify(packet.header));
console.log('');
console.log(';; QUESTION SECTION:');
packet.question.forEach(function (q) {
console.log(';' + q.name + '.', ' ', q.className, q.typeName);
});
function print(q) {
var printer = commonPrinters[q.typeName] || commonPrinters.ANY;
printer(q);
}
if (packet.answer.length) {
console.log('');
console.log(';; ANSWER SECTION:');
packet.answer.forEach(print);
}
if (packet.authority.length) {
console.log('');
console.log(';; AUTHORITY SECTION:');
packet.authority.forEach(print);
}
if (packet.additional.length) {
console.log('');
console.log(';; ADDITIONAL SECTION:');
packet.additional.forEach(print);
}
console.log('');
console.log(';; MSG SIZE rcvd: ' + nb.byteLength);
console.log('');
if (opts.output) {
console.log('');
writeQuery(opts, query, queryAb);
writeResponse(opts, query, nb, packet);
}
};
handlers.onListening = function () {
/*jshint validthis:true*/
var server = this;
var nameserver = opts.nameserver;
var nameservers;
var index;
if (!nameserver) {
nameservers = require('dns').getServers();
index = crypto.randomBytes(2).readUInt16BE(0) % nameservers.length;
nameserver = nameservers[index];
if (opts.debug) {
console.log(index, nameservers);
}
}
if (opts.mdns || '224.0.0.251' === opts.nameserver) {
server.setBroadcast(true);
server.addMembership(opts.nameserver);
}
if (opts.debug) {
console.log('');
console.log('Bound and Listening:');
console.log(server.address());
}
if (opts.debug) {
console.log("querying '" + nameserver + "':'" + opts.port + "'");
}
server.send(Buffer.from(queryAb), opts.port, nameserver, function () {
if (opts.debug) {
console.log('');
console.log('request sent');
}
});
};
server.on('error', handlers.onError);
server.on('message', handlers.onMessage);
server.on('listening', handlers.onListening);
// 0 dns request
// 53 dns server
// 5353 mdns
if (opts.mdns) {
server.bind(opts.port /*5353*/);
setTimeout(function () {
server.close();
}, opts.timeout || (5 * 1000));
}
else {
server.bind(0);
}
}
cli.main(function (args, cli) { cli.main(function (args, cli) {
cli.implicitType = cli.type;
cli.implicitQuery = cli.query;
args.forEach(function (arg) { args.forEach(function (arg) {
if (-1 !== commonTypes.concat([ 'ANY' ]).indexOf(arg.toUpperCase())) { if (typeRe.test(arg) || -1 !== common.types.concat([ 'ANY' ]).indexOf(arg.toUpperCase())) {
if (cli.type) { if (cli.implicitType) {
console.error("'type' was specified more than once"); console.error("'type' was specified more than once");
process.exit(1); process.exit(1);
return; return;
} }
cli.type = cli.t = arg.toUpperCase(); cli.implicitType = cli.t = arg.toUpperCase();
return;
}
if (arg === '+aaonly' || arg === '+aaflag') {
if (cli.aaonly) {
console.error("'+aaonly' was specified more than once");
process.exit(1);
return;
}
cli.aaonly = true;
return;
}
if (arg === '+norecurse') {
if (cli.norecurse) {
console.error("'+norecurse' was specified more than once");
process.exit(1);
return;
}
cli.norecurse = true;
return; return;
} }
@ -275,15 +83,41 @@ cli.main(function (args, cli) {
return; return;
} }
if (cli.query) { if ('string' === typeof cli.implicitQuery) {
console.error("'query' was specified more than once"); console.error("'query' was specified more than once or unrecognized flag: " + cli.implicitQuery + ", " + arg);
process.exit(1); process.exit(1);
return; return;
} }
cli.query = cli.q = arg; cli.implicitQuery = cli.q = arg;
}); });
// it can happen that a TLD is created with the name of a common type
if (!cli.type && cli.implicitType && !cli.implicitQuery) {
cli.implicitQuery = cli.implicitType;
cli.implicitType = null;
}
if ('string' === typeof cli.implicitQuery) {
cli.query = cli.implicitQuery;
}
if (cli.implicitType) {
cli.type = cli.implicitType;
}
if ('string' !== typeof cli.query) {
console.error('');
console.error('Usage:');
console.error('dig.js [@server] [TYPE] [domain]');
console.error('');
console.error('Example:');
console.error('dig.js daplie.com');
console.error('');
process.exit(1);
}
if (cli.query !== cli.query.toLowerCase()) {
cli.norecase = true;
}
if (cli.mdns) { if (cli.mdns) {
if (!cli.type) { if (!cli.type) {
cli.type = cli.t = 'PTR'; cli.type = cli.t = 'PTR';
@ -294,52 +128,222 @@ cli.main(function (args, cli) {
if (!cli.nameserver) { if (!cli.nameserver) {
cli.nameserver = '224.0.0.251'; cli.nameserver = '224.0.0.251';
} }
if (!cli.query) { if ('string' !== typeof cli.query) {
cli.query = '_services._dns-sd._udp.local'; cli.query = '_services._dns-sd._udp.local';
} }
if (!cli.timeout) { if (!cli.timeout) {
cli.timeout = 3000; cli.timeout = 3000;
} }
} else {
if (!cli.timeout) {
cli.timeout = 5000;
}
}
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) { if (!cli.type) {
cli.type = cli.t = 'ANY'; cli.type = cli.t = 'ANY';
} }
if (typeRe.test(cli.type)) {
cli.rawType = parseInt(cli.type.replace('type', ''), 10);
}
if (!cli.port) { if (!cli.port) {
cli.port = cli.p = 53; cli.port = cli.p = 53;
} }
if (!cli.class) { if (!cli.class) {
cli.class = cli.c = 'IN'; cli.class = cli.c = 'IN';
} }
if (!cli.query) {
console.error('');
console.error('Usage:');
console.error('dig.js [@server] [TYPE] [domain]');
console.error('');
console.error('Example:');
console.error('dig.js daplie.com');
console.error('');
process.exit(1);
}
var query = { var query = {
header: { header: {
id: require('crypto').randomBytes(2).readUInt16BE(0) id: require('crypto').randomBytes(2).readUInt16BE(0)
, qr: 0 , qr: 0
, opcode: 0 , opcode: 0
, aa: 0 // NA , aa: cli.aaonly ? 1 : 0 // NA
, tc: 0 // NA , tc: 0 // NA
, rd: 1 , rd: cli.norecurse ? 0 : 1
, ra: 0 // NA , ra: 0 // NA
, rcode: 0 // NA , rcode: 0 // NA
} }
, question: [ , question: [
{ name: cli.query { name: cli.casedQuery
, typeName: cli.type , type: cli.rawType
, typeName: cli.rawType ? undefined : cli.type
, className: cli.class , className: cli.class
} }
] ]
}; };
request(query, cli); var dnsjs = require('dns-suite');
var queryAb = dnsjs.DNSPacket.write(query);
var hexdump = require('hexdump.js').hexdump;
if (cli.debug) {
console.log('');
console.log('DNS Question:');
console.log('');
console.log(query);
console.log('');
console.log(hexdump(queryAb));
console.log('');
console.log(dnsjs.DNSPacket.parse(queryAb));
console.log('');
}
cli.onError = function (err) {
console.error("error:", err.stack);
};
cli.onMessage = function (nb) {
var packet = dnsjs.DNSPacket.parse(nb.buffer.slice(nb.byteOffset, nb.byteOffset + nb.byteLength));
var fail0x20;
if (packet.id !== query.id) {
console.error('[SECURITY] ignoring packet for \'' + packet.question[0].name + '\' due to mismatched id');
console.error(packet);
return;
}
if (cli.debug) {
console.log('');
console.log('DNS Response:');
console.log(packet);
}
packet.question.forEach(function (q) {
// if (-1 === q.name.lastIndexOf(cli.casedQuery))
if (q.name !== cli.casedQuery) {
fail0x20 = 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().lastIndexOf(a.name.toLowerCase()); // answer is something like ExAMPle.cOM and query was wWw.ExAMPle.cOM
var j = a.name.toLowerCase().lastIndexOf(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 if (-1 !== j) {
// "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] question / answer mismatch: '" + an + "' != '" + a.length + "'");
console.error(a);
}
});
});
}
if (fail0x20) {
console.warn("");
console.warn(";; Warning: DNS 0x20 security not implemented (or packet spoofed). Queried '" + cli.casedQuery + "' but got response for '" + fail0x20 + "'.");
console.warn("");
}
console.log(';; Got answer:');
dig.logQuestion(packet);
function print(q) {
var printer = common.printers[q.typeName] || common.printers.ANY;
printer(q);
}
if (packet.answer.length) {
console.log('');
console.log(';; ANSWER SECTION:');
packet.answer.forEach(print);
}
if (packet.authority.length) {
console.log('');
console.log(';; AUTHORITY SECTION:');
packet.authority.forEach(print);
}
if (packet.additional.length) {
console.log('');
console.log(';; ADDITIONAL SECTION:');
packet.additional.forEach(print);
}
console.log('');
console.log(';; Query time: ' + (Date.now() - cli._ts) + ' msec');
// ;; SERVER: 8.8.8.8#53(8.8.8.8)
console.log(';; SERVER: ' + cli._nameserver + '#' + cli.port + '(' + cli._nameserver + ')');
// TODO ;; WHEN: Fri Sep 15 18:25:53 2017
console.log(';; WHEN: ' + new Date().toString());
console.log(';; MSG SIZE rcvd: ' + nb.byteLength);
console.log('');
if (cli.output) {
console.log('');
common.writeQuery(cli, query, queryAb);
common.writeResponse(cli, query, nb, packet);
}
};
cli.onListening = function () {
/*jshint validthis:true*/
var server = this;
if (cli.debug) {
console.log('');
console.log('Bound and Listening:', server.type);
console.log(server.address());
}
// technicially this should be a seperate event
if (cli.debug) {
console.log("querying '" + server.nameserver + "':'" + cli.port + "'");
}
};
console.log('');
if (!cli.nocmd) {
console.log('; <<>> dig.js ' + 'v0.0.0' + ' <<>> ' + process.argv.slice(2).join(' ').replace(cli.query, cli.casedQuery));
console.log(';; global options: +cmd');
}
var opts = {
onError: cli.onError
, onMessage: cli.onMessage
, onListening: cli.onListening
, onSent: function (res) {
cli._nameserver = res.nameserver;
cli._ts = Date.now();
if (cli.debug) {
console.log('');
console.log('request sent to', res.nameserver);
}
}
, onTimeout: function (res) {
console.log(";; connection timed out; no servers could be reached");
console.log(";; [timed out after " + res.timeout + "ms and 1 tries]");
}
, onClose: function () {
console.log('');
}
, mdns: cli.mdns
, nameserver: cli.nameserver
, port: cli.port
, timeout: cli.timeout
};
dig.resolve(queryAb, opts);
}); });

View File

@ -1,331 +0,0 @@
#!/usr/bin/env node
'use strict';
var dnsjs = require('dns-suite');
var cli = require('cli');
var hexdump = require('../hexdump');
var crypto = require('crypto');
cli.parse({
// 'b': [ false, 'set source IP address (defaults to 0.0.0.0)', 'string' ]
'debug': [ false, 'more verbose output', 'boolean', false ]
//, 'insecure': [ false, 'turn off RaNDOm cAPS required for securing queries']
//, 'ipv4': [ '4', 'use ipv4 exclusively (defaults to false)', 'boolean', false ]
//, 'ipv6': [ '6', 'use ipv6 exclusively (defaults to false)', 'boolean', false ]
//, 'json': [ false, 'output results as json', 'string' ]
//, 'lint': [ false, 'attack (in the metaphorical sense) a nameserver with all sorts of queries to test for correct responses', 'string', false ]
, 'mdns': [ false, "Alias for setting defaults to -p 5353 @224.0.0.251 -t PTR -q _services._dns-sd._udp.local and waiting for multiple responses", 'boolean', false ]
, 'output': [ 'o', 'output prefix to use for writing query and response(s) to disk', 'file' ]
, 'port': [ 'p', 'port (defaults to 53 for dns and 5353 for mdns)', 'int' ]
//, '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' ]
});
var fs = require('fs');
var dgram = require('dgram');
var commonTypes = [ 'A', 'AAAA', 'CNAME', 'MX', 'NS', 'PTR', 'SOA', 'SRV', 'TXT' ];
var commonPrinters = {
'ANY': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.data || q.rdata || 'unknown record type');
}
, 'A': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.address);
}
, 'AAAA': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.address);
}
, 'CNAME': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.data + '.');
}
, 'MX': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.priority + ' ' + q.exchange + '.');
}
, 'NS': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.data);
}
, '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);
}
*/
, 'SRV': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.priority + ' ' + q.weight + ' ' + q.port + ' ' + q.target);
}
, 'TXT': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, '"' + q.data.join('" "') + '"');
}
};
function writeQuery(opts, query, queryAb) {
var path = require('path');
var binname = query.question[0].name + '.' + query.question[0].typeName.toLowerCase() + '.query.bin';
var jsonname = query.question[0].name + '.' + query.question[0].typeName.toLowerCase() + '.query.json';
var binpath = opts.output + '.' + binname;
var jsonpath = opts.output + '.' + jsonname;
var json = JSON.stringify(query, null, 2);
if (-1 !== ['.', '/', '\\' ].indexOf(opts.output[opts.output.length -1])) {
binpath = path.join(opts.output, binname);
jsonpath = path.join(opts.output, jsonname);
}
fs.writeFile(binpath, Buffer.from(queryAb), null, function () {
console.log('wrote ' + queryAb.byteLength + ' bytes to ' + binpath);
});
fs.writeFile(jsonpath, json, null, function () {
console.log('wrote ' + json.length + ' bytes to ' + jsonpath);
});
}
var count = 0;
function writeResponse(opts, query, nb, packet) {
var path = require('path');
var binname = query.question[0].name + '.' + query.question[0].typeName.toLowerCase() + '.' + count + '.bin';
var jsonname = query.question[0].name + '.' + query.question[0].typeName.toLowerCase() + '.' + count + '.json';
var binpath = opts.output + '.' + binname;
var jsonpath = opts.output + '.' + jsonname;
var json = JSON.stringify(packet, null, 2);
if (-1 !== ['.', '/', '\\' ].indexOf(opts.output[opts.output.length -1])) {
binpath = path.join(opts.output, binname);
jsonpath = path.join(opts.output, jsonname);
}
count += 1;
fs.writeFile(binpath, nb, null, function () {
console.log('wrote ' + nb.byteLength + ' bytes to ' + binpath);
});
fs.writeFile(jsonpath, json, null, function () {
console.log('wrote ' + json.length + ' bytes to ' + jsonpath);
});
}
function request(query, opts) {
var queryAb = dnsjs.DNSPacket.write(query);
if (opts.debug) {
console.log('');
console.log('DNS Question:');
console.log('');
console.log(query);
console.log('');
console.log(hexdump(queryAb));
console.log('');
console.log(dnsjs.DNSPacket.parse(queryAb));
console.log('');
}
var handlers = {};
var server = dgram.createSocket({
type: 'udp4'
, reuseAddr: true
});
handlers.onError = function (err) {
console.error("error:", err.stack);
server.close();
};
handlers.onMessage = function (nb) {
console.log("YOYOYO GOT MESSAGE");
var packet = dnsjs.DNSPacket.parse(nb.buffer.slice(nb.byteOffset, nb.byteOffset + nb.byteLength));
if (opts.debug) {
console.log('');
console.log('DNS Request:');
console.log(packet);
}
console.log('');
console.log('; <<>> dig.js ' + 'v0.0.0' + ' <<>> ' + query.question[0].name);
console.log(';; Got answer:');
console.log(';; ->>HEADER<<-');
console.log(JSON.stringify(packet.header));
console.log('');
console.log(';; QUESTION SECTION:');
packet.question.forEach(function (q) {
console.log(';' + q.name + '.', ' ', q.className, q.typeName);
});
/*
function print(q) {
var printer = commonPrinters[q.typeName] || commonPrinters.ANY;
printer(q);
}
if (packet.answer.length) {
console.log('');
console.log(';; ANSWER SECTION:');
packet.answer.forEach(print);
}
if (packet.authority.length) {
console.log('');
console.log(';; AUTHORITY SECTION:');
packet.authority.forEach(print);
}
if (packet.additional.length) {
console.log('');
console.log(';; ADDITIONAL SECTION:');
packet.additional.forEach(print);
}
console.log('');
console.log(';; MSG SIZE rcvd: ' + nb.byteLength);
console.log('');
*/
if (opts.output) {
console.log('');
writeQuery(opts, query, queryAb);
//writeResponse(opts, query, nb, packet);
}
};
handlers.onListening = function () {
console.log("YOYOYO ON LISTENING");
/*jshint validthis:true*/
var server = this;
var nameserver = opts.nameserver;
var nameservers;
var index;
if (!nameserver) {
nameservers = require('dns').getServers();
index = crypto.randomBytes(2).readUInt16BE(0) % nameservers.length;
nameserver = nameservers[index];
if (opts.debug) {
console.log(index, nameservers);
}
}
if (opts.mdns || '224.0.0.251' === opts.nameserver) {
server.setBroadcast(true);
server.addMembership(opts.nameserver);
}
if (opts.debug) {
console.log('');
console.log('Bound and Listening:');
console.log(server.address());
}
if (opts.debug) {
console.log('querying ' + nameserver + ':' + opts.port);
}
};
server.on('error', handlers.onError);
server.on('message', handlers.onMessage);
server.on('listening', handlers.onListening);
// 53 dns server
// 5353 mdns
console.log("YOYOYO BINDING ON", opts.port);
server.bind(opts.port);
}
cli.main(function (args, cli) {
args.forEach(function (arg) {
if (-1 !== commonTypes.indexOf(arg.toUpperCase())) {
if (cli.type) {
console.error("'type' was specified more than once");
process.exit(1);
return;
}
cli.type = cli.t = arg.toUpperCase();
return;
}
if (/^\+time=/.test(arg)) {
if (cli.timeout) {
console.error("'+time=' was specified more than once");
process.exit(1);
return;
}
cli.timeout = Math.round(parseInt(arg.replace(/\+time=/, ''), 10) * 1000);
return;
}
if (/^@/.test(arg)) {
if (cli.nameserver) {
console.error("'@server' was specified more than once");
process.exit(1);
return;
}
cli.nameserver = cli.n = arg.substr(1);
return;
}
if (cli.query) {
console.error("'query' was specified more than once");
process.exit(1);
return;
}
cli.query = cli.q = arg;
});
if (cli.mdns) {
if (!cli.type) {
cli.type = cli.t = 'PTR';
}
if (!cli.port) {
cli.port = cli.p = 5353;
}
if (!cli.nameserver) {
cli.nameserver = '224.0.0.251';
}
if (!cli.query) {
cli.query = '_services._dns-sd._udp.local';
}
if (!cli.timeout) {
cli.timeout = 3000;
}
}
if (!cli.type) {
cli.type = cli.t = 'A';
}
if (!cli.port) {
cli.port = cli.p = 53;
}
if (!cli.class) {
cli.class = cli.c = 'IN';
}
if (!cli.query) {
cli.query = 'example.com';
/*
console.error('');
console.error('Usage:');
console.error('digd.js [@server] [TYPE] [domain]');
console.error('');
console.error('Example:');
console.error('digd.js daplie.com');
console.error('');
process.exit(1);
*/
}
var query = {
header: {
id: crypto.randomBytes(2).readUInt16BE(0)
, qr: 0
, opcode: 0
, aa: 0 // NA
, tc: 0 // NA
, rd: 1
, ra: 0 // NA
, rcode: 0 // NA
}
, question: [
{ name: cli.query
, typeName: cli.type
, className: cli.class
}
]
};
if (!cli.daemon) {
request(query, cli);
return;
}
});

90
common.js Normal file
View File

@ -0,0 +1,90 @@
'use strict';
var fs = require('fs');
module.exports = {
types: [ 'A', 'AAAA', 'CNAME', 'MX', 'NS', 'PTR', 'SOA', 'SRV', 'TXT' ]
, printers: {
'ANY': function (q) {
console.log(';' + q.name + '.', q.ttl, (q.className || q.class), (q.typeName || ('type' + q.type)), q.data || q.rdata || 'unknown record type');
}
, 'A': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.address);
}
, 'AAAA': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.address);
}
, 'CNAME': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.data + '.');
}
, 'MX': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.priority + ' ' + q.exchange + '.');
}
, 'NS': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.data);
}
, 'PTR': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.data);
}
, 'SOA': function (q) {
// 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);
}
, 'TXT': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, '"' + q.data.join('" "') + '"');
}
, 'CAA': function (q) {
console.log(';' + q.name + '.', q.ttl, q.className, q.typeName, q.flag + ' ' + q.tag + ' "' + q.value + '"');
}
}
, writeQuery: function (opts, query, queryAb) {
var path = require('path');
var basename = query.question[0].name + '.'
+ (query.question[0].typeName||query.question[0].type.toString()).toLowerCase();
var binname = basename + '.query.bin';
var jsonname = basename + '.query.json';
var binpath = opts.output + '.' + binname;
var jsonpath = opts.output + '.' + jsonname;
var json = JSON.stringify(query, null, 2);
if (-1 !== ['.', '/', '\\' ].indexOf(opts.output[opts.output.length -1])) {
binpath = path.join(opts.output, binname);
jsonpath = path.join(opts.output, jsonname);
}
fs.writeFile(binpath, Buffer.from(queryAb), null, function () {
console.log('wrote ' + queryAb.byteLength + ' bytes to ' + binpath);
});
fs.writeFile(jsonpath, json, null, function () {
console.log('wrote ' + json.length + ' bytes to ' + jsonpath);
});
}
, writeResponse: function (opts, query, nb, packet) {
var me = this;
me._count = me._count || 0;
var path = require('path');
var basename = query.question[0].name + '.'
+ (query.question[0].typeName||query.question[0].type.toString()).toLowerCase();
var binname = basename + '.' + me._count + '.bin';
var jsonname = basename + '.' + me._count + '.json';
var binpath = opts.output + '.' + binname;
var jsonpath = opts.output + '.' + jsonname;
var json = JSON.stringify(packet, null, 2);
if (-1 !== ['.', '/', '\\' ].indexOf(opts.output[opts.output.length -1])) {
binpath = path.join(opts.output, binname);
jsonpath = path.join(opts.output, jsonname);
}
me._count += 1;
fs.writeFile(binpath, nb, null, function () {
console.log('wrote ' + nb.byteLength + ' bytes to ' + binpath);
});
fs.writeFile(jsonpath, json, null, function () {
console.log('wrote ' + json.length + ' bytes to ' + jsonpath);
});
}
};

154
dns-request.js Normal file
View File

@ -0,0 +1,154 @@
'use strict';
var dnsjs = require('dns-suite');
var crypto = require('crypto');
var dgram = require('dgram');
var RCODES = {
0: 'NOERROR'
, 3: 'NXDOMAIN'
, 5: 'REFUSED'
};
function logQuestion(packet) {
var flags = "";
// TODO opcode 0 QUERY rcode 0 NOERROR
console.info(';; ->>HEADER<<- [opcode: ' + packet.header.opcode + ', status: ' + (RCODES[packet.header.rcode] || packet.header.rcode) + '], id: ' + packet.header.id);
if (packet.header.tc) { console.info("Truncated [tc] (we don't know the normal way to print a tc packet... you should record this with -o tc-packet.dig and send it to us)"); }
flags += ";; flags:";
if (packet.header.qr) { flags += " qr"; }
if (packet.header.aa) { flags += " aa"; }
if (packet.header.rd) { flags += " rd"; }
if (packet.header.ra) { flags += " ra"; }
flags += "; QUERY: " + packet.question.length + ", ANSWER: " + packet.answer.length + ", AUTHORITY: " + packet.authority.length + ", ADDITIONAL: " + packet.additional.length;
console.info(flags);
if (packet.header.res1) { console.info("[res1] (we don't know how to print a packet with res1 yet)"); }
if (packet.header.res2) { console.info("[res2] (we don't know how to print a packet with res2 yet)"); }
if (packet.header.res3) { console.info("[res3] (we don't know how to print a packet with res2 yet)"); }
// {"id":32736,"qr":1,"opcode":0,"aa":0,"tc":0,"rd":1,"ra":0,"res1":0,"res2":0,"res3":0,"rcode":5}
//console.log(JSON.stringify(packet.header));
console.info('');
console.info(';; QUESTION SECTION:');
packet.question.forEach(function (q) {
console.info(';' + q.name + '.', ' ', q.className, q.typeName || ('type' + q.type));
});
}
function resolve(queryAb, opts) {
var handlers = {};
var nameservers;
var nameserver = opts.nameserver;
var index;
var udpType;
var receivedMessage;
if (!nameserver) {
nameservers = require('dns').getServers();
index = crypto.randomBytes(2).readUInt16BE(0) % nameservers.length;
nameserver = nameservers[index];
}
udpType = /:/.test(nameserver) ? 'udp6' : 'udp4';
var server = dgram.createSocket({
type: udpType
, reuseAddr: true
});
server.nameserver = nameserver;
handlers.onError = function (err) {
if (opts.onError) { opts.onError(err); } else { throw err; }
server.close();
};
handlers.onMessage = function (bin) {
receivedMessage = true;
if (!opts.mdns) {
clearTimeout(server._timeoutToken);
server.close();
}
if (opts.onMessage) { opts.onMessage(bin); }
};
handlers.onListening = function () {
/*jshint validthis:true*/
var server = this;
if (opts.mdns || '224.0.0.251' === server.nameserver) {
server.setBroadcast(true);
server.addMembership(server.nameserver || '224.0.0.251');
}
if (opts.onListening) { opts.onListening.apply(server); }
server.send(Buffer.from(queryAb), opts.port, server.nameserver, function () {
if (opts.onSent) { opts.onSent({ port: opts.port, nameserver: server.nameserver }); }
});
};
handlers.onClose = function () {
if (opts.onClose) { opts.onClose(); }
};
server.on('error', handlers.onError);
server.on('message', handlers.onMessage);
server.on('listening', handlers.onListening);
server.on('close', handlers.onClose);
// 0 dns request
// 53 dns server
// 5353 mdns
if (opts.mdns) {
server.bind(opts.port /*5353*/);
}
else {
server.bind(0);
}
var ms = opts.timeout || (5 * 1000);
server._timeoutToken = setTimeout(function () {
if (!receivedMessage && opts.onTimeout) { opts.onTimeout({ timeout: ms }); }
server.close();
}, ms);
}
function resolveJson(query, opts) {
var queryAb;
try {
queryAb = dnsjs.DNSPacket.write(query);
} catch(e) {
if ('function' === typeof opts.onError) { opts.onError(e); return; }
throw e;
}
//console.log('[DEV] nameserver', opts.nameserver);
var options = {
onError: opts.onError
, onMessage: function (nb) {
var packet;
try {
packet = dnsjs.DNSPacket.parse(nb.buffer.slice(nb.byteOffset, nb.byteOffset + nb.byteLength));
} catch(e) {
if (opts.onError) { opts.onError(e); return; }
console.error("[Error] couldn't parse incoming message");
console.error(e);
return;
}
opts.onMessage(packet);
}
, onListening: opts.onListening
, onSent: opts.onSent
, onClose: opts.onClose
, onTimeout: opts.onTimeout
, mdns: opts.mdns
, nameserver: opts.nameserver
, port: opts.port
, timeout: opts.timeout
};
return resolve(queryAb, options);
}
module.exports.resolve = resolve;
module.exports.resolveJson = resolveJson;
module.exports.request = resolve;
module.exports.requestJson = resolveJson;
module.exports.logQuestion = logQuestion;

View File

@ -1,27 +0,0 @@
module.exports = function hexdump(ab) {
var ui8 = new Uint8Array(ab);
var bytecount = 0;
var head = ' 0 1 2 3 4 5 6 7 8 9 A B C D E F';
var trail;
var str = [].slice.call(ui8).map(function (i) {
var h = i.toString(16);
if (h.length < 2) {
h = '0' + h;
}
return h;
}).join('').match(/.{1,2}/g).join(' ').match(/.{1,48}/g).map(function (str) {
var lead = bytecount.toString(16);
bytecount += 16;
while (lead.length < 7) {
lead = '0' + lead;
}
return lead + ' ' + str;
}).join('\n');
trail = ab.byteLength.toString(16);
while (trail.length < 7) {
trail = '0' + trail;
}
return head + '\n' + str + '\n' + trail;
};

View File

@ -1,18 +1,18 @@
{ {
"name": "dig.js", "name": "dig.js",
"version": "1.0.9", "version": "1.3.9",
"description": "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.", "description": "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.",
"main": "index.js", "main": "index.js",
"homepage": "https://git.coolaj86.com/coolaj86/dig.js",
"bin": { "bin": {
"dig.js": "./bin/dig.js", "dig.js": "./bin/dig.js"
"digd.js": "./bin/digd.js"
}, },
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git@git.daplie.com:Daplie/dig.js.git" "url": "git://git.coolaj86.com:coolaj86/dig.js.git"
}, },
"keywords": [ "keywords": [
"mdig", "mdig",
@ -25,6 +25,8 @@
"dig", "dig",
"dns", "dns",
"mdns", "mdns",
"dns0x20",
"0x20",
"lint", "lint",
"capture", "capture",
"create", "create",
@ -32,14 +34,16 @@
"binary", "binary",
"json" "json"
], ],
"author": "AJ ONeal <aj@daplie.com> (https://daplie.com/)", "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
"license": "(MIT OR Apache-2.0)", "license": "(MIT OR Apache-2.0)",
"bugs": { "bugs": {
"url": "https://git.daplie.com/Daplie/dig.js/issues" "url": "https://git.coolaj86.com/coolaj86/dig.js/issues"
}, },
"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" "dns-suite": "git+https://git.coolaj86.com/coolaj86/dns-suite.js#v1.2"
},
"optionalDependencies": {
"hexdump.js": "git+https://git.coolaj86.com/coolaj86/hexdump.js#v1.0.4"
} }
} }