2017-09-18 23:40:11 +00:00
'use strict' ;
var dnsjs = require ( 'dns-suite' ) ;
var crypto = require ( 'crypto' ) ;
var dgram = require ( 'dgram' ) ;
2017-10-18 21:26:07 +00:00
var RCODES = {
0 : 'NOERROR'
, 3 : 'NXDOMAIN'
, 5 : 'REFUSED'
} ;
2017-09-20 19:27:53 +00:00
function logQuestion ( packet ) {
var flags = "" ;
// TODO opcode 0 QUERY rcode 0 NOERROR
2017-10-18 21:26:07 +00:00
console . info ( ';; ->>HEADER<<- [opcode: ' + packet . header . opcode + ', status: ' + ( RCODES [ packet . header . rcode ] || packet . header . rcode ) + '], id: ' + packet . header . id ) ;
2017-10-07 00:42:37 +00:00
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)" ) ; }
2017-09-20 19:27:53 +00:00
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 ;
2017-10-07 00:42:37 +00:00
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)" ) ; }
2017-09-20 19:27:53 +00:00
// {"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));
2017-10-07 00:42:37 +00:00
console . info ( '' ) ;
console . info ( ';; QUESTION SECTION:' ) ;
2017-09-20 19:27:53 +00:00
packet . question . forEach ( function ( q ) {
2017-10-09 20:45:07 +00:00
console . info ( ';' + q . name + '.' , ' ' , q . className , q . typeName || ( 'type' + q . type ) ) ;
2017-09-20 19:27:53 +00:00
} ) ;
}
function resolve ( queryAb , opts ) {
2017-09-18 23:40:11 +00:00
var handlers = { } ;
2017-09-19 00:06:27 +00:00
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' ;
2017-09-18 23:40:11 +00:00
var server = dgram . createSocket ( {
2017-09-19 00:06:27 +00:00
type : udpType
2017-09-18 23:40:11 +00:00
, reuseAddr : true
} ) ;
2017-09-19 00:06:27 +00:00
server . nameserver = nameserver ;
2017-09-18 23:40:11 +00:00
handlers . onError = function ( err ) {
2017-09-20 18:50:32 +00:00
if ( opts . onError ) { opts . onError ( err ) ; } else { throw err ; }
2017-09-18 23:40:11 +00:00
server . close ( ) ;
} ;
handlers . onMessage = function ( bin ) {
2017-09-19 00:06:27 +00:00
receivedMessage = true ;
2017-09-18 23:40:11 +00:00
if ( ! opts . mdns ) {
2017-09-19 00:06:27 +00:00
clearTimeout ( server . _timeoutToken ) ;
2017-09-18 23:40:11 +00:00
server . close ( ) ;
}
if ( opts . onMessage ) { opts . onMessage ( bin ) ; }
} ;
handlers . onListening = function ( ) {
/*jshint validthis:true*/
var server = this ;
2017-09-19 00:06:27 +00:00
if ( opts . mdns || '224.0.0.251' === server . nameserver ) {
2017-09-18 23:40:11 +00:00
server . setBroadcast ( true ) ;
2017-09-19 00:06:27 +00:00
server . addMembership ( server . nameserver || '224.0.0.251' ) ;
2017-09-18 23:40:11 +00:00
}
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 } ) ; }
} ) ;
} ;
2017-09-20 18:50:32 +00:00
handlers . onClose = function ( ) {
if ( opts . onClose ) { opts . onClose ( ) ; }
} ;
2017-09-18 23:40:11 +00:00
server . on ( 'error' , handlers . onError ) ;
server . on ( 'message' , handlers . onMessage ) ;
server . on ( 'listening' , handlers . onListening ) ;
2017-09-20 18:50:32 +00:00
server . on ( 'close' , handlers . onClose ) ;
2017-09-18 23:40:11 +00:00
// 0 dns request
// 53 dns server
// 5353 mdns
if ( opts . mdns ) {
server . bind ( opts . port /*5353*/ ) ;
}
else {
server . bind ( 0 ) ;
}
2017-09-19 00:06:27 +00:00
var ms = opts . timeout || ( 5 * 1000 ) ;
server . _timeoutToken = setTimeout ( function ( ) {
if ( ! receivedMessage && opts . onTimeout ) { opts . onTimeout ( { timeout : ms } ) ; }
server . close ( ) ;
} , ms ) ;
2017-09-18 23:40:11 +00:00
}
2017-09-20 19:27:53 +00:00
function resolveJson ( query , opts ) {
2017-10-09 21:11:32 +00:00
var queryAb ;
try {
queryAb = dnsjs . DNSPacket . write ( query ) ;
} catch ( e ) {
if ( 'function' === typeof opts . onError ) { opts . onError ( e ) ; return ; }
throw e ;
}
2017-10-07 00:42:37 +00:00
//console.log('[DEV] nameserver', opts.nameserver);
2017-09-18 23:40:11 +00:00
var options = {
onError : opts . onError
, onMessage : function ( nb ) {
2017-10-09 21:11:32 +00:00
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 ;
}
2017-09-18 23:40:11 +00:00
opts . onMessage ( packet ) ;
}
, onListening : opts . onListening
, onSent : opts . onSent
2017-09-20 19:27:53 +00:00
, onClose : opts . onClose
, onTimeout : opts . onTimeout
2017-09-18 23:40:11 +00:00
, mdns : opts . mdns
, nameserver : opts . nameserver
, port : opts . port
, timeout : opts . timeout
} ;
2017-09-20 19:27:53 +00:00
return resolve ( queryAb , options ) ;
2017-09-18 23:40:11 +00:00
}
2017-09-20 19:27:53 +00:00
module . exports . resolve = resolve ;
module . exports . resolveJson = resolveJson ;
module . exports . request = resolve ;
module . exports . requestJson = resolveJson ;
module . exports . logQuestion = logQuestion ;