ScSSHChannel on Android: Cannot bind to address...

Discussion of open issues, suggestions and bugs regarding network security and data protection solution - SecureBridge
Post Reply
Ollinux
Posts: 4
Joined: Mon 20 Mar 2017 08:11

ScSSHChannel on Android: Cannot bind to address...

Post by Ollinux » Mon 27 Mar 2017 10:24

Hello,

i'm using the Trial-Version of SecureBridge.

Here is the short version of my problem: After SSH Disconnect i can't connect the Channel again when running on Android -> 'Cannot bind to address 'localhost'. Address already in use. Socket Error Code: 98($62)'.

The long version:
I wrote a very straight-forward and simple demo consisting of two projects:
A Server-Project (VCL), running under Windows 10, with a TScSSHServer, a TScFileStorage and a TIdHTTPServer.
A Client-Project (FMX) with a TScSSHClient, a TScFileStorage, a TScChannel and a TIdHTTP.
The Server creates its components and waits for an incoming GET-Request, answering with a string.
The Client has a 'Connect'-Button to connect to the server (ScSSHClient.Connect) and establish the Tunnel (ScSSHChannel.Connect).
The Client has a 'Send'-Button to send the Get-Request.
The Client has a 'Disconnect'-Button to disconnect the ScSSHChannel, then disconnect the ScSSHClient.

On Win32 and iOs, everything works fine: The Client connects, sends it's request, gets an answer, disconnects. I can repeat this as often as i want.

On Android, everything works fine for the first connection. If i try to connect again after disconnect, sometimes it works (10%), but sometimes (90%) i got an exception: "Im Projekt ProjectClientFMX.apk ist eine Exception der Klasse std::ostream mit der Meldung 'Cannot bind to address 'localhost'. Address already in use. Socket Error Code: 98($62)' aufgetreten."

PS: Under Android, sometimes i get an Exception when trying to connect the first time: "Error on data reading from the connection: Interrupted system call. Socket Error Code: 4($4)". But this is not reproducable. Maybe this is a side effect of the "You are using SecureBridge Trial edition!"-Message?

Am I doing something wrong or is it a bug?

Here is the Server-Source (VCL-Form with one TButton and one TEdit):

unit Unit1;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms,
Vcl.Dialogs, ScBridge, Vcl.StdCtrls, System.IOUtils,
IdContext, IdCustomHTTPServer, IdBaseComponent, IdComponent, IdCustomTCPServer, IdHTTPServer,
ScSSHServer, ScSSHChannel, ScSSHUtils, ScUtils;

const
SERVERKEYNAME = 'serverkey';

type
TForm1 = class(TForm)
Label1: TLabel;
edFingerprint: TEdit;
btGenerateHostKey: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure IdHTTPServerCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
procedure ScSSHServerChannelError(Sender: TObject; ChannelInfo: TScSSHChannelInfo; E: Exception);
procedure ScSSHServerError(Sender: TObject; E: Exception);
procedure btGenerateHostKeyClick(Sender: TObject);
private
MyScSSHServer: TScSSHServer;
MyScFileStorage: TScFileStorage;
MyIdHTTPServer: TIdHTTPServer;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btGenerateHostKeyClick(Sender: TObject);
var
fp: string;
User: TScUser;
Key: TScKey;
begin
// eigenen Key löschen und neu erzeugen.
MyScSSHServer.Storage.DeleteStorage;

User := TScUser.Create(MyScSSHServer.Storage.Users);
User.UserName := 'Olli';
User.Password := 'Olli';
User.Authentications := [uaPassword];

try
MyScSSHServer.Storage.Keys.CheckKeyName(SERVERKEYNAME);
except
on E:Exception do
ShowMessage(Format('Key with this name already exists: %s', [E.Message]));
end;

Key := TscKey.Create(MyScSSHServer.Storage.Keys);
Key.KeyName := SERVERKEYNAME;
Key.Generate(aaRSA, 1024);

Key.GetFingerprint(haSHA2_256, fp);
ShowMessage(Format('Fine, Key added. Fingerprint = %s', [fp]));
edFingerprint.Text := fp;

//Key.ExportTo('d:\publickey.pub', TRUE, '', saTripleDES_cbc, kfIETF, 'erzeugt am '+DateToStr(Now) + ' um ' + TimeToStr(Now));

