mscdex / socksv5

SOCKS protocol version 5 server and client implementations for node.js
MIT License
400 stars 121 forks source link

Node.js socks5 proxy with forwarding for SOAP requests #43

Open scorsi opened 5 years ago

scorsi commented 5 years ago

Hello,

I am trying to reproduce this ssh command with node.js : ssh -D 1080 -N user@host -I key.pem, to use this tunnel to execute SOAP requests.

My node.js implementation of SOAP API using port 1080 is as follow (and works with the ssh command launched) :

const
    Agent = require('socks5-https-client/lib/Agent'),
    request = require('request'),
    soap = require('strong-soap').soap,
    url = 'https://example.com/wsdl'; //path to wsdl

soap.createClient(url, {
    request: request.defaults({
        agentClass: Agent,
        agentOptions: {
            socksPort: 1080
        }
    })
}, function (err, client) {
    if (err) console.log(err)
    let description = client.describe()

    console.log(JSON.stringify(description.ExampleService.ExamplePort.example_method))

    client['example_method']({ /* PAYLOAD */ }, function (err, result, envelope, soapHeader) {
        if (err) console.log(err)
        else console.log(JSON.stringify(result))
    })
})

And everything works as expected like this, whether client.describe() and client.example_method().

The issue comes when trying to create the socks proxy with node. Full (censored) code below :

const Agent = require('socks5-https-client/lib/Agent');
const Server = require('socksv5/lib/server').Server;
const socksAuth = require('socksv5/lib/auth/None');
const Client = require('ssh2').Client;
const soap = require('strong-soap').soap;
const request = require('request');
const fs = require('fs');

const config = {
    localProxy: {
        host: 'localhost',
        port: 1080
    }
};

const conn = new Client();
const server = new Server((info, accept, deny) => {
    conn.on('ready', () => {
        conn.forwardOut(
            info.srcAddr, info.srcPort,
            info.dstAddr, info.dstPort,
            (err, stream) => {
                if (err) {
                    conn.end();
                    return deny();
                }

                const clientSocket = accept(true);
                if (clientSocket) {
                    stream.pipe(clientSocket).pipe(stream).on('close', () => {
                        conn.end();
                    });
                } else {
                    conn.end();
                }
            })
    }).on('error', () => {
        deny()
    }).connect({
        host: 'sshhostname',
        port: 22,
        username: 'sshusername',
        privateKey: fs.readFileSync('./sshkey.pem'),
        debug: (s) => console.info(s)
    });
}).listen(config.localProxy.port, config.localProxy.host, () => {
    const stop = (err) => {
        if (err) console.error(err);
        conn.end();
        server.close();
    };
    try {
        soap.createClient(
            'https://somesoaphost/wsdl', {
                request: request.defaults({
                    agentClass: Agent,
                    agentOptions: {
                        socksHost: config.localProxy.host,
                        socksPort: config.localProxy.port
                    }
                })
            }, (err, client) => {
                if (err) {
                    stop(err);
                    return;
                }

                client['example_method']({
                    // Some payload
                }, (err, result) => {
                    if (err) stop(err);
                    else console.log(JSON.stringify(result));
                });
            });
    } catch (e) {
        stop(e);
    } finally {
    }
}).useAuth(socksAuth());

The description of the method example_method is well printed, so I'm sure the tunneling works (because methods can't work without it, as there is an IP restriction which accept only requests from the host server). The error comes when calling client.example_method(). The output is :

Error: SOCKS connection failed. Connection not allowed by ruleset.
    at Socket.<anonymous> (xxxxx/node_modules/socks5-client/lib/Socket.js:246:25)
    at Object.onceWrapper (events.js:285:13)
    at Socket.emit (events.js:197:13)
    at addChunk (_stream_readable.js:288:12)
    at readableAddChunk (_stream_readable.js:269:11)
    at Socket.Readable.push (_stream_readable.js:224:10)
    at TCP.onStreamRead (internal/stream_base_commons.js:145:17)

Any idea of what is missing ? Thanks !