theophilusx / ssh2-sftp-client

a client for SSH2 SFTP
Apache License 2.0
813 stars 200 forks source link

Is possibile to use proxy with sftp connection ? #39

Closed FaberNa closed 3 years ago

FaberNa commented 6 years ago

let Client = require('ssh2-sftp-client'); let sftp = new Client(); sftp.connect({ host: '127.0.0.1', port: '8080', username: 'username', password: '******' }).then(() => { return sftp.list('/pathname'); }).then((data) => { console.log(data, 'the data info'); }).catch((err) => { console.log(err, 'catch error'); });

I use this type of code but is there an option for setting proxy ?

jyu213 commented 6 years ago

@FaberNa ssh2-sftp-client can't support proxy at this time. ssh2 now only support SOCKSv5

FaberNa commented 6 years ago

It's possible to have an example where we upload a file with SOCKSv5 ?

jyu213 commented 6 years ago

@FaberNa sorry. ssh2-sftp-client module also can't support SOCKSv5

sandrooco commented 6 years ago

@FaberNa Did you find an alternate solution to this package that supports proxies?

alechirsch commented 5 years ago

@FaberNa @sandrooco I am also looking into a proxy solution, did either of you come up with something?

jmorino commented 5 years ago

I struggled a bit for having this module work behind a corporate proxy, trying with ssh2, socksv5 and some of its forks.

I finally got it working using the (very simple to use) socks module.

Here is my solution:

import { SocksClient } from 'socks';
import SFTPClient from 'ssh2-sftp-client';

const host = 'my-sftp-server.net';
const port = 22; // default SSH/SFTP port on remote server

// connect to SOCKS 5 proxy
const { socket } = await SocksClient.createConnection({
  proxy: {
    host: 'my.proxy', // proxy hostname
    port: 1080, // proxy port
    type: 5, // for SOCKS v5
  },
  command: 'connect',
  destination: { host, port } // the remote SFTP server
});

const client = new SFTPClient();
await client.connect({
  host,
  sock: socket, // pass the socket to proxy here (see ssh2 doc)
  username: '.....',
  privateKey: '.....'
});

// client is connected
amstrad commented 5 years ago

I struggled a bit for having this module work behind a corporate proxy, trying with ssh2, socksv5 and some of its forks.

I finally got it working using the (very simple to use) socks module.

Here is my solution:

import { SocksClient } from 'socks';
import SFTPClient from 'ssh2-sftp-client';

const host = 'my-sftp-server.net';
const port = 22; // default SSH/SFTP port on remote server

// connect to SOCKS 5 proxy
const socket = await SocksClient.createConnection({
  proxy: {
    host: 'my.proxy', // proxy hostname
    port: 1080, // proxy port
    type: 5, // for SOCKS v5
  },
  command: 'connect',
  destination: { host, port } // the remote SFTP server
});

const client = new SFTPClient();
await client.connect({
  host,
  sock: socket, // pass the socket to proxy here (see ssh2 doc)
  username: '.....',
  privateKey: '.....'
});

// client is connected

Hey, thanks for adding some light here. I can connect to the proxy but right after, when passing the sock param to the sftp i get " TypeError: sock.on is not a function". May i ask if you had this issue and how could be solved ?


const socketCon = await SocksClient.createConnection(options);
                console.log('SOCKET CONNECTED') //<- i get here fine

                const client = new SFTPClient();
                await client.connect({
                    sock: socketCon, // pass the socket to proxy here (see ssh2 doc)
                    host: '****',
                    port: ***,
                    username: '***',
                    password: '***',
                    algorithms: {
                        serverHostKey: ['ssh-rsa', 'ssh-dss', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521'],
                    },
                });```
jmorino commented 5 years ago

Hi @amstrad,

Sorry there was a typo in my snippet. The SocksClient.createConnection returns an object with a socket property, and not the socket itself directly.

So you should read

const { socket } = await SocksClient.createConnection(...)

instead of

const socket = await SocksClient.createConnection(...)

I also edited my previous answer.

amstrad commented 5 years ago

thanks @jmorino !, still not having luck but i might be missing something else.. i´ll get around this a bit more (i did tried object.socket and others props before, it seems the socket is an object? but docs state "sock - ReadableStream - A ReadableStream to use for communicating with the server instead of creating and using a new TCP connection (useful for connection hopping)." it´s a bit after me, as i´m relatively new to node.. i´ll report back i get it working.

amstrad commented 5 years ago

My bad, got this working using @jmorino solution, just dunno why but i need to pass the socket property in the object... my code is as follow:

const {socket} = await SocksClient.createConnection(options)
                console.log('SCOCKET CONNECTED. Connecting to SFTP...')
                const sftp_client = new SFTPClient();
                await sftp_client.connect({
                    host: '****',
                    sock: socket.socket,
                    port: 22, // Normal is 22 port
                    username: '***',
                    password: '***',
                    algorithms: {
                        serverHostKey: ['ssh-rsa', 'ssh-dss'],
                    },
                }).then(async () => {

                    console.log('SFTP CONNECTED!')

                }).catch((err) => {
                    console.log('error ' + err)

                });
rafipiccolo commented 4 years ago

Just to be clear. Here is a full exemple.

The situation : Server B is the only server allowed to connect to server C. I need to use server A to connect to C. Then i create a socks proxy on server B. which means A => B => C

First i need to create a socks proxy

root@A# ssh -D 1818 -q -C -N root@B

then i used this code

require('dotenv').config();
let SocksClient = require('socks').SocksClient;
let Client = require('ssh2-sftp-client');
let fs = require('fs');

(async () => {
    try {
        const host = 'C';
        const port = 22;

        // connect to SOCKS 5 proxy
        const { socket } = await SocksClient.createConnection({
            proxy: {
                host: 'B', // proxy hostname
                port: 1818, // proxy port
                type: 5, // for SOCKS v5
            },
            command: 'connect',
            destination: { host, port } // the remote SFTP server
        });

        const sftp = new Client();

        await sftp.connect({
            sock: socket,
            host: host,
            port: port,
            username: process.env.SSH_USERNAME,
            agent: process.env.SSH_AGENT,
            privateKey: fs.readFileSync(process.env.SSH_PRIVATE_KEY),
        })

        console.log('SFTP CONNECTED!')

        await sftp.end();
    } catch(err){
        console.error(err);
    }
})()

it works.

Can someone help me determine this :

theophilusx commented 4 years ago

I have never done this myself, but believe it is possible (there is an example in the FAQ section of the README).

You can probably find more information in the ssh2 repository - especially the issues section. The ssh2-sftp-client module is just a wrapper module around ssh2 and ssh2-streams which provides a promise based interface. You should be able to adjust any examples based on ssh2/ssh2-streams to work with ssh2-sftp-client without too many problems.

You could probably achieve the same thing using ssh tunnels, but you would need to setup the tunnel on server B, then connect to that tunnel from server A. Essentially, a 'poor mans' proxy. I would try getting the socks proxy working first as it is likely to be a more robust solution that would provide better security.

theophilusx commented 3 years ago

As using a SOCKS proxy appears to be possible just using available ssh2 functionality, I don't see any need to add anything to this module. Therefore, I am closing this issue.