Merge pull request #1568 from fmcontrib/issue_420_proxy_aka_jumphost_support

SSH tunneling aka jumphost implemented
This commit is contained in:
Faryan Rezagholi
2020-05-21 11:16:15 +02:00
committed by GitHub
33 changed files with 3325 additions and 4552 deletions

View File

@@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
### Added
- #545: Option to minimize to system tray on closing
- #283: Support for native PowerShell remoting as new protocol
- #420: SSH tunneling implemented
### Changed
- #1460: Updated GeckoFX to v60
### Fixed

View File

@@ -66,5 +66,7 @@
public TType VNCViewOnly { get; set; }
public TType RdpVersion { get; set; }
public TType UseEnhancedMode { get; set; }
public TType SSHOptions { get; set; }
public TType SSHTunnelConnectionName { get; set; }
}
}

View File

@@ -248,6 +248,7 @@ namespace mRemoteNGTests.UI.Window.ConfigWindowTests
nameof(ConnectionInfo.MacAddress),
nameof(ConnectionInfo.UserField),
nameof(ConnectionInfo.Favorite),
nameof(ConnectionInfo.SSHTunnelConnectionName),
};
if (!isContainer)
@@ -308,6 +309,7 @@ namespace mRemoteNGTests.UI.Window.ConfigWindowTests
nameof(ConnectionInfo.Username),
nameof(ConnectionInfo.Password),
nameof(ConnectionInfo.Port),
nameof(ConnectionInfo.SSHOptions),
nameof(ConnectionInfo.PuttySession)
});
break;

View File

