Struct makiko::Client

source ·
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

source

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 produces ClientEvents, which mostly correspond to actions initiated by the server. The only event that you need to handle is ClientEvent::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.
source

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 (inside AuthNoneResult::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.

source

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.

source

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.

source

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.

source

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.

source

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.

source

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 the SessionEvents 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.

source

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 as TunnelEvents. 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.

source

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.

source

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.

source

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 the ChannelEvents produced by the channel. You must receive these events in time, otherwise the client will stall.
  • The Bytes contain the channel specific data from the SSH_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.

source

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.

source

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.

source

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.

Trait Implementations§

source§

impl Clone for Client

source§

fn clone(&self) -> Client

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

§

impl !RefUnwindSafe for Client

§

impl Send for Client

§

impl Sync for Client

§

impl Unpin for Client

§

impl !UnwindSafe for Client

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> ToOwned for Twhere T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for Twhere V: MultiLane<T>,

§

fn vzip(self) -> V