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

Commit 4641d47

Browse files
committed
#868 Add Forward port & host options
1 parent 20e56c1 commit 4641d47

File tree

5 files changed

+68
-9
lines changed

5 files changed

+68
-9
lines changed

examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class ProxyTestController : IDisposable
2727

2828
public ProxyTestController()
2929
{
30-
Task.Run(()=> listenToConsole());
30+
Task.Run(() => listenToConsole());
3131

3232
proxyServer = new ProxyServer();
3333

@@ -97,13 +97,13 @@ public void StartProxy()
9797
proxyServer.Start();
9898

9999
// Transparent endpoint is useful for reverse proxy (client is not aware of the existence of proxy)
100-
// A transparent endpoint usually requires a network router port forwarding HTTP(S) packets or DNS
101-
// to send data to this endPoint
100+
// A transparent endpoint usually requires a network router port forwarding HTTP(S) packets
101+
// or by DNS to send data to this endPoint.
102102
//var transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Any, 443, true)
103-
//{
103+
//{
104104
// // Generic Certificate hostname to use
105105
// // When SNI is disabled by client
106-
// GenericCertificateName = "google.com"
106+
// GenericCertificateName = "localhost"
107107
//};
108108

109109
//proxyServer.AddEndPoint(transparentEndPoint);

src/Titanium.Web.Proxy/EventArguments/BeforeSslAuthenticateEventArgs.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ internal BeforeSslAuthenticateEventArgs(ProxyServer server, TcpClientConnection
1414
{
1515
TaskCancellationSource = taskCancellationSource;
1616
SniHostName = sniHostName;
17+
ForwardHttpsHostName = sniHostName;
1718
}
1819

1920
/// <summary>
20-
/// The server name indication hostname if available. Otherwise the generic certificate hostname of
21-
/// TransparentEndPoint.
21+
/// The server name indication hostname if available.
22+
/// Otherwise the GenericCertificateName property of TransparentEndPoint.
2223
/// </summary>
2324
public string SniHostName { get; }
2425

@@ -29,6 +30,25 @@ internal BeforeSslAuthenticateEventArgs(ProxyServer server, TcpClientConnection
2930
/// </summary>
3031
public bool DecryptSsl { get; set; } = true;
3132

33+
/// <summary>
34+
/// We need to know the server hostname we are forwarding the request to.
35+
/// By default its the SNI hostname indicated in SSL handshake, when SNI is available.
36+
/// When SNI is not available, it will use the GenericCertificateName of TransparentEndPoint.
37+
/// This property is used only when DecryptSsl or when BeforeSslAuthenticateEventArgs.DecryptSsl is false.
38+
/// When DecryptSsl is true, we need to explicitly set the Forwarded host and port by setting
39+
/// e.HttpClient.Request.Url inside BeforeRequest event handler.
40+
/// </summary>
41+
public string ForwardHttpsHostName { get; set; }
42+
43+
/// <summary>
44+
/// We need to know the server port we are forwarding the request to.
45+
/// By default its the standard https port, 443.
46+
/// This property is used only when DecryptSsl or when BeforeSslAuthenticateEventArgs.DecryptSsl is false.
47+
/// When DecryptSsl is true, we need to explicitly set the Forwarded host and port by setting
48+
/// e.HttpClient.Request.Url inside BeforeRequest event handler.
49+
/// </summary>
50+
public int ForwardHttpsPort { get; set; } = 443;
51+
3252
/// <summary>
3353
/// Terminate the request abruptly by closing client/server connections.
3454
/// </summary>

src/Titanium.Web.Proxy/Models/TransparentBaseProxyEndPoint.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
namespace Titanium.Web.Proxy.Models
66
{
77
public abstract class TransparentBaseProxyEndPoint : ProxyEndPoint
8-
{
8+
{
9+
/// <summary>
10+
/// The hostname of the generic certificate to negotiate SSL.
11+
/// This will be only used when Sever Name Indication (SNI) is not supported by client,
12+
/// or when it does not indicate any host name.
13+
/// </summary>
914
public abstract string GenericCertificateName { get; set; }
1015

1116
protected TransparentBaseProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl) : base(ipAddress, port, decryptSsl)

src/Titanium.Web.Proxy/TransparentClientHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ private async Task handleClient(TransparentBaseProxyEndPoint endPoint, TcpClient
9191
else
9292
{
9393
var sessionArgs = new SessionEventArgs(this, endPoint, clientStream, null, cancellationTokenSource);
94-
var connection = (await tcpConnectionFactory.GetServerConnection(this, httpsHostName, port,
94+
var connection = (await tcpConnectionFactory.GetServerConnection(this, args.ForwardHttpsHostName, args.ForwardHttpsPort,
9595
HttpHeader.VersionUnknown, false, null,
9696
true, sessionArgs, UpStreamEndPoint,
9797
UpStreamHttpsProxy, true, false, cancellationToken))!;

tests/Titanium.Web.Proxy.IntegrationTests/ReverseProxyTests.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
using System;
2+
using System.Linq;
23
using System.Net;
34
using System.Net.Http;
45
using System.Threading.Tasks;
56
using Microsoft.AspNetCore.Http;
67
using Microsoft.VisualStudio.TestTools.UnitTesting;
8+
using Titanium.Web.Proxy.Models;
79

810
namespace Titanium.Web.Proxy.IntegrationTests
911
{
@@ -126,5 +128,37 @@ public async Task Smoke_Test_Https_To_Https_Reverse_Proxy()
126128
Assert.AreEqual("I am server. I received your greetings.", body);
127129
}
128130

131+
[TestMethod]
132+
public async Task Smoke_Test_Https_To_Https_Reverse_Proxy_Tunnel_Without_Decryption()
133+
{
134+
var testSuite = new TestSuite();
135+
136+
var server = testSuite.GetServer();
137+
server.HandleRequest((context) =>
138+
{
139+
return context.Response.WriteAsync("I am server. I received your greetings.");
140+
});
141+
142+
var proxy = testSuite.GetReverseProxy();
143+
var endpoint = proxy.ProxyEndPoints.Where(x => x is TransparentProxyEndPoint).First() as TransparentProxyEndPoint;
144+
145+
endpoint.BeforeSslAuthenticate += async (sender, e) =>
146+
{
147+
e.DecryptSsl = false;
148+
e.ForwardHttpsPort = server.HttpsListeningPort;
149+
};
150+
151+
var client = testSuite.GetReverseProxyClient();
152+
153+
var response = await client.PostAsync(new Uri($"https://localhost:{proxy.ProxyEndPoints[0].Port}"),
154+
new StringContent("hello server. I am a client."));
155+
156+
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
157+
var body = await response.Content.ReadAsStringAsync();
158+
159+
Assert.AreEqual("I am server. I received your greetings.", body);
160+
}
161+
129162
}
163+
130164
}

0 commit comments

Comments
 (0)