From 7ddb46e74db7f733968925160a6334dd17260e79 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Tue, 24 Mar 2026 03:25:02 +0000 Subject: [PATCH] Xray browser header masquerading (#8981) --- v2rayN/ServiceLib/Global.cs | 8 ++++---- v2rayN/ServiceLib/Models/V2rayConfig.cs | 3 +++ .../CoreConfig/V2ray/V2rayOutboundService.cs | 18 ++++++++++-------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index e9a5a41e..bf8dd7ab 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -182,13 +182,14 @@ public class Global @"https://raw.githubusercontent.com/Chocolate4U/Iran-v2ray-rules/main/v2rayN/" ]; - public static readonly Dictionary UserAgentTexts = new() + public static readonly Dictionary TcpHttpUserAgentTexts = new() { {"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" }, {"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" }, {"safari","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15" }, {"edge","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.70" }, - {"none",""} + {"none",""}, + {"golang",""} }; public const string Hysteria2ProtocolShare = "hy2://"; @@ -391,9 +392,8 @@ public class Global [ "chrome", "firefox", - "safari", "edge", - "none" + "golang" ]; public static readonly List XhttpMode = diff --git a/v2rayN/ServiceLib/Models/V2rayConfig.cs b/v2rayN/ServiceLib/Models/V2rayConfig.cs index 4d3f9512..983cb4da 100644 --- a/v2rayN/ServiceLib/Models/V2rayConfig.cs +++ b/v2rayN/ServiceLib/Models/V2rayConfig.cs @@ -421,6 +421,8 @@ public class HttpupgradeSettings4Ray public string? path { get; set; } public string? host { get; set; } + + public Headers4Ray headers { get; set; } } public class XhttpSettings4Ray @@ -456,6 +458,7 @@ public class GrpcSettings4Ray public int? health_check_timeout { get; set; } public bool? permit_without_stream { get; set; } public int? initial_windows_size { get; set; } + public string? user_agent { get; set; } } public class HysteriaSettings4Ray diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs index e9241030..85f72e41 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs @@ -354,11 +354,7 @@ public partial class CoreConfigV2rayService var host = _node.RequestHost.TrimEx(); var path = _node.Path.TrimEx(); var sni = _node.Sni.TrimEx(); - var useragent = ""; - if (!_config.CoreBasicItem.DefUserAgent.IsNullOrEmpty()) - { - useragent = Global.UserAgentTexts.GetValueOrDefault(_config.CoreBasicItem.DefUserAgent, _config.CoreBasicItem.DefUserAgent); - } + var useragent = _config.CoreBasicItem.DefUserAgent ?? string.Empty; //if tls if (_node.StreamSecurity == Global.StreamSecurity) @@ -496,13 +492,17 @@ public partial class CoreConfigV2rayService case nameof(ETransport.httpupgrade): HttpupgradeSettings4Ray httpupgradeSettings = new(); + if (host.IsNotEmpty()) + { + httpupgradeSettings.host = host; + } if (path.IsNotEmpty()) { httpupgradeSettings.path = path; } - if (host.IsNotEmpty()) + if (useragent.IsNotEmpty()) { - httpupgradeSettings.host = host; + httpupgradeSettings.headers.UserAgent = useragent; } streamSettings.httpupgradeSettings = httpupgradeSettings; @@ -581,6 +581,7 @@ public partial class CoreConfigV2rayService health_check_timeout = _config.GrpcItem.HealthCheckTimeout, permit_without_stream = _config.GrpcItem.PermitWithoutStream, initial_windows_size = _config.GrpcItem.InitialWindowsSize, + user_agent = useragent.NullIfEmpty(), }; streamSettings.grpcSettings = grpcSettings; break; @@ -655,10 +656,11 @@ public partial class CoreConfigV2rayService //request Host var request = EmbedUtils.GetEmbedText(Global.V2raySampleHttpRequestFileName); + var useragentValue = Global.TcpHttpUserAgentTexts.GetValueOrDefault(useragent, useragent); var arrHost = host.Split(','); var host2 = string.Join(",".AppendQuotes(), arrHost); request = request.Replace("$requestHost$", $"{host2.AppendQuotes()}"); - request = request.Replace("$requestUserAgent$", $"{useragent.AppendQuotes()}"); + request = request.Replace("$requestUserAgent$", $"{useragentValue.AppendQuotes()}"); //Path var pathHttp = @"/"; if (path.IsNotEmpty())