[WIP] began dns server
This commit is contained in:
		
							parent
							
								
									51daf2378d
								
							
						
					
					
						commit
						01e753996a
					
				
							
								
								
									
										398
									
								
								bin/digd.js
									
									
									
									
									
								
							
							
						
						
									
										398
									
								
								bin/digd.js
									
									
									
									
									
								
							@ -1,267 +1,42 @@
 | 
			
		||||
#!/usr/bin/env node
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var dnsjs = require('dns-suite');
 | 
			
		||||
var cli = require('cli');
 | 
			
		||||
var dgram = require('dgram');
 | 
			
		||||
var dnsjs = require('dns-suite');
 | 
			
		||||
var hexdump = require('../hexdump');
 | 
			
		||||
var crypto = require('crypto');
 | 
			
		||||
var common = require('../common');
 | 
			
		||||
 | 
			
		||||
cli.parse({
 | 
			
		||||
//  'b': [ false, 'set source IP address (defaults to 0.0.0.0)', 'string' ]
 | 
			
		||||
  'debug': [ false, 'more verbose output', 'boolean', false ]
 | 
			
		||||
  '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 ]
 | 
			
		||||
, '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' ]
 | 
			
		||||
, 'address': [ false, 'ip address(es) to listen on (defaults to 0.0.0.0,::0)', 'string' ]
 | 
			
		||||
, '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 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 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) {
 | 
			
		||||
    console.log("YOYOYO GOT MESSAGE");
 | 
			
		||||
    var packet = dnsjs.DNSPacket.parse(nb.buffer.slice(nb.byteOffset, nb.byteOffset + nb.byteLength));
 | 
			
		||||
 | 
			
		||||
    if (opts.debug) {
 | 
			
		||||
      console.log('');
 | 
			
		||||
      console.log('DNS Request:');
 | 
			
		||||
      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 () {
 | 
			
		||||
    console.log("YOYOYO ON LISTENING");
 | 
			
		||||
    /*jshint validthis:true*/
 | 
			
		||||
    var server = this;
 | 
			
		||||
    var nameserver = opts.nameserver;
 | 
			
		||||
    var nameservers;
 | 
			
		||||
    var index;
 | 
			
		||||
 | 
			
		||||
    if (!nameserver) {
 | 
			
		||||
      nameservers = require('dns').getServers();
 | 
			
		||||
      index = crypto.randomBytes(2).readUInt16BE(0) % 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.on('error', handlers.onError);
 | 
			
		||||
  server.on('message', handlers.onMessage);
 | 
			
		||||
  server.on('listening', handlers.onListening);
 | 
			
		||||
 | 
			
		||||
  // 53 dns server
 | 
			
		||||
  // 5353 mdns
 | 
			
		||||
  console.log("YOYOYO BINDING ON", opts.port);
 | 
			
		||||
  server.bind(opts.port);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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");
 | 
			
		||||
    if (arg === '+norecurse') {
 | 
			
		||||
      if (cli.norecurse) {
 | 
			
		||||
        console.error("'+norecurse' was specified more than once");
 | 
			
		||||
        process.exit(1);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      cli.type = cli.t = arg.toUpperCase();
 | 
			
		||||
      cli.norecurse = true;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (/^\+time=/.test(arg)) {
 | 
			
		||||
      if (cli.timeout) {
 | 
			
		||||
        console.error("'+time=' was specified more than once");
 | 
			
		||||
        process.exit(1);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      cli.timeout = Math.round(parseInt(arg.replace(/\+time=/, ''), 10) * 1000);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (/^@/.test(arg)) {
 | 
			
		||||
      if (cli.nameserver) {
 | 
			
		||||
        console.error("'@server' was specified more than once");
 | 
			
		||||
        process.exit(1);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      cli.nameserver = cli.n = arg.substr(1);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (cli.query) {
 | 
			
		||||
      console.error("'query' was specified more than once");
 | 
			
		||||
      process.exit(1);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    cli.query = cli.q = arg;
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  if (cli.mdns) {
 | 
			
		||||
@ -277,55 +52,116 @@ cli.main(function (args, cli) {
 | 
			
		||||
    if (!cli.query) {
 | 
			
		||||
      cli.query = '_services._dns-sd._udp.local';
 | 
			
		||||
    }
 | 
			
		||||
    if (!cli.timeout) {
 | 
			
		||||
    if (!('timeout' in cli)) {
 | 
			
		||||
      cli.timeout = 3000;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!cli.type) {
 | 
			
		||||
    cli.type = cli.t = 'A';
 | 
			
		||||
  }
 | 
			
		||||
  if (!cli.port) {
 | 
			
		||||
    cli.port = cli.p = 53;
 | 
			
		||||
  }
 | 
			
		||||
  if (!cli.class) {
 | 
			
		||||
    cli.class = cli.c = 'IN';
 | 
			
		||||
  }
 | 
			
		||||
  if (!cli.query) {
 | 
			
		||||
    cli.query = 'example.com';
 | 
			
		||||
    /*
 | 
			
		||||
    console.error('');
 | 
			
		||||
    console.error('Usage:');
 | 
			
		||||
    console.error('digd.js [@server] [TYPE] [domain]');
 | 
			
		||||
    console.error('');
 | 
			
		||||
    console.error('Example:');
 | 
			
		||||
    console.error('digd.js daplie.com');
 | 
			
		||||
    console.error('');
 | 
			
		||||
    process.exit(1);
 | 
			
		||||
    */
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  var query = {
 | 
			
		||||
    header: {
 | 
			
		||||
      id: crypto.randomBytes(2).readUInt16BE(0)
 | 
			
		||||
    , qr: 0
 | 
			
		||||
    , opcode: 0
 | 
			
		||||
    , aa: 0     // NA
 | 
			
		||||
    , tc: 0     // NA
 | 
			
		||||
    , rd: 1
 | 
			
		||||
    , ra: 0     // NA
 | 
			
		||||
    , rcode: 0  // NA
 | 
			
		||||
  } else {
 | 
			
		||||
    if (!cli.port) {
 | 
			
		||||
      cli.port = cli.p = 53;
 | 
			
		||||
    }
 | 
			
		||||
  , question: [
 | 
			
		||||
      { name: cli.query
 | 
			
		||||
      , typeName: cli.type
 | 
			
		||||
      , className: cli.class
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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) {
 | 
			
		||||
    console.error("error:", err.stack);
 | 
			
		||||
    server.close();
 | 
			
		||||
  };
 | 
			
		||||
  handlers.onMessage = function (nb) {
 | 
			
		||||
    var queryAb = nb.buffer.slice(nb.byteOffset, nb.byteOffset + nb.byteLength);
 | 
			
		||||
    var query = dnsjs.DNSPacket.parse(queryAb);
 | 
			
		||||
 | 
			
		||||
    if (cli.debug) {
 | 
			
		||||
      console.log('');
 | 
			
		||||
      console.log('DNS Question:');
 | 
			
		||||
      console.log('');
 | 
			
		||||
      console.log(query);
 | 
			
		||||
      console.log('');
 | 
			
		||||
      console.log(hexdump(queryAb));
 | 
			
		||||
      console.log('');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    console.log(';; Got question:');
 | 
			
		||||
    console.log(';; ->>HEADER<<-');
 | 
			
		||||
    console.log(JSON.stringify(query.header));
 | 
			
		||||
    console.log('');
 | 
			
		||||
    console.log(';; QUESTION SECTION:');
 | 
			
		||||
    query.question.forEach(function (q) {
 | 
			
		||||
      console.log(';' + q.name + '.', ' ', q.className, q.typeName);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    function print(q) {
 | 
			
		||||
      var printer = common.printers[q.typeName] || common.printers.ANY;
 | 
			
		||||
      printer(q);
 | 
			
		||||
    }
 | 
			
		||||
    if (query.answer.length) {
 | 
			
		||||
      console.error('[ERROR] Query contains an answer section:');
 | 
			
		||||
      console.log(';; ANSWER SECTION:');
 | 
			
		||||
      query.answer.forEach(print);
 | 
			
		||||
    }
 | 
			
		||||
    if (query.authority.length) {
 | 
			
		||||
      console.log('');
 | 
			
		||||
      console.error('[ERROR] Query contains an authority section:');
 | 
			
		||||
      console.log(';; AUTHORITY SECTION:');
 | 
			
		||||
      query.authority.forEach(print);
 | 
			
		||||
    }
 | 
			
		||||
    if (query.additional.length) {
 | 
			
		||||
      console.log('');
 | 
			
		||||
      console.error('[ERROR] Query contains an additional section:');
 | 
			
		||||
      console.log(';; ADDITIONAL SECTION:');
 | 
			
		||||
      query.additional.forEach(print);
 | 
			
		||||
    }
 | 
			
		||||
    console.log('');
 | 
			
		||||
    console.log(';; MSG SIZE  rcvd: ' + nb.byteLength);
 | 
			
		||||
    console.log('');
 | 
			
		||||
 | 
			
		||||
    if (cli.output) {
 | 
			
		||||
      console.log('');
 | 
			
		||||
      common.writeQuery(cli, query, queryAb);
 | 
			
		||||
      //common.writeResponse(opts, query, nb, packet);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  handlers.onListening = function () {
 | 
			
		||||
    /*jshint validthis:true*/
 | 
			
		||||
    var server = this;
 | 
			
		||||
    var nameserver = cli.nameserver;
 | 
			
		||||
    var nameservers;
 | 
			
		||||
    var index;
 | 
			
		||||
 | 
			
		||||
    if (!nameserver) {
 | 
			
		||||
      nameservers = require('dns').getServers();
 | 
			
		||||
      index = crypto.randomBytes(2).readUInt16BE(0) % nameservers.length;
 | 
			
		||||
      nameserver = nameservers[index];
 | 
			
		||||
      if (cli.debug) {
 | 
			
		||||
        console.log(index, nameservers);
 | 
			
		||||
      }
 | 
			
		||||
    ]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if (!cli.daemon) {
 | 
			
		||||
    request(query, cli);
 | 
			
		||||
    return;
 | 
			
		||||
  console.log('');
 | 
			
		||||
  if (!cli.nocmd) {
 | 
			
		||||
    console.log('; <<>> dig.js ' + 'v0.0.0' + ' <<>> ' + process.argv.slice(2));
 | 
			
		||||
    console.log(';; global options: +cmd');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  server.on('error', handlers.onError);
 | 
			
		||||
  server.on('message', handlers.onMessage);
 | 
			
		||||
  server.on('listening', handlers.onListening);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user