diff --git a/v2rayN/v2rayN/Global.cs b/v2rayN/v2rayN/Global.cs index 37604545..86579d78 100644 --- a/v2rayN/v2rayN/Global.cs +++ b/v2rayN/v2rayN/Global.cs @@ -96,6 +96,15 @@ public static readonly List domainStrategys = new List { "AsIs", "IPIfNonMatch", "IPOnDemand" }; public static readonly List domainMatchers = new List { "linear", "mph", "" }; public static readonly List fingerprints = new List { "chrome", "firefox", "safari", "randomized", "" }; + public static readonly List userAgent = new List { "chrome", "firefox", "safari", "edge", "none" }; + public static readonly Dictionary userAgentTxt = new Dictionary + { + {"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",""} + }; public static readonly List allowInsecures = new List { "true", "false", "" }; public static readonly List domainStrategy4Freedoms = new List { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" }; public static readonly List Languages = new List { "zh-Hans", "en", "fa-Ir" }; diff --git a/v2rayN/v2rayN/Handler/CoreConfigHandler.cs b/v2rayN/v2rayN/Handler/CoreConfigHandler.cs index 454117a3..86617d8c 100644 --- a/v2rayN/v2rayN/Handler/CoreConfigHandler.cs +++ b/v2rayN/v2rayN/Handler/CoreConfigHandler.cs @@ -546,6 +546,18 @@ namespace v2rayN.Handler streamSettings.network = node.GetNetwork(); string host = node.requestHost.TrimEx(); string sni = node.sni; + string useragent = ""; + if (!config.defUserAgent.IsNullOrEmpty()) + { + try + { + useragent = Global.userAgentTxt[config.defUserAgent]; + } + catch (KeyNotFoundException) + { + useragent = config.defUserAgent; + } + } //if tls if (node.streamSecurity == Global.StreamSecurity) @@ -634,19 +646,22 @@ namespace v2rayN.Handler WsSettings wsSettings = new WsSettings { }; - + wsSettings.headers = new Headers + { + }; string path = node.path; if (!string.IsNullOrWhiteSpace(host)) { - wsSettings.headers = new Headers - { - Host = host - }; + wsSettings.headers.Host = host; } if (!string.IsNullOrWhiteSpace(path)) { wsSettings.path = path; } + if (!string.IsNullOrWhiteSpace(useragent)) + { + wsSettings.headers.UserAgent = useragent; + } streamSettings.wsSettings = wsSettings; //TlsSettings tlsSettings = new TlsSettings(); @@ -730,7 +745,7 @@ namespace v2rayN.Handler string host2 = string.Join("\",\"", arrHost); request = request.Replace("$requestHost$", $"\"{host2}\""); //request = request.Replace("$requestHost$", string.Format("\"{0}\"", config.requestHost())); - + request = request.Replace("$requestUserAgent$", $"\"{useragent}\""); //Path string pathHttp = @"/"; if (!Utils.IsNullOrEmpty(node.path)) diff --git a/v2rayN/v2rayN/Mode/Config.cs b/v2rayN/v2rayN/Mode/Config.cs index 11ed01fc..0166d894 100644 --- a/v2rayN/v2rayN/Mode/Config.cs +++ b/v2rayN/v2rayN/Mode/Config.cs @@ -94,6 +94,11 @@ public string defFingerprint { get; set; } + /// + /// 默认用户代理 + /// + public string defUserAgent { get; set; } + /// /// 域名解析策略 /// diff --git a/v2rayN/v2rayN/Mode/V2rayConfig.cs b/v2rayN/v2rayN/Mode/V2rayConfig.cs index e0247c7e..ec1fd03b 100644 --- a/v2rayN/v2rayN/Mode/V2rayConfig.cs +++ b/v2rayN/v2rayN/Mode/V2rayConfig.cs @@ -1,4 +1,6 @@ -namespace v2rayN.Mode +using Newtonsoft.Json; + +namespace v2rayN.Mode { /// /// v2ray配置文件实体类 @@ -505,6 +507,12 @@ /// /// public string Host { get; set; } + + /// + /// 用户代理 + /// + [JsonProperty("User-Agent")] + public string UserAgent { get; set; } } public class HttpSettings diff --git a/v2rayN/v2rayN/Resx/ResUI.Designer.cs b/v2rayN/v2rayN/Resx/ResUI.Designer.cs index eb4862c3..8597560f 100644 --- a/v2rayN/v2rayN/Resx/ResUI.Designer.cs +++ b/v2rayN/v2rayN/Resx/ResUI.Designer.cs @@ -2410,6 +2410,24 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 User-Agent 的本地化字符串。 + /// + public static string TbSettingsDefUserAgent { + get { + return ResourceManager.GetString("TbSettingsDefUserAgent", resourceCulture); + } + } + + /// + /// 查找类似 This parameter is valid only for tcp/http and ws 的本地化字符串。 + /// + public static string TbSettingsDefUserAgentTips { + get { + return ResourceManager.GetString("TbSettingsDefUserAgentTips", resourceCulture); + } + } + /// /// 查找类似 Outbound Freedom domainStrategy 的本地化字符串。 /// diff --git a/v2rayN/v2rayN/Resx/ResUI.fa-Ir.resx b/v2rayN/v2rayN/Resx/ResUI.fa-Ir.resx index e6fc55b2..9008d82d 100644 --- a/v2rayN/v2rayN/Resx/ResUI.fa-Ir.resx +++ b/v2rayN/v2rayN/Resx/ResUI.fa-Ir.resx @@ -1060,4 +1060,10 @@ نمایش کنسول + + User-Agent + + + This parameter is valid only for tcp/http and ws + \ No newline at end of file diff --git a/v2rayN/v2rayN/Resx/ResUI.resx b/v2rayN/v2rayN/Resx/ResUI.resx index a96733f4..cfa575dd 100644 --- a/v2rayN/v2rayN/Resx/ResUI.resx +++ b/v2rayN/v2rayN/Resx/ResUI.resx @@ -1087,4 +1087,10 @@ Default TLS fingerprint + + User-Agent + + + This parameter is valid only for tcp/http and ws + \ No newline at end of file diff --git a/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx b/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx index bda8b0ce..f27e18bd 100644 --- a/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx @@ -1087,4 +1087,10 @@ 默认TLS指纹(fingerprint) + + 用户代理(UA) + + + 仅对tcp/http、ws协议生效 + \ No newline at end of file diff --git a/v2rayN/v2rayN/Sample/SampleHttprequest b/v2rayN/v2rayN/Sample/SampleHttprequest index 48a0be41..583b89eb 100644 --- a/v2rayN/v2rayN/Sample/SampleHttprequest +++ b/v2rayN/v2rayN/Sample/SampleHttprequest @@ -1 +1 @@ -{"version":"1.1","method":"GET","path":[$requestPath$],"headers":{"Host":[$requestHost$],"User-Agent":["Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36","Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46"],"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}} \ No newline at end of file +{"version":"1.1","method":"GET","path":[$requestPath$],"headers":{"Host":[$requestHost$],"User-Agent":[$requestUserAgent$],"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}} \ No newline at end of file diff --git a/v2rayN/v2rayN/ViewModels/OptionSettingViewModel.cs b/v2rayN/v2rayN/ViewModels/OptionSettingViewModel.cs index eb157f6d..d532dba0 100644 --- a/v2rayN/v2rayN/ViewModels/OptionSettingViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/OptionSettingViewModel.cs @@ -29,6 +29,7 @@ namespace v2rayN.ViewModels [Reactive] public string loglevel { get; set; } [Reactive] public bool defAllowInsecure { get; set; } [Reactive] public string defFingerprint { get; set; } + [Reactive] public string defUserAgent { get; set; } #endregion #region Core DNS @@ -112,6 +113,7 @@ namespace v2rayN.ViewModels loglevel = _config.loglevel; defAllowInsecure = _config.defAllowInsecure; defFingerprint = _config.defFingerprint; + defUserAgent = _config.defUserAgent; #endregion #region Core DNS @@ -272,6 +274,7 @@ namespace v2rayN.ViewModels _config.muxEnabled = muxEnabled; _config.defAllowInsecure = defAllowInsecure; _config.defFingerprint = defFingerprint; + _config.defUserAgent = defUserAgent; //DNS diff --git a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml index 018214a9..72dd0f6e 100644 --- a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml +++ b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml @@ -48,209 +48,232 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + diff --git a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml.cs b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml.cs index 459207a4..639adb31 100644 --- a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml.cs @@ -25,6 +25,10 @@ namespace v2rayN.Views { cmbdefFingerprint.Items.Add(it); }); + Global.userAgent.ForEach(it => + { + cmbdefUserAgent.Items.Add(it); + }); Global.domainStrategy4Freedoms.ForEach(it => { cmbdomainStrategy4Freedom.Items.Add(it); @@ -68,6 +72,7 @@ namespace v2rayN.Views this.Bind(ViewModel, vm => vm.loglevel, v => v.cmbloglevel.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.defAllowInsecure, v => v.togdefAllowInsecure.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.defFingerprint, v => v.cmbdefFingerprint.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.defUserAgent, v => v.cmbdefUserAgent.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.domainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.Text).DisposeWith(disposables);