253 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			253 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 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`.
 | ||
| 
 | ||
| ```json
 | ||
| { "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:
 | ||
| 
 | ||
| ```bash
 | ||
| # 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**:
 | ||
| 
 | ||
| ```bash
 | ||
| pushd node_modules/dns-suite
 | ||
| 
 | ||
| npm test
 | ||
| ```
 | ||
| 
 | ||
| Usage
 | ||
| -----
 | ||
| 
 | ||
| * CLI
 | ||
| * API
 | ||
| 
 | ||
| ### CLI Usage
 | ||
| 
 | ||
| When installed globally you can use these commands:
 | ||
| 
 | ||
| ```
 | ||
| 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
 | ||
| ```
 | ||
| 
 | ||
| You can also access them directly from `node_modules/dns-suite` in a project:
 | ||
| 
 | ||
| ```bash
 | ||
| node node_modules/dns-suite/bin/dns-parse.js node_modules/dns-suite/samples/a-0.mdns.bin
 | ||
| ```
 | ||
| 
 | ||
| ### Library API
 | ||
| 
 | ||
| * `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:
 | ||
| ```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:
 | ||
| ```js
 | ||
| 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](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 .
 | ||
| ```
 | ||
| 
 | ||
| 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
 | ||
| ```
 | ||
| 
 | ||
| 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
 | ||
| ```
 | ||
| 
 | ||
| 3) 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));
 | ||
| ```
 | ||
| 
 | ||
| 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)
 | ||
| ├── packer
 | ||
| |   └── type.cname.js
 | ||
| ├── parser
 | ||
| |   └── type.cname.js
 | ||
| └── test
 | ||
|     └── fixtures
 | ||
|         ├── www.google.com.cname.bin
 | ||
|         └── www.google.com.cname.js
 | ||
| ```
 |