forked from atauenis/webone
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHttpSecurePassthroughServer.cs
More file actions
130 lines (117 loc) · 3.75 KB
/
HttpSecurePassthroughServer.cs
File metadata and controls
130 lines (117 loc) · 3.75 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
using System;
using System.IO;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace WebOne
{
/// <summary>
/// CONNECT Proxy Server for all protocols tunneling without SSL certificate spoof
/// </summary>
class HttpSecurePassthroughServer
{
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 HttpSecurePassthroughServer(HttpRequest Request, HttpResponse Response, LogWriter Logger)
{
RequestReal = Request;
ResponseReal = Response;
ClientStream = Request.InputStream;
this.Logger = Logger;
HostName = RequestReal.RawUrl.Substring(0, RequestReal.RawUrl.IndexOf(":"));
PortNo = int.Parse(RequestReal.RawUrl.Substring(RequestReal.RawUrl.IndexOf(":") + 1));
}
/// <summary>
/// Accept an incoming "connection" by establishing tunnel & start data exchange.
/// </summary>
public void Accept()
{
// Check for unwanted usage
if (PortNo != 443 && !ConfigFile.AllowNonHttpsCONNECT)
{
// 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;
}
// 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(">Passthrough: {0}", RequestReal.RawUrl);
// Establish tunnel
TcpClient TunnelToRemote = new();
try
{
TunnelToRemote.Connect(HostName, PortNo);
RemoteStream = TunnelToRemote.GetStream();
Logger.WriteLine(" PT tunnel established.", RequestReal.RawUrl);
}
catch (Exception ex)
{
//An error occured, try to return nice error message, some clients like KVIrc will display it
Logger.WriteLine(" PT Connection failed: {0}.", ex.Message);
try { new StreamWriter(ClientStream).WriteLine("The proxy server is unable to connect pass-though: " + 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(" PT connection to {0} closed.", RequestReal.RawUrl);
}
}
}