Skip to content
This repository was archived by the owner on Jul 9, 2023. It is now read-only.

Commit f26c560

Browse files
committed
issue #31, #32, #35
fix multiple issues reported
1 parent 37714ce commit f26c560

File tree

11 files changed

+92
-65
lines changed

11 files changed

+92
-65
lines changed

Titanium.Web.Proxy.Test/Program.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,6 @@ public static void Main(string[] args)
1414
NativeMethods.SetConsoleCtrlHandler(NativeMethods.Handler, true);
1515

1616

17-
Console.Write("Do you want to monitor HTTPS? (Y/N):");
18-
19-
var readLine = Console.ReadLine();
20-
if (readLine != null && readLine.Trim().ToLower() == "y")
21-
{
22-
Controller.EnableSsl = true;
23-
}
24-
25-
Console.Write("Do you want to set this as a System Proxy? (Y/N):");
26-
27-
var line = Console.ReadLine();
28-
if (line != null && line.Trim().ToLower() == "y")
29-
{
30-
Controller.SetAsSystemProxy = true;
31-
}
32-
3317
//Start proxy controller
3418
Controller.StartProxy();
3519

Titanium.Web.Proxy.Test/ProxyTestController.cs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Net;
34
using System.Text.RegularExpressions;
45
using Titanium.Web.Proxy.EventArguments;
@@ -8,29 +9,33 @@ namespace Titanium.Web.Proxy.Test
89
{
910
public class ProxyTestController
1011
{
11-
public int ListeningPort { get; set; }
12-
public bool EnableSsl { get; set; }
13-
public bool SetAsSystemProxy { get; set; }
12+
1413

1514
public void StartProxy()
1615
{
1716
ProxyServer.BeforeRequest += OnRequest;
1817
ProxyServer.BeforeResponse += OnResponse;
1918

20-
2119
//Exclude Https addresses you don't want to proxy
2220
//Usefull for clients that use certificate pinning
2321
//for example dropbox.com
24-
// ProxyServer.ExcludedHttpsHostNameRegex.Add(".dropbox.com");
25-
var explicitEndPoint = new ExplicitProxyEndPoint { EnableSsl = true, IpAddress = IPAddress.Any, Port = 8000 };
26-
var transparentEndPoint = new TransparentProxyEndPoint { EnableSsl = true, IpAddress = IPAddress.Loopback, Port = 443 };
22+
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Loopback, 8000, true){
23+
ExcludedHostNameRegex = new List<string>() { "dropbox.com" }
24+
};
25+
26+
var transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Loopback, 8001, true)
27+
{
28+
};
29+
2730
ProxyServer.AddEndPoint(explicitEndPoint);
2831
ProxyServer.AddEndPoint(transparentEndPoint);
2932
ProxyServer.Start();
30-
ProxyServer.SetAsSystemProxy(explicitEndPoint);
3133

34+
foreach (var endPoint in ProxyServer.ProxyEndPoints)
35+
Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ", endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port);
36+
37+
ProxyServer.SetAsSystemProxy(explicitEndPoint);
3238

33-
// Console.WriteLine("Proxy listening on local machine port: {0} ", ProxyServer.ListeningPort);
3439
}
3540

3641
public void Stop()

Titanium.Web.Proxy/Extensions/HttpWebResponseExtensions.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,14 @@ public static class HttpWebResponseExtensions
88
{
99
public static Encoding GetResponseEncoding(this HttpWebSession response)
1010
{
11-
if (string.IsNullOrEmpty(response.Response.CharacterSet)) return Encoding.GetEncoding("ISO-8859-1");
12-
return Encoding.GetEncoding(response.Response.CharacterSet.Replace(@"""", string.Empty));
11+
if (string.IsNullOrEmpty(response.Response.CharacterSet))
12+
return Encoding.GetEncoding("ISO-8859-1");
13+
14+
try
15+
{
16+
return Encoding.GetEncoding(response.Response.CharacterSet.Replace(@"""", string.Empty));
17+
}
18+
catch { return Encoding.GetEncoding("ISO-8859-1"); }
1319
}
1420
}
1521
}

