Git Product home page Git Product logo

simple-socks's Introduction

Simple Socks Server

Creates a simple SOCKS5 server and exposes additional SOCKS5 proxy events.

Build Status

Installation

npm install simple-socks

Example Usage

In the examples folder exists two examples, one that requires no authentication and one that requires username/password authentication. Below is an example with no authentication:

import socks5 from 'simple-socks'

const server = socks5.createServer().listen(1080);

// When a reqest arrives for a remote destination
server.on('proxyConnect', (info, destination) => {
  console.log('connected to remote server at %s:%d', info.address, info.port);

  destination.on('data', (data) => {
    console.log(data.length);
  });
});

// When data arrives from the remote connection
server.on('proxyData', (data) => {
  console.log(data.length);
});

// When an error occurs connecting to remote destination
server.on('proxyError', (err) => {
  console.error('unable to connect to remote server');
  console.error(err);
});

// When a request for a remote destination ends
server.on('proxyDisconnect', (originInfo, destinationInfo, hadError) => {
  console.log(
    'client %s:%d request has disconnected from remote server at %s:%d with %serror',
    originInfo.address,
    originInfo.port,
    destinationInfo.address,
    destinationInfo.port,
    hadError ? '' : 'no ');
});

// When a proxy connection ends
server.on('proxyEnd', (response, args) => {
  console.log('socket closed with code %d', response);
  console.log(args);
});

Running The Examples

No Authentication

For a SOCKS5 server that does not require authentication, look at examples/createServer.js:

node examples/createServer

In a separate terminal window:

curl http://www.google.com --socks5 127.0.0.1:1080

Username/Password Authentication

For a SOCKS5 server that requires username/password authentication, look at examples/createServerWithAuthentication.js:

node examples/createServerWithAuthentication

In a separate terminal window:

curl http://www.google.com --socks5 127.0.0.1:1080 --proxy-user foo:bar

Connection Filter

For a SOCKS5 server that can perform either origin or destination (or both!) address filtering, look at examples/createServerConnectionFilter.js:

node examples/createServerConnectionFilter

In a separate terminal window:

curl http://www.github.com --socks5 127.0.0.1:1080 # allowed
curl http://www.google.com --socks5 127.0.0.1:1080 # denied

Methods

createServer

Factory method that creates an instance of a SOCKS5 proxy server:

import socks5 from 'simple-socks';

const server = socks5.createServer();

server.listen(1080, '0.0.0.0', function () {
  console.log('SOCKS5 proxy server started on 0.0.0.0:1080');
});

This method accepts an optional options argument:

  • options.authentication - A callback for authentication
  • options.connectionFilter - A callback for connection filtering

authentication

To make the socks5 server require username/password authentication, supply a function callback in the options as follows:

import socks5 from 'simple-socks';

const options = {
  authenticate : function (username, password, socket, callback) {
    if (username === 'foo' && password === 'bar') {
      return setImmediate(callback);
    }

    return setImmediate(callback, new Error('incorrect username and password'));
  }
};

const server = socks5.createServer(options);

// begin listening and require user/pass authentication
server.listen(1080);

The authenticate callback accepts three arguments:

  • username - username of the proxy user
  • password - password of the proxy user
  • socket - the socket for the client connection
  • callback - callback for authentication... if authentication is successful, the callback should be called with no arguments

connectionFilter

Allows you to filter incoming connections, based on either origin and/or destination, return false to disallow:

import socks5 from 'simple-socks';

const server = socks5.createServer({
  connectionFilter : function (destination, origin, callback) {
    if (origin.address === '127.0.0.1') {
      console.log('denying access from %s:%s', origin.address, origin.port);

      return setImmediate(callback, new Error('access from specified origin is denied'));
    }

    if (destination.address === '10.0.0.1') {
      console.log('denying access to %s:%s', remote.address, remote.port);

      return setImmediate(callback, new Error('access to specified destination is denied'));
    }

    return setImmediate(callback);
  }
});

The connectionFilter callback accepts three arguments:

  • destination - an information object containing details for destination connection
    • address - the TCP address of the remote server
    • port - the TCP port of the remote server
  • origin - an information object containing details for origin connection
    • address - the TCP address of the origin (client) connection
    • port - the TCP port of the origin (client) connection
  • callback - callback for destination and/or origin address validation... if connections are allowed to the destination address, the callback should be called with no arguments

For an example, see examples/createServerConnectionFilter.js.

Events

