[libvirt PATCH 9/9] rpc: use new virt-nc binary for remote tunnelling

Daniel P. Berrangé berrange at redhat.com
Thu Jul 9 18:36:46 UTC 2020


This wires up support for using the new virt-nc binary with the ssh,
libssh and libssh2 protocols.

The new binary will be used preferentially if it is available in $PATH,
otherwise we fall back to traditional netcat.

The "proxy" URI parameter can be used to force use of netcat e.g.

  qemu+ssh://host/system?proxy=netcat

or the disable fallback e.g.

  qemu+ssh://host/system?proxy=virt-nc

With use of virt-nc, we can now support remote session URIs

  qemu+ssh://host/session

and this will only use virt-nc, with no fallback. This also lets the
libvirtd process be auto-started.

Signed-off-by: Daniel P. Berrangé <berrange at redhat.com>
---
 docs/uri.html.in            | 18 ++++++++++
 src/remote/remote_driver.c  | 30 +++++++++++++++-
 src/remote/remote_sockets.c |  8 -----
 src/rpc/virnetclient.c      | 70 ++++++++++++++++++++++++++++++-------
 src/rpc/virnetclient.h      | 30 +++++++++++++---
 tests/virnetsockettest.c    |  7 ++--
 6 files changed, 136 insertions(+), 27 deletions(-)

diff --git a/docs/uri.html.in b/docs/uri.html.in
index 49f92773f8..5311579273 100644
--- a/docs/uri.html.in
+++ b/docs/uri.html.in
@@ -259,6 +259,24 @@ Note that parameter values must be
         <td colspan="2"/>
         <td> Example: <code>mode=direct</code> </td>
       </tr>
+      <tr>
+        <td>
+          <code>proxy</code>
+        </td>
+        <td>auto, virt, generic </td>
+        <td>
+          <dl>
+            <dt><code>auto</code></dt><dd>try virt-nc, fallback to netcat</dd>
+            <dt><code>netcat</code></dt><dd>only use netcat</dd>
+            <dt><code>virt-nc</code></dt><dd>only use virt-nc</dd>
+          </dl>
+          Can also be set in <code>libvirt.conf</code> as <code>remote_proxy</code>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="2"/>
+        <td> Example: <code>proxy=virt-nc</code> </td>
+      </tr>
       <tr>
         <td>
           <code>command</code>
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index c1f7a45aab..83789a86a9 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -761,12 +761,14 @@ doRemoteOpen(virConnectPtr conn,
     g_autofree char *knownHosts = NULL;
     g_autofree char *mode_str = NULL;
     g_autofree char *daemon_name = NULL;
+    g_autofree char *proxy_str = NULL;
     bool sanity = true;
     bool verify = true;
 #ifndef WIN32
     bool tty = true;
 #endif
     int mode;
+    int proxy;
 
     if (inside_daemon && !conn->uri->server) {
         mode = REMOTE_DRIVER_MODE_DIRECT;
@@ -774,6 +776,14 @@ doRemoteOpen(virConnectPtr conn,
         mode = REMOTE_DRIVER_MODE_AUTO;
     }
 
+    /* Historically we didn't allow ssh tunnel with session mode,
+     * since we can't construct the accurate path remotely,
+     * so we can default to modern virt-nc */
+    if (flags & VIR_DRV_OPEN_REMOTE_USER)
+        proxy = VIR_NET_CLIENT_PROXY_VIRT_NC;
+    else
+        proxy = VIR_NET_CLIENT_PROXY_NETCAT;
+
     /* We handle *ALL* URIs here. The caller has rejected any
      * URIs we don't care about */
 
@@ -813,6 +823,7 @@ doRemoteOpen(virConnectPtr conn,
             EXTRACT_URI_ARG_STR("known_hosts_verify", knownHostsVerify);
             EXTRACT_URI_ARG_STR("tls_priority", tls_priority);
             EXTRACT_URI_ARG_STR("mode", mode_str);
+            EXTRACT_URI_ARG_STR("proxy", proxy_str);
             EXTRACT_URI_ARG_BOOL("no_sanity", sanity);
             EXTRACT_URI_ARG_BOOL("no_verify", verify);
 #ifndef WIN32
@@ -865,6 +876,14 @@ doRemoteOpen(virConnectPtr conn,
         (mode = remoteDriverModeTypeFromString(mode_str)) < 0)
         goto failed;
 
+    if (conf && !proxy_str &&
+        virConfGetValueString(conf, "remote_proxy", &proxy_str) < 0)
+        goto failed;
+
+    if (proxy_str &&
+        (proxy = virNetClientProxyTypeFromString(proxy_str)) < 0)
+        goto failed;
+
     /* Sanity check that nothing requested !direct mode by mistake */
     if (inside_daemon && !conn->uri->server && mode != REMOTE_DRIVER_MODE_DIRECT) {
         virReportError(VIR_ERR_INVALID_ARG, "%s",
@@ -949,8 +968,11 @@ doRemoteOpen(virConnectPtr conn,
                                               knownHosts,
                                               knownHostsVerify,
                                               sshauth,
+                                              proxy,
                                               netcat,
                                               sockname,
+                                              name,
+                                              flags & VIR_DRV_OPEN_REMOTE_RO,
                                               auth,
                                               conn->uri);
         if (!priv->client)
@@ -970,8 +992,11 @@ doRemoteOpen(virConnectPtr conn,
                                              knownHosts,
                                              knownHostsVerify,
                                              sshauth,
+                                             proxy,
                                              netcat,
                                              sockname,
+                                             name,
+                                             flags & VIR_DRV_OPEN_REMOTE_RO,
                                              auth,
                                              conn->uri);
         if (!priv->client)
@@ -1011,8 +1036,11 @@ doRemoteOpen(virConnectPtr conn,
                                                 !tty,
                                                 !verify,
                                                 keyfile,
+                                                proxy,
                                                 netcat ? netcat : "nc",
-                                                sockname)))
+                                                sockname,
+                                                name,
+                                                flags & VIR_DRV_OPEN_REMOTE_RO)))
             goto failed;
 
         priv->is_secure = 1;
