mirror of
https://github.com/2dust/v2rayN.git
synced 2025-10-26 18:24:43 +00:00
Compare commits
6 commits
14b8938d24
...
1d54f88e79
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d54f88e79 | ||
|
|
c2c13ad318 | ||
|
|
3a21596d95 | ||
|
|
18ccabd193 | ||
|
|
942335db61 | ||
|
|
12b46e7c43 |
22 changed files with 200 additions and 26 deletions
|
|
@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
|
|||
using System.Security.Cryptography;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using CliWrap;
|
||||
using CliWrap.Buffered;
|
||||
|
||||
|
|
@ -357,6 +358,14 @@ public class Utils
|
|||
return userHostsMap;
|
||||
}
|
||||
|
||||
public static List<string> ParseCertSha256ToList(string certSha256Content)
|
||||
{
|
||||
return String2List(certSha256Content)
|
||||
.Select(s => s.Replace(":", "").Replace(" ", ""))
|
||||
.Where(s => s.Length == 64 && Regex.IsMatch(s, @"\A\b[0-9a-fA-F]+\b\Z"))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
#endregion 转换函数
|
||||
|
||||
#region 数据检查
|
||||
|
|
|
|||
|
|
@ -598,6 +598,7 @@ public class Global
|
|||
{ "cloudflare-dns.com", new List<string> { "104.16.249.249", "104.16.248.249", "2606:4700::6810:f8f9", "2606:4700::6810:f9f9" } },
|
||||
{ "dns.cloudflare.com", new List<string> { "104.16.132.229", "104.16.133.229", "2606:4700::6810:84e5", "2606:4700::6810:85e5" } },
|
||||
{ "dot.pub", new List<string> { "1.12.12.12", "120.53.53.53" } },
|
||||
{ "doh.pub", new List<string> { "1.12.12.12", "120.53.53.53" } },
|
||||
{ "dns.quad9.net", new List<string> { "9.9.9.9", "149.112.112.112", "2620:fe::fe", "2620:fe::9" } },
|
||||
{ "dns.yandex.net", new List<string> { "77.88.8.8", "77.88.8.1", "2a02:6b8::feed:0ff", "2a02:6b8:0:1::feed:0ff" } },
|
||||
{ "dns.sb", new List<string> { "185.222.222.222", "2a09::" } },
|
||||
|
|
|
|||
|
|
@ -253,6 +253,7 @@ public static class ConfigHandler
|
|||
item.ShortId = profileItem.ShortId;
|
||||
item.SpiderX = profileItem.SpiderX;
|
||||
item.Mldsa65Verify = profileItem.Mldsa65Verify;
|
||||
item.CertSha256 = profileItem.CertSha256;
|
||||
item.Extra = profileItem.Extra;
|
||||
item.MuxEnabled = profileItem.MuxEnabled;
|
||||
}
|
||||
|
|
@ -1214,11 +1215,11 @@ public static class ConfigHandler
|
|||
CoreType = ECoreType.sing_box,
|
||||
ConfigType = EConfigType.SOCKS,
|
||||
Address = Global.Loopback,
|
||||
Sni = node.Address, //Tun2SocksAddress
|
||||
SpiderX = node.Address, // Tun2SocksAddress
|
||||
Port = AppManager.Instance.GetLocalPort(EInboundProtocol.socks)
|
||||
};
|
||||
}
|
||||
else if ((node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0))
|
||||
else if (node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0)
|
||||
{
|
||||
var preCoreType = config.RunningCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
|
||||
itemSocks = new ProfileItem()
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ public class ProfileItem : ReactiveObject
|
|||
public string ShortId { get; set; }
|
||||
public string SpiderX { get; set; }
|
||||
public string Mldsa65Verify { get; set; }
|
||||
public string CertSha256 { get; set; }
|
||||
public string Extra { get; set; }
|
||||
public bool? MuxEnabled { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ public class Tls4Sbox
|
|||
public bool? fragment { get; set; }
|
||||
public string? fragment_fallback_delay { get; set; }
|
||||
public bool? record_fragment { get; set; }
|
||||
public List<string>? certificate_sha256 { get; set; }
|
||||
}
|
||||
|
||||
public class Multiplex4Sbox
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ public class TlsSettings4Ray
|
|||
public string? shortId { get; set; }
|
||||
public string? spiderX { get; set; }
|
||||
public string? mldsa65Verify { get; set; }
|
||||
public List<string>? pinnedPeerCertificateSha256 { get; set; }
|
||||
}
|
||||
|
||||
public class TcpSettings4Ray
|
||||
|
|
|
|||
18
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
18
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
|
|
@ -2364,6 +2364,24 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Server Certificate Fingerprint (SHA-256) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbCertSha256 {
|
||||
get {
|
||||
return ResourceManager.GetString("TbCertSha256", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Hex SHA-256, comma-separated for certificate chain 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbCertSha256Tips {
|
||||
get {
|
||||
return ResourceManager.GetString("TbCertSha256Tips", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Clear system proxy 的本地化字符串。
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1515,4 +1515,10 @@
|
|||
<data name="TbFakeIPTips" xml:space="preserve">
|
||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
||||
</data>
|
||||
<data name="TbCertSha256" xml:space="preserve">
|
||||
<value>Server Certificate Fingerprint (SHA-256)</value>
|
||||
</data>
|
||||
<data name="TbCertSha256Tips" xml:space="preserve">
|
||||
<value>Hex SHA-256, comma-separated for certificate chain</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1515,4 +1515,10 @@
|
|||
<data name="TbFakeIPTips" xml:space="preserve">
|
||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
||||
</data>
|
||||
<data name="TbCertSha256" xml:space="preserve">
|
||||
<value>Server Certificate Fingerprint (SHA-256)</value>
|
||||
</data>
|
||||
<data name="TbCertSha256Tips" xml:space="preserve">
|
||||
<value>Hex SHA-256, comma-separated for certificate chain</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1515,4 +1515,10 @@
|
|||
<data name="TbFakeIPTips" xml:space="preserve">
|
||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
||||
</data>
|
||||
<data name="TbCertSha256" xml:space="preserve">
|
||||
<value>Server Certificate Fingerprint (SHA-256)</value>
|
||||
</data>
|
||||
<data name="TbCertSha256Tips" xml:space="preserve">
|
||||
<value>Hex SHA-256, comma-separated for certificate chain</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1515,4 +1515,10 @@
|
|||
<data name="TbFakeIPTips" xml:space="preserve">
|
||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
||||
</data>
|
||||
<data name="TbCertSha256" xml:space="preserve">
|
||||
<value>Server Certificate Fingerprint (SHA-256)</value>
|
||||
</data>
|
||||
<data name="TbCertSha256Tips" xml:space="preserve">
|
||||
<value>Hex SHA-256, comma-separated for certificate chain</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1512,4 +1512,10 @@
|
|||
<data name="TbFakeIPTips" xml:space="preserve">
|
||||
<value>默认全局生效,内置 FakeIP 过滤,仅在 sing-box 中生效</value>
|
||||
</data>
|
||||
<data name="TbCertSha256" xml:space="preserve">
|
||||
<value>服务器证书指纹 (SHA-256)</value>
|
||||
</data>
|
||||
<data name="TbCertSha256Tips" xml:space="preserve">
|
||||
<value>十六进制 SHA-256,证书链用逗号分隔</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1512,4 +1512,10 @@
|
|||
<data name="TbFakeIPTips" xml:space="preserve">
|
||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
||||
</data>
|
||||
<data name="TbCertSha256" xml:space="preserve">
|
||||
<value>Server Certificate Fingerprint (SHA-256)</value>
|
||||
</data>
|
||||
<data name="TbCertSha256Tips" xml:space="preserve">
|
||||
<value>Hex SHA-256, comma-separated for certificate chain</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -43,16 +43,7 @@ public partial class CoreConfigSingboxService
|
|||
});
|
||||
}
|
||||
|
||||
// Tun2SocksAddress
|
||||
if (node != null && Utils.IsDomain(node.Address))
|
||||
{
|
||||
singboxConfig.dns.rules ??= new List<Rule4Sbox>();
|
||||
singboxConfig.dns.rules.Insert(0, new Rule4Sbox
|
||||
{
|
||||
server = Global.SingboxOutboundResolverTag,
|
||||
domain = [node.Address],
|
||||
});
|
||||
}
|
||||
await GenOutboundDnsRule(node, singboxConfig, Global.SingboxOutboundResolverTag);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -346,16 +337,7 @@ public partial class CoreConfigSingboxService
|
|||
await GenDnsDomainsLegacyCompatible(singboxConfig, item);
|
||||
}
|
||||
|
||||
// Tun2SocksAddress
|
||||
if (node != null && Utils.IsDomain(node.Address))
|
||||
{
|
||||
singboxConfig.dns.rules ??= new List<Rule4Sbox>();
|
||||
singboxConfig.dns.rules.Insert(0, new Rule4Sbox
|
||||
{
|
||||
server = Global.SingboxFinalResolverTag,
|
||||
domain = [node.Address],
|
||||
});
|
||||
}
|
||||
await GenOutboundDnsRule(node, singboxConfig, Global.SingboxFinalResolverTag);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -425,6 +407,37 @@ public partial class CoreConfigSingboxService
|
|||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private async Task<int> GenOutboundDnsRule(ProfileItem? node, SingboxConfig singboxConfig, string? server)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var domain = string.Empty;
|
||||
if (Utils.IsDomain(node.Address)) // normal outbound
|
||||
{
|
||||
domain = node.Address;
|
||||
}
|
||||
else if (node.Address == Global.Loopback && node.SpiderX.IsNotEmpty() && Utils.IsDomain(node.SpiderX)) // Tun2SocksAddress
|
||||
{
|
||||
domain = node.SpiderX;
|
||||
}
|
||||
if (domain.IsNullOrEmpty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
singboxConfig.dns.rules ??= new List<Rule4Sbox>();
|
||||
singboxConfig.dns.rules.Insert(0, new Rule4Sbox
|
||||
{
|
||||
server = server,
|
||||
domain = [domain],
|
||||
});
|
||||
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private static Server4Sbox? ParseDnsAddress(string address)
|
||||
{
|
||||
var addressFirst = address?.Split(address.Contains(',') ? ',' : ';').FirstOrDefault()?.Trim();
|
||||
|
|
|
|||
|
|
@ -251,6 +251,20 @@ public partial class CoreConfigSingboxService
|
|||
fingerprint = node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : node.Fingerprint
|
||||
};
|
||||
}
|
||||
if (node.CertSha256.IsNotEmpty())
|
||||
{
|
||||
// hex to raw to base64
|
||||
var certSha256List = Utils.ParseCertSha256ToList(node.CertSha256)
|
||||
.Select(s => Convert.ToBase64String(
|
||||
Enumerable.Range(0, 32)
|
||||
.Select(i => Convert.ToByte(s.Substring(i * 2, 2), 16))
|
||||
.ToArray()))
|
||||
.ToList();
|
||||
if (certSha256List.Count > 0)
|
||||
{
|
||||
tls.certificate_sha256 = certSha256List;
|
||||
}
|
||||
}
|
||||
if (node.StreamSecurity == Global.StreamSecurityReality)
|
||||
{
|
||||
tls.reality = new Reality4Sbox()
|
||||
|
|
|
|||
|
|
@ -277,6 +277,14 @@ public partial class CoreConfigV2rayService
|
|||
{
|
||||
tlsSettings.serverName = Utils.String2List(host)?.First();
|
||||
}
|
||||
if (node.CertSha256.IsNotEmpty())
|
||||
{
|
||||
var certSha256List = Utils.ParseCertSha256ToList(node.CertSha256);
|
||||
if (certSha256List.Count > 0)
|
||||
{
|
||||
tlsSettings.pinnedPeerCertificateSha256 = certSha256List;
|
||||
}
|
||||
}
|
||||
streamSettings.tlsSettings = tlsSettings;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -709,9 +709,9 @@
|
|||
<Grid
|
||||
x:Name="gridTlsMore"
|
||||
Grid.Row="7"
|
||||
ColumnDefinitions="180,Auto"
|
||||
ColumnDefinitions="180,Auto,Auto"
|
||||
IsVisible="False"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
|
|
@ -765,6 +765,26 @@
|
|||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbCertSha256}" />
|
||||
<TextBox
|
||||
x:Name="txtCertSha256"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbCertSha256Tips}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridRealityMore"
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||
this.Bind(ViewModel, vm => vm.SelectedSource.AllowInsecure, v => v.cmbAllowInsecure.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Fingerprint, v => v.cmbFingerprint.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Alpn, v => v.cmbAlpn.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.CertSha256, v => v.txtCertSha256.Text).DisposeWith(disposables);
|
||||
//reality
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Fingerprint, v => v.cmbFingerprint2.SelectedValue).DisposeWith(disposables);
|
||||
|
|
|
|||
24
v2rayN/v2rayN.slnx
Normal file
24
v2rayN/v2rayN.slnx
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<Solution>
|
||||
<Folder Name="/GitHub Action/">
|
||||
<File Path="../.github/workflows/build-all.yml" />
|
||||
<File Path="../.github/workflows/build-linux.yml" />
|
||||
<File Path="../.github/workflows/build-osx.yml" />
|
||||
<File Path="../.github/workflows/build-windows-desktop.yml" />
|
||||
<File Path="../.github/workflows/build-windows.yml" />
|
||||
<File Path="../.github/workflows/winget-publish.yml" />
|
||||
<File Path="../package-appimage.sh" />
|
||||
<File Path="../package-debian.sh" />
|
||||
<File Path="../package-osx.sh" />
|
||||
<File Path="../package-release-zip.sh" />
|
||||
<File Path="../pkg2appimage.yml" />
|
||||
</Folder>
|
||||
<Folder Name="/Solution Files/">
|
||||
<File Path="Directory.Build.props" />
|
||||
<File Path="Directory.Packages.props" />
|
||||
</Folder>
|
||||
<Project Path="AmazTool/AmazTool.csproj" />
|
||||
<Project Path="GlobalHotKeys/src/GlobalHotKeys/GlobalHotKeys.csproj" />
|
||||
<Project Path="ServiceLib/ServiceLib.csproj" />
|
||||
<Project Path="v2rayN.Desktop/v2rayN.Desktop.csproj" />
|
||||
<Project Path="v2rayN/v2rayN.csproj" />
|
||||
</Solution>
|
||||
|
|
@ -32,8 +32,8 @@ public class QRCodeUtils
|
|||
{
|
||||
GetDpi(window, out var dpiX, out var dpiY);
|
||||
|
||||
var left = (int)(SystemParameters.WorkArea.Left);
|
||||
var top = (int)(SystemParameters.WorkArea.Top);
|
||||
var left = (int)SystemParameters.WorkArea.Left;
|
||||
var top = (int)SystemParameters.WorkArea.Top;
|
||||
var width = (int)(SystemParameters.WorkArea.Width / dpiX);
|
||||
var height = (int)(SystemParameters.WorkArea.Height / dpiY);
|
||||
|
||||
|
|
|
|||
|
|
@ -928,10 +928,12 @@
|
|||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
|
|
@ -995,6 +997,29 @@
|
|||
Width="200"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbCertSha256}" />
|
||||
<TextBox
|
||||
x:Name="txtCertSha256"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbCertSha256Tips}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridRealityMore"
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@ public partial class AddServerWindow
|
|||
this.Bind(ViewModel, vm => vm.SelectedSource.AllowInsecure, v => v.cmbAllowInsecure.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Fingerprint, v => v.cmbFingerprint.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Alpn, v => v.cmbAlpn.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.CertSha256, v => v.txtCertSha256.Text).DisposeWith(disposables);
|
||||
//reality
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Fingerprint, v => v.cmbFingerprint2.Text).DisposeWith(disposables);
|
||||
|
|
|
|||
Loading…
Reference in a new issue