The socks5 server supports all events that exist on a native net.Server object. Additionally, the following events have been added that are specific to the SOCKS5 proxy:

  • handshake - The first event fired and it occurs when a new SOCKS5 client proxy negotiation occurs
  • authenticate - When username/password authentication is configured (see above), this event is fired when a successful authentication occurs
  • authenticateError - When username/password authentication is configured, this event is fired when authentication fails
  • connectionFilter - When a destination address is denied by the configured connection filter callback, this event is fired
  • proxyConnect - After handshake and optional authentication, this event is emitted upon successful connection with the remote destination
  • proxyError - If connection to the remote destination fails, this event is emitted
  • proxyDisconnect - If a successful proxyConnect occurs, this event is emitted when the remote destination ends the connection
  • proxyData - When data is recieved from the remote destination, this event is fired
  • proxyEnd - This event is emitted when the SOCKS5 client connection is closed for any reason

Note:

This module exports the above events as constants for convenience purposes via the property events:

console.log(socks5.events);

Outputs the following:

{ AUTHENTICATION: 'authenticate',
  AUTHENTICATION_ERROR: 'authenticateError',
  CONNECTION_FILTER: 'connectionFilter',
  HANDSHAKE: 'handshake',
  PROXY_CONNECT: 'proxyConnect',
  PROXY_DATA: 'proxyData',
  PROXY_DISCONNECT: 'proxyDisconnect',
  PROXY_END: 'proxyEnd',
  PROXY_ERROR: 'proxyError' }

handshake

This is event is emitted when a socks5 client connects to the server. The callback accepts a single argument:

// When a new request is initiated
server.on('handshake', function (socket) {
  console.log('new socks5 client from %s:%d', socket.remoteAddress, socket.remotePort);
});

authenticate

This event is emitted when successful authentication occurs. The callback accepts a single argument:

  • username - the username of the successfully authenticated SOCKS5 proxy user
// When authentication succeeds
server.on('authenticate', function (username) {
  console.log('user %s successfully authenticated!', username);
});

authenticateError

This event is emitted when authentication is not successful. The callback accepts the following arguments:

  • username - the username of the SOCKS5 proxy user
  • err - the error returned to the options.authenticate callback
// When authentication fails
server.on('authenticateError', function (username, err) {
  console.log('user %s failed to authenticate...', username);
  console.error(err);
});

connectionFilter

This event is emitted when a destination address and port is filtered by the connectionFilter callback. The callback accepts the following arguments:

  • destination - an information object containing details for destination connection
    • address - the TCP address of the remote server
    • port - the TCP port of the remote server
  • origin - an information object containing details for origin connection
    • address - the TCP address of the origin (client) connection
    • port - the TCP port of the origin (client) connection
  • err - the error returned to the options.connectionFilter callback
// When a destination connection is filtered
server.on('connectionFilter', function (port, address, err) {
  console.log('connection to %s:%s has been denied', address, port);
  console.error(err);
});

proxyConnect

This event is emitted each time a connection is requested to a remote destination. The callback accepts two arguments:

  • info - object with two fields
    • address - the TCP address of the remote (destination) server
    • port - the TCP port of the remote (destination) server
  • destination - the destination TCP net.Socket
// When a reqest arrives for a remote destination
server.on('proxyConnect', function (info, destination) {
  console.log('connected to remote server at %s:%d', info.address, info.port);
});

proxyData

This event is emitted each time a remote connection returns data:

// When a reqest arrives for a remote destination
server.on('proxyData', function (data) {
  console.log('data received from remote destination: %d', data.length);
});

Note: This can also be accomplished by listening to the data event on the destination connection received in the proxyConnect event:

// When a reqest arrives for a remote destination
server.on('proxyConnect', function (info, destination) {
  destination.on('data', function (data) {
    console.log('data received from remote destination: %d', data.length);
  });
});

proxyDisconnect

This event is emitted after a proxyConnect when a connection to a remote destination has ended. The callback accepts three arguments:

  • originInfo - object with two fields
    • address - the TCP address of the origin of the request
    • port - the TCP port of the origin of the request
  • destinationInfo - object with two fields
    • address - the TCP address of the remote (destination) server
    • port the TCP port of the remote (destination) server
  • hadError - a Boolean indicating if a transmission error occurred after connecting with the remote (destination) server
// When a request for a remote destination ends
server.on('proxyDisconnect', function (err) {
  console.log(
    'client %s:%d request has disconnected from remote server at %s:%d with %serror',
    originInfo.address,
    originInfo.port,
    destinationInfo.address,
    destinationInfo.port,
    hadError ? '' : 'no ');
});

proxyError

In the event that a network error occurs attempting to create communication with the destination, this event is raised.

// When an error occurs connecting to remote destination
server.on('proxyError', function (err) {
  console.error('unable to connect to remote server');
  console.error(err);
});

