Skip to content

A Node.js socks5 server implementation enabling fine-grained connection control.

License

Notifications You must be signed in to change notification settings

PondWader/node-socks5-server

Repository files navigation

node-socks5-server

A Node.js implementation of a socks5 server written in TypeScript.
The library handles the protocol side but allows you to gain fine-grained control of connections and how they're handled.

Features:

  • Override the handling of socket proxying
  • Handle authentication yourself
  • Full type support
  • Process Duplex streams as connections

Installation

With npm:

npm i @pondwader/socks5-server

With yarn:

yarn add @pondwader/socks5-server

Basic usage

Spin up a basic socks5 proxy server with just this code:

const { createServer } = require('@pondwader/socks5-server');

createServer({
    port: 5000
})

Or handle the listening yourself:

const { createServer } = require('@pondwader/socks5-server');

const server = createServer();
server.listen(5000, '127.0.0.1', () => {
    console.log('Server listening on port 5000');
})

Username-password authentication

const { createServer } = require('@pondwader/socks5-server');

createServer({
    port: 5000,
    auth: {
        username: 'user123',
        password: 'password123'
    }
})

Or handle the authentication yourself:

const { createServer } = require('@pondwader/socks5-server');

const server = createServer({
    port: 5000
})

// Using a synchronous function
server.setAuthHandler((conn) => {
    return conn.username === 'user123' && conn.password === 'password123';
})

// Using a promise
server.setAuthHandler((conn) => {
    return new Promise(resolve => {
        resolve(conn.username === 'user123' && conn.password === 'password123');
    })
})

// Using callbacks
server.setAuthHandler((conn, accept, reject) => {
    if (conn.username === 'user123' && conn.password === 'password123') accept();
    else reject();
})

Rejecting connections for breaking ruleset

You can reject connections that beak your ruleset:

const { createServer } = require('@pondwader/socks5-server');

const server = createServer({
    port: 5000
})

// Using a synchronous return
server.setRulesetValidator((conn) => {
    return conn.destPort !== 25;
});

// Using a promise
server.setRulesetValidator((conn) => {
    return new Promise(resolve => {
        resolve(conn.destPort !== 25);
    })
});

// Using callbacks
server.setRulesetValidator((conn, accept, deny) => {
    if (conn.destPort === 25) deny();
    else accept();
});

You also have to access to <Socks5Connection>.destAddress.

Handling the proxying of connections

By default the library will handle connections itself using the built in connection handler, but you can override this to use your own handler.
See the built in connection handling function here to further your understanding on how to handle connections.
You can set your handling function:

const { createServer } = require('@pondwader/socks5-server');

const server = createServer({
    port: 5000
})

server.setConnectionHandler((conn, sendStatus) => {
    const { socket, destAddress, destPort } = conn;

    /*
        You need to send a status before the client should start sending data in the socket.
        If you send REQUEST_GRANTED the client should begin sending data, any other status will close the socket.

        REQUEST_GRANTED,
        GENERAL_FAILURE,
        CONNECTION_NOT_ALLOWED,
        NETWORK_UNREACHABLE,
        HOST_UNREACHABLE,
        CONNECTION_REFUSED,
        TTL_EXPIRED,
        COMMAND_NOT_SUPPORTED
    */

    // Do stuff here
})

Handling commands other than connect

The library only has a built in handler for connections using the connect command, this is used for TCP socket proxying and is by far the most common command however, you may wish to add support for other commands.
The other command types are udp and bind. To handle these you will need to make your own connection handler (see section above). Note: the Socks5Connection class exposes the command property which gives you access to the command sent by the client.
You will also need to add the commands you want to handle to the supported commands set. The Socks5Server class has the supportedCommands property which is a Set instance.
For example: <Socks5Server>.supportedCommands.add('udp');

You can also pass Duplex streams as connections...

const { Duplex } = require('streams');
server._handleConnection(new Duplex());

Metadata

The Socks5Connection class has a metadata attribute which starts as an empty object, you can put data in this to pass data about a connection between seperate handlers.

About

A Node.js socks5 server implementation enabling fine-grained connection control.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published