diff mbox series

[7/8] VNC Acceptance test: check protocol version

Message ID 20190607152223.9467-8-crosa@redhat.com
State New
Headers show
Series Miscellaneous acceptance test and Travis CI improvements | expand

Commit Message

Cleber Rosa June 7, 2019, 3:22 p.m. UTC
This goes a bit further than the other tests, and does a basic (read
only) interaction with the VNC protocol.

This is not a enough to perform a handshake, but enough to make sure
that the socket is somewhat operational and that the expected initial
step of the handshake is performed by the server and that the version
matches.

Signed-off-by: Cleber Rosa <crosa@redhat.com>
---
 tests/acceptance/vnc.py | 12 ++++++++++++
 1 file changed, 12 insertions(+)

Comments

Daniel P. Berrangé June 7, 2019, 5:29 p.m. UTC | #1
On Fri, Jun 07, 2019 at 11:22:22AM -0400, Cleber Rosa wrote:
> This goes a bit further than the other tests, and does a basic (read
> only) interaction with the VNC protocol.
> 
> This is not a enough to perform a handshake, but enough to make sure
> that the socket is somewhat operational and that the expected initial
> step of the handshake is performed by the server and that the version
> matches.

The GTK-VNC project provides a low level library libgvnc that can
be used to talk the RFB protocol in a fairly fine grained manner.
This is built using GObject, so is accessible from Python thanks
to GObject Introspection.

We could use libgvnc for exercising the VNC server instead of writing
custom RFB code. For your simple test just sending/receiving the
version it won't save much, but if we ever want to test TLS or
SASL integration, it would save alot of work dealing wth the auth
handshake and subsequent encryption needs.

The main limitation it would have is that it would only work well
for sending "well formed" RFB protocol messages. If we ever want to
send intentionally evil/bad RFB data to check QEMU's VNC server
security hardening it would be harder.

As the maintainer of GTK-VNC though, I would be open to adding more
APIs to the low level gvnc library to facilitate QEMU's testing
needs if we want.

> 
> Signed-off-by: Cleber Rosa <crosa@redhat.com>
> ---
>  tests/acceptance/vnc.py | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/tests/acceptance/vnc.py b/tests/acceptance/vnc.py
> index d32ae46685..b000446d7c 100644
> --- a/tests/acceptance/vnc.py
> +++ b/tests/acceptance/vnc.py
> @@ -11,6 +11,7 @@
>  import os
>  import tempfile
>  import shutil
> +import socket
>  
>  from avocado_qemu import Test
>  
> @@ -71,5 +72,16 @@ class VncUnixSocket(Test):
>                                              arg='new_password')
>          self.assertEqual(set_password_response['return'], {})
>  
> +    def test_protocol_version(self):
> +        self.vm.add_args('-nodefaults', '-S',
> +                         '-vnc', 'unix:%s' % self.socket_path)
> +        self.vm.launch()
> +        self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled'])
> +        client = socket.socket(socket.AF_UNIX)
> +        client.connect(self.socket_path)
> +        expected = b'RFB 003.008'
> +        actual = client.recv(len(expected))
> +        self.assertEqual(expected, actual, "Wrong protocol version")
> +
>      def tearDown(self):
>          shutil.rmtree(self.socket_dir)
> -- 
> 2.21.0
> 
> 

Regards,
Daniel
Cleber Rosa June 7, 2019, 6:12 p.m. UTC | #2
On Fri, Jun 07, 2019 at 06:29:15PM +0100, Daniel P. Berrangé wrote:
> On Fri, Jun 07, 2019 at 11:22:22AM -0400, Cleber Rosa wrote:
> > This goes a bit further than the other tests, and does a basic (read
> > only) interaction with the VNC protocol.
> > 
> > This is not a enough to perform a handshake, but enough to make sure
> > that the socket is somewhat operational and that the expected initial
> > step of the handshake is performed by the server and that the version
> > matches.
> 
> The GTK-VNC project provides a low level library libgvnc that can
> be used to talk the RFB protocol in a fairly fine grained manner.
> This is built using GObject, so is accessible from Python thanks
> to GObject Introspection.
>

Interesting.

