├── screenshot1.png
├── TSTunnels.UI
├── App.ico
├── Properties
│ ├── Settings.settings
│ ├── Settings.Designer.cs
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── Program.cs
├── Win32Api.cs
├── TSTunnels.UI.csproj
├── UI.cs
├── UI.resx
└── UI.Designer.cs
├── tools
├── ExportDll.exe
├── ExportDllAttribute.dll
└── ExportDll.exe.config
├── README.md
├── TSTunnels
├── Common
│ ├── Messages
│ │ ├── MessageType.cs
│ │ ├── ListenResponse.cs
│ │ ├── HelloResponse.cs
│ │ ├── HelloRequest.cs
│ │ ├── AcceptRequest.cs
│ │ ├── StreamData.cs
│ │ ├── ConnectResponse.cs
│ │ ├── ListenRequest.cs
│ │ ├── ChannelMessage.cs
│ │ ├── ConnectRequest.cs
│ │ └── StreamError.cs
│ ├── IStreamServer.cs
│ ├── TcpListenerHelper.cs
│ └── StreamPump.cs
├── Server
│ ├── MessageLoggedEventArgs.cs.cs
│ ├── ConnectedEventArgs.cs.cs
│ ├── ForwardedPortEventArgs.cs
│ ├── ForwardedPort.cs
│ ├── WtsApi32.cs
│ └── Server.cs
├── Client
│ ├── Program.cs
│ ├── WtsApi32.cs
│ └── Client.cs
├── Properties
│ └── AssemblyInfo.cs
└── TSTunnels.csproj
└── TSTunnels.sln
/screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/normanr/tstunnels/HEAD/screenshot1.png
--------------------------------------------------------------------------------
/TSTunnels.UI/App.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/normanr/tstunnels/HEAD/TSTunnels.UI/App.ico
--------------------------------------------------------------------------------
/tools/ExportDll.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/normanr/tstunnels/HEAD/tools/ExportDll.exe
--------------------------------------------------------------------------------
/tools/ExportDllAttribute.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/normanr/tstunnels/HEAD/tools/ExportDllAttribute.dll
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Remote Desktop Tunnels - Network Port Redirection
2 | Allows you to port forward with Remote Desktop, in the same way that ssh has been able to for years.
3 |
4 | ## Screen Shot
5 | 
6 |
--------------------------------------------------------------------------------
/TSTunnels.UI/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TSTunnels/Common/Messages/MessageType.cs:
--------------------------------------------------------------------------------
1 | namespace TSTunnels.Common.Messages
2 | {
3 | public enum MessageType
4 | {
5 | Unknown = 0,
6 | HelloRequest,
7 | HelloResponse,
8 | ConnectRequest,
9 | ConnectResponse,
10 | ListenRequest,
11 | ListenResponse,
12 | AcceptRequest,
13 | StreamData,
14 | StreamError,
15 | }
16 | }
--------------------------------------------------------------------------------
/TSTunnels/Server/MessageLoggedEventArgs.cs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace TSTunnels.Server
6 | {
7 | public class MessageLoggedEventArgs : EventArgs
8 | {
9 | public string Message { get; private set; }
10 |
11 | public MessageLoggedEventArgs(string Message)
12 | {
13 | this.Message = Message;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/TSTunnels/Server/ConnectedEventArgs.cs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace TSTunnels.Server
6 | {
7 | public class ConnectedEventArgs : EventArgs
8 | {
9 | public string MachineName { get; private set; }
10 |
11 | public ConnectedEventArgs(string MachineName)
12 | {
13 | this.MachineName = MachineName;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/TSTunnels/Server/ForwardedPortEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace TSTunnels.Server
6 | {
7 | public class ForwardedPortEventArgs : EventArgs
8 | {
9 | public ForwardedPort ForwardedPort { get; private set; }
10 |
11 | public ForwardedPortEventArgs(ForwardedPort forwardedPort)
12 | {
13 | ForwardedPort = forwardedPort;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/TSTunnels.UI/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Windows.Forms;
4 |
5 | namespace TSTunnels.UI
6 | {
7 | static class Program
8 | {
9 | ///
10 | /// The main entry point for the application.
11 | ///
12 | [STAThread]
13 | static void Main()
14 | {
15 | Application.EnableVisualStyles();
16 | Application.SetCompatibleTextRenderingDefault(false);
17 | Application.Run(new UI());
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/TSTunnels/Common/IStreamServer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Net.Sockets;
5 | using System.Text;
6 | using TSTunnels.Common.Messages;
7 |
8 | namespace TSTunnels.Common
9 | {
10 | public interface IStreamServer
11 | {
12 | void MessageReceived(ChannelMessage msg);
13 | int ConnectionCount { get; set; }
14 | IDictionary Streams { get; }
15 | IDictionary Listeners { get; }
16 | bool WriteMessage(ChannelMessage msg);
17 | void Log(object message);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/TSTunnels/Server/ForwardedPort.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Windows.Forms;
5 |
6 | namespace TSTunnels.Server
7 | {
8 | public enum ForwardDirection
9 | {
10 | Local,
11 | Remote
12 | }
13 |
14 | public class ForwardedPort
15 | {
16 | public ForwardDirection Direction;
17 | public string ListenEndPoint;
18 | public string ConnectEndPoint;
19 | public MethodInvoker Remove;
20 |
21 | public override string ToString()
22 | {
23 | return Direction + "\t" + ListenEndPoint + "\t" + ConnectEndPoint;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/TSTunnels/Common/Messages/ListenResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace TSTunnels.Common.Messages
5 | {
6 | [Serializable]
7 | public class ListenResponse : ChannelMessage
8 | {
9 | public readonly int ListenIndex;
10 |
11 | public ListenResponse(int ListenIndex)
12 | : base(MessageType.ListenResponse)
13 | {
14 | this.ListenIndex = ListenIndex;
15 | }
16 |
17 | protected ListenResponse(BinaryReader reader)
18 | : base(reader)
19 | {
20 | ListenIndex = reader.ReadInt32();
21 | }
22 |
23 | protected override void Serialize(BinaryWriter writer)
24 | {
25 | base.Serialize(writer);
26 | writer.Write(ListenIndex);
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/TSTunnels/Common/Messages/HelloResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace TSTunnels.Common.Messages
5 | {
6 | [Serializable]
7 | public class HelloResponse : ChannelMessage
8 | {
9 | public readonly string MachineName;
10 |
11 | public HelloResponse()
12 | : base(MessageType.HelloResponse)
13 | {
14 | MachineName = Environment.MachineName;
15 | }
16 |
17 | protected HelloResponse(BinaryReader reader)
18 | : base(reader)
19 | {
20 | MachineName = reader.ReadString();
21 | }
22 |
23 | protected override void Serialize(BinaryWriter writer)
24 | {
25 | base.Serialize(writer);
26 | writer.Write(MachineName);
27 | }
28 |
29 | public override string ToString()
30 | {
31 | return base.ToString() + ": " + MachineName;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/TSTunnels.UI/Win32Api.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 |
7 | namespace TSTunnels.UI
8 | {
9 | class Win32Api
10 | {
11 | [DllImport("Kernel32.dll", SetLastError = true)]
12 | private static extern IntPtr GetModuleHandle(string moduleName);
13 |
14 | [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true)]
15 | private static extern IntPtr LoadIcon(IntPtr hInst, string iconId);
16 |
17 | private const string IDI_APPLICATION = "#32512";
18 |
19 | public static Icon GetApplicationIcon()
20 | {
21 | var icon = LoadIcon(GetModuleHandle(null), IDI_APPLICATION);
22 | // vshost.exe doesn't have our application icon, so we could fail at this point
23 | return icon != IntPtr.Zero ? Icon.FromHandle(icon) : SystemIcons.Application;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/TSTunnels/Common/Messages/HelloRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace TSTunnels.Common.Messages
5 | {
6 | [Serializable]
7 | public class HelloRequest : ChannelMessage
8 | {
9 | public readonly string MachineName;
10 |
11 | public HelloRequest()
12 | : base(MessageType.HelloRequest)
13 | {
14 | MachineName = Environment.MachineName;
15 | }
16 |
17 | protected HelloRequest(BinaryReader reader)
18 | : base(reader)
19 | {
20 | MachineName = reader.ReadString();
21 | }
22 |
23 | protected override void Serialize(BinaryWriter writer)
24 | {
25 | base.Serialize(writer);
26 | writer.Write(MachineName);
27 | }
28 |
29 | public override string ToString()
30 | {
31 | return base.ToString() + ": " + MachineName;
32 | }
33 |
34 | public void Process(IStreamServer server)
35 | {
36 | server.WriteMessage(new HelloResponse());
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/TSTunnels/Common/Messages/AcceptRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace TSTunnels.Common.Messages
5 | {
6 | [Serializable]
7 | public class AcceptRequest : ChannelMessage
8 | {
9 | public readonly int ListenIndex;
10 | public readonly int StreamIndex;
11 | public readonly string RemoteEndPoint;
12 |
13 | public AcceptRequest(int ListenIndex, int StreamIndex, string RemoteEndPoint)
14 | : base(MessageType.AcceptRequest)
15 | {
16 | this.ListenIndex = ListenIndex;
17 | this.StreamIndex = StreamIndex;
18 | this.RemoteEndPoint = RemoteEndPoint;
19 | }
20 |
21 | protected AcceptRequest(BinaryReader reader)
22 | : base(reader)
23 | {
24 | ListenIndex = reader.ReadInt32();
25 | StreamIndex = reader.ReadInt32();
26 | RemoteEndPoint = reader.ReadString();
27 | }
28 |
29 | protected override void Serialize(BinaryWriter writer)
30 | {
31 | base.Serialize(writer);
32 | writer.Write(ListenIndex);
33 | writer.Write(StreamIndex);
34 | writer.Write(RemoteEndPoint);
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/tools/ExportDll.exe.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\ildasm.exe
12 |
13 |
14 | C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ilasm.exe
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/TSTunnels.UI/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:2.0.50727.3053
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace TSTunnels.UI.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/TSTunnels/Common/TcpListenerHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Net;
5 | using System.Net.Sockets;
6 | using System.Text;
7 |
8 | namespace TSTunnels.Common
9 | {
10 | public static class TcpListenerHelper
11 | {
12 | public static TcpListener Start(string listenAddress, int listenPort, Action acceptDelegate, Action exceptionDelegate)
13 | {
14 | var listener = new TcpListener(IPAddress.Parse(listenAddress), listenPort);
15 | listener.Start();
16 | listener.BeginAcceptTcpClient(listener_AcceptTcpClient, (Converter)delegate(IAsyncResult ar)
17 | {
18 | try
19 | {
20 | acceptDelegate(listener.EndAcceptTcpClient(ar));
21 | return listener;
22 | }
23 | catch (Exception ex)
24 | {
25 | Debug.Print(DateTime.Now + " " + Environment.MachineName + ": " + ex);
26 | exceptionDelegate(ex);
27 | return null;
28 | }
29 | });
30 | return listener;
31 | }
32 |
33 | private static void listener_AcceptTcpClient(IAsyncResult ar)
34 | {
35 | var callback = (Converter)ar.AsyncState;
36 | var listener = callback(ar);
37 | if (listener != null) listener.BeginAcceptTcpClient(listener_AcceptTcpClient, callback);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/TSTunnels/Common/Messages/StreamData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 |
6 | namespace TSTunnels.Common.Messages
7 | {
8 | [Serializable]
9 | public class StreamData : ChannelMessage
10 | {
11 | public readonly int StreamIndex;
12 | public readonly byte[] Data;
13 |
14 | public StreamData(int StreamIndex, byte[] Data)
15 | : base(MessageType.StreamData)
16 | {
17 | this.StreamIndex = StreamIndex;
18 | this.Data = Data;
19 | }
20 |
21 | protected StreamData(BinaryReader reader)
22 | : base(reader)
23 | {
24 | StreamIndex = reader.ReadInt32();
25 | var length = reader.ReadInt32();
26 | Data = reader.ReadBytes(length);
27 | }
28 |
29 | protected override void Serialize(BinaryWriter writer)
30 | {
31 | base.Serialize(writer);
32 | writer.Write(StreamIndex);
33 | writer.Write(Data.Length);
34 | writer.Write(Data);
35 | }
36 |
37 | public void Process(IStreamServer server)
38 | {
39 | Stream stream;
40 | lock (server.Streams)
41 | {
42 | if (!server.Streams.ContainsKey(StreamIndex)) return;
43 | stream = server.Streams[StreamIndex];
44 | }
45 | try
46 | {
47 | stream.Write(Data, 0, Data.Length);
48 | }
49 | catch (Exception ex)
50 | {
51 | server.WriteMessage(new StreamError(StreamIndex, ex));
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/TSTunnels/Client/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 | using Microsoft.Win32;
7 | using TSTunnels.Common.Messages;
8 | using TSTunnels.Client.WtsApi32;
9 |
10 | namespace TSTunnels.Client
11 | {
12 | public static class Program
13 | {
14 | private const string registryAddins = @"Software\Microsoft\Terminal Server Client\Default\AddIns\";
15 |
16 | [ExportDllAttribute.ExportDll("DllRegisterServer", CallingConvention.StdCall)]
17 | public static void DllRegisterServer()
18 | {
19 | using (var key = Registry.CurrentUser.CreateSubKey(registryAddins + ChannelMessage.ChannelName))
20 | {
21 | Debug.Assert(key != null);
22 | var location = typeof(Client).Assembly.Location;
23 | Debug.Assert(location != null);
24 | key.SetValue("Name", location);
25 | }
26 | }
27 |
28 | [ExportDllAttribute.ExportDll("DllUnregisterServer", CallingConvention.StdCall)]
29 | public static void DllUnregisterServer()
30 | {
31 | Registry.CurrentUser.DeleteSubKey(registryAddins + ChannelMessage.ChannelName);
32 | }
33 |
34 | private static Client client;
35 |
36 | [ExportDllAttribute.ExportDll("VirtualChannelEntry", CallingConvention.StdCall)]
37 | public static bool VirtualChannelEntry(ref ChannelEntryPoints entry)
38 | {
39 | client = new Client(entry);
40 | return client.VirtualChannelInit();
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/TSTunnels/Common/StreamPump.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 |
6 | namespace TSTunnels.Common
7 | {
8 | public class StreamPump
9 | {
10 | const int bufferSize = 10000;
11 | private readonly Stream stream;
12 | private readonly Action writeCallback;
13 | private readonly Action errorCallback;
14 | private readonly byte[] buf = new byte[bufferSize];
15 |
16 | public StreamPump(Stream stream, Action writeCallback, Action errorCallback)
17 | {
18 | this.stream = stream;
19 | this.writeCallback = writeCallback;
20 | this.errorCallback = errorCallback;
21 | }
22 |
23 | public void Pump()
24 | {
25 | try
26 | {
27 | stream.BeginRead(buf, 0, bufferSize, ReadCallback, null);
28 | }
29 | catch (Exception ex)
30 | {
31 | errorCallback(ex);
32 | }
33 | }
34 |
35 | private void ReadCallback(IAsyncResult ar)
36 | {
37 | try
38 | {
39 | var bytesReceived = stream.EndRead(ar);
40 | if (bytesReceived > 0)
41 | {
42 | var data = new byte[bytesReceived];
43 | Buffer.BlockCopy(buf, 0, data, 0, bytesReceived);
44 | writeCallback(data);
45 | Pump();
46 | }
47 | else
48 | {
49 | errorCallback(new EndOfStreamException());
50 | return;
51 | }
52 | }
53 | catch (Exception ex)
54 | {
55 | errorCallback(ex);
56 | }
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/TSTunnels/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("TSTunnels")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("TSTunnels")]
13 | [assembly: AssemblyCopyright("Copyright © Darkskies 2009")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("0723206d-9a8a-4238-aa70-3ebc50831f64")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/TSTunnels.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 10.00
3 | # Visual Studio 2008
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TSTunnels", "TSTunnels\TSTunnels.csproj", "{46202B33-3B41-4B2B-B349-9DE165C8883A}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TSTunnels.UI", "TSTunnels.UI\TSTunnels.UI.csproj", "{8D98224E-FDA0-422F-BDAA-8AF5BCE5F28A}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {46202B33-3B41-4B2B-B349-9DE165C8883A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {46202B33-3B41-4B2B-B349-9DE165C8883A}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {46202B33-3B41-4B2B-B349-9DE165C8883A}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {46202B33-3B41-4B2B-B349-9DE165C8883A}.Release|Any CPU.Build.0 = Release|Any CPU
18 | {8D98224E-FDA0-422F-BDAA-8AF5BCE5F28A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {8D98224E-FDA0-422F-BDAA-8AF5BCE5F28A}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {8D98224E-FDA0-422F-BDAA-8AF5BCE5F28A}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {8D98224E-FDA0-422F-BDAA-8AF5BCE5F28A}.Release|Any CPU.Build.0 = Release|Any CPU
22 | EndGlobalSection
23 | GlobalSection(SolutionProperties) = preSolution
24 | HideSolutionNode = FALSE
25 | EndGlobalSection
26 | GlobalSection(ExtensibilityGlobals) = postSolution
27 | VisualSVNWorkingCopyRoot = .
28 | EndGlobalSection
29 | EndGlobal
30 |
--------------------------------------------------------------------------------
/TSTunnels.UI/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Remote Desktop Tunnels")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Remote Desktop Tunnels")]
13 | [assembly: AssemblyCopyright("Copyright © Darkskies 2009")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("01bd97f3-b6e2-46eb-8c77-f79088498b9d")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/TSTunnels/Common/Messages/ConnectResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 |
5 | namespace TSTunnels.Common.Messages
6 | {
7 | [Serializable]
8 | public class ConnectResponse : ChannelMessage
9 | {
10 | public readonly int StreamIndex;
11 | public readonly string LocalEndPoint;
12 | public readonly string RemoteEndPoint;
13 |
14 | public ConnectResponse(int StreamIndex, string RemoteEndPoint, string LocalEndPoint)
15 | : base(MessageType.ConnectResponse)
16 | {
17 | this.StreamIndex = StreamIndex;
18 | this.LocalEndPoint = LocalEndPoint;
19 | this.RemoteEndPoint = RemoteEndPoint;
20 | }
21 |
22 | protected ConnectResponse(BinaryReader reader)
23 | : base(reader)
24 | {
25 | StreamIndex = reader.ReadInt32();
26 | LocalEndPoint = reader.ReadString();
27 | RemoteEndPoint = reader.ReadString();
28 | }
29 |
30 | protected override void Serialize(BinaryWriter writer)
31 | {
32 | base.Serialize(writer);
33 | writer.Write(StreamIndex);
34 | writer.Write(LocalEndPoint);
35 | writer.Write(RemoteEndPoint);
36 | }
37 |
38 | public override string ToString()
39 | {
40 | return base.ToString() + ": " + RemoteEndPoint + " to " + LocalEndPoint;
41 | }
42 |
43 | public void Process(IStreamServer server)
44 | {
45 | new StreamPump(server.Streams[StreamIndex],
46 | data => server.WriteMessage(new StreamData(StreamIndex, data)),
47 | ex =>
48 | {
49 | server.Log("Forwarded port closed: " + RemoteEndPoint + " to " + LocalEndPoint);
50 | server.WriteMessage(new StreamError(StreamIndex, ex));
51 | }).Pump();
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/TSTunnels/Common/Messages/ListenRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace TSTunnels.Common.Messages
5 | {
6 | [Serializable]
7 | public class ListenRequest : ChannelMessage
8 | {
9 | public readonly int StreamIndex;
10 | public readonly string Address;
11 | public readonly int Port;
12 |
13 | public ListenRequest(int StreamIndex, string Address, int Port)
14 | : base(MessageType.ListenRequest)
15 | {
16 | this.StreamIndex = StreamIndex;
17 | this.Address = Address;
18 | this.Port = Port;
19 | }
20 |
21 | protected ListenRequest(BinaryReader reader)
22 | : base(reader)
23 | {
24 | StreamIndex = reader.ReadInt32();
25 | Address = reader.ReadString();
26 | Port = reader.ReadInt32();
27 | }
28 |
29 | protected override void Serialize(BinaryWriter writer)
30 | {
31 | base.Serialize(writer);
32 | writer.Write(StreamIndex);
33 | writer.Write(Address);
34 | writer.Write(Port);
35 | }
36 |
37 | public void Process(IStreamServer server)
38 | {
39 | try
40 | {
41 | server.Listeners[StreamIndex] = TcpListenerHelper.Start(Address, Port, client =>
42 | {
43 | var streamIndex = --server.ConnectionCount;
44 | server.Streams[streamIndex] = client.GetStream();
45 | server.WriteMessage(new AcceptRequest(StreamIndex, streamIndex, client.Client.RemoteEndPoint.ToString()));
46 | }, exception => server.WriteMessage(new StreamError(StreamIndex, new EndOfStreamException())));
47 | server.WriteMessage(new ListenResponse(StreamIndex));
48 | }
49 | catch (Exception ex)
50 | {
51 | server.WriteMessage(new StreamError(StreamIndex, ex));
52 | }
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/TSTunnels/Server/WtsApi32.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.IO;
4 | using System.Runtime.InteropServices;
5 | using Microsoft.Win32.SafeHandles;
6 |
7 | namespace TSTunnels.Server
8 | {
9 | class WtsApi32
10 | {
11 | [DllImport("Wtsapi32.dll", SetLastError = true)]
12 | public static extern IntPtr WTSVirtualChannelOpen(IntPtr server, int sessionId, [MarshalAs(UnmanagedType.LPStr)] string virtualName);
13 |
14 | [DllImport("Wtsapi32.dll", SetLastError = true)]
15 | public static extern bool WTSVirtualChannelQuery(IntPtr channelHandle, WtsVirtualClass Class, out IntPtr data, out int bytesReturned);
16 |
17 | [DllImport("Wtsapi32.dll")]
18 | public static extern void WTSFreeMemory(IntPtr memory);
19 |
20 | [DllImport("Wtsapi32.dll", SetLastError = true)]
21 | public static extern bool WTSVirtualChannelWrite(IntPtr channelHandle, byte[] data, int length, out int bytesWritten);
22 |
23 | [DllImport("Wtsapi32.dll", SetLastError = true)]
24 | public static extern bool WTSVirtualChannelRead(IntPtr channelHandle, int TimeOut, IntPtr data, int length, out int bytesRead);
25 |
26 | [DllImport("Wtsapi32.dll")]
27 | public static extern bool WTSVirtualChannelClose(IntPtr channelHandle);
28 |
29 | public static Stream WTSVirtualChannelQuery_WTSVirtualFileHandle(IntPtr channelHandle)
30 | {
31 | int len;
32 | IntPtr buffer;
33 | var b = WTSVirtualChannelQuery(channelHandle, WtsVirtualClass.WTSVirtualFileHandle, out buffer, out len);
34 | if (!b) throw new Win32Exception();
35 | var fileHandle = new SafeFileHandle(Marshal.ReadIntPtr(buffer), true);
36 | WTSFreeMemory(buffer);
37 |
38 | return new FileStream(fileHandle, FileAccess.ReadWrite, 0x1000, true);
39 | }
40 | }
41 |
42 | public enum WtsVirtualClass
43 | {
44 | WTSVirtualClient = 0,
45 | WTSVirtualFileHandle = 1
46 | }
47 |
48 | }
--------------------------------------------------------------------------------
/TSTunnels/Common/Messages/ChannelMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Reflection;
5 | using System.Runtime.InteropServices;
6 | using System.Runtime.Serialization.Formatters.Binary;
7 | using System.Text;
8 | using System.Runtime.Serialization;
9 |
10 | namespace TSTunnels.Common.Messages
11 | {
12 | public abstract class ChannelMessage
13 | {
14 | //ATTENTION: name should have 7 or less chars
15 | public const string ChannelName = "TSTnls";
16 |
17 | public readonly MessageType Type;
18 |
19 | protected ChannelMessage(MessageType Type)
20 | {
21 | this.Type = Type;
22 | }
23 |
24 | protected ChannelMessage(BinaryReader reader)
25 | {
26 | Type = (MessageType)reader.ReadInt32();
27 | }
28 |
29 | protected virtual void Serialize(BinaryWriter writer)
30 | {
31 | writer.Write((int)Type);
32 | }
33 |
34 | public byte[] ToByteArray()
35 | {
36 | if (Type == MessageType.Unknown)
37 | throw new ArgumentException();
38 | using (var stream = new MemoryStream())
39 | {
40 | using (var writer = new BinaryWriter(stream))
41 | {
42 | writer.Write(GetType().FullName);
43 | Serialize(writer);
44 | }
45 | return stream.ToArray();
46 | }
47 | }
48 |
49 | public static ChannelMessage FromByteArray(byte[] data)
50 | {
51 | using (var stream = new MemoryStream(data))
52 | {
53 | return FromStream(stream);
54 | }
55 | }
56 |
57 | public static ChannelMessage FromStream(Stream stream)
58 | {
59 | using (var reader = new BinaryReader(stream))
60 | {
61 | var type = System.Type.GetType(reader.ReadString());
62 | return (ChannelMessage)type.InvokeMember(null, BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.NonPublic, null, null, new object[] { reader });
63 | }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/TSTunnels/Common/Messages/ConnectRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Net.Sockets;
6 |
7 | namespace TSTunnels.Common.Messages
8 | {
9 | [Serializable]
10 | public class ConnectRequest : ChannelMessage
11 | {
12 | public readonly int StreamIndex;
13 | public readonly string LocalEndPoint;
14 | public readonly string Address;
15 | public readonly int Port;
16 |
17 | public ConnectRequest(int StreamIndex, string LocalEndPoint, string Address, int Port)
18 | : base(MessageType.ConnectRequest)
19 | {
20 | this.StreamIndex = StreamIndex;
21 | this.LocalEndPoint = LocalEndPoint;
22 | this.Address = Address;
23 | this.Port = Port;
24 | }
25 |
26 | protected ConnectRequest(BinaryReader reader)
27 | : base(reader)
28 | {
29 | StreamIndex = reader.ReadInt32();
30 | LocalEndPoint = reader.ReadString();
31 | Address = reader.ReadString();
32 | Port = reader.ReadInt32();
33 | }
34 |
35 | protected override void Serialize(BinaryWriter writer)
36 | {
37 | base.Serialize(writer);
38 | writer.Write(StreamIndex);
39 | writer.Write(LocalEndPoint);
40 | writer.Write(Address);
41 | writer.Write(Port);
42 | }
43 |
44 | public void Process(IStreamServer server)
45 | {
46 | var client = new TcpClient();
47 | client.BeginConnect(Address, Port, ar =>
48 | {
49 | try
50 | {
51 | client.EndConnect(ar);
52 | server.Streams[StreamIndex] = client.GetStream();
53 | var connectResult = new ConnectResponse(StreamIndex, LocalEndPoint, client.Client.RemoteEndPoint.ToString());
54 | connectResult.Process(server);
55 | server.WriteMessage(connectResult);
56 | }
57 | catch (Exception ex)
58 | {
59 | Debug.Print(DateTime.Now + " " + Environment.MachineName + ": " + ex);
60 | server.WriteMessage(new StreamError(StreamIndex, ex));
61 | }
62 | }, null);
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/TSTunnels.UI/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:2.0.50727.3053
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace TSTunnels.UI.Properties
12 | {
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// Returns the cached ResourceManager instance used by this class.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TSTunnels.UI.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// Overrides the current thread's CurrentUICulture property for all
56 | /// resource lookups using this strongly typed resource class.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/TSTunnels/Common/Messages/StreamError.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Net.Sockets;
5 | using System.Text;
6 |
7 | namespace TSTunnels.Common.Messages
8 | {
9 | [Serializable]
10 | public class StreamError : ChannelMessage
11 | {
12 | public readonly int StreamIndex;
13 | public readonly string ExceptionType;
14 | public readonly string Message;
15 | public readonly string StackTrace;
16 |
17 | public StreamError(int StreamIndex, Exception Exception)
18 | : base(MessageType.StreamError)
19 | {
20 | this.StreamIndex = StreamIndex;
21 | ExceptionType = Exception.GetType().Name;
22 | Message = Exception.Message ?? "";
23 | StackTrace = Exception.StackTrace ?? "";
24 | }
25 |
26 | protected StreamError(BinaryReader reader)
27 | : base(reader)
28 | {
29 | StreamIndex = reader.ReadInt32();
30 | ExceptionType = reader.ReadString();
31 | Message = reader.ReadString();
32 | StackTrace = reader.ReadString();
33 | }
34 |
35 | protected override void Serialize(BinaryWriter writer)
36 | {
37 | base.Serialize(writer);
38 | writer.Write(StreamIndex);
39 | writer.Write(ExceptionType);
40 | writer.Write(Message);
41 | writer.Write(StackTrace);
42 | }
43 |
44 | public override string ToString()
45 | {
46 | return base.ToString() + ": " + ExceptionType + ": " + Message;
47 | }
48 |
49 | public void Process(IStreamServer server)
50 | {
51 | ProcessStreams(server.Streams);
52 | ProcessListeners(server.Listeners);
53 | }
54 |
55 | private void ProcessStreams(IDictionary streams)
56 | {
57 | Stream stream;
58 | lock (streams)
59 | {
60 | if (!streams.ContainsKey(StreamIndex)) return;
61 | stream = streams[StreamIndex];
62 | }
63 | if (Message.Length != 0)
64 | {
65 | try
66 | {
67 | var data = Encoding.UTF8.GetBytes(Message);
68 | stream.Write(data, 0, data.Length);
69 | }
70 | catch (IOException)
71 | {
72 | }
73 | }
74 | try
75 | {
76 | stream.Close();
77 | }
78 | catch (IOException)
79 | {
80 | }
81 | lock (streams)
82 | {
83 | if (streams.ContainsKey(StreamIndex)) streams.Remove(StreamIndex);
84 | }
85 | }
86 |
87 | private void ProcessListeners(IDictionary listeners)
88 | {
89 | TcpListener listener;
90 | lock (listeners)
91 | {
92 | if (!listeners.ContainsKey(StreamIndex)) return;
93 | listener = listeners[StreamIndex];
94 | }
95 | try
96 | {
97 | listener.Stop();
98 | }
99 | catch (IOException)
100 | {
101 | }
102 | lock (listeners)
103 | {
104 | if (listeners.ContainsKey(StreamIndex)) listeners.Remove(StreamIndex);
105 | }
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/TSTunnels/Client/WtsApi32.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using Microsoft.Win32;
4 | using System.Text;
5 | using System.Threading;
6 |
7 | namespace TSTunnels.Client
8 | {
9 | namespace WtsApi32
10 | {
11 | public delegate ChannelReturnCodes VirtualChannelInitDelegate(ref IntPtr initHandle, ChannelDef[] channels, int channelCount, int versionRequested, [MarshalAs(UnmanagedType.FunctionPtr)] ChannelInitEventDelegate channelInitEventProc);
12 | public delegate ChannelReturnCodes VirtualChannelOpenDelegate(IntPtr initHandle, ref int openHandle, [MarshalAs(UnmanagedType.LPStr)] string channelName, [MarshalAs(UnmanagedType.FunctionPtr)] ChannelOpenEventDelegate channelOpenEventProc);
13 | public delegate ChannelReturnCodes VirtualChannelCloseDelegate(int openHandle);
14 | public delegate ChannelReturnCodes VirtualChannelWriteDelegate(int openHandle, IntPtr data, uint dataLength, IntPtr userData);
15 |
16 | public delegate void ChannelInitEventDelegate(IntPtr initHandle, ChannelEvents Event, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] data, int dataLength);
17 | public delegate void ChannelOpenEventDelegate(int openHandle, ChannelEvents Event, IntPtr data, int dataLength, uint totalLength, ChannelFlags dataFlags);
18 |
19 | [StructLayout(LayoutKind.Sequential)]
20 | public struct ChannelEntryPoints
21 | {
22 | public int Size;
23 | public int ProtocolVersion;
24 | [MarshalAs(UnmanagedType.FunctionPtr)]
25 | public VirtualChannelInitDelegate VirtualChannelInit;
26 | [MarshalAs(UnmanagedType.FunctionPtr)]
27 | public VirtualChannelOpenDelegate VirtualChannelOpen;
28 | [MarshalAs(UnmanagedType.FunctionPtr)]
29 | public VirtualChannelCloseDelegate VirtualChannelClose;
30 | [MarshalAs(UnmanagedType.FunctionPtr)]
31 | public VirtualChannelWriteDelegate VirtualChannelWrite;
32 | }
33 |
34 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
35 | public struct ChannelDef
36 | {
37 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
38 | public string name;
39 | public ChannelOptions options;
40 | }
41 |
42 | public enum ChannelEvents
43 | {
44 | Initialized = 0,
45 | Connected = 1,
46 | V1Connected = 2,
47 | Disconnected = 3,
48 | Terminated = 4,
49 | DataReceived = 10,
50 | WriteComplete = 11,
51 | WriteCanceled = 12
52 | }
53 |
54 | [Flags]
55 | public enum ChannelFlags
56 | {
57 | First = 0x01,
58 | Last = 0x02,
59 | Only = First | Last,
60 | Middle = 0,
61 | Fail = 0x100,
62 | ShowProtocol = 0x10,
63 | Suspend = 0x20,
64 | Resume = 0x40
65 | }
66 |
67 | [Flags]
68 | public enum ChannelOptions : uint
69 | {
70 | Initialized = 0x80000000,
71 | EncryptRDP = 0x40000000,
72 | EncryptSC = 0x20000000,
73 | EncryptCS = 0x10000000,
74 | PriorityHigh = 0x08000000,
75 | PriorityMedium = 0x04000000,
76 | PriorityLow = 0x02000000,
77 | CompressRDP = 0x00800000,
78 | Compress = 0x00400000,
79 | ShowProtocol = 0x00200000
80 | }
81 |
82 | public enum ChannelReturnCodes
83 | {
84 | Ok = 0,
85 | AlreadyInitialized = 1,
86 | NotInitialized = 2,
87 | AlreadyConnected = 3,
88 | NotConnected = 4,
89 | TooManyChanels = 5,
90 | BadChannel = 6,
91 | BadChannelHandle = 7,
92 | NoBuffer = 8,
93 | BadInitHandle = 9,
94 | NotOpen = 10,
95 | BadProc = 11,
96 | NoMemory = 12,
97 | UnknownChannelName = 13,
98 | AlreadyOpen = 14,
99 | NotInVirtualchannelEntry = 15,
100 | NullData = 16,
101 | ZeroLength = 17
102 | }
103 | }
104 | }
--------------------------------------------------------------------------------
/TSTunnels/TSTunnels.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 9.0.30729
7 | 2.0
8 | {46202B33-3B41-4B2B-B349-9DE165C8883A}
9 | Library
10 | Properties
11 | TSTunnels
12 | TSTunnels
13 | v2.0
14 | 512
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 |
35 | False
36 | ..\tools\ExportDllAttribute.dll
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
78 |
79 | "$(SolutionDir)tools\ExportDll.exe" "$(TargetPath)" /$(ConfigurationName)
80 | regsvr32 /s "$(TargetPath)"
81 |
82 |
--------------------------------------------------------------------------------
/TSTunnels.UI/TSTunnels.UI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 9.0.30729
7 | 2.0
8 | {8D98224E-FDA0-422F-BDAA-8AF5BCE5F28A}
9 | WinExe
10 | Properties
11 | TSTunnels.UI
12 | TSTunnels.UI
13 | v2.0
14 | 512
15 | App.ico
16 |
17 |
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | Form
45 |
46 |
47 | UI.cs
48 |
49 |
50 |
51 |
52 | UI.cs
53 |
54 |
55 | ResXFileCodeGenerator
56 | Resources.Designer.cs
57 | Designer
58 |
59 |
60 | True
61 | Resources.resx
62 |
63 |
64 | SettingsSingleFileGenerator
65 | Settings.Designer.cs
66 |
67 |
68 | True
69 | Settings.settings
70 | True
71 |
72 |
73 |
74 |
75 |
76 | {46202B33-3B41-4B2B-B349-9DE165C8883A}
77 | TSTunnels
78 |
79 |
80 |
81 |
82 |
83 |
84 |
91 |
92 | xcopy /d/y $(TargetDir)*.* \\hunnypot\c$\usr\src\darkskies\winapps\$(SolutionName)\$(ProjectName)\$(OutDir)
93 |
94 |
--------------------------------------------------------------------------------
/TSTunnels.UI/UI.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Text;
7 | using System.Windows.Forms;
8 | using TSTunnels.Server;
9 |
10 | namespace TSTunnels.UI
11 | {
12 | public partial class UI : Form
13 | {
14 | private readonly Server.Server Server;
15 |
16 | public UI()
17 | {
18 | InitializeComponent();
19 | Icon = Win32Api.GetApplicationIcon();
20 | Server = new Server.Server();
21 | Server.Connected += Server_Connected;
22 | Server.ForwardedPortAdded += Server_ForwardedPortAdded;
23 | Server.ForwardedPortRemoved += Server_ForwardedPortRemoved;
24 | Server.MessageLogged += Server_MessageLogged;
25 | }
26 |
27 | private void UI_Load(object sender, EventArgs e)
28 | {
29 | Server.Connect();
30 | }
31 |
32 | private bool CloseInProgress;
33 | private void UI_FormClosing(object sender, FormClosingEventArgs e)
34 | {
35 | if (CloseInProgress || forwardedPortsListBox.Items.Count == 0) return;
36 | CloseInProgress = true;
37 | e.Cancel = true;
38 | AppendLogMessage("Cancelling all port forwardings");
39 | foreach (ForwardedPort forwardedPort in forwardedPortsListBox.Items)
40 | {
41 | forwardedPort.Remove();
42 | }
43 | }
44 |
45 | private void UI_FormClosed(object sender, FormClosedEventArgs e)
46 | {
47 | Server.Disconnect();
48 | }
49 |
50 | private void Server_ForwardedPortAdded(object sender, ForwardedPortEventArgs e)
51 | {
52 | if (InvokeRequired)
53 | {
54 | Invoke(new EventHandler(Server_ForwardedPortAdded), new[] { sender, e });
55 | return;
56 | }
57 | forwardedPortsListBox.Items.Add(e.ForwardedPort);
58 | sourceTextBox.Text = string.Empty;
59 | destinationTextBox.Text = string.Empty;
60 | }
61 |
62 | private void Server_ForwardedPortRemoved(object sender, ForwardedPortEventArgs e)
63 | {
64 | if (InvokeRequired)
65 | {
66 | Invoke(new EventHandler(Server_ForwardedPortRemoved), new[] { sender, e });
67 | return;
68 | }
69 | forwardedPortsListBox.Items.Remove(e.ForwardedPort);
70 | sourceTextBox.Text = e.ForwardedPort.ListenEndPoint;
71 | destinationTextBox.Text = e.ForwardedPort.ConnectEndPoint;
72 | (e.ForwardedPort.Direction == ForwardDirection.Local ? localRadioButton : remoteRadioButton).Checked = true;
73 | if (CloseInProgress && forwardedPortsListBox.Items.Count == 0) Close();
74 | }
75 |
76 | public void Server_Connected(object sender, ConnectedEventArgs e)
77 | {
78 | if (InvokeRequired)
79 | {
80 | Invoke(new EventHandler(Server_Connected), new[] { sender, e });
81 | return;
82 | }
83 | portForwardingGroupBox.Enabled = true;
84 | toolTip1.SetToolTip(localRadioButton, "client -> " + e.MachineName + " => " + Environment.MachineName + " -> server");
85 | toolTip1.SetToolTip(remoteRadioButton, "client -> " + Environment.MachineName + " => " + e.MachineName + " -> server");
86 | }
87 |
88 | public void Server_MessageLogged(object sender, MessageLoggedEventArgs e)
89 | {
90 | if (InvokeRequired)
91 | {
92 | Invoke(new EventHandler(Server_MessageLogged), new[] { sender, e });
93 | return;
94 | }
95 | AppendLogMessage(e.Message);
96 | }
97 |
98 | private void AppendLogMessage(object message)
99 | {
100 | eventLogListBox.SelectedIndex = eventLogListBox.Items.Add(DateTime.Now + "\t" + message);
101 | }
102 |
103 | private void addButton_Click(object sender, EventArgs e)
104 | {
105 | try
106 | {
107 | var listenEndPoint = sourceTextBox.Text.Split(':');
108 | if (listenEndPoint[0].Length == 0 || listenEndPoint.Length > 2)
109 | {
110 | MessageBox.Show("You need to specify a source address in the form \"[host.name:]port\"", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
111 | return;
112 | }
113 | var listenAddress = listenEndPoint.Length > 1 ? listenEndPoint[0] : "127.0.0.1";
114 | var listenPort = int.Parse(listenEndPoint.Length > 1 ? listenEndPoint[1] : listenEndPoint[0]);
115 | var connectEndPoint = destinationTextBox.Text.Split(':');
116 | if (connectEndPoint[0].Length == 0 || connectEndPoint.Length > 2)
117 | {
118 | MessageBox.Show("You need to specify a destination address in the form \"[host.name:]port\"", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
119 | return;
120 | }
121 | var connectAddress = connectEndPoint.Length > 1 ? connectEndPoint[0] : "127.0.0.1";
122 | var connectPort = int.Parse(connectEndPoint.Length > 1 ? connectEndPoint[1] : connectEndPoint[0]);
123 | (localRadioButton.Checked ? (Server.Server.CreatePort)Server.CreateClientPort : Server.CreateServerPort)(listenAddress, listenPort, connectAddress, connectPort);
124 | }
125 | catch (Exception ex)
126 | {
127 | AppendLogMessage(ex);
128 | }
129 | }
130 |
131 | private void removeButton_Click(object sender, EventArgs e)
132 | {
133 | var forwardedPort = forwardedPortsListBox.SelectedItem as ForwardedPort;
134 | if (forwardedPort != null) forwardedPort.Remove();
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/TSTunnels.UI/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/TSTunnels.UI/UI.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | 17, 17
122 |
123 |
--------------------------------------------------------------------------------
/TSTunnels/Client/Client.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Net.Sockets;
6 | using System.Runtime.InteropServices;
7 | using System.Windows.Forms;
8 | using TSTunnels.Client.WtsApi32;
9 | using TSTunnels.Common;
10 | using TSTunnels.Common.Messages;
11 |
12 | namespace TSTunnels.Client
13 | {
14 | public class Client : IStreamServer
15 | {
16 | private readonly ChannelEntryPoints entryPoints;
17 | private readonly ChannelInitEventDelegate channelInitEventDelegate;
18 | private readonly ChannelOpenEventDelegate channelOpenEventDelegate;
19 |
20 | private IntPtr Channel;
21 | private int OpenChannel;
22 |
23 | public Client(ChannelEntryPoints entry)
24 | {
25 | entryPoints = entry;
26 | channelInitEventDelegate = VirtualChannelInitEventProc;
27 | channelOpenEventDelegate = VirtualChannelOpenEvent;
28 | Streams = new Dictionary();
29 | Listeners = new Dictionary();
30 | }
31 |
32 | public bool VirtualChannelInit()
33 | {
34 | var cd = new ChannelDef[1];
35 | cd[0] = new ChannelDef { name = ChannelMessage.ChannelName };
36 | var ret = entryPoints.VirtualChannelInit(ref Channel, cd, 1, 1, channelInitEventDelegate);
37 | if (ret != ChannelReturnCodes.Ok)
38 | {
39 | MessageBox.Show("TSTunnels: RDP Virtual channel Init Failed.\n" + ret, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
40 | return false;
41 | }
42 | return true;
43 | }
44 |
45 | private void VirtualChannelInitEventProc(IntPtr initHandle, ChannelEvents Event, byte[] data, int dataLength)
46 | {
47 | Debug.Print(DateTime.Now + " " + Environment.MachineName + ": VirtualChannelInitEventProc: " + Event);
48 | switch (Event)
49 | {
50 | case ChannelEvents.Initialized:
51 | break;
52 | case ChannelEvents.Connected:
53 | var ret = entryPoints.VirtualChannelOpen(initHandle, ref OpenChannel, ChannelMessage.ChannelName, channelOpenEventDelegate);
54 | if (ret != ChannelReturnCodes.Ok)
55 | {
56 | MessageBox.Show("TSTunnels: Open of RDP virtual channel failed.\n" + ret, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
57 | }
58 | else
59 | {
60 | /*main = new frmMain(entryPoints, OpenChannel);
61 | main.Show();
62 | main.Hide();
63 | string servername = System.Text.Encoding.Unicode.GetString(data);
64 | servername = servername.Substring(0, servername.IndexOf('\0'));
65 | main.Text = "TS addin in C#: " + servername;*/
66 | }
67 | break;
68 | case ChannelEvents.V1Connected:
69 | MessageBox.Show("TSTunnels: Connecting to a non Windows 2000 Terminal Server.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
70 | break;
71 | case ChannelEvents.Disconnected:
72 | //main.RealClosing = true;
73 | //main.Close();
74 | break;
75 | case ChannelEvents.Terminated:
76 | break;
77 | }
78 | }
79 |
80 | private MemoryStream memoryStream;
81 | public void VirtualChannelOpenEvent(int openHandle, ChannelEvents Event, IntPtr pData, int dataLength, uint totalLength, ChannelFlags dataFlags)
82 | {
83 | Debug.Print(DateTime.Now + " " + Environment.MachineName + ": VirtualChannelOpenEvent: " + Event);
84 | switch (Event)
85 | {
86 | case ChannelEvents.DataReceived:
87 | var data = new byte[dataLength];
88 | Marshal.Copy(pData, data, 0, dataLength);
89 | switch (dataFlags & ChannelFlags.Only)
90 | {
91 | case ChannelFlags.Only:
92 | MessageReceived(ChannelMessage.FromByteArray(data));
93 | break;
94 | case ChannelFlags.First:
95 | memoryStream = new MemoryStream((int)totalLength);
96 | memoryStream.Write(data, 0, data.Length);
97 | break;
98 | case ChannelFlags.Middle:
99 | if (memoryStream != null)
100 | {
101 | memoryStream.Write(data, 0, data.Length);
102 | }
103 | break;
104 | case ChannelFlags.Last:
105 | if (memoryStream != null)
106 | {
107 | memoryStream.Write(data, 0, data.Length);
108 | memoryStream.Position = 0;
109 | MessageReceived(ChannelMessage.FromStream(memoryStream));
110 | memoryStream = null;
111 | }
112 | break;
113 | }
114 | break;
115 | case ChannelEvents.WriteCanceled:
116 | case ChannelEvents.WriteComplete:
117 | /*
118 | * The VirtualChannelWrite function is asynchronous. When the write operation has been completed,
119 | * your VirtualChannelOpenEvent function receives a CHANNEL_EVENT_WRITE_COMPLETE notification.
120 | * Until that notification is received, the caller must not free or reuse the pData buffer passed to VirtualChannelWrite
121 | */
122 | Marshal.FreeHGlobal(pData);
123 | break;
124 | }
125 | }
126 |
127 | #region Implementation of IStreamServer
128 |
129 | public int ConnectionCount { get; set; }
130 | public IDictionary Listeners { get; private set; }
131 | public IDictionary Streams { get; private set; }
132 |
133 | public void Log(object message)
134 | {
135 | Debug.Print(DateTime.Now + " " + Environment.MachineName + ": Log: " + message);
136 | }
137 |
138 | public void MessageReceived(ChannelMessage msg)
139 | {
140 | switch (msg.Type)
141 | {
142 | case MessageType.HelloRequest:
143 | ((HelloRequest)msg).Process(this);
144 | break;
145 | case MessageType.ConnectRequest:
146 | ((ConnectRequest)msg).Process(this);
147 | break;
148 | case MessageType.ListenRequest:
149 | ((ListenRequest)msg).Process(this);
150 | break;
151 | case MessageType.ConnectResponse:
152 | ((ConnectResponse)msg).Process(this);
153 | break;
154 | case MessageType.StreamData:
155 | ((StreamData)msg).Process(this);
156 | break;
157 | case MessageType.StreamError:
158 | ((StreamError)msg).Process(this);
159 | break;
160 | }
161 | }
162 |
163 | public bool WriteMessage(ChannelMessage msg)
164 | {
165 | var data = msg.ToByteArray();
166 | var len = 4 + data.Length;
167 | var ptr = Marshal.AllocHGlobal(len);
168 | Marshal.WriteInt32(ptr, 0, data.Length);
169 | Marshal.Copy(data, 0, new IntPtr(ptr.ToInt32() + 4), data.Length);
170 | var ret = entryPoints.VirtualChannelWrite(OpenChannel, ptr, (uint)len, ptr);
171 | return ret == ChannelReturnCodes.Ok;
172 | }
173 |
174 | #endregion
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/TSTunnels/Server/Server.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.IO;
5 | using System.Net.Sockets;
6 | using System.Text;
7 | using System.Threading;
8 | using TSTunnels.Common;
9 | using TSTunnels.Common.Messages;
10 |
11 | namespace TSTunnels.Server
12 | {
13 | public class Server : IStreamServer
14 | {
15 | private IntPtr mHandle;
16 | private BinaryReader reader;
17 |
18 | public bool IsConnected { get; private set; }
19 | private bool SeenHello;
20 |
21 | public delegate void CreatePort(string listenAddress, int listenPort, string connectAddress, int connectPort);
22 |
23 | class ClientListener
24 | {
25 | public Action ListenResponse;
26 | public Action StreamError;
27 | public Action AcceptRequest;
28 | }
29 | private readonly Dictionary clientListeners = new Dictionary();
30 |
31 | #region Events
32 |
33 | public EventHandler Connected;
34 |
35 | protected void OnConnected(string machineName)
36 | {
37 | if (Connected != null)
38 | Connected(this, new ConnectedEventArgs(machineName));
39 | }
40 |
41 | public EventHandler ForwardedPortAdded;
42 |
43 | protected void OnForwardedPortAdded(ForwardedPort forwardedPort)
44 | {
45 | if (ForwardedPortAdded != null)
46 | ForwardedPortAdded(this, new ForwardedPortEventArgs(forwardedPort));
47 | }
48 |
49 | public EventHandler ForwardedPortRemoved;
50 |
51 | protected void OnForwardedPortRemoved(ForwardedPort forwardedPort)
52 | {
53 | if (ForwardedPortRemoved != null)
54 | ForwardedPortRemoved(this, new ForwardedPortEventArgs(forwardedPort));
55 | }
56 |
57 | public EventHandler MessageLogged;
58 |
59 | protected void OnMessageLogged(string message)
60 | {
61 | if (MessageLogged != null)
62 | MessageLogged(this, new MessageLoggedEventArgs(message));
63 | }
64 |
65 | #endregion
66 |
67 | public Server()
68 | {
69 | Streams = new Dictionary();
70 | Listeners = new Dictionary();
71 | }
72 |
73 | private delegate void Action();
74 | public void Connect()
75 | {
76 | mHandle = WtsApi32.WTSVirtualChannelOpen(IntPtr.Zero, -1, ChannelMessage.ChannelName);
77 | if (mHandle == IntPtr.Zero)
78 | {
79 | Log("RDP Virtual channel Open Failed: " + new Win32Exception().Message);
80 | return;
81 | }
82 |
83 | try
84 | {
85 | var stream = WtsApi32.WTSVirtualChannelQuery_WTSVirtualFileHandle(mHandle);
86 | reader = new BinaryReader(new BufferedStream(stream));
87 | }
88 | catch (Win32Exception ex)
89 | {
90 | Log("RDP Virtual channel Query Failed: " + ex.Message);
91 | return;
92 | }
93 |
94 | IsConnected = true;
95 |
96 | Action process = Process;
97 | process.BeginInvoke(process.EndInvoke, null);
98 |
99 | Action hello = () =>
100 | {
101 | while (!SeenHello && IsConnected)
102 | {
103 | WriteMessage(new HelloRequest());
104 | Thread.Sleep(200);
105 | }
106 | };
107 | hello.BeginInvoke(hello.EndInvoke, null);
108 | }
109 |
110 | public void Disconnect()
111 | {
112 | IsConnected = false;
113 | if (reader != null) reader.Close();
114 | var ret = WtsApi32.WTSVirtualChannelClose(mHandle);
115 | }
116 |
117 | private void Process()
118 | {
119 | while (IsConnected)
120 | {
121 | try
122 | {
123 | var len = reader.ReadInt32();
124 | var buff = reader.ReadBytes(len);
125 | MessageReceived(ChannelMessage.FromByteArray(buff));
126 | }
127 | catch (OperationCanceledException)
128 | {
129 | return;
130 | }
131 | catch (Exception ex)
132 | {
133 | Log(ex);
134 | }
135 | }
136 | }
137 |
138 | public void CreateClientPort(string listenAddress, int listenPort, string connectAddress, int connectPort)
139 | {
140 | var listenIndex = ++ConnectionCount;
141 | ForwardedPort forwardedPort = null;
142 | var listener = new ClientListener
143 | {
144 | ListenResponse = response =>
145 | {
146 | forwardedPort = new ForwardedPort
147 | {
148 | Direction = ForwardDirection.Local,
149 | ListenEndPoint = listenAddress + ":" + listenPort,
150 | ConnectEndPoint = connectAddress + ":" + connectPort,
151 | Remove = () =>
152 | {
153 | Log("Cancelling local port " + listenAddress + ":" + listenPort + " forwarding to " + connectAddress + ":" + connectPort + " requested");
154 | WriteMessage(new StreamError(listenIndex, new EndOfStreamException()));
155 | },
156 | };
157 | Log("Local port forwarding from " + listenAddress + ":" + listenPort + " enabled");
158 | OnForwardedPortAdded(forwardedPort);
159 | },
160 | StreamError = error =>
161 | {
162 | if (forwardedPort == null)
163 | {
164 | Log("Local port forwarding from " + listenAddress + ":" + listenPort + " failed: " + error.Message);
165 | lock (clientListeners)
166 | {
167 | if (clientListeners.ContainsKey(listenIndex)) clientListeners.Remove(listenIndex);
168 | }
169 | }
170 | else
171 | {
172 | Log("Cancelled local port " + listenAddress + ":" + listenPort + " forwarding to " + connectAddress + ":" + connectPort);
173 | OnForwardedPortRemoved(forwardedPort);
174 | }
175 | },
176 | AcceptRequest = request =>
177 | {
178 | Log("Opening forwarded connection " + request.RemoteEndPoint + " to " + connectAddress + ":" + connectPort);
179 | new ConnectRequest(request.StreamIndex, request.RemoteEndPoint, connectAddress, connectPort).Process(this);
180 | },
181 | };
182 | lock (clientListeners)
183 | {
184 | clientListeners[listenIndex] = listener;
185 | }
186 | Log("Requesting local port " + listenAddress + ":" + listenPort + " forward to " + connectAddress + ":" + connectPort);
187 | WriteMessage(new ListenRequest(listenIndex, listenAddress, listenPort));
188 | }
189 |
190 | public void CreateServerPort(string listenAddress, int listenPort, string connectAddress, int connectPort)
191 | {
192 | try
193 | {
194 | var listenIndex = ++ConnectionCount;
195 | ForwardedPort forwardedPort = null;
196 | Listeners[listenIndex] = TcpListenerHelper.Start(listenAddress, listenPort, client =>
197 | {
198 | var streamIndex = ++ConnectionCount;
199 | Log("Attempting to forward remote port " + client.Client.RemoteEndPoint + " to " + connectAddress + ":" + connectPort);
200 | Streams[streamIndex] = client.GetStream();
201 | WriteMessage(new ConnectRequest(streamIndex, client.Client.RemoteEndPoint.ToString(), connectAddress, connectPort));
202 | }, exception =>
203 | {
204 | if (forwardedPort == null)
205 | {
206 | Log("Remote port " + listenAddress + ":" + listenPort + " forwarding to " + connectAddress + ":" + connectPort + " exception: " + exception);
207 | }
208 | else
209 | {
210 | Log("Cancelled remote port " + listenAddress + ":" + listenPort + " forwarding to " + connectAddress + ":" + connectPort);
211 | OnForwardedPortRemoved(forwardedPort);
212 | }
213 | });
214 | Log("Remote port " + listenAddress + ":" + listenPort + " forwarding to " + connectAddress + ":" + connectPort);
215 | forwardedPort = new ForwardedPort
216 | {
217 | Direction = ForwardDirection.Remote,
218 | ListenEndPoint = listenAddress + ":" + listenPort,
219 | ConnectEndPoint = connectAddress + ":" + connectPort,
220 | Remove = () =>
221 | {
222 | Log("Cancelling remote port " + listenAddress + ":" + listenPort + " forwarding to " + connectAddress + ":" + connectPort);
223 | new StreamError(listenIndex, new EndOfStreamException()).Process(this);
224 | },
225 | };
226 | OnForwardedPortAdded(forwardedPort);
227 | }
228 | catch (Exception ex)
229 | {
230 | Log("Remote port " + listenAddress + ":" + listenPort + " forwarding to " + connectAddress + ":" + connectPort + " failed: " + ex);
231 | }
232 | }
233 |
234 | #region Implementation of IStreamServer
235 |
236 | public int ConnectionCount { get; set; }
237 | public IDictionary Listeners { get; private set; }
238 | public IDictionary Streams { get; private set; }
239 |
240 | public void Log(object message)
241 | {
242 | OnMessageLogged(message.ToString());
243 | }
244 |
245 | public void MessageReceived(ChannelMessage msg)
246 | {
247 | switch (msg.Type)
248 | {
249 | default:
250 | Log("Unknown message: " + msg);
251 | break;
252 | case MessageType.HelloResponse:
253 | {
254 | var response = (HelloResponse)msg;
255 | if (!SeenHello)
256 | {
257 | SeenHello = true;
258 | Log(response.MachineName + " connected to " + Environment.MachineName);
259 | OnConnected(response.MachineName);
260 | }
261 | }
262 | break;
263 | case MessageType.ListenResponse:
264 | {
265 | var response = (ListenResponse)msg;
266 | ClientListener listener = null;
267 | lock (clientListeners)
268 | {
269 | if (clientListeners.ContainsKey(response.ListenIndex)) listener = clientListeners[response.ListenIndex];
270 | }
271 | if (listener != null) listener.ListenResponse(response);
272 | }
273 | break;
274 | case MessageType.AcceptRequest:
275 | {
276 | var request = (AcceptRequest)msg;
277 | ClientListener listener = null;
278 | lock (clientListeners)
279 | {
280 | if (clientListeners.ContainsKey(request.ListenIndex)) listener = clientListeners[request.ListenIndex];
281 | }
282 | if (listener != null) listener.AcceptRequest(request);
283 | }
284 | break;
285 | case MessageType.ConnectResponse:
286 | ((ConnectResponse)msg).Process(this);
287 | break;
288 | case MessageType.StreamData:
289 | ((StreamData)msg).Process(this);
290 | break;
291 | case MessageType.StreamError:
292 | {
293 | var error = (StreamError)msg;
294 | ClientListener listener = null;
295 | lock (clientListeners)
296 | {
297 | if (clientListeners.ContainsKey(error.StreamIndex)) listener = clientListeners[error.StreamIndex];
298 | }
299 | if (listener != null)
300 | {
301 | listener.StreamError(error);
302 | }
303 | else
304 | {
305 | ((StreamError)msg).Process(this);
306 | }
307 | }
308 | break;
309 | }
310 | }
311 |
312 | public bool WriteMessage(ChannelMessage msg)
313 | {
314 | var data = msg.ToByteArray();
315 | int written;
316 | var ret = WtsApi32.WTSVirtualChannelWrite(mHandle, data, data.Length, out written);
317 | if (ret) return true;
318 | var ex = new Win32Exception();
319 | if (!SeenHello && ex.NativeErrorCode == 1 /* Incorrect Function */) return false;
320 | Log("RDP Virtual channel Write Failed: " + ex.Message);
321 | return false;
322 | }
323 |
324 | #endregion
325 | }
326 | }
327 |
--------------------------------------------------------------------------------
/TSTunnels.UI/UI.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace TSTunnels.UI
2 | {
3 | partial class UI
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.components = new System.ComponentModel.Container();
32 | this.eventLogListBox = new System.Windows.Forms.ListBox();
33 | this.eventLogGroupBox = new System.Windows.Forms.GroupBox();
34 | this.portForwardingGroupBox = new System.Windows.Forms.GroupBox();
35 | this.remoteRadioButton = new System.Windows.Forms.RadioButton();
36 | this.localRadioButton = new System.Windows.Forms.RadioButton();
37 | this.destinationTextBox = new System.Windows.Forms.TextBox();
38 | this.addButton = new System.Windows.Forms.Button();
39 | this.removeButton = new System.Windows.Forms.Button();
40 | this.label4 = new System.Windows.Forms.Label();
41 | this.label3 = new System.Windows.Forms.Label();
42 | this.label2 = new System.Windows.Forms.Label();
43 | this.label1 = new System.Windows.Forms.Label();
44 | this.forwardedPortsListBox = new System.Windows.Forms.ListBox();
45 | this.sourceTextBox = new System.Windows.Forms.TextBox();
46 | this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
47 | this.eventLogGroupBox.SuspendLayout();
48 | this.portForwardingGroupBox.SuspendLayout();
49 | this.SuspendLayout();
50 | //
51 | // eventLogListBox
52 | //
53 | this.eventLogListBox.Dock = System.Windows.Forms.DockStyle.Fill;
54 | this.eventLogListBox.FormattingEnabled = true;
55 | this.eventLogListBox.Location = new System.Drawing.Point(3, 16);
56 | this.eventLogListBox.Name = "eventLogListBox";
57 | this.eventLogListBox.Size = new System.Drawing.Size(650, 199);
58 | this.eventLogListBox.TabIndex = 0;
59 | //
60 | // eventLogGroupBox
61 | //
62 | this.eventLogGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
63 | | System.Windows.Forms.AnchorStyles.Left)
64 | | System.Windows.Forms.AnchorStyles.Right)));
65 | this.eventLogGroupBox.Controls.Add(this.eventLogListBox);
66 | this.eventLogGroupBox.Location = new System.Drawing.Point(12, 207);
67 | this.eventLogGroupBox.Name = "eventLogGroupBox";
68 | this.eventLogGroupBox.Size = new System.Drawing.Size(656, 219);
69 | this.eventLogGroupBox.TabIndex = 1;
70 | this.eventLogGroupBox.TabStop = false;
71 | this.eventLogGroupBox.Text = "Event log";
72 | //
73 | // portForwardingGroupBox
74 | //
75 | this.portForwardingGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
76 | | System.Windows.Forms.AnchorStyles.Right)));
77 | this.portForwardingGroupBox.Controls.Add(this.remoteRadioButton);
78 | this.portForwardingGroupBox.Controls.Add(this.localRadioButton);
79 | this.portForwardingGroupBox.Controls.Add(this.destinationTextBox);
80 | this.portForwardingGroupBox.Controls.Add(this.addButton);
81 | this.portForwardingGroupBox.Controls.Add(this.removeButton);
82 | this.portForwardingGroupBox.Controls.Add(this.label4);
83 | this.portForwardingGroupBox.Controls.Add(this.label3);
84 | this.portForwardingGroupBox.Controls.Add(this.label2);
85 | this.portForwardingGroupBox.Controls.Add(this.label1);
86 | this.portForwardingGroupBox.Controls.Add(this.forwardedPortsListBox);
87 | this.portForwardingGroupBox.Controls.Add(this.sourceTextBox);
88 | this.portForwardingGroupBox.Enabled = false;
89 | this.portForwardingGroupBox.Location = new System.Drawing.Point(12, 12);
90 | this.portForwardingGroupBox.Name = "portForwardingGroupBox";
91 | this.portForwardingGroupBox.Size = new System.Drawing.Size(656, 189);
92 | this.portForwardingGroupBox.TabIndex = 0;
93 | this.portForwardingGroupBox.TabStop = false;
94 | this.portForwardingGroupBox.Text = "Port forwarding";
95 | //
96 | // remoteRadioButton
97 | //
98 | this.remoteRadioButton.AutoSize = true;
99 | this.remoteRadioButton.Location = new System.Drawing.Point(494, 163);
100 | this.remoteRadioButton.Name = "remoteRadioButton";
101 | this.remoteRadioButton.Size = new System.Drawing.Size(62, 17);
102 | this.remoteRadioButton.TabIndex = 6;
103 | this.remoteRadioButton.Text = "Re&mote";
104 | this.remoteRadioButton.UseVisualStyleBackColor = true;
105 | //
106 | // localRadioButton
107 | //
108 | this.localRadioButton.AutoSize = true;
109 | this.localRadioButton.Checked = true;
110 | this.localRadioButton.Location = new System.Drawing.Point(437, 163);
111 | this.localRadioButton.Name = "localRadioButton";
112 | this.localRadioButton.Size = new System.Drawing.Size(51, 17);
113 | this.localRadioButton.TabIndex = 5;
114 | this.localRadioButton.TabStop = true;
115 | this.localRadioButton.Text = "&Local";
116 | this.localRadioButton.UseVisualStyleBackColor = true;
117 | //
118 | // destinationTextBox
119 | //
120 | this.destinationTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
121 | this.destinationTextBox.Location = new System.Drawing.Point(281, 162);
122 | this.destinationTextBox.Name = "destinationTextBox";
123 | this.destinationTextBox.Size = new System.Drawing.Size(150, 20);
124 | this.destinationTextBox.TabIndex = 4;
125 | //
126 | // addButton
127 | //
128 | this.addButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
129 | this.addButton.Location = new System.Drawing.Point(562, 160);
130 | this.addButton.Name = "addButton";
131 | this.addButton.Size = new System.Drawing.Size(88, 23);
132 | this.addButton.TabIndex = 7;
133 | this.addButton.Text = "A&dd";
134 | this.addButton.UseVisualStyleBackColor = true;
135 | this.addButton.Click += new System.EventHandler(this.addButton_Click);
136 | //
137 | // removeButton
138 | //
139 | this.removeButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
140 | this.removeButton.Location = new System.Drawing.Point(562, 19);
141 | this.removeButton.Name = "removeButton";
142 | this.removeButton.Size = new System.Drawing.Size(88, 23);
143 | this.removeButton.TabIndex = 10;
144 | this.removeButton.Text = "&Remove";
145 | this.removeButton.UseVisualStyleBackColor = true;
146 | this.removeButton.Click += new System.EventHandler(this.removeButton_Click);
147 | //
148 | // label4
149 | //
150 | this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
151 | this.label4.AutoSize = true;
152 | this.label4.Location = new System.Drawing.Point(212, 165);
153 | this.label4.Name = "label4";
154 | this.label4.Size = new System.Drawing.Size(63, 13);
155 | this.label4.TabIndex = 3;
156 | this.label4.Text = "Destination:";
157 | //
158 | // label3
159 | //
160 | this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
161 | this.label3.AutoSize = true;
162 | this.label3.Location = new System.Drawing.Point(6, 165);
163 | this.label3.Name = "label3";
164 | this.label3.Size = new System.Drawing.Size(44, 13);
165 | this.label3.TabIndex = 1;
166 | this.label3.Text = "Source:";
167 | //
168 | // label2
169 | //
170 | this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
171 | this.label2.AutoSize = true;
172 | this.label2.Location = new System.Drawing.Point(6, 146);
173 | this.label2.Name = "label2";
174 | this.label2.Size = new System.Drawing.Size(123, 13);
175 | this.label2.TabIndex = 0;
176 | this.label2.Text = "Add new forwarded port:";
177 | //
178 | // label1
179 | //
180 | this.label1.AutoSize = true;
181 | this.label1.Location = new System.Drawing.Point(6, 24);
182 | this.label1.Name = "label1";
183 | this.label1.Size = new System.Drawing.Size(86, 13);
184 | this.label1.TabIndex = 8;
185 | this.label1.Text = "Forwarded ports:";
186 | //
187 | // forwardedPortsListBox
188 | //
189 | this.forwardedPortsListBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
190 | | System.Windows.Forms.AnchorStyles.Left)
191 | | System.Windows.Forms.AnchorStyles.Right)));
192 | this.forwardedPortsListBox.FormattingEnabled = true;
193 | this.forwardedPortsListBox.Location = new System.Drawing.Point(9, 48);
194 | this.forwardedPortsListBox.Name = "forwardedPortsListBox";
195 | this.forwardedPortsListBox.Size = new System.Drawing.Size(641, 95);
196 | this.forwardedPortsListBox.TabIndex = 9;
197 | //
198 | // sourceTextBox
199 | //
200 | this.sourceTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
201 | this.sourceTextBox.Location = new System.Drawing.Point(56, 162);
202 | this.sourceTextBox.Name = "sourceTextBox";
203 | this.sourceTextBox.Size = new System.Drawing.Size(150, 20);
204 | this.sourceTextBox.TabIndex = 2;
205 | //
206 | // UI
207 | //
208 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
209 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
210 | this.ClientSize = new System.Drawing.Size(680, 438);
211 | this.Controls.Add(this.portForwardingGroupBox);
212 | this.Controls.Add(this.eventLogGroupBox);
213 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
214 | this.MaximizeBox = false;
215 | this.Name = "UI";
216 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
217 | this.Text = "Remote Desktop Tunnels";
218 | this.Load += new System.EventHandler(this.UI_Load);
219 | this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.UI_FormClosed);
220 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.UI_FormClosing);
221 | this.eventLogGroupBox.ResumeLayout(false);
222 | this.portForwardingGroupBox.ResumeLayout(false);
223 | this.portForwardingGroupBox.PerformLayout();
224 | this.ResumeLayout(false);
225 |
226 | }
227 |
228 | #endregion
229 |
230 | private System.Windows.Forms.ListBox eventLogListBox;
231 | private System.Windows.Forms.GroupBox eventLogGroupBox;
232 | private System.Windows.Forms.GroupBox portForwardingGroupBox;
233 | private System.Windows.Forms.ListBox forwardedPortsListBox;
234 | private System.Windows.Forms.TextBox sourceTextBox;
235 | private System.Windows.Forms.Button removeButton;
236 | private System.Windows.Forms.Label label2;
237 | private System.Windows.Forms.Label label1;
238 | private System.Windows.Forms.TextBox destinationTextBox;
239 | private System.Windows.Forms.Label label4;
240 | private System.Windows.Forms.Label label3;
241 | private System.Windows.Forms.Button addButton;
242 | private System.Windows.Forms.RadioButton remoteRadioButton;
243 | private System.Windows.Forms.RadioButton localRadioButton;
244 | private System.Windows.Forms.ToolTip toolTip1;
245 | }
246 | }
247 |
248 |
--------------------------------------------------------------------------------