diff --git a/docs/uri.html.in b/docs/uri.html.in index 429768116b..e39d49c2ef 100644 --- a/docs/uri.html.in +++ b/docs/uri.html.in @@ -259,6 +259,24 @@ Note that parameter values must be Example: mode=direct + + + proxy + + auto, netcat, native + +
+
auto
try native, fallback to netcat
+
netcat
only use netcat
+
native
only use native
+
+ Can also be set in libvirt.conf as remote_proxy + + + + + Example: proxy=native + command @@ -296,8 +314,10 @@ Note that parameter values must be ssh, libssh2, libssh The name of the netcat command on the remote machine. - The default is nc. For ssh transport, libvirt - constructs an ssh command which looks like: + The default is nc. This is not permitted + when using the native proxy mode. For ssh + transport, libvirt constructs an ssh command which looks + like:
command -p port [-l username] hostname netcat -U socket
 
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index a5b820d7bf..97fff5971a 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -761,6 +761,7 @@ 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 @@ -768,6 +769,7 @@ doRemoteOpen(virConnectPtr conn, #endif int mode; size_t i; + int proxy; if (inside_daemon && !conn->uri->server) { mode = REMOTE_DRIVER_MODE_DIRECT; @@ -775,6 +777,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_AUTO; + /* We handle *ALL* URIs here. The caller has rejected any * URIs we don't care about */ @@ -812,6 +822,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 @@ -864,6 +875,17 @@ 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) { + virReportError(VIR_ERR_INVALID_ARG, + _("Unnkown proxy type '%s'"), proxy_str); + 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", @@ -948,8 +970,11 @@ doRemoteOpen(virConnectPtr conn, knownHosts, knownHostsVerify, sshauth, + proxy, netcat, sockname, + name, + flags & VIR_DRV_OPEN_REMOTE_RO, auth, conn->uri); if (!priv->client) @@ -969,8 +994,11 @@ doRemoteOpen(virConnectPtr conn, knownHosts, knownHostsVerify, sshauth, + proxy, netcat, sockname, + name, + flags & VIR_DRV_OPEN_REMOTE_RO, auth, conn->uri); if (!priv->client) @@ -1010,8 +1038,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 b1273fee8c..8c7c7a0f0a 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) +virNetClientSSHHelperCommand(virNetClientProxy proxy, + const char *netcatPath, + const char *socketPath, + const char *driverURI, + bool readonly) { - g_autofree char *netcatPathSafe = virNetClientDoubleEscapeShell(netcatPath); + 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 (!netcatPath) - netcatPath = "nc"; + /* 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,18 @@ 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); + if (!(command = virNetClientSSHHelperCommand(proxy, netcatPath, socketPath, + driverURI, readonly))) + return NULL; if (virNetSocketNewConnectSSH(nodename, service, binary, username, noTTY, noVerify, keyfile, command, &sock) < 0) @@ -470,8 +518,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 +561,9 @@ virNetClientPtr virNetClientNewLibSSH2(const char *host, DEFAULT_VALUE(username, "root"); DEFAULT_VALUE(knownHostsVerify, "normal"); - command = virNetClientSSHHelperCommand(netcatPath, socketPath); + if (!(command = virNetClientSSHHelperCommand(proxy, netcatPath, socketPath, + driverURI, readonly))) + return NULL; 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,9 @@ virNetClientPtr virNetClientNewLibssh(const char *host, DEFAULT_VALUE(username, "root"); DEFAULT_VALUE(knownHostsVerify, "normal"); - command = virNetClientSSHHelperCommand(netcatPath, socketPath); + if (!(command = virNetClientSSHHelperCommand(proxy, netcatPath, socketPath, + driverURI, readonly))) + return NULL; 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 e603cf2bf2..d6b461cbc8 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,