> We could use libgvnc for exercising the VNC server instead of writing
> custom RFB code. For your simple test just sending/receiving the
> version it won't save much, but if we ever want to test TLS or
> SASL integration, it would save alot of work dealing wth the auth
> handshake and subsequent encryption needs.
>

Absolutely.

> The main limitation it would have is that it would only work well
> for sending "well formed" RFB protocol messages. If we ever want to
> send intentionally evil/bad RFB data to check QEMU's VNC server
> security hardening it would be harder.
>

Right.  Still, there's a lot that can be done until we eventually
exaust all possibilities and look into sending bad messages.

> As the maintainer of GTK-VNC though, I would be open to adding more
> APIs to the low level gvnc library to facilitate QEMU's testing
> needs if we want.
>

I personally need to get acquainted with the currently available APIs
first, but it looks like you alread have ideas for extensions that
would come in handy.

Also, the one concern I have is how to deploy the library and Python
bindings so that we can host those more advanced tests and still allow
for a "make check-acceptance"-like experience.  What I mean is, I
expect the Python bindings to be easily installed by pip, by I'd be
(positively) surprised if the libgvnc would also have such an easy
bootstrap.

Any ideas on this?

Thanks!
- Cleber.

> > 
> > Signed-off-by: Cleber Rosa <crosa@redhat.com>
> > ---
> >  tests/acceptance/vnc.py | 12 ++++++++++++
> >  1 file changed, 12 insertions(+)
> > 
> > diff --git a/tests/acceptance/vnc.py b/tests/acceptance/vnc.py
> > index d32ae46685..b000446d7c 100644
> > --- a/tests/acceptance/vnc.py
> > +++ b/tests/acceptance/vnc.py
> > @@ -11,6 +11,7 @@
> >  import os
> >  import tempfile
> >  import shutil
> > +import socket
> >  
> >  from avocado_qemu import Test
> >  
> > @@ -71,5 +72,16 @@ class VncUnixSocket(Test):
> >                                              arg='new_password')
> >          self.assertEqual(set_password_response['return'], {})
> >  
> > +    def test_protocol_version(self):
> > +        self.vm.add_args('-nodefaults', '-S',
> > +                         '-vnc', 'unix:%s' % self.socket_path)
> > +        self.vm.launch()
> > +        self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled'])
> > +        client = socket.socket(socket.AF_UNIX)
> > +        client.connect(self.socket_path)
> > +        expected = b'RFB 003.008'
> > +        actual = client.recv(len(expected))
> > +        self.assertEqual(expected, actual, "Wrong protocol version")
> > +
> >      def tearDown(self):
> >          shutil.rmtree(self.socket_dir)
> > -- 
> > 2.21.0
> > 
> > 
> 
> Regards,
> Daniel
> -- 
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
Daniel P. Berrangé June 10, 2019, 8:58 a.m. UTC | #3
On Fri, Jun 07, 2019 at 02:12:07PM -0400, Cleber Rosa wrote:
> On Fri, Jun 07, 2019 at 06:29:15PM +0100, Daniel P. Berrangé wrote:
> > On Fri, Jun 07, 2019 at 11:22:22AM -0400, Cleber Rosa wrote:
> > > This goes a bit further than the other tests, and does a basic (read
> > > only) interaction with the VNC protocol.
> > > 
> > > This is not a enough to perform a handshake, but enough to make sure
> > > that the socket is somewhat operational and that the expected initial
> > > step of the handshake is performed by the server and that the version
> > > matches.
> > 
> > The GTK-VNC project provides a low level library libgvnc that can
> > be used to talk the RFB protocol in a fairly fine grained manner.
> > This is built using GObject, so is accessible from Python thanks
> > to GObject Introspection.
> >
> 
> Interesting.
> 
> > We could use libgvnc for exercising the VNC server instead of writing
> > custom RFB code. For your simple test just sending/receiving the
> > version it won't save much, but if we ever want to test TLS or
> > SASL integration, it would save alot of work dealing wth the auth
> > handshake and subsequent encryption needs.
> >
> 
> Absolutely.
> 
> > The main limitation it would have is that it would only work well
> > for sending "well formed" RFB protocol messages. If we ever want to
> > send intentionally evil/bad RFB data to check QEMU's VNC server
> > security hardening it would be harder.
> >
> 
> Right.  Still, there's a lot that can be done until we eventually
> exaust all possibilities and look into sending bad messages.
> 
> > As the maintainer of GTK-VNC though, I would be open to adding more
> > APIs to the low level gvnc library to facilitate QEMU's testing
> > needs if we want.
> >
> 
> I personally need to get acquainted with the currently available APIs
> first, but it looks like you alread have ideas for extensions that
> would come in handy.
> 
> Also, the one concern I have is how to deploy the library and Python
> bindings so that we can host those more advanced tests and still allow
> for a "make check-acceptance"-like experience.  What I mean is, I
> expect the Python bindings to be easily installed by pip, by I'd be
> (positively) surprised if the libgvnc would also have such an easy
> bootstrap.
> 
> Any ideas on this?