diff --git a/src/remote/remote_sockets.c b/src/remote/remote_sockets.c
index 854775f401..7c69ed9e7f 100644
--- a/src/remote/remote_sockets.c
+++ b/src/remote/remote_sockets.c
@@ -108,14 +108,6 @@ remoteGetUNIXSocketHelper(remoteDriverTransport transport,
     g_autofree char *userdir = NULL;
 
     if (session) {
-        if (transport != REMOTE_DRIVER_TRANSPORT_UNIX) {
-            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
-                           _("Connecting to session instance without "
-                             "socket path is not supported by the %s "
-                             "transport"),
-                           remoteDriverTransportTypeToString(transport));
-            return NULL;
-        }
         userdir = virGetUserRuntimeDirectory();
 
         sockname = g_strdup_printf("%s/%s-sock", userdir, sock_prefix);
diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index cd1bcc3ab3..5939f74e62 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -50,6 +50,10 @@ enum {
     VIR_NET_CLIENT_MODE_COMPLETE,
 };
 
+VIR_ENUM_IMPL(virNetClientProxy,
+              VIR_NET_CLIENT_PROXY_LAST,
+              "auto", "netcat", "virt-nc");
+
 struct _virNetClientCall {
     int mode;
 
@@ -414,20 +418,50 @@ virNetClientDoubleEscapeShell(const char *str)
 }
 
 char *
-virNetClientSSHHelperCommand(const char *netcatPath,
-                             const char *socketPath)
+virNetClientSSHHelperCommand(virNetClientProxy proxy,
+                             const char *netcatPath,
+                             const char *socketPath,
+                             const char *driverURI,
+                             bool readonly)
 {
     g_autofree char *netcatPathSafe = virNetClientDoubleEscapeShell(netcatPath);
+    g_autofree char *driverURISafe = virNetClientDoubleEscapeShell(driverURI);
+    g_autofree char *nccmd = NULL;
+    g_autofree char *virtnccmd = NULL;
 
-    return g_strdup_printf(
-        "sh -c "
-        "'if '%s' -q 2>&1 | grep \"requires an argument\" >/dev/null 2>&1; then "
-          "ARG=-q0;"
+    nccmd = g_strdup_printf(
+        "if '%s' -q 2>&1 | grep \"requires an argument\" >/dev/null 2>&1; then "
+            "ARG=-q0;"
         "else "
-          "ARG=;"
+            "ARG=;"
         "fi;"
-        "'%s' $ARG -U %s'",
+        "'%s' $ARG -U %s",
         netcatPathSafe, netcatPathSafe, socketPath);
+
+    virtnccmd = g_strdup_printf("%s '%s'",
+                                readonly ? "virt-nc -r" : "virt-nc",
+                                driverURISafe);
+
+    switch (proxy) {
+    case VIR_NET_CLIENT_PROXY_AUTO:
+        return g_strdup_printf("sh -c 'which virt-nc 1>/dev/null 2>&1; "
+                               "if test $? = 0; then "
+                               "    %s; "
+                               "else"
+                               "    %s; "
+                               "fi'", virtnccmd, nccmd);
+
+    case VIR_NET_CLIENT_PROXY_NETCAT:
+        return g_strdup_printf("sh -c '%s'", nccmd);
+
+    case VIR_NET_CLIENT_PROXY_VIRT_NC:
+        return g_strdup_printf("sh -c '%s'", virtnccmd);
+
+    case VIR_NET_CLIENT_PROXY_LAST:
+    default:
+        virReportEnumRangeError(virNetClientProxy, proxy);
+        return NULL;
+    }
 }
 
 
@@ -442,8 +476,11 @@ virNetClientPtr virNetClientNewSSH(const char *nodename,
                                    bool noTTY,
                                    bool noVerify,
                                    const char *keyfile,
+                                   virNetClientProxy proxy,
                                    const char *netcatPath,
-                                   const char *socketPath)
+                                   const char *socketPath,
+                                   const char *driverURI,
+                                   bool readonly)
 {
     virNetSocketPtr sock;
 
@@ -451,7 +488,8 @@ virNetClientPtr virNetClientNewSSH(const char *nodename,
 
     DEFAULT_VALUE(netcatPath, "nc");
 
-    command = virNetClientSSHHelperCommand(netcatPath, socketPath);
+    command = virNetClientSSHHelperCommand(proxy, netcatPath, socketPath,
+                                           driverURI, readonly);
 
     if (virNetSocketNewConnectSSH(nodename, service, binary, username, noTTY,
                                   noVerify, keyfile, command, &sock) < 0)
@@ -468,8 +506,11 @@ virNetClientPtr virNetClientNewLibSSH2(const char *host,
                                        const char *knownHostsPath,
                                        const char *knownHostsVerify,
                                        const char *authMethods,
+                                       virNetClientProxy proxy,
                                        const char *netcatPath,
                                        const char *socketPath,
+                                       const char *driverURI,
+                                       bool readonly,
                                        virConnectAuthPtr authPtr,
                                        virURIPtr uri)
 {
@@ -511,7 +552,8 @@ virNetClientPtr virNetClientNewLibSSH2(const char *host,
     DEFAULT_VALUE(netcatPath, "nc");
     DEFAULT_VALUE(knownHostsVerify, "normal");
 
-    command = virNetClientSSHHelperCommand(netcatPath, socketPath);
+    command = virNetClientSSHHelperCommand(proxy, netcatPath, socketPath,
+                                           driverURI, readonly);
 
     if (virNetSocketNewConnectLibSSH2(host, port,
                                       family,
@@ -531,8 +573,11 @@ virNetClientPtr virNetClientNewLibssh(const char *host,
                                       const char *knownHostsPath,
                                       const char *knownHostsVerify,
                                       const char *authMethods,
+                                      virNetClientProxy proxy,
                                       const char *netcatPath,
                                       const char *socketPath,
+                                      const char *driverURI,
+                                      bool readonly,
                                       virConnectAuthPtr authPtr,
                                       virURIPtr uri)
 {
@@ -574,7 +619,8 @@ virNetClientPtr virNetClientNewLibssh(const char *host,
     DEFAULT_VALUE(netcatPath, "nc");
     DEFAULT_VALUE(knownHostsVerify, "normal");
 
-    command = virNetClientSSHHelperCommand(netcatPath, socketPath);
+    command = virNetClientSSHHelperCommand(proxy, netcatPath, socketPath,
+                                           driverURI, readonly);
 
     if (virNetSocketNewConnectLibssh(host, port,
                                      family,
diff --git a/src/rpc/virnetclient.h b/src/rpc/virnetclient.h
index 6fdc370083..76500e2c3f 100644
--- a/src/rpc/virnetclient.h
+++ b/src/rpc/virnetclient.h
@@ -30,9 +30,22 @@
 #include "virobject.h"
 #include "viruri.h"
 
+typedef enum {
+    VIR_NET_CLIENT_PROXY_AUTO,
+    VIR_NET_CLIENT_PROXY_NETCAT,
+    VIR_NET_CLIENT_PROXY_VIRT_NC,
+
+    VIR_NET_CLIENT_PROXY_LAST,
+} virNetClientProxy;
+
+VIR_ENUM_DECL(virNetClientProxy);
+
 char *
-virNetClientSSHHelperCommand(const char *netcatPath,
-                             const char *socketPath);
+virNetClientSSHHelperCommand(virNetClientProxy proxy,
+                             const char *netcatPath,
+                             const char *socketPath,
+                             const char *driverURI,
+                             bool readonly);
 
 virNetClientPtr virNetClientNewUNIX(const char *path,
                                     bool spawnDaemon,
@@ -49,8 +62,11 @@ virNetClientPtr virNetClientNewSSH(const char *nodename,
                                    bool noTTY,
                                    bool noVerify,
                                    const char *keyfile,
-                                   const char *netcat,
-                                   const char *socketPath);
+                                   virNetClientProxy proxy,
+                                   const char *netcatPath,
+                                   const char *socketPath,
+                                   const char *driverURI,
+                                   bool readonly);
 
 virNetClientPtr virNetClientNewLibSSH2(const char *host,
                                        const char *port,
@@ -60,8 +76,11 @@ virNetClientPtr virNetClientNewLibSSH2(const char *host,
                                        const char *knownHostsPath,
                                        const char *knownHostsVerify,
                                        const char *authMethods,
+                                       virNetClientProxy proxy,
                                        const char *netcatPath,
                                        const char *socketPath,
+                                       const char *driverURI,
+                                       bool readonly,
                                        virConnectAuthPtr authPtr,
                                        virURIPtr uri);
 
@@ -73,8 +92,11 @@ virNetClientPtr virNetClientNewLibssh(const char *host,
                                       const char *knownHostsPath,
                                       const char *knownHostsVerify,
                                       const char *authMethods,
+                                      virNetClientProxy proxy,
                                       const char *netcatPath,
                                       const char *socketPath,
+                                      const char *driverURI,
+                                      bool readonly,
                                       virConnectAuthPtr authPtr,
                                       virURIPtr uri);
 
diff --git a/tests/virnetsockettest.c b/tests/virnetsockettest.c
index 842eb1bcfc..c6fbe479d7 100644
--- a/tests/virnetsockettest.c
+++ b/tests/virnetsockettest.c
@@ -464,8 +464,11 @@ static int testSocketSSH(const void *opaque)
     virNetSocketPtr csock = NULL; /* Client socket */
     int ret = -1;
     char buf[1024];
-    g_autofree char *command = virNetClientSSHHelperCommand(data->netcat,
-                                                            data->path);
+    g_autofree char *command = virNetClientSSHHelperCommand(VIR_NET_CLIENT_PROXY_AUTO,
+                                                            data->netcat,
+                                                            data->path,
+                                                            "qemu:///session",
+                                                            true);
 
     if (virNetSocketNewConnectSSH(data->nodename,
                                   data->service,
-- 
2.26.2




More information about the libvir-list mailing list