Compare commits
	
		
			2 Commits
		
	
	
		
			bd8b57efd1
			...
			bc93b942ee
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | bc93b942ee | ||
|  | c3934acb30 | 
| @ -89,6 +89,8 @@ Options | ||||
| +time=<seconds>             Sets the timeout for a query in seconds. | ||||
| +norecurse                  Set `ra` flag to 0. Do not perform recursion. | ||||
| +aaonly                     Set `aa` flag to 1. Do not respond with non-authoritative responses. | ||||
| +notcp                      Disable TCP server (default in v1.2) | ||||
| +tcp                        Enable TCP server (default in v1.3) | ||||
| 
 | ||||
| --debug                     verbose output | ||||
| ``` | ||||
|  | ||||
							
								
								
									
										101
									
								
								bin/digd.js
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								bin/digd.js
									
									
									
									
									
								
							| @ -5,9 +5,7 @@ | ||||
| var cli = require('cli'); | ||||
| var pkg = require('../package.json'); | ||||
| var dig = require('dig.js/dns-request'); | ||||
| var dgram = require('dgram'); | ||||
| var dnsjs = require('dns-suite'); | ||||
| var crypto = require('crypto'); | ||||
| var common = require('dig.js/common'); | ||||
| var defaultNameservers = require('dns').getServers(); | ||||
| var hexdump; | ||||
| @ -49,8 +47,32 @@ cli.main(function (args, cli) { | ||||
|       cli.norecurse = true; | ||||
|       return; | ||||
|     } | ||||
|     if (arg === '+notcp') { | ||||
|       if (cli.notcp) { | ||||
|         console.error("'+notcp' was specified more than once"); | ||||
|         process.exit(1); | ||||
|         return; | ||||
|       } | ||||
|       cli.notcp = true; | ||||
|       return; | ||||
|     } | ||||
|     if (arg === '+tcp') { | ||||
|       if (cli.tcp) { | ||||
|         console.error("'+tcp' was specified more than once"); | ||||
|         process.exit(1); | ||||
|         return; | ||||
|       } | ||||
|       cli.tcp = true; | ||||
|       return; | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   if (!cli.tcp) { | ||||
|     if (!cli.notcp) { | ||||
|       console.info("[WARNING] Set '+notcp' to disable tcp connections. The default behavior changes to +tcp in v1.3"); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if (cli.mdns) { | ||||
|     if (!cli.type) { | ||||
|       cli.type = cli.t = 'PTR'; | ||||
| @ -73,32 +95,10 @@ cli.main(function (args, cli) { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   var handlers = {}; | ||||
|   var server = dgram.createSocket({ | ||||
|     type: cli.udp6 ? 'udp6' : 'udp4' | ||||
|   , reuseAddr: true | ||||
|   }); | ||||
|   server.bind({ | ||||
|     port: cli.port | ||||
|   , address: cli.address | ||||
|   }); | ||||
| 
 | ||||
|   handlers.onError = function (err) { | ||||
|     if ('EACCES' === err.code) { | ||||
|       console.error(""); | ||||
|       console.error("EACCES: Couldn't bind to port. You probably need to use sudo, authbind, or setcap."); | ||||
|       console.error(""); | ||||
|       process.exit(123); | ||||
|       return; | ||||
|     } | ||||
|     console.error("error:", err.stack); | ||||
|     server.close(); | ||||
|   }; | ||||
| 
 | ||||
|   handlers.onMessage = function (nb, rinfo) { | ||||
|     console.log('[DEBUG] got a message'); | ||||
| 
 | ||||
|     var queryAb = nb.buffer.slice(nb.byteOffset, nb.byteOffset + nb.byteLength); | ||||
|   var dnsd = {}; | ||||
|   dnsd.onMessage = function (nb, cb) { | ||||
|     var byteOffset = nb._dnsByteOffset || nb.byteOffset; | ||||
|     var queryAb = nb.buffer.slice(byteOffset, byteOffset + nb.byteLength); | ||||
|     var query; | ||||
|     var count; | ||||
| 
 | ||||
| @ -215,12 +215,11 @@ cli.main(function (args, cli) { | ||||
|         console.error("Could not write empty DNS response"); | ||||
|         console.error(e); | ||||
|         console.error(emptyResp); | ||||
|         cb(e, null, '[DEV] response sent (empty)'); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       server.send(newAb, rinfo.port, rinfo.address, function () { | ||||
|         console.log('[DEV] response sent (empty)', rinfo.port, rinfo.address); | ||||
|       }); | ||||
|       cb(null, newAb, '[DEV] response sent (empty)'); | ||||
|     } | ||||
| 
 | ||||
|     function sendResponse(newPacket) { | ||||
| @ -232,12 +231,11 @@ cli.main(function (args, cli) { | ||||
|         console.error("Could not write DNS response from local"); | ||||
|         console.error(e); | ||||
|         console.error(newPacket); | ||||
|         cb(e, null, '[DEV] response sent (local query)'); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       server.send(newAb, rinfo.port, rinfo.address, function () { | ||||
|         console.log('[DEV] response sent (local query)', rinfo.port, rinfo.address); | ||||
|       }); | ||||
|       cb(null, newAb, '[DEV] response sent (local query)'); | ||||
|     } | ||||
| 
 | ||||
|     function recurse() { | ||||
| @ -290,12 +288,11 @@ cli.main(function (args, cli) { | ||||
|             } catch(e) { | ||||
|               console.error("Could not write DNS response"); | ||||
|               console.error(newResponse); | ||||
|               cb(e, null, '[DEV] response sent'); | ||||
|               return; | ||||
|             } | ||||
| 
 | ||||
|             server.send(newAb, rinfo.port, rinfo.address, function () { | ||||
|               console.log('[DEV] response sent', rinfo.port, rinfo.address); | ||||
|             }); | ||||
|             cb(null, newAb, '[DEV] response sent'); | ||||
|           } | ||||
|         } | ||||
| 
 | ||||
| @ -335,7 +332,8 @@ cli.main(function (args, cli) { | ||||
|               console.log('request sent to', res.nameserver); | ||||
|             } | ||||
|             */ | ||||
|             console.log('[DEV] query sent (recurse)', rinfo.port, rinfo.address); | ||||
|             //console.log('[DEV] query sent (recurse)', rinfo.port, rinfo.address);
 | ||||
|             //dnsd.onSent('[DEV] query sent (recurse)');
 | ||||
|           } | ||||
|         , onTimeout: function (res) { | ||||
|             console.log(";; [" + q.name + "] connection timed out; no servers could be reached"); | ||||
| @ -393,40 +391,29 @@ cli.main(function (args, cli) { | ||||
|       return; | ||||
|     } | ||||
|     require('../lib/digd.js').query(engine, query, respondWithResults); | ||||
| 
 | ||||
|   }; | ||||
| 
 | ||||
|   handlers.onListening = function () { | ||||
|     /*jshint validthis:true*/ | ||||
|     var server = this; | ||||
|   cli.defaultNameservers = defaultNameservers; | ||||
|   require('../lib/udpd.js').create(cli, dnsd).on('listening', function () { | ||||
|     cli.chosenNameserver = cli.nameserver; | ||||
|     var index; | ||||
| 
 | ||||
|     if (!cli.chosenNameserver) { | ||||
|       index = crypto.randomBytes(2).readUInt16BE(0) % defaultNameservers.length; | ||||
|       cli.chosenNameserver = defaultNameservers[index]; | ||||
|       index = require('crypto').randomBytes(2).readUInt16BE(0) % cli.defaultNameservers.length; | ||||
|       cli.chosenNameserver = cli.defaultNameservers[index]; | ||||
|       if (cli.debug) { | ||||
|         console.log('index, defaultNameservers', index, defaultNameservers); | ||||
|         console.log('index, defaultNameservers', index, cli.defaultNameservers); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (cli.mdns || '224.0.0.251' === cli.nameserver) { | ||||
|       server.setBroadcast(true); | ||||
|       server.addMembership(cli.nameserver); | ||||
|   }); | ||||
|   if (cli.tcp /* TODO v1.3 !cli.notcp */) { | ||||
|     require('../lib/tcpd.js').create(cli, dnsd); | ||||
|   } | ||||
| 
 | ||||
|     console.log(''); | ||||
|     console.log('Bound and Listening:'); | ||||
|     console.log(server.address().address + '#' + server.address().port + ' (' + server.type + ')'); | ||||
|   }; | ||||
| 
 | ||||
|   console.log(''); | ||||
|   if (!cli.nocmd) { | ||||
|     console.log('; <<>> digd.js v' + pkg.version + ' <<>> ' + process.argv.slice(2).join(' ')); | ||||
|     console.log(';; global options: +cmd'); | ||||
|   } | ||||
| 
 | ||||
|   server.on('error', handlers.onError); | ||||
|   server.on('message', handlers.onMessage); | ||||
|   server.on('listening', handlers.onListening); | ||||
| }); | ||||
|  | ||||
							
								
								
									
										70
									
								
								lib/tcpd.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								lib/tcpd.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| module.exports.create = function (cli, dnsd) { | ||||
|   function runTcp() { | ||||
|     var tcpServer = require('net').createServer({ }, function (c) { | ||||
|       c.on('error', function (err) { | ||||
|         console.warn("TCP Connection Error:"); | ||||
|         console.warn(err); | ||||
|       }); | ||||
|       c.on('data', function (nb) { | ||||
|         //console.log('TCP data.length:', nb.length);
 | ||||
|         //console.log(nb.toString('hex'));
 | ||||
| 
 | ||||
|         // DNS packets include a 2-byte length header
 | ||||
|         var count = nb.length; | ||||
|         var length = nb[0] << 8; | ||||
|         length = length | nb[1]; | ||||
|         count -= 2; | ||||
|         // TODO slice?
 | ||||
|         nb._dnsByteOffset = nb.byteOffset + 2; | ||||
| 
 | ||||
|         if (length !== count) { | ||||
|           console.error("Handling TCP packets > 512 bytes not implemented."); | ||||
|           c.end(); | ||||
|           return; | ||||
|         } | ||||
| 
 | ||||
|         // TODO pad two bytes for lengths
 | ||||
|         dnsd.onMessage(nb, function (err, newAb, dbgmsg) { | ||||
|           var lenbuf = Buffer.from([ newAb.length >> 8, newAb.length & 255 ]); | ||||
|           // TODO XXX generate legit error packet
 | ||||
|           if (err) { console.error("Error", err); c.end(); return; } | ||||
|           console.log('TCP ' + dbgmsg); | ||||
| 
 | ||||
|           c.write(lenbuf); | ||||
|           c.end(newAb); | ||||
|         }); | ||||
|       }); | ||||
|       c.on('end', function () { | ||||
|         console.log('TCP client disconnected from server'); | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     tcpServer.on('error', function (err) { | ||||
|       if ('EADDRINUSE' === err.code) { | ||||
|         console.error("Port '" + cli.port + "' is already in use."); | ||||
|         tcpServer.close(); | ||||
|         process.exit(0); | ||||
|       } | ||||
|       if ('EACCES' === err.code) { | ||||
|         console.error("Could not bind on port '" + cli.port + "': EACCESS (you probably need root permissions)"); | ||||
|         tcpServer.close(); | ||||
|         process.exit(0); | ||||
|       } | ||||
|       console.error("TCP Server Error:"); | ||||
|       console.error(err); | ||||
|       tcpServer.close(function () { | ||||
|         setTimeout(runTcp, 1000); | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     tcpServer.listen(cli.port, function () { | ||||
|       console.log('TCP Server bound'); | ||||
|     }); | ||||
| 
 | ||||
|     return tcpServer; | ||||
|   } | ||||
| 
 | ||||
|   return runTcp(); | ||||
| }; | ||||
							
								
								
									
										58
									
								
								lib/udpd.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								lib/udpd.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| module.exports.create = function (cli, dnsd) { | ||||
|   var server = require('dgram').createSocket({ | ||||
|     type: cli.udp6 ? 'udp6' : 'udp4' | ||||
|   , reuseAddr: true | ||||
|   }); | ||||
|   server.bind({ | ||||
|     port: cli.port | ||||
|   , address: cli.address | ||||
|   }); | ||||
| 
 | ||||
|   var handlers = {}; | ||||
|   handlers.onError = function (err) { | ||||
|     if ('EACCES' === err.code) { | ||||
|       console.error(""); | ||||
|       console.error("EACCES: Couldn't bind to port. You probably need to use sudo, authbind, or setcap."); | ||||
|       console.error(""); | ||||
|       process.exit(123); | ||||
|       return; | ||||
|     } | ||||
|     console.error("error:", err.stack); | ||||
|     server.close(); | ||||
|   }; | ||||
| 
 | ||||
|   handlers.onMessage = function (nb, rinfo) { | ||||
|     //console.log('[DEBUG] got a UDP message', nb.length);
 | ||||
|     //console.log(nb.toString('hex'));
 | ||||
| 
 | ||||
|     dnsd.onMessage(nb, function (err, newAb, dbgmsg) { | ||||
|       // TODO send legit error message
 | ||||
|       if (err) { server.send(Buffer.from([0x00])); return; } | ||||
|       server.send(newAb, rinfo.port, rinfo.address, function () { | ||||
|         console.log(dbgmsg, rinfo.port, rinfo.address); | ||||
|       }); | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   handlers.onListening = function () { | ||||
|     /*jshint validthis:true*/ | ||||
|     var server = this; | ||||
| 
 | ||||
|     if (cli.mdns || '224.0.0.251' === cli.nameserver) { | ||||
|       server.setBroadcast(true); | ||||
|       server.addMembership(cli.nameserver); | ||||
|     } | ||||
| 
 | ||||
|     console.log(''); | ||||
|     console.log('Bound and Listening:'); | ||||
|     console.log(server.address().address + '#' + server.address().port + ' (' + server.type + ')'); | ||||
|   }; | ||||
| 
 | ||||
|   server.on('error', handlers.onError); | ||||
|   server.on('message', handlers.onMessage); | ||||
|   server.on('listening', handlers.onListening); | ||||
| 
 | ||||
|   return server; | ||||
| }; | ||||
| @ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "digd.js", | ||||
|   "version": "1.2.0", | ||||
|   "version": "1.2.1", | ||||
|   "description": "A lightweight DNS / mDNS daemon (server) for creating and capturing DNS and mDNS query and response packets to disk as binary and/or JSON. Options are similar to the Unix dig command.", | ||||
|   "main": "bin/digd.js", | ||||
|   "homepage": "https://git.coolaj86.com/coolaj86/digd.js", | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user