From d3b01002cd303943667804c698b61e4790b6e8c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=99=88=E5=9B=BD=E4=BC=9F?= <366193849@qq.com>
Date: Mon, 19 Jul 2021 17:49:43 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0TlsSniPattern=E9=85=8D?=
=?UTF-8?q?=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
FastGithub.Core/DomainConfig.cs | 22 +++++
FastGithub.Core/TlsSniPattern.cs | 86 +++++++++++++++++++
FastGithub.ReverseProxy/HttpClient.cs | 10 +--
FastGithub.ReverseProxy/HttpClientHanlder.cs | 16 ++--
.../ReverseProxyMiddleware.cs | 13 +--
.../{SniContext.cs => TlsSniContext.cs} | 12 +--
...tensions.cs => TlsSniContextExtensions.cs} | 14 +--
FastGithub/appsettings.json | 1 +
8 files changed, 144 insertions(+), 30 deletions(-)
create mode 100644 FastGithub.Core/TlsSniPattern.cs
rename FastGithub.ReverseProxy/{SniContext.cs => TlsSniContext.cs} (59%)
rename FastGithub.ReverseProxy/{SniContextExtensions.cs => TlsSniContextExtensions.cs} (61%)
diff --git a/FastGithub.Core/DomainConfig.cs b/FastGithub.Core/DomainConfig.cs
index 345d1a7..bbde172 100644
--- a/FastGithub.Core/DomainConfig.cs
+++ b/FastGithub.Core/DomainConfig.cs
@@ -12,6 +12,11 @@ namespace FastGithub
///
public bool TlsSni { get; init; }
+ ///
+ /// 自定义SNI值的表达式
+ ///
+ public string? TlsSniPattern { get; init; }
+
///
/// 请求超时时长
///
@@ -27,5 +32,22 @@ namespace FastGithub
/// 自定义响应
///
public ResponseConfig? Response { get; init; }
+
+ ///
+ /// 获取TlsSniPattern
+ ///
+ ///
+ public TlsSniPattern GetTlsSniPattern()
+ {
+ if (this.TlsSni == false)
+ {
+ return FastGithub.TlsSniPattern.None;
+ }
+ if (string.IsNullOrEmpty(this.TlsSniPattern))
+ {
+ return FastGithub.TlsSniPattern.Domain;
+ }
+ return new TlsSniPattern(this.TlsSniPattern);
+ }
}
}
diff --git a/FastGithub.Core/TlsSniPattern.cs b/FastGithub.Core/TlsSniPattern.cs
new file mode 100644
index 0000000..f1af0f9
--- /dev/null
+++ b/FastGithub.Core/TlsSniPattern.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Net;
+
+namespace FastGithub
+{
+ ///
+ /// Sni自定义值表达式
+ /// @domain变量表示取域名值
+ /// @ipadress变量表示取ip
+ /// @random变量表示取随机值
+ ///
+ public struct TlsSniPattern
+ {
+ ///
+ /// 获取表示式值
+ ///
+ public string Value { get; }
+
+ ///
+ /// 无SNI
+ ///
+ public static TlsSniPattern None { get; } = new TlsSniPattern(string.Empty);
+
+ ///
+ /// 域名SNI
+ ///
+ public static TlsSniPattern Domain { get; } = new TlsSniPattern("@domain");
+
+ ///
+ /// IP值的SNI
+ ///
+ public static TlsSniPattern IPAddress { get; } = new TlsSniPattern("@ipaddress");
+
+ ///
+ /// 随机值的SNI
+ ///
+ public static TlsSniPattern Random { get; } = new TlsSniPattern("@random");
+
+ ///
+ /// Sni自定义值表达式
+ ///
+ /// 表示式值
+ public TlsSniPattern(string value)
+ {
+ this.Value = value;
+ }
+
+ ///
+ /// 更新域名
+ ///
+ ///
+ public TlsSniPattern WithDomain(string domain)
+ {
+ var value = this.Value.Replace(Domain.Value, domain, StringComparison.OrdinalIgnoreCase);
+ return new TlsSniPattern(value);
+ }
+
+ ///
+ /// 更新ip地址
+ ///
+ ///
+ public TlsSniPattern WithIPAddress(IPAddress address)
+ {
+ var value = this.Value.Replace(IPAddress.Value, address.ToString(), StringComparison.OrdinalIgnoreCase);
+ return new TlsSniPattern(value);
+ }
+
+ ///
+ /// 更新随机数
+ ///
+ public TlsSniPattern WithRandom()
+ {
+ var value = this.Value.Replace(Random.Value, Environment.TickCount64.ToString(), StringComparison.OrdinalIgnoreCase);
+ return new TlsSniPattern(value);
+ }
+
+ ///
+ /// 转换为文本
+ ///
+ ///
+ public override string ToString()
+ {
+ return this.Value;
+ }
+ }
+}
diff --git a/FastGithub.ReverseProxy/HttpClient.cs b/FastGithub.ReverseProxy/HttpClient.cs
index fedb9ae..a8c4887 100644
--- a/FastGithub.ReverseProxy/HttpClient.cs
+++ b/FastGithub.ReverseProxy/HttpClient.cs
@@ -10,18 +10,18 @@ namespace FastGithub.ReverseProxy
///
class HttpClient : HttpMessageInvoker
{
- private readonly string tlsSniValue;
+ private readonly TlsSniPattern tlsSniPattern;
///
/// YARP的HttpClient
///
///
- ///
+ ///
///
- public HttpClient(HttpMessageHandler handler, string tlsSniValue, bool disposeHandler = false) :
+ public HttpClient(HttpMessageHandler handler, TlsSniPattern tlsSniPattern, bool disposeHandler = false) :
base(handler, disposeHandler)
{
- this.tlsSniValue = tlsSniValue;
+ this.tlsSniPattern = tlsSniPattern;
}
///
@@ -33,7 +33,7 @@ namespace FastGithub.ReverseProxy
public override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var isHttps = request.RequestUri?.Scheme == Uri.UriSchemeHttps;
- request.SetSniContext(new SniContext(isHttps, this.tlsSniValue));
+ request.SetTlsSniContext(new TlsSniContext(isHttps, this.tlsSniPattern));
return base.SendAsync(request, cancellationToken);
}
}
diff --git a/FastGithub.ReverseProxy/HttpClientHanlder.cs b/FastGithub.ReverseProxy/HttpClientHanlder.cs
index 7063332..2e2c18a 100644
--- a/FastGithub.ReverseProxy/HttpClientHanlder.cs
+++ b/FastGithub.ReverseProxy/HttpClientHanlder.cs
@@ -35,13 +35,14 @@ namespace FastGithub.ReverseProxy
Proxy = null,
UseProxy = false,
AllowAutoRedirect = false,
- ConnectCallback = async (ctx, ct) =>
+ ConnectCallback = async (context, cancellationToken) =>
{
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
- await socket.ConnectAsync(ctx.DnsEndPoint, ct);
+ await socket.ConnectAsync(context.DnsEndPoint, cancellationToken);
var stream = new NetworkStream(socket, ownsSocket: true);
- var sniContext = ctx.InitialRequestMessage.GetSniContext();
- if (sniContext.IsHttps == false)
+
+ var tlsSniContext = context.InitialRequestMessage.GetTlsSniContext();
+ if (tlsSniContext.IsHttps == false)
{
return stream;
}
@@ -49,9 +50,9 @@ namespace FastGithub.ReverseProxy
var sslStream = new SslStream(stream, leaveInnerStreamOpen: false);
await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
{
- TargetHost = sniContext.TlsSniValue,
+ TargetHost = tlsSniContext.TlsSniPattern.Value,
RemoteCertificateValidationCallback = delegate { return true; }
- }, ct);
+ }, cancellationToken);
return sslStream;
}
};
@@ -76,6 +77,9 @@ namespace FastGithub.ReverseProxy
};
request.RequestUri = builder.Uri;
request.Headers.Host = uri.Host;
+
+ var context = request.GetTlsSniContext();
+ context.TlsSniPattern = context.TlsSniPattern.WithDomain(uri.Host).WithIPAddress(address).WithRandom();
}
return await base.SendAsync(request, cancellationToken);
}
diff --git a/FastGithub.ReverseProxy/ReverseProxyMiddleware.cs b/FastGithub.ReverseProxy/ReverseProxyMiddleware.cs
index c92edb5..dec5eb4 100644
--- a/FastGithub.ReverseProxy/ReverseProxyMiddleware.cs
+++ b/FastGithub.ReverseProxy/ReverseProxyMiddleware.cs
@@ -56,10 +56,10 @@ namespace FastGithub.ReverseProxy
var destinationPrefix = GetDestinationPrefix(host, domainConfig.Destination);
var requestConfig = new ForwarderRequestConfig { Timeout = domainConfig.Timeout };
- var tlsSniValue = domainConfig.TlsSni ? destinationPrefix.Host : string.Empty;
- using var httpClient = new HttpClient(this.httpClientHanlder, tlsSniValue);
+ var tlsSniPattern = domainConfig.GetTlsSniPattern();
+ using var httpClient = new HttpClient(this.httpClientHanlder, tlsSniPattern);
- var error = await httpForwarder.SendAsync(context, destinationPrefix.ToString(), httpClient, requestConfig);
+ var error = await httpForwarder.SendAsync(context, destinationPrefix, httpClient, requestConfig);
await ResponseErrorAsync(context, error);
}
}
@@ -70,15 +70,16 @@ namespace FastGithub.ReverseProxy
///
///
///
- private Uri GetDestinationPrefix(string host, Uri? destination)
+ private string GetDestinationPrefix(string host, Uri? destination)
{
- var defaultValue = new Uri($"https://{host}/");
+ var defaultValue = $"https://{host}/";
if (destination == null)
{
return defaultValue;
}
- var result = new Uri(defaultValue, destination);
+ var baseUri = new Uri(defaultValue);
+ var result = new Uri(baseUri, destination).ToString();
this.logger.LogInformation($"[{defaultValue}->{result}]");
return result;
}
diff --git a/FastGithub.ReverseProxy/SniContext.cs b/FastGithub.ReverseProxy/TlsSniContext.cs
similarity index 59%
rename from FastGithub.ReverseProxy/SniContext.cs
rename to FastGithub.ReverseProxy/TlsSniContext.cs
index 5c33d02..0e308d5 100644
--- a/FastGithub.ReverseProxy/SniContext.cs
+++ b/FastGithub.ReverseProxy/TlsSniContext.cs
@@ -3,7 +3,7 @@
///
/// Sni上下文
///
- sealed class SniContext
+ sealed class TlsSniContext
{
///
/// 获取是否为https请求
@@ -11,19 +11,19 @@
public bool IsHttps { get; }
///
- /// 获取Sni值
+ /// 获取或设置Sni值的表达式
///
- public string TlsSniValue { get; }
+ public TlsSniPattern TlsSniPattern { get; set; }
///
/// Sni上下文
///
///
- ///
- public SniContext(bool isHttps, string tlsSniValue)
+ ///
+ public TlsSniContext(bool isHttps, TlsSniPattern tlsSniPattern)
{
this.IsHttps = isHttps;
- this.TlsSniValue = tlsSniValue;
+ this.TlsSniPattern = tlsSniPattern;
}
}
}
diff --git a/FastGithub.ReverseProxy/SniContextExtensions.cs b/FastGithub.ReverseProxy/TlsSniContextExtensions.cs
similarity index 61%
rename from FastGithub.ReverseProxy/SniContextExtensions.cs
rename to FastGithub.ReverseProxy/TlsSniContextExtensions.cs
index da9cb3d..0d44351 100644
--- a/FastGithub.ReverseProxy/SniContextExtensions.cs
+++ b/FastGithub.ReverseProxy/TlsSniContextExtensions.cs
@@ -6,32 +6,32 @@ namespace FastGithub.ReverseProxy
///
/// SniContext扩展
///
- static class SniContextExtensions
+ static class TlsSniContextExtensions
{
- private static readonly HttpRequestOptionsKey key = new(nameof(SniContext));
+ private static readonly HttpRequestOptionsKey key = new(nameof(TlsSniContext));
///
- /// 设置SniContext
+ /// 设置TlsSniContext
///
///
///
- public static void SetSniContext(this HttpRequestMessage httpRequestMessage, SniContext context)
+ public static void SetTlsSniContext(this HttpRequestMessage httpRequestMessage, TlsSniContext context)
{
httpRequestMessage.Options.Set(key, context);
}
///
- /// 获取SniContext
+ /// 获取TlsSniContext
///
///
///
- public static SniContext GetSniContext(this HttpRequestMessage httpRequestMessage)
+ public static TlsSniContext GetTlsSniContext(this HttpRequestMessage httpRequestMessage)
{
if (httpRequestMessage.Options.TryGetValue(key, out var value))
{
return value;
}
- throw new InvalidOperationException($"请先调用{nameof(SetSniContext)}");
+ throw new InvalidOperationException($"请先调用{nameof(SetTlsSniContext)}");
}
}
}
diff --git a/FastGithub/appsettings.json b/FastGithub/appsettings.json
index 03c8323..696de65 100644
--- a/FastGithub/appsettings.json
+++ b/FastGithub/appsettings.json
@@ -11,6 +11,7 @@
"DomainConfigs": { // 域名的*表示0到多个任意字符
"github.com": {
"TlsSni": false, // 指示tls握手时是否发送SNI
+ "TlsSniPattern": null, // SNI表达式,@domain变量表示取域名值 @ipadress变量表示取ip @random变量表示取随机值,其它字符保留不替换
"Timeout": null, // 请求超时时长,格式为"00:02:00",默认为null
"Destination": null // 请求目的地,格式为绝对或相对Uri,默认null
},