-
Notifications
You must be signed in to change notification settings - Fork 27
Expand file tree
/
Copy pathHttpSecureNonHttpDecryptServer.cs
More file actions
135 lines (122 loc) · 3.86 KB
/
HttpSecureNonHttpDecryptServer.cs
File metadata and controls
135 lines (122 loc) · 3.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
using System;
using System.IO;
using System.Net.Security;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace WebOne
{
/// <summary>
/// CONNECT Proxy Server for all protocols tunneling with full SSL decrypting
/// </summary>
class HttpSecureNonHttpDecryptServer
{
Stream ClientStream;
Stream RemoteStream;
HttpRequest RequestReal;
HttpResponse ResponseReal;
LogWriter Logger;
string HostName;
int PortNo;
/// <summary>
/// Start CONNECT proxy server emulation for already established NetworkStream.
/// </summary>
public HttpSecureNonHttpDecryptServer(HttpRequest Request, HttpResponse Response, string TargetServer, LogWriter Logger)
{
RequestReal = Request;
ResponseReal = Response;
ClientStream = Request.InputStream;
this.Logger = Logger;
HostName = TargetServer.Substring(0, TargetServer.IndexOf(":"));
PortNo = int.Parse(TargetServer.Substring(TargetServer.IndexOf(":") + 1));
}
/// <summary>
/// Accept an incoming "connection" by establishing tunnel & start data exchange.
/// </summary>
public void Accept()
{
if (ConfigFile.AllowNonHttpsCONNECT)
{
// Answer that this proxy supports CONNECT method
ResponseReal.ProtocolVersion = new Version(1, 1);
ResponseReal.StatusCode = 200;
ResponseReal.StatusMessage = " Connection established";
ResponseReal.SendHeaders(); //"HTTP/1.1 200 Connection established"
Logger.WriteLine(">Decrypt: {0}:{1}", HostName, PortNo);
}
else
{
// Reject connection request
string OnlyHTTPS = "This proxy is performing only HTTP and HTTPS tunneling.";
ResponseReal.ProtocolVersion = new Version(1, 1);
ResponseReal.StatusCode = 502;
ResponseReal.ContentType = "text/plain";
ResponseReal.ContentLength64 = OnlyHTTPS.Length;
ResponseReal.SendHeaders();
ResponseReal.OutputStream.Write(System.Text.Encoding.Default.GetBytes(OnlyHTTPS), 0, OnlyHTTPS.Length);
ResponseReal.Close();
Logger.WriteLine("<Not a HTTPS CONNECT, goodbye.");
return;
}
// Establish tunnel
TcpClient TunnelToRemote = new();
try
{
TunnelToRemote.Connect(HostName, PortNo);
Logger.WriteLine(" D tunnel connected.");
RemoteStream = new SslStream(TunnelToRemote.GetStream(), true);
((SslStream)RemoteStream).AuthenticateAsClient(HostName);
Logger.WriteLine(" D tunnel established.");
}
catch (Exception ex)
{
//An error occured, try to return nice error message, some clients like KVIrc will display it
Logger.WriteLine(" D connection failed: {0}.", ex.Message);
try { new StreamWriter(ClientStream).WriteLine("The proxy server is unable to connect with decryption: " + ex.Message); }
catch { };
ClientStream.Close();
return;
}
// Do routing
bool tunnelAlive = true;
byte[] clientBuffer = new byte[8192];
byte[] remoteBuffer = new byte[8192];
// Forward data from client to remote
var clientToRemote = Task.Run(() =>
{
try
{
int bytesRead;
while (tunnelAlive && (bytesRead = ClientStream.Read(clientBuffer, 0, clientBuffer.Length)) > 0)
{
RemoteStream.Write(clientBuffer, 0, bytesRead);
RemoteStream.Flush();
}
}
catch { }
tunnelAlive = false;
});
// Forward data from remote to client
var remoteToClient = Task.Run(() =>
{
try
{
int bytesRead;
while (tunnelAlive && (bytesRead = RemoteStream.Read(remoteBuffer, 0, remoteBuffer.Length)) > 0)
{
ClientStream.Write(remoteBuffer, 0, bytesRead);
ClientStream.Flush();
}
}
catch { }
tunnelAlive = false;
});
// Wait while connection is alive
Task.WhenAny(clientToRemote, remoteToClient).Wait();
tunnelAlive = false;
// All done, close
try { TunnelToRemote.Close(); } catch { }
try { ClientStream.Close(); } catch { }
Logger.WriteLine(" D connection to {0} closed.", RequestReal.RawUrl);
}
}
}