[PATCH] libxcb : Adds AF_VSOCK support

Choung Park cspark at choung.net
Wed Jul 14 19:50:56 UTC 2021


[ SUMMARY ]

This patch adds a new connection protocol 'vsock' for X clients running in a VM (virtual machine) guest when you want to have those clients connect back to the X server running in the VM host via AF_VSOCK.

AF_VSOCK can be used to provide seamless communication between virtual machines and their host with minimal overhead. TCP can also provide similar experience, but it has the inherit overhead of TCP/IP protocol and may even cause security issues. For example, if a virtual machine is configured with an isolated network (ex. Hyper-V in Windows), TCP connections can only be made to the X server running in the host when you allow its public access. In order to protect your host from that public access, you need to set up firewall and it inevitably causes additional communication overhead as well as management headaches.

All in all, supporting AF_VSOCK can open up new possibilities for X servers and clients in virtual machine platforms.

[ USAGE ]

Although it's not well known, libxcb already supports various protocol names such as 'tcp', 'unix' and etc. For example, the following two DISPLAY variable settings are very valid and already processed exactly the same in the current version of libxcb (1.14):

export DISPLAY=127.0.0.1:0.0
export DISPLAY=tcp/127.0.0.1:0.0

This patch extends the existing libxcb protocol framework for AF_VSOCK by adding a new protocol name 'vsock'. When the DISPLAY variable is set as the following, the patch makes connections to an X server via AF_VSOCK accordingly:

export DISPLAY=vsock/[<VMADDR_CID>]:<display_number>[.<screen_number>]

For example, in order to have X clients running in a VM guest connected to the X server running in the host, you can set the DISPLAY variable as:

export DISPLAY=vsock/2:0.0

It can be shortened as the following:

export DISPLAY=vsock/:0

'2' is the assigned number for VMADDR_CID_HOST and it's used as a default value when it's not found in the DISPLAY variable. For a port number, it can be any 'unsigned int', but in order to maintain the consistency, it's defined the same as the TCP: 6000 + <display_number>.

[ TESTING ]

Unfortunately, I was not able to make an AF_VSOCK patch for the current version of X.org server. However, you should be able to test my patch by running a relay program such as socat (1.7.4+; https://stefano-garzarella.github.io/posts/2021-01-22-socat-vsock/) in the host and set the DISPLAY variable to 'vsock/:0' in the guest with a patched libxcb:

> VM Host
socat VSOCK-LISTEN:6000,fork UNIX-CONNECT:/tmp/.X11-unix/X0

> VM Guest (with a patched libxcb)
export DISPLAY=vsock/:0

Any X program launched in the guest should then be shown in the host.


Best regards,
Choung Park


[ PATCH 1: xcb_util.c ]

--- libxcb-1.14/src/xcb_util.c	2020-02-22 12:50:14.000000000 -0800
+++ libxcb-1.14+vsock/src/xcb_util.c	2021-07-09 03:30:33.880000000 -0700
@@ -44,6 +44,9 @@
 #else
 #include <arpa/inet.h>
 #include <sys/socket.h>
+#ifdef HAVE_LINUX_VM_SOCKETS_H
+#include <linux/vm_sockets.h>
+#endif
 #include <sys/un.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
@@ -216,6 +219,9 @@
 }
 
 static int _xcb_open_tcp(const char *host, char *protocol, const unsigned short port);
+#ifdef HAVE_LINUX_VM_SOCKETS_H
+static int _xcb_open_vsock(const char *host, char *protocol, const unsigned short port);
+#endif
 #ifndef _WIN32
 static int _xcb_open_unix(char *protocol, const char *file);
 #endif /* !WIN32 */
@@ -236,6 +242,14 @@
     char *file = NULL;
     int actual_filelen;
 
+#ifdef HAVE_LINUX_VM_SOCKETS_H
+    if (protocol && (strcmp("vsock",protocol) == 0))
+    {
+        unsigned short port = X_TCP_PORT + display;
+        return _xcb_open_vsock(host, protocol, port);
+    }
+#endif
+
     /* If protocol or host is "unix", fall through to Unix socket code below */
     if ((!protocol || (strcmp("unix",protocol) != 0)) &&
         (*host != '\0') && (strcmp("unix",host) != 0))
@@ -425,6 +439,49 @@
 #endif
 }
 
+#ifdef HAVE_LINUX_VM_SOCKETS_H
+static int _xcb_open_vsock(const char *host, char *protocol, const unsigned short port)
+{
+    struct sockaddr_vm savm;
+    int fd;
+
+    if(protocol && strcmp("vsock",protocol))
+        return -1;
+
+    fd = _xcb_socket(AF_VSOCK, SOCK_STREAM, 0);
+    if(fd == -1)
+        return -1;
+
+    {
+        socklen_t len = sizeof(int);
+        int val = 0;
+
+        if((getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &len) == 0) && (val < (64 * 1024)))
+        {
+            val = (64 * 1024);
+            setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, sizeof(int));
+        }
+    }
+
+    memset(&savm, 0, sizeof(savm));
+
+    savm.svm_family = AF_VSOCK;
+    savm.svm_cid = VMADDR_CID_HOST;
+
+    if(*host != '\0')
+        savm.svm_cid = (unsigned int)atoi(host);
+
+    savm.svm_port = port;
+
+    if(connect(fd, (struct sockaddr*)&savm, sizeof(savm)) == -1)
+    {
+        close(fd);
+        return -1;
+    }
+    return fd;
+}
+#endif
+
 #ifndef _WIN32
 static int _xcb_open_unix(char *protocol, const char *file)
 {


[ PATCH 2: configure.ac ]

--- libxcb-1.14/configure.ac	2020-02-22 12:50:14.000000000 -0800
+++ libxcb-1.14+vsock/configure.ac	2021-07-09 03:24:38.690000000 -0700
@@ -186,6 +186,7 @@
 XCB_CHECK_VISIBILITY()
 
 AC_CHECK_FUNC(getaddrinfo, [AC_DEFINE(HAVE_GETADDRINFO, 1, [getaddrinfo() function is available])], )
+AC_CHECK_HEADERS([linux/vm_sockets.h], [], [], [#include <sys/socket.h>])
 
 case $host_os in
         # darwin through Snow Leopard has poll() but can't be used to poll character devices.




More information about the xorg-devel mailing list