MyScSSHServer.Active := TRUE;
MyIdHTTPServer.Active := TRUE;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
fp: String;
begin
MyScSSHServer := TScSSHServer.Create(nil);
MyScFileStorage := TScFileStorage.Create(nil);
MyIdHTTPServer := TIdHTTPServer.Create(nil);

MyScSSHServer.KeyNameRSA := SERVERKEYNAME;
MyScSSHServer.OnError := ScSSHServerError;
MyScSSHServer.OnChannelError := ScSSHServerChannelError;
MyScSSHServer.Storage := MyScFileStorage;

MyScFileStorage.Path := TPath.GetDocumentsPath + TPath.DirectorySeparatorChar + 'My_SSH_Server_Test' + TPath.DirectorySeparatorChar;
MyScFileStorage.Algorithm := saAES256_cbc;
MyScFileStorage.Password := '12345678';

MyIdHTTPServer.DefaultPort := 7779;
MyIdHTTPServer.OnCommandGet := IdHTTPServerCommandGet;

MyScSSHServer.Active := TRUE;
MyIdHTTPServer.Active := TRUE;

MyScSSHServer.Storage.Keys.KeyByName(SERVERKEYNAME).GetFingerprint(TScHashAlgorithm.haSHA2_256, fp);
edFingerprint.Text := fp;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
MyIdHTTPServer.Active := FALSE;
MyScSSHServer.Active := FALSE;

MyScSSHServer.Free;
MyScFileStorage.Free;
MyIdHTTPServer.Free;
end;

procedure TForm1.IdHTTPServerCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
AResponseInfo.ResponseNo := 200;
AResponseInfo.ContentText := 'It is ' + TimeToStr(Now);
end;

procedure TForm1.ScSSHServerChannelError(Sender: TObject; ChannelInfo: TScSSHChannelInfo; E: Exception);
begin
ShowMessage('SSH Server Channel Error, Exception: ' + E.Message);
end;

procedure TForm1.ScSSHServerError(Sender: TObject; E: Exception);
begin
ShowMessage('SSH Server Error, Exception: ' + E.Message);
end;

end.


Here is the Client-Source (FMX-Form with one TLabel, four TButton and one TEdit):

unit Unit1;

interface

uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, System.IOUtils,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, FMX.Edit, FMX.Controls.Presentation,
IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP,
ScBridge, ScSSHClient, ScSSHChannel, ScUtils;

const
SERVERKEYNAME = 'serverkey';

type
TForm1 = class(TForm)
btDelKeys: TButton;
btConnect: TButton;
btSend: TButton;
btDisconnect: TButton;
EditExpectedFingerprint: TEdit;
Label1: TLabel;
procedure btDelKeysClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ScSSHClient1ServerKeyValidate(Sender: TObject; NewServerKey: TScKey; var Accept: Boolean);
procedure btConnectClick(Sender: TObject);
procedure btSendClick(Sender: TObject);
procedure btDisconnectClick(Sender: TObject);
procedure ScSSHChannel1Error(Sender: TObject; E: Exception);
procedure FormDestroy(Sender: TObject);
private
MyScSSHClient: TScSSHClient;
MyScFileStorage: TScFileStorage;
MyScSSHChannel: TScSSHChannel;
MyIdHTTP: TIdHttp;
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;

var
Form1: TForm1;

implementation

{$R *.fmx}
{$R *.LgXhdpiPh.fmx ANDROID}
{$R *.iPad.fmx IOS}

procedure TForm1.btConnectClick(Sender: TObject);
begin
try
MyScSSHClient.Connect;
except
on E:Exception do
Label1.Text := 'ScSSHClient.Connect: ' + E.Message;
end;

try
if MyScSSHClient.Connected then
MyScSSHChannel.Connect;

if MyScSSHChannel.Connected then
Label1.Text := 'Channel connected'
else
Label1.Text := 'Channel NOT connected';

except
on E:Exception do
Label1.Text := 'ScSSHChannel.Connect: ' + E.Message;
end;
end;

procedure TForm1.btDelKeysClick(Sender: TObject);
begin
MyScFileStorage.DeleteStorage;
if MyScFileStorage.Keys.Count = 0 then
Label1.Text := 'Key Storage cleared'
else
Label1.Text := 'Key Storage NOT cleared'
end;

