Socket
Socket
Sign inDemoInstall

socks

Package Overview
Dependencies
Maintainers
1
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

socks - npm Package Compare versions

Comparing version 2.1.2 to 2.1.3

build/common/receiveBuffer.js

304

build/client/socksclient.js

@@ -17,2 +17,3 @@ "use strict";

const helpers_1 = require("../common/helpers");
const receiveBuffer_1 = require("../common/receiveBuffer");
const util_1 = require("../common/util");

@@ -219,2 +220,3 @@ class SocksClient extends events_1.EventEmitter {

this.state = constants_1.SocksClientState.Connecting;
this._receiveBuffer = new receiveBuffer_1.ReceiveBuffer();
if (existing_socket) {

@@ -226,4 +228,12 @@ this._socket.emit('connect');

}
// Listens for instance 'established' event to remove internal data socket handlers.
this.once('established', () => this.removeInternalSocketHandlers());
// Listen for established event so we can re-emit any excess data received during handshakes.
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();
});
});
}

@@ -259,33 +269,51 @@ /**

onDataReceived(data) {
// Sent initial handshake, waiting for response.
if (this.state === constants_1.SocksClientState.SentInitialHandshake) {
if (this._options.proxy.type === 4) {
// Socks v4 only has one handshake response.
this.handleSocks4FinalHandshakeResponse(data);
/*
All received data is appended to a ReceiveBuffer.
This makes sure that all the data we need is received before we attempt to process it.
*/
this._receiveBuffer.append(data);
// Process data that we have.
this.processData();
}
/**
* Handles processing of the data we have received.
*/
processData() {
// If we have enough data to process the next step in the SOCKS handshake, proceed.
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) {
// Socks v4 only has one handshake response.
this.handleSocks4FinalHandshakeResponse();
}
else {
// Socks v5 has two handshakes, handle initial one here.
this.handleInitialSocks5HandshakeResponse();
}
// Sent auth request for Socks v5, waiting for response.
}
else {
// Socks v5 has two handshakes, handle initial one here.
this.handleInitialSocks5HandshakeResponse(data);
else if (this.state === constants_1.SocksClientState.SentAuthentication) {
this.handleInitialSocks5AuthenticationHandshakeResponse();
// Sent final Socks v5 handshake, waiting for final response.
}
// Sent auth request for Socks v5, waiting for response.
}
else if (this.state === constants_1.SocksClientState.SentAuthentication) {
this.handleInitialSocks5AuthenticationHandshakeResponse(data);
// Sent final Socks v5 handshake, waiting for final response.
}
else if (this.state === constants_1.SocksClientState.SentFinalHandshake) {
this.handleSocks5FinalHandshakeResponse(data);
// Socks BIND established. Waiting for remote connection via proxy.
}
else if (this.state === constants_1.SocksClientState.BoundWaitingForConnection) {
if (this._options.proxy.type === 4) {
this.handleSocks4IncomingConnectionResponse(data);
else if (this.state === constants_1.SocksClientState.SentFinalHandshake) {
this.handleSocks5FinalHandshakeResponse();
// Socks BIND established. Waiting for remote connection via proxy.
}
else if (this.state === constants_1.SocksClientState.BoundWaitingForConnection) {
if (this._options.proxy.type === 4) {
this.handleSocks4IncomingConnectionResponse();
}
else {
this.handleSocks5IncomingConnectionResponse();
}
}
else if (this.state === constants_1.SocksClientState.Established) {
// do nothing (prevents closing of the socket)
}
else {
this.handleSocks5IncomingConnectionResponse(data);
this._closeSocket(constants_1.ERRORS.InternalError);
}
}
else {
this._closeSocket(constants_1.ERRORS.InternalError);
}
}