Titanium.Web.Proxy/Extensions/StreamExtensions.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@ public static class StreamHelper
88
{
99
public static void CopyToAsync(this Stream input, string initialData, Stream output, int bufferSize)
1010
{
11-
var bytes = Encoding.ASCII.GetBytes(initialData);
12-
output.Write(bytes, 0, bytes.Length);
11+
if(!string.IsNullOrEmpty(initialData))
12+
{
13+
var bytes = Encoding.ASCII.GetBytes(initialData);
14+
output.Write(bytes, 0, bytes.Length);
15+
}
16+
1317
CopyToAsync(input, output, bufferSize);
1418
}
1519

1620
//http://stackoverflow.com/questions/1540658/net-asynchronous-stream-read-write
17-
public static void CopyToAsync(this Stream input, Stream output, int bufferSize)
21+
private static void CopyToAsync(this Stream input, Stream output, int bufferSize)
1822
{
1923
try
2024
{

Titanium.Web.Proxy/Helpers/Tcp.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public static void SendRaw(Stream clientStream, string httpCmd, List<HttpHeader>
5151
try
5252
{
5353
sslStream = new SslStream(tunnelStream);
54-
sslStream.AuthenticateAsClient(hostName);
54+
sslStream.AuthenticateAsClient(hostName, null, ProxyServer.SupportedProtocols, false);
5555
tunnelStream = sslStream;
5656
}
5757
catch
@@ -69,10 +69,10 @@ public static void SendRaw(Stream clientStream, string httpCmd, List<HttpHeader>
6969
if (sb != null)
7070
clientStream.CopyToAsync(sb.ToString(), tunnelStream, BUFFER_SIZE);
7171
else
72-
clientStream.CopyToAsync(tunnelStream, BUFFER_SIZE);
72+
clientStream.CopyToAsync(string.Empty, tunnelStream, BUFFER_SIZE);
7373
});
7474

75-
var receiveRelay = Task.Factory.StartNew(() => tunnelStream.CopyToAsync(clientStream, BUFFER_SIZE));
75+
var receiveRelay = Task.Factory.StartNew(() => tunnelStream.CopyToAsync(string.Empty, clientStream, BUFFER_SIZE));
7676

7777
Task.WaitAll(sendRelay, receiveRelay);
7878
}

Titanium.Web.Proxy/Models/EndPoint.cs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,16 @@ namespace Titanium.Web.Proxy.Models
99
{
1010
public abstract class ProxyEndPoint
1111
{
12-
public IPAddress IpAddress { get; set; }
13-
public int Port { get; set; }
14-
public bool EnableSsl { get; set; }
12+
public ProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl)
13+
{
14+
this.IpAddress = IpAddress;
15+
this.Port = Port;
16+
this.EnableSsl = EnableSsl;
17+
}
18+
19+
public IPAddress IpAddress { get; internal set; }
20+
public int Port { get; internal set; }
21+
public bool EnableSsl { get; internal set; }
1522

1623
internal TcpListener listener { get; set; }
1724
}
@@ -20,11 +27,20 @@ public class ExplicitProxyEndPoint : ProxyEndPoint
2027
{
2128
internal bool IsSystemProxy { get; set; }
2229
public List<string> ExcludedHostNameRegex { get; set; }
23-
30+
31+
public ExplicitProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl)
32+
: base(IpAddress, Port, EnableSsl)
33+
{
34+
35+
}
2436
}
2537

2638
public class TransparentProxyEndPoint : ProxyEndPoint
2739
{
28-
40+
public TransparentProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl)
41+
: base(IpAddress, Port, EnableSsl)
42+
{
43+
44+
}
2945
}
3046
}

Titanium.Web.Proxy/Network/TcpConnectionManager.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Net.Security;
1010
using Titanium.Web.Proxy.Helpers;
1111
using System.Threading;
12+
using System.Security.Authentication;
1213

