增加TlsSniPattern配置

This commit is contained in:
陈国伟 2021-07-19 17:49:43 +08:00
parent 73b2ff58b7
commit d3b01002cd
8 changed files with 144 additions and 30 deletions

View File

@ -12,6 +12,11 @@ namespace FastGithub
/// </summary>
public bool TlsSni { get; init; }
/// <summary>
/// 自定义SNI值的表达式
/// </summary>
public string? TlsSniPattern { get; init; }
/// <summary>
/// 请求超时时长
/// </summary>
@ -27,5 +32,22 @@ namespace FastGithub
/// 自定义响应
/// </summary>
public ResponseConfig? Response { get; init; }
/// <summary>
/// 获取TlsSniPattern
/// </summary>
/// <returns></returns>
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);
}
}
}

View File

@ -0,0 +1,86 @@
using System;
using System.Net;
namespace FastGithub
{
/// <summary>
/// Sni自定义值表达式
/// @domain变量表示取域名值
/// @ipadress变量表示取ip
/// @random变量表示取随机值
/// </summary>
public struct TlsSniPattern
{
/// <summary>
/// 获取表示式值
/// </summary>
public string Value { get; }
/// <summary>
/// 无SNI
/// </summary>
public static TlsSniPattern None { get; } = new TlsSniPattern(string.Empty);
/// <summary>
/// 域名SNI
/// </summary>
public static TlsSniPattern Domain { get; } = new TlsSniPattern("@domain");
/// <summary>
/// IP值的SNI
/// </summary>
public static TlsSniPattern IPAddress { get; } = new TlsSniPattern("@ipaddress");
/// <summary>
/// 随机值的SNI
/// </summary>
public static TlsSniPattern Random { get; } = new TlsSniPattern("@random");
/// <summary>
/// Sni自定义值表达式
/// </summary>
/// <param name="value">表示式值</param>
public TlsSniPattern(string value)
{
this.Value = value;
}
/// <summary>
/// 更新域名
/// </summary>
/// <param name="domain"></param>
public TlsSniPattern WithDomain(string domain)
{
var value = this.Value.Replace(Domain.Value, domain, StringComparison.OrdinalIgnoreCase);
return new TlsSniPattern(value);
}
/// <summary>
/// 更新ip地址
/// </summary>
/// <param name="address"></param>
public TlsSniPattern WithIPAddress(IPAddress address)
{
var value = this.Value.Replace(IPAddress.Value, address.ToString(), StringComparison.OrdinalIgnoreCase);
return new TlsSniPattern(value);
}
/// <summary>
/// 更新随机数
/// </summary>
public TlsSniPattern WithRandom()
{
var value = this.Value.Replace(Random.Value, Environment.TickCount64.ToString(), StringComparison.OrdinalIgnoreCase);
return new TlsSniPattern(value);
}
/// <summary>
/// 转换为文本
/// </summary>
/// <returns></returns>
public override string ToString()
{
return this.Value;
}
}
}

View File

@ -10,18 +10,18 @@ namespace FastGithub.ReverseProxy
/// </summary>
class HttpClient : HttpMessageInvoker
{
private readonly string tlsSniValue;
private readonly TlsSniPattern tlsSniPattern;
/// <summary>
/// YARP的HttpClient
/// </summary>
/// <param name="handler"></param>
/// <param name="tlsSniValue"></param>
/// <param name="tlsSniPattern"></param>
/// <param name="disposeHandler"></param>
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;
}
/// <summary>
@ -33,7 +33,7 @@ namespace FastGithub.ReverseProxy
public override Task<HttpResponseMessage> 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);
}
}

View File

@ -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);
}

View File

@ -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
/// <param name="host"></param>
/// <param name="destination"></param>
/// <returns></returns>
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;
}

View File

@ -3,7 +3,7 @@
/// <summary>
/// Sni上下文
/// </summary>
sealed class SniContext
sealed class TlsSniContext
{
/// <summary>
/// 获取是否为https请求
@ -11,19 +11,19 @@
public bool IsHttps { get; }
/// <summary>
/// 获取Sni值
/// 获取或设置Sni值的表达式
/// </summary>
public string TlsSniValue { get; }
public TlsSniPattern TlsSniPattern { get; set; }
/// <summary>
/// Sni上下文
/// </summary>
/// <param name="isHttps"></param>
/// <param name="tlsSniValue"></param>
public SniContext(bool isHttps, string tlsSniValue)
/// <param name="tlsSniPattern"></param>
public TlsSniContext(bool isHttps, TlsSniPattern tlsSniPattern)
{
this.IsHttps = isHttps;
this.TlsSniValue = tlsSniValue;
this.TlsSniPattern = tlsSniPattern;
}
}
}

View File

@ -6,32 +6,32 @@ namespace FastGithub.ReverseProxy
/// <summary>
/// SniContext扩展
/// </summary>
static class SniContextExtensions
static class TlsSniContextExtensions
{
private static readonly HttpRequestOptionsKey<SniContext> key = new(nameof(SniContext));
private static readonly HttpRequestOptionsKey<TlsSniContext> key = new(nameof(TlsSniContext));
/// <summary>
/// 设置SniContext
/// 设置TlsSniContext
/// </summary>
/// <param name="httpRequestMessage"></param>
/// <param name="context"></param>
public static void SetSniContext(this HttpRequestMessage httpRequestMessage, SniContext context)
public static void SetTlsSniContext(this HttpRequestMessage httpRequestMessage, TlsSniContext context)
{
httpRequestMessage.Options.Set(key, context);
}
/// <summary>
/// 获取SniContext
/// 获取TlsSniContext
/// </summary>
/// <param name="httpRequestMessage"></param>
/// <returns></returns>
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)}");
}
}
}

View File

@ -11,6 +11,7 @@
"DomainConfigs": { // *0
"github.com": {
"TlsSni": false, // tlsSNI
"TlsSniPattern": null, // SNI@domain @ipadressip @random
"Timeout": null, // "00:02:00"null
"Destination": null // Urinull
},