增加TlsSniPattern配置
This commit is contained in:
		
							parent
							
								
									73b2ff58b7
								
							
						
					
					
						commit
						d3b01002cd
					
				@ -12,6 +12,11 @@ namespace FastGithub
 | 
				
			|||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public bool TlsSni { get; init; }
 | 
					        public bool TlsSni { get; init; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 自定义SNI值的表达式
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        public string? TlsSniPattern { get; init; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 请求超时时长
 | 
					        /// 请求超时时长
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
@ -27,5 +32,22 @@ namespace FastGithub
 | 
				
			|||||||
        /// 自定义响应
 | 
					        /// 自定义响应
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public ResponseConfig? Response { get; init; }
 | 
					        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);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										86
									
								
								FastGithub.Core/TlsSniPattern.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								FastGithub.Core/TlsSniPattern.cs
									
									
									
									
									
										Normal 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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -10,18 +10,18 @@ namespace FastGithub.ReverseProxy
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    class HttpClient : HttpMessageInvoker
 | 
					    class HttpClient : HttpMessageInvoker
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly string tlsSniValue;
 | 
					        private readonly TlsSniPattern tlsSniPattern;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// YARP的HttpClient
 | 
					        /// YARP的HttpClient
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="handler"></param>
 | 
					        /// <param name="handler"></param>
 | 
				
			||||||
        /// <param name="tlsSniValue"></param>
 | 
					        /// <param name="tlsSniPattern"></param>
 | 
				
			||||||
        /// <param name="disposeHandler"></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)
 | 
					            base(handler, disposeHandler)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            this.tlsSniValue = tlsSniValue;
 | 
					            this.tlsSniPattern = tlsSniPattern;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
@ -33,7 +33,7 @@ namespace FastGithub.ReverseProxy
 | 
				
			|||||||
        public override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
					        public override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var isHttps = request.RequestUri?.Scheme == Uri.UriSchemeHttps;
 | 
					            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);
 | 
					            return base.SendAsync(request, cancellationToken);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -35,13 +35,14 @@ namespace FastGithub.ReverseProxy
 | 
				
			|||||||
                Proxy = null,
 | 
					                Proxy = null,
 | 
				
			||||||
                UseProxy = false,
 | 
					                UseProxy = false,
 | 
				
			||||||
                AllowAutoRedirect = false,
 | 
					                AllowAutoRedirect = false,
 | 
				
			||||||
                ConnectCallback = async (ctx, ct) =>
 | 
					                ConnectCallback = async (context, cancellationToken) =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
 | 
					                    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 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;
 | 
					                        return stream;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@ -49,9 +50,9 @@ namespace FastGithub.ReverseProxy
 | 
				
			|||||||
                    var sslStream = new SslStream(stream, leaveInnerStreamOpen: false);
 | 
					                    var sslStream = new SslStream(stream, leaveInnerStreamOpen: false);
 | 
				
			||||||
                    await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
 | 
					                    await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        TargetHost = sniContext.TlsSniValue,
 | 
					                        TargetHost = tlsSniContext.TlsSniPattern.Value,
 | 
				
			||||||
                        RemoteCertificateValidationCallback = delegate { return true; }
 | 
					                        RemoteCertificateValidationCallback = delegate { return true; }
 | 
				
			||||||
                    }, ct);
 | 
					                    }, cancellationToken);
 | 
				
			||||||
                    return sslStream;
 | 
					                    return sslStream;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
@ -76,6 +77,9 @@ namespace FastGithub.ReverseProxy
 | 
				
			|||||||
                };
 | 
					                };
 | 
				
			||||||
                request.RequestUri = builder.Uri;
 | 
					                request.RequestUri = builder.Uri;
 | 
				
			||||||
                request.Headers.Host = uri.Host;
 | 
					                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);
 | 
					            return await base.SendAsync(request, cancellationToken);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -56,10 +56,10 @@ namespace FastGithub.ReverseProxy
 | 
				
			|||||||
                var destinationPrefix = GetDestinationPrefix(host, domainConfig.Destination);
 | 
					                var destinationPrefix = GetDestinationPrefix(host, domainConfig.Destination);
 | 
				
			||||||
                var requestConfig = new ForwarderRequestConfig { Timeout = domainConfig.Timeout };
 | 
					                var requestConfig = new ForwarderRequestConfig { Timeout = domainConfig.Timeout };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                var tlsSniValue = domainConfig.TlsSni ? destinationPrefix.Host : string.Empty;
 | 
					                var tlsSniPattern = domainConfig.GetTlsSniPattern();
 | 
				
			||||||
                using var httpClient = new HttpClient(this.httpClientHanlder, tlsSniValue);
 | 
					                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);
 | 
					                await ResponseErrorAsync(context, error);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -70,15 +70,16 @@ namespace FastGithub.ReverseProxy
 | 
				
			|||||||
        /// <param name="host"></param> 
 | 
					        /// <param name="host"></param> 
 | 
				
			||||||
        /// <param name="destination"></param>
 | 
					        /// <param name="destination"></param>
 | 
				
			||||||
        /// <returns></returns>
 | 
					        /// <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)
 | 
					            if (destination == null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return defaultValue;
 | 
					                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}]");
 | 
					            this.logger.LogInformation($"[{defaultValue}->{result}]");
 | 
				
			||||||
            return result;
 | 
					            return result;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,7 @@
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// Sni上下文
 | 
					    /// Sni上下文
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    sealed class SniContext
 | 
					    sealed class TlsSniContext
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 获取是否为https请求
 | 
					        /// 获取是否为https请求
 | 
				
			||||||
