From cce3988a397f91d5933a2eab0ac45b06bad45bd2 Mon Sep 17 00:00:00 2001 From: Micooz Date: Sun, 18 Jun 2017 20:07:17 +0800 Subject: [PATCH] chore(lib): update --- lib/core/client-proxy.js | 2 +- lib/core/socket.js | 2 +- lib/presets/aead-random-cipher.js | 2 +- lib/presets/obfs-tls1.2-ticket.js | 2 +- lib/presets/ss-aead-cipher.js | 2 +- lib/presets/ss-base.js | 2 +- lib/presets/ss-stream-cipher.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/core/client-proxy.js b/lib/core/client-proxy.js index 26c4866..3b22092 100644 --- a/lib/core/client-proxy.js +++ b/lib/core/client-proxy.js @@ -1 +1 @@ -'use strict';Object.defineProperty(exports,'__esModule',{value:true});exports.ClientProxy=undefined;var _ip=require('ip');var _ip2=_interopRequireDefault(_ip);var _utils=require('../utils');var _socks=require('../proxies/socks5');var _socks2=require('../proxies/socks4');var _http=require('../proxies/http');var _common=require('../proxies/common');function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}class ClientProxy{constructor(props){this._socksTcpReady=false;this._socksUdpReady=false;this._httpReady=false;this.onHandshakeDone=props.onHandshakeDone}isDone(){return[this._socksTcpReady,this._socksUdpReady,this._httpReady].some(v=>!!v)}makeHandshake(socket,buffer){this._trySocksHandshake(socket,buffer);if(!this.isDone()){this._tryHttpHandshake(socket,buffer)}}_trySocksHandshake(socket,buffer){if(!this.isDone()){this._trySocks5Handshake(socket,buffer)}if(!this.isDone()){this._trySocks4Handshake(socket,buffer)}}_trySocks4Handshake(socket,buffer){const request=_socks2.RequestMessage.parse(buffer);if(request!==null){const CMD=request.CMD,DSTIP=request.DSTIP,DSTADDR=request.DSTADDR,DSTPORT=request.DSTPORT;if(CMD===_common.REQUEST_COMMAND_CONNECT){const addr={type:DSTADDR.length>0?_common.ATYP_DOMAIN:_common.ATYP_V4,host:DSTADDR.length>0?DSTADDR:DSTIP,port:DSTPORT};if(addr.type!==_common.ATYP_DOMAIN){addr.host=_ip2.default.toString(addr.host)}this.onHandshakeDone(addr,()=>{const message=new _socks2.ReplyMessage({CMD:_common.REPLY_GRANTED});socket.write(message.toBuffer());this._socksTcpReady=true})}}}_trySocks5Handshake(socket,buffer){const identifier=_socks.IdentifierMessage.parse(buffer);if(identifier!==null){const message=new _socks.SelectMessage;socket.write(message.toBuffer());return}const request=_socks.RequestMessage.parse(buffer);if(request!==null){const type=request.CMD;switch(type){case _common.REQUEST_COMMAND_UDP:case _common.REQUEST_COMMAND_CONNECT:{const addr={type:request.ATYP,host:request.DSTADDR,port:request.DSTPORT};if(addr.type!==_common.ATYP_DOMAIN){addr.host=_ip2.default.toString(addr.host)}this.onHandshakeDone(addr,()=>{const message=new _socks.ReplyMessage({REP:_common.REPLY_SUCCEEDED});socket.write(message.toBuffer());if(type===_common.REQUEST_COMMAND_CONNECT){this._socksTcpReady=true}else{this._socksUdpReady=true}});break}default:{const message=new _socks.ReplyMessage({REP:_common.REPLY_COMMAND_NOT_SUPPORTED});socket.write(message.toBuffer());break}}}}_tryHttpHandshake(socket,buffer){const request=_http.HttpRequestMessage.parse(buffer);if(request!==null){const METHOD=request.METHOD,HOST=request.HOST;const addr=(0,_utils.parseURI)(HOST.toString());this.onHandshakeDone(addr,onForward=>{if(METHOD.toString()==='CONNECT'){const message=new _http.ConnectReplyMessage;socket.write(message.toBuffer())}else{onForward(buffer)}this._httpReady=true})}}}exports.ClientProxy=ClientProxy; \ No newline at end of file +'use strict';Object.defineProperty(exports,'__esModule',{value:true});exports.ClientProxy=undefined;var _net=require('net');var _net2=_interopRequireDefault(_net);var _ip=require('ip');var _ip2=_interopRequireDefault(_ip);var _utils=require('../utils');var _socks=require('../proxies/socks5');var _socks2=require('../proxies/socks4');var _http=require('../proxies/http');var _common=require('../proxies/common');function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}class ClientProxy{constructor(props){this._socksTcpReady=false;this._socksUdpReady=false;this._httpReady=false;this.onHandshakeDone=props.onHandshakeDone}isDone(){return[this._socksTcpReady,this._socksUdpReady,this._httpReady].some(v=>!!v)}makeHandshake(socket,buffer){this._trySocksHandshake(socket,buffer);if(!this.isDone()){this._tryHttpHandshake(socket,buffer)}}_trySocksHandshake(socket,buffer){if(!this.isDone()){this._trySocks5Handshake(socket,buffer)}if(!this.isDone()){this._trySocks4Handshake(socket,buffer)}}_trySocks4Handshake(socket,buffer){const request=_socks2.RequestMessage.parse(buffer);if(request!==null){const CMD=request.CMD,DSTIP=request.DSTIP,DSTADDR=request.DSTADDR,DSTPORT=request.DSTPORT;if(CMD===_common.REQUEST_COMMAND_CONNECT){const addr={type:DSTADDR.length>0?_common.ATYP_DOMAIN:_common.ATYP_V4,host:DSTADDR.length>0?DSTADDR:DSTIP,port:DSTPORT};this.onHandshakeDone(addr,()=>{const message=new _socks2.ReplyMessage({CMD:_common.REPLY_GRANTED});socket.write(message.toBuffer());this._socksTcpReady=true})}}}_trySocks5Handshake(socket,buffer){const identifier=_socks.IdentifierMessage.parse(buffer);if(identifier!==null){const message=new _socks.SelectMessage;socket.write(message.toBuffer());return}const request=_socks.RequestMessage.parse(buffer);if(request!==null){const type=request.CMD;switch(type){case _common.REQUEST_COMMAND_UDP:case _common.REQUEST_COMMAND_CONNECT:{const addr={type:request.ATYP,host:request.DSTADDR,port:request.DSTPORT};this.onHandshakeDone(addr,()=>{const message=new _socks.ReplyMessage({REP:_common.REPLY_SUCCEEDED});socket.write(message.toBuffer());if(type===_common.REQUEST_COMMAND_CONNECT){this._socksTcpReady=true}else{this._socksUdpReady=true}});break}default:{const message=new _socks.ReplyMessage({REP:_common.REPLY_COMMAND_NOT_SUPPORTED});socket.write(message.toBuffer());break}}}}_tryHttpHandshake(socket,buffer){const request=_http.HttpRequestMessage.parse(buffer);if(request!==null){const METHOD=request.METHOD,URI=request.URI,HOST=request.HOST;const method=METHOD.toString();let addr={};if(method==='CONNECT'){addr=(0,_utils.parseURI)(URI.toString())}else{let type=null;let host=HOST.toString();if(_net2.default.isIP(host)){if(_net2.default.isIPv4(host)){type=_common.ATYP_V4}else{type=_common.ATYP_V6}host=_ip2.default.toBuffer(host)}else{type=_common.ATYP_DOMAIN;host=HOST}addr={type,host,port:Buffer.from([0,80])}}this.onHandshakeDone(addr,onForward=>{if(method==='CONNECT'){const message=new _http.ConnectReplyMessage;socket.write(message.toBuffer())}else{onForward(buffer)}this._httpReady=true})}}}exports.ClientProxy=ClientProxy; \ No newline at end of file diff --git a/lib/core/socket.js b/lib/core/socket.js index cc3c1e4..26665e0 100755 --- a/lib/core/socket.js +++ b/lib/core/socket.js @@ -1 +1 @@ -'use strict';Object.defineProperty(exports,'__esModule',{value:true});exports.Socket=undefined;var _slicedToArray=function(){function sliceIterator(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break}}catch(err){_d=true;_e=err}finally{try{if(!_n&&_i['return'])_i['return']()}finally{if(_d)throw _e}}return _arr}return function(arr,i){if(Array.isArray(arr)){return arr}else if(Symbol.iterator in Object(arr)){return sliceIterator(arr,i)}else{throw new TypeError('Invalid attempt to destructure non-iterable instance')}}}();var _extends=Object.assign||function(target){for(var i=1;i=MAX_BUFFERED_SIZE){this._bsocket.pause()}}onBackward(buffer){if(__IS_CLIENT__){this.clientIn(buffer)}else{if(this._isRedirect){this.bsocketWritable&&this._bsocket.write(buffer);return}this.serverOut(buffer)}if(this._bsocket&&this._bsocket.bufferSize>=MAX_BUFFERED_SIZE){this._fsocket.pause()}}onError(err){_logger2.default.warn(`[socket] [${this.remote}] ${err.code} - ${err.message}`);_profile.Profile.errors+=1}onForwardSocketDrain(){if(this._bsocket!==null&&!this._bsocket.destroyed){this._bsocket.resume()}else{this.onForwardSocketClose()}}onForwardSocketTimeout({host,port}){_logger2.default.warn(`[socket] [${host}:${port}] timeout: no I/O on the connection for ${__TIMEOUT__}s`);this.onForwardSocketClose()}onForwardSocketClose(){if(this._fsocket!==null&&!this._fsocket.destroyed){this._fsocket.destroy()}if(this._bsocket&&this._bsocket.bufferSize<=0){this.onBackwardSocketClose()}if(__IS_CLIENT__&&this._tracks.length>0){this.dumpTrack()}this._fsocket=null}onBackwardSocketDrain(){if(this._fsocket!==null&&!this._fsocket.destroyed){this._fsocket.resume()}else{this.onBackwardSocketClose()}}onBackwardSocketTimeout({host,port}){_logger2.default.warn(`[socket] [${host}:${port}] timeout: no I/O on the connection for ${__TIMEOUT__}s`);this.onBackwardSocketClose()}onBackwardSocketClose(){if(this._bsocket!==null&&!this._bsocket.destroyed){this._bsocket.destroy()}if(this._fsocket&&this._fsocket.bufferSize<=0){this.onForwardSocketClose()}if(__IS_SERVER__&&this._tracks.length>0){this.dumpTrack()}this._bsocket=null;this._onClose(this)}onHandshakeDone(addr,callback){const server=_balancer.Balancer.getFastest();if(lastServer===null||!(0,_lodash2.default)(server,lastServer)){_config.Config.initServer(server);lastServer=server;_logger2.default.info(`[balancer] use: ${__SERVER_HOST__}:${__SERVER_PORT__}`)}var _ref=[addr.host.toString(),addr.port.readUInt16BE(0)];const dstHost=_ref[0],dstPort=_ref[1];return this.connect({host:__SERVER_HOST__,port:__SERVER_PORT__,dstHost,dstPort},()=>{this.createPipe(addr);this._tracks.push(`${dstHost}:${dstPort}`);this._isHandshakeDone=true;callback(this.onForward)})}clientOut(buffer){if(this.fsocketWritable){try{this._pipe.feed(_middleware.MIDDLEWARE_DIRECTION_UPWARD,buffer)}catch(err){_logger2.default.error(`[socket] [${this.remote}]`,err)}}}serverIn(buffer){if(this.fsocketWritable||!this._isHandshakeDone){try{this._pipe.feed(_middleware.MIDDLEWARE_DIRECTION_DOWNWARD,buffer);this._tracks.push(TRACK_CHAR_DOWNLOAD);this._tracks.push(buffer.length)}catch(err){_logger2.default.error(`[socket] [${this.remote}]`,err)}}}serverOut(buffer){if(this.bsocketWritable){try{this._pipe.feed(_middleware.MIDDLEWARE_DIRECTION_UPWARD,buffer)}catch(err){_logger2.default.error(`[socket] [${this.remote}]`,err)}}}clientIn(buffer){if(this.bsocketWritable){try{this._pipe.feed(_middleware.MIDDLEWARE_DIRECTION_DOWNWARD,buffer);this._tracks.push(TRACK_CHAR_DOWNLOAD);this._tracks.push(buffer.length)}catch(err){_logger2.default.error(`[socket] [${this.remote}]`,err)}}}send(direction,buffer){if(direction===_middleware.MIDDLEWARE_DIRECTION_UPWARD){if(__IS_CLIENT__){this.clientForward(buffer)}else{this.serverBackward(buffer)}}else{if(__IS_CLIENT__){this.clientBackward(buffer)}else{this.serverForward(buffer)}}_profile.Profile.totalOut+=buffer.length}clientForward(buffer){if(this.fsocketWritable){this._fsocket.write(buffer);this._tracks.push(TRACK_CHAR_UPLOAD);this._tracks.push(buffer.length)}}serverForward(buffer){if(this.fsocketWritable){this._fsocket.write(buffer)}}serverBackward(buffer){if(this.bsocketWritable){this._bsocket.write(buffer);this._tracks.push(TRACK_CHAR_UPLOAD);this._tracks.push(buffer.length)}}clientBackward(buffer){if(this.bsocketWritable){this._bsocket.write(buffer)}}connect({host,port,dstHost,dstPort},callback){var _this=this;return _asyncToGenerator(function*(){if(host&&port){if(__IS_CLIENT__){_logger2.default.info(`[socket] [${_this.remote}] request: ${dstHost}:${dstPort}, connecting to: ${host}:${port}`)}else{_logger2.default.info(`[socket] [${_this.remote}] connecting to: ${host}:${port}`)}_this._tracks.push(`${host}:${port}`);try{const ip=yield dnsCache.get(host);_this._fsocket=_net2.default.connect({host:ip,port},callback);_this._fsocket.on('error',_this.onError);_this._fsocket.on('close',_this.onForwardSocketClose);_this._fsocket.on('timeout',_this.onForwardSocketTimeout.bind(_this,{host,port}));_this._fsocket.on('data',_this.onBackward);_this._fsocket.on('drain',_this.onForwardSocketDrain);_this._fsocket.setTimeout(__TIMEOUT__*1e3)}catch(err){_logger2.default.error(`[socket] [${_this.remote}] connect to ${host}:${port} failed due to: ${err.message}`)}}else{_logger2.default.warn(`unexpected host=${host} port=${port}`);_this.onBackwardSocketClose()}})()}createPipe(addr){const presets=__PRESETS__.map((preset,i)=>(0,_middleware.createMiddleware)(preset.name,_extends({},preset.params,i===0?addr:{})));this._pipe=new _pipe.Pipe({onNotified:this.onPipeNotified.bind(this)});this._pipe.setMiddlewares(_middleware.MIDDLEWARE_DIRECTION_UPWARD,presets);this._pipe.on(`next_${_middleware.MIDDLEWARE_DIRECTION_UPWARD}`,buf=>this.send(_middleware.MIDDLEWARE_DIRECTION_UPWARD,buf));this._pipe.on(`next_${_middleware.MIDDLEWARE_DIRECTION_DOWNWARD}`,buf=>this.send(_middleware.MIDDLEWARE_DIRECTION_DOWNWARD,buf))}onPipeNotified(action){if(__IS_SERVER__&&action.type===_defs.SOCKET_CONNECT_TO_DST){var _action$payload=action.payload;const targetAddress=_action$payload.targetAddress,onConnected=_action$payload.onConnected;return this.connect(targetAddress,()=>{this._isHandshakeDone=true;onConnected()})}if(action.type===_defs.PROCESSING_FAILED){return this.onPresetFailed(action)}}onPresetFailed(action){var _action$payload2=action.payload;const message=_action$payload2.message,orgData=_action$payload2.orgData;if(__IS_SERVER__&&__REDIRECT__!==''&&this._fsocket===null){var _REDIRECT__$split=__REDIRECT__.split(':'),_REDIRECT__$split2=_slicedToArray(_REDIRECT__$split,2);const host=_REDIRECT__$split2[0],port=_REDIRECT__$split2[1];_logger2.default.error(`[socket] [${this.remote}] connection is redirected to ${host}:${port} due to: ${message}`);this.connect({host,port},()=>{this._isRedirect=true;this.fsocketWritable&&this._fsocket.write(orgData)})}else{const timeout=(0,_utils.getRandomInt)(10,40);_logger2.default.error(`[socket] [${this.remote}] connection will be closed in ${timeout}s due to: ${message}`);setTimeout(()=>{this.onForwardSocketClose();this.onBackwardSocketClose()},timeout*1e3)}_profile.Profile.fatals+=1}dumpTrack(){let strs=[];let dp=0,db=0;let up=0,ub=0;let ud='';var _iteratorNormalCompletion=true;var _didIteratorError=false;var _iteratorError=undefined;try{for(var _iterator=this._tracks[Symbol.iterator](),_step;!(_iteratorNormalCompletion=(_step=_iterator.next()).done);_iteratorNormalCompletion=true){const el=_step.value;if(el===TRACK_CHAR_UPLOAD||el===TRACK_CHAR_DOWNLOAD){if(ud===el){continue}ud=el}if(Number.isInteger(el)){if(ud===TRACK_CHAR_DOWNLOAD){dp+=1;db+=el}if(ud===TRACK_CHAR_UPLOAD){up+=1;ub+=el}}strs.push(el)}}catch(err){_didIteratorError=true;_iteratorError=err}finally{try{if(!_iteratorNormalCompletion&&_iterator.return){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}}const perSize=Math.floor(TRACK_MAX_SIZE/2);if(strs.length>TRACK_MAX_SIZE){strs=strs.slice(0,perSize).concat([' ... ']).concat(strs.slice(-perSize))}const summary=__IS_CLIENT__?`out/in = ${up}/${dp}, ${ub}b/${db}b`:`in/out = ${dp}/${up}, ${db}b/${ub}b`;_logger2.default.info(`[socket] [${this.remote}] closed with summary(${summary}) abstract(${strs.join(' ')})`);this._tracks=[]}destroy(){this.onForwardSocketClose();this.onBackwardSocketClose()}}exports.Socket=Socket; \ No newline at end of file +'use strict';Object.defineProperty(exports,'__esModule',{value:true});exports.Socket=undefined;var _slicedToArray=function(){function sliceIterator(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break}}catch(err){_d=true;_e=err}finally{try{if(!_n&&_i['return'])_i['return']()}finally{if(_d)throw _e}}return _arr}return function(arr,i){if(Array.isArray(arr)){return arr}else if(Symbol.iterator in Object(arr)){return sliceIterator(arr,i)}else{throw new TypeError('Invalid attempt to destructure non-iterable instance')}}}();var _extends=Object.assign||function(target){for(var i=1;i=MAX_BUFFERED_SIZE){this._bsocket.pause()}}onBackward(buffer){if(__IS_CLIENT__){this.clientIn(buffer)}else{if(this._isRedirect){this.bsocketWritable&&this._bsocket.write(buffer);return}this.serverOut(buffer)}if(this._bsocket&&this._bsocket.bufferSize>=MAX_BUFFERED_SIZE){this._fsocket.pause()}}onError(err){_logger2.default.warn(`[socket] [${this.remote}] ${err.code} - ${err.message}`);_profile.Profile.errors+=1}onForwardSocketDrain(){if(this._bsocket!==null&&!this._bsocket.destroyed){this._bsocket.resume()}else{this.onForwardSocketClose()}}onForwardSocketTimeout({host,port}){_logger2.default.warn(`[socket] [${host}:${port}] timeout: no I/O on the connection for ${__TIMEOUT__}s`);this.onForwardSocketClose()}onForwardSocketClose(){if(this._fsocket!==null&&!this._fsocket.destroyed){this._fsocket.destroy()}if(this._bsocket&&this._bsocket.bufferSize<=0){this.onBackwardSocketClose()}if(__IS_CLIENT__&&this._tracks.length>0){this.dumpTrack()}this._fsocket=null}onBackwardSocketDrain(){if(this._fsocket!==null&&!this._fsocket.destroyed){this._fsocket.resume()}else{this.onBackwardSocketClose()}}onBackwardSocketTimeout({host,port}){_logger2.default.warn(`[socket] [${host}:${port}] timeout: no I/O on the connection for ${__TIMEOUT__}s`);this.onBackwardSocketClose()}onBackwardSocketClose(){if(this._bsocket!==null&&!this._bsocket.destroyed){this._bsocket.destroy()}if(this._fsocket&&this._fsocket.bufferSize<=0){this.onForwardSocketClose()}if(__IS_SERVER__&&this._tracks.length>0){this.dumpTrack()}this._bsocket=null;this._onClose(this)}onHandshakeDone(addr,callback){const server=_balancer.Balancer.getFastest();if(lastServer===null||!(0,_lodash2.default)(server,lastServer)){_config.Config.initServer(server);lastServer=server;_logger2.default.info(`[balancer] use: ${__SERVER_HOST__}:${__SERVER_PORT__}`)}var _ref=[addr.type===_common.ATYP_DOMAIN?addr.host.toString():_ip2.default.toString(addr.host),addr.port.readUInt16BE(0)];const dstHost=_ref[0],dstPort=_ref[1];return this.connect({host:__SERVER_HOST__,port:__SERVER_PORT__,dstHost,dstPort},()=>{this.createPipe(addr);this._tracks.push(`${dstHost}:${dstPort}`);this._isHandshakeDone=true;callback(this.onForward)})}clientOut(buffer){if(this.fsocketWritable){try{this._pipe.feed(_middleware.MIDDLEWARE_DIRECTION_UPWARD,buffer)}catch(err){_logger2.default.error(`[socket] [${this.remote}]`,err)}}}serverIn(buffer){if(this.fsocketWritable||!this._isHandshakeDone){try{this._pipe.feed(_middleware.MIDDLEWARE_DIRECTION_DOWNWARD,buffer);this._tracks.push(TRACK_CHAR_DOWNLOAD);this._tracks.push(buffer.length)}catch(err){_logger2.default.error(`[socket] [${this.remote}]`,err)}}}serverOut(buffer){if(this.bsocketWritable){try{this._pipe.feed(_middleware.MIDDLEWARE_DIRECTION_UPWARD,buffer)}catch(err){_logger2.default.error(`[socket] [${this.remote}]`,err)}}}clientIn(buffer){if(this.bsocketWritable){try{this._pipe.feed(_middleware.MIDDLEWARE_DIRECTION_DOWNWARD,buffer);this._tracks.push(TRACK_CHAR_DOWNLOAD);this._tracks.push(buffer.length)}catch(err){_logger2.default.error(`[socket] [${this.remote}]`,err)}}}send(direction,buffer){if(direction===_middleware.MIDDLEWARE_DIRECTION_UPWARD){if(__IS_CLIENT__){this.clientForward(buffer)}else{this.serverBackward(buffer)}}else{if(__IS_CLIENT__){this.clientBackward(buffer)}else{this.serverForward(buffer)}}_profile.Profile.totalOut+=buffer.length}clientForward(buffer){if(this.fsocketWritable){this._fsocket.write(buffer);this._tracks.push(TRACK_CHAR_UPLOAD);this._tracks.push(buffer.length)}}serverForward(buffer){if(this.fsocketWritable){this._fsocket.write(buffer)}}serverBackward(buffer){if(this.bsocketWritable){this._bsocket.write(buffer);this._tracks.push(TRACK_CHAR_UPLOAD);this._tracks.push(buffer.length)}}clientBackward(buffer){if(this.bsocketWritable){this._bsocket.write(buffer)}}connect({host,port,dstHost,dstPort},callback){var _this=this;return _asyncToGenerator(function*(){if(host&&port){if(__IS_CLIENT__){_logger2.default.info(`[socket] [${_this.remote}] request: ${dstHost}:${dstPort}, connecting to: ${host}:${port}`)}else{_logger2.default.info(`[socket] [${_this.remote}] connecting to: ${host}:${port}`)}_this._tracks.push(`${host}:${port}`);try{const ip=yield dnsCache.get(host);_this._fsocket=_net2.default.connect({host:ip,port},callback);_this._fsocket.on('error',_this.onError);_this._fsocket.on('close',_this.onForwardSocketClose);_this._fsocket.on('timeout',_this.onForwardSocketTimeout.bind(_this,{host,port}));_this._fsocket.on('data',_this.onBackward);_this._fsocket.on('drain',_this.onForwardSocketDrain);_this._fsocket.setTimeout(__TIMEOUT__*1e3)}catch(err){_logger2.default.error(`[socket] [${_this.remote}] connect to ${host}:${port} failed due to: ${err.message}`)}}else{_logger2.default.warn(`unexpected host=${host} port=${port}`);_this.onBackwardSocketClose()}})()}createPipe(addr){const presets=__PRESETS__.map((preset,i)=>(0,_middleware.createMiddleware)(preset.name,_extends({},preset.params,i===0?addr:{})));this._pipe=new _pipe.Pipe({onNotified:this.onPipeNotified.bind(this)});this._pipe.setMiddlewares(_middleware.MIDDLEWARE_DIRECTION_UPWARD,presets);this._pipe.on(`next_${_middleware.MIDDLEWARE_DIRECTION_UPWARD}`,buf=>this.send(_middleware.MIDDLEWARE_DIRECTION_UPWARD,buf));this._pipe.on(`next_${_middleware.MIDDLEWARE_DIRECTION_DOWNWARD}`,buf=>this.send(_middleware.MIDDLEWARE_DIRECTION_DOWNWARD,buf))}onPipeNotified(action){if(__IS_SERVER__&&action.type===_defs.SOCKET_CONNECT_TO_DST){var _action$payload=action.payload;const targetAddress=_action$payload.targetAddress,onConnected=_action$payload.onConnected;return this.connect(targetAddress,()=>{this._isHandshakeDone=true;onConnected()})}if(action.type===_defs.PROCESSING_FAILED){return this.onPresetFailed(action)}}onPresetFailed(action){var _action$payload2=action.payload;const message=_action$payload2.message,orgData=_action$payload2.orgData;if(__IS_SERVER__&&__REDIRECT__!==''&&this._fsocket===null){var _REDIRECT__$split=__REDIRECT__.split(':'),_REDIRECT__$split2=_slicedToArray(_REDIRECT__$split,2);const host=_REDIRECT__$split2[0],port=_REDIRECT__$split2[1];_logger2.default.error(`[socket] [${this.remote}] connection is redirected to ${host}:${port} due to: ${message}`);this.connect({host,port},()=>{this._isRedirect=true;this.fsocketWritable&&this._fsocket.write(orgData)})}else{const timeout=(0,_utils.getRandomInt)(10,40);_logger2.default.error(`[socket] [${this.remote}] connection will be closed in ${timeout}s due to: ${message}`);setTimeout(()=>{this.onForwardSocketClose();this.onBackwardSocketClose()},timeout*1e3)}_profile.Profile.fatals+=1}dumpTrack(){let strs=[];let dp=0,db=0;let up=0,ub=0;let ud='';var _iteratorNormalCompletion=true;var _didIteratorError=false;var _iteratorError=undefined;try{for(var _iterator=this._tracks[Symbol.iterator](),_step;!(_iteratorNormalCompletion=(_step=_iterator.next()).done);_iteratorNormalCompletion=true){const el=_step.value;if(el===TRACK_CHAR_UPLOAD||el===TRACK_CHAR_DOWNLOAD){if(ud===el){continue}ud=el}if(Number.isInteger(el)){if(ud===TRACK_CHAR_DOWNLOAD){dp+=1;db+=el}if(ud===TRACK_CHAR_UPLOAD){up+=1;ub+=el}}strs.push(el)}}catch(err){_didIteratorError=true;_iteratorError=err}finally{try{if(!_iteratorNormalCompletion&&_iterator.return){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}}const perSize=Math.floor(TRACK_MAX_SIZE/2);if(strs.length>TRACK_MAX_SIZE){strs=strs.slice(0,perSize).concat([' ... ']).concat(strs.slice(-perSize))}const summary=__IS_CLIENT__?`out/in = ${up}/${dp}, ${ub}b/${db}b`:`in/out = ${dp}/${up}, ${db}b/${ub}b`;_logger2.default.info(`[socket] [${this.remote}] closed with summary(${summary}) abstract(${strs.join(' ')})`);this._tracks=[]}destroy(){this.onForwardSocketClose();this.onBackwardSocketClose()}}exports.Socket=Socket; \ No newline at end of file diff --git a/lib/presets/aead-random-cipher.js b/lib/presets/aead-random-cipher.js index 1e2344b..b31f12b 100644 --- a/lib/presets/aead-random-cipher.js +++ b/lib/presets/aead-random-cipher.js @@ -1 +1 @@ -'use strict';Object.defineProperty(exports,'__esModule',{value:true});var _slicedToArray=function(){function sliceIterator(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break}}catch(err){_d=true;_e=err}finally{try{if(!_n&&_i['return'])_i['return']()}finally{if(_d)throw _e}}return _arr}return function(arr,i){if(Array.isArray(arr)){return arr}else if(Symbol.iterator in Object(arr)){return sliceIterator(arr,i)}else{throw new TypeError('Invalid attempt to destructure non-iterable instance')}}}();var _crypto=require('crypto');var _crypto2=_interopRequireDefault(_crypto);var _utils=require('../utils');var _defs=require('./defs');function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}const NONCE_LEN=12;const TAG_LEN=16;const MIN_CHUNK_LEN=TAG_LEN*2+3;const MIN_CHUNK_SPLIT_LEN=2048;const MAX_CHUNK_SPLIT_LEN=16383;const DEFAULT_FACTOR=2;const ciphers=['aes-128-gcm','aes-192-gcm','aes-256-gcm'];const HKDF_HASH_ALGORITHM='sha1';class AeadRandomCipherPreset extends _defs.IPreset{constructor({method,info,factor}){super();this._cipherName='';this._info=null;this._factor=DEFAULT_FACTOR;this._rawKey=null;this._cipherKey=null;this._decipherKey=null;this._cipherNonce=0;this._decipherNonce=0;this._nextExpectDecipherNonce=0;this._adBuf=null;if(typeof method==='undefined'||method===''){throw Error('\'method\' must be set.')}if(!ciphers.includes(method)){throw Error(`method \'${method}\' is not supported.`)}if(typeof info!=='string'||info.length<=0){throw Error('\'info\' must be a non-empty string.')}if(typeof factor==='undefined'){factor=DEFAULT_FACTOR}else{if(!Number.isInteger(factor)){throw Error('\'factor\' must be an integer.')}if(factor<1||factor>10){throw Error('\'factor\' must be in [1, 10].')}}this._cipherName=method;this._info=Buffer.from(info);this._factor=factor;this._rawKey=global.__KEY__?Buffer.from(__KEY__):null;this._adBuf=new _utils.AdvancedBuffer({getPacketLength:this.onReceiving.bind(this)});this._adBuf.on('data',this.onChunkReceived.bind(this))}beforeOut({buffer}){let salt=null;if(this._cipherKey===null){const size=this._cipherName.split('-')[1]/8;salt=_crypto2.default.randomBytes(size);this._cipherKey=(0,_utils.HKDF)(HKDF_HASH_ALGORITHM,salt,this._rawKey,this._info,size)}const chunks=(0,_utils.getRandomChunks)(buffer,MIN_CHUNK_SPLIT_LEN,MAX_CHUNK_SPLIT_LEN).map(chunk=>{const paddingLen=this.getPaddingLength(this._cipherKey,this._cipherNonce);const padding=_crypto2.default.randomBytes(paddingLen);const dataLen=(0,_utils.numberToBuffer)(chunk.length);var _encrypt=this.encrypt(dataLen),_encrypt2=_slicedToArray(_encrypt,2);const encLen=_encrypt2[0],lenTag=_encrypt2[1];var _encrypt3=this.encrypt(chunk),_encrypt4=_slicedToArray(_encrypt3,2);const encData=_encrypt4[0],dataTag=_encrypt4[1];return Buffer.concat([padding,encLen,lenTag,encData,dataTag])});if(salt){return Buffer.concat([salt,...chunks])}else{return Buffer.concat(chunks)}}beforeIn({buffer,next,fail}){this._adBuf.put(buffer,{next,fail})}onReceiving(buffer,{fail}){if(this._decipherKey===null){const size=this._cipherName.split('-')[1]/8;if(buffer.length10){throw Error('\'factor\' must be in [1, 10].')}}this._cipherName=method;this._info=Buffer.from(info);this._factor=factor;this._rawKey=global.__KEY__?Buffer.from(__KEY__):null;this._adBuf=new _utils.AdvancedBuffer({getPacketLength:this.onReceiving.bind(this)});this._adBuf.on('data',this.onChunkReceived.bind(this))}beforeOut({buffer}){let salt=null;if(this._cipherKey===null){const size=this._cipherName.split('-')[1]/8;salt=_crypto2.default.randomBytes(size);this._cipherKey=(0,_utils.HKDF)(HKDF_HASH_ALGORITHM,salt,this._rawKey,this._info,size)}const chunks=(0,_utils.getRandomChunks)(buffer,MIN_CHUNK_SPLIT_LEN,MAX_CHUNK_SPLIT_LEN).map(chunk=>{const paddingLen=this.getPaddingLength(this._cipherKey,this._cipherNonce);const padding=_crypto2.default.randomBytes(paddingLen);const dataLen=(0,_utils.numberToBuffer)(chunk.length);var _encrypt=this.encrypt(dataLen),_encrypt2=_slicedToArray(_encrypt,2);const encLen=_encrypt2[0],lenTag=_encrypt2[1];var _encrypt3=this.encrypt(chunk),_encrypt4=_slicedToArray(_encrypt3,2);const encData=_encrypt4[0],dataTag=_encrypt4[1];return Buffer.concat([padding,encLen,lenTag,encData,dataTag])});if(salt){return Buffer.concat([salt,...chunks])}else{return Buffer.concat(chunks)}}beforeIn({buffer,next,fail}){this._adBuf.put(buffer,{next,fail})}onReceiving(buffer,{fail}){if(this._decipherKey===null){const size=this._cipherName.split('-')[1]/8;if(buffer.lengthApplicationData(chunk));return Buffer.concat(chunks)}}serverIn({buffer,next,direct,fail}){if(this._stage===TLS_STAGE_HELLO){this._stage=TLS_STAGE_CHANGE_CIPHER_SPEC;if(buffer.length<200){fail(`TLS handshake header(${buffer.length} bytes) is too short`);return}if(!buffer.slice(0,3).equals((0,_utils.hexStringToBuffer)('160301'))){fail('invalid TLS handshake header');return}const tlsLen=buffer.slice(3,5).readUInt16BE(0);if(tlsLen!==buffer.length-5){fail('unexpected TLS handshake header length');return}const random=[...(0,_utils.getUTC)(),..._crypto2.default.randomBytes(28)];const session=[...(0,_utils.hexStringToBuffer)('20'),..._crypto2.default.randomBytes(32)];const exts=[...(0,_utils.hexStringToBuffer)('ff01000100'),...(0,_utils.hexStringToBuffer)('00050000'),...(0,_utils.hexStringToBuffer)('00170000')];const body=[...(0,_utils.hexStringToBuffer)('0303'),...random,...session,...(0,_utils.hexStringToBuffer)('c02f'),...(0,_utils.hexStringToBuffer)('00'),...(0,_utils.numberToBuffer)(exts.length),...exts];const header=[...(0,_utils.hexStringToBuffer)('16'),...(0,_utils.hexStringToBuffer)('0303'),...(0,_utils.numberToBuffer)(1+3+body.length),...(0,_utils.hexStringToBuffer)('02'),...(0,_utils.numberToBuffer)(body.length,3)];const server_hello=[...header,...body];const change_cipher_spec=[...(0,_utils.hexStringToBuffer)('140303000101')];const finishedLen=(0,_utils.getRandomInt)(32,40);const finished=[...(0,_utils.hexStringToBuffer)('16'),...(0,_utils.hexStringToBuffer)('0303'),...(0,_utils.numberToBuffer)(finishedLen),..._crypto2.default.randomBytes(finishedLen)];return direct(Buffer.from([...server_hello,...change_cipher_spec,...finished]),true)}let _buffer=buffer;if(this._stage===TLS_STAGE_CHANGE_CIPHER_SPEC){this._stage=TLS_STAGE_APPLICATION_DATA;_buffer=buffer.slice(43)}this._adBuf.put(_buffer,{next,fail})}serverOut({buffer}){const chunks=(0,_utils.getRandomChunks)(buffer,MIN_AD_PAYLOAD_LEN,MAX_AD_PAYLOAD_LEN).map(chunk=>ApplicationData(chunk));return Buffer.concat(chunks)}clientIn({buffer,next,direct,fail}){if(this._stage===TLS_STAGE_CHANGE_CIPHER_SPEC){this._stage=TLS_STAGE_APPLICATION_DATA;const change_cipher_spec=[...(0,_utils.hexStringToBuffer)('140303000101')];const finished=[...(0,_utils.hexStringToBuffer)('16'),...(0,_utils.hexStringToBuffer)('0303'),...(0,_utils.hexStringToBuffer)('0020'),..._crypto2.default.randomBytes(32)];const chunks=(0,_utils.getRandomChunks)(this._pending,MIN_AD_PAYLOAD_LEN,MAX_AD_PAYLOAD_LEN).map(chunk=>ApplicationData(chunk));this._pending=null;return direct(Buffer.from([...change_cipher_spec,...finished,...Buffer.concat(chunks)]),true)}this._adBuf.put(buffer,{next,fail})}onReceiving(buffer){if(buffer.length<5){return}return 5+buffer.readUInt16BE(3)}onChunkReceived(chunk,{next}){next(chunk.slice(5))}}exports.default=ObfsTLS12TicketPreset; \ No newline at end of file +'use strict';Object.defineProperty(exports,'__esModule',{value:true});var _crypto=require('crypto');var _crypto2=_interopRequireDefault(_crypto);var _utils=require('../utils');var _defs=require('./defs');function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}const TLS_STAGE_HELLO=1;const TLS_STAGE_CHANGE_CIPHER_SPEC=2;const TLS_STAGE_APPLICATION_DATA=3;const MIN_AD_PAYLOAD_LEN=2048;const MAX_AD_PAYLOAD_LEN=16383;function ApplicationData(buffer){const len=(0,_utils.numberToBuffer)(buffer.length);return Buffer.concat([(0,_utils.hexStringToBuffer)('170303'),len,buffer])}class ObfsTLS12TicketPreset extends _defs.IPreset{constructor({sni}){super();this._sni=[];this._stage=TLS_STAGE_HELLO;this._pending=null;this._adBuf=null;if(typeof sni==='undefined'){throw Error('\'sni\' must be set')}if(!Array.isArray(sni)){sni=[sni]}if(sni.some(s=>typeof s!=='string'||s.length<1)){throw Error('\'sni\' must be a non-empty string or an array without empty strings')}this.onReceiving=this.onReceiving.bind(this);this.onChunkReceived=this.onChunkReceived.bind(this);this._sni=Array.isArray(sni)?sni:[sni];this._adBuf=new _utils.AdvancedBuffer({getPacketLength:this.onReceiving});this._adBuf.on('data',this.onChunkReceived)}getRandomSNI(){const index=_crypto2.default.randomBytes(1)[0]%this._sni.length;return Buffer.from(this._sni[index])}clientOut({buffer,direct}){if(this._stage===TLS_STAGE_HELLO){this._stage=TLS_STAGE_CHANGE_CIPHER_SPEC;this._pending=buffer;const sni=this.getRandomSNI();const random=[...(0,_utils.getUTC)(),..._crypto2.default.randomBytes(28)];const session=[...(0,_utils.hexStringToBuffer)('20'),..._crypto2.default.randomBytes(32)];const cipher_suites=[...(0,_utils.hexStringToBuffer)('001a'),...(0,_utils.hexStringToBuffer)('c02b'),...(0,_utils.hexStringToBuffer)('c02f'),...(0,_utils.hexStringToBuffer)('c02c'),...(0,_utils.hexStringToBuffer)('c030'),...(0,_utils.hexStringToBuffer)('cc14'),...(0,_utils.hexStringToBuffer)('cc13'),...(0,_utils.hexStringToBuffer)('c013'),...(0,_utils.hexStringToBuffer)('c014'),...(0,_utils.hexStringToBuffer)('009c'),...(0,_utils.hexStringToBuffer)('009d'),...(0,_utils.hexStringToBuffer)('002f'),...(0,_utils.hexStringToBuffer)('0035'),...(0,_utils.hexStringToBuffer)('000a')];const ext_server_name=[...(0,_utils.hexStringToBuffer)('0000'),...(0,_utils.numberToBuffer)(2+1+2+sni.length),...(0,_utils.numberToBuffer)(1+2+sni.length),...(0,_utils.hexStringToBuffer)('00'),...(0,_utils.numberToBuffer)(sni.length),...sni];const ticketLen=(0,_utils.getRandomInt)(200,400);const session_ticket=[...(0,_utils.hexStringToBuffer)('0023'),...(0,_utils.numberToBuffer)(ticketLen),..._crypto2.default.randomBytes(ticketLen)];const exts=[...(0,_utils.hexStringToBuffer)('ff01000100'),...ext_server_name,...(0,_utils.hexStringToBuffer)('00170000'),...session_ticket,...(0,_utils.hexStringToBuffer)('000d00140012040308040401050308050501080606010201'),...(0,_utils.hexStringToBuffer)('000500050100000000'),...(0,_utils.hexStringToBuffer)('00120000'),...(0,_utils.hexStringToBuffer)('75500000'),...(0,_utils.hexStringToBuffer)('000b00020100'),...(0,_utils.hexStringToBuffer)('000a0006000400170018')];const body=[...(0,_utils.hexStringToBuffer)('0303'),...random,...session,...cipher_suites,...(0,_utils.hexStringToBuffer)('01'),...(0,_utils.hexStringToBuffer)('00'),...(0,_utils.numberToBuffer)(exts.length),...exts];const header=[...(0,_utils.hexStringToBuffer)('16'),...(0,_utils.hexStringToBuffer)('0301'),...(0,_utils.numberToBuffer)(1+3+body.length),...(0,_utils.hexStringToBuffer)('01'),...(0,_utils.numberToBuffer)(body.length,3)];return direct(Buffer.from([...header,...body]))}if(this._stage===TLS_STAGE_APPLICATION_DATA){const chunks=(0,_utils.getRandomChunks)(buffer,MIN_AD_PAYLOAD_LEN,MAX_AD_PAYLOAD_LEN).map(chunk=>ApplicationData(chunk));return Buffer.concat(chunks)}}serverIn({buffer,next,direct,fail}){if(this._stage===TLS_STAGE_HELLO){this._stage=TLS_STAGE_CHANGE_CIPHER_SPEC;if(buffer.length<200){fail(`TLS handshake header(${buffer.length} bytes) is too short`);return}if(!buffer.slice(0,3).equals((0,_utils.hexStringToBuffer)('160301'))){fail('invalid TLS handshake header');return}const tlsLen=buffer.slice(3,5).readUInt16BE(0);if(tlsLen!==buffer.length-5){fail('unexpected TLS handshake header length');return}const random=[...(0,_utils.getUTC)(),..._crypto2.default.randomBytes(28)];const session=[...(0,_utils.hexStringToBuffer)('20'),..._crypto2.default.randomBytes(32)];const exts=[...(0,_utils.hexStringToBuffer)('ff01000100'),...(0,_utils.hexStringToBuffer)('00050000'),...(0,_utils.hexStringToBuffer)('00170000')];const body=[...(0,_utils.hexStringToBuffer)('0303'),...random,...session,...(0,_utils.hexStringToBuffer)('c02f'),...(0,_utils.hexStringToBuffer)('00'),...(0,_utils.numberToBuffer)(exts.length),...exts];const header=[...(0,_utils.hexStringToBuffer)('16'),...(0,_utils.hexStringToBuffer)('0303'),...(0,_utils.numberToBuffer)(1+3+body.length),...(0,_utils.hexStringToBuffer)('02'),...(0,_utils.numberToBuffer)(body.length,3)];const server_hello=[...header,...body];const ticket=_crypto2.default.randomBytes((0,_utils.getRandomInt)(200,255));const session_ticket=[...(0,_utils.hexStringToBuffer)('000004b0'),...(0,_utils.numberToBuffer)(ticket.length),...ticket];const new_session_ticket_body=[...(0,_utils.hexStringToBuffer)('04'),...(0,_utils.numberToBuffer)(session_ticket.length,3),...session_ticket];const new_session_ticket=[...(0,_utils.hexStringToBuffer)('160303'),...(0,_utils.numberToBuffer)(new_session_ticket_body.length),...new_session_ticket_body];const change_cipher_spec=[...(0,_utils.hexStringToBuffer)('140303000101')];const finishedLen=(0,_utils.getRandomInt)(32,40);const finished=[...(0,_utils.hexStringToBuffer)('16'),...(0,_utils.hexStringToBuffer)('0303'),...(0,_utils.numberToBuffer)(finishedLen),..._crypto2.default.randomBytes(finishedLen)];return direct(Buffer.from([...server_hello,...new_session_ticket,...change_cipher_spec,...finished]),true)}let _buffer=buffer;if(this._stage===TLS_STAGE_CHANGE_CIPHER_SPEC){this._stage=TLS_STAGE_APPLICATION_DATA;_buffer=buffer.slice(43)}this._adBuf.put(_buffer,{next,fail})}serverOut({buffer}){const chunks=(0,_utils.getRandomChunks)(buffer,MIN_AD_PAYLOAD_LEN,MAX_AD_PAYLOAD_LEN).map(chunk=>ApplicationData(chunk));return Buffer.concat(chunks)}clientIn({buffer,next,direct,fail}){if(this._stage===TLS_STAGE_CHANGE_CIPHER_SPEC){this._stage=TLS_STAGE_APPLICATION_DATA;const change_cipher_spec=[...(0,_utils.hexStringToBuffer)('140303000101')];const finished=[...(0,_utils.hexStringToBuffer)('16'),...(0,_utils.hexStringToBuffer)('0303'),...(0,_utils.hexStringToBuffer)('0020'),..._crypto2.default.randomBytes(32)];const chunks=(0,_utils.getRandomChunks)(this._pending,MIN_AD_PAYLOAD_LEN,MAX_AD_PAYLOAD_LEN).map(chunk=>ApplicationData(chunk));this._pending=null;return direct(Buffer.from([...change_cipher_spec,...finished,...Buffer.concat(chunks)]),true)}this._adBuf.put(buffer,{next,fail})}onReceiving(buffer){if(buffer.length<5){return}return 5+buffer.readUInt16BE(3)}onChunkReceived(chunk,{next}){next(chunk.slice(5))}}exports.default=ObfsTLS12TicketPreset; \ No newline at end of file diff --git a/lib/presets/ss-aead-cipher.js b/lib/presets/ss-aead-cipher.js index 4a11a4f..f6240b1 100644 --- a/lib/presets/ss-aead-cipher.js +++ b/lib/presets/ss-aead-cipher.js @@ -1 +1 @@ -'use strict';Object.defineProperty(exports,'__esModule',{value:true});var _slicedToArray=function(){function sliceIterator(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break}}catch(err){_d=true;_e=err}finally{try{if(!_n&&_i['return'])_i['return']()}finally{if(_d)throw _e}}return _arr}return function(arr,i){if(Array.isArray(arr)){return arr}else if(Symbol.iterator in Object(arr)){return sliceIterator(arr,i)}else{throw new TypeError('Invalid attempt to destructure non-iterable instance')}}}();var _crypto=require('crypto');var _crypto2=_interopRequireDefault(_crypto);var _utils=require('../utils');var _defs=require('./defs');function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}const NONCE_LEN=12;const TAG_LEN=16;const MIN_CHUNK_LEN=TAG_LEN*2+3;const MIN_CHUNK_SPLIT_LEN=2048;const MAX_CHUNK_SPLIT_LEN=16383;const ciphers=['aes-128-gcm','aes-192-gcm','aes-256-gcm'];const HKDF_HASH_ALGORITHM='sha1';class SSAeadCipherPreset extends _defs.IPreset{constructor({method,info}){super();this._cipherName='';this._info=null;this._cipherKey=null;this._decipherKey=null;this._cipherNonce=0;this._decipherNonce=0;this._adBuf=null;if(typeof method==='undefined'||method===''){throw Error('\'method\' must be set.')}if(!ciphers.includes(method)){throw Error(`method \'${method}\' is not supported.`)}this._cipherName=method;this._info=Buffer.from(info);this._adBuf=new _utils.AdvancedBuffer({getPacketLength:this.onReceiving.bind(this)});this._adBuf.on('data',this.onChunkReceived.bind(this))}beforeOut({buffer}){let salt=null;if(this._cipherKey===null){const size=this._cipherName.split('-')[1]/8;salt=_crypto2.default.randomBytes(size);this._cipherKey=(0,_utils.HKDF)(HKDF_HASH_ALGORITHM,salt,(0,_utils.EVP_BytesToKey)(__KEY__,size,16),this._info,size)}const chunks=(0,_utils.getRandomChunks)(buffer,MIN_CHUNK_SPLIT_LEN,MAX_CHUNK_SPLIT_LEN).map(chunk=>{const dataLen=(0,_utils.numberToBuffer)(chunk.length);var _encrypt=this.encrypt(dataLen),_encrypt2=_slicedToArray(_encrypt,2);const encLen=_encrypt2[0],lenTag=_encrypt2[1];var _encrypt3=this.encrypt(chunk),_encrypt4=_slicedToArray(_encrypt3,2);const encData=_encrypt4[0],dataTag=_encrypt4[1];return Buffer.concat([encLen,lenTag,encData,dataTag])});if(salt){return Buffer.concat([salt,...chunks])}else{return Buffer.concat(chunks)}}beforeIn({buffer,next,fail}){this._adBuf.put(buffer,{next,fail})}onReceiving(buffer,{fail}){if(this._decipherKey===null){const size=this._cipherName.split('-')[1]/8;if(buffer.length{const dataLen=(0,_utils.numberToBuffer)(chunk.length);var _encrypt=this.encrypt(dataLen),_encrypt2=_slicedToArray(_encrypt,2);const encLen=_encrypt2[0],lenTag=_encrypt2[1];var _encrypt3=this.encrypt(chunk),_encrypt4=_slicedToArray(_encrypt3,2);const encData=_encrypt4[0],dataTag=_encrypt4[1];return Buffer.concat([encLen,lenTag,encData,dataTag])});if(salt){return Buffer.concat([salt,...chunks])}else{return Buffer.concat(chunks)}}beforeIn({buffer,next,fail}){this._adBuf.put(buffer,{next,fail})}onReceiving(buffer,{fail}){if(this._decipherKey===null){const size=this._cipherName.split('-')[1]/8;if(buffer.length{next(Buffer.concat([this._staging,data]));this._isHandshakeDone=true;this._staging=null}}});this._isAddressReceived=true}else{return buffer}}}exports.default=SSBasePreset; \ No newline at end of file +'use strict';Object.defineProperty(exports,'__esModule',{value:true});var _ip=require('ip');var _ip2=_interopRequireDefault(_ip);var _utils=require('../utils');var _defs=require('./defs');function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}const ATYP_V4=1;const ATYP_V6=4;const ATYP_DOMAIN=3;class SSBasePreset extends _defs.IPreset{constructor(addr){super();this._isHandshakeDone=false;this._isAddressReceived=false;this._atyp=ATYP_V4;this._host=null;this._port=null;this._staging=Buffer.alloc(0);if(__IS_CLIENT__){const type=addr.type,host=addr.host,port=addr.port;this._atyp=type;this._port=port;this._host=host}}clientOut({buffer}){if(!this._isHandshakeDone){this._isHandshakeDone=true;return Buffer.from([this._atyp,...(this._atyp===ATYP_DOMAIN?(0,_utils.numberToBuffer)(this._host.length,1):[]),...this._host,...this._port,...buffer])}else{return buffer}}serverIn({buffer,next,broadcast,fail}){if(!this._isHandshakeDone){if(this._isAddressReceived){this._staging=Buffer.concat([this._staging,buffer]);return}if(buffer.length<7){fail(`invalid length: ${buffer.length}`);return}const atyp=buffer[0];let addr;let port;let offset=3;switch(atyp){case ATYP_V4:addr=_ip2.default.toString(buffer.slice(1,5));port=buffer.slice(5,7).readUInt16BE(0);offset+=4;break;case ATYP_V6:if(buffer.length<19){fail(`invalid length: ${buffer.length}`);return}addr=_ip2.default.toString(buffer.slice(1,17));port=buffer.slice(16,18).readUInt16BE(0);offset+=16;break;case ATYP_DOMAIN:const domainLen=buffer[1];if(buffer.length{next(Buffer.concat([this._staging,data]));this._isHandshakeDone=true;this._staging=null}}});this._isAddressReceived=true}else{return buffer}}}exports.default=SSBasePreset; \ No newline at end of file diff --git a/lib/presets/ss-stream-cipher.js b/lib/presets/ss-stream-cipher.js index 3d29f2b..88a6b80 100644 --- a/lib/presets/ss-stream-cipher.js +++ b/lib/presets/ss-stream-cipher.js @@ -1 +1 @@ -'use strict';Object.defineProperty(exports,'__esModule',{value:true});var _crypto=require('crypto');var _crypto2=_interopRequireDefault(_crypto);var _utils=require('../utils');var _defs=require('./defs');function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}const IV_LEN=16;const ciphers=['aes-128-ctr','aes-192-ctr','aes-256-ctr','aes-128-cfb','aes-192-cfb','aes-256-cfb','camellia-128-cfb','camellia-192-cfb','camellia-256-cfb','aes-128-ofb','aes-192-ofb','aes-256-ofb','aes-128-cbc','aes-192-cbc','aes-256-cbc'];class SSStreamCipherPreset extends _defs.IPreset{constructor({method}){super();this._cipherName='';this._key=null;this._cipher=null;this._decipher=null;if(typeof method!=='string'||method===''){throw Error('\'method\' must be set')}if(!ciphers.includes(method)){throw Error(`method \'${method}\' is not supported.`)}this._cipherName=method;if(global.__KEY__){this._key=(0,_utils.EVP_BytesToKey)(__KEY__,this._cipherName.split('-')[1]/8,IV_LEN)}}beforeOut({buffer}){if(!this._cipher){const iv=_crypto2.default.randomBytes(IV_LEN);this._cipher=_crypto2.default.createCipheriv(this._cipherName,this._key,iv);return Buffer.concat([iv,this.encrypt(buffer)])}else{return this.encrypt(buffer)}}beforeIn({buffer}){if(!this._decipher){const iv=buffer.slice(0,IV_LEN);this._decipher=_crypto2.default.createDecipheriv(this._cipherName,this._key,iv);return this.decrypt(buffer.slice(IV_LEN))}else{return this.decrypt(buffer)}}encrypt(buffer){return this._cipher.update(buffer)}decrypt(buffer){return this._decipher.update(buffer)}}exports.default=SSStreamCipherPreset; \ No newline at end of file +'use strict';Object.defineProperty(exports,'__esModule',{value:true});var _crypto=require('crypto');var _crypto2=_interopRequireDefault(_crypto);var _utils=require('../utils');var _defs=require('./defs');function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}const IV_LEN=16;const ciphers=['aes-128-ctr','aes-192-ctr','aes-256-ctr','aes-128-cfb','aes-192-cfb','aes-256-cfb','camellia-128-cfb','camellia-192-cfb','camellia-256-cfb','aes-128-ofb','aes-192-ofb','aes-256-ofb','aes-128-cbc','aes-192-cbc','aes-256-cbc'];class SSStreamCipherPreset extends _defs.IPreset{constructor({method}){super();this._cipherName='';this._key=null;this._cipher=null;this._decipher=null;if(typeof method!=='string'||method===''){throw Error('\'method\' must be set')}if(!ciphers.includes(method)){throw Error(`method '${method}' is not supported.`)}this._cipherName=method;if(global.__KEY__){this._key=(0,_utils.EVP_BytesToKey)(__KEY__,this._cipherName.split('-')[1]/8,IV_LEN)}}beforeOut({buffer}){if(!this._cipher){const iv=_crypto2.default.randomBytes(IV_LEN);this._cipher=_crypto2.default.createCipheriv(this._cipherName,this._key,iv);return Buffer.concat([iv,this.encrypt(buffer)])}else{return this.encrypt(buffer)}}beforeIn({buffer}){if(!this._decipher){const iv=buffer.slice(0,IV_LEN);this._decipher=_crypto2.default.createDecipheriv(this._cipherName,this._key,iv);return this.decrypt(buffer.slice(IV_LEN))}else{return this.decrypt(buffer)}}encrypt(buffer){return this._cipher.update(buffer)}decrypt(buffer){return this._decipher.update(buffer)}}exports.default=SSStreamCipherPreset; \ No newline at end of file