@@ -310,2 +338,4 @@ /**

removeInternalSocketHandlers() {
// Pauses data flow of the socket (this is internally resumed after 'established' is emitted)
this._socket.pause();
this._socket.removeListener('data', this._onDataReceived);

@@ -358,2 +388,4 @@ this._socket.removeListener('close', this._onClose);

}
this._nextRequiredPacketBufferSize =
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks4Response;
this._socket.write(buff.toBuffer());

@@ -365,8 +397,5 @@ }

*/
handleSocks4FinalHandshakeResponse(data) {
if (data.length < 8) {
// 8 is required
this._closeSocket(constants_1.ERRORS.InvalidSocks4HandshakeResponse);
}
else if (data[1] !== constants_1.Socks4Response.Granted) {
handleSocks4FinalHandshakeResponse() {
const data = this._receiveBuffer.get(8);
if (data[1] !== constants_1.Socks4Response.Granted) {
this._closeSocket(`${constants_1.ERRORS.Socks4ProxyRejectedConnection} - (${constants_1.Socks4Response[data[1]]})`);

@@ -393,2 +422,3 @@ }

this.state = constants_1.SocksClientState.Established;
this.removeInternalSocketHandlers();
this.emit('established', { socket: this._socket });

@@ -402,8 +432,5 @@ }

*/
handleSocks4IncomingConnectionResponse(data) {
if (data.length < 8) {
// 8 is required.
this._closeSocket(constants_1.ERRORS.InvalidSocks4IncomingConnectionResponse);
}
else if (data[1] !== constants_1.Socks4Response.Granted) {
handleSocks4IncomingConnectionResponse() {
const data = this._receiveBuffer.get(8);
if (data[1] !== constants_1.Socks4Response.Granted) {
this._closeSocket(`${constants_1.ERRORS.Socks4ProxyRejectedIncomingBoundConnection} - (${constants_1.Socks4Response[data[1]]})`);

@@ -419,2 +446,3 @@ }

this.state = constants_1.SocksClientState.Established;
this.removeInternalSocketHandlers();
this.emit('established', { socket: this._socket, remoteHost });

@@ -432,2 +460,3 @@ }

buff.writeUInt8(constants_1.Socks5Auth.UserPass);
this._nextRequiredPacketBufferSize = 2; // Need 2 bytes back
this._socket.write(buff.toBuffer());

@@ -440,8 +469,5 @@ this.state = constants_1.SocksClientState.SentInitialHandshake;

*/
handleInitialSocks5HandshakeResponse(data) {
if (data.length !== 2) {
// 2 is required
this._closeSocket(constants_1.ERRORS.InvalidSocks5InitialHandshakeResponse);
}
else if (data[0] !== 0x05) {
handleInitialSocks5HandshakeResponse() {
const data = this._receiveBuffer.get(2);
if (data[0] !== 0x05) {
this._closeSocket(constants_1.ERRORS.InvalidSocks5IntiailHandshakeSocksVersion);

@@ -480,2 +506,4 @@ }

buff.writeString(password);
this._nextRequiredPacketBufferSize =
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5UserPassAuthenticationResponse;
this._socket.write(buff.toBuffer());

@@ -488,5 +516,6 @@ this.state = constants_1.SocksClientState.SentAuthentication;

*/
handleInitialSocks5AuthenticationHandshakeResponse(data) {
handleInitialSocks5AuthenticationHandshakeResponse() {
this.state = constants_1.SocksClientState.ReceivedAuthenticationResponse;
if (data.length !== 2 || data[1] !== 0x00) {
const data = this._receiveBuffer.get(2);
if (data[1] !== 0x00) {
this._closeSocket(constants_1.ERRORS.Socks5AuthenticationFailed);

@@ -521,2 +550,4 @@ }

buff.writeUInt16BE(this._options.destination.port);
this._nextRequiredPacketBufferSize =
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5Response;
this._socket.write(buff.toBuffer());

@@ -529,75 +560,87 @@ this.state = constants_1.SocksClientState.SentFinalHandshake;

*/
handleSocks5FinalHandshakeResponse(data) {
if (data.length < 5) {
// 4 is required to get address type, 5 is hostname length and should be there anyways.
this._closeSocket(constants_1.ERRORS.InvalidSocks5FinalHandshake);
handleSocks5FinalHandshakeResponse() {
// Peek at available data (we need at least 5 bytes to get the hostname length)
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]]}`);
}
else if (data[0] !== 0x05 || data[1] !== constants_1.Socks5Response.Granted) {
this._closeSocket(`${constants_1.ERRORS.InvalidSocks5FinalHandshakeRejected} - ${constants_1.Socks5Response[data[1]]}`);
}
else {
// Read address type
const addressType = header[3];
let remoteHost;
let buff;
// IPv4
if (addressType === constants_1.Socks5HostType.IPv4) {
// Check if data is available.
if (this._receiveBuffer.length <
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv4) {
this._nextRequiredPacketBufferSize =
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv4;
return;
}
buff = smart_buffer_1.SmartBuffer.fromBuffer(this._receiveBuffer.get(10));
remoteHost = {
host: ip.fromLong(buff.readUInt32BE()),
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;
}
// Hostname
}
else if (addressType === constants_1.Socks5HostType.Hostname) {
const hostLength = buff.readUInt8();
const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseHostname(hostLength); // header + host length + port
// Check if data is available.
if (this._receiveBuffer.length < dataNeeded) {
this._nextRequiredPacketBufferSize = dataNeeded;
return;
}
buff = smart_buffer_1.SmartBuffer.fromBuffer(this._receiveBuffer.get(dataNeeded));
remoteHost = {
host: buff.readString(hostLength),
port: buff.readUInt16BE()
};
// IPv6
}
else if (addressType === constants_1.Socks5HostType.IPv6) {
// Check if data is available.
if (this._receiveBuffer.length <
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv6) {
this._nextRequiredPacketBufferSize =
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv6;
return;
}
buff = smart_buffer_1.SmartBuffer.fromBuffer(this._receiveBuffer.get(24));
remoteHost = {
host: ip.toString(buff.readBuffer(16)),
port: buff.readUInt16BE()
};
}
// We have everything we need
this.state = 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;
this.removeInternalSocketHandlers();
this.emit('established', { socket: this._socket });
}
else {
// Read address type
const buff = smart_buffer_1.SmartBuffer.fromBuffer(data);
buff.readOffset = 3;
const addressType = buff.readUInt8();
let remoteHost;
// IPv4
if (addressType === constants_1.Socks5HostType.IPv4) {
// Check if data is available.
if (data.length < 10) {
return this._closeSocket(constants_1.ERRORS.InvalidSocks5FinalHandshake);
}
remoteHost = {
host: ip.fromLong(buff.readUInt32BE()),
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;
}
// Hostname
}
else if (addressType === constants_1.Socks5HostType.Hostname) {
const hostLength = buff.readUInt8();
// Check if data is available.
if (buff.length - 5 < hostLength) {
return this._closeSocket(constants_1.ERRORS.InvalidSocks5FinalHandshake);
}
remoteHost = {
host: buff.readString(hostLength),
port: buff.readUInt16BE()
};
// IPv6
}
else if (addressType === constants_1.Socks5HostType.IPv6) {
// Check if data is available.
if (buff.length < 24) {
return this._closeSocket(constants_1.ERRORS.InvalidSocks5FinalHandshake);
}
remoteHost = {
host: ip.toString(buff.readBuffer(16)),
port: buff.readUInt16BE()
};
}
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. */
if (constants_1.SocksCommand[this._options.command] === constants_1.SocksCommand.bind) {
this.state = constants_1.SocksClientState.BoundWaitingForConnection;
this.emit('bound', { socket: this._socket, remoteHost });
/*
If using Associate, the Socks client is now Established. And the proxy server is now accepting UDP packets at the
given bound port. This initial Socks TCP connection must remain open for the UDP relay to continue to work.
*/
}
else if (constants_1.SocksCommand[this._options.command] === constants_1.SocksCommand.associate) {
this.state = constants_1.SocksClientState.Established;
this.emit('established', { socket: this._socket, remoteHost });
}
this.state = constants_1.SocksClientState.BoundWaitingForConnection;
this._nextRequiredPacketBufferSize =
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5Response;
this.emit('bound', { socket: this._socket, remoteHost });
/*
If using Associate, the Socks client is now Established. And the proxy server is now accepting UDP packets at the
given bound port. This initial Socks TCP connection must remain open for the UDP relay to continue to work.
*/
}
else if (constants_1.SocksCommand[this._options.command] === constants_1.SocksCommand.associate) {
this.state = constants_1.SocksClientState.Established;
this.removeInternalSocketHandlers();
this.emit('established', { socket: this._socket, remoteHost });
}
}

@@ -607,23 +650,24 @@ }

* Handles Socks v5 incoming connection request (BIND).
* @param data
*/
handleSocks5IncomingConnectionResponse(data) {
if (data.length < 4) {
this._closeSocket(constants_1.ERRORS.InvalidSocks5IncomingConnectionResponse);
handleSocks5IncomingConnectionResponse() {
// Peek at available data (we need at least 5 bytes to get the hostname length)
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]]}`);
}
else if (data[0] !== 0x05 || data[1] !== constants_1.Socks5Response.Granted) {
this._closeSocket(`${constants_1.ERRORS.Socks5ProxyRejectedIncomingBoundConnection} - ${constants_1.Socks5Response[data[1]]}`);
}
else {
// Read address type
const buff = smart_buffer_1.SmartBuffer.fromBuffer(data);
buff.readOffset = 3;
const addressType = buff.readUInt8();
const addressType = header[3];
let remoteHost;
let buff;
// IPv4
if (addressType === constants_1.Socks5HostType.IPv4) {
// Check if data is available.
if (data.length < 10) {
return this._closeSocket(constants_1.ERRORS.InvalidSocks5IncomingConnectionResponse);
if (this._receiveBuffer.length <
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv4) {
this._nextRequiredPacketBufferSize =
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv4;
return;
}
buff = smart_buffer_1.SmartBuffer.fromBuffer(this._receiveBuffer.get(10));
remoteHost = {

@@ -641,6 +685,9 @@ host: ip.fromLong(buff.readUInt32BE()),

const hostLength = buff.readUInt8();
const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseHostname(hostLength); // header + host length + port
// Check if data is available.
if (buff.length - 5 < hostLength) {
return this._closeSocket(constants_1.ERRORS.InvalidSocks5IncomingConnectionResponse);
if (this._receiveBuffer.length < dataNeeded) {
this._nextRequiredPacketBufferSize = dataNeeded;
return;
}
buff = smart_buffer_1.SmartBuffer.fromBuffer(this._receiveBuffer.get(dataNeeded));
remoteHost = {

@@ -654,5 +701,9 @@ host: buff.readString(hostLength),

// Check if data is available.
if (buff.length < 24) {
return this._closeSocket(constants_1.ERRORS.InvalidSocks5IncomingConnectionResponse);
if (this._receiveBuffer.length <
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv6) {
this._nextRequiredPacketBufferSize =
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv6;
return;
}
buff = smart_buffer_1.SmartBuffer.fromBuffer(this._receiveBuffer.get(24));
remoteHost = {

@@ -664,2 +715,3 @@ host: ip.toString(buff.readBuffer(16)),

this.state = constants_1.SocksClientState.Established;
this.removeInternalSocketHandlers();
this.emit('established', { socket: this._socket, remoteHost });

@@ -666,0 +718,0 @@ }

@@ -34,2 +34,14 @@ "use strict";

exports.ERRORS = ERRORS;
const SOCKS_INCOMING_PACKET_SIZES = {
Socks5InitialHandshakeResponse: 2,
Socks5UserPassAuthenticationResponse: 2,
// Command response + incoming connection (bind)
Socks5Response: 5,
Socks5ResponseIPv4: 10,
Socks5ResponseIPv6: 24,
Socks5ResponseHostname: (hostNameLength) => hostNameLength + 6,
// Command response + incoming connection (bind)
Socks4Response: 8
};
exports.SOCKS_INCOMING_PACKET_SIZES = SOCKS_INCOMING_PACKET_SIZES;
var SocksCommand;

@@ -36,0 +48,0 @@ (function (SocksCommand) {

{
"name": "socks",
"private": false,
"version": "2.1.2",
"version": "2.1.3",
"description": "Fully featured SOCKS proxy client supporting SOCKSv4, SOCKSv4a, and SOCKSv5. Includes Bind and Associate functionality.",

@@ -6,0 +6,0 @@ "main": "build/index.js",

@@ -23,2 +23,4 @@ /// <reference types="node" />

private _state;
private _receiveBuffer;
private _nextRequiredPacketBufferSize;
private _onDataReceived;

@@ -85,2 +87,6 @@ private _onClose;

/**
* Handles processing of the data we have received.
*/
private processData();
/**
* Handles Socket close event.

@@ -112,3 +118,3 @@ * @param had_error

*/
private handleSocks4FinalHandshakeResponse(data);
private handleSocks4FinalHandshakeResponse();
/**

@@ -118,3 +124,3 @@ * Handles Socks v4 incoming connection request (BIND)

*/
private handleSocks4IncomingConnectionResponse(data);
private handleSocks4IncomingConnectionResponse();
/**

@@ -128,3 +134,3 @@ * Sends initial Socks v5 handshake request.

*/
private handleInitialSocks5HandshakeResponse(data);
private handleInitialSocks5HandshakeResponse();
/**

@@ -140,3 +146,3 @@ * Sends Socks v5 user & password auth handshake.

*/
private handleInitialSocks5AuthenticationHandshakeResponse(data);
private handleInitialSocks5AuthenticationHandshakeResponse();
/**

@@ -150,10 +156,9 @@ * Sends Socks v5 final handshake request.

*/
private handleSocks5FinalHandshakeResponse(data);
private handleSocks5FinalHandshakeResponse();
/**
* Handles Socks v5 incoming connection request (BIND).
* @param data
*/
private handleSocks5IncomingConnectionResponse(data);
private handleSocks5IncomingConnectionResponse();
readonly socksClientOptions: SocksClientOptions;
}
export { SocksClient, SocksClientOptions, SocksClientChainOptions, SocksRemoteHost, SocksProxy, SocksUDPFrameDetails };

@@ -32,2 +32,11 @@ /// <reference types="node" />

};
declare const SOCKS_INCOMING_PACKET_SIZES: {
Socks5InitialHandshakeResponse: number;
Socks5UserPassAuthenticationResponse: number;
Socks5Response: number;
Socks5ResponseIPv4: number;
Socks5ResponseIPv6: number;
Socks5ResponseHostname: (hostNameLength: number) => number;
Socks4Response: number;
};
declare type SocksCommandOption = 'connect' | 'bind' | 'associate';

@@ -128,2 +137,2 @@ declare enum SocksCommand {

}
export { DEFAULT_TIMEOUT, ERRORS, SocksProxyType, SocksCommand, Socks4Response, Socks5Auth, Socks5HostType, Socks5Response, SocksClientState, SocksProxy, SocksRemoteHost, SocksCommandOption, SocksClientOptions, SocksClientChainOptions, SocksClientEstablishedEvent, SocksClientBoundEvent, SocksUDPFrameDetails };
export { DEFAULT_TIMEOUT, ERRORS, SocksProxyType, SocksCommand, Socks4Response, Socks5Auth, Socks5HostType, Socks5Response, SocksClientState, SocksProxy, SocksRemoteHost, SocksCommandOption, SocksClientOptions, SocksClientChainOptions, SocksClientEstablishedEvent, SocksClientBoundEvent, SocksUDPFrameDetails, SOCKS_INCOMING_PACKET_SIZES };

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc