novnc / noVNC

VNC client web application
https://novnc.com
Other
11.36k stars 2.27k forks source link

failure to connect to siemens touch panels #1030

Closed cyrilrey closed 6 years ago

cyrilrey commented 6 years ago

This is related to https://github.com/novnc/noVNC/issues/364, but not quite the same

I am having an issue whit last version vnc_lite.html :

13:54:27.984 Navigated to http://192.168.91.26:6080/vnc_lite.html?token=yyyyy&debug=1
13:54:28.656 rfb.js:688 Failed when connecting: Server wanted tunnels, but doesn't support the notunnel type
_fail @ rfb.js:688
_negotiate_tight_tunnels @ rfb.js:1028
_negotiate_tight_auth @ rfb.js:1042
_negotiate_authentication @ rfb.js:1111
_init_msg @ rfb.js:1302
_handle_message @ rfb.js:734
_recv_message @ websock.js:304

As info: I am trying to connect a small hmi panel Siemens running windows CE 6.0 with a processor AMD Inc., i486. As a result this is an embedded industrial device, I have very limited access to VNC server configuration. It could be possible that this system is not totally compliant with standard vnc protocol. I know that it seems to be an exotic product for IT people, but that kind of product is even widely deployed in almost every industrial facilities.

I get these extra information from UltraVnc connection info :

Host:  192.168.147.10 Port: 5900 
| Port 2089940572

Desktop geometry: 1280 x 800 x 32
Using depth: 32
Line speed estimate: 40 kbits/s
Current protocol version 3.8

Current keyboard name: 0000100C
Using plugin : -

I think there is something wrong while protocol negotiation?

Else, my novnc server can connect without any problem to alternate standards VNC servers and devices, and that really really rocks. So thanks.

Best regards Cyril

CendioOssman commented 6 years ago

We need to figure out exactly what the server is exposing, so please do the following:

  1. Apply this patch:
diff --git a/core/rfb.js b/core/rfb.js
index 7c4e0c9..5f1f377 100644
--- a/core/rfb.js
+++ b/core/rfb.js
@@ -1015,6 +1015,8 @@ RFB.prototype = {
             serverSupportedTunnelTypes[cap_code] = { vendor: cap_vendor, signature: cap_signature };
         }

+        Log.Debug("Server Tight tunnel types: " + serverSupportedTunnelTypes);
+
         // choose the notunnel type
         if (serverSupportedTunnelTypes[0]) {
             if (serverSupportedTunnelTypes[0].vendor != clientSupportedTunnelTypes[0].vendor ||
@@ -1022,6 +1024,7 @@ RFB.prototype = {
                 return this._fail("Client's tunnel type had the incorrect " +
                                   "vendor or signature");
             }
+            Log.Debug("Selected tunnel type: " + clientSupportedTunnelTypes[0]);
             this._sock.send([0, 0, 0, 0]);  // use NOTUNNEL
             return false; // wait until we receive the sub auth count to continue
         } else {
@@ -1067,9 +1070,12 @@ RFB.prototype = {
             serverSupportedTypes.push(capabilities);
         }

+        Log.Debug("Server Tight authentication types: " + serverSupportedTypes);
+
         for (var authType in clientSupportedTypes) {
             if (serverSupportedTypes.indexOf(authType) != -1) {
                 this._sock.send([0, 0, 0, clientSupportedTypes[authType]]);
+                Log.Debug("Selected authentication type: " + authType);

                 switch (authType) {
                     case 'STDVNOAUTH__':  // no auth
  1. Use vnc.html rather than vnc_lite.html

  2. Use the settings to turn up the log level to debug

Try to connect again and send us the browser console log.

cyrilrey commented 6 years ago

Sorry but I encounter some difficulties to do requested operations.

1) I was not able to apply diff with git. I am not a git user, unfortunately. But it doesn't matter, I did it by hand. 2) I never be able to use token with vnc.html? I trought it was not possible to connect remote vnc host with vnc.html? Could you confirm? 3) I append &logging=debug to url and get that :

16:31:45.182 Navigated to https://192.168.91.26:6080/vnc_lite.html?token=ufmiege&password=100&logging=debug
16:31:45.449 rfb.js:399 connecting to wss://192.168.91.26:6080/websockify?token=ufmiege
16:31:45.659 websock.js:217 Server choose sub-protocol: binary
16:31:45.812 rfb.js:818 Server ProtocolVersion: 003.008
16:31:46.140 rfb.js:688 Failed when connecting: Server wanted tunnels, but doesn't support the notunnel type
_fail @ rfb.js:688
_negotiate_tight_tunnels @ rfb.js:1033
_negotiate_tight_auth @ rfb.js:1047
_negotiate_authentication @ rfb.js:1119
_init_msg @ rfb.js:1310
_handle_message @ rfb.js:734
_recv_message @ websock.js:304
16:31:46.144 websock.js:239 Closing WebSocket connection
16:31:46.145 rfb.js:452 Encoding stats for this connection:
16:31:46.145 rfb.js:460 Encoding stats since page load:

I am not sure if it is useful enough and if I did it right? Else tell me what to do and I will try.

DirectXMan12 commented 6 years ago

So, base questions first:

How's your server configured? Is it set to request tunnel authentication? Is the "notunnel" tunnel type disabled? We don't actually support tunneled auth, except for the notunnel type.

cyrilrey commented 6 years ago

How's your server configured?

VNC server

Vnc server is built within an embedded device industrial touch panel. This is that kind of products : https://mall.industry.siemens.com/mall/en/fr/Catalog/Products/10015539?tree=CatalogTree.

They have a VNC based option for remote monitoring trough network, but I have no configuration option. Everything is hardcoded by Siemens.

More than that some models works with novnc and some do not work with novnc. My colleague also experiment some issue with several alternate vnc client. So I think vnc support is really basic and compatibility may be not great.

We use those devices as local IHM for clean water treatment and distribution infrastructure. Our goal is to include those local display into a global html5 supervision SCADA system.

NOVNC Server

My novnc server is a service managed by supervisor (python) tool. This is ma configuration :

;novnc server section
[program:novnc]
command=/home/novnc/websockify/websockify.py --cert /home/novnc/certificate.crt --key /home/novnc/privateKey.key --web /home/novnc/noVNC/ 608                                                                      0 --target-config /home/novnc/vnclist.conf
;command=/home/novnc/websockify/websockify.py --web /home/novnc/noVNC/ 6080 --target-config /home/novnc/vnclist.conf
user=novnc
priority=100
autostart=true
autorestart=true

Next to novnc, I have a self made python xml rpc service for adding and removing token and hosts within vnclist.conf. Token are generated from central supervision system according to user sessions and access level.


     def add(self, token, vncserveur, port):
                self.list[token]={}
                self.list[token]['vnc'] = str(vncserveur)
                self.list[token]['token'] = str(token)
                self.list[token]['port'] = str(port)
                self.list[token]['time'] = datetime.now()

                host = token+": "+token+":"+str(port)
                print("add : "+host)
                self.tofile()
                return host
cyrilrey commented 6 years ago

@CendioOssman , I manage to read content of serverSupportedTunnelTypes:

rfb.js:1018 Server Tight tunnel types: [object Object]
09:43:51.649

rfb.js:1019 
{1: {…}, 2: {…}}
1:
signature:"SCHANNEL"
vendor:"SICR"
__proto__:Object

2:
signature:"SCHANLPW"
vendor:"SICR"
__proto_:Object
__proto__:Object`

Then I notice in the loop just above, debug mode when i=0, cap code=1. Maybe the server start counting from 1?

// receive tunnel capabilities
 for (var i = 0; i < numTunnels; i++) {
            var cap_code = this._sock.rQshift32();
            var cap_vendor = this._sock.rQshiftStr(4);
            var cap_signature = this._sock.rQshiftStr(8);
            serverSupportedTunnelTypes[cap_code] = { vendor: cap_vendor, signature: cap_signature };
        }

Then maybe the following test fail because no index 0 ? if (serverSupportedTunnelTypes[0]) {

CendioOssman commented 6 years ago

The 0 index is a bit of a hack, but it isn't what's failing here. That server isn't presenting NOTUNNEL at any index. Unfortunately those two things it does present seem to be proprietary Siemens extensions. Without documentation there is no way we can support those. So I'm afraid you won't be able to use noVNC with this device. :/

cyrilrey commented 6 years ago

I trough Siemens returns bad values. In fact I am not really surprised with that. But nevertheless, on that kind of devices VNC implementation should be very basic.

So I decide to gamble while trying something dirty and forcing the way.

And Luckily with the function shown below it seems to work, but I will try more deeply to be sure.


   _negotiate_tight_tunnels: function (numTunnels) {
        var clientSupportedTunnelTypes = {
            0: { vendor: 'TGHT', signature: 'NOTUNNEL' },
            1: { vendor: 'SICR', signature: 'SCHANNEL' },
            2: { vendor: 'SICR', signature: 'SCHANLPW' }
        };
        var serverSupportedTunnelTypes = {};
        // receive tunnel capabilities
        for (var i = 0; i < numTunnels; i++) {
            var cap_code = this._sock.rQshift32();
            var cap_vendor = this._sock.rQshiftStr(4);
            var cap_signature = this._sock.rQshiftStr(8);
            serverSupportedTunnelTypes[cap_code] = { vendor: cap_vendor, signature: cap_signature };

            Log.Debug("Server tunnel type: " + cap_code+" "+ cap_vendor +" "+ cap_signature);

            for (var tunnelType in clientSupportedTunnelTypes) {
                               if (cap_vendor == clientSupportedTunnelTypes[tunnelType].vendor && cap_signature == clientSupportedTunnelTypes[tunnelType].signature ) {
                    Log.Debug("Server tunnel type supported");
                    this._sock.send([0, 0, 0, 0]);  // use NOTUNNEL
                    return false; // wait until we receive the sub auth count to continue

                }
            }

        }
        Log.Debug("Server Tight tunnel types: " + serverSupportedTunnelTypes);
        Log.Debug(serverSupportedTunnelTypes);

        // choose the notunnel type

    return this._fail("Client's tunnel type had the incorrect vendor or signature or server wanted tunnels, but doesn't support the notunnel type");
    },

I am not JavaScript programmer, neither git user. So that code is not clean. But you can ask for my help if you would push that into the main branch.

I notice that you are much more reactive than commercial solution that I get used to work with. So you have my respect and I would congratulate novnc's team for that. Again, thanks for you help. Cyril

CendioOssman commented 6 years ago

Your suggestion simply selects NOTUNNEL even if the server doesn't announce support for it. That's not very well behaved, so not really something we can take in. We'd have to detect that this is indeed a broken Siemens server where this will work.

cyrilrey commented 6 years ago

Your suggestion simply selects NOTUNNEL even if the server doesn't announce support for it.

Yes and not.

In fact, NOTUNNEL is selected only if server announcement match one of those entry :

            0: { vendor: 'TGHT', signature: 'NOTUNNEL' },
            1: { vendor: 'SICR', signature: 'SCHANNEL' },
            2: { vendor: 'SICR', signature: 'SCHANLPW' }

I know it is dirty. It would be better if we can fix it from Siemens side.

That's not very well behaved, so not really something we can take in. We'd have to detect that this is indeed a broken Siemens server where this will work.

Do you have any suggestion about, how we should do that ?

CendioOssman commented 6 years ago

That's not very well behaved, so not really something we can take in. We'd have to detect that this is indeed a broken Siemens server where this will work.

Do you have any suggestion about, how we should do that ?

Not really. The only info we have so far are those tunnel types your patch checks for. And to use those we would need to be somewhat sure that there aren't servers that advertise those types, yet do broken things if we ask for 0.

Do you have any other models you can test with? Or is there some community where we could ask people to test?

cyrilrey commented 6 years ago

I understand your position. We are only concerned by Siemens yet but there are much others brand with that kind of windows CE providing basic VNC server. (Allen Bradley, Schneider, Mitsubishi, Wago, Saia, ...)

Is there some community where we could ask people to test?

Honestly no. People using that those devices are automation engineers and not IT specialist. So using novnc on a linux server is generally out of there field. Secondly, potential community are unfortunately our competitors. And so my boss is not in concern with helping them, because he doses not have an advanced open source spirit.

Do you have any other models you can test with?

Yes. We have almost 20-30 devices installed at our customers that we will soon be able to reach from our novnc server. These are recent and old models. We also have a mix of standard computer with ultravnc servers. We are conducting some tests next months with my patch. If you tell me what details you need I can come back with.

And to use those we would need to be somewhat sure that there aren't servers that advertise those types, yet do broken things if we ask for 0.

It need to be confirmed, but I think that the code where we are asking [0] (hard coded) may need to be reviewed. Maybe I am wrong, but It seems to work yet only because we have one supported type...

Else, that loop for (var tunnelType in clientSupportedTunnelTypes) {
will ask for index [0]

CendioOssman commented 6 years ago

Alright, so if you have a bunch of different models then I think that could be enough testing for us to commit something permanently. However I'd like to keep things minimal, so please edit the function to look like this:

    _negotiate_tight_tunnels: function (numTunnels) {
        var clientSupportedTunnelTypes = {
            0: { vendor: 'TGHT', signature: 'NOTUNNEL' }
        };
        var serverSupportedTunnelTypes = {};
        // receive tunnel capabilities
        for (var i = 0; i < numTunnels; i++) {
            var cap_code = this._sock.rQshift32();
            var cap_vendor = this._sock.rQshiftStr(4);
            var cap_signature = this._sock.rQshiftStr(8);
            serverSupportedTunnelTypes[cap_code] = { vendor: cap_vendor, signature: cap_signature };
        }

        // Siemens touch panels have a VNC server that supports NOTUNNEL,
        // but forgets to advertise it. Try to detect such servers by
        // looking for their custom tunnel type.
        if (serverSupportedTunnelTypes[1] &&
            (serverSupportedTunnelTypes[1].vendor === "SICR") &&
            (serverSupportedTunnelTypes[1].signature === "SCHANNEL")) {
            Log.Debug("Detected Siemens server. Assuming NOTUNNEL support.");
            serverSupportedTunnelTypes[0] = { vendor: 'TGHT', signature: 'NOTUNNEL' };
        }

        // choose the notunnel type
        if (serverSupportedTunnelTypes[0]) {
            if (serverSupportedTunnelTypes[0].vendor != clientSupportedTunnelTypes[0].vendor ||
                serverSupportedTunnelTypes[0].signature != clientSupportedTunnelTypes[0].signature) {
                return this._fail("Client's tunnel type had the incorrect " +
                                  "vendor or signature");
            }
            this._sock.send([0, 0, 0, 0]);  // use NOTUNNEL
            return false; // wait until we receive the sub auth count to continue
        } else {
            return this._fail("Server wanted tunnels, but doesn't support " +
                              "the notunnel type");
        }
    },

Please test that with the devices you have and let us know how it works.

cyrilrey commented 6 years ago

@CendioOssman, I apply given modification to my development server. I can connect with a Siemens industrial touch panels. So at that point I can confirm you that the modification did the job.

Next, I will have more devices with several type, version or generation. I will have to conduct some integration and testing during next mounts. I can not exclude that some devices will return alternate value.

It would be suitable to wait before committing definitely. What do you think?

CendioOssman commented 6 years ago

Right. We'll wait for you to have time to do some more testing with more devices.

samhed commented 6 years ago

No response.

cyrilrey commented 6 years ago

I confirm that our testing were successful with suggested modification. Case can be closed. Thanks every body for your help.

samhed commented 6 years ago

In that case we should consider committing to master @CendioOssman ?

CendioOssman commented 6 years ago

I think so.

cyrilrey commented 6 years ago

I think so too.

CendioOssman commented 6 years ago

Fixed in 8f47bd296c9e757fe3b6aa6b148effc4c94abaaf.

cyrilrey commented 6 years ago

Thanks