2017-02-18 02:07:02 +00:00
'use strict' ;
var dnsjs = require ( '../../dns-lint' ) ;
var cli = require ( 'cli' ) ;
cli . parse ( {
// 'b': [ false, 'set source IP address (defaults to 0.0.0.0)', 'string' ]
'class' : [ 'c' , 'class (defaults to IN)' , 'string' , 'IN' ]
, '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 PromiseA = require ( 'bluebird' ) ;
var fs = PromiseA . promisifyAll ( require ( 'fs' ) ) ;
var dgram = require ( 'dgram' ) ;
var commonTypes = [ 'A' , 'AAAA' , 'CNAME' , 'MX' , 'NS' , 'PTR' , 'SOA' , 'SRV' , 'TXT' ] ;
2017-02-18 03:00:42 +00:00
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 ( '" "' ) + '"' ) ;
}
} ;
2017-02-18 02:07:02 +00:00
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 ;
}
2017-02-18 03:18:19 +00:00
function writeQuery ( opts , query , queryAb ) {
var path = require ( 'path' ) ;
var filename = query . question [ 0 ] . name + '.' + query . question [ 0 ] . typeName . toLowerCase ( ) + '.query.bin' ;
var fullpath = opts . output + '.' + filename ;
if ( - 1 !== [ '.' , '/' , '\\' ] . indexOf ( opts . output [ opts . output . length - 1 ] ) ) {
fullpath = path . join ( opts . output , filename ) ;
}
fs . writeFileAsync ( fullpath , Buffer . from ( queryAb ) ) . then ( function ( ) {
console . log ( 'wrote ' + queryAb . byteLength + ' bytes to ' + fullpath ) ;
} ) ;
}
var count = 0 ;
function writeResponse ( opts , query , nb ) {
var path = require ( 'path' ) ;
var filename = query . question [ 0 ] . name + '.' + query . question [ 0 ] . typeName . toLowerCase ( ) + '.' + count + '.bin' ;
var fullpath = opts . output + '.' + filename ;
if ( - 1 !== [ '.' , '/' , '\\' ] . indexOf ( opts . output [ opts . output . length - 1 ] ) ) {
fullpath = path . join ( opts . output , filename ) ;
}
count += 1 ;
fs . writeFileAsync ( fullpath , nb ) . then ( function ( ) {
console . log ( 'wrote ' + nb . length + ' bytes to ' + fullpath ) ;
} ) ;
}
2017-02-18 02:40:01 +00:00
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 ( ) ;
}
2017-02-18 03:00:42 +00:00
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 ) ;
2017-02-18 02:40:01 +00:00
console . log ( '' ) ;
if ( opts . output ) {
2017-02-18 03:18:19 +00:00
console . log ( '' ) ;
writeQuery ( opts , query , queryAb ) ;
writeResponse ( opts , query , nb ) ;
2017-02-18 02:40:01 +00:00
}
} ;
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
server . bind ( 0 ) ;
}
2017-02-18 02:07:02 +00:00
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 ( ) ;
}
if ( /^@/ . test ( arg ) ) {
if ( cli . nameserver ) {
console . error ( "'@server' was specified more than once" ) ;
process . exit ( 1 ) ;
return ;
}
cli . nameserver = cli . n = arg ;
}
if ( cli . query ) {
console . error ( "'@server' 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 ;
}
2017-02-18 02:40:01 +00:00
if ( ! cli . nameserver ) {
cli . nameserver = '224.0.0.251' ;
}
2017-02-18 02:07:02 +00:00
}
if ( ! cli . type ) {
cli . type = cli . t = 'ANY' ;
}
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
, tc : 0 // NA
, rd : 1
, ra : 0 // NA
, rcode : 0 // NA
}
, question : [
{ name : cli . query
, typeName : cli . type
, className : cli . class
}
]
} ;
2017-02-18 02:40:01 +00:00
request ( query , cli ) ;
2017-02-18 02:07:02 +00:00
} ) ;