proxyEnd

When a socket connection is closed by the server, the proxyEnd event is emitted. It returns two arguments in the callback:

  • response - the specific RFC 1928 documented response code
  • args - RFC 1928 fields for the proxy request including
    • ver
    • cmd
    • atype
    • dst.addr
    • dst.port
// When a proxy connection ends
server.on('proxyEnd', function (response, args) {
  console.log('socket closed with code %d', response);
  console.log(args);
});

simple-socks's People

Contributors

brozeph avatar dependabot[bot] avatar dgramop avatar fabiensk avatar lanius-collaris avatar pronskiy avatar slava-vishnyakov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

simple-socks's Issues

Unhandled 'error' event

I wanted to use hexchat with this. i set (just for test) invalid password in hexchat. After i try to connect. i got this in proxy:

------------------------------------------------------------
new client connection
user elbandi_ failed to authenticate...
[Error: invalid credentials]
socket closed with code 255
{ ver: 1,
  ulen: 8,
  uname: <Buffer 65 6c 62 61 6e 64 69 5f>,
  plen: 5,
  passwd: <Buffer 6b 75 6b 61 63>,
  requestBuffer: <Buffer 01 ff 65 6c 62 61 6e 64 69 5f 05 6b 75 6b 61 63> }


events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: read ECONNRESET
    at errnoException (net.js:901:11)
    at TCP.onread (net.js:556:19)

Adding typescript types

We are using this package in a typescript application and it would be great to have typescript support for this package.

telegram https error

hi
what is problem?

connected to remote server at 149.154.166.120:443
unable to connect to remote server
{ Error: read ECONNRESET
    at TCP.onread (net.js:659:25) errno: 'ECONNRESET', code: 'ECONNRESET', syscall: 'read' }
connected to remote server at 149.154.166.120:443
unable to connect to remote server
{ Error: This socket has been ended by the other party
    at Socket.writeAfterFIN [as write] (net.js:401:12)
    at Socket.<anonymous> (/var/www/simple-socks/lib/socks5.js:260:18)
    at Object.onceWrapper (events.js:275:13)
    at Socket.emit (events.js:187:15)
    at Socket.EventEmitter.emit (domain.js:460:23)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1147:10) code: 'EPIPE' }

Idea: Edit content before return

Is it possible to edit response before returning to the client?

For example show a "Your subscription has been expired" page
or remove ads from page and then return result (like many other VPNs)

Upstream Proxy Server

I am interested in using your server in the folowing configuration. We currently have SOCKS5 proxies that do not support authentication. We'd like to have this setup:

CLIENT ---> SIMPLE-SOCKS ---> REMOTE_PROXY ---> WEB/WHATEVER

request proxyDisconnect event

I want to limit connected devices count per user (for example sell a 2 devices subscription)
The database and codes are ready. But there is a problem. Here is the scenario:

  1. Each time the proxyConnect fired, We count a connection for the user to limit the number of connections (1 of 2 devices is remaining).
  2. And each time the proxyDisconnect event fired, We know that the user connection has been closed, So we revoke the step 1 connection (2 of 2 devices is remaining).

So we need a proxyDisconnect event to run this scenario. Thanks for your time.

Upstream SOCKS5 Server

I am interested in using your server in the folowing configuration. We currently have SOCKS5 proxies that do not support authentication. We'd like to have this setup:

CLIENT ---> SIMPLE-SOCKS ---> CURRENT_SOCKS5 _PROXY ---> WEB/WHATEVER

Is this possible? Furthermore, is it possible to somehow configure it like so?

server1 = socks5.createServer().listen(1080).upstream("socks5://host:1080");
server2= socks5.createServer().listen(1081).upstream("socks5://host:1081");

Browser support?

It work fine with curl but not in browser.
I get:
Possible security risk looking up this domain
and when force
Unable to connect
It would seem an SSL problem.
Do it have a solution?

How can I use this?

Hello, I want to use this project in a NodeJS project as below, but I don't know how, sorry, I'm a beginner in NodeJS.

It can't work when I use remote proxy. Please kindly help look at it.

test in local env
image
test in my computer
image

this is the log

[root@iZj6caq81rcy1s8vj7cxx0Z simple-proxy]# node ./createServer.js 

------------------------------------------------------------
new socks5 client from ::ffff:127.0.0.1:37772
connected to remote server at 142.250.199.68:443
4304
4304
642
642
31
31
4855
4855
11306
11306
client ::ffff:127.0.0.1:37772 request has disconnected from remote server at 142.250.199.68:443 with no error

------------------------------------------------------------
new socks5 client from ::ffff:183.237.146.203:46706