IMHO we shouldn't try to install anything from pip. It should all be
available from distro repos already. In fact if you have "virt-install"
or "virt-manager" installed, you should already have the required
python bits.

On RHEL/Fedora you need python3-gobject to get the GObject introspection
support and then all you need is the native gvnc library. There is no
python library for gvnc because GObject introspection makes this
redundant - the python API is dynamically created at runtime using
FFI to access the native library APIs.


Regards,
Daniel
Wainer dos Santos Moschetta June 10, 2019, 8:43 p.m. UTC | #4
On 06/07/2019 12:22 PM, Cleber Rosa wrote:
> This goes a bit further than the other tests, and does a basic (read
> only) interaction with the VNC protocol.
>
> This is not a enough to perform a handshake, but enough to make sure
> that the socket is somewhat operational and that the expected initial
> step of the handshake is performed by the server and that the version
> matches.
>
> Signed-off-by: Cleber Rosa <crosa@redhat.com>
> ---
>   tests/acceptance/vnc.py | 12 ++++++++++++
>   1 file changed, 12 insertions(+)
>
> diff --git a/tests/acceptance/vnc.py b/tests/acceptance/vnc.py
> index d32ae46685..b000446d7c 100644
> --- a/tests/acceptance/vnc.py
> +++ b/tests/acceptance/vnc.py
> @@ -11,6 +11,7 @@
>   import os
>   import tempfile
>   import shutil
> +import socket
>   
>   from avocado_qemu import Test
>   
> @@ -71,5 +72,16 @@ class VncUnixSocket(Test):
>                                               arg='new_password')
>           self.assertEqual(set_password_response['return'], {})
>   
> +    def test_protocol_version(self):
> +        self.vm.add_args('-nodefaults', '-S',
> +                         '-vnc', 'unix:%s' % self.socket_path)
> +        self.vm.launch()
> +        self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled'])

I will advocate for the use QEMUMachine.command() instead of qmp(). The 
former do some checks on the qmp response and raises a more gently 
exception if something went wrong. This patch looks good to me though.

Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com>

> +        client = socket.socket(socket.AF_UNIX)
> +        client.connect(self.socket_path)
> +        expected = b'RFB 003.008'
> +        actual = client.recv(len(expected))
> +        self.assertEqual(expected, actual, "Wrong protocol version")
> +
>       def tearDown(self):
>           shutil.rmtree(self.socket_dir)
diff mbox series

Patch

diff --git a/tests/acceptance/vnc.py b/tests/acceptance/vnc.py
index d32ae46685..b000446d7c 100644
--- a/tests/acceptance/vnc.py
+++ b/tests/acceptance/vnc.py
@@ -11,6 +11,7 @@ 
 import os
 import tempfile
 import shutil
+import socket
 
 from avocado_qemu import Test
 
@@ -71,5 +72,16 @@  class VncUnixSocket(Test):
                                             arg='new_password')
         self.assertEqual(set_password_response['return'], {})
 
+    def test_protocol_version(self):
+        self.vm.add_args('-nodefaults', '-S',
+                         '-vnc', 'unix:%s' % self.socket_path)
+        self.vm.launch()
+        self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled'])
+        client = socket.socket(socket.AF_UNIX)
+        client.connect(self.socket_path)
+        expected = b'RFB 003.008'
+        actual = client.recv(len(expected))
+        self.assertEqual(expected, actual, "Wrong protocol version")
+
     def tearDown(self):
         shutil.rmtree(self.socket_dir)