import { EventEmitter } from 'events' ; import * as net from 'net' ; import * as ip from 'ip' ; import { SmartBuffer } from 'smart-buffer' ; import { DEFAULT_TIMEOUT , SocksCommand , Socks4Response , Socks5Auth , Socks5HostType , Socks5Response , SocksClientOptions , SocksClientChainOptions , SocksClientState , SocksRemoteHost , SocksProxy , SocksClientBoundEvent , SocksClientEstablishedEvent , SocksUDPFrameDetails , ERRORS , SOCKS_INCOMING_PACKET_SIZES , SOCKS5_NO_ACCEPTABLE_AUTH , } from '../common/constants' ; import { validateSocksClientOptions , validateSocksClientChainOptions , } from '../common/helpers' ; import { ReceiveBuffer } from '../common/receivebuffer' ; import { SocksClientError , shuffleArray } from '../common/util' ; import { Duplex } from 'stream' ; declare interface SocksClient { on ( event , listener ) : this ; on ( event , listener ) : this ; on ( event , listener ) : this ; once ( event , listener ) : this ; once ( event , listener ) : this ; once ( event , listener ) : this ; once ( event , listener ) : this ; emit ( event , ... args ) : boolean ; emit ( event , err ) : boolean ; emit ( event , info ) : boolean ; emit ( event , info ) : boolean ; } class SocksClient extends EventEmitter implements SocksClient { private options : SocksClientOptions ; private socket : Duplex ; private state : SocksClientState ; private receiveBuffer : ReceiveBuffer ; private nextRequiredPacketBufferSize : number ; private socks5ChosenAuthType : number ; private onDataReceived : ( data : Buffer ) => void ; private onClose : ( hadError : boolean ) => void ; private onError : ( err : Error ) => void ; private onConnect : ( ) => void ; constructor ( options ) { super ( ) ; this . options = { ... options , } ; validateSocksClientOptions ( options ) ; this . setState ( SocksClientState . Created ) ; } param options { SocksClientOptions } param callback { Function } returns { Promise } static createConnection ( options , callback ? ) { return new Promise < SocksClientEstablishedEvent > ( ( resolve , reject ) => { try { validateSocksClientOptions ( options , [ 'connect' ] ) ; } catch ( err ) { if ( typeof callback === 'function' ) { callback ( err ) ; return resolve ( err as any ) ; } else { return reject ( err ) ; } } const client = new SocksClient ( options ) ; client . connect ( options . existing_socket ) ; client . once ( 'established' , ( info ) => { client . removeAllListeners ( ) ; if ( typeof callback === 'function' ) { callback ( null , info ) ; resolve ( info ) ; } else { resolve ( info ) ; } } ) ; client . once ( 'error' , ( err ) => { client . removeAllListeners ( ) ; if ( typeof callback === 'function' ) { callback ( err ) ; resolve ( err as any ) ; } else { reject ( err ) ; } } ) ; } ) ; } param options { SocksClientChainOptions } param callback { Function } returns { Promise } static createConnectionChain ( options , callback ? ) { return new Promise < SocksClientEstablishedEvent > ( async ( resolve , reject ) => { try { validateSocksClientChainOptions ( options ) ; } catch ( err ) { if ( typeof callback === 'function' ) { callback ( err ) ; return resolve ( err as any ) ; } else { return reject ( err ) ; } } let sock ; if ( options . randomizeChain ) { shuffleArray ( options . proxies ) ; } try { for ( let i = 0 ; i < options . proxies . length ; i ++ ) { const nextProxy = options . proxies [ i ] ; const nextDestination = i === options . proxies . length - 1 ? options . destination : { host : options . proxies [ i + 1 ] . ipaddress , port : options . proxies [ i + 1 ] . port , } ; const result = await SocksClient . createConnection ( { command : 'connect' , proxy : nextProxy , destination : nextDestination , } ) ; if ( ! sock ) { sock = result . socket ; } } if ( typeof callback === 'function' ) { callback ( null , { socket : sock } ) ; resolve ( { socket : sock } ) ; } else { resolve ( { socket : sock } ) ; } } catch ( err ) { if ( typeof callback === 'function' ) { callback ( err ) ; resolve ( err as any ) ; } else { reject ( err ) ; } } } ) ; } param options static createUDPFrame ( options ) { const buff = new SmartBuffer ( ) ; buff . writeUInt16BE ( 0 ) ; buff . writeUInt8 ( options . frameNumber || 0 ) ; if ( net . isIPv4 ( options . remoteHost . host ) ) { buff . writeUInt8 ( Socks5HostType . IPv4 ) ; buff . writeUInt32BE ( ip . toLong ( options . remoteHost . host ) ) ; } else if ( net . isIPv6 ( options . remoteHost . host ) ) { buff . writeUInt8 ( Socks5HostType . IPv6 ) ; buff . writeBuffer ( ip . toBuffer ( options . remoteHost . host ) ) ; } else { buff . writeUInt8 ( Socks5HostType . Hostname ) ; buff . writeUInt8 ( Buffer . byteLength ( options . remoteHost . host ) ) ; buff . writeString ( options . remoteHost . host ) ; } buff . writeUInt16BE ( options . remoteHost . port ) ; buff . writeBuffer ( options . data ) ; return buff . toBuffer ( ) ; } param data static parseUDPFrame ( data ) { const buff = SmartBuffer . fromBuffer ( data ) ; buff . readOffset = 2 ; const frameNumber = buff . readUInt8 ( ) ; const hostType = buff . readUInt8 ( ) ; let remoteHost ; if ( hostType === Socks5HostType . IPv4 ) { remoteHost = ip . fromLong ( buff . readUInt32BE ( ) ) ; } else if ( hostType === Socks5HostType . IPv6 ) { remoteHost = ip . toString ( buff . readBuffer ( 16 ) ) ; } else { remoteHost = buff . readString ( buff . readUInt8 ( ) ) ; } const remotePort = buff . readUInt16BE ( ) ; return { frameNumber , remoteHost : { host : remoteHost , port : remotePort , } , data : buff . readBuffer ( ) , } ; } /**
     * Internal state setter. If the SocksClient is in an error state, it cannot be changed to a non error state.
     */ private setState ( newState ) { if ( this . state !== SocksClientState . Error ) { this . state = newState ; } } param existingSocket public connect ( existingSocket ? ) { this . onDataReceived = ( data ) => this . onDataReceivedHandler ( data ) ; this . onClose = ( ) => this . onCloseHandler ( ) ; this . onError = ( err ) => this . onErrorHandler ( err ) ; this . onConnect = ( ) => this . onConnectHandler ( ) ; const timer = setTimeout ( ( ) => this . onEstablishedTimeout ( ) , this . options . timeout || DEFAULT_TIMEOUT ) ; if ( timer . unref && typeof timer . unref === 'function' ) { timer . unref ( ) ; } if ( existingSocket ) { this . socket = existingSocket ; } else { this . socket = new net . Socket ( ) ; } this . socket . once ( 'close' , this . onClose ) ; this . socket . once ( 'error' , this . onError ) ; this . socket . once ( 'connect' , this . onConnect ) ; this . socket . on ( 'data' , this . onDataReceived ) ; this . setState ( SocksClientState . Connecting ) ; this . receiveBuffer = new ReceiveBuffer ( ) ; if ( existingSocket ) { this . socket . emit ( 'connect' ) ; } else { ( this . socket as net . Socket ) . connect ( this . getSocketOptions ( ) ) ; if ( this . options . set_tcp_nodelay !== undefined && this . options . set_tcp_nodelay !== null ) { ( this . socket as net . Socket ) . setNoDelay ( ! ! this . options . set_tcp_nodelay ) ; } } this . prependOnceListener ( 'established' , ( info ) => { setImmediate ( ( ) => { if ( this . receiveBuffer . length > 0 ) { const excessData = this . receiveBuffer . get ( this . receiveBuffer . length ) ; info . socket . emit ( 'data' , excessData ) ; } info . socket . resume ( ) ; } ) ; } ) ; } private getSocketOptions ( ) { return { ... this . options . socket_options , host : this . options . proxy . host || this . options . proxy . ipaddress , port : this . options . proxy . port , } ; } /**
     * Handles internal Socks timeout callback.
     * Note: If the Socks client is not BoundWaitingForConnection or Established, the connection will be closed.
     */ private onEstablishedTimeout ( ) { if ( this . state !== SocksClientState . Established && this . state !== SocksClientState . BoundWaitingForConnection ) { this . closeSocket ( ERRORS . ProxyConnectionTimedOut ) ; } } /**
     * Handles Socket connect event.
     */ private onConnectHandler ( ) { this . setState ( SocksClientState . Connected ) ; if ( this . options . proxy . type === 4 ) { this . sendSocks4InitialHandshake ( ) ; } else { this . sendSocks5InitialHandshake ( ) ; } this . setState ( SocksClientState . SentInitialHandshake ) ; } param data private onDataReceivedHandler ( data ) { this . receiveBuffer . append ( data ) ; this . processData ( ) ; } /**
     * Handles processing of the data we have received.
     */ private processData ( ) { while ( this . state !== SocksClientState . Established && this . state !== SocksClientState . Error && this . receiveBuffer . length >= this . nextRequiredPacketBufferSize ) { if ( this . state === SocksClientState . SentInitialHandshake ) { if ( this . options . proxy . type === 4 ) { this . handleSocks4FinalHandshakeResponse ( ) ; } else { this . handleInitialSocks5HandshakeResponse ( ) ; } } else if ( this . state === SocksClientState . SentAuthentication ) { this . handleInitialSocks5AuthenticationHandshakeResponse ( ) ; } else if ( this . state === SocksClientState . SentFinalHandshake ) { this . handleSocks5FinalHandshakeResponse ( ) ; } else if ( this . state === SocksClientState . BoundWaitingForConnection ) { if ( this . options . proxy . type === 4 ) { this . handleSocks4IncomingConnectionResponse ( ) ; } else { this . handleSocks5IncomingConnectionResponse ( ) ; } } else { this . closeSocket ( ERRORS . InternalError ) ; break ; } } } param had_error private onCloseHandler ( ) { this . closeSocket ( ERRORS . SocketClosed ) ; } param err private onErrorHandler ( err ) { this . closeSocket ( err . message ) ; } /**
     * Removes internal event listeners on the underlying Socket.
     */ private removeInternalSocketHandlers ( ) { this . socket . pause ( ) ; this . socket . removeListener ( 'data' , this . onDataReceived ) ; this . socket . removeListener ( 'close' , this . onClose ) ; this . socket . removeListener ( 'error' , this . onError ) ; this . socket . removeListener ( 'connect' , this . onConnect ) ; } param err { String } private closeSocket ( err ) { if ( this . state !== SocksClientState . Error ) { this . setState ( SocksClientState . Error ) ; this . socket . destroy ( ) ; this . removeInternalSocketHandlers ( ) ; this . emit ( 'error' , new SocksClientError ( err , this . options ) ) ; } } /**
     * Sends initial Socks v4 handshake request.
     */ private sendSocks4InitialHandshake ( ) { const userId = this . options . proxy . userId || '' ; const buff = new SmartBuffer ( ) ; buff . writeUInt8 ( 0x04 ) ; buff . writeUInt8 ( SocksCommand [ this . options . command ] ) ; buff . writeUInt16BE ( this . options . destination . port ) ; if ( net . isIPv4 ( this . options . destination . host ) ) { buff . writeBuffer ( ip . toBuffer ( this . options . destination . host ) ) ; buff . writeStringNT ( userId ) ; } else { buff . writeUInt8 ( 0x00 ) ; buff . writeUInt8 ( 0x00 ) ; buff . writeUInt8 ( 0x00 ) ; buff . writeUInt8 ( 0x01 ) ; buff . writeStringNT ( userId ) ; buff . writeStringNT ( this . options . destination . host ) ; } this . nextRequiredPacketBufferSize = SOCKS_INCOMING_PACKET_SIZES . Socks4Response ; this . socket . write ( buff . toBuffer ( ) ) ; } param data private handleSocks4FinalHandshakeResponse ( ) { const data = this . receiveBuffer . get ( 8 ) ; if ( data [ 1 ] !== Socks4Response . Granted ) { this . closeSocket ( `${ ERRORS . Socks4ProxyRejectedConnection } - (${ Socks4Response [ data [ 1 ] ] })` ) ; } else { if ( SocksCommand [ this . options . command ] === SocksCommand . bind ) { const buff = SmartBuffer . fromBuffer ( data ) ; buff . readOffset = 2 ; const remoteHost = { port : buff . readUInt16BE ( ) , host : ip . fromLong ( buff . readUInt32BE ( ) ) , } ; if ( remoteHost . host === '0.0.0.0' ) { remoteHost . host = this . options . proxy . ipaddress ; } this . setState ( SocksClientState . BoundWaitingForConnection ) ; this . emit ( 'bound' , { remoteHost , socket : this . socket } ) ; } else { this . setState ( SocksClientState . Established ) ; this . removeInternalSocketHandlers ( ) ; this . emit ( 'established' , { socket : this . socket } ) ; } } } param data private handleSocks4IncomingConnectionResponse ( ) { const data = this . receiveBuffer . get ( 8 ) ; if ( data [ 1 ] !== Socks4Response . Granted ) { this . closeSocket ( `${ ERRORS . Socks4ProxyRejectedIncomingBoundConnection } - (${ Socks4Response [ data [ 1 ] ] })` ) ; } else { const buff = SmartBuffer . fromBuffer ( data ) ; buff . readOffset = 2 ; const remoteHost = { port : buff . readUInt16BE ( ) , host : ip . fromLong ( buff . readUInt32BE ( ) ) , } ; this . setState ( SocksClientState . Established ) ; this . removeInternalSocketHandlers ( ) ; this . emit ( 'established' , { remoteHost , socket : this . socket } ) ; } } /**
     * Sends initial Socks v5 handshake request.
     */ private sendSocks5InitialHandshake ( ) { const buff = new SmartBuffer ( ) ; const supportedAuthMethods = [ Socks5Auth . NoAuth ] ; if ( this . options . proxy . userId || this . options . proxy . password ) { supportedAuthMethods . push ( Socks5Auth . UserPass ) ; } if ( this . options . proxy . custom_auth_method !== undefined ) { supportedAuthMethods . push ( this . options . proxy . custom_auth_method ) ; } buff . writeUInt8 ( 0x05 ) ; buff . writeUInt8 ( supportedAuthMethods . length ) ; for ( const authMethod of supportedAuthMethods ) { buff . writeUInt8 ( authMethod ) ; } this . nextRequiredPacketBufferSize = SOCKS_INCOMING_PACKET_SIZES . Socks5InitialHandshakeResponse ; this . socket . write ( buff . toBuffer ( ) ) ; this . setState ( SocksClientState . SentInitialHandshake ) ; } param data private handleInitialSocks5HandshakeResponse ( ) { const data = this . receiveBuffer . get ( 2 ) ; if ( data [ 0 ] !== 0x05 ) { this . closeSocket ( ERRORS . InvalidSocks5IntiailHandshakeSocksVersion ) ; } else if ( data [ 1 ] === SOCKS5_NO_ACCEPTABLE_AUTH ) { this . closeSocket ( ERRORS . InvalidSocks5InitialHandshakeNoAcceptedAuthType ) ; } else { if ( data [ 1 ] === Socks5Auth . NoAuth ) { this . socks5ChosenAuthType = Socks5Auth . NoAuth ; this . sendSocks5CommandRequest ( ) ; } else if ( data [ 1 ] === Socks5Auth . UserPass ) { this . socks5ChosenAuthType = Socks5Auth . UserPass ; this . sendSocks5UserPassAuthentication ( ) ; } else if ( data [ 1 ] === this . options . proxy . custom_auth_method ) { this . socks5ChosenAuthType = this . options . proxy . custom_auth_method ; this . sendSocks5CustomAuthentication ( ) ; } else { this . closeSocket ( ERRORS . InvalidSocks5InitialHandshakeUnknownAuthType ) ; } } } /**
     * Sends Socks v5 user & password auth handshake.
     *
     * Note: No auth and user/pass are currently supported.
     */ private sendSocks5UserPassAuthentication ( ) { const userId = this . options . proxy . userId || '' ; const password = this . options . proxy . password || '' ; const buff = new SmartBuffer ( ) ; buff . writeUInt8 ( 0x01 ) ; buff . writeUInt8 ( Buffer . byteLength ( userId ) ) ; buff . writeString ( userId ) ; buff . writeUInt8 ( Buffer . byteLength ( password ) ) ; buff . writeString ( password ) ; this . nextRequiredPacketBufferSize = SOCKS_INCOMING_PACKET_SIZES . Socks5UserPassAuthenticationResponse ; this . socket . write ( buff . toBuffer ( ) ) ; this . setState ( SocksClientState . SentAuthentication ) ; } private async sendSocks5CustomAuthentication ( ) { this . nextRequiredPacketBufferSize = this . options . proxy . custom_auth_response_size ; this . socket . write ( await this . options . proxy . custom_auth_request_handler ( ) ) ; this . setState ( SocksClientState . SentAuthentication ) ; } private async handleSocks5CustomAuthHandshakeResponse ( data ) { return await this . options . proxy . custom_auth_response_handler ( data ) ; } private async handleSocks5AuthenticationNoAuthHandshakeResponse ( data ) { return data [ 1 ] === 0x00 ; } private async handleSocks5AuthenticationUserPassHandshakeResponse ( data ) { return data [ 1 ] === 0x00 ; } param data private async handleInitialSocks5AuthenticationHandshakeResponse ( ) { this . setState ( SocksClientState . ReceivedAuthenticationResponse ) ; let authResult = false ; if ( this . socks5ChosenAuthType === Socks5Auth . NoAuth ) { authResult = await this . handleSocks5AuthenticationNoAuthHandshakeResponse ( this . receiveBuffer . get ( 2 ) ) ; } else if ( this . socks5ChosenAuthType === Socks5Auth . UserPass ) { authResult = await this . handleSocks5AuthenticationUserPassHandshakeResponse ( this . receiveBuffer . get ( 2 ) ) ; } else if ( this . socks5ChosenAuthType === this . options . proxy . custom_auth_method ) { authResult = await this . handleSocks5CustomAuthHandshakeResponse ( this . receiveBuffer . get ( this . options . proxy . custom_auth_response_size ) ) ; } if ( ! authResult ) { this . closeSocket ( ERRORS . Socks5AuthenticationFailed ) ; } else { this . sendSocks5CommandRequest ( ) ; } } /**
     * Sends Socks v5 final handshake request.
     */ private sendSocks5CommandRequest ( ) { const buff = new SmartBuffer ( ) ; buff . writeUInt8 ( 0x05 ) ; buff . writeUInt8 ( SocksCommand [ this . options . command ] ) ; buff . writeUInt8 ( 0x00 ) ; if ( net . isIPv4 ( this . options . destination . host ) ) { buff . writeUInt8 ( Socks5HostType . IPv4 ) ; buff . writeBuffer ( ip . toBuffer ( this . options . destination . host ) ) ; } else if ( net . isIPv6 ( this . options . destination . host ) ) { buff . writeUInt8 ( Socks5HostType . IPv6 ) ; buff . writeBuffer ( ip . toBuffer ( this . options . destination . host ) ) ; } else { buff . writeUInt8 ( Socks5HostType . Hostname ) ; buff . writeUInt8 ( this . options . destination . host . length ) ; buff . writeString ( this . options . destination . host ) ; } buff . writeUInt16BE ( this . options . destination . port ) ; this . nextRequiredPacketBufferSize = SOCKS_INCOMING_PACKET_SIZES . Socks5ResponseHeader ; this . socket . write ( buff . toBuffer ( ) ) ; this . setState ( SocksClientState . SentFinalHandshake ) ; } param data private handleSocks5FinalHandshakeResponse ( ) { const header = this . receiveBuffer . peek ( 5 ) ; if ( header [ 0 ] !== 0x05 || header [ 1 ] !== Socks5Response . Granted ) { this . closeSocket ( `${ ERRORS . InvalidSocks5FinalHandshakeRejected } - ${ Socks5Response [ header [ 1 ] ] }` ) ; } else { const addressType = header [ 3 ] ; let remoteHost ; let buff ; if ( addressType === Socks5HostType . IPv4 ) { const dataNeeded = SOCKS_INCOMING_PACKET_SIZES . Socks5ResponseIPv4 ; if ( this . receiveBuffer . length < dataNeeded ) { this . nextRequiredPacketBufferSize = dataNeeded ; return ; } buff = SmartBuffer . fromBuffer ( this . receiveBuffer . get ( dataNeeded ) . slice ( 4 ) ) ; remoteHost = { host : ip . fromLong ( buff . readUInt32BE ( ) ) , port : buff . readUInt16BE ( ) , } ; if ( remoteHost . host === '0.0.0.0' ) { remoteHost . host = this . options . proxy . ipaddress ; } } else if ( addressType === Socks5HostType . Hostname ) { const hostLength = header [ 4 ] ; const dataNeeded = SOCKS_INCOMING_PACKET_SIZES . Socks5ResponseHostname ( hostLength ) ; if ( this . receiveBuffer . length < dataNeeded ) { this . nextRequiredPacketBufferSize = dataNeeded ; return ; } buff = SmartBuffer . fromBuffer ( this . receiveBuffer . get ( dataNeeded ) . slice ( 5 ) ) ; remoteHost = { host : buff . readString ( hostLength ) , port : buff . readUInt16BE ( ) , } ; } else if ( addressType === Socks5HostType . IPv6 ) { const dataNeeded = SOCKS_INCOMING_PACKET_SIZES . Socks5ResponseIPv6 ; if ( this . receiveBuffer . length < dataNeeded ) { this . nextRequiredPacketBufferSize = dataNeeded ; return ; } buff = SmartBuffer . fromBuffer ( this . receiveBuffer . get ( dataNeeded ) . slice ( 4 ) ) ; remoteHost = { host : ip . toString ( buff . readBuffer ( 16 ) ) , port : buff . readUInt16BE ( ) , } ; } this . setState ( SocksClientState . ReceivedFinalResponse ) ; if ( SocksCommand [ this . options . command ] === SocksCommand . connect ) { this . setState ( SocksClientState . Established ) ; this . removeInternalSocketHandlers ( ) ; this . emit ( 'established' , { remoteHost , socket : this . socket } ) ; } else if ( SocksCommand [ this . options . command ] === SocksCommand . bind ) { this . setState ( SocksClientState . BoundWaitingForConnection ) ; this . nextRequiredPacketBufferSize = SOCKS_INCOMING_PACKET_SIZES . Socks5ResponseHeader ; this . emit ( 'bound' , { remoteHost , socket : this . socket } ) ; } else if ( SocksCommand [ this . options . command ] === SocksCommand . associate ) { this . setState ( SocksClientState . Established ) ; this . removeInternalSocketHandlers ( ) ; this . emit ( 'established' , { remoteHost , socket : this . socket , } ) ; } } } /**
     * Handles Socks v5 incoming connection request (BIND).
     */ private handleSocks5IncomingConnectionResponse ( ) { const header = this . receiveBuffer . peek ( 5 ) ; if ( header [ 0 ] !== 0x05 || header [ 1 ] !== Socks5Response . Granted ) { this . closeSocket ( `${ ERRORS . Socks5ProxyRejectedIncomingBoundConnection } - ${ Socks5Response [ header [ 1 ] ] }` ) ; } else { const addressType = header [ 3 ] ; let remoteHost ; let buff ; if ( addressType === Socks5HostType . IPv4 ) { const dataNeeded = SOCKS_INCOMING_PACKET_SIZES . Socks5ResponseIPv4 ; if ( this . receiveBuffer . length < dataNeeded ) { this . nextRequiredPacketBufferSize = dataNeeded ; return ; } buff = SmartBuffer . fromBuffer ( this . receiveBuffer . get ( dataNeeded ) . slice ( 4 ) ) ; remoteHost = { host : ip . fromLong ( buff . readUInt32BE ( ) ) , port : buff . readUInt16BE ( ) , } ; if ( remoteHost . host === '0.0.0.0' ) { remoteHost . host = this . options . proxy . ipaddress ; } } else if ( addressType === Socks5HostType . Hostname ) { const hostLength = header [ 4 ] ; const dataNeeded = SOCKS_INCOMING_PACKET_SIZES . Socks5ResponseHostname ( hostLength ) ; if ( this . receiveBuffer . length < dataNeeded ) { this . nextRequiredPacketBufferSize = dataNeeded ; return ; } buff = SmartBuffer . fromBuffer ( this . receiveBuffer . get ( dataNeeded ) . slice ( 5 ) ) ; remoteHost = { host : buff . readString ( hostLength ) , port : buff . readUInt16BE ( ) , } ; } else if ( addressType === Socks5HostType . IPv6 ) { const dataNeeded = SOCKS_INCOMING_PACKET_SIZES . Socks5ResponseIPv6 ; if ( this . receiveBuffer . length < dataNeeded ) { this . nextRequiredPacketBufferSize = dataNeeded ; return ; } buff = SmartBuffer . fromBuffer ( this . receiveBuffer . get ( dataNeeded ) . slice ( 4 ) ) ; remoteHost = { host : ip . toString ( buff . readBuffer ( 16 ) ) , port : buff . readUInt16BE ( ) , } ; } this . setState ( SocksClientState . Established ) ; this . removeInternalSocketHandlers ( ) ; this . emit ( 'established' , { remoteHost , socket : this . socket } ) ; } } get socksClientOptions ( ) : SocksClientOptions { return { ... this . options , } ; } } export { SocksClient , SocksClientOptions , SocksClientChainOptions , SocksClientError , SocksRemoteHost , SocksProxy , SocksUDPFrameDetails , } ;