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