unable to connect to remote server
Error: connect ETIMEDOUT 172.217.17.36:443
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1146:16)
    at TCPConnectWrap.callbackTrampoline (internal/async_hooks.js:129:14) {
  errno: -110,
  code: 'ETIMEDOUT',
  syscall: 'connect',
  address: '172.217.17.36',
  port: 443,
  addr: '172.217.17.36',
  atyp: 1
}
socket closed with code 3
{
  ver: 5,
  cmd: 1,
  rsv: 0,
  atyp: 1,
  requestBuffer: <Buffer 05 03 00 01 ac d9 11 24 01 bb>,
  dst: { addr: '172.217.17.36', port: 443 },
  addr: { buf: <Buffer ac d9 11 24> }
}

I don't why the ip address is 172.217.17.36, can we do more enhancement?

How to White-list Url's? Proxy only allowed urls.

Thanks for the beautiful piece of code. I'm running a proxy server locally (that is pointing my network settings to the proxy server). This proxies logs all of the network traffic including my slack, Spotify and so on. However, I need only a list of given url's to be proxied. Like if an user enters a url which is not allowed by my proxy server then his request shouldn't go through. How can I achieve it using this proxy?

Authentication not working with clients

Authentication in examples/createServerWithAuthentication works using the curl command in the README, but providing the same credentials in macOS system preferences for SOCKS Proxy config, nor Electron webview proxy authentication does not work. The error "invalid credentials" is printed to the console.

ipv6 bug

src/socks5.js:178
args.dst.addr.push((x >>> 16).toString(16))

test:

node examples/createServer.js
curl -v -I --socks5 127.0.0.1:1080 https://ipv6.mirrors.ustc.edu.cn/

High CPU Usage 100% when creating a simple socks proxy server

Proxy works for few days and then suddenly cpu spikes to 100% and doesn't come down i have to restart the machine to make it work again. I am attaching code and cpu snapshot. On this server nothing other than this code is running. I have same code running on 5 machines and all having same issue.

import socks5 from 'simple-socks';
let stats = {}; //not big object since I only proxy traffic to 5 domains
let AUTH = {user: 'test', pass: 'test'};

const options = {
    authenticate : function (username, password, socket, callback) {
        if (username === AUTH.user && password === AUTH.pass) {
            return setImmediate(callback);
        }

        return setImmediate(callback, new Error('incorrect username and password'));
    }
};

function updateStats(info) {
    const ip = info.address;
    stats[ip] = stats[ip] ? stats[ip]+1: 1;
    console.log('Proxy Stats:', stats);
}

const server = socks5.createServer(options);

// Better Logging and error handling
server.on('proxyConnect', (info, destination) => {
    updateStats(info);
    console.log(`[ProxyConnect] Connected to remote server at ${info.address}:${info.port}`);

    destination.on('data', (data) => {
        console.log(`[ProxyConnect] Data received from ${info.address}:${info.port}. Length: ${data.length} bytes`);
    });
});

server.on('proxyData', (data) => {
    console.log(`[ProxyData] Data received. Length: ${data.length} bytes`);
});

server.on('proxyError', (err) => {
    console.error('[ProxyError] Unable to connect to remote server.');
    console.error('Error:', err.message);
});

server.on('proxyDisconnect', (originInfo, destinationInfo, hadError) => {
    const errorStatus = hadError ? 'with error' : 'without error';
    console.log(
        `[ProxyDisconnect] Client ${originInfo.address}:${originInfo.port} request disconnected from remote server at ${destinationInfo.address}:${destinationInfo.port} ${errorStatus}`
    );
});

server.on('proxyEnd', (response, args) => {
    console.log(`[ProxyEnd] Socket closed with code ${response}. Args:`, args);
});

server.listen(8080, () => {
    console.log(`Server started at ${new Date().toISOString()}`);
});
image

How to view the raw client requests?

I'm trying to intercept Get, Post requests made by the client and modify by them accordingly under my preference.

I try so hard to read your code but fail miserably.

I've put console.log in the Connect function to log the raw buffer but it seems that raw buffer only contain the Dest. domain name not the Body (Whatever it's).

I'm already started to burn down. Appreciate your help!

I could donate too.

Https doesn't work with the windows proxy settings

I am testing the library. It works well with firefox proxy setting ans some other browsers as well. But it doesn't open https pages in chrome and similar ones that works with windows internet options. I got ERR_PROXY_CONNECTION_FAILED on the client side and

socket closed with code 1
{ ver: 4, nmethods: 1, methods: <Buffer 08> } 

on the proxy side.
What could be the reason?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.