Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Attempt to use an SSH tunnel to connect to MySQL on a remote host
<?php
/***
Based off code from:
https://www.experts-exchange.com/questions/26619790/Connect-to-Mysql-through-PHP-ssh2-tunnel.html
Example usage: User/Pass Based Auth MySQL Proxy
-----------------------------------------------
$user_pass_config = array(
'user' => 'username',
'pass' => 'password',
'host' => 'myserver.com',
'port' => 22
);
$local_proxy_port = 3307;
$remote_proxy_host = '127.0.0.1';
$remote_proxy_port = 3306;
$tunnel = new Tunnel();
$tunnel->set_config( $user_pass_config );
$tunnel->proxy( $local_proxy_port, $remote_proxy_host, $remote_proxy_port );
// We now have a tcp server on 127.0.0.1 port 3307 which is proxying, over ssh, to 127.0.0.1 port 3306 on myserver.com
**/
class Tunnel {
public $host = NULL; // SSH Host
public $port = 22; // SSH Port
public $user = NULL; // Username
public $pass = NULL; // User Password
private $conn = NULL; // Resource: SSH2 connection
private $tunnel = NULL; // Resource: SSH2 tunnel
private $socket = NULL; // Local socket
private $debug_array = []; // Debug messages
// -----------------------------------------------------------------------
public function __construct(){ return $this; }
// -----------------------------------------------------------------------
public function set_config( $args = [] )
{
foreach( $args as $k => $v )
$this->$k = $v;
return $this;
}
// -----------------------------------------------------------------------
public function proxy( $local_port, $remote_host, $remote_port )
{
if( ! $this->_connect_to_remote_server( $remote_host, $remote_port ) )
return FALSE;
if( ! $this->_create_local_socket( $local_port ) )
return FALSE;
$conn = @stream_socket_accept( $this->socket, 180 );
stream_set_blocking( $conn, FALSE );
while( ! feof($conn) && ! feof($this->socket) )
{
// Read from server to client
if ( strlen( $data = @fread( $this->tunnel, 4096 ) ) ) {
if ( FALSE === fwrite( $conn, $data ) )
break;
} else if ( strlen( $data = @fread( $conn, 4096 ) ) ) {
if ( FALSE === fwrite( $this->tunnel, $data ) )
break;
} else {
usleep( 5000 );
}
}
@fclose( $conn );
@fclose( $this->tunnel );
return TRUE;
}
// -----------------------------------------------------------------------
private function _connect_to_remote_server( $remote_host, $remote_port )
{
if( ! $this->_connect() ) return FALSE;
if( $this->tunnel )
return TRUE;
$this->tunnel = fopen("ssh2.tunnel://$this->conn/$remote_host:$remote_port", 'r+');
if( ! $this->tunnel OR ! is_resource( $this->tunnel ) )
{
$this->debug_array[] = "Failed Initializing Tunnel To $remote_host:$remote_port";
return FALSE;
}
$this->debug_array[] = "Tunnel To $remote_host:$remote_port Initialized";
stream_set_blocking( $this->tunnel, FALSE );
return TRUE;
}
// -----------------------------------------------------------------------
private function _connect()
{
if( $this->conn )
return $this->conn;
if( ! $this->host OR ! $this->port OR ! $this->user OR ! $this->pass )
return FALSE;
$this->conn = ssh2_connect( $this->host, $this->port );
if( ! $this->conn )
{
$this->conn = NULL;
$this->debug_array[] = "Could not connect to $this->host:$this->port";
return FALSE;
}
$this->debug_array[] = "Connected to $this->host:$this->port";
$auth = ssh2_auth_password( $this->conn, $this->user, $this->pass );
if( ! $auth )
{
$this->conn = NULL;
$this->debug_array[] = "Could not authenticate for user $this->user";
return FALSE;
}
$this->debug_array[] = "Logged in as $this->user";
return TRUE;
}
// -----------------------------------------------------------------------
private function _create_local_socket( $port )
{
$this->socket = stream_socket_server( "tcp://127.0.0.1:$port", $errno, $errstr );
if( ! $this->socket )
{
$this->debug_array[] = "Failed creating socket server: $errstr ($errno)";
return FALSE;
}
return TRUE;
}
// -----------------------------------------------------------------------
public function halt()
{
$this->conn = NULL;
@fclose( $this->tunnel );
die('<pre>' . print_r( $this->debug_array, TRUE ) . '</pre>');
}
// -----------------------------------------------------------------------
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment