Client
[C]
struct FlowSshC_Client {};
Creation
---------
FlowSshC_Client* __cdecl FlowSshC_Client_Create();
[C++]
class Client : public MainBase (.. public RefCountable, public NoCopy)
{
public:
Client();
..
}
[C#]
public class ClientBase : IDisposable, MainBase
{
public ClientBase();
..
}
// Client derives from ClientBase and implements additional methods that can help a simple FlowSshNet application, such
// as a PowerShell script, from having to define event handlers entirely. This makes FlowSshNet easier to use for scripting,
// and allows it to be used from PowerShell, which does not support implementing event handlers with return values.
public ref class Client : ClientBase
{
public Client();
..
}
Members
Creation, Destruction
- Create - Create a new client object.
- [C] AddRef - Increment reference count.
- [C] Release - Decrement reference count.
Initialization
- SetAppName - Application name and version.
- SetActCode - For use in deployed applications where Bitvise SSH Client might not be installed, provide an activation code using SetActCode to ensure that FlowSsh does not display an evaluation dialog. On computers with Bitvise SSH Client, use of FlowSsh is permitted under the same terms as the Client; in this case, there will be no evaluation dialog, and SetActCode does not have to be called.
Connection and User Authentication
- Connect - Connect to an SSH server.
- Disconnect - Disconnect.
- SetHost - The DNS name or IP address to which to connect.
- SetKeypair - Keypair for public-key authentication.
- SetObfuscation - Configure SSH protocol obfuscation.
- SetPassword - Password for password authentication.
- SetPort - Port to which to connect.
- SetUserName - Your user name.
Proxy Settings
- SetProxyHost - DNS name or IP of proxy server.
- SetProxyOptions - Resolve DNS names locally or let the proxy server do it?
- SetProxyPassword - Password used for the authentication.
- SetProxyPort - Port of proxy server.
- SetProxyType - Type of proxy server (socks, http).
- SetProxyUserName - User name for the authentication.
Algorithms
- SetCompressionAlgs - Enable zlib compression? Disabled by default.
- SetEncryptionAlgs - Specify encryption algorithms.
- SetHostKeyAlgs - Specify host authentication algorithms.
- SetKeyExchangeAlgs - Specify key exchange algorithms.
- SetMacAlgs - Specify MAC algorithms.
Options
- SetOptions - Enable or disable key re-exchange and keep-alive.
Port Forwarding
- AddForwarding - Add a port forwarding rule.
- CancelForwarding - Cancel a port forwarding rule.
- DisableProxyForwarding - Disable dynamic proxy forwarding.
- EnableProxyForwarding - Enable dynamic proxy forwarding using SOCKS v4/v5 or HTTP CONNECT.
- InviteForwardings - Enable server-configured forwardings (works only with Bitvise SSH Server).
[C] Handler Registration
- SetBannerHandler - Register a banner handler.
- SetDisconnectHandler - Register a disconnect handler.
- SetForwardingLogHandler - Register a port forwarding log handler.
- SetHostKeyHandler - Register a host-key handler. Mandatory.
- SetUserAuthHandler - Register a user-auth handler.
- SetVersionHandler - Register a server version string handler.
[C++/.NET] Overrides and Events
- OnBanner - Banner handler.
- OnDisconnect - Disconnect handler.
- OnForwardingLog - Port forwarding log handler.
- OnFurtherAuth - Further-auth handler.
- OnHostKey - Host-key handler. Mandatory to implement. [.NET] Alternatively use AcceptHostKey.
- OnPasswordChange - Password-change handler.
- OnSshVersion - Server version string handler.
[.NET] Disposing
- IsDisposed - Is the object disposed?
- Dispose - Release all resources used by the object. Also initiates a disconnect.
[.NET] Derived Client implementation
- ClearHostKeyState - Clear host key state.
- AcceptHostKey - Host key to accept.
- AcceptHostKeyBB - Adds a bubble-babble of a host key to accept.
- AcceptHostKeyMd5 - Adds an MD5 fingerprint of a host key to accept.
- AcceptHostKeySha256 - Adds a SHA-256 fingerprint of host key to accept.
- GetServerHostKey - Retrieves the host key sent by the server.
Remarks
The client interface enables you to establish a secure connection with an SSH server. Every connected client represents a single encrypted TCP connection with the server. Each connection can then host several channels that perform various SSH tasks. In FlowSshC, clients are represented by an opaque FlowSshC_Client structure. In FlowSshCpp/Net they are managed by the Client class. Handlers are called only for active clients. A client is said to be active if it is either connected or connecting.
Before you establish a connection you have to:
- Set an application name with [Client]SetAppName.
- Specify a host name or IP of your SSH server and (optionally) a port number.
- Specify a user name and (optionally) a password or a keypair which authenticates you to the server.
- Register/implement at least the OnHostKey handler. Without this handler server (host-key) verification fails and the connection is aborted.
- (optionally) Register/implement other handlers. Usually you will also have an OnBanner, OnPasswordChange, and an OnFurtherAuth handler (in [C] the last two are registered with SetUserAuthHandler).
- (optionally) Set proxy settings.
User Authentication. By default:
- Host and user name are empty strings, and port is set to 22.
- Password and keypair are NULL/null - not set.
- DNS names are resolved locally (ProxyOptions: resolveLocally = true).
Authentication procedure
- If neither a password nor a keypair is set, the 'none' authentication method will be attempted.
- If both password and keypair are set, 'public-key' authentication will be performed first.
- If a password is set and the 'password' authentication method either fails or is not available, then password through 'keyboard-interactive' will be attempted. Conditions for a successful password through 'keyboard-interactive' authentication are as follows:
- The kbdi-info request must contain exactly one prompt.
- One of the kbdi-info request strings must contain a case-insensitive "password" substring.
- If further authentication is required, the [Client]OnFurtherAuth handler (in [C] UserAuth) will be invoked. If this handler is not registered/implemented, or if it returns false, the client will disconnect with a user authentication failure.
- If a password change is requested during 'password' authentication, the [Client]OnPasswordChange (in [C] UserAuth) will be invoked. If this handler is not registered/implemented, if it returns false, or if the server rejects the new password, the original 'password' authentication attempt will fail.
Proxy Behavior. By default:
- The use of a proxy server is disabled (ProxyType = [ProxyType]None).
- The proxy host is an empty string and the proxy port is set to 1080.
- DNS names are resolved locally (ProxyOptions: resolveLocally = true), not by the proxy server.
SOCKSv4 supports DNS names starting with the SOCKSv4a extension. Therefore, if your SOCKSv4 proxy does not support the SOCKSv4a extension, DNS names must be resolved locally (the default). SOCKSv4 (including SOCKSv4a) does not support authentication.
Algorithms. By default:
- All key exchange algorithms are enabled and ordered by their declaration order.
- Both host-key algorithms are enabled and "ssh-rsa" takes precedence.
- All encryption algorithms except "none" are enabled and ordered by their declaration order.
- All MAC algorithms except "none" are enabled and ordered by their declaration order.
- Zlib compression is disabled while "none" is enabled. Note that compression may deteriorate transfer rates in modern high-bandwidth environments. Compression will be used only if both the client and server have enabled it.
Changing algorithm options has no effect on active clients past the initial key exchange. You will normally not need to alter any of these options. If you do, it should be only for a clear reason.
Port Forwarding. Forwarding instructions will fail immediately if the client is not connected or connecting, and if the client is connecting they will be delayed until the connect request completes.
Examples
The examples below demonstrate how to establish a connection with the server using FlowSshC, FlowSshCpp, and FlowSshNet, respectively. For the sake of simplicity only three basic handlers are implemented:
- A global error handler. It must always be registered before using the library.
- A host-key handler. When a connection with the server is being established, this handler authenticates the server.
- A progress handler which tracks the connection progress. It also tells us if the connection was established or not.
In a real world scenario you will mostly also implement the other available handlers (at least some of them).
While [Client]Connect returns immediately, without blocking, both the host-key and progress handler are called asynchronously and very likely after [Client]Connect itself returns. In these examples, OnHostKey verifies the public-key of the server to ensure we are connecting to the right server. It is our code inside this handler that decides if the connection should succeed or fail. The progress handler on the other side merely informs us about the progress of the connection being established, and about the final success or failure.
Connect to an SSH server with FlowSshC
C
#include <stdio.h>
#include "FlowSshC.h"
// OnError handler
void OnError(void* handlerData, unsigned int flags, wchar_t const* desc)
{
wprintf(L"Fatal error: %s\n", desc ? desc : L"<no error description>");
// For the sake of simplicity, no cleanup is performed here.
// The lack of cleanup may cause debugger to report memory leaks.
exit(1);
}
// OnHostKey handler - authenticates the server
bool OnHostKey(void* handlerData, FlowSshC_PublicKey* publicKey)
{
BSTR md5 = FlowSshC_PublicKey_GetMD5(publicKey);
BSTR bb = FlowSshC_PublicKey_GetBubbleBabble(publicKey);
wprintf(L"Received the following host key:\n"
L"MD5 Fingerprint: %s\n"
L"Bubble-Babble: %s\n",
md5, bb);
SysFreeString(md5);
SysFreeString(bb);
wprintf(L"Accept the key (yes/no)? ");
wchar_t input[10];
if (_getws_s(input, 9))
return _wcsicmp(input, L"yes") == 0;
else return false;
}
// OnProgressConnect handler
struct ProgressConnectData
{
bool m_connected;
HANDLE m_doneEvent;
};
void OnProgressConnect(void* handlerData, unsigned int taskState, unsigned int taskSpecificStep, wchar_t const* auxInfo)
{
ProgressConnectData* data = (ProgressConnectData*)handlerData;
if (taskState == FlowSshC_TaskState::Completed)
{
data->m_connected = true;
SetEvent(data->m_doneEvent);
}
else if (taskState == FlowSshC_TaskState::Failed)
{
data->m_connected = false;
SetEvent(data->m_doneEvent);
// We could also log the taskSpecificStep here.
// It contains a FlowSshC_ConnectStep enumeration.
}
}
// ConnectToServer
bool ConnectToServer(FlowSshC_Client* client, wchar_t const* host, int port, wchar_t const* userName, wchar_t const* userPwd)
{
ProgressConnectData data = { FALSE, CreateEvent(0, true, false, 0)};
FlowSshC_Client_SetHost(client, host);
FlowSshC_Client_SetPort(client, port);
FlowSshC_Client_SetUserName(client, userName);
FlowSshC_Client_SetPassword(client, userPwd);
FlowSshC_Client_SetHostKeyHandler(client, OnHostKey, 0);
FlowSshC_Client_Connect(client, OnProgressConnect, &data);
WaitForSingleObject(data.m_doneEvent, INFINITE);
CloseHandle(data.m_doneEvent);
return data.m_connected;
}
// wmain
int wmain(int argc, wchar_t const* argv[])
{
wchar_t const* appName = L"my-app 1.0";
wchar_t const* host = L"127.0.0.1";
unsigned int port = 22;
wchar_t const* userName = L"my-name";
wchar_t const* userPwd = L"my-pwd";
FlowSshC_Client* client = NULL;
FlowSshC_Initialize(OnError, 0);
// FlowSshC_SetActCode(L"Enter Your Activation Code Here");
client = FlowSshC_Client_Create();
FlowSshC_Client_SetAppName(client, appName);
if (ConnectToServer(client, host, port, userName, userPwd))
{
// client successfully connected so let's do something with it
// ..
}
FlowSshC_Client_Release(client);
FlowSshC_Shutdown();
}
Connect to an SSH server with FlowSshCpp
C++
#include <iostream>
#include "FlowSshCpp.h"
using namespace std;
using namespace FlowSshCpp;
// MyErrorHandler
class MyErrorHandler : public ErrorHandler
{
private:
// This object must be created on the heap.
~MyErrorHandler() {}
protected:
virtual void OnExceptionInHandler(bool fatal, wchar_t const* desc)
{
wcout << (fatal ? L"Error [fatal]: " : L"Error: ");
wcout << (desc ? desc : L"<no error description>") << endl;
// For the sake of simplicity, no cleanup is performed here.
// The lack of cleanup may cause debugger to report memory leaks.
exit(1);
}
};
// MyClient
class MyClient : public Client
{
private:
// This object must be created on the heap.
~MyClient() {}
protected:
// OnHostKey handler - authenticates the server
bool OnHostKey(RefPtr<PublicKey> publicKey)
{
wcout << L"Received the following host key:" << endl;
wcout << L" MD5 Fingerprint: " << publicKey->GetMD5() << endl;
wcout << L" Bubble-Babble: " << publicKey->GetBubbleBabble() << endl;
wcout << L"Accept the key (yes/no)? ";
std::wstring input;
wcin >> input;
if (input == L"yes")
return true;
// host key rejected
return false;
}
};
// wmain
int wmain(int argc, wchar_t const* argv[])
{
wchar_t const* appName = L"my-app 1.0";
wchar_t const* host = L"127.0.0.1";
unsigned int port = 22;
wchar_t const* userName = L"my-name";
wchar_t const* userPwd = L"my-pwd";
try
{
// Initialize FlowSsh and register an ErrorHandler for uncaught exceptions in user-defined handlers.
// Example: If there is an uncaught exception in MyClient::OnHostKey,
// then this is reported in MyErrorHandler::OnExceptionInHandler.
Initializer init(new MyErrorHandler());
// init.SetActCode(L"Enter Your Activation Code Here");
// create and connect client
RefPtr<MyClient> client(new MyClient);
client->SetAppName(appName);
client->SetHost(host);
client->SetPort(port);
client->SetUserName(userName);
client->SetPassword(userPwd);
RefPtr<ProgressEvent> progress(new ProgressEvent);
client->Connect(progress);
progress->WaitDone();
if (progress->Success())
{
// client successfully connected so let's do something with it
// ..
}
}
catch (Exception const& e)
{
wcout << e.What() << endl;
return 1;
}
return 0;
}
Connect to an SSH server with FlowSshNet
C#
using System;
using System.Text;
using Bitvise;
using Bitvise.FlowSshNet;
namespace SshSample
{
// MyClient
public class MyClient : Client
{
public MyClient()
{
this.OnHostKey += new HostKeyEventHandler(this.OnMyHostKey);
}
// OnHostKey handler - authenticates the server
private bool OnMyHostKey(object sender, PublicKey publicKey)
{
Console.WriteLine("Received the following host key:");
Console.WriteLine(" MD5 Fingerprint: {0}", publicKey.GetMD5());
Console.WriteLine(" Bubble-Babble: {0}", publicKey.GetBubbleBabble());
Console.Write("Accept the key (yes/no)? ");
string input = Console.ReadLine();
if (input == "yes")
return true;
return false; // host key rejected
}
}
class Program
{
static void OnUncaughtExceptionInEvent(object sender, bool fatal, System.Exception e)
{
Console.WriteLine((fatal ? "Error [fatal]: " : "Error: ") + e.ToString());
// For the sake of simplicity, no cleanup is performed here.
// The lack of cleanup may cause debugger to report memory leaks.
System.Environment.Exit(1);
}
static int Main(string[] args)
{
try
{
string appName = "my-app 1.0";
string host = "127.0.0.1";
uint port = 22;
string userName = "my-name";
string userPwd = "my-pwd";
// Register delegate for uncaught exceptions in user-defined events.
// Example: If there is an uncaught exception in MyClient.OnMyHostKey,
// then this is reported in OnUncaughtExceptionInEvent.
SshNet.OnExceptionInEvent += new ExceptionInEventEventHandler(OnUncaughtExceptionInEvent);
// SshNet.SetActCode("Enter Your Activation Code Here");
// create and connect client
MyClient client = new MyClient();
client.SetAppName(appName);
client.SetHost(host);
client.SetPort(port);
client.SetUserName(userName);
client.SetPassword(userPwd);
ProgressHandler progress = new ProgressHandler();
client.Connect(progress);
progress.WaitDone();
if (progress.Success)
{
// client successfully connected so let's do something with it
// ..
}
}
catch (System.Exception e) // inclusive Bitvise.FlowSshNet.Exception's
{
Console.WriteLine(e.Message);
return 1;
}
finally
{
SshNet.Shutdown();
}
return 0;
} // Main
} // Program
}