#!/usr/bin/env node var cluster = require('cluster'), fs = require('fs'), net = require('net'), tls = require('tls'); var argv = require('yargs') .usage('Usage: $0 [options]') .option('w', { alias: 'workers', default: 4, describe: 'number of concurrent listeners' }) .option('p', { alias: 'port', default: 25125, describe: 'port to listen on' }) .option('l', { alias: 'level', default: 'info', describe: 'debug level' }) .option('k', { alias: 'key', describe: 'keypair to use for TLS' }) .option('c', { alias: 'cert', describe: 'server cert to send' }) .argv; function tlsToString(buf, start, end){ var t = buf[start]; var len = (buf[start+3] << 8) | (buf[start+4] & 0xff); if (t == 23) return {pos: start+len+5}; // no need to log application messages if (end < start+len+5) return {pos: start+len+5}; end = start+len+5; var str = 'ContentType: ' + buf[start] + '\nProtocolVersion: ' + buf.toString('hex', start+1, start+3); str += '\nLength: ' + len; if (t==22){ // handshake var pos = start+5; var msgtype = buf[pos++]; str += '\nHandshakeType: ' + msgtype; str += '\nLength: ' + buf.toString('hex', pos, pos+3); if (msgtype == 11) str += '\n(here was certificate)'; else str += '\nContents: ' + buf.toString('hex', pos+3, end); }else str = str + '\nContents: ' + buf.toString('hex', start+5, end); return {pos: end, str: str}; } function tlsChunkToString(chunk){ var str = ''; var pos = 0; while(pos chunk.length) str+='\n------\nnot complete TLS packet in chunk; the subsequent messages will be garbled'; pos = r.pos; } if (str == '') return null; return str; } if (cluster.isMaster){ for(i = 0; i < argv.workers; i++) cluster.fork(); }else{ var tlsserverid = cluster.worker.id*1000; var opts = {port: argv.port, host: '0.0.0.0', key: argv.key, cert: argv.cert}; console.log('starting server on ' + opts.port + ' using key: ' + opts.key + ' and cert: ' + opts.cert); opts.key = fs.readFileSync(opts.key); opts.cert = fs.readFileSync(opts.cert); net.createServer(opts, function(stream){ stream.on('error', function(err){}); var tserver = tls.createServer(opts); tserver.id = tlsserverid++; tserver.mysock = stream.remoteAddress + ':' + stream.remotePort; tserver.listen(0, '127.0.0.1', function(){ var s = net.connect(tserver.address().port, '127.0.0.1'); s.on('error', function(err){ stream.end(); }); if (argv.level != 'info'){ s.on('data', function(chunk) { var str = tlsChunkToString(chunk); if (str) console.log('tserver for socket ' + tserver.mysock + ' tls id: ' + tserver.id + ' sends ' + chunk.length + ' bytes' + str); }); stream.on('data', function(chunk){ var str = tlsChunkToString(chunk); if (str) console.log('tserver for socket ' + tserver.mysock + ' tls id: ' + tserver.id + 'receives ' + chunk.length + ' bytes' + str); }); } s.pipe(stream).pipe(s); }); var index = 0; tserver.on('secureConnection', function(sec){ if (index++ > 0) return sec.end(); sec.pipe(sec); // echo if (argv.level != 'info') sec.on('data', function(chunk){ console.log(chunk.toString()); }); }); tserver.on('clientError', function(err){ console.trace('clientError', err); }); stream.on('close', function(){ tserver.close(); }); }).listen(opts.port, opts.host); }