Fast, lightweight, easy-to-extend, easy-to-test, pure JavaScript (ES5.1) implementation for DNS / mDNS.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
tigerbot a295f9c3e7 v1.1.1 7 years ago
bin create proper ArrayBuffer from NodeBuffer https://github.com/nodejs/node/issues/11132 7 years ago
examples added random ID to all aditional record responses 7 years ago
packer changed examples to use `dns-suite` instead of `dns-js` 7 years ago
parser added shortening of unpacked string IPv6 addresses 7 years ago
samples finished PTR parser 7 years ago
test captured some txt records with dig.js 7 years ago
.gitignore ignore generated json files 7 years ago
.gitmodules reorganzing 7 years ago
ORIGINAL_PROBLEM.md update docs 7 years ago
README.md Bump version for new CAA parser and new type IDs 7 years ago
browser.js started browser code 7 years ago
demo.css started fixing format to match native dns. Spotted bug in unpacking labels. Not fixed yet 7 years ago
demo.html more dir restructure updates 7 years ago
dns.classes.js in reverse also 7 years ago
dns.js limited how often we log about unsupported features 7 years ago
dns.packer.js changed examples to use `dns-suite` instead of `dns-js` 7 years ago
dns.parser.js limited how often we log about unsupported features 7 years ago
dns.rdata.pack.js dir for packer 7 years ago
dns.rdata.parse.js load parsers correctly 7 years ago
dns.type.any.js clean up 7 years ago
dns.types.js Add missing dns type IDs to mapping table 7 years ago
dns.unpack-labels.js only add compression pointer length once 7 years ago
notes.md renamed some files and added objective statement and purpose of document 7 years ago
package.json v1.1.1 7 years ago
parse-binary-test.js added the test code that AJ wrote 7 years ago

README.md

dns-suite

Fast, lightweight, and easy-to-extend pure JavaScript (ES5.1) implementation for DNS / mDNS.

Works great in Web Browsers and in node.js!

Detailed error checking makes it great for

  • capture
  • packing (JSON to DNS/mDNS)
  • parsing (DNS/mDNS to JSON)
  • linting (finding errors in packets)
  • debugging

No external dependencies for node.js or modern browsers. Uses DataView, Uint8Array, Uint16Array, and ArrayBuffer

Similar API to dns.js and native-dns-packet.

{ "header": {
    "id": 5423
  , "qr": 0
  , "opcode": 0
  , "aa": 0
  , "tc": 0
  , "rd": 1
  , "ra": 0
  , "res1": 0
  , "res2": 0
  , "res3": 0
  , "rcode": 0
  }
, "question": [
    { "name": "bowie._sftp-ssh._tcp.local"
    , "type": 1
    , "typeName": "A"
    , "class": 1
    , "className": "IN"
    , "byteLength": 32
    }
  ]
, "answer": []
, "authority": []
, "additional": []
, "edns_options": []
, "byteLength": 44
}

Install with git

You can use git to install v1.x like so:

# latest of v1.x
npm install 'git+https://git@git.daplie.com:Daplie/dns-suite#v1'

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:

npm install --save dns-suite

Test:

pushd node_modules/dns-suite

npm test

Usage

  • CLI
  • API

CLI

You can work directly from node_modules/dns-suite:

pushd node_modules/dns-suite/

Parsing a saved packet

# example
# node bin/dns-parse.js </path/to/packet.dns.bin>
node bin/dns-parse.js samples/a-0.mdns.bin

You can also parse a saved packet from the native-dns-packet directory. these test packets have the binary for each record type and what it's parsed output should be.

Library

  • DNSPacket.parse(nodeOrArrayBuffer) returns json (as shown above)
  • DNSPacket.pack(packet) returns ArrayBuffer (browser and node)
  • DNSPacket.write(packet) returns NodeBuffer (node only)

node.js:

var nodeBuffer = fs.readFileSync('./samples/a-0.mdns.bin');
var arrayBuffer = nodeBuffer.buffer;

var DNSPacket = require('dns-suite').DNSPacket;
var packet = DNSPacket.parse(arrayBuffer);
var ab = DNSPacket.pack(packet);

console.log(packet);
console.log(new Uint8Array(ab));

Browser:

var arrayBuffer = new Uint8Array.from([ /* bytes */ ]).buffer;

var packet = DNSPacket.parse(arrayBuffer);
var ab = DNSPacket.pack(packet);

console.log(packet);
console.log(new Uint8Array(ab));

Capturing Packets

We have a command line tool for that! See 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 .

Contributing and Development

How to add a new parser

Each RR (aka Resource Record or RData) parser is individual. Examples include:

  • 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)

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 the name of the type in the format parser/type.<typename>.js.

For example, if CNAME wasn't already supported and I wanted to add support for it I would follow these steps:

  1. Update dns.types.js if it's not there already.
  A: 			0x01	//   1
, NS: 		0x02  //   2
, CNAME: 	0x05  //   5    // I would simply add this line
, SOA: 		0x06  //   6
  1. 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

node bin/capture-query.js --name www.google.com --type CNAME
  1. Create parser/type.cname.js

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.

var unpackLabels = exports.DNS_UNPACK_LABELS || require('./dns.unpack-labels.js').DNS_UNPACK_LABELS;
exports.DNS_PARSER_TYPE_CNAME = function (ab, packet, record) {
  // 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));
  1. 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.

  1. 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)
├── packer
|   └── type.cname.js
├── parser
|   └── type.cname.js
└── test
    └── fixtures
        ├── www.google.com.cname.bin
        └── www.google.com.cname.js