TurboVNC / turbovnc

Main TurboVNC repository
https://TurboVNC.org
GNU General Public License v2.0
746 stars 136 forks source link

VNC server reverse connection automatically closed #378

Closed wyxarcz closed 10 months ago

wyxarcz commented 10 months ago

Hi there,

could I have one question about VNC server reverse connection functionality?

I am trying to make endless connection using TurboVNC server to UltraVNC repeater to make server accessible from the Internet indefinitely long time. My TurboVNC server is running on AArch64 Linux platform. The connection to the UltraVNC repeater passes correctly, the repeater notices enstablished connection, but after a few tens of seconds (30~60 s) is connection ended by server side, perhaps due to the connection is idle (no more packets are transmitted through a session).

Is this normal behaviour of the server reverse connection or not? If it is normal, is there any option to set the connection to wait indefinitely long? I tried to modify Xvnc rfbwait parameter to different values, but without any success. I am not sure if this one is that right one to modify, but I tried it.

When I tryied to connect UltraVNC repeater using UltraVNC server on my desktop PC, I noticed the UltraVNC server is sending to the repeater empty packets with keep-alive flag to keep connection still active.

Note: On my Linux platform I am running Xvnc version v3.0.3 (build 20230227).

image Image 1 - The connection between TurboVNC server and UltraVNC repeater

image Image 2 - The connection between UltraVNC server and UltraVNC repeater

Thanks in advance for a help.

dcommander commented 10 months ago

Unless you have explicitly set an idle timeout in the TurboVNC Server (it isn't enabled by default), then I can't think of anything that would cause that unless the UltraVNC Repeater is closing the connection because of the lack of a keepalive message. I have only tested the Unix version of the UltraVNC Repeater (https://github.com/qian-jiahong/uvncrep017-ws), not the Windows version provided at uvnc.com.

wyxarcz commented 10 months ago

I am not able to test it right now on my aarch64 Linux platform. I haven't access to it right now. I will test it tommorow.

But I tried to install TurboVNC server on VirtualBox VM inside my laptop (OS Ubuntu arm64), this tutorial helped me: https://gist.github.com/cyberang3l/422a77a47bdc15a0824d5cca47e64ba2. Also I installed UltraVNC Repeater on my main OS inside laptop (OS Windows arm64). The server was able to access the repeater without complications. I tried to use or use not the parameter "rfbwait" while I was starting "vncserver" script. Also I tried to modify setting of UltraVNC Repeater different ways.

I am not sure, if this is caused by this option, but is possible that the setting UltraVNC Repeater option "Keepalive require winvnc >=1201" to enabled makes this issues? It seems, when this option is enabled, the repeater send to server a VNC packet at regular intervals with text "REP 000.000\n". An UltraVNC server installed on my main OS also ansfers by ACK message, sends VNC packet with text containing version of VNC protocol "RFB 003.008\n". The repeater then ansfers ACK. Meanwhile both keeps connection by TCP keep-alive messages.

obrazek Image 1 - Connection between UltraVNC repeater and server

But when VNC packet from the repeater obtains the TurboVNC server, it seems it will enforce connection finish, also I found this content inside Xvnc log file on Ubuntu:

24/08/2023 21:51:14 Making connection to client on host 192.168.1.242 port 5500
24/08/2023 21:51:14 UltraVNC Repeater Mode II ID is 12345
24/08/2023 21:51:14 Normal socket connection
24/08/2023 21:52:15 rfbProcessClientProtocolVersion: not a valid RFB client
24/08/2023 21:52:15 Client 192.168.1.242 gone
24/08/2023 21:52:15 Statistics:
24/08/2023 21:52:15   framebuffer updates 0, rectangles 0, bytes 0

Is possible the using of the "Keepalive require winvnc >=1201" option breaks the functionality, or it could be something else also?

dcommander commented 10 months ago

That is the most likely explanation. Our server does not support the RFB KeepAlive message. However, the repeater should never send a KeepAlive message unless it has verified, through an RFB pseudo-encoding, that the server is capable of receiving it. If in fact the repeater is doing so, then it is misbehaving.

wyxarcz commented 10 months ago

Yes, it seems the removal of the "rfbwait" flag and not using of "Keepalive require winvnc >=1201" option on UltraVNC repeater solved the problem.

Thanks for Your assistance very much.

Although... the session is kept alive, but the keeping-alive packets could be transmitted more frequently, if I could offer this little improvement, because Linux OS has by default predefined sending keeping-alive packet once per 2 hours, during this period is possible someones 'cut a wire' and no one will know that for a long time (unless someone will try to connect to repeater by VNC client). When sending of keeping-alive packet will be done more frequently, the VNC server can take a chance to restart connection by custom script for an example. I found this page, which could be handy: https://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/#setsockopt

wyxarcz commented 10 months ago

...maybe something like this (see below), but this is only my ugly try. Of course it could be handled better way, e.g. used variables could be defined as Xvnc executable parameters.

int ConnectToTcpAddr(char *host, int port)
{
  char portname[10];
  int sock;
  struct addrinfo hints, *addr;
  int one = 1;
///// MODIFIED CODE - START /////
  int keepalive_idle_period = 60;   // Send keep-alive packet every x seconds
  int keepalive_retry_period = 20;  // Send keep-alive packet when previous try failed every x seconds
  int keepalive_probes = 5;     // Count of retries when keep-alive routine fails
                    // before the connection is considered as dead
///// MODIFIED CODE - END /////

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  snprintf(portname, 10, "%d", port);
  if (getaddrinfo(host, portname, &hints, &addr) != 0)
    return -1;

  if ((sock =
       socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol)) < 0) {
    freeaddrinfo(addr);
    return -1;
  }

///// MODIFIED CODE - START /////
#if defined(TCP_KEEPCNT) && defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
  if (setsockopt(sock, SOL_TCP , TCP_KEEPCNT, (void *)&keepalive_probes,
                 sizeof(keepalive_probes)) < 0) {
    close(sock);
    return -1;
  }

  if (setsockopt(sock, SOL_TCP , TCP_KEEPIDLE, (void *)&keepalive_idle_period,
                 sizeof(keepalive_idle_period)) < 0) {
    close(sock);
    return -1;
  }

  if (setsockopt(sock, SOL_TCP , TCP_KEEPINTVL, (void *)&keepalive_retry_period,
                 sizeof(keepalive_retry_period)) < 0) {
    close(sock);
    return -1;
  }
#endif

  if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&one,
                 sizeof(one)) < 0) {
    close(sock);
    return -1;
  }
///// MODIFIED CODE - END /////

  if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) {
    close(sock);
    freeaddrinfo(addr);
    return -1;
  }

  freeaddrinfo(addr);
  return sock;
}

(Source code from ./unix/Xvnc/programs/Xserver/hw/vnc file)

dcommander commented 10 months ago

I am interested in both TCP keep-alive packets and the RFB KeepAlive message, but there are good reasons why those features shouldn't be enabled for all use cases. Thus I would need to do a lot of testing to figure out the cases in which the features are the most beneficial, then I would need to expose the features through the TurboVNC interfaces, then I would need to document them. That's a lot of effort. As an independent developer, I don't get paid for developing new TurboVNC features unless those features are covered by a funded development contract. Thus it would be best to implement a keep-alive feature in the context of such a contract with an organization that can test the feature on a large scale as it is being developed.