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(a)redhat.com>
---
docs/uri.html.in | 24 +++++++++-
src/remote/remote_driver.c | 30 +++++++++++-
src/remote/remote_sockets.c | 8 ----
src/rpc/virnetclient.c | 91 ++++++++++++++++++++++++++++++-------
src/rpc/virnetclient.h | 30 ++++++++++--
tests/virnetsockettest.c | 7 ++-
6 files changed, 156 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 d56f4b7260..3058849153 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..5ce6ffa686 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,64 @@ 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 user gave a 'netcat' path in the URI, we must
+ * assume they want the legacy 'nc' based proxy, not
+ * our new virt-ssh-helper
+ */
+ 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 +490,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 +519,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 +562,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 +583,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 +626,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