Jump to content
dummzeuch

ssh tunnel with ssh-pascal

Recommended Posts

I'm trying to get ssh tunneling to work with ssh-pascal. The goal is to replace the currently used ssh tunnel for Remote Desktop via Putty with my own program.

 

I adapted the LocalForward demo and I can connect to and read from

http://detectportal.firefox.com/success.txt

(the original url http://git.php.net/ is apparently no longer available)

 

Then I changed the code to connect to my employer's internet facing ssh server port and forwarded a local port to the remote 3389 port of a computer in our LAN.

I can log on fine to the ssh server, even the Remote Desktop client starts, connects and gets a valid logon. But then it asks whether it should connect even though the certificate is not from a trusted certifying authority (which is normal for that connection) and pressing Yes there odes not do anything and the RDC connection times out after a while.

 

I added some debug WriteLns and found that the processing thread while executing TSshTunnel.ForwardLocalPort is waiting to read from ForwardSock here, after apparently FD_ISSET returned True:

    SetLength(Buf, FBufferSize);
    while not FCancelled do
    begin
      FD_ZERO(ReadFds);
      _FD_SET(ForwardSock, ReadFds);
      _FD_SET(ChannelSock, ReadFds);
      // wait for action
      ReturnCode := select(0, @ReadFds, nil, nil, @TimeVal);
      if ReturnCode < 0 then CheckSocketResult(ReturnCode, 'select');
      if ReturnCode = 0 then Continue;

      // we should be able to read now
      WriteLn('Checking ForwardSock');
      if FD_ISSET(ForwardSock, ReadFds) then begin
        WriteLn('Reading from ForwardSock');
        Read := recv(Forwardsock, Buf[0], FBufferSize, 0); // <=== hangs here
        if Read = SOCKET_ERROR then
          CheckSocketResult(WSAGetLastError, 'recv');
        if Read = 0 then
          raise ESshTunnelError.CreateRes(@Err_ConnClosed);
        WriteLn(Read, ' bytes read from ForwardSock');
        Total := 0;
        While (Total < Read) do
        begin
          Written := libssh2_channel_write(Channel, PAnsiChar(Buf) + Total, Read - Total);
          // Takes care of LIBSSH2_ERROR_EAGAIN
          CheckLibSsh2Result(Written, FSession, 'libssh2_channel_write');
          Inc(Total, Written);
          Writeln(Written, ' bytes written to ChannelSock');
        end;
      end;
      WriteLn('Checking ChannelSock');
      if FD_ISSET(ChannelSock, ReadFds) then begin
        WriteLn('Reading from ChannelSock');
        Read := libssh2_channel_read(channel, PAnsiChar(Buf), FBufferSize);
        if Read = LIBSSH2_ERROR_EAGAIN then
          // Go to Wait state again
          Continue;
        CheckLibSsh2Result(Read, FSession, 'libssh2_channel_read');
        WriteLn(Read, ' bytes read from ChannelSock');
        Total := 0;
        While (Total < Read) do
        begin
          Written := send(forwardsock, Buf[Total], Read - Total, 0);
          if Written = SOCKET_ERROR then
            CheckSocketResult(WSAGetLastError, 'send');
          Inc(Total, Written);
          Writeln(Written, ' bytes written to ForwardSock');
        end;
      end;
    end;

These are the last lines of the debug output:

Checking ChannelSock
Checking ForwardSock
Checking ChannelSock
Reading from ChannelSock
88 bytes read from ChannelSock
88 bytes written to ForwardSock
Checking ForwardSock
Reading from ForwardSock

Has anybody ever used this code successfully for more than requesting a simple webpage?

Edited by dummzeuch

Share this post


Link to post

@dummzeuch Can't test it right now, as it need more code to make it work, but

 

Don't ever use select in that way, in general all looks fine and correct, but without socket errors not the ones with API calls return, but the ones from "exceptfds", without checking for socket level errors you are driving in the dark, if error was signaled on the socket then read will hang for ever !

 

Add exceptfds, and then check for errors before read or write, as in many cases both error and read/write might be triggered and reported at the same time, in your case most likely this what did happen, an acknowledgment received to close and both readfds and exceptfds had been signaled.

Share this post


Link to post

@dummzeuch I have pushed a couple of fixes to SshTunnel.pas (issues found by Copilot!).  Could you please check whether they make a difference?  One of them might:  

 

SocketOption := 1; // Initialize SocketOption

Edited by pyscripter

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×