@@ -96,6 +96,10 @@ namespace mRemoteNG.Config.Serializers.Csv
connectionRecord.Domain = headers.Contains("Domain") ? connectionCsv[headers.IndexOf("Domain")] : "";
connectionRecord.Hostname = headers.Contains("Hostname") ? connectionCsv[headers.IndexOf("Hostname")] : "";
connectionRecord.VmId = headers.Contains("VmId") ? connectionCsv[headers.IndexOf("VmId")] : "";
connectionRecord.SSHOptions =
headers.Contains("SSHOptions") ? connectionCsv[headers.IndexOf("SSHOptions")] : "";
connectionRecord.SSHTunnelConnectionName =
headers.Contains("SSHTunnelConnectionName") ? connectionCsv[headers.IndexOf("SSHTunnelConnectionName")] : "";
connectionRecord.PuttySession = headers.Contains("PuttySession") ? connectionCsv[headers.IndexOf("PuttySession")] : "";
connectionRecord.LoadBalanceInfo = headers.Contains("LoadBalanceInfo")
? connectionCsv[headers.IndexOf("LoadBalanceInfo")]
@@ -480,6 +484,20 @@ namespace mRemoteNG.Config.Serializers.Csv
connectionRecord.Inheritance.Protocol = value;
}
if (headers.Contains("InheritSSHTunnelConnectionName"))
{
bool value;
if (bool.TryParse(connectionCsv[headers.IndexOf("InheritSSHTunnelConnectionName")], out value))
connectionRecord.Inheritance.SSHTunnelConnectionName = value;
}
if (headers.Contains("InheritSSHOptions"))
{
bool value;
if (bool.TryParse(connectionCsv[headers.IndexOf("InheritSSHOptions")], out value))
connectionRecord.Inheritance.SSHOptions = value;
}
if (headers.Contains("InheritPuttySession"))
{
bool value;

View File

@@ -56,7 +56,7 @@ namespace mRemoteNG.Config.Serializers.Csv
if (_saveFilter.SaveDomain)
sb.Append("Domain;");
sb.Append("Hostname;Port;VmId;Protocol;PuttySession;ConnectToConsole;UseCredSsp;UseVmId;UseEnhancedMode;RenderingEngine;ICAEncryptionStrength;RDPAuthenticationLevel;" +
sb.Append("Hostname;Port;VmId;Protocol;SSHTunnelConnectionName;SSHOptions;PuttySession;ConnectToConsole;UseCredSsp;UseVmId;UseEnhancedMode;RenderingEngine;ICAEncryptionStrength;RDPAuthenticationLevel;" +
"LoadBalanceInfo;Colors;Resolution;AutomaticResize;DisplayWallpaper;DisplayThemes;EnableFontSmoothing;EnableDesktopComposition;" +
"CacheBitmaps;RedirectDiskDrives;RedirectPorts;RedirectPrinters;RedirectClipboard;RedirectSmartCards;RedirectSound;RedirectKeys;" +
"PreExtApp;PostExtApp;MacAddress;UserField;ExtApp;Favorite;VNCCompression;VNCEncoding;VNCAuthMode;VNCProxyType;VNCProxyIP;" +
@@ -66,7 +66,7 @@ namespace mRemoteNG.Config.Serializers.Csv
if (_saveFilter.SaveInheritance)
sb.Append("InheritCacheBitmaps;InheritColors;InheritDescription;InheritDisplayThemes;InheritDisplayWallpaper;" +
"InheritEnableFontSmoothing;InheritEnableDesktopComposition;InheritDomain;InheritIcon;InheritPanel;InheritPassword;InheritPort;" +
"InheritProtocol;InheritPuttySession;InheritRedirectDiskDrives;InheritRedirectKeys;InheritRedirectPorts;InheritRedirectPrinters;" +
"InheritProtocol;InheritSSHTunnelConnectionName;InheritSSHOptions;InheritPuttySession;InheritRedirectDiskDrives;InheritRedirectKeys;InheritRedirectPorts;InheritRedirectPrinters;" +
"InheritRedirectClipboard;InheritRedirectSmartCards;InheritRedirectSound;InheritResolution;InheritAutomaticResize;" +
"InheritUseConsoleSession;InheritUseCredSsp;InheritUseVmId;InheritUseEnhancedMode;InheritVmId;InheritRenderingEngine;InheritUsername;InheritICAEncryptionStrength;" +
"InheritRDPAuthenticationLevel;InheritLoadBalanceInfo;InheritPreExtApp;InheritPostExtApp;InheritMacAddress;InheritUserField;" +
@@ -119,6 +119,8 @@ namespace mRemoteNG.Config.Serializers.Csv
.Append(FormatForCsv(con.Port))
.Append(FormatForCsv(con.VmId))
.Append(FormatForCsv(con.Protocol))
.Append(FormatForCsv(con.SSHTunnelConnectionName))
.Append(FormatForCsv(con.SSHOptions))
.Append(FormatForCsv(con.PuttySession))
.Append(FormatForCsv(con.UseConsoleSession))
.Append(FormatForCsv(con.UseCredSsp))
@@ -186,6 +188,8 @@ namespace mRemoteNG.Config.Serializers.Csv
.Append(FormatForCsv(con.Inheritance.Password))
.Append(FormatForCsv(con.Inheritance.Port))
.Append(FormatForCsv(con.Inheritance.Protocol))
.Append(FormatForCsv(con.Inheritance.SSHTunnelConnectionName))
.Append(FormatForCsv(con.Inheritance.SSHOptions))
.Append(FormatForCsv(con.Inheritance.PuttySession))
.Append(FormatForCsv(con.Inheritance.RedirectDiskDrives))
.Append(FormatForCsv(con.Inheritance.RedirectKeys))

View File

@@ -91,6 +91,8 @@ namespace mRemoteNG.Config.Serializers.MsSql
connectionInfo.VmId = (string)dataRow["VmId"];
connectionInfo.UseEnhancedMode = (bool)dataRow["UseEnhancedMode"];
connectionInfo.Protocol = (ProtocolType)Enum.Parse(typeof(ProtocolType), (string)dataRow["Protocol"]);
connectionInfo.SSHTunnelConnectionName = (string)dataRow["SSHTunnelConnectionName"];
connectionInfo.SSHOptions = (string)dataRow["SSHOptions"];
connectionInfo.PuttySession = (string)dataRow["PuttySession"];
connectionInfo.Port = (int)dataRow["Port"];
connectionInfo.UseConsoleSession = (bool)dataRow["ConnectToConsole"];
@@ -181,6 +183,8 @@ namespace mRemoteNG.Config.Serializers.MsSql
connectionInfo.Inheritance.Password = (bool)dataRow["InheritPassword"];
connectionInfo.Inheritance.Port = (bool)dataRow["InheritPort"];
connectionInfo.Inheritance.Protocol = (bool)dataRow["InheritProtocol"];
connectionInfo.Inheritance.SSHTunnelConnectionName = (bool)dataRow["InheritSSHTunnelConnectionName"];
connectionInfo.Inheritance.SSHOptions = (bool)dataRow["InheritSSHOptions"];
connectionInfo.Inheritance.PuttySession = (bool)dataRow["InheritPuttySession"];
connectionInfo.Inheritance.RedirectDiskDrives = (bool)dataRow["InheritRedirectDiskDrives"];
connectionInfo.Inheritance.RedirectKeys = (bool)dataRow["InheritRedirectKeys"];

View File

@@ -109,9 +109,11 @@ namespace mRemoteNG.Config.Serializers.MsSql
dataTable.Columns.Add("DomainName", typeof(string));
dataTable.Columns.Add("Password", typeof(string));
dataTable.Columns.Add("Hostname", typeof(string));
dataTable.Columns.Add("Protocol", typeof(string));
dataTable.Columns.Add("PuttySession", typeof(string));
dataTable.Columns.Add("Port", typeof(int));
dataTable.Columns.Add("Protocol", typeof(string));
dataTable.Columns.Add("SSHTunnelConnectionName", typeof(string));
dataTable.Columns.Add("SSHOptions", typeof(string));
dataTable.Columns.Add("PuttySession", typeof(string));
dataTable.Columns.Add("ConnectToConsole", typeof(bool));
dataTable.Columns.Add("UseCredSsp", typeof(bool));
dataTable.Columns.Add("RenderingEngine", typeof(string));
@@ -168,6 +170,8 @@ namespace mRemoteNG.Config.Serializers.MsSql
dataTable.Columns.Add("InheritPassword", typeof(bool));
dataTable.Columns.Add("InheritPort", typeof(bool));
dataTable.Columns.Add("InheritProtocol", typeof(bool));
dataTable.Columns.Add("InheritSSHTunnelConnectionName", typeof(bool));
dataTable.Columns.Add("InheritSSHOptions", typeof(bool));
dataTable.Columns.Add("InheritPuttySession", typeof(bool));
dataTable.Columns.Add("InheritRedirectDiskDrives", typeof(bool));
dataTable.Columns.Add("InheritRedirectKeys", typeof(bool));
@@ -497,6 +501,8 @@ namespace mRemoteNG.Config.Serializers.MsSql
dataRow["Hostname"] = connectionInfo.Hostname;
dataRow["VmId"] = connectionInfo.VmId;
dataRow["Protocol"] = connectionInfo.Protocol;
dataRow["SSHTunnelConnectionName"] = connectionInfo.SSHTunnelConnectionName;
dataRow["SSHOptions"] = connectionInfo.SSHOptions;
dataRow["PuttySession"] = connectionInfo.PuttySession;
dataRow["Port"] = connectionInfo.Port;
dataRow["ConnectToConsole"] = connectionInfo.UseConsoleSession;
@@ -568,6 +574,8 @@ namespace mRemoteNG.Config.Serializers.MsSql
dataRow["InheritPassword"] = connectionInfo.Inheritance.Password;
dataRow["InheritPort"] = connectionInfo.Inheritance.Port;
dataRow["InheritProtocol"] = connectionInfo.Inheritance.Protocol;
dataRow["InheritSSHTunnelConnectionName"] = connectionInfo.Inheritance.SSHTunnelConnectionName;
dataRow["InheritSSHOptions"] = connectionInfo.Inheritance.SSHOptions;
dataRow["InheritPuttySession"] = connectionInfo.Inheritance.PuttySession;
dataRow["InheritRedirectDiskDrives"] = connectionInfo.Inheritance.RedirectDiskDrives;
dataRow["InheritRedirectKeys"] = connectionInfo.Inheritance.RedirectKeys;
@@ -631,6 +639,8 @@ namespace mRemoteNG.Config.Serializers.MsSql
dataRow["InheritPassword"] = false;
dataRow["InheritPort"] = false;
dataRow["InheritProtocol"] = false;
dataRow["InheritSSHTunnelConnectionName"] = false;
dataRow["InheritSSHOptions"] = false;
dataRow["InheritPuttySession"] = false;
dataRow["InheritRedirectDiskDrives"] = false;
dataRow["InheritRedirectKeys"] = false;

View File

@@ -68,6 +68,8 @@ namespace mRemoteNG.Config.Serializers.Xml
element.Add(new XAttribute("Hostname", connectionInfo.Hostname));
element.Add(new XAttribute("Protocol", connectionInfo.Protocol));
element.Add(new XAttribute("SSHTunnelConnectionName", connectionInfo.SSHTunnelConnectionName));
element.Add(new XAttribute("SSHOptions", connectionInfo.SSHOptions));
element.Add(new XAttribute("PuttySession", connectionInfo.PuttySession));
element.Add(new XAttribute("Port", connectionInfo.Port));
element.Add(new XAttribute("ConnectToConsole",
@@ -185,6 +187,10 @@ namespace mRemoteNG.Config.Serializers.Xml
connectionInfo.Inheritance.Port.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritProtocol",
connectionInfo.Inheritance.Protocol.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritSSHTunnelConnectionName",
connectionInfo.Inheritance.SSHTunnelConnectionName.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritSSHOptions",
connectionInfo.Inheritance.SSHOptions.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritPuttySession",
connectionInfo.Inheritance.PuttySession.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRedirectDiskDrives",
@@ -293,6 +299,8 @@ namespace mRemoteNG.Config.Serializers.Xml
element.Add(new XAttribute("InheritPassword", falseString));
element.Add(new XAttribute("InheritPort", falseString));
element.Add(new XAttribute("InheritProtocol", falseString));
element.Add(new XAttribute("InheritSSHTunnelConnectionName", falseString));
element.Add(new XAttribute("InheritSSHOptions", falseString));
element.Add(new XAttribute("InheritPuttySession", falseString));
element.Add(new XAttribute("InheritRedirectDiskDrives", falseString));
element.Add(new XAttribute("InheritRedirectKeys", falseString));

View File

@@ -76,6 +76,8 @@ namespace mRemoteNG.Config.Serializers.Xml
element.Add(new XAttribute("Hostname", connectionInfo.Hostname));
element.Add(new XAttribute("Protocol", connectionInfo.Protocol));
element.Add(new XAttribute("RdpVersion", connectionInfo.RdpVersion.ToString().ToLowerInvariant()));
element.Add(new XAttribute("SSHTunnelConnectionName", connectionInfo.SSHTunnelConnectionName));
element.Add(new XAttribute("SSHOptions", connectionInfo.SSHOptions));
element.Add(new XAttribute("PuttySession", connectionInfo.PuttySession));
element.Add(new XAttribute("Port", connectionInfo.Port));
element.Add(new XAttribute("ConnectToConsole",
@@ -197,6 +199,10 @@ namespace mRemoteNG.Config.Serializers.Xml
connectionInfo.Inheritance.Protocol.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRdpVersion",
connectionInfo.Inheritance.RdpVersion.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritSSHTunnelConnectionName",
connectionInfo.Inheritance.SSHTunnelConnectionName.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritSSHOptions",
connectionInfo.Inheritance.SSHOptions.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritPuttySession",
connectionInfo.Inheritance.PuttySession.ToString().ToLowerInvariant()));
element.Add(new XAttribute("InheritRedirectDiskDrives",
@@ -316,6 +322,8 @@ namespace mRemoteNG.Config.Serializers.Xml
element.Add(new XAttribute("InheritPassword", falseString));
element.Add(new XAttribute("InheritPort", falseString));
element.Add(new XAttribute("InheritProtocol", falseString));
element.Add(new XAttribute("InheritSSHTunnelConnectionName", falseString));
element.Add(new XAttribute("InheritSSHOptions", falseString));
element.Add(new XAttribute("InheritPuttySession", falseString));
element.Add(new XAttribute("InheritRedirectDiskDrives", falseString));
element.Add(new XAttribute("InheritRedirectKeys", falseString));

View File

@@ -533,8 +533,7 @@ namespace mRemoteNG.Config.Serializers.Xml
xmlnode.GetAttributeAsBool("InheritRDPMinutesToIdleTimeout");
connectionInfo.RDPAlertIdleTimeout = xmlnode.GetAttributeAsBool("RDPAlertIdleTimeout");
connectionInfo.Inheritance.RDPAlertIdleTimeout =
xmlnode.GetAttributeAsBool("InheritRDPAlertIdleTimeout");
}
xmlnode.GetAttributeAsBool("InheritRDPAlertIdleTimeout"); }
if (_confVersion >= 2.7)
{
@@ -543,13 +542,17 @@ namespace mRemoteNG.Config.Serializers.Xml
connectionInfo.UseVmId = xmlnode.GetAttributeAsBool("UseVmId");
connectionInfo.VmId = xmlnode.GetAttributeAsString("VmId");
connectionInfo.UseEnhancedMode = xmlnode.GetAttributeAsBool("UseEnhancedMode");
connectionInfo.RdpVersion = xmlnode.GetAttributeAsEnum("RdpVersion", RdpVersion.Highest);
connectionInfo.SSHTunnelConnectionName = xmlnode.GetAttributeAsString("SSHTunnelConnectionName");
connectionInfo.SSHOptions = xmlnode.GetAttributeAsString("SSHOptions");
connectionInfo.Inheritance.RedirectClipboard = xmlnode.GetAttributeAsBool("InheritRedirectClipboard");
connectionInfo.Inheritance.Favorite = xmlnode.GetAttributeAsBool("InheritFavorite");
connectionInfo.RdpVersion = xmlnode.GetAttributeAsEnum("RdpVersion", RdpVersion.Highest);
connectionInfo.Inheritance.RdpVersion = xmlnode.GetAttributeAsBool("InheritRdpVersion");
connectionInfo.Inheritance.UseVmId = xmlnode.GetAttributeAsBool("InheritUseVmId");
connectionInfo.Inheritance.VmId = xmlnode.GetAttributeAsBool("InheritVmId");
connectionInfo.Inheritance.UseEnhancedMode = xmlnode.GetAttributeAsBool("InheritUseEnhancedMode");
connectionInfo.Inheritance.SSHTunnelConnectionName = xmlnode.GetAttributeAsBool("InheritSSHTunnelConnectionName");
connectionInfo.Inheritance.SSHOptions = xmlnode.GetAttributeAsBool("InheritSSHOptions");
}
}
catch (Exception ex)

View File

@@ -27,11 +27,15 @@ namespace mRemoteNG.Config.Serializers.Versioning
ALTER TABLE tblCons
ADD RedirectClipboard bit NOT NULL DEFAULT 0,
InheritRedirectClipboard bit NOT NULL DEFAULT 0,
VmId varchar NOT NULL DEFAULT 0,
VmId varchar NOT NULL DEFAULT '',
UseVmId bit NOT NULL DEFAULT 0,
UseEnhancedMode bit NOT NULL DEFAULT 0,
InheritVmId bit NOT NULL DEFAULT 0,
InheritUseVmId bit NOT NULL DEFAULT 0,
SSHTunnelConnectionName varchar NOT NULL DEFAULT '',
InheritSSHTunnelConnectionName bit NOT NULL DEFAULT 0,
SSHOptions varchar NOT NULL DEFAULT '',
InheritSSHOptions bit NOT NULL DEFAULT 0,
InheritUseEnhancedMode bit NOT NULL DEFAULT 0;
UPDATE tblRoot
SET ConfVersion='2.7'";

View File

@@ -27,10 +27,12 @@ namespace mRemoteNG.Connection
private string _vmId = "";
private bool _useEnhancedMode;
private string _sshTunnelConnectionName = "";
private ProtocolType _protocol;
private RdpVersion _rdpProtocolVersion;
private string _extApp;
private int _port;
private string _sshOptions = "";
private string _puttySession;
private IcaProtocol.EncryptionStrength _icaEncryption;
private bool _useConsoleSession;
@@ -194,6 +196,16 @@ namespace mRemoteNG.Connection
set => SetField(ref _vmId, value?.Trim(), "VmId");
}
[LocalizedAttributes.LocalizedCategory(nameof(Language.strCategoryConnection), 2),
LocalizedAttributes.LocalizedDisplayName(nameof(Language.strPropertyNameSSHTunnelConnection)),
LocalizedAttributes.LocalizedDescription(nameof(Language.strPropertyDescriptionSSHTunnelConnection)),
TypeConverter(typeof(SshTunnelTypeConverter)),
UsedInAllProtocolsExcept()]
public string SSHTunnelConnectionName
{
get => GetPropertyValue("SSHTunnelConnectionName", _sshTunnelConnectionName).Trim();
set => SetField(ref _sshTunnelConnectionName, value?.Trim(), "SSHTunnelConnectionName");
}
#endregion
#region Protocol
@@ -242,6 +254,16 @@ namespace mRemoteNG.Connection
set => SetField(ref _puttySession, value, "PuttySession");
}
[LocalizedAttributes.LocalizedCategory(nameof(Language.strCategoryProtocol), 3),
LocalizedAttributes.LocalizedDisplayName(nameof(Language.strPropertyNameSSHOptions)),
LocalizedAttributes.LocalizedDescription(nameof(Language.strPropertyDescriptionSSHOptions)),
UsedInProtocol(ProtocolType.SSH1, ProtocolType.SSH2)]
public virtual string SSHOptions
{
get => GetPropertyValue("SSHOptions", _sshOptions);
set => SetField(ref _sshOptions, value, "SSHOptions");
}
[LocalizedAttributes.LocalizedCategory(nameof(Language.strCategoryProtocol), 3),
LocalizedAttributes.LocalizedDisplayName(nameof(Language.strPropertyNameEncryptionStrength)),
LocalizedAttributes.LocalizedDescription(nameof(Language.strPropertyDescriptionEncryptionStrength)),

View File

@@ -83,6 +83,13 @@ namespace mRemoteNG.Connection
LocalizedAttributes.LocalizedDescriptionInherit(nameof(Language.strPropertyDescriptionPort)),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool Port { get; set; }
[LocalizedAttributes.LocalizedCategory(nameof(Language.strCategoryConnection), 3),
LocalizedAttributes.LocalizedDisplayNameInheritAttribute(nameof(Language.strPropertyNameSSHTunnelConnection)),
LocalizedAttributes.LocalizedDescriptionInheritAttribute(nameof(Language.strPropertyDescriptionSSHTunnelConnection)),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
[Browsable(true)]
public bool SSHTunnelConnectionName { get; set; }
#endregion
@@ -112,6 +119,12 @@ namespace mRemoteNG.Connection
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool PuttySession { get; set; }
[LocalizedAttributes.LocalizedCategory(nameof(Language.strCategoryProtocol), 4),
LocalizedAttributes.LocalizedDisplayNameInherit(nameof(Language.strPropertyNameSSHOptions)),
LocalizedAttributes.LocalizedDescriptionInherit(nameof(Language.strPropertyDescriptionSSHOptions)),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool SSHOptions { get; set; }
[LocalizedAttributes.LocalizedCategory(nameof(Language.strCategoryProtocol), 4),
LocalizedAttributes.LocalizedDisplayNameInherit(nameof(Language.strPropertyNameEncryptionStrength)),
LocalizedAttributes.LocalizedDescriptionInherit(nameof(Language.strPropertyDescriptionEncryptionStrength)),

View File

@@ -5,6 +5,8 @@ using mRemoteNG.App;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container;
using mRemoteNG.Messages;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNG.UI.Forms;
using mRemoteNG.UI.Panels;
using mRemoteNG.UI.Tabs;
@@ -49,7 +51,8 @@ namespace mRemoteNG.Connection
}
}
public void OpenConnection(
// async is necessary so UI can update while OpenConnection waits for tunnel connection to get ready in case of connection through SSH tunnel
public async void OpenConnection(
ConnectionInfo connectionInfo,
ConnectionInfo.Force force = ConnectionInfo.Force.None,
ConnectionWindow conForm = null)
@@ -75,15 +78,137 @@ namespace mRemoteNG.Connection
}
var protocolFactory = new ProtocolFactory();
var newProtocol = protocolFactory.CreateProtocol(connectionInfo);
var connectionPanel = SetConnectionPanel(connectionInfo, force);
if (string.IsNullOrEmpty(connectionPanel)) return;
var connectionForm = SetConnectionForm(conForm, connectionPanel);
var connectionContainer = SetConnectionContainer(connectionInfo, connectionForm);
Control connectionContainer = null;
// Handle connection through SSH tunnel:
// in case of connection through SSH tunnel, connectionInfo gets cloned, so that modification of its name, hostname and port do not modify the original connection info
// connectionInfoOriginal points to the original connection info in either case, for where its needed later on.
var connectionInfoOriginal = connectionInfo;
ConnectionInfo connectionInfoSshTunnel = null; // SSH tunnel connection info will be set if SSH tunnel connection is configured, can be found and connected.
if (!string.IsNullOrEmpty(connectionInfoOriginal.SSHTunnelConnectionName))
{
// Find the connection info specified as SSH tunnel in the connections tree
connectionInfoSshTunnel = getSSHConnectionInfoByName(Runtime.ConnectionsService.ConnectionTreeModel.RootNodes, connectionInfoOriginal.SSHTunnelConnectionName);
if (connectionInfoSshTunnel == null)
{
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg,
string.Format(Language.strSSHTunnelConfigProblem, connectionInfoOriginal.Name, connectionInfoOriginal.SSHTunnelConnectionName));
return;
}
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg,
$"SSH Tunnel connection '{connectionInfoOriginal.SSHTunnelConnectionName}' configured for '{connectionInfoOriginal.Name}' found. Finding free local port for use as local tunnel port ...");
// determine a free local port to use as local tunnel port
var l = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Loopback, 0);
l.Start();
var localSshTunnelPort = ((System.Net.IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg,
$"{localSshTunnelPort} will be used as local tunnel port. Establishing SSH connection to '{connectionInfoSshTunnel.Hostname}' with additional tunnel options for target connection ...");
// clone SSH tunnel connection as tunnel options will be added to it, and those changes shall not be saved to the configuration
connectionInfoSshTunnel = connectionInfoSshTunnel.Clone();
connectionInfoSshTunnel.SSHOptions += " -L " + localSshTunnelPort + ":" + connectionInfoOriginal.Hostname + ":" + connectionInfoOriginal.Port;
// clone target connection info as its hostname will be changed to localhost and port to local tunnel port to establish connection through tunnel, and those changes shall not be saved to the configuration
connectionInfo = connectionInfoOriginal.Clone();
connectionInfo.Name += " via " + connectionInfoSshTunnel.Name;
connectionInfo.Hostname = "localhost";
connectionInfo.Port = localSshTunnelPort;
// connect the SSH connection to setup the tunnel
var protocolSshTunnel = protocolFactory.CreateProtocol(connectionInfoSshTunnel);
if (!(protocolSshTunnel is PuttyBase puttyBaseSshTunnel))
{
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg,
string.Format(Language.strSSHTunnelIsNotPutty, connectionInfoOriginal.Name, connectionInfoSshTunnel.Name));
return;
}
SetConnectionFormEventHandlers(protocolSshTunnel, connectionForm);
SetConnectionEventHandlers(protocolSshTunnel);
connectionContainer = SetConnectionContainer(connectionInfo, connectionForm);
BuildConnectionInterfaceController(connectionInfoSshTunnel, protocolSshTunnel, connectionContainer);
protocolSshTunnel.InterfaceControl.OriginalInfo = connectionInfoSshTunnel;
if (protocolSshTunnel.Initialize() == false)
{
protocolSshTunnel.Close();
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg,
string.Format(Language.strSSHTunnelNotInitialized, connectionInfoOriginal.Name, connectionInfoSshTunnel.Name));
return;
}
if (protocolSshTunnel.Connect() == false)
{
protocolSshTunnel.Close();
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg,
string.Format(Language.strSSHTunnelNotConnected, connectionInfoOriginal.Name, connectionInfoSshTunnel.Name));
return;
}
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg,
"Putty started for SSH connection for tunnel. Waiting for local tunnel port to become available ...");
// wait until SSH tunnel connection is ready, by checking if local port can be connected to, but max 60 sec.
var testsock = new System.Net.Sockets.Socket(System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
while (stopwatch.ElapsedMilliseconds < 60000)
{
// confirm that SSH connection is still active
// works only if putty is connfigured to always close window on exit
// else, if connection attempt fails, window remains open and putty process remains running, and we cannot know that connection is already doomed
// in this case the timeout will expire and the log message below will be created
// awkward for user as he has already acknowledged the putty popup some seconds again when the below notification comes....
if (!puttyBaseSshTunnel.isRunning())
{
protocolSshTunnel.Close();
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg,
string.Format(Language.strSSHTunnelFailed, connectionInfoOriginal.Name, connectionInfoSshTunnel.Name));
return;
}
try
{
testsock.Connect(System.Net.IPAddress.Loopback, localSshTunnelPort);
testsock.Close();
break;
}
catch (Exception e)
{
await System.Threading.Tasks.Task.Delay(1000);
}
}
if (stopwatch.ElapsedMilliseconds >= 60000)
{
protocolSshTunnel.Close();
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg,
string.Format(Language.strSSHTunnelPortNotReadyInTime, connectionInfoOriginal.Name, connectionInfoSshTunnel.Name));
return;
}
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg,
"Local tunnel port is now available. Hiding putty display and setting up target connection via local tunnel port ...");
// hide the display of the SSH tunnel connection which has been shown until this time, such that password can be entered if required or errors be seen
// it stays invisible in the container however which will be reused for the actual connection and such that if the container is closed the SSH tunnel connection is closed as well
protocolSshTunnel.InterfaceControl.Hide();
}
var newProtocol = protocolFactory.CreateProtocol(connectionInfo);
SetConnectionFormEventHandlers(newProtocol, connectionForm);
SetConnectionEventHandlers(newProtocol);
// in case of connection through SSH tunnel the container is already defined and must be use, else it needs to be created here
if (connectionContainer == null) connectionContainer = SetConnectionContainer(connectionInfo, connectionForm);
BuildConnectionInterfaceController(connectionInfo, newProtocol, connectionContainer);
// in case of connection through SSH tunnel the connectionInfo was modified but connectionInfoOriginal in all cases retains the original info
// and is stored in interface control for further use
newProtocol.InterfaceControl.OriginalInfo = connectionInfoOriginal;
// SSH tunnel connection is stored in Interface Control to be used in log messages etc
newProtocol.InterfaceControl.SSHTunnelInfo = connectionInfoSshTunnel;
newProtocol.Force = force;
@@ -99,7 +224,7 @@ namespace mRemoteNG.Connection
return;
}
connectionInfo.OpenConnections.Add(newProtocol);
connectionInfoOriginal.OpenConnections.Add(newProtocol);
_activeConnections.Add(connectionInfo.ConstantID);
FrmMain.Default.SelectedConnection = connectionInfo;
}
@@ -109,6 +234,25 @@ namespace mRemoteNG.Connection
}
}
// recursively traverse the tree to find ConnectionInfo of a specific name
private ConnectionInfo getSSHConnectionInfoByName(IEnumerable<ConnectionInfo> rootnodes, string SSHTunnelConnectionName)
{
ConnectionInfo result = null;
foreach (var node in rootnodes)
{
if (node is ContainerInfo container)
{
result = getSSHConnectionInfoByName(container.Children, SSHTunnelConnectionName);
}
else
{
if (node.Name == SSHTunnelConnectionName && (node.Protocol == ProtocolType.SSH1 || node.Protocol == ProtocolType.SSH2)) result = node;
}
if (result != null) break;
}
return result;
}
#region Private
private static void StartPreConnectionExternalApp(ConnectionInfo connectionInfo)
{
@@ -132,7 +276,7 @@ namespace mRemoteNG.Connection
var tab = (ConnectionTab)dockContent;
var ic = InterfaceControl.FindInterfaceControl(tab);
if (ic == null) continue;
if (ic.Info == connectionInfo)
if (ic.Info == connectionInfo || ic.OriginalInfo == connectionInfo)
return ic;
}
}
@@ -221,11 +365,16 @@ namespace mRemoteNG.Connection
}
}
var strHostname = prot.InterfaceControl.OriginalInfo.Hostname;
if (prot.InterfaceControl.SSHTunnelInfo != null)
{
strHostname += " via SSH Tunnel " + prot.InterfaceControl.SSHTunnelInfo.Name;
}
Runtime.MessageCollector.AddMessage(msgClass,
string.Format(
Language.strProtocolEventDisconnected,
disconnectedMessage,
prot.InterfaceControl.Info.Hostname,
strHostname,
prot.InterfaceControl.Info.Protocol.ToString()));
}
catch (Exception ex)
@@ -242,11 +391,11 @@ namespace mRemoteNG.Connection
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strConnenctionCloseEvent,
true);
string connDetail;
if (prot.InterfaceControl.Info.Hostname == "" &&
if (prot.InterfaceControl.OriginalInfo.Hostname == "" &&
prot.InterfaceControl.Info.Protocol == ProtocolType.IntApp)
connDetail = prot.InterfaceControl.Info.ExtApp;
else if (prot.InterfaceControl.Info.Hostname != "")
connDetail = prot.InterfaceControl.Info.Hostname;
else if (prot.InterfaceControl.OriginalInfo.Hostname != "")
connDetail = prot.InterfaceControl.OriginalInfo.Hostname;
else
connDetail = "UNKNOWN";
@@ -254,13 +403,13 @@ namespace mRemoteNG.Connection
string.Format(Language.strConnenctionClosedByUser, connDetail,
prot.InterfaceControl.Info.Protocol,
Environment.UserName));
prot.InterfaceControl.Info.OpenConnections.Remove(prot);
prot.InterfaceControl.OriginalInfo.OpenConnections.Remove(prot);
if (_activeConnections.Contains(prot.InterfaceControl.Info.ConstantID))
_activeConnections.Remove(prot.InterfaceControl.Info.ConstantID);
if (prot.InterfaceControl.Info.PostExtApp == "") return;
var extA = Runtime.ExternalToolsService.GetExtAppByName(prot.InterfaceControl.Info.PostExtApp);
extA?.Start(prot.InterfaceControl.Info);
extA?.Start(prot.InterfaceControl.OriginalInfo);
}
catch (Exception ex)
{
@@ -275,7 +424,7 @@ namespace mRemoteNG.Connection
true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg,
string.Format(Language.strConnectionEventConnectedDetail,
prot.InterfaceControl.Info.Hostname,
prot.InterfaceControl.OriginalInfo.Hostname,
prot.InterfaceControl.Info.Protocol, Environment.UserName,
prot.InterfaceControl.Info.Description,
prot.InterfaceControl.Info.UserField));
@@ -290,7 +439,7 @@ namespace mRemoteNG.Connection
var msg = string.Format(
Language.strConnectionEventErrorOccured,
errorMessage,
prot.InterfaceControl.Info.Hostname,
prot.InterfaceControl.OriginalInfo.Hostname,
errorCode?.ToString() ?? "-");
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, msg);
}

