Closed neronmoon closed 5 months ago
Hello Vitaliy 👋
I don't have much exprience with PHP, but I've just tried using the port forwarding endpoint from Python, and it is indeed somewhat painful: both of the Python libraries for SSH I've tried (Paramiko and AsyncSSH) expect a real socket.socket
to be handed to them, on which they call things like settimeout(...)
and setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
.
In Golang however, this is way easier because of a well-defined net.Conn
inteface. We actually just use a result of NetConn()
method provided by the [nhooyr.io/websocket
package]() to instantiate the SSH client, which powers our orchard ssh vm
command:
This got me thinking that we should expose a more convenient method for running commands inside of a VM, something like a /v1/vms/{name}/exec
method that would accept commands as an input and return stdout/stderr. Would that work for what you're trying to achieve?
Thank you for answering, Nikolay!
v1/vms/{name}/exec
endpoint looks promising at first sight.
But i think that will fail in case that i would execute some very-long running script.
For example: connection can be dropped by any middleware server by timeout.
Of course, that problem could be easely solved by foregrounding script process and reading stdout/stderr in bunch of repeating read-logs-if-exist
scripts., but it smells badly. I really don't like make unnecessary http requests
Ok, i came to some point. I'm using folloginw libraries:
I have wrapper around php socket
<?php
namespace App\Services;
use WSSC\Components\ClientConfig;
use WSSC\Contracts\CommonsContract;
use WSSC\WebSocketClient;
class WebsocketStreamWrapper
{
private WebSocketClient $client;
public function stream_open($url, $options, $test, $test1)
{
$config = new ClientConfig();
$config->setHeaders([
'User-Agent' => 'Orchard/v2.0.0',
]);
$this->client = new WebSocketClient($url, $config);
return $this->client->isConnected();
}
public function stream_write($data)
{
$this->client->send($data, CommonsContract::EVENT_TYPE_BINARY);
return strlen($data);
}
public function stream_read()
{
return $this->client->receive();
}
public function stream_eof()
{
return feof($this->client->socket);
}
public function stream_cast($cast_as)
{
return $this->client->socket ?: false;
}
public function stream_stat()
{
return stream_get_meta_data($this->client->socket);
}
}
And using following code to connect:
stream_wrapper_register("ws", WebsocketStreamWrapper::class);
$socket = fopen("ws://<orchard ip>:6120/v1/vms/test/port-forward?port=22&wait=60", "w+b");
$ssh = new SSH2($socket);
define('NET_SSH2_LOGGING', 3);
$ssh = new SSH2($socket);
$ssh->login('admin', 'admin');
Looks like eather websocket server or ssh server hands on handshake process. Here is some logs:
<-
00000000 53:53:48:2d:32:2e:30:2d:4f:70:65:6e:53:53:48:5f SSH-2.0-OpenSSH_
00000010 39:2e:33:0d:0a 9.3..
->
00000000 53:53:48:2d:32:2e:30:2d:70:68:70:73:65:63:6c:69 SSH-2.0-phpsecli
00000010 62:5f:33:2e:30:20:28:6c:69:62:73:6f:64:69:75:6d b_3.0 (libsodium
00000020 2c:20:6f:70:65:6e:73:73:6c:29:0d:0a , openssl)..
-> NET_SSH2_MSG_KEXINIT (since last: 0.0812, network: 0.0005s)
00000000 6a:40:04:29:0f:eb:bc:7a:f5:46:38:6e:47:78:06:b4 j@.)...z.F8nGx..
00000010 00:00:01:87:63:75:72:76:65:32:35:35:31:39:2d:73 ....curve25519-s
[DELETED]
00000630 00:1a:6e:6f:6e:65:2c:7a:6c:69:62:40:6f:70:65:6e ..none,zlib@open
00000640 73:73:68:2e:63:6f:6d:2c:7a:6c:69:62:00:00:00:00 ssh.com,zlib....
00000650 00:00:00:00:00:00:00:00:00 .........
<- NET_SSH2_MSG_KEXINIT (since last: 0.003, network: 0.0001s)
00000000 93:bb:43:74:8d:8b:4c:66:fb:29:d5:eb:b8:53:a4:03 ..Ct..Lf.)...S..
00000010 00:00:01:09:73:6e:74:72:75:70:37:36:31:78:32:35 ....sntrup761x25
00000020 35:31:39:2d:73:68:61:35:31:32:40:6f:70:65:6e:73 519-sha512@opens
00000030 73:68:2e:63:6f:6d:2c:63:75:72:76:65:32:35:35:31 sh.com,curve2551
[DELETED]
00000420 00:00:00:00:00:00:00:00:00:00:00 ...........
-> NET_SSH2_MSG_KEXDH_INIT (since last: 0.0815, network: 0.0001s)
00000000 00:00:00:20:7e:ba:a3:8a:b0:ca:8a:60:64:ee:26:d0 ... ~......`d.&.
00000010 c9:fb:83:8f:c3:23:5f:ef:81:e7:67:a2:8f:7c:8d:a6 .....#_...g..|..
00000020 a1:98:19:52 ...R
<- NET_SSH2_MSG_KEXDH_REPLY (since last: 0.0078, network: 0.0077s)
00000000 00:00:00:33:00:00:00:0b:73:73:68:2d:65:64:32:35 ...3....ssh-ed25
[DELETED]
000000b0 d9:0d ..
-> NET_SSH2_MSG_NEWKEYS (since last: 0.0013, network: 0.0001s)
Hangs here, and then throws exception because of timeout
I've also tested phpseclib's connection on my ubuntu box and it works just fine. Without websocket wrapping, of course
Hey @neronmoon, will it be a one off long running script that you know before starting a VM? If so, you can consider adding a startup script for the VM and then checking for log events.
Alternatively we can also consider adding a new API to submit a script for execution on a VM, logs of which will be streamed to events.
Closing because of no reply.
Hello!
I'm struggling to make ssh connection via websocket using php/python. Could you please provide some hints/documentation/example how to do it?