phpcurlproxyphpseclibfsockopen

PHP - Connect to sftp from private key through socks5 proxy


I'm trying to connect to sftp with rsa private key auth, through proxy.

use phpseclib\Net\SFTP;
use phpseclib\Crypt\RSA;

$proxyHost = 'proxy-host';
$proxyPort = 1080;
$fsock = fsockopen($proxyHost, $proxyPort);

$host = 'sftp.hostname.com';
$login = 'sftp_login';
$privatekey = file_get_contents('sftp_private.ppk');
$password = new RSA();
$password->loadKey($privatekey);
$request = "CONNECT $host:22 HTTP/1.0\r\nContent-Length: 0\r\n\r\n";

if(fputs($fsock, $request) != strlen($request)) {
  exit("premature termination");
}
while ($line = fgets($fsock, 1024)) {
    if ($line == "\r\n") {
      break;
    }
    //echo $line;
}
$sftp = new SFTP($fsock);
if (!$sftp->login($login, $password)) {
  exit('Login Failed');
}

I get the "Login Failed" exit.

Thanks


Solution

  • Quoting https://github.com/phpseclib/phpseclib/issues/1460 :

    Port 1080 is typically used for SOCKS5 proxies - not HTTP proxies.

    Assuming you're using a SOCKS5 proxy then something like this should work:

    // SSH connection info
    $port = 22;
    $address = 'localhost';
    
    // SOCKS5 connection info
    $fsock = fsockopen('127.0.0.1', 1080, $errno, $errstr, 1);
    if (!$fsock) {
        throw new \Exception($errstr);
    }
    
    $port = pack('n', $port);
    $address = chr(strlen($address)) . $address;
    
    $request = "\5\1\0";
    if (fwrite($fsock, $request) != strlen($request)) {
        throw new \Exception('Premature termination');
    }
    
    $response = fread($fsock, 2);
    if ($response != "\5\0") {
        throw new \Exception('Unsupported protocol or unsupported method');
    }
    
    $request = "\5\1\0\3$address$port";
    if (fwrite($fsock, $request) != strlen($request)) {
        throw new \Exception('Premature termination');
    }
    
    $response = fread($fsock, strlen($address) + 6);
    if (substr($response, 0, 2) != "\5\0") {
    echo bin2hex($response) . "\n";
        throw new \Exception("Unsupported protocol or connection refused");
    }
    
    $ssh = new SSH2($fsock);
    $ssh->login('username', 'password');
    echo $ssh->exec('ls -latr');
    

    That said, SOCKS5 has a lot more bells and whistles then this sample code currently accommodates. Really, what'd be good is a full on SOCKS5 class.

    Hope it will help someone else.