View File

@@ -1,4 +1,4 @@
using mRemoteNG.App;
using mRemoteNG.App;
using mRemoteNG.Connection.Protocol;
using System;
using System.Drawing;
@@ -13,6 +13,11 @@ namespace mRemoteNG.Connection
{
public ProtocolBase Protocol { get; set; }
public ConnectionInfo Info { get; set; }
// in case the connection is through a SSH tunnel the Info is a copy of original info with hostname and port number overwritten with localhost and local tunnel port
// and the original Info is saved in the following variable
public ConnectionInfo OriginalInfo { get; set; }
// in case the connection is through a SSH tunnel the Info of the SSHTunnelConnection is also saved for reference in log messages etc.
public ConnectionInfo SSHTunnelInfo { get; set; }
public InterfaceControl(Control parent, ProtocolBase protocol, ConnectionInfo info)
@@ -37,19 +42,24 @@ namespace mRemoteNG.Connection
public static InterfaceControl FindInterfaceControl(DockPanel DockPnl)
{
if (!(DockPnl.ActiveDocument is ConnectionTab ct)) return null;
if (ct.Controls.Count < 1) return null;
if (ct.Controls[0] is InterfaceControl ic)
return ic;
// instead of repeating the code, call the routine using ConnectionTab if called by DockPanel
if (DockPnl.ActiveDocument is ConnectionTab ct)
return FindInterfaceControl(ct);
return null;
}
public static InterfaceControl FindInterfaceControl(ConnectionTab tab)
{
if (tab.Controls.Count < 1) return null;
if (tab.Controls[0] is InterfaceControl ic)
return ic;
// if the tab has more than one controls and the second is an InterfaceControl than it must be a connection through SSH tunnel
// and the first Control is the SSH tunnel connection and thus the second control must be returned.
if (tab.Controls.Count > 1)
{
if (tab.Controls[1] is InterfaceControl ic1)
return ic1;
}
if (tab.Controls[0] is InterfaceControl ic0)
return ic0;
return null;
}

View File

@@ -50,6 +50,11 @@ namespace mRemoteNG.Connection.Protocol
#region Public Methods
public bool isRunning()
{
return !PuttyProcess.HasExited;
}
public override bool Connect()
{
try
@@ -136,6 +141,11 @@ namespace mRemoteNG.Connection.Protocol
}
PuttyProcess.StartInfo.Arguments = arguments.ToString();
// add additional SSH options, f.e. tunnel or noshell parameters that may be specified for the the connnection
if (!string.IsNullOrEmpty(InterfaceControl.Info.SSHOptions))
{
PuttyProcess.StartInfo.Arguments += " " + InterfaceControl.Info.SSHOptions;
}
PuttyProcess.EnableRaisingEvents = true;
PuttyProcess.Exited += ProcessExited;

View File

@@ -1,31 +0,0 @@
.. HowTo - Jump server / Bastion host with mRemoteNG
.. Need more information here to explain and work with hosts for jumps
**************************
Jump server / Bastion host
**************************
Introduction
============
This document will not go into details on what a bastion host or a jump server really is. Instead
it will give you a howto for setting up the hosts so you can do the jump with mRemoteNG. If you need
more information regarding the function of bastion host and jump server then see links mentioned below.
.. note::
The information below could probably be a lot better. If you have a better idea or easier
way to work with bastion host and jump server, then please let us know.
References
==========
- `Wikipedia Bastion host <https://en.wikipedia.org/wiki/Bastion_host>`_
- `Wikipedia Jump server <https://en.wikipedia.org/wiki/Jump_server>`_
Linux Server to target host
===========================
In this section we will use a Ubuntu 18.04 LTS to jump to another host both RDP and SSH.
Windows Server to target host
=============================
In this section we will use a Windows 2016 Server to jump to another host both RDP and SSH.

View File

@@ -0,0 +1,13 @@
*************
SSH Tunneling
*************
You can use any configured SSH connection to be used as a tunnel server for another connection.
.. figure:: /images/ssh_tunnel.png
If an SSH Tunnel is configured the connection is searched and if found a free local TCP port determined. The SSH tunnel connection
is setup with additional parameters for the tunnel. The original connection info is copied and the copy is modified to connect
to local host and the local TCP port and the target connection is opened.
You can use the SSH connection attribute for additional SSH options. It can be used by all
normal SSH connections as well to specify any additional options, e.g. to not start a shell which some SSH servers.

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -32,7 +32,7 @@ Welcome to mRemoteNG's documentation!
:maxdepth: 2
:caption: HowTos
howtos/jumpservers.rst
howtos/sshtunnel.rst
howtos/external_tools.rst
howtos/bulk_connections.rst
howtos/vmrdp.rst

BIN
mRemoteV1/Icons/Admin.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
mRemoteV1/Icons/Staging.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -2927,6 +2927,54 @@ namespace mRemoteNG {
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool InhDefaultSSHTunnelConnectionName {
get {
return ((bool)(this["InhDefaultSSHTunnelConnectionName"]));
}
set {
this["InhDefaultSSHTunnelConnectionName"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string ConDefaultSSHTunnelConnectionName {
get {
return ((string)(this["ConDefaultSSHTunnelConnectionName"]));
}
set {
this["ConDefaultSSHTunnelConnectionName"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool InhDefaultSSHOptions {
get {
return ((bool)(this["InhDefaultSSHOptions"]));
}
set {
this["InhDefaultSSHOptions"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string ConDefaultSSHOptions {
get {
return ((string)(this["ConDefaultSSHOptions"]));
}
set {
this["ConDefaultSSHOptions"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]

View File

@@ -728,6 +728,18 @@
<Setting Name="InhDefaultRdpVersion" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="InhDefaultSSHTunnelConnectionName" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="ConDefaultSSHTunnelConnectionName" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="InhDefaultSSHOptions" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="ConDefaultSSHOptions" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="StartMinimized" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>

File diff suppressed because it is too large Load Diff

View File

@@ -2678,6 +2678,30 @@ Development umfasst Alphas, Betas und Release Candidates.</value>
<data name="strPropertyDescriptionRdpVersion" xml:space="preserve">
<value>Legt die Version des RDP fest, die beim Öffnen von Verbindungen verwendet wird.</value>
</data>
<data name="strPropertyDescriptionSSHTunnelConnection" xml:space="preserve">
<value>Zum Verbinden mittels eines SSH Tunnels (Jump Host) geben Sie hier den Namen der SSH Verbindung an, welche benutzt werden soll um den SSH Tunnel einzurichten.</value>
</data>
<data name="strPropertyDescriptionSSHOptions" xml:space="preserve">
<value>Geben Sie hier zusaetzliche Optionen an welche fuer die SSH Verbindung verwendet werden sollen. Fuer weitere Infos zu den moeglichen Optionen konsultieren sie die Putty Dokumentation.</value>
</data>
<data name="strSSHTunnelConfigProblem" xml:space="preserve">
<value>Konfigurationsfehler der Verbindung. Verbindung zu: "{0}" via SSH Tunnel: "{1}" nicht möglich. Eine Verbindung mit dem als SSH Tunnel konfiguriertem Namen konnte nicht gefunden werden. Löschen Sie die SSH Tunnel Konfiguration or geben sie eine existierende SSH Verbindung an, welche zum Aufbau eine Tunnels zum Erreichen des eigentlichen Zielsystems verwendet werden soll.</value>
</data>
<data name="strSSHTunnelIsNotPutty" xml:space="preserve">
<value>Konfigurationsfehler des SSH Tunnel. Verbindung zu: "{0}" via SSH Tunnel: "{1}" nicht möglich. Die als SSH Tunnel konfigurierte Verbindung wurde zwar gefunden, aber das zugehörige Protokoll ist nicht von Putty abgeleitet. Stellen Sie sicher dass die als SSH Tunnel konfigurierte Verbindung das SSH version 1 oder 2 Protokoll verwendet.</value>
</data>
<data name="strSSHTunnelNotInitialized" xml:space="preserve">
<value>Initialisierungsproblem des SSH Tunnel. Verbindung zu: "{0}" via SSH Tunnel: "{1}" nicht möglich. Initialisierung der SSH Verbindung fehlgeschlagen. Überprüfen Sie die als SSH Tunnel konfigurierte Verbindung auf etwaige Probleme.</value>
</data>
<data name="strSSHTunnelNotConnected" xml:space="preserve">
<value>Verbindungsproblem des SSH Tunnel. Verbindung zu: "{0}" via SSH Tunnel: "{1}" nicht möglich. SSH Verbindungsaufbau fehlgeschlagen. Überprüfen Sie die als SSH Tunnel konfigurierte Verbindung auf etwaige Probleme.</value>
</data>
<data name="strSSHTunnelFailed" xml:space="preserve">
<value>SSH Tunnel Verbindung fehlgeschlagen. Verbindung zu: "{0}" via SSH Tunnel: "{1}" nicht möglich. Putty Prozess vorzeitig beendet. Überprüfen Sie die als SSH Tunnel konfigurierte Verbindung auf etwaige Probleme.</value>
</data>
<data name="strSSHTunnelPortNotReadyInTime" xml:space="preserve">
<value>Zeitüberschreitung des SSH Tunnel. Verbindung zu: "{0}" via SSH Tunnel: "{1}" nicht möglich. Lokaler Tunnel Port nicht vor Ablauf der Zeitüberschreitung verfügbar. Überprüfen Sie die als SSH Tunnel konfigurierte Verbindung auf etwaige Probleme.</value>
</data>
<data name="strStartMinimized" xml:space="preserve">
<value>Minimiert starten</value>
</data>

View File

@@ -2813,6 +2813,36 @@ Development Channel includes Alphas, Betas &amp; Release Candidates.</value>
<data name="RdpProtocolVersionNotSupported" xml:space="preserve">
<value>Could not create RDP client. RDP protocol version {0} is not supported on this machine. Please choose an older protocol version.</value>
</data>
<data name="strPropertyDescriptionSSHTunnelConnection" xml:space="preserve">
<value>For connection through a SSH tunnel (jump host) specify SSH connection to be used to establish SSH tunnel.</value>
</data>
<data name="strPropertyNameSSHTunnelConnection" xml:space="preserve">
<value>SSH Tunnel</value>
</data>
<data name="strPropertyDescriptionSSHOptions" xml:space="preserve">
<value>Specify here additional options to be used for SSH connection. See putty documentation for further details.</value>
</data>
<data name="strPropertyNameSSHOptions" xml:space="preserve">
<value>SSH Options</value>
</data>
<data name="strSSHTunnelConfigProblem" xml:space="preserve">
<value>Connection configuration problem. Connection to: "{0}" via SSH Tunnel: "{1}" not possible. A connection with the name configured as SSH Tunnel and protocol SSH version 1 or SSH2 version 2 cannot be found in the connection tree. Clear SSH Tunnel configuration or specify existing SSH connection.</value>
</data>
<data name="strSSHTunnelIsNotPutty" xml:space="preserve">
<value>SSH tunnel configuration problem. Connection to: "{0}" via SSH Tunnel: "{1}" not possible. Connection configured as SSH Tunnel found in tree, but protocol is not derived from putty. Make sure connection configured as SSH Tunnel is using SSH protocol.</value>
</data>
<data name="strSSHTunnelNotInitialized" xml:space="preserve">
<value>SSH tunnel initialization problem. Connection to: "{0}" via SSH Tunnel: "{1}" not possible. SSH connection could not be initialized. Check for any problems with the connection configured as SSH Tunnel.</value>
</data>
<data name="strSSHTunnelNotConnected" xml:space="preserve">
<value>SSH tunnel connection problem. Connection to: "{0}" via SSH Tunnel: "{1}" not possible. SSH connection failed. Check for any problems with the connection configured as SSH Tunnel.</value>
</data>
<data name="strSSHTunnelFailed" xml:space="preserve">
<value>SSH tunnel connection failed. Connection to: "{0}" via SSH Tunnel: "{1}" not possible. Putty process terminated. Check for any problems with the connection configured as SSH Tunnel.</value>
</data>
<data name="strSSHTunnelPortNotReadyInTime" xml:space="preserve">
<value>SSH tunnel connection timed out. Connection to: "{0}" via SSH Tunnel: "{1}" not possible. Local tunnel port did not become available in time. Check for any problems with the connection configured as SSH Tunnel.</value>
</data>
<data name="strStartMinimized" xml:space="preserve">
<value>Start minimized</value>
</data>

View File

@@ -36,18 +36,17 @@
<xs:attribute name="Descr" type="xs:string" use="required" />
<xs:attribute name="Icon" type="xs:string" use="required" />
<xs:attribute name="Panel" type="xs:string" use="required" />
<!--<xs:attribute name="CredentialId" type="xs:string" use="required" />-->
<xs:attribute name="Username" type="xs:string" use="required" />
<xs:attribute name="Domain" type="xs:string" use="required" />
<xs:attribute name="Password" type="xs:string" use="required" />
<xs:attribute name="Hostname" type="xs:string" use="required" />
<xs:attribute name="Protocol" type="xs:string" use="required" />
<xs:attribute name="RdpVersion" type="xs:string" use="required" />
<xs:attribute name="VmId" type="xs:string" use="required" />
<xs:attribute name="UseVmId" type="xs:boolean" use="required" />
<xs:attribute name="UseEnhancedMode" type="xs:boolean" use="required" />
<xs:attribute name="SSHTunnelConnectionName" type="xs:string" use="optional" />
<xs:attribute name="SSHOptions" type="xs:string" use="optional" />
<xs:attribute name="PuttySession" type="xs:string" use="required" />
<xs:attribute name="Port" type="xs:int" use="required" />
<xs:attribute name="ConnectToConsole" type="xs:boolean" use="required" />
@@ -114,6 +113,8 @@
<xs:attribute name="InheritPort" type="xs:boolean" use="optional" />
<xs:attribute name="InheritProtocol" type="xs:boolean" use="optional" />
<xs:attribute name="InheritRdpVersion" type="xs:boolean" use="optional" />
<xs:attribute name="InheritSSHTunnelConnectionName" type="xs:boolean" use="optional" />
<xs:attribute name="InheritSSHOptions" type="xs:boolean" use="optional" />
<xs:attribute name="InheritPuttySession" type="xs:boolean" use="optional" />
<xs:attribute name="InheritRedirectDiskDrives" type="xs:boolean" use="optional" />
<xs:attribute name="InheritRedirectKeys" type="xs:boolean" use="optional" />

View File

@@ -0,0 +1,58 @@
using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container;
using System.Collections.Generic;
using System.ComponentModel;
namespace mRemoteNG.Tools
{
public class SshTunnelTypeConverter : StringConverter
{
public static string[] SshTunnels
{
get
{
var sshTunnelList = new List<string> {string.Empty};
// Add a blank entry to signify that no external tool is selected
sshTunnelList.AddRange(GetSshConnectionNames(Runtime.ConnectionsService.ConnectionTreeModel.RootNodes));
return sshTunnelList.ToArray();
}
}
// recursively traverse the connection tree to find all ConnectionInfo s of type SSH
private static IEnumerable<string> GetSshConnectionNames(IEnumerable<ConnectionInfo> rootnodes)
{
var result = new List<string>();
foreach (var node in rootnodes)
if (node is ContainerInfo container)
{
result.AddRange(GetSshConnectionNames(container.Children));
}
else
{
if (node is PuttySessionInfo) continue;
if (node.Protocol == ProtocolType.SSH1 || node.Protocol == ProtocolType.SSH2)
result.Add(node.Name);
}
return result;
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
return new StandardValuesCollection(SshTunnels);
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
return true;
}
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
}
}

View File

@@ -753,6 +753,18 @@
<setting name="InhDefaultRdpVersion" serializeAs="String">
<value>False</value>
</setting>
<setting name="InhDefaultSSHTunnelConnectionName" serializeAs="String">
<value>False</value>
</setting>
<setting name="ConDefaultSSHTunnelConnectionName" serializeAs="String">
<value />
</setting>
<setting name="InhDefaultSSHOptions" serializeAs="String">
<value>False</value>
</setting>
<setting name="ConDefaultSSHOptions" serializeAs="String">
<value />
</setting>
<setting name="StartMinimized" serializeAs="String">
<value>False</value>
</setting>

View File

@@ -299,6 +299,11 @@
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Resources\Language\Language.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Language.resx</DependentUpon>
</Compile>
<Compile Include="Resources\Themes\ColorMapTheme.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@@ -375,6 +380,7 @@
<Compile Include="Tools\Cmdline\CmdArgumentsInterpreter.cs" />
<Compile Include="Tools\ConnectionsTreeToMenuItemsConverter.cs" />
<Compile Include="Tools\ExternalToolsService.cs" />
<Compile Include="Tools\SshTunnelTypeConverter.cs" />
<Compile Include="Tools\ExternalToolsTypeConverter.cs" />
<Compile Include="Tools\CustomCollections\INotifyCollectionUpdated.cs" />
<Compile Include="Tools\Optional.cs" />
@@ -686,11 +692,6 @@
<Compile Include="UI\Forms\PasswordForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Resources\Language\Language.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Language.resx</DependentUpon>
</Compile>
<Compile Include="Messages\Message.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\Settings.Designer.cs">
@@ -1026,7 +1027,7 @@
<Generator>ResXFileCodeGenerator</Generator>
<CustomToolNamespace>mRemoteNG</CustomToolNamespace>
<SubType>Designer</SubType>
<LastGenOutput>Language1.Designer.cs</LastGenOutput>
<LastGenOutput>Language.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\Language\Language.fr.resx">
<SubType>Designer</SubType>
@@ -1198,6 +1199,7 @@
<None Include="Documentation\images\connections_status.png" />
<None Include="Documentation\images\putty.png" />
<Content Include="Console.ico" />
<Content Include="Documentation\images\ssh_tunnel.png" />
<Content Include="Documentation\mssql_db_setup.sql" />
<Content Include="Documentation\mysql_db_setup.sql" />
<None Include="Documentation\images\config_top_bar.png" />
@@ -1219,6 +1221,7 @@
<None Include="Documentation\images\connections_open.png" />
<None Include="Documentation\images\screenshot_manager_rightclick_menu.png" />
<None Include="Documentation\images\screenshot_manager_overview.png" />
<Content Include="Icons\Admin.ico" />
<Content Include="Firefox\AccessibleHandler.dll" />
<Content Include="Firefox\AccessibleMarshal.dll" />
<Content Include="Firefox\breakpadinjector.dll" />
@@ -1286,6 +1289,15 @@
<None Include="Resources\Images\tab_edit.png" />
<None Include="Resources\Images\tab_delete.png" />
<None Include="Resources\Images\star.png" />
<Content Include="Icons\Infrastructure.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Icons\Production.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Icons\Staging.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Icons\PowerShell.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1425,7 +1437,7 @@
<None Include="Documentation\installation.rst" />
<None Include="Documentation\installation\minimum_requirements.rst" />
<None Include="Documentation\installation\uninstall.rst" />
<None Include="Documentation\howtos\jumpservers.rst" />
<None Include="Documentation\howtos\sshtunnel.rst" />
<None Include="Documentation\user_interface.rst" />
<None Include="Documentation\user_interface\main_window.rst" />
<None Include="Documentation\user_interface\panels.rst" />