Compare commits
	
		
			63 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 25d150de07 | ||
|  | 90ed10c129 | ||
|  | 3bf715998d | ||
|  | 6e7a0c57c8 | ||
|  | 22f5297582 | ||
|  | 79154b093d | ||
|  | 9ad274a0bb | ||
|  | 56048ad5d2 | ||
|  | 39ba065ce0 | ||
|  | d5f5267c18 | ||
|  | 3323379194 | ||
| 6ef8c7a475 | |||
|  | f441c0cfc5 | ||
|  | 7bba8f18e9 | ||
|  | 875d288db3 | ||
|  | c6ba3ccde6 | ||
|  | 1b79eb262f | ||
|  | 9373336675 | ||
|  | e279f753f8 | ||
|  | 17b4d6d57f | ||
|  | 44b4801ef6 | ||
|  | 893574a3c2 | ||
|  | 4c85be0ebf | ||
|  | aba58292ee | ||
|  | b6bc592e56 | ||
|  | b3d7408db4 | ||
|  | 6287f13f2b | ||
|  | 1533576023 | ||
|  | 76fee917ea | ||
|  | a7ebc7ce86 | ||
|  | f8b2fb7ff8 | ||
|  | e1d0322ed2 | ||
|  | 08c3791bec | ||
|  | 510f8b93e7 | ||
|  | 4e0a37c0f5 | ||
|  | 7bb2e84486 | ||
|  | 0bf55e7589 | ||
|  | 51b05e9860 | ||
|  | 1b182f7c2f | ||
|  | 09d95fd88c | ||
|  | 0c71c39dc1 | ||
|  | fcaafbf8b9 | ||
|  | 083df5755b | ||
|  | 6d0f9b1588 | ||
|  | cdd490ec42 | ||
|  | 57ced95c0d | ||
|  | f979638090 | ||
|  | 03e3e527dc | ||
|  | de6fe5039b | ||
|  | 36d7aaccbb | ||
|  | 2f318607a1 | ||
|  | 5dae97b60d | ||
|  | 01e753996a | ||
|  | 51daf2378d | ||
|  | 0cabe30b88 | ||
|  | c7668e7381 | ||
|  | f65cd74ea3 | ||
|  | e3ccb16e42 | ||
|  | 11677feb12 | ||
|  | ce84e4262d | ||
|  | 8c3126a2ac | ||
|  | d225cfa5c6 | ||
|  | a41b3f8f3f | 
							
								
								
									
										16
									
								
								.jshintrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								.jshintrc
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										1
									
								
								BUGS.txt
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										6
									
								
								CHANGELOG
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										41
									
								
								LICENSE
									
									
									
									
									
										Normal 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. | ||||
							
								
								
									
										61
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								README.md
									
									
									
									
									
								
							| @ -1,27 +1,34 @@ | ||||