@ -11,19 +11,19 @@
 | 
				
			|||||||
        public bool IsHttps { get; }
 | 
					        public bool IsHttps { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 获取Sni值
 | 
					        /// 获取或设置Sni值的表达式 
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public string TlsSniValue { get; }
 | 
					        public TlsSniPattern TlsSniPattern { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Sni上下文
 | 
					        /// Sni上下文
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="isHttps"></param>
 | 
					        /// <param name="isHttps"></param>
 | 
				
			||||||
        /// <param name="tlsSniValue"></param>
 | 
					        /// <param name="tlsSniPattern"></param>
 | 
				
			||||||
        public SniContext(bool isHttps, string tlsSniValue)
 | 
					        public TlsSniContext(bool isHttps, TlsSniPattern tlsSniPattern)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            this.IsHttps = isHttps;
 | 
					            this.IsHttps = isHttps;
 | 
				
			||||||
            this.TlsSniValue = tlsSniValue;
 | 
					            this.TlsSniPattern = tlsSniPattern;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -6,32 +6,32 @@ namespace FastGithub.ReverseProxy
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// SniContext扩展
 | 
					    /// SniContext扩展
 | 
				
			||||||
    /// </summary>
 | 
					    /// </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>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 设置SniContext
 | 
					        /// 设置TlsSniContext
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="httpRequestMessage"></param>
 | 
					        /// <param name="httpRequestMessage"></param>
 | 
				
			||||||
        /// <param name="context"></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);
 | 
					            httpRequestMessage.Options.Set(key, context);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 获取SniContext
 | 
					        /// 获取TlsSniContext
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="httpRequestMessage"></param>
 | 
					        /// <param name="httpRequestMessage"></param>
 | 
				
			||||||
        /// <returns></returns>
 | 
					        /// <returns></returns>
 | 
				
			||||||
        public static SniContext GetSniContext(this HttpRequestMessage httpRequestMessage)
 | 
					        public static TlsSniContext GetTlsSniContext(this HttpRequestMessage httpRequestMessage)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (httpRequestMessage.Options.TryGetValue(key, out var value))
 | 
					            if (httpRequestMessage.Options.TryGetValue(key, out var value))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return value;
 | 
					                return value;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            throw new InvalidOperationException($"请先调用{nameof(SetSniContext)}");
 | 
					            throw new InvalidOperationException($"请先调用{nameof(SetTlsSniContext)}");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -11,6 +11,7 @@
 | 
				
			|||||||
    "DomainConfigs": { // 域名的*表示0到多个任意字符
 | 
					    "DomainConfigs": { // 域名的*表示0到多个任意字符
 | 
				
			||||||
      "github.com": {
 | 
					      "github.com": {
 | 
				
			||||||
        "TlsSni": false, // 指示tls握手时是否发送SNI
 | 
					        "TlsSni": false, // 指示tls握手时是否发送SNI
 | 
				
			||||||
 | 
					        "TlsSniPattern": null, // SNI表达式,@domain变量表示取域名值 @ipadress变量表示取ip @random变量表示取随机值,其它字符保留不替换
 | 
				
			||||||
        "Timeout": null, // 请求超时时长,格式为"00:02:00",默认为null
 | 
					        "Timeout": null, // 请求超时时长,格式为"00:02:00",默认为null
 | 
				
			||||||
        "Destination": null // 请求目的地,格式为绝对或相对Uri,默认null
 | 
					        "Destination": null // 请求目的地,格式为绝对或相对Uri,默认null
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user