pub struct Client { /* private fields */ }
Expand description
Handle to an SSH connection.
Use this object to send requests to the SSH server. In tandem, you will also need to use
ClientReceiver
to handle events that we receive from the server, and ClientFuture
to
perform the actual I/O.
To open a connection, pass your I/O stream (such as tokio::net::TcpStream
) to
Client::open()
and perform authentication using one of the auth_*
methods. Once
you are authenticated, you can open a Session
and execute a program. You can also open
multiple sessions from a single connection.
At the same time, you must handle events from the ClientReceiver
and poll the
ClientFuture
(probably from a different task).
You can cheaply clone this object and safely share the clones between tasks.
Implementations§
source§impl Client
impl Client
sourcepub fn open<IO>(
stream: IO,
config: ClientConfig
) -> Result<(Client, ClientReceiver, ClientFuture<IO>)>where
IO: AsyncRead + AsyncWrite,
pub fn open<IO>( stream: IO, config: ClientConfig ) -> Result<(Client, ClientReceiver, ClientFuture<IO>)>where IO: AsyncRead + AsyncWrite,
Create an SSH connection from an existing stream.
We initialize the client, but do not perform any I/O in this method. You should use the returned objects as follows:
Client
allows you to interact with the SSH client. You should use it to authenticate yourself to the server and then you can open channels or sessions.ClientReceiver
is the receiving half of the client. It producesClientEvent
s, which mostly correspond to actions initiated by the server. The only event that you need to handle isClientEvent::ServerPubkey
. However, you must receive these events in a timely manner, otherwise the client will stall.ClientFuture
is a future that you must poll to drive the connection state machine forward. You will usually spawn a task for this future.
sourcepub async fn auth_none(&self, username: String) -> Result<AuthNoneResult>
pub async fn auth_none(&self, username: String) -> Result<AuthNoneResult>
Try to authenticate using the “none” method.
The “none” method (RFC 4252, section 5.2) is useful in two situations:
- The user can be “authorized” without any authorization, e.g. if the user has a blank password. Note that most SSH servers disable blank passwords by default.
- You want to determine the list of authentication methods for this user, so you expect to
get an
AuthFailure
(insideAuthNoneResult::Failure
) and look at the list of methods that can continue.
If a previous authentication attempt was successful, this call immediately succeeds. If you
start another authentication attempt before this attempt is resolved, it will fail with
Error::AuthPending
.
sourcepub async fn auth_password(
&self,
username: String,
password: String
) -> Result<AuthPasswordResult>
pub async fn auth_password( &self, username: String, password: String ) -> Result<AuthPasswordResult>
Try to authenticate using the “password” method.
Technically, the “password” method (RFC 4252, section 8) allows you to change the password during authentication, but nobody seems to implement it (neither servers nor client), so we don’t support that.
If a previous authentication attempt was successful, this call immediately succeeds. If you
start another authentication attempt before this attempt is resolved, it will fail with
Error::AuthPending
.
sourcepub async fn auth_pubkey(
&self,
username: String,
privkey: Privkey,
pubkey_algo: &'static PubkeyAlgo
) -> Result<AuthPubkeyResult>
pub async fn auth_pubkey( &self, username: String, privkey: Privkey, pubkey_algo: &'static PubkeyAlgo ) -> Result<AuthPubkeyResult>
Try to authenticate using the “publickey” method.
With the “publickey” method (RFC 4252, section 7), the server knows your public key and you prove that you own the corresponding private key.
You must specify the private key privkey
and also pubkey_algo
, the pubkey algorithm
that is used to prove that you own the private key (see Pubkey::algos_secure()
and
Pubkey::algos_compatible_less_secure()
). If you supply pubkey_algo
that is not
compatible with the privkey
, you will get an Error::PrivkeyFormat
.
If a previous authentication attempt was successful, this call immediately succeeds. If you
start another authentication attempt before this attempt is resolved, it will fail with
Error::AuthPending
.
sourcepub async fn check_pubkey(
&self,
username: String,
pubkey: &Pubkey,
pubkey_algo: &'static PubkeyAlgo
) -> Result<bool>
pub async fn check_pubkey( &self, username: String, pubkey: &Pubkey, pubkey_algo: &'static PubkeyAlgo ) -> Result<bool>
Check whether “publickey” authentication method would be acceptable.
Before attempting the “publickey” authentication method using
auth_pubkey()
, you may ask the server whether authentication using
the given username
, pubkey
and pubkey_algo
would be acceptable.
sourcepub fn auth_pubkey_algo_names(&self) -> Result<Option<Vec<String>>>
pub fn auth_pubkey_algo_names(&self) -> Result<Option<Vec<String>>>
Get the public key algorithms that the server supports for authentication.
Returns a list of public key algorithm names that the server claims to support for
“publickey” authentication (see Self::auth_pubkey()
). For example, you can use this
information to select which algorithm to use in case of a
RsaPrivkey
, which supports multiple algorithms.
The server sends this information using the SSH extension packet (RFC 8308, section
3.1). If we haven’t received this packet, this method returns None
. Unfortunately, before
you start authenticating, None
might mean that the server sent the packet, but we
simply haven’t received it yet. We suggest that you call Self::auth_none()
and then
call this method: in this case you can be sure that if the server supports this extension,
this method returns Some
.
sourcepub fn is_authenticated(&self) -> Result<bool>
pub fn is_authenticated(&self) -> Result<bool>
Return true if the server has authenticated you.
You must use one of the auth_*
methods to authenticate.
sourcepub async fn open_session(
&self,
config: ChannelConfig
) -> Result<(Session, SessionReceiver)>
pub async fn open_session( &self, config: ChannelConfig ) -> Result<(Session, SessionReceiver)>
Open an SSH session to execute a program or the shell.
If the session is opened successfully, you receive two objects:
Session
is the handle for interacting with the session and sending data to the server.SessionReceiver
receives theSessionEvent
s produced by the session. You must receive these events in time, otherwise the client will stall.
You can open many sessions in parallel, the SSH protocol will multiplex the sessions over the underlying connection under the hood.
This method will wait until you are authenticated before doing anything.
sourcepub async fn connect_tunnel(
&self,
config: ChannelConfig,
connect_addr: (String, u16),
originator_addr: (String, u16)
) -> Result<(Tunnel, TunnelReceiver)>
pub async fn connect_tunnel( &self, config: ChannelConfig, connect_addr: (String, u16), originator_addr: (String, u16) ) -> Result<(Tunnel, TunnelReceiver)>
Open a tunnel by asking the server to connect to a host (“local forwarding”).
If the server accepts the request, it will try to connect to a host and port determined by
connect_addr
. The host may be either an IP address or a domain name. You should also
specify the originator_addr
, which should be the IP address and port of the machine from
where the connection request originates.
If the tunnel is opened successfully, you receive two objects:
Tunnel
is the handle for sending data to the server.TunnelReceiver
receives the data from the server asTunnelEvent
s. You must receive these events in time, otherwise the client will stall.
You can open many tunnels or sessions in parallel, the SSH protocol will multiplex them over the underlying connection.
This method will wait until you are authenticated before doing anything.
sourcepub fn bind_tunnel(
&self,
bind_addr: (String, u16)
) -> Result<ClientResp<Option<u16>>>
pub fn bind_tunnel( &self, bind_addr: (String, u16) ) -> Result<ClientResp<Option<u16>>>
Start listening for connections on the server and tunnels them to us (“remote forwarding”).
If the server accepts the request, it will try to bind to the host and port determined by
bind_addr
. The host might be an IP address, "localhost"
(listen on loopback addresses)
or ""
(listen on all addresses). The port might be 0, in which case the server assigns a
free port and returns it in the response. Note that by default, most SSH servers will allow
you to bind only to the loopback (localhost) address.
Once somebody connects to the server on the bound address, you will receive
ClientEvent::Tunnel
from the ClientReceiver
, and you
then may accept the tunnel.
The server responds with the bound port if you specified port 0.
This method will wait until you are authenticated before doing anything.
sourcepub fn unbind_tunnel(&self, bind_addr: (String, u16)) -> Result<ClientResp<()>>
pub fn unbind_tunnel(&self, bind_addr: (String, u16)) -> Result<ClientResp<()>>
Stop listening for connections on the server.
This cancels the remote forwarding set up by bind_tunnel()
.
This method will wait until you are authenticated before doing anything.
sourcepub async fn open_channel(
&self,
channel_type: String,
config: ChannelConfig,
open_payload: Bytes
) -> Result<(Channel, ChannelReceiver, Bytes)>
pub async fn open_channel( &self, channel_type: String, config: ChannelConfig, open_payload: Bytes ) -> Result<(Channel, ChannelReceiver, Bytes)>
Open a raw SSH channel (low level API).
Use this to directly open an SSH channel, as described in RFC 4254, section 5.
The bytes in open_payload
will be appended to the SSH_MSG_CHANNEL_OPEN
packet as the
“channel specific data”.
If the channel is opened successfully, you receive three objects:
Channel
is the handle for interacting with the channel and sending data to the server.ChannelReceiver
receives theChannelEvent
s produced by the channel. You must receive these events in time, otherwise the client will stall.- The
Bytes
contain the channel specific data from theSSH_MSG_CHANNEL_OPEN_CONFIRMATION
packet.
You should use this method only if you really know what you are doing. To execute programs,
please use open_session()
and Session
, which wrap the
Channel
in an API that hides the details of the SSH protocol.
This method will wait until you are authenticated before doing anything.
sourcepub fn send_request(&self, req: GlobalReq) -> Result<()>
pub fn send_request(&self, req: GlobalReq) -> Result<()>
Send a global request (low level API).
This sends SSH_MSG_GLOBAL_REQUEST
to the server (RFC 4254, section 4). We simply enqueue
the request and immediately return without any blocking, but you may use
GlobalReq::reply_tx
to wait for the reply.
The request will not be sent until you are authenticated.
sourcepub async fn rekey(&self) -> Result<()>
pub async fn rekey(&self) -> Result<()>
Trigger key exchange (rekeying).
Starts a key re-exchange (RFC 4253, section 9). Normally, we trigger the re-exchange
automatically as needed (see ClientConfig::rekey_after_bytes
and
ClientConfig::rekey_after_duration
), but you can use this method to start the exchange
earlier.
This method returns when the key exchange completes. If an exchange is already in progress, we simply wait for it to complete, we don’t trigger another one.
Note that according to the SSH specification, you should not trigger a key re-exchange
before the authentication is complete. Some servers tolerate it, but others reject the
exchange (OpenSSH) or disconnect (tinyssh). If the server rejects the request, you will get
Error::RekeyRejected
.
sourcepub fn disconnect(&self, error: DisconnectError) -> Result<()>
pub fn disconnect(&self, error: DisconnectError) -> Result<()>
Disconnect from the server and close the client.
We send a disconnection message to the server, so that they can be sure that we intended to
close the connection (i.e., it was not closed by a man-in-the-middle attacker). After
this message is sent, the ClientFuture
returns.
The error
describes the reasons for the disconnection to the server. You may want to use
DisconnectError::by_app()
as a reasonable default value.