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(a)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