[libvirt PATCH v2 10/10] rpc: use new virt-ssh-helper binary for remote tunnelling

Daniel P. Berrangé berrange at redhat.com
Fri Jul 24 15:14:14 UTC 2020


This wires up support for using the new virt-ssh-helper 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=native

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

  qemu+ssh://host/session

and this will only use virt-ssh-helper, with no fallback. This also lets
the libvirtd process be auto-started, and connect directly to the
modular daemons, avoiding use of virtproxyd back-compat tunnelling.

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

diff --git a/docs/uri.html.in b/docs/uri.html.in
index 49f92773f8..4cce2d6a48 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 native, fallback to netcat</dd>
+            <dt><code>netcat</code></dt><dd>only use netcat</dd>
+            <dt><code>native</code></dt><dd>only use native</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=native</code> </td>
+      </tr>
       <tr>
         <td>
           <code>command</code>
@@ -296,8 +314,10 @@ Note that parameter values must be
         <td> ssh, libssh2, libssh </td>
         <td>
   The name of the netcat command on the remote machine.
-  The default is <code>nc</code>.  For ssh transport, libvirt
-  constructs an ssh command which looks like:
+  The default is <code>nc</code>. This is not permitted
+  when using the <code>native</code> proxy mode. For ssh
+  transport, libvirt constructs an ssh command which looks
+  like:
 
 <pre><i>command</i> -p <i>port</i> [-l <i>username</i>] <i>hostname</i> <i>netcat</i> -U <i>socket</i>
 </pre>
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 1c6a273520..d7d52234b0 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-ssh-helper */
+    if (flags & VIR_DRV_OPEN_REMOTE_USER)
+        proxy = VIR_NET_CLIENT_PROXY_NATIVE;
+    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,
-                                                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 72ece28f59..af2e80fdab 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", "native");
+
 struct _virNetClientCall {
     int mode;
 
@@ -414,23 +418,60 @@ virNetClientDoubleEscapeShell(const char *str)
 }
 
 char *
-virNetClientSSHHelperCommand(const char *netcatPath,
-                             const char *socketPath)
-{
-    g_autofree char *netcatPathSafe = virNetClientDoubleEscapeShell(netcatPath);
-
-    if (!netcatPath)
-        netcatPath = "nc";
+virNetClientSSHHelperCommand(virNetClientProxy proxy,
+                             const char *netcatPath,
+                             const char *socketPath,
+                             const char *driverURI,
+                             bool readonly)
+{
+    g_autofree char *netcatPathSafe = virNetClientDoubleEscapeShell(netcatPath ? netcatPath : "nc");
+    g_autofree char *driverURISafe = virNetClientDoubleEscapeShell(driverURI);
+    g_autofree char *nccmd = NULL;
+    g_autofree char *helpercmd = NULL;
+
+    if (proxy == VIR_NET_CLIENT_PROXY_AUTO &&
+        netcatPath != NULL) {
+        proxy = VIR_NET_CLIENT_PROXY_NETCAT;
+    }
 
-    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);
+
+    helpercmd = g_strdup_printf("virt-ssh-helper%s'%s'",
+                                readonly ? " -r " : " ",
+                                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'", helpercmd, nccmd);
+
+    case VIR_NET_CLIENT_PROXY_NETCAT:
+        return g_strdup_printf("sh -c '%s'", nccmd);
+
+    case VIR_NET_CLIENT_PROXY_NATIVE:
+        if (netcatPath) {
+            virReportError(VIR_ERR_INVALID_ARG, "%s",
+                           _("netcat path not valid with native proxy mode"));
+            return NULL;
+        }
+        return g_strdup_printf("sh -c '%s'", helpercmd);
+
+    case VIR_NET_CLIENT_PROXY_LAST:
+    default:
+        virReportEnumRangeError(virNetClientProxy, proxy);
+        return NULL;
+    }
 }
 
 
@@ -445,15 +486,19 @@ 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;
     g_autofree char *command = NULL;
 
     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)
@@ -470,8 +515,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)
 {
@@ -510,7 +558,8 @@ virNetClientPtr virNetClientNewLibSSH2(const char *host,
     DEFAULT_VALUE(username, "root");
     DEFAULT_VALUE(knownHostsVerify, "normal");
 
-    command = virNetClientSSHHelperCommand(netcatPath, socketPath);
+    command = virNetClientSSHHelperCommand(proxy, netcatPath, socketPath,
+                                           driverURI, readonly);
 
     if (virNetSocketNewConnectLibSSH2(host, port,
                                       family,
@@ -530,8 +579,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)
 {
@@ -570,7 +622,8 @@ virNetClientPtr virNetClientNewLibssh(const char *host,
     DEFAULT_VALUE(username, "root");
     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..4789316e32 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_NATIVE,
+
+    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 31fe1f86f4..93835af62f 100644
--- a/tests/virnetsockettest.c
+++ b/tests/virnetsockettest.c
@@ -469,8 +469,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