1314
namespace Titanium.Web.Proxy.Network
1415
{
@@ -76,7 +77,7 @@ private static TcpConnection CreateClient(string Hostname, int port, bool IsSecu
7677
try
7778
{
7879
sslStream = new SslStream(stream);
79-
sslStream.AuthenticateAsClient(Hostname);
80+
sslStream.AuthenticateAsClient(Hostname, null, ProxyServer.SupportedProtocols , false);
8081
stream = (Stream)sslStream;
8182
}
8283
catch

Titanium.Web.Proxy/ProxyServer.cs

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Titanium.Web.Proxy.Models;
1313
using Titanium.Web.Proxy.Network;
1414
using System.Linq;
15+
using System.Security.Authentication;
1516

1617
namespace Titanium.Web.Proxy
1718
{
@@ -33,15 +34,18 @@ public partial class ProxyServer
3334
private static readonly byte[] ChunkEnd =
3435
Encoding.ASCII.GetBytes(0.ToString("x2") + Environment.NewLine + Environment.NewLine);
3536

36-
private static List<ProxyEndPoint> _proxyEndPoints { get; set; }
37-
37+
#if NET45
38+
internal static SslProtocols SupportedProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Ssl3 ;
39+
#else
40+
public static SslProtocols SupportedProtocols = SslProtocols.Tls | SslProtocols.Ssl3;
41+
#endif
3842

3943
static ProxyServer()
4044
{
4145
CertManager = new CertificateManager("Titanium",
4246
"Titanium Root Certificate Authority");
4347

44-
_proxyEndPoints = new List<ProxyEndPoint>();
48+
ProxyEndPoints = new List<ProxyEndPoint>();
4549

4650
Initialize();
4751
}
@@ -56,6 +60,7 @@ static ProxyServer()
5660
public static event EventHandler<SessionEventArgs> BeforeRequest;
5761
public static event EventHandler<SessionEventArgs> BeforeResponse;
5862

63+
public static List<ProxyEndPoint> ProxyEndPoints { get; set; }
5964

6065
public static void Initialize()
6166
{
@@ -67,25 +72,25 @@ public static void AddEndPoint(ProxyEndPoint endPoint)
6772
if (proxyStarted)
6873
throw new Exception("Cannot add end points after proxy started.");
6974

70-
_proxyEndPoints.Add(endPoint);
75+
ProxyEndPoints.Add(endPoint);
7176
}
7277

7378

7479
public static void SetAsSystemProxy(ExplicitProxyEndPoint endPoint)
7580
{
76-
if (_proxyEndPoints.Contains(endPoint) == false)
81+
if (ProxyEndPoints.Contains(endPoint) == false)
7782
throw new Exception("Cannot set endPoints not added to proxy as system proxy");
7883

7984
if (!proxyStarted)
8085
throw new Exception("Cannot set system proxy settings before proxy has been started.");
8186

8287
//clear any settings previously added
83-
_proxyEndPoints.OfType<ExplicitProxyEndPoint>().ToList().ForEach(x => x.IsSystemProxy = false);
88+
ProxyEndPoints.OfType<ExplicitProxyEndPoint>().ToList().ForEach(x => x.IsSystemProxy = false);
8489

8590
endPoint.IsSystemProxy = true;
8691

8792
SystemProxyHelper.EnableProxyHttp(
88-
Equals(endPoint.IpAddress, IPAddress.Any) ? "127.0.0.1" : endPoint.IpAddress.ToString(), endPoint.Port);
93+
Equals(endPoint.IpAddress, IPAddress.Any) | Equals(endPoint.IpAddress, IPAddress.Loopback) ? "127.0.0.1" : endPoint.IpAddress.ToString(), endPoint.Port);
8994

9095
#if !DEBUG
9196
FireFoxHelper.AddFirefox();
@@ -99,21 +104,23 @@ public static void SetAsSystemProxy(ExplicitProxyEndPoint endPoint)
99104
if (certTrusted)
100105
{
101106
SystemProxyHelper.EnableProxyHttps(
102-
Equals(endPoint.IpAddress, IPAddress.Any) ? "127.0.0.1" : endPoint.IpAddress.ToString(),
107+
Equals(endPoint.IpAddress, IPAddress.Any) | Equals(endPoint.IpAddress, IPAddress.Loopback) ? "127.0.0.1" : endPoint.IpAddress.ToString(),
103108
endPoint.Port);
104109
}
105110
}
106111

112+
Console.WriteLine("Set endpoint at Ip {1} and port: {2} as System Proxy", endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port);
113+
107114
}
108115

109116
public static void Start()
110117
{
111-
EnableSsl = _proxyEndPoints.Any(x => x.EnableSsl);
118+
EnableSsl = ProxyEndPoints.Any(x => x.EnableSsl);
112119

113120
if (EnableSsl)
114121
certTrusted = CertManager.CreateTrustedRootCertificate();
115122

116-
foreach (var endPoint in _proxyEndPoints)
123+
foreach (var endPoint in ProxyEndPoints)
117124
{
118125

119126
endPoint.listener = new TcpListener(endPoint.IpAddress, endPoint.Port);
@@ -130,10 +137,7 @@ public static void Start()
130137
private static void OnAcceptConnection(IAsyncResult asyn)
131138
{
132139
var endPoint = (ProxyEndPoint)asyn.AsyncState;
133-
134-
// Get the listener that handles the client request.
135-
endPoint.listener.BeginAcceptTcpClient(OnAcceptConnection, endPoint);
136-
140+
137141
var client = endPoint.listener.EndAcceptTcpClient(asyn);
138142

139143
try
@@ -147,12 +151,15 @@ private static void OnAcceptConnection(IAsyncResult asyn)
147151
{
148152
// ignored
149153
}
154+
// Get the listener that handles the client request.
155+
endPoint.listener.BeginAcceptTcpClient(OnAcceptConnection, endPoint);
156+
150157
}
151158

152159

153160
public static void Stop()
154161
{
155-
var SetAsSystemProxy = _proxyEndPoints.OfType<ExplicitProxyEndPoint>().Any(x => x.IsSystemProxy);
162+
var SetAsSystemProxy = ProxyEndPoints.OfType<ExplicitProxyEndPoint>().Any(x => x.IsSystemProxy);
156163

157164
if (SetAsSystemProxy)
158165
{
@@ -162,7 +169,7 @@ public static void Stop()
162169
#endif
163170
}
164171

165-
foreach (var endPoint in _proxyEndPoints)
172+
foreach (var endPoint in ProxyEndPoints)
166173
{
167174
endPoint.listener.Stop();
168175
}

Titanium.Web.Proxy/RequestHandler.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,10 @@ private static void HandleClient(ExplicitProxyEndPoint endPoint, TcpClient clien
5151

5252
var httpVersion = httpCmdSplit[2];
5353

54-
5554
var excluded = endPoint.ExcludedHostNameRegex != null ? endPoint.ExcludedHostNameRegex.Any(x => Regex.IsMatch(httpRemoteUri.Host, x)) : false;
5655

5756
//Client wants to create a secure tcp tunnel (its a HTTPS request)
58-
if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port == 443)
57+
if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port!=80)
5958
{
6059
httpRemoteUri = new Uri("https://" + httpCmdSplit[1]);
6160
clientStreamReader.ReadAllLines();
@@ -69,9 +68,10 @@ private static void HandleClient(ExplicitProxyEndPoint endPoint, TcpClient clien
6968
try
7069
{
7170
sslStream = new SslStream(clientStream, true);
71+
7272
//Successfully managed to authenticate the client using the fake certificate
7373
sslStream.AuthenticateAsServer(certificate, false,
74-
SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, false);
74+
SupportedProtocols, false);
7575

7676
clientStreamReader = new CustomBinaryReader(sslStream, Encoding.ASCII);
7777
clientStreamWriter = new StreamWriter(sslStream);
@@ -96,13 +96,16 @@ private static void HandleClient(ExplicitProxyEndPoint endPoint, TcpClient clien
9696
{
9797
clientStreamReader.ReadAllLines();
9898
WriteConnectResponse(clientStreamWriter, httpVersion);
99-
TcpHelper.SendRaw(clientStreamReader.BaseStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port,
99+
100+
TcpHelper.SendRaw(clientStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port,
100101
false);
102+
101103
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
102104
return;
103105
}
104106

105107
//Now create the request
108+
106109
HandleHttpSessionRequest(client, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
107110
httpRemoteUri.Scheme == Uri.UriSchemeHttps ? true : false);
108111
}
@@ -125,8 +128,8 @@ private static void HandleClient(TransparentProxyEndPoint endPoint, TcpClient cl
125128
sslStream.AuthenticateAsServer(certificate, false,
126129
SslProtocols.Tls, false);
127130

128-
clientStreamReader = new CustomBinaryReader(sslStream, Encoding.ASCII);
129-
clientStreamWriter = new StreamWriter(sslStream);
131+
clientStreamReader = new CustomBinaryReader(sslStream, Encoding.ASCII);
132+
clientStreamWriter = new StreamWriter(sslStream);
130133
//HTTPS server created - we can now decrypt the client's traffic
131134

132135
}
@@ -201,8 +204,8 @@ private static void HandleHttpSessionRequest(TcpClient client, string httpCmd, S
201204

202205
if (args.ProxySession.Request.UpgradeToWebSocket)
203206
{
204-
TcpHelper.SendRaw(clientStreamReader.BaseStream, httpCmd, args.ProxySession.Request.RequestHeaders,
205-
httpRemoteUri.Host, httpRemoteUri.Port, httpRemoteUri.Scheme == Uri.UriSchemeHttps);
207+
TcpHelper.SendRaw(clientStream, httpCmd, args.ProxySession.Request.RequestHeaders,
208+
httpRemoteUri.Host, httpRemoteUri.Port, args.IsHttps);
206209
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
207210
return;
208211
}

Titanium.Web.Proxy/ResponseHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ private static List<HttpHeader> ReadResponseHeaders(HttpWebSession response)
103103
if (response.Response.ResponseHeaders[i].Value.Contains(";"))
104104
{
105105
response.Response.ContentType = response.Response.ResponseHeaders[i].Value.Split(';')[0].Trim();
106-
response.Response.CharacterSet = response.Response.ResponseHeaders[i].Value.Split(';')[1].ToLower().Replace("charset=", string.Empty).Trim();
106+
response.Response.CharacterSet = response.Response.ResponseHeaders[i].Value.Split(';')[1].Substring(9).Trim();
107107
}
108108
else
109109
response.Response.ContentType = response.Response.ResponseHeaders[i].Value.ToLower().Trim();

0 commit comments

Comments
 (0)