2017-02-23 23:25:39 +00:00
|
|
|
|
dns-suite
|
2017-01-21 22:07:10 +00:00
|
|
|
|
========
|
|
|
|
|
|
2017-02-23 23:25:39 +00:00
|
|
|
|
Fast, lightweight, and easy-to-extend **pure JavaScript** (ES5.1) implementation for DNS / mDNS.
|
2017-01-21 22:07:10 +00:00
|
|
|
|
|
|
|
|
|
Works great in **Web Browsers** and in node.js!
|
|
|
|
|
|
2017-01-27 00:03:16 +00:00
|
|
|
|
Detailed error checking makes it great for
|
2017-01-21 22:07:10 +00:00
|
|
|
|
|
|
|
|
|
* capture
|
2017-02-23 23:25:39 +00:00
|
|
|
|
* packing (JSON to DNS/mDNS)
|
|
|
|
|
* parsing (DNS/mDNS to JSON)
|
2017-01-21 22:07:10 +00:00
|
|
|
|
* linting (finding errors in packets)
|
|
|
|
|
* debugging
|
|
|
|
|
|
2017-02-23 23:25:39 +00:00
|
|
|
|
**No external dependencies** for node.js or modern browsers. Uses `DataView`, `Uint8Array`, `Uint16Array`, and `ArrayBuffer`
|
2017-01-21 22:07:10 +00:00
|
|
|
|
|
|
|
|
|
Similar API to `dns.js` and `native-dns-packet`.
|
|
|
|
|
|
2017-01-21 22:11:39 +00:00
|
|
|
|
```json
|
2017-02-11 15:51:47 +00:00
|
|
|
|
{ "header": {
|
2017-02-17 23:22:56 +00:00
|
|
|
|
"id": 5423
|
2017-02-11 15:51:47 +00:00
|
|
|
|
, "qr": 0
|
|
|
|
|
, "opcode": 0
|
|
|
|
|
, "aa": 0
|
|
|
|
|
, "tc": 0
|
|
|
|
|
, "rd": 1
|
|
|
|
|
, "ra": 0
|
|
|
|
|
, "res1": 0
|
|
|
|
|
, "res2": 0
|
|
|
|
|
, "res3": 0
|
|
|
|
|
, "rcode": 0
|
|
|
|
|
}
|
2017-02-03 04:26:05 +00:00
|
|
|
|
, "question": [
|
2017-01-21 22:11:39 +00:00
|
|
|
|
{ "name": "bowie._sftp-ssh._tcp.local"
|
|
|
|
|
, "type": 1
|
2017-02-11 15:51:47 +00:00
|
|
|
|
, "typeName": "A"
|
2017-01-21 22:11:39 +00:00
|
|
|
|
, "class": 1
|
2017-02-11 15:51:47 +00:00
|
|
|
|
, "className": "IN"
|
2017-01-21 22:11:39 +00:00
|
|
|
|
, "byteLength": 32
|
|
|
|
|
}
|
|
|
|
|
]
|
2017-02-03 04:26:05 +00:00
|
|
|
|
, "answer": []
|
2017-01-21 22:11:39 +00:00
|
|
|
|
, "authority": []
|
|
|
|
|
, "additional": []
|
2017-02-16 21:16:21 +00:00
|
|
|
|
, "edns_options": []
|
2017-01-21 22:11:39 +00:00
|
|
|
|
, "byteLength": 44
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2017-02-23 23:40:20 +00:00
|
|
|
|
Install with git
|
2017-01-21 22:07:10 +00:00
|
|
|
|
-------
|
|
|
|
|
|
2017-02-23 23:40:20 +00:00
|
|
|
|
You can use git to install v1.x like so:
|
2017-02-23 23:35:19 +00:00
|
|
|
|
|
2017-01-21 22:11:39 +00:00
|
|
|
|
```bash
|
2017-02-23 23:35:19 +00:00
|
|
|
|
# latest of v1.x
|
|
|
|
|
npm install 'git+https://git@git.daplie.com:Daplie/dns-suite#v1'
|
|
|
|
|
```
|
|
|
|
|
|
2017-02-23 23:40:20 +00:00
|
|
|
|
If you want to be more specific to v1.0.x or exactly v1.0.2 you can do so like this:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
# latest of v1.0.x
|
|
|
|
|
npm install 'git+https://git@git.daplie.com:Daplie/dns-suite#v1.0'
|
|
|
|
|
|
|
|
|
|
# exactly v1.0.2
|
|
|
|
|
npm install 'git+https://git@git.daplie.com:Daplie/dns-suite#v1.0.2'
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Install without git
|
|
|
|
|
-------
|
|
|
|
|
|
|
|
|
|
Don't have git? Well you can also bow down to the gods of the centralized, monopolized, concentrated, dictatornet
|
|
|
|
|
(as we like to call it here at Daplie Labs), if that's how you roll:
|
2017-02-23 23:35:19 +00:00
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
npm install --save dns-suite
|
2017-01-21 22:07:10 +00:00
|
|
|
|
```
|
|
|
|
|
|
2017-02-03 04:26:05 +00:00
|
|
|
|
**Test**:
|
|
|
|
|
|
|
|
|
|
```bash
|
2017-02-23 23:25:39 +00:00
|
|
|
|
pushd node_modules/dns-suite
|
2017-02-03 04:26:05 +00:00
|
|
|
|
|
|
|
|
|
npm test
|
|
|
|
|
```
|
|
|
|
|
|
2017-01-21 22:07:10 +00:00
|
|
|
|
Usage
|
|
|
|
|
-----
|
|
|
|
|
|
2017-02-24 01:09:21 +00:00
|
|
|
|
* CLI
|
|
|
|
|
* API
|
|
|
|
|
|
2017-09-28 19:30:03 +00:00
|
|
|
|
### CLI Usage
|
2017-01-21 22:07:10 +00:00
|
|
|
|
|
2017-09-28 19:30:03 +00:00
|
|
|
|
When installed globally you can use these commands:
|
2017-01-21 22:07:10 +00:00
|
|
|
|
|
2017-09-28 19:30:03 +00:00
|
|
|
|
```
|
|
|
|
|
dns-parse.js </path/to/packet.dns.bin> [out.json] # parses a saved DNS packet to JSON
|
|
|
|
|
dns-pack.js </path/to/packet.dns.json> [out.bin] # packs a JSON DNS packet to binary
|
|
|
|
|
dns-test.js </path/to/packet.dns(.json|.bin)> # convert a packet back and forth to test reciprocity of the packer and parser
|
|
|
|
|
mdns-capture.js <prefixname> [startnum] # listen and save all mDNS packets, numbering by sequence of arrival
|
2017-01-21 22:07:10 +00:00
|
|
|
|
```
|
|
|
|
|
|
2017-09-28 19:30:03 +00:00
|
|
|
|
You can also access them directly from `node_modules/dns-suite` in a project:
|
2017-01-21 22:07:10 +00:00
|
|
|
|
|
2017-01-21 22:11:39 +00:00
|
|
|
|
```bash
|
2017-09-28 19:30:03 +00:00
|
|
|
|
node node_modules/dns-suite/bin/dns-parse.js node_modules/dns-suite/samples/a-0.mdns.bin
|
2017-01-21 22:07:10 +00:00
|
|
|
|
```
|
|
|
|
|
|
2017-09-28 19:30:03 +00:00
|
|
|
|
### Library API
|
2017-01-21 22:07:10 +00:00
|
|
|
|
|
2017-02-24 01:09:21 +00:00
|
|
|
|
* `DNSPacket.parse(nodeOrArrayBuffer)` returns json (as shown above)
|
|
|
|
|
* `DNSPacket.pack(packet)` returns ArrayBuffer (browser and node)
|
|
|
|
|
* `DNSPacket.write(packet)` returns NodeBuffer (node only)
|
2017-01-21 22:07:10 +00:00
|
|
|
|
|
|
|
|
|
node.js:
|
2017-01-21 22:11:39 +00:00
|
|
|
|
```js
|
2017-01-21 22:07:10 +00:00
|
|
|
|
var nodeBuffer = fs.readFileSync('./samples/a-0.mdns.bin');
|
|
|
|
|
var arrayBuffer = nodeBuffer.buffer;
|
|
|
|
|
|
2017-02-24 01:09:21 +00:00
|
|
|
|
var DNSPacket = require('dns-suite').DNSPacket;
|
|
|
|
|
var packet = DNSPacket.parse(arrayBuffer);
|
|
|
|
|
var ab = DNSPacket.pack(packet);
|
2017-01-21 22:07:10 +00:00
|
|
|
|
|
|
|
|
|
console.log(packet);
|
2017-02-24 01:09:21 +00:00
|
|
|
|
console.log(new Uint8Array(ab));
|
2017-01-21 22:07:10 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Browser:
|
2017-01-21 22:11:39 +00:00
|
|
|
|
```js
|
2017-01-21 22:07:10 +00:00
|
|
|
|
var arrayBuffer = new Uint8Array.from([ /* bytes */ ]).buffer;
|
|
|
|
|
|
2017-02-24 01:09:21 +00:00
|
|
|
|
var packet = DNSPacket.parse(arrayBuffer);
|
|
|
|
|
var ab = DNSPacket.pack(packet);
|
2017-01-21 22:07:10 +00:00
|
|
|
|
|
|
|
|
|
console.log(packet);
|
2017-02-24 01:09:21 +00:00
|
|
|
|
console.log(new Uint8Array(ab));
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Capturing Packets
|
|
|
|
|
-----
|
|
|
|
|
|
|
|
|
|
We have a command line tool for that! See [dig.js](https://git.daplie.com/Daplie/dig.js).
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
# Install
|
|
|
|
|
npm install -g 'git+https://git@git.daplie.com/Daplie/dig.js.git'
|
|
|
|
|
|
|
|
|
|
# Use with DNS
|
|
|
|
|
dig.js A daplie.com --output .
|
|
|
|
|
|
|
|
|
|
# Use with mDNS
|
|
|
|
|
dig.js --mdns PTR _services._dns-sd._udp.local --output .
|
2017-01-21 22:07:10 +00:00
|
|
|
|
```
|
|
|
|
|
|
2017-02-11 15:51:47 +00:00
|
|
|
|
Contributing and Development
|
|
|
|
|
============================
|
|
|
|
|
|
|
|
|
|
How to add a new parser
|
|
|
|
|
-----------------------
|
|
|
|
|
|
|
|
|
|
Each RR (aka Resource Record or RData) parser is individual. Examples include:
|
|
|
|
|
|
2017-02-17 23:22:56 +00:00
|
|
|
|
* A (`parser/type.a.js`)
|
|
|
|
|
* AAAA (`parser/type.aaaa.js`)
|
|
|
|
|
* CNAME (`parser/type.cname.js`)
|
|
|
|
|
* TXT (`parser/type.txt.js`)
|
|
|
|
|
* SRV (`parser/type.srv.js`)
|
2017-02-11 15:51:47 +00:00
|
|
|
|
|
|
|
|
|
Let's say that To create a parser for a type which we don't currently support,
|
|
|
|
|
just add the appropriate information to `dns.types.js` and create a file for
|
2017-02-17 23:22:56 +00:00
|
|
|
|
the name of the type in the format `parser/type.<typename>.js`.
|
2017-02-11 15:51:47 +00:00
|
|
|
|
|
|
|
|
|
For example, if `CNAME` wasn't already supported and I wanted to add support for
|
|
|
|
|
it I would follow these steps:
|
|
|
|
|
|
2017-04-13 20:21:15 +00:00
|
|
|
|
1) Update `dns.types.js` if it's not there already.
|
2017-02-11 15:51:47 +00:00
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
A: 0x01 // 1
|
|
|
|
|
, NS: 0x02 // 2
|
|
|
|
|
, CNAME: 0x05 // 5 // I would simply add this line
|
|
|
|
|
, SOA: 0x06 // 6
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2) Capture a packet to `test/fixtures/<domain>.<tld>.<type>.bin`
|
|
|
|
|
|
|
|
|
|
This will construct and send a DNS query and save the first result
|
|
|
|
|
that comes back.
|
|
|
|
|
|
|
|
|
|
In some cases (such as CNAME), the typical (or required) way to illicit
|
|
|
|
|
the desired response is to make a request of a different type.
|
|
|
|
|
|
|
|
|
|
If that's the case, manually rename the the file afterwards.
|
|
|
|
|
|
|
|
|
|
Ideally you should have some idea of what the result file should look
|
|
|
|
|
like and should place that in `test/fixtures/<domain>.<tld>.<type>.json`
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
node bin/capture-query.js --name www.google.com --type CNAME
|
|
|
|
|
```
|
|
|
|
|
|
2017-02-17 23:22:56 +00:00
|
|
|
|
3) Create `parser/type.cname.js`
|
2017-02-11 15:51:47 +00:00
|
|
|
|
|
2017-02-17 23:22:56 +00:00
|
|
|
|
Copy `parser/type.TEMPLATE.js` to the type for which you wish to create support
|
|
|
|
|
(`parser/type.cname.js` in this example) and fill in the blanks.
|
2017-02-11 15:51:47 +00:00
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
var unpackLabels = exports.DNS_UNPACK_LABELS || require('./dns.unpack-labels.js').DNS_UNPACK_LABELS;
|
2017-02-17 23:22:56 +00:00
|
|
|
|
exports.DNS_PARSER_TYPE_CNAME = function (ab, packet, record) {
|
2017-02-11 15:51:47 +00:00
|
|
|
|
// record = { rdstart, rdlength, type, class }
|
|
|
|
|
// example of not parsing and just leaving as binary data
|
|
|
|
|
record.data = new Uint8Array(ab.slice(record.rdstart, record.rdstart + record.rdlength));
|
|
|
|
|
|
|
|
|
|
return record;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}('undefined' !== typeof window ? window : exports));
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
4) Document what you've learned in `doc/<type>.txt`
|
|
|
|
|
|
|
|
|
|
You may be right or you might be wrong, but you might be right.
|
|
|
|
|
|
|
|
|
|
In any case, take a minute to document some of the gritty details of what you learned about this
|
|
|
|
|
record type - tips, tricks, little-known facts, etc.
|
|
|
|
|
|
|
|
|
|
This may help (or wildly mislead) others if there's a bug in your parser that they need to track down.
|
|
|
|
|
At the very least someone can follow a few links you followed and your thought process.
|
|
|
|
|
|
|
|
|
|
5) Check that my changes include these files
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
├── README.md
|
|
|
|
|
├── demo.html (add the appropriate script tag)
|
|
|
|
|
├── doc
|
|
|
|
|
| └── cname.txt
|
|
|
|
|
├── dns.classes.js (not necessarily, but potentially)
|
|
|
|
|
├── dns.types.js
|
|
|
|
|
├── package.json (bump the minor version)
|
2017-02-17 23:22:56 +00:00
|
|
|
|
├── packer
|
|
|
|
|
| └── type.cname.js
|
|
|
|
|
├── parser
|
|
|
|
|
| └── type.cname.js
|
2017-02-11 15:51:47 +00:00
|
|
|
|
└── test
|
|
|
|
|
└── fixtures
|
|
|
|
|
├── www.google.com.cname.bin
|
|
|
|
|
└── www.google.com.cname.js
|
|
|
|
|
```
|