| dig.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. | ||||
| | [dns-suite](https://git.coolaj86.com/coolaj86/dns-suite) | ||||
| | **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 | ||||
| # 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 | ||||
| # 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 | ||||
| (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 | ||||
| npm install -g dig.js | ||||
| @ -30,16 +37,14 @@ npm install -g dig.js | ||||
| Usage | ||||
| ----- | ||||
| 
 | ||||
| ### Format | ||||
| 
 | ||||
| ```bash | ||||
| dig.js [TYPE] <domainname> | ||||
| ``` | ||||
| 
 | ||||
| ### Example | ||||
| **Example**: | ||||
| 
 | ||||
| ```bash | ||||
| dig.js daplie.com | ||||
| dig.js coolaj86.com | ||||
| ``` | ||||
| 
 | ||||
| ### 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 | ||||
| 
 | ||||
| ```bash | ||||
| dig.js A daplie.com | ||||
| dig.js A coolaj86.com | ||||
| 
 | ||||
| dig.js -t A daplie.com | ||||
| 
 | ||||
| dig.js @8.8.8.8 A daplie.com | ||||
| dig.js @8.8.8.8 A coolaj86.com | ||||
| ``` | ||||
| 
 | ||||
| Options | ||||
| ------- | ||||
| 
 | ||||
| ``` | ||||
| --debug | ||||
| --mdns | ||||
| --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 | ||||
| -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. | ||||
| +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. | ||||
|  | ||||
							
								
								
									
										524
									
								
								bin/dig.js
									
									
									
									
									
								
							
							
						
						
									
										524
									
								
								bin/dig.js
									
									
									
									
									
								
							| @ -1,8 +1,11 @@ | ||||
| #!/usr/bin/env node
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| var dnsjs = require('dns-suite'); | ||||
| var dig = require('../dns-request'); | ||||
| var cli = require('cli'); | ||||
| var defaultNameservers = require('dns').getServers(); | ||||
| var typeRe = /^type\d+$/i; | ||||
| 
 | ||||
| cli.parse({ | ||||
| //  'b': [ false, 'set source IP address (defaults to 0.0.0.0)', 'string' ]
 | ||||
|   'class': [ 'c', 'class (defaults to IN)', 'string', 'IN' ] | ||||
| @ -13,271 +16,50 @@ cli.parse({ | ||||
| //, '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 ] | ||||
| , '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' ] | ||||
| , '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' ]
 | ||||
| , '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 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 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; | ||||
| } | ||||
| 
 | ||||
| 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 = (Math.round(Math.random() * 7777)) % 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(5353); | ||||
|     setTimeout(function () { | ||||
|       server.close(); | ||||
|     }, opts.timeout || (5 * 1000)); | ||||
|   } | ||||
|   else { | ||||
|     server.bind(0); | ||||
|   } | ||||
| } | ||||
| var common = require('../common.js'); | ||||
| 
 | ||||
| cli.main(function (args, cli) { | ||||
|   cli.implicitType = cli.type; | ||||
|   cli.implicitQuery = cli.query; | ||||
|   args.forEach(function (arg) { | ||||
|     if (-1 !== commonTypes.concat([ 'ANY' ]).indexOf(arg.toUpperCase())) { | ||||
|       if (cli.type) { | ||||
|     if (typeRe.test(arg) || -1 !== common.types.concat([ 'ANY' ]).indexOf(arg.toUpperCase())) { | ||||
|       if (cli.implicitType) { | ||||
|         console.error("'type' was specified more than once"); | ||||
|         process.exit(1); | ||||
|         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; | ||||
|     } | ||||
| 
 | ||||
| @ -297,19 +79,45 @@ cli.main(function (args, cli) { | ||||
|         process.exit(1); | ||||
|         return; | ||||
|       } | ||||
|       cli.nameserver = cli.n = arg; | ||||
|       cli.nameserver = cli.n = arg.substr(1); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     if (cli.query) { | ||||
|       console.error("'query' was specified more than once"); | ||||
|     if ('string' === typeof cli.implicitQuery) { | ||||
|       console.error("'query' was specified more than once or unrecognized flag: " + cli.implicitQuery + ", " + arg); | ||||
|       process.exit(1); | ||||
|       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.type) { | ||||
|       cli.type = cli.t = 'PTR'; | ||||
| @ -320,52 +128,222 @@ cli.main(function (args, cli) { | ||||
|     if (!cli.nameserver) { | ||||
|       cli.nameserver = '224.0.0.251'; | ||||
|     } | ||||
|     if (!cli.query) { | ||||
|     if ('string' !== typeof cli.query) { | ||||
|       cli.query = '_services._dns-sd._udp.local'; | ||||
|     } | ||||
|     if (!cli.timeout) { | ||||
|       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) { | ||||
|     cli.type = cli.t = 'ANY'; | ||||
|   } | ||||
|   if (typeRe.test(cli.type)) { | ||||
|     cli.rawType = parseInt(cli.type.replace('type', ''), 10); | ||||
|   } | ||||
|   if (!cli.port) { | ||||
|     cli.port = cli.p = 53; | ||||
|   } | ||||
|   if (!cli.class) { | ||||
|     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 = { | ||||
|     header: { | ||||
|       id: require('crypto').randomBytes(2).readUInt16BE(0) | ||||
|     , qr: 0 | ||||
|     , opcode: 0 | ||||
|     , aa: 0     // NA
 | ||||
|     , aa: cli.aaonly ? 1 : 0  // NA
 | ||||
|     , tc: 0                   // NA
 | ||||
|     , rd: 1 | ||||
|     , rd: cli.norecurse ? 0 : 1 | ||||
|     , ra: 0                   // NA
 | ||||
|     , rcode: 0                // NA
 | ||||
|     } | ||||
|   , question: [ | ||||
|       { name: cli.query | ||||
|       , typeName: cli.type | ||||
|       { name: cli.casedQuery | ||||
|       , type: cli.rawType | ||||
|       , typeName: cli.rawType ? undefined : cli.type | ||||
|       , 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); | ||||
| }); | ||||
|  | ||||
							
								
								
									
										90
									
								
								common.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								common.js
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										154
									
								
								dns-request.js
									
									
									
									
									
										Normal 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; | ||||
							
								
								
									
										17
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								package.json
									
									
									
									
									
								
							| @ -1,8 +1,9 @@ | ||||
| { | ||||
|   "name": "dig.js", | ||||
|   "version": "1.0.8", | ||||
|   "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.", | ||||
|   "main": "index.js", | ||||
|   "homepage": "https://git.coolaj86.com/coolaj86/dig.js", | ||||
|   "bin": { | ||||
|     "dig.js": "./bin/dig.js" | ||||
|   }, | ||||
| @ -11,7 +12,7 @@ | ||||
|   }, | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
|     "url": "git@git.daplie.com:Daplie/dig.js.git" | ||||
|     "url": "git://git.coolaj86.com:coolaj86/dig.js.git" | ||||
|   }, | ||||
|   "keywords": [ | ||||
|     "mdig", | ||||
| @ -24,6 +25,8 @@ | ||||
|     "dig", | ||||
|     "dns", | ||||
|     "mdns", | ||||
|     "dns0x20", | ||||
|     "0x20", | ||||
|     "lint", | ||||
|     "capture", | ||||
|     "create", | ||||
| @ -31,14 +34,16 @@ | ||||
|     "binary", | ||||
|     "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)", | ||||
|   "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": { | ||||
|     "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" | ||||
|   } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user