libssh2_delphiを使ってSSHトンネル(SSHポートフォワーディング) ~Delphiでお手軽プログラミング

libssh2_delphiを使ってSSHトンネル(SSHポートフォワーディング) ~Delphiでお手軽プログラミング

Ssh-Pascal-master.zipのダウンロード

https://github.com/pyscripter/Ssh-Pascal
(Code⇒Download ZIPでダウンロードできます)
からSsh-Pascal-master.zipをダウンロードし解凍します。

プロジェクトとフォームの作成

Delphi IDEを起動し、「ファイル」⇒「Windows VCLアプリケーション -Delphi」をクリックします
フォーム上にTPanel(Name:TPanel1,Align:alTop)×1個、
TButton(Caption:接続,Name:BConnect)×1個、
TButton(Caption:切断,Name:BDisConnect)×1個をドラッグ&ドロップします。
Panel1にTLabel×10個(Captionプロパティは以下画像を参照)と、
TEdit(Name:E_LPort,NumbersOnly:True,Text:3333)、
TEdit(Name:E_MHost)、
TEdit(Name:E_MPort,NumbersOnly:True,Text:22)、
TEdit(name:E_MUser)、
TEdit(name:E_MPass)、
TEdit(Name:E_RHost)、
TEdit(Name:E_RPort,NumbersOnly:True,Text:3306)・・・MySQLの場合
を配置します。

プロジェクトとユニットの保存

「すべて保存」ボタンを押してユニットとプロジェクトを保存します。
プロジェクトを保存したディレクトリに
「\Ssh-Pascal-master\Source\libssh2.pas」 「\Ssh-Pascal-master\Source\libssh2_publickey.pas」 「\Ssh-Pascal-master\Source\libssh2_sftp.pas」 「\Ssh-Pascal-master\Source\SftpClient.pas」 「\Ssh-Pascal-master\Source\SocketUtils.pas」 「\Ssh-Pascal-master\Source\Ssh2Client.pas」 「\Ssh-Pascal-master\Source\SshTunnel.pas」
をコピーします。

一度コンパイルする

「プロジェクト」⇒「すべてのプロジェクトをコンパイル」を押して、一度コンパイルしておく。(フォルダが作成される)
プロジェクトを保存したディレクトリ内の「\Win32\Debug」フォルダ内に
「\Ssh-Pascal-master\Bin\Win32\libssh2.dll」ファイルをコピーします。

ソースコードの記述

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.StdCtrls, Vcl.ExtCtrls,
  libssh2, SocketUtils, SSh2Client, SshTunnel;

type
  TForm1 = class(TForm)
    BConnect: TButton;
    BDisConnect: TButton;
    Memo1: TMemo;
    Panel1: TPanel;
    Label1: TLabel;
    E_LPort: TEdit;
    Label2: TLabel;
    E_MHost: TEdit;
    Label3: TLabel;
    Label4: TLabel;
    E_MPort: TEdit;
    Label5: TLabel;
    Label6: TLabel;
    E_RHost: TEdit;
    Label7: TLabel;
    E_RPort: TEdit;
    Label8: TLabel;
    E_MUser: TEdit;
    Label9: TLabel;
    E_MPass: TEdit;
    Label10: TLabel;
    procedure BConnectClick(Sender: TObject);
    procedure BDisConnectClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
    tunnel:ISshTunnel;
    sess:ISshSession;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


{ SSHトンネル、SSHポートフォワーディング }
procedure TForm1.BConnectClick(Sender: TObject);
var i:integer;
    auth:TAuthMethods;
    flag:boolean;
    Thread:TThread;
    p:TKnownHostCheckPolicy;
    stl:TStringList;
begin
  BConnect.Enabled:=False;
  BDisConnect.Enabled:=True;
  sess:=CreateSession(E_MHost.Text,StrToInt(E_MPort.Text));
  //未知のホスト鍵でも許可する設定を行う(フィンガープリントの確認)
  stl:=TStringList.Create;
  stl.Add('host '+E_MHost.Text);
  stl.Add('  StrictHostKeyChecking no');
  stl.SaveToFile(ExtractFilePath(Application.ExeName)+'config.ini');
  p[TKnownHostCheckState.khcsMatch]:=TKnownHostCheckAction.khcaContinue;
  p[TKnownHostCheckState.khcsMisMatch]:=TKnownHostCheckAction.khcaContinue;
  p[TKnownHostCheckState.khcsNotFound]:=TKnownHostCheckAction.khcaContinue;
  p[TKnownHostCheckState.khcsFailure]:=TKnownHostCheckAction.khcaContinue;
  sess.ConfigKnownHostCheckPolicy(
    true,p,
    ExtractFilePath(Application.ExeName)+'config.ini'
  );
  //sess.ConfigKeepAlive(false,5);
  //sess.SetTimeout(4000);
  //sess.CodePage:=65001;
  //接続
  sess.Connect(TIPVersion.IPv4);
  //認証
  flag:=sess.UserAuthPass(
    E_MUser.Text,
    E_MPass.Text
  );
  memo1.Lines.Add(sess.HostBanner);
  memo1.Lines.Add(sess.SessionMethods);
  if flag then
    memo1.Lines.Add('Connected')
  else
  begin
    memo1.Lines.Add('Can''t connect');
    BConnect.Enabled:=True;
    BDisConnect.Enabled:=False;
  end;

  //トンネルの作成
  tunnel:=CreateSshTunnel(sess);
  Thread := TThread.CreateAnonymousThread(
  procedure
  begin
    try
      tunnel.ForwardLocalPort(
        StrToInt(E_LPort.Text),
        E_RHost.Text,
        StrToInt(E_RPort.Text)
      );
    except
      sess.Disconnect;
      BConnect.Enabled:=True;
      BDisConnect.Enabled:=False;
      TThread.Synchronize(TThread.CurrentThread,
        procedure
        begin
          Memo1.Lines.Add('Disconnected');
        end
      );
    end;
  end
  );
  Thread.FreeOnTerminate:=True;
  Thread.Start;
end;

procedure TForm1.BDisConnectClick(Sender: TObject);
begin
  if BConnect.Enabled=False then
  begin
    BConnect.Enabled:=True;
    BDisConnect.Enabled:=False;
    tunnel.Cancel;
    sess.Disconnect;
    Memo1.Lines.Add('Disconnected');
  end;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  BDisConnect.Enabled:=False;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if BConnect.Enabled=False then
  begin
    BConnect.Enabled:=True;
    BDisConnect.Enabled:=False;
    tunnel.Cancel;
    sess.Disconnect;
  end;
end;

end.