Comparing version 2.3.3 to 2.4.0
@@ -12,2 +12,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.SocksClientError = exports.SocksClient = void 0; | ||
const events_1 = require("events"); | ||
@@ -21,10 +22,11 @@ const net = require("net"); | ||
const util_1 = require("../common/util"); | ||
Object.defineProperty(exports, "SocksClientError", { enumerable: true, get: function () { return util_1.SocksClientError; } }); | ||
class SocksClient extends events_1.EventEmitter { | ||
constructor(options) { | ||
super(); | ||
this._options = Object.assign({}, options); | ||
this.options = Object.assign({}, options); | ||
// Validate SocksClientOptions | ||
helpers_1.validateSocksClientOptions(options); | ||
// Default state | ||
this.state = constants_1.SocksClientState.Created; | ||
this.setState(constants_1.SocksClientState.Created); | ||
} | ||
@@ -87,2 +89,3 @@ /** | ||
try { | ||
// tslint:disable-next-line:no-increment-decrement | ||
for (let i = 0; i < options.proxies.length; i++) { | ||
@@ -95,3 +98,3 @@ const nextProxy = options.proxies[i]; | ||
host: options.proxies[i + 1].ipaddress, | ||
port: options.proxies[i + 1].port | ||
port: options.proxies[i + 1].port, | ||
}; | ||
@@ -102,4 +105,3 @@ // Creates the next connection in the chain. | ||
proxy: nextProxy, | ||
destination: nextDestination | ||
// Initial connection ignores this as sock is undefined. Subsequent connections re-use the first proxy socket to form a chain. | ||
destination: nextDestination, | ||
}); | ||
@@ -182,19 +184,13 @@ // If sock is undefined, assign it here. | ||
host: remoteHost, | ||
port: remotePort | ||
port: remotePort, | ||
}, | ||
data: buff.readBuffer() | ||
data: buff.readBuffer(), | ||
}; | ||
} | ||
/** | ||
* Gets the SocksClient internal state. | ||
*/ | ||
get state() { | ||
return this._state; | ||
} | ||
/** | ||
* Internal state setter. If the SocksClient is in an error state, it cannot be changed to a non error state. | ||
*/ | ||
set state(newState) { | ||
if (this._state !== constants_1.SocksClientState.Error) { | ||
this._state = newState; | ||
setState(newState) { | ||
if (this.state !== constants_1.SocksClientState.Error) { | ||
this.state = newState; | ||
} | ||
@@ -204,11 +200,11 @@ } | ||
* Starts the connection establishment to the proxy and destination. | ||
* @param existing_socket Connected socket to use instead of creating a new one (internal use). | ||
* @param existingSocket Connected socket to use instead of creating a new one (internal use). | ||
*/ | ||
connect(existing_socket) { | ||
this._onDataReceived = (data) => this.onDataReceived(data); | ||
this._onClose = () => this.onClose(); | ||
this._onError = (err) => this.onError(err); | ||
this._onConnect = () => this.onConnect(); | ||
connect(existingSocket) { | ||
this.onDataReceived = (data) => this.onDataReceivedHandler(data); | ||
this.onClose = () => this.onCloseHandler(); | ||
this.onError = (err) => this.onErrorHandler(err); | ||
this.onConnect = () => this.onConnectHandler(); | ||
// Start timeout timer (defaults to 30 seconds) | ||
const timer = setTimeout(() => this.onEstablishedTimeout(), this._options.timeout || constants_1.DEFAULT_TIMEOUT); | ||
const timer = setTimeout(() => this.onEstablishedTimeout(), this.options.timeout || constants_1.DEFAULT_TIMEOUT); | ||
// check whether unref is available as it differs from browser to NodeJS (#33) | ||
@@ -219,30 +215,30 @@ if (timer.unref && typeof timer.unref === 'function') { | ||
// If an existing socket is provided, use it to negotiate SOCKS handshake. Otherwise create a new Socket. | ||
if (existing_socket) { | ||
this._socket = existing_socket; | ||
if (existingSocket) { | ||
this.socket = existingSocket; | ||
} | ||
else { | ||
this._socket = new net.Socket(); | ||
this.socket = new net.Socket(); | ||
} | ||
// Attach Socket error handlers. | ||
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.state = constants_1.SocksClientState.Connecting; | ||
this._receiveBuffer = new receivebuffer_1.ReceiveBuffer(); | ||
if (existing_socket) { | ||
this._socket.emit('connect'); | ||
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(constants_1.SocksClientState.Connecting); | ||
this.receiveBuffer = new receivebuffer_1.ReceiveBuffer(); | ||
if (existingSocket) { | ||
this.socket.emit('connect'); | ||
} | ||
else { | ||
this._socket.connect(this.getSocketOptions()); | ||
if (this._options.set_tcp_nodelay !== undefined && | ||
this._options.set_tcp_nodelay !== null) { | ||
this._socket.setNoDelay(!!this._options.set_tcp_nodelay); | ||
this.socket.connect(this.getSocketOptions()); | ||
if (this.options.set_tcp_nodelay !== undefined && | ||
this.options.set_tcp_nodelay !== null) { | ||
this.socket.setNoDelay(!!this.options.set_tcp_nodelay); | ||
} | ||
} | ||
// Listen for established event so we can re-emit any excess data received during handshakes. | ||
this.prependOnceListener('established', info => { | ||
this.prependOnceListener('established', (info) => { | ||
setImmediate(() => { | ||
if (this._receiveBuffer.length > 0) { | ||
const excessData = this._receiveBuffer.get(this._receiveBuffer.length); | ||
if (this.receiveBuffer.length > 0) { | ||
const excessData = this.receiveBuffer.get(this.receiveBuffer.length); | ||
info.socket.emit('data', excessData); | ||
@@ -256,3 +252,3 @@ } | ||
getSocketOptions() { | ||
return Object.assign(Object.assign({}, this._options.socket_options), { host: this._options.proxy.host || this._options.proxy.ipaddress, port: this._options.proxy.port }); | ||
return Object.assign(Object.assign({}, this.options.socket_options), { host: this.options.proxy.host || this.options.proxy.ipaddress, port: this.options.proxy.port }); | ||
} | ||
@@ -266,3 +262,3 @@ /** | ||
this.state !== constants_1.SocksClientState.BoundWaitingForConnection) { | ||
this._closeSocket(constants_1.ERRORS.ProxyConnectionTimedOut); | ||
this.closeSocket(constants_1.ERRORS.ProxyConnectionTimedOut); | ||
} | ||
@@ -273,6 +269,6 @@ } | ||
*/ | ||
onConnect() { | ||
this.state = constants_1.SocksClientState.Connected; | ||
onConnectHandler() { | ||
this.setState(constants_1.SocksClientState.Connected); | ||
// Send initial handshake. | ||
if (this._options.proxy.type === 4) { | ||
if (this.options.proxy.type === 4) { | ||
this.sendSocks4InitialHandshake(); | ||
@@ -283,3 +279,3 @@ } | ||
} | ||
this.state = constants_1.SocksClientState.SentInitialHandshake; | ||
this.setState(constants_1.SocksClientState.SentInitialHandshake); | ||
} | ||
@@ -290,3 +286,3 @@ /** | ||
*/ | ||
onDataReceived(data) { | ||
onDataReceivedHandler(data) { | ||
/* | ||
@@ -296,3 +292,3 @@ All received data is appended to a ReceiveBuffer. | ||
*/ | ||
this._receiveBuffer.append(data); | ||
this.receiveBuffer.append(data); | ||
// Process data that we have. | ||
@@ -306,6 +302,6 @@ this.processData(); | ||
// If we have enough data to process the next step in the SOCKS handshake, proceed. | ||
if (this._receiveBuffer.length >= this._nextRequiredPacketBufferSize) { | ||
if (this.receiveBuffer.length >= this.nextRequiredPacketBufferSize) { | ||
// Sent initial handshake, waiting for response. | ||
if (this.state === constants_1.SocksClientState.SentInitialHandshake) { | ||
if (this._options.proxy.type === 4) { | ||
if (this.options.proxy.type === 4) { | ||
// Socks v4 only has one handshake response. | ||
@@ -329,3 +325,3 @@ this.handleSocks4FinalHandshakeResponse(); | ||
else if (this.state === constants_1.SocksClientState.BoundWaitingForConnection) { | ||
if (this._options.proxy.type === 4) { | ||
if (this.options.proxy.type === 4) { | ||
this.handleSocks4IncomingConnectionResponse(); | ||
@@ -341,3 +337,3 @@ } | ||
else { | ||
this._closeSocket(constants_1.ERRORS.InternalError); | ||
this.closeSocket(constants_1.ERRORS.InternalError); | ||
} | ||
@@ -350,4 +346,4 @@ } | ||
*/ | ||
onClose() { | ||
this._closeSocket(constants_1.ERRORS.SocketClosed); | ||
onCloseHandler() { | ||
this.closeSocket(constants_1.ERRORS.SocketClosed); | ||
} | ||
@@ -358,4 +354,4 @@ /** | ||
*/ | ||
onError(err) { | ||
this._closeSocket(err.message); | ||
onErrorHandler(err) { | ||
this.closeSocket(err.message); | ||
} | ||
@@ -367,7 +363,7 @@ /** | ||
// Pauses data flow of the socket (this is internally resumed after 'established' is emitted) | ||
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); | ||
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); | ||
} | ||
@@ -378,13 +374,13 @@ /** | ||
*/ | ||
_closeSocket(err) { | ||
closeSocket(err) { | ||
// Make sure only one 'error' event is fired for the lifetime of this SocksClient instance. | ||
if (this.state !== constants_1.SocksClientState.Error) { | ||
// Set internal state to Error. | ||
this.state = constants_1.SocksClientState.Error; | ||
this.setState(constants_1.SocksClientState.Error); | ||
// Destroy Socket | ||
this._socket.destroy(); | ||
this.socket.destroy(); | ||
// Remove internal listeners | ||
this.removeInternalSocketHandlers(); | ||
// Fire 'error' event. | ||
this.emit('error', new util_1.SocksClientError(err, this._options)); | ||
this.emit('error', new util_1.SocksClientError(err, this.options)); | ||
} | ||
@@ -396,10 +392,10 @@ } | ||
sendSocks4InitialHandshake() { | ||
const userId = this._options.proxy.userId || ''; | ||
const userId = this.options.proxy.userId || ''; | ||
const buff = new smart_buffer_1.SmartBuffer(); | ||
buff.writeUInt8(0x04); | ||
buff.writeUInt8(constants_1.SocksCommand[this._options.command]); | ||
buff.writeUInt16BE(this._options.destination.port); | ||
buff.writeUInt8(constants_1.SocksCommand[this.options.command]); | ||
buff.writeUInt16BE(this.options.destination.port); | ||
// Socks 4 (IPv4) | ||
if (net.isIPv4(this._options.destination.host)) { | ||
buff.writeBuffer(ip.toBuffer(this._options.destination.host)); | ||
if (net.isIPv4(this.options.destination.host)) { | ||
buff.writeBuffer(ip.toBuffer(this.options.destination.host)); | ||
buff.writeStringNT(userId); | ||
@@ -414,7 +410,7 @@ // Socks 4a (hostname) | ||
buff.writeStringNT(userId); | ||
buff.writeStringNT(this._options.destination.host); | ||
buff.writeStringNT(this.options.destination.host); | ||
} | ||
this._nextRequiredPacketBufferSize = | ||
this.nextRequiredPacketBufferSize = | ||
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks4Response; | ||
this._socket.write(buff.toBuffer()); | ||
this.socket.write(buff.toBuffer()); | ||
} | ||
@@ -426,9 +422,9 @@ /** | ||
handleSocks4FinalHandshakeResponse() { | ||
const data = this._receiveBuffer.get(8); | ||
const data = this.receiveBuffer.get(8); | ||
if (data[1] !== constants_1.Socks4Response.Granted) { | ||
this._closeSocket(`${constants_1.ERRORS.Socks4ProxyRejectedConnection} - (${constants_1.Socks4Response[data[1]]})`); | ||
this.closeSocket(`${constants_1.ERRORS.Socks4ProxyRejectedConnection} - (${constants_1.Socks4Response[data[1]]})`); | ||
} | ||
else { | ||
// Bind response | ||
if (constants_1.SocksCommand[this._options.command] === constants_1.SocksCommand.bind) { | ||
if (constants_1.SocksCommand[this.options.command] === constants_1.SocksCommand.bind) { | ||
const buff = smart_buffer_1.SmartBuffer.fromBuffer(data); | ||
@@ -438,16 +434,16 @@ buff.readOffset = 2; | ||
port: buff.readUInt16BE(), | ||
host: ip.fromLong(buff.readUInt32BE()) | ||
host: ip.fromLong(buff.readUInt32BE()), | ||
}; | ||
// If host is 0.0.0.0, set to proxy host. | ||
if (remoteHost.host === '0.0.0.0') { | ||
remoteHost.host = this._options.proxy.ipaddress; | ||
remoteHost.host = this.options.proxy.ipaddress; | ||
} | ||
this.state = constants_1.SocksClientState.BoundWaitingForConnection; | ||
this.emit('bound', { socket: this._socket, remoteHost }); | ||
this.setState(constants_1.SocksClientState.BoundWaitingForConnection); | ||
this.emit('bound', { remoteHost, socket: this.socket }); | ||
// Connect response | ||
} | ||
else { | ||
this.state = constants_1.SocksClientState.Established; | ||
this.setState(constants_1.SocksClientState.Established); | ||
this.removeInternalSocketHandlers(); | ||
this.emit('established', { socket: this._socket }); | ||
this.emit('established', { socket: this.socket }); | ||
} | ||
@@ -461,5 +457,5 @@ } | ||
handleSocks4IncomingConnectionResponse() { | ||
const data = this._receiveBuffer.get(8); | ||
const data = this.receiveBuffer.get(8); | ||
if (data[1] !== constants_1.Socks4Response.Granted) { | ||
this._closeSocket(`${constants_1.ERRORS.Socks4ProxyRejectedIncomingBoundConnection} - (${constants_1.Socks4Response[data[1]]})`); | ||
this.closeSocket(`${constants_1.ERRORS.Socks4ProxyRejectedIncomingBoundConnection} - (${constants_1.Socks4Response[data[1]]})`); | ||
} | ||
@@ -471,7 +467,7 @@ else { | ||
port: buff.readUInt16BE(), | ||
host: ip.fromLong(buff.readUInt32BE()) | ||
host: ip.fromLong(buff.readUInt32BE()), | ||
}; | ||
this.state = constants_1.SocksClientState.Established; | ||
this.setState(constants_1.SocksClientState.Established); | ||
this.removeInternalSocketHandlers(); | ||
this.emit('established', { socket: this._socket, remoteHost }); | ||
this.emit('established', { remoteHost, socket: this.socket }); | ||
} | ||
@@ -487,3 +483,3 @@ } | ||
// Note: As of Tor v0.3.5.7+, if user/pass auth is an option from the client, by default it will always take priority. | ||
if (this._options.proxy.userId || this._options.proxy.password) { | ||
if (this.options.proxy.userId || this.options.proxy.password) { | ||
buff.writeUInt8(2); | ||
@@ -497,6 +493,6 @@ buff.writeUInt8(constants_1.Socks5Auth.NoAuth); | ||
} | ||
this._nextRequiredPacketBufferSize = | ||
this.nextRequiredPacketBufferSize = | ||
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5InitialHandshakeResponse; | ||
this._socket.write(buff.toBuffer()); | ||
this.state = constants_1.SocksClientState.SentInitialHandshake; | ||
this.socket.write(buff.toBuffer()); | ||
this.setState(constants_1.SocksClientState.SentInitialHandshake); | ||
} | ||
@@ -508,8 +504,8 @@ /** | ||
handleInitialSocks5HandshakeResponse() { | ||
const data = this._receiveBuffer.get(2); | ||
const data = this.receiveBuffer.get(2); | ||
if (data[0] !== 0x05) { | ||
this._closeSocket(constants_1.ERRORS.InvalidSocks5IntiailHandshakeSocksVersion); | ||
this.closeSocket(constants_1.ERRORS.InvalidSocks5IntiailHandshakeSocksVersion); | ||
} | ||
else if (data[1] === 0xff) { | ||
this._closeSocket(constants_1.ERRORS.InvalidSocks5InitialHandshakeNoAcceptedAuthType); | ||
this.closeSocket(constants_1.ERRORS.InvalidSocks5InitialHandshakeNoAcceptedAuthType); | ||
} | ||
@@ -526,3 +522,3 @@ else { | ||
else { | ||
this._closeSocket(constants_1.ERRORS.InvalidSocks5InitialHandshakeUnknownAuthType); | ||
this.closeSocket(constants_1.ERRORS.InvalidSocks5InitialHandshakeUnknownAuthType); | ||
} | ||
@@ -537,4 +533,4 @@ } | ||
sendSocks5UserPassAuthentication() { | ||
const userId = this._options.proxy.userId || ''; | ||
const password = this._options.proxy.password || ''; | ||
const userId = this.options.proxy.userId || ''; | ||
const password = this.options.proxy.password || ''; | ||
const buff = new smart_buffer_1.SmartBuffer(); | ||
@@ -546,6 +542,6 @@ buff.writeUInt8(0x01); | ||
buff.writeString(password); | ||
this._nextRequiredPacketBufferSize = | ||
this.nextRequiredPacketBufferSize = | ||
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5UserPassAuthenticationResponse; | ||
this._socket.write(buff.toBuffer()); | ||
this.state = constants_1.SocksClientState.SentAuthentication; | ||
this.socket.write(buff.toBuffer()); | ||
this.setState(constants_1.SocksClientState.SentAuthentication); | ||
} | ||
@@ -557,6 +553,6 @@ /** | ||
handleInitialSocks5AuthenticationHandshakeResponse() { | ||
this.state = constants_1.SocksClientState.ReceivedAuthenticationResponse; | ||
const data = this._receiveBuffer.get(2); | ||
this.setState(constants_1.SocksClientState.ReceivedAuthenticationResponse); | ||
const data = this.receiveBuffer.get(2); | ||
if (data[1] !== 0x00) { | ||
this._closeSocket(constants_1.ERRORS.Socks5AuthenticationFailed); | ||
this.closeSocket(constants_1.ERRORS.Socks5AuthenticationFailed); | ||
} | ||
@@ -573,23 +569,23 @@ else { | ||
buff.writeUInt8(0x05); | ||
buff.writeUInt8(constants_1.SocksCommand[this._options.command]); | ||
buff.writeUInt8(constants_1.SocksCommand[this.options.command]); | ||
buff.writeUInt8(0x00); | ||
// ipv4, ipv6, domain? | ||
if (net.isIPv4(this._options.destination.host)) { | ||
if (net.isIPv4(this.options.destination.host)) { | ||
buff.writeUInt8(constants_1.Socks5HostType.IPv4); | ||
buff.writeBuffer(ip.toBuffer(this._options.destination.host)); | ||
buff.writeBuffer(ip.toBuffer(this.options.destination.host)); | ||
} | ||
else if (net.isIPv6(this._options.destination.host)) { | ||
else if (net.isIPv6(this.options.destination.host)) { | ||
buff.writeUInt8(constants_1.Socks5HostType.IPv6); | ||
buff.writeBuffer(ip.toBuffer(this._options.destination.host)); | ||
buff.writeBuffer(ip.toBuffer(this.options.destination.host)); | ||
} | ||
else { | ||
buff.writeUInt8(constants_1.Socks5HostType.Hostname); | ||
buff.writeUInt8(this._options.destination.host.length); | ||
buff.writeString(this._options.destination.host); | ||
buff.writeUInt8(this.options.destination.host.length); | ||
buff.writeString(this.options.destination.host); | ||
} | ||
buff.writeUInt16BE(this._options.destination.port); | ||
this._nextRequiredPacketBufferSize = | ||
buff.writeUInt16BE(this.options.destination.port); | ||
this.nextRequiredPacketBufferSize = | ||
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseHeader; | ||
this._socket.write(buff.toBuffer()); | ||
this.state = constants_1.SocksClientState.SentFinalHandshake; | ||
this.socket.write(buff.toBuffer()); | ||
this.setState(constants_1.SocksClientState.SentFinalHandshake); | ||
} | ||
@@ -602,5 +598,5 @@ /** | ||
// Peek at available data (we need at least 5 bytes to get the hostname length) | ||
const header = this._receiveBuffer.peek(5); | ||
const header = this.receiveBuffer.peek(5); | ||
if (header[0] !== 0x05 || header[1] !== constants_1.Socks5Response.Granted) { | ||
this._closeSocket(`${constants_1.ERRORS.InvalidSocks5FinalHandshakeRejected} - ${constants_1.Socks5Response[header[1]]}`); | ||
this.closeSocket(`${constants_1.ERRORS.InvalidSocks5FinalHandshakeRejected} - ${constants_1.Socks5Response[header[1]]}`); | ||
} | ||
@@ -616,14 +612,14 @@ else { | ||
const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv4; | ||
if (this._receiveBuffer.length < dataNeeded) { | ||
this._nextRequiredPacketBufferSize = dataNeeded; | ||
if (this.receiveBuffer.length < dataNeeded) { | ||
this.nextRequiredPacketBufferSize = dataNeeded; | ||
return; | ||
} | ||
buff = smart_buffer_1.SmartBuffer.fromBuffer(this._receiveBuffer.get(dataNeeded).slice(4)); | ||
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(4)); | ||
remoteHost = { | ||
host: ip.fromLong(buff.readUInt32BE()), | ||
port: buff.readUInt16BE() | ||
port: buff.readUInt16BE(), | ||
}; | ||
// If given host is 0.0.0.0, assume remote proxy ip instead. | ||
if (remoteHost.host === '0.0.0.0') { | ||
remoteHost.host = this._options.proxy.ipaddress; | ||
remoteHost.host = this.options.proxy.ipaddress; | ||
} | ||
@@ -636,11 +632,10 @@ // Hostname | ||
// Check if data is available. | ||
if (this._receiveBuffer.length < dataNeeded) { | ||
this._nextRequiredPacketBufferSize = dataNeeded; | ||
if (this.receiveBuffer.length < dataNeeded) { | ||
this.nextRequiredPacketBufferSize = dataNeeded; | ||
return; | ||
} | ||
buff = smart_buffer_1.SmartBuffer.fromBuffer(this._receiveBuffer.get(dataNeeded).slice(5) // Slice at 5 to skip host length | ||
); | ||
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(5)); | ||
remoteHost = { | ||
host: buff.readString(hostLength), | ||
port: buff.readUInt16BE() | ||
port: buff.readUInt16BE(), | ||
}; | ||
@@ -652,27 +647,27 @@ // IPv6 | ||
const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv6; | ||
if (this._receiveBuffer.length < dataNeeded) { | ||
this._nextRequiredPacketBufferSize = dataNeeded; | ||
if (this.receiveBuffer.length < dataNeeded) { | ||
this.nextRequiredPacketBufferSize = dataNeeded; | ||
return; | ||
} | ||
buff = smart_buffer_1.SmartBuffer.fromBuffer(this._receiveBuffer.get(dataNeeded).slice(4)); | ||
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(4)); | ||
remoteHost = { | ||
host: ip.toString(buff.readBuffer(16)), | ||
port: buff.readUInt16BE() | ||
port: buff.readUInt16BE(), | ||
}; | ||
} | ||
// We have everything we need | ||
this.state = constants_1.SocksClientState.ReceivedFinalResponse; | ||
this.setState(constants_1.SocksClientState.ReceivedFinalResponse); | ||
// If using CONNECT, the client is now in the established state. | ||
if (constants_1.SocksCommand[this._options.command] === constants_1.SocksCommand.connect) { | ||
this.state = constants_1.SocksClientState.Established; | ||
if (constants_1.SocksCommand[this.options.command] === constants_1.SocksCommand.connect) { | ||
this.setState(constants_1.SocksClientState.Established); | ||
this.removeInternalSocketHandlers(); | ||
this.emit('established', { socket: this._socket }); | ||
this.emit('established', { socket: this.socket }); | ||
} | ||
else if (constants_1.SocksCommand[this._options.command] === constants_1.SocksCommand.bind) { | ||
else if (constants_1.SocksCommand[this.options.command] === constants_1.SocksCommand.bind) { | ||
/* If using BIND, the Socks client is now in BoundWaitingForConnection state. | ||
This means that the remote proxy server is waiting for a remote connection to the bound port. */ | ||
this.state = constants_1.SocksClientState.BoundWaitingForConnection; | ||
this._nextRequiredPacketBufferSize = | ||
this.setState(constants_1.SocksClientState.BoundWaitingForConnection); | ||
this.nextRequiredPacketBufferSize = | ||
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseHeader; | ||
this.emit('bound', { socket: this._socket, remoteHost }); | ||
this.emit('bound', { remoteHost, socket: this.socket }); | ||
/* | ||
@@ -683,6 +678,9 @@ If using Associate, the Socks client is now Established. And the proxy server is now accepting UDP packets at the | ||
} | ||
else if (constants_1.SocksCommand[this._options.command] === constants_1.SocksCommand.associate) { | ||
this.state = constants_1.SocksClientState.Established; | ||
else if (constants_1.SocksCommand[this.options.command] === constants_1.SocksCommand.associate) { | ||
this.setState(constants_1.SocksClientState.Established); | ||
this.removeInternalSocketHandlers(); | ||
this.emit('established', { socket: this._socket, remoteHost }); | ||
this.emit('established', { | ||
remoteHost, | ||
socket: this.socket, | ||
}); | ||
} | ||
@@ -696,5 +694,5 @@ } | ||
// Peek at available data (we need at least 5 bytes to get the hostname length) | ||
const header = this._receiveBuffer.peek(5); | ||
const header = this.receiveBuffer.peek(5); | ||
if (header[0] !== 0x05 || header[1] !== constants_1.Socks5Response.Granted) { | ||
this._closeSocket(`${constants_1.ERRORS.Socks5ProxyRejectedIncomingBoundConnection} - ${constants_1.Socks5Response[header[1]]}`); | ||
this.closeSocket(`${constants_1.ERRORS.Socks5ProxyRejectedIncomingBoundConnection} - ${constants_1.Socks5Response[header[1]]}`); | ||
} | ||
@@ -710,14 +708,14 @@ else { | ||
const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv4; | ||
if (this._receiveBuffer.length < dataNeeded) { | ||
this._nextRequiredPacketBufferSize = dataNeeded; | ||
if (this.receiveBuffer.length < dataNeeded) { | ||
this.nextRequiredPacketBufferSize = dataNeeded; | ||
return; | ||
} | ||
buff = smart_buffer_1.SmartBuffer.fromBuffer(this._receiveBuffer.get(dataNeeded).slice(4)); | ||
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(4)); | ||
remoteHost = { | ||
host: ip.fromLong(buff.readUInt32BE()), | ||
port: buff.readUInt16BE() | ||
port: buff.readUInt16BE(), | ||
}; | ||
// If given host is 0.0.0.0, assume remote proxy ip instead. | ||
if (remoteHost.host === '0.0.0.0') { | ||
remoteHost.host = this._options.proxy.ipaddress; | ||
remoteHost.host = this.options.proxy.ipaddress; | ||
} | ||
@@ -730,11 +728,10 @@ // Hostname | ||
// Check if data is available. | ||
if (this._receiveBuffer.length < dataNeeded) { | ||
this._nextRequiredPacketBufferSize = dataNeeded; | ||
if (this.receiveBuffer.length < dataNeeded) { | ||
this.nextRequiredPacketBufferSize = dataNeeded; | ||
return; | ||
} | ||
buff = smart_buffer_1.SmartBuffer.fromBuffer(this._receiveBuffer.get(dataNeeded).slice(5) // Slice at 5 to skip host length | ||
); | ||
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(5)); | ||
remoteHost = { | ||
host: buff.readString(hostLength), | ||
port: buff.readUInt16BE() | ||
port: buff.readUInt16BE(), | ||
}; | ||
@@ -746,19 +743,19 @@ // IPv6 | ||
const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv6; | ||
if (this._receiveBuffer.length < dataNeeded) { | ||
this._nextRequiredPacketBufferSize = dataNeeded; | ||
if (this.receiveBuffer.length < dataNeeded) { | ||
this.nextRequiredPacketBufferSize = dataNeeded; | ||
return; | ||
} | ||
buff = smart_buffer_1.SmartBuffer.fromBuffer(this._receiveBuffer.get(dataNeeded).slice(4)); | ||
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(4)); | ||
remoteHost = { | ||
host: ip.toString(buff.readBuffer(16)), | ||
port: buff.readUInt16BE() | ||
port: buff.readUInt16BE(), | ||
}; | ||
} | ||
this.state = constants_1.SocksClientState.Established; | ||
this.setState(constants_1.SocksClientState.Established); | ||
this.removeInternalSocketHandlers(); | ||
this.emit('established', { socket: this._socket, remoteHost }); | ||
this.emit('established', { remoteHost, socket: this.socket }); | ||
} | ||
} | ||
get socksClientOptions() { | ||
return Object.assign({}, this._options); | ||
return Object.assign({}, this.options); | ||
} | ||
@@ -765,0 +762,0 @@ } |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.SOCKS_INCOMING_PACKET_SIZES = exports.SocksClientState = exports.Socks5Response = exports.Socks5HostType = exports.Socks5Auth = exports.Socks4Response = exports.SocksCommand = exports.ERRORS = exports.DEFAULT_TIMEOUT = void 0; | ||
const DEFAULT_TIMEOUT = 30000; | ||
@@ -43,3 +44,3 @@ exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT; | ||
// Command response + incoming connection (bind) | ||
Socks4Response: 8 // 2 header + 2 port + 4 ip | ||
Socks4Response: 8, | ||
}; | ||
@@ -46,0 +47,0 @@ exports.SOCKS_INCOMING_PACKET_SIZES = SOCKS_INCOMING_PACKET_SIZES; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.validateSocksClientChainOptions = exports.validateSocksClientOptions = void 0; | ||
const util_1 = require("./util"); | ||
@@ -4,0 +5,0 @@ const constants_1 = require("./constants"); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ReceiveBuffer = void 0; | ||
class ReceiveBuffer { | ||
constructor(size = 4096) { | ||
this._buffer = Buffer.allocUnsafe(size); | ||
this._offset = 0; | ||
this._originalSize = size; | ||
this.buffer = Buffer.allocUnsafe(size); | ||
this.offset = 0; | ||
this.originalSize = size; | ||
} | ||
get length() { | ||
return this._offset; | ||
return this.offset; | ||
} | ||
@@ -16,24 +17,24 @@ append(data) { | ||
} | ||
if (this._offset + data.length >= this._buffer.length) { | ||
const tmp = this._buffer; | ||
this._buffer = Buffer.allocUnsafe(Math.max(this._buffer.length + this._originalSize, this._buffer.length + data.length)); | ||
tmp.copy(this._buffer); | ||
if (this.offset + data.length >= this.buffer.length) { | ||
const tmp = this.buffer; | ||
this.buffer = Buffer.allocUnsafe(Math.max(this.buffer.length + this.originalSize, this.buffer.length + data.length)); | ||
tmp.copy(this.buffer); | ||
} | ||
data.copy(this._buffer, this._offset); | ||
return (this._offset += data.length); | ||
data.copy(this.buffer, this.offset); | ||
return (this.offset += data.length); | ||
} | ||
peek(length) { | ||
if (length > this._offset) { | ||
if (length > this.offset) { | ||
throw new Error('Attempted to read beyond the bounds of the managed internal data.'); | ||
} | ||
return this._buffer.slice(0, length); | ||
return this.buffer.slice(0, length); | ||
} | ||
get(length) { | ||
if (length > this._offset) { | ||
if (length > this.offset) { | ||
throw new Error('Attempted to read beyond the bounds of the managed internal data.'); | ||
} | ||
const value = Buffer.allocUnsafe(length); | ||
this._buffer.slice(0, length).copy(value); | ||
this._buffer.copyWithin(0, length, length + this._offset - length); | ||
this._offset -= length; | ||
this.buffer.slice(0, length).copy(value); | ||
this.buffer.copyWithin(0, length, length + this.offset - length); | ||
this.offset -= length; | ||
return value; | ||
@@ -40,0 +41,0 @@ } |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.shuffleArray = exports.SocksClientError = void 0; | ||
/** | ||
@@ -18,4 +19,5 @@ * Error wrapper for SocksClient | ||
function shuffleArray(array) { | ||
// tslint:disable-next-line:no-increment-decrement | ||
for (let i = array.length - 1; i > 0; i--) { | ||
let j = Math.floor(Math.random() * (i + 1)); | ||
const j = Math.floor(Math.random() * (i + 1)); | ||
[array[i], array[j]] = [array[j], array[i]]; | ||
@@ -22,0 +24,0 @@ } |
"use strict"; | ||
function __export(m) { | ||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
} | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__export(require("./client/socksclient")); | ||
__exportStar(require("./client/socksclient"), exports); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "socks", | ||
"private": false, | ||
"version": "2.3.3", | ||
"version": "2.4.0", | ||
"description": "Fully featured SOCKS proxy client supporting SOCKSv4, SOCKSv4a, and SOCKSv5. Includes Bind and Associate functionality.", | ||
@@ -26,3 +26,3 @@ "main": "build/index.js", | ||
"engines": { | ||
"node": ">= 6.0.0", | ||
"node": ">= 10.13.0", | ||
"npm": ">= 3.0.0" | ||
@@ -37,18 +37,19 @@ }, | ||
"devDependencies": { | ||
"@types/chai": "4.2.4", | ||
"@types/chai": "4.2.11", | ||
"@types/ip": "1.1.0", | ||
"@types/mocha": "5.2.7", | ||
"@types/node": "12.12.6", | ||
"@types/mocha": "7.0.2", | ||
"@types/node": "^14.0.13", | ||
"chai": "^4.1.2", | ||
"coveralls": "^3.0.0", | ||
"mocha": "6.2.2", | ||
"nyc": "14.1.1", | ||
"prettier": "^1.9.2", | ||
"coveralls": "3.1.0", | ||
"mocha": "8.0.1", | ||
"nyc": "15.1.0", | ||
"socks5-server": "^0.1.1", | ||
"ts-node": "8.4.1", | ||
"tslint": "^5.8.0", | ||
"typescript": "3.7.2" | ||
"ts-node": "8.10.2", | ||
"tslint": "6.1.2", | ||
"tslint-config-airbnb": "^5.11.2", | ||
"typescript": "3.9.5" | ||
}, | ||
"dependencies": { | ||
"ip": "1.1.5", | ||
"prettier": "^2.0.5", | ||
"smart-buffer": "^4.1.0" | ||
@@ -59,2 +60,3 @@ }, | ||
"test": "NODE_ENV=test mocha --recursive --require ts-node/register test/**/*.ts", | ||
"prettier": "prettier --write ./src/**/*.ts --config .prettierrc.yaml", | ||
"coverage": "NODE_ENV=test nyc npm test", | ||
@@ -61,0 +63,0 @@ "coveralls": "NODE_ENV=test nyc npm test && nyc report --reporter=text-lcov | coveralls", |
@@ -17,3 +17,3 @@ # socks [![Build Status](https://travis-ci.org/JoshGlazebrook/socks.svg?branch=master)](https://travis-ci.org/JoshGlazebrook/socks) [![Coverage Status](https://coveralls.io/repos/github/JoshGlazebrook/socks/badge.svg?branch=master)](https://coveralls.io/github/JoshGlazebrook/socks?branch=v2) | ||
* Node.js v6.0+ (Please use [v1](https://github.com/JoshGlazebrook/socks/tree/82d83923ad960693d8b774cafe17443ded7ed584) for older versions of Node.js) | ||
* Node.js v10.0+ (Please use [v1](https://github.com/JoshGlazebrook/socks/tree/82d83923ad960693d8b774cafe17443ded7ed584) for older versions of Node.js) | ||
@@ -20,0 +20,0 @@ ### Looking for v1? |
@@ -20,11 +20,11 @@ /// <reference types="node" /> | ||
declare class SocksClient extends EventEmitter implements SocksClient { | ||
private _options; | ||
private _socket; | ||
private _state; | ||
private _receiveBuffer; | ||
private _nextRequiredPacketBufferSize; | ||
private _onDataReceived; | ||
private _onClose; | ||
private _onError; | ||
private _onConnect; | ||
private options; | ||
private socket; | ||
private state; | ||
private receiveBuffer; | ||
private nextRequiredPacketBufferSize; | ||
private onDataReceived; | ||
private onClose; | ||
private onError; | ||
private onConnect; | ||
constructor(options: SocksClientOptions); | ||
@@ -61,14 +61,10 @@ /** | ||
/** | ||
* Gets the SocksClient internal state. | ||
*/ | ||
private get state(); | ||
/** | ||
* Internal state setter. If the SocksClient is in an error state, it cannot be changed to a non error state. | ||
*/ | ||
private set state(value); | ||
private setState; | ||
/** | ||
* Starts the connection establishment to the proxy and destination. | ||
* @param existing_socket Connected socket to use instead of creating a new one (internal use). | ||
* @param existingSocket Connected socket to use instead of creating a new one (internal use). | ||
*/ | ||
connect(existing_socket?: Duplex): void; | ||
connect(existingSocket?: Duplex): void; | ||
private getSocketOptions; | ||
@@ -83,3 +79,3 @@ /** | ||
*/ | ||
private onConnect; | ||
private onConnectHandler; | ||
/** | ||
@@ -89,3 +85,3 @@ * Handles Socket data event. | ||
*/ | ||
private onDataReceived; | ||
private onDataReceivedHandler; | ||
/** | ||
@@ -99,3 +95,3 @@ * Handles processing of the data we have received. | ||
*/ | ||
private onClose; | ||
private onCloseHandler; | ||
/** | ||
@@ -105,3 +101,3 @@ * Handles Socket error event. | ||
*/ | ||
private onError; | ||
private onErrorHandler; | ||
/** | ||
@@ -115,3 +111,3 @@ * Removes internal event listeners on the underlying Socket. | ||
*/ | ||
private _closeSocket; | ||
private closeSocket; | ||
/** | ||
@@ -166,2 +162,2 @@ * Sends initial Socks v4 handshake request. | ||
} | ||
export { SocksClient, SocksClientOptions, SocksClientChainOptions, SocksRemoteHost, SocksProxy, SocksUDPFrameDetails }; | ||
export { SocksClient, SocksClientOptions, SocksClientChainOptions, SocksClientError, SocksRemoteHost, SocksProxy, SocksUDPFrameDetails, }; |
@@ -141,2 +141,2 @@ /// <reference types="node" /> | ||
} | ||
export { DEFAULT_TIMEOUT, ERRORS, SocksProxyType, SocksCommand, Socks4Response, Socks5Auth, Socks5HostType, Socks5Response, SocksClientState, SocksProxy, SocksRemoteHost, SocksCommandOption, SocksClientOptions, SocksClientChainOptions, SocksClientEstablishedEvent, SocksClientBoundEvent, SocksUDPFrameDetails, SOCKS_INCOMING_PACKET_SIZES }; | ||
export { DEFAULT_TIMEOUT, ERRORS, SocksProxyType, SocksCommand, Socks4Response, Socks5Auth, Socks5HostType, Socks5Response, SocksClientState, SocksProxy, SocksRemoteHost, SocksCommandOption, SocksClientOptions, SocksClientChainOptions, SocksClientEstablishedEvent, SocksClientBoundEvent, SocksUDPFrameDetails, SOCKS_INCOMING_PACKET_SIZES, }; |
/// <reference types="node" /> | ||
declare class ReceiveBuffer { | ||
private _buffer; | ||
private _offset; | ||
private _originalSize; | ||
private buffer; | ||
private offset; | ||
private originalSize; | ||
constructor(size?: number); | ||
@@ -7,0 +7,0 @@ get length(): number; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
141116
1344
3
+ Addedprettier@^2.0.5
+ Addedprettier@2.8.8(transitive)