procedure TForm1.btDisconnectClick(Sender: TObject);
begin
MyScSSHChannel.Disconnect;
MyScSSHClient.Disconnect;
Label1.Text := 'Disconnected';
end;

procedure TForm1.btSendClick(Sender: TObject);
begin
if MyScSSHChannel.Connected then
begin
// Get-Request to Servers TIdHttpServer, Server answers "'It is ' + TimeToStr(Now)"
Label1.Text := MyIdHTTP.Get('http://127.0.0.1:7778/doyouknowwhattimeitis.cgi');
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
MyScSSHClient := TScSSHClient.Create(nil);
MyScFileStorage := TScFileStorage.Create(nil);
MyScSSHChannel := TScSSHChannel.Create(nil);
MyIdHTTP := TIdHTTP.Create(nil);

MyScFileStorage.Path := TPath.GetDocumentsPath + TPath.DirectorySeparatorChar + 'My_SSH_Client_Test' + TPath.DirectorySeparatorChar;
MyScFileStorage.Password := '1234';

MyScSSHClient.KeyStorage := MyScFileStorage;
MyScSSHClient.HostKeyName := SERVERKEYNAME;
MyScSSHClient.OnServerKeyValidate := ScSSHClient1ServerKeyValidate;
MyScSSHClient.HostName := '192.168.1.26';
MyScSSHClient.User := 'Olli';
MyScSSHClient.Password := 'Olli';

MyScSSHChannel.Client := MyScSSHClient;
MyScSSHChannel.DestHost := '192.168.1.26';
MyScSSHChannel.DestPort := 7779;
MyScSSHChannel.SourcePort := 7778;
MyScSSHChannel.OnError := ScSSHChannel1Error;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
MyIdHTTP.Free;
MyScSSHChannel.Free;
MyScSSHClient.Free;
MyScFileStorage.Free;
end;

procedure TForm1.ScSSHChannel1Error(Sender: TObject; E: Exception);
begin
ShowMessage('Channel Error: ' + E.Message);
end;

procedure TForm1.ScSSHClient1ServerKeyValidate(Sender: TObject; NewServerKey: TScKey; var Accept: Boolean);
var
fp: string;
begin
// There is no matching server key in the KeyStorage, so we end here.
NewServerKey.GetFingerprint(TScHashAlgorithm.haSHA2_256, fp);
Label1.Text := 'NewServerKey Fingerprint: ' + fp;

// Only for Test: Compare the first 8 Chars of the TEdit with the Server-Key-Fingerprint.
Accept := EditExpectedFingerprint.Text.Substring(0, 8) = fp.Substring(0, 8);

// if Key is unknown but accepted, save it in KeyStorage.
if Accept and (MyScSSHClient.KeyStorage.Keys.FindKey(SERVERKEYNAME) = nil) then
begin
NewServerKey.KeyName := SERVERKEYNAME;
MyScSSHClient.KeyStorage.Keys.Add(NewServerKey);
end;
end;

end.

ViktorV
Devart Team
Posts: 3168
Joined: Wed 30 Jul 2014 07:16

Re: ScSSHChannel on Android: Cannot bind to address...

Post by ViktorV » Wed 29 Mar 2017 13:36

Thank you for the information. We have reproduced the issue and investigation is in progress. We will inform you when we have any results.

Dido
Posts: 20
Joined: Fri 18 Sep 2009 20:04

Re: ScSSHChannel on Android: Cannot bind to address...

Post by Dido » Tue 30 May 2017 18:32

Hello,
i have absolutely same problem with registered version of SecureBridge 8.0.1.
If i change source port with new one - work, but if disconnect and then try to connect with
same source port (50001) - "Cannot bind to address 'localhost': Address already in use. Socket Error Code: 98 ($62)".
Probably the source port (50001) is not closed.
What is current status of this issue?

ViktorV
Devart Team
Posts: 3168
Joined: Wed 30 Jul 2014 07:16

Re: ScSSHChannel on Android: Cannot bind to address...

Post by ViktorV » Thu 01 Jun 2017 07:48

We have already fixed this bug. This fix will be included in next SecureBridge build.
We can send you SecureBridge night build including the fix. Please send your license number to viktor*devart*com and we will send you night build.

Post Reply