Compare commits

...

20 Commits
1.6.4 ... 1.6.5

Author SHA1 Message Date
ChsBuffer
2247a75269 bump version to 1.6.5 2020-10-24 16:06:13 +08:00
ChsBuffer
c1e9856e92 refactor: check and build dns string 2020-10-23 18:32:06 +08:00
ChsBuffer
41e74e0794 feat: Add setting ”Modified DNS“ for Process Mode 2020-10-23 17:46:31 +08:00
ChsBuffer
6f8214951a fix: update subscription async warning 2020-10-23 17:20:58 +08:00
ChsBuffer
0fc5b77004 refactor: Regenerate SettingForm designer code 2020-10-23 16:35:49 +08:00
ChsBuffer
34cbcbfb0f fix: SettingForm Control Order 2020-10-23 16:30:21 +08:00
ChsBuffer
1ad4a08a85 fix: Edit subscription link shows "Remark Name Duplicate!" 2020-10-23 14:46:16 +08:00
ChsBuffer
8e0bc8e260 feat: Notification update subscription exception status code 2020-10-23 14:45:30 +08:00
ChsBuffer
bae9ecfe88 fix: ImportServerFromClipboard parse twice 2020-10-23 14:36:43 +08:00
ChsBuffer
3ca3e45ce2 feat: Add AioDNS Setting 2020-10-23 13:48:33 +08:00
ChsBuffer
bcb220bc4b Revert "refactor: MainForm change Enabled to change State"
This reverts commit abfae4a9a0.
2020-10-23 12:36:46 +08:00
AmazingDM
c50eb32828 Update README.md 2020-10-23 10:19:53 +08:00
ChsBuffer
b96f171b47 fix: V2RayConfigUtils direct outbound config
refactor: rename VMessController Name V2Ray to VMess
2020-10-22 21:31:20 +08:00
ChsBuffer
4fbbd1dbd4 feat: update progress check hash 2020-10-22 15:17:26 +08:00
ChsBuffer
2ad394dfde refactor: builder dns string and Mode FileString 2020-10-22 15:17:26 +08:00
ChsBuffer
421b35a797 fix: SettingForm UseCustomDNSCheckBox click event is not bound 2020-10-22 15:17:26 +08:00
Connection Refused
25612df086 Update v2ray-core 4.31.2 2020-10-22 13:24:43 +08:00
ChsBuffer
4ac5065ce4 feat: add UseMux Setting 2020-10-21 22:18:11 +08:00
ChsBuffer
d4b97a99e0 feat: V2Ray AllowInsecure Setting 2020-10-21 22:09:53 +08:00
ChsBuffer
3d49fe0338 Revert "feat: V2Ray TLS AllowInsecure Setting"
This reverts commit 591f8e5a5c.
2020-10-21 22:07:58 +08:00
22 changed files with 760 additions and 544 deletions

View File

@@ -15,9 +15,9 @@ namespace Netch.Controllers
/// <returns></returns>
public bool Start()
{
if (!aiodns_dial(Encoding.UTF8.GetBytes(Path.GetFullPath("bin\\china_site_list")),
Encoding.UTF8.GetBytes("223.5.5.5:53"),
Encoding.UTF8.GetBytes("1.1.1.1:53"))
if (!aiodns_dial(Encoding.UTF8.GetBytes(Path.GetFullPath(Global.Settings.AioDNS.RulePath)),
Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.ChinaDNS}:53"),
Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.OtherDNS}:53"))
)
return false;
return

View File

@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Threading.Tasks;
@@ -78,7 +80,9 @@ namespace Netch.Controllers
{
// 备份并替换系统 DNS
_sysDns = DNS.OutboundDNS;
DNS.OutboundDNS = "1.1.1.1,8.8.8.8";
if (string.IsNullOrWhiteSpace(Global.Settings.ModifiedDNS))
Global.Settings.ModifiedDNS = "1.1.1.1,8.8.8.8";
DNS.OutboundDNS = Global.Settings.ModifiedDNS;
}
return aio_init();

View File

@@ -73,7 +73,7 @@ namespace Netch.Controllers
{
if (Global.Settings.TUNTAP.DNS.Any())
{
dns = Global.Settings.TUNTAP.DNS.Aggregate((current, ip) => $"{current},{ip}");
dns = DNS.Join(Global.Settings.TUNTAP.DNS);
}
else
{

View File

@@ -15,7 +15,7 @@ namespace Netch.Controllers
public const string Name = @"Netch";
public const string Copyright = @"Copyright © 2019 - 2020";
public const string AssemblyVersion = @"1.6.4";
public const string AssemblyVersion = @"1.6.5";
private const string Suffix = @"";
public static readonly string Version = $"{AssemblyVersion}{(string.IsNullOrEmpty(Suffix) ? "" : $"-{Suffix}")}";

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
@@ -26,8 +27,9 @@ namespace Netch.Forms
var texts = Clipboard.GetText();
if (!string.IsNullOrWhiteSpace(texts))
{
Global.Settings.Server.AddRange(ShareLink.ParseText(texts));
NotifyTip(i18N.TranslateFormat("Import {0} server(s) form Clipboard", ShareLink.ParseText(texts).Count));
var servers = ShareLink.ParseText(texts);
Global.Settings.Server.AddRange(servers);
NotifyTip(i18N.TranslateFormat("Import {0} server(s) form Clipboard", servers.Count));
InitServer();
Configuration.Save();
@@ -136,7 +138,7 @@ namespace Netch.Forms
await MainController.Start(ServerComboBox.SelectedItem as Server, mode);
}
await Task.WhenAll(Global.Settings.SubscribeLink.Select(async item => await Task.Run(async () =>
await Task.WhenAll(Global.Settings.SubscribeLink.Select(async item => await Task.Run(() =>
{
try
{
@@ -146,7 +148,17 @@ namespace Netch.Forms
if (Global.Settings.UseProxyToUpdateSubscription)
request.Proxy = new WebProxy($"http://127.0.0.1:{Global.Settings.HTTPLocalPort}");
var servers = ShareLink.ParseText(await WebUtil.DownloadStringAsync(request));
List<Server> servers;
var result = WebUtil.DownloadString(request, out var rep);
if (rep.StatusCode == HttpStatusCode.OK)
{
servers = ShareLink.ParseText(result);
}
else
{
throw new Exception($"{item.Remark} Response Status Code: {rep.StatusCode}");
}
foreach (var server in servers)
{
@@ -298,36 +310,32 @@ namespace Netch.Forms
private async void UninstallServiceToolStripMenuItem_Click(object sender, EventArgs e)
{
State = State.Starting;
Enabled = false;
StatusText(i18N.TranslateFormat("Uninstalling {0}", "NF Service"));
var result = false;
try
{
await Task.Run(() =>
{
if (NFController.UninstallDriver())
{
result = true;
StatusText(i18N.TranslateFormat("{0} has been uninstalled", "NF Service"));
}
});
}
finally
{
State = State.Stopped;
if (result)
StatusText(i18N.TranslateFormat("{0} has been uninstalled", "NF Service"));
Enabled = true;
}
}
private async void reinstallTapDriverToolStripMenuItem_Click(object sender, EventArgs e)
{
State = State.Starting;
StatusText(i18N.TranslateFormat("Uninstalling {0}", "TUN/TAP driver"));
var result = false;
Enabled = false;
try
{
await Task.Run(TUNTAP.deltapall);
result = true;
StatusText(i18N.TranslateFormat("{0} has been uninstalled", "TUN/TAP driver"));
}
catch (Exception exception)
{
@@ -335,9 +343,8 @@ namespace Netch.Forms
}
finally
{
State = State.Stopped;
if (result)
StatusText(i18N.TranslateFormat("{0} has been uninstalled", "TUN/TAP driver"));
State = State.Waiting;
Enabled = true;
}
}

View File

@@ -2,6 +2,7 @@
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using Netch.Controllers;
using Netch.Utils;
@@ -44,15 +45,37 @@ namespace Netch.Forms
if (MessageBoxX.Show(i18N.Translate("Download and install now?"), confirm: true) != DialogResult.OK)
return;
NotifyTip(i18N.Translate("Start downloading new version"));
var tagPage = await WebUtil.DownloadStringAsync(WebUtil.CreateRequest(_updater.LatestVersionUrl));
var match = Regex.Match(tagPage, @"<td .*>(?<sha256>.*)</td>", RegexOptions.Singleline);
// TODO Replace with regex get basename and sha256
var fileName = Path.GetFileName(new Uri(_updater.LatestVersionDownloadUrl).LocalPath);
fileName = fileName.Insert(fileName.LastIndexOf('.'), _updater.LatestVersionNumber);
var fileFullPath = Path.Combine(Global.NetchDir, "data", fileName);
var sha256 = match.Groups["sha256"].Value;
try
{
if (!File.Exists(fileFullPath))
if (File.Exists(fileFullPath))
{
await WebUtil.DownloadFileAsync(WebUtil.CreateRequest(_updater.LatestVersionDownloadUrl), fileFullPath);
if (Utils.Utils.SHA256CheckSum(fileFullPath) == sha256)
{
RunUpdater();
return;
}
File.Delete(fileFullPath);
}
// TODO Replace "New Version Found" to Progress bar
await WebUtil.DownloadFileAsync(WebUtil.CreateRequest(_updater.LatestVersionDownloadUrl), fileFullPath);
if (Utils.Utils.SHA256CheckSum(fileFullPath) != sha256)
{
MessageBoxX.Show("The downloaded file has the wrong hash");
return;
}
RunUpdater();

View File

@@ -334,7 +334,7 @@ namespace Netch.Forms
private async void SpeedPictureBox_Click(object sender, EventArgs e)
{
State = State.Starting;
Enabled = false;
StatusText(i18N.Translate("Testing"));
try
{
@@ -342,7 +342,7 @@ namespace Netch.Forms
}
finally
{
State = State.Stopped;
Enabled = true;
StatusText(i18N.Translate("Test done"));
Refresh();
}

File diff suppressed because it is too large Load Diff

View File

@@ -83,13 +83,17 @@ namespace Netch.Forms
#endregion
#region Process Mode
BindCheckBox(ModifySystemDNSCheckBox,
b => Global.Settings.ModifySystemDNS = b,
Global.Settings.ModifySystemDNS);
BindTextBox(ModifiedDNSTextBox,
s => DNS.TrySplit(s, out _, 2),
s => Global.Settings.ModifiedDNS = s,
Global.Settings.ModifiedDNS);
#endregion
#region TUN/TAP
@@ -111,6 +115,11 @@ namespace Netch.Forms
Global.Settings.TUNTAP.UseCustomDNS);
TUNTAPUseCustomDNSCheckBox_CheckedChanged(null, null);
BindTextBox(TUNTAPDNSTextBox,
s => !UseCustomDNSCheckBox.Checked || DNS.TrySplit(s, out _, 2),
s => Global.Settings.TUNTAP.DNS = DNS.Split(s).ToList(),
DNS.Join(Global.Settings.TUNTAP.DNS));
BindCheckBox(ProxyDNSCheckBox,
b => Global.Settings.TUNTAP.ProxyDNS = b,
Global.Settings.TUNTAP.ProxyDNS);
@@ -139,6 +148,9 @@ namespace Netch.Forms
BindCheckBox(TLSAllowInsecureCheckBox,
b => Global.Settings.V2RayConfig.AllowInsecure = b,
Global.Settings.V2RayConfig.AllowInsecure);
BindCheckBox(UseMuxCheckBox,
b => Global.Settings.V2RayConfig.UseMux = b,
Global.Settings.V2RayConfig.UseMux);
BindTextBox<int>(mtuTextBox,
i => true,
@@ -205,6 +217,25 @@ namespace Netch.Forms
Global.Settings.UpdateSubscribeatWhenOpened);
#endregion
#region AioDNS
BindTextBox(AioDNSRulePathTextBox,
s => true,
s => Global.Settings.AioDNS.RulePath = s,
Global.Settings.AioDNS.RulePath);
BindTextBox(ChinaDNSTextBox,
s => IPAddress.TryParse(s, out _),
s => Global.Settings.AioDNS.ChinaDNS = s,
Global.Settings.AioDNS.ChinaDNS);
BindTextBox(OtherDNSTextBox,
s => IPAddress.TryParse(s, out _),
s => Global.Settings.AioDNS.OtherDNS = s,
Global.Settings.AioDNS.OtherDNS);
#endregion
}
private void TUNTAPUseCustomDNSCheckBox_CheckedChanged(object sender, EventArgs e)
@@ -214,12 +245,12 @@ namespace Netch.Forms
if (UseCustomDNSCheckBox.Checked)
{
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Any()
? Global.Settings.TUNTAP.DNS.Aggregate((current, ip) => $"{current},{ip}")
? DNS.Join(Global.Settings.TUNTAP.DNS)
: "1.1.1.1";
}
else
{
TUNTAPDNSTextBox.Text = "Local DNS";
TUNTAPDNSTextBox.Text = "AioDNS";
}
}
@@ -253,42 +284,6 @@ namespace Netch.Forms
#region Check
#region TUNTAP
var dns = new string[0];
try
{
if (UseCustomDNSCheckBox.Checked)
{
dns = TUNTAPDNSTextBox.Text.Split(',').Where(s => !string.IsNullOrEmpty(s)).Select(s => s.Trim())
.ToArray();
if (dns.Any())
{
foreach (var ip in dns)
IPAddress.Parse(ip);
}
else
{
MessageBoxX.Show("DNS can not be empty");
return;
}
}
}
catch (Exception exception)
{
if (exception is FormatException)
MessageBoxX.Show(i18N.Translate("IP address format illegal. Try again."));
if (UseCustomDNSCheckBox.Checked)
{
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Aggregate((current, ip) => $"{current},{ip}");
}
return;
}
#endregion
#region Behavior
// STUN
@@ -326,7 +321,6 @@ namespace Netch.Forms
pair.Value.Invoke(pair.Key);
}
Global.Settings.TUNTAP.DNS = dns.ToList();
Global.Settings.STUN_Server = stunServer;
Global.Settings.STUN_Server_Port = stunServerPort;
@@ -454,5 +448,10 @@ namespace Netch.Forms
private readonly Dictionary<Control, Func<string, bool>> _checkActions = new Dictionary<Control, Func<string, bool>>();
private readonly Dictionary<Control, Action<Control>> _saveActions = new Dictionary<Control, Action<Control>>();
private void ModifySystemDNSCheckBox_CheckedChanged(object sender, EventArgs e)
{
ModifiedDNSTextBox.Enabled = ModifySystemDNSCheckBox.Checked;
}
}
}

View File

@@ -109,14 +109,14 @@ namespace Netch.Forms
return;
}
if (Global.Settings.SubscribeLink.Any(link => link.Remark.Equals(RemarkTextBox.Text)))
{
MessageBoxX.Show("Remark Name Duplicate!");
return;
}
if (_editingIndex == -1)
{
if (Global.Settings.SubscribeLink.Any(link => link.Remark.Equals(RemarkTextBox.Text)))
{
MessageBoxX.Show("Remark Name Duplicate!");
return;
}
Global.Settings.SubscribeLink.Add(new SubscribeLink
{
Remark = RemarkTextBox.Text,

View File

@@ -131,30 +131,30 @@ namespace Netch.Models
/// <returns>模式文件字符串</returns>
public string ToFileString()
{
string fileString;
StringBuilder fileString = new StringBuilder();
switch (Type)
{
case 0:
// 进程模式
fileString = $"# {Remark}";
fileString.Append($"# {Remark}");
break;
case 1:
// TUN/TAP 规则内 IP CIDR无 Bypass China 设置
fileString = $"# {Remark}, {Type}, 0";
fileString.Append($"# {Remark}, {Type}, 0");
break;
default:
fileString = $"# {Remark}, {Type}, {(BypassChina ? 1 : 0)}";
fileString.Append($"# {Remark}, {Type}, {(BypassChina ? 1 : 0)}");
break;
}
fileString += Global.EOF;
if (Rule.Any())
{
fileString.Append(Global.EOF);
fileString.Append(string.Join(Global.EOF, Rule));
}
fileString = Rule.Aggregate(fileString, (current, item) => $"{current}{item}{Global.EOF}");
// 去除最后的行尾符
fileString = fileString.Substring(0, fileString.Length - 2);
return fileString;
return fileString.ToString();
}
public string TypeToString()

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Netch.Models
{
@@ -65,6 +67,17 @@ namespace Netch.Models
public bool AllowInsecure = true;
public KcpConfig KcpConfig = new KcpConfig();
public bool UseMux = true;
}
public class AioDNSConfig
{
public string RulePath = "bin\\china_site_list";
public string ChinaDNS = "223.5.5.5";
public string OtherDNS = "1.1.1.1";
}
/// <summary>
@@ -127,6 +140,11 @@ namespace Netch.Models
/// </summary>
public bool ModifySystemDNS = false;
/// <summary>
/// 要修改为的系统 DNS
/// </summary>
public string ModifiedDNS = "1.1.1.1,8.8.8.8";
/// <summary>
/// 解析服务器主机名
/// </summary>
@@ -233,5 +251,7 @@ namespace Netch.Models
public string Language = "System";
public V2rayConfig V2RayConfig = new V2rayConfig();
public AioDNSConfig AioDNS = new AioDNSConfig();
}
}

View File

@@ -39,22 +39,19 @@ namespace Netch.Servers.VLESS.VLESSForm
s => true,
s => server.Path = s,
server.Path);
CreateComboBox("TLSSecure", "TLS Secure",
CreateComboBox("UseMux", "Use Mux",
new List<string> {"", "true", "false"},
s =>
s => server.UseMux = s switch
{
server.TLSSecure = s switch
{
"" => null,
"true" => true,
"false" => false,
_ => null
};
"" => null,
"true" => true,
"false" => false,
_ => null
},
server.TLSSecure?.ToString() ?? string.Empty);
CreateCheckBox("UseMux", "Use Mux",
b => server.UseMux = b,
server.UseMux);
server.UseMux?.ToString() ?? "");
CreateCheckBox("TLSSecure", "TLS Secure",
b => server.TLSSecure = b,
server.TLSSecure);
}
}
}

View File

@@ -48,22 +48,19 @@ namespace Netch.Servers.VMess.Form
s => true,
s => server.QUICSecret = s,
server.QUICSecret);
CreateComboBox("TLSSecure", "TLS Secure",
CreateComboBox("UseMux", "Use Mux",
new List<string> {"", "true", "false"},
s =>
s => server.UseMux = s switch
{
server.TLSSecure = s switch
{
"" => null,
"true" => true,
"false" => false,
_ => null
};
"" => null,
"true" => true,
"false" => false,
_ => null
},
server.TLSSecure?.ToString() ?? string.Empty);
CreateCheckBox("UseMux", "Use Mux",
s => server.UseMux = s,
server.UseMux);
server.UseMux?.ToString() ?? "");
CreateCheckBox("TLSSecure", "TLS Secure",
s => server.TLSSecure = s,
server.TLSSecure);
}
}
}

View File

@@ -18,7 +18,7 @@ namespace Netch.Servers.VMess.Utils
routing(server, mode, ref v2rayConfig);
outbound(server, ref v2rayConfig);
outbound(server, mode, ref v2rayConfig);
return JsonConvert.SerializeObject(v2rayConfig);
}
@@ -103,7 +103,7 @@ namespace Netch.Servers.VMess.Utils
}
}
private static void outbound(Server server, ref V2rayConfig v2rayConfig)
private static void outbound(Server server, Mode mode, ref V2rayConfig v2rayConfig)
{
try
{
@@ -174,8 +174,8 @@ namespace Netch.Servers.VMess.Utils
usersItem.flow = string.Empty;
usersItem.encryption = vless.EncryptMethod;
outbound.mux.enabled = vless.UseMux;
outbound.mux.concurrency = vless.UseMux ? 8 : -1;
outbound.mux.enabled = vless.UseMux ?? Global.Settings.V2RayConfig.UseMux;
outbound.mux.concurrency = vless.UseMux ?? Global.Settings.V2RayConfig.UseMux ? 8 : -1;
var streamSettings = outbound.streamSettings;
boundStreamSettings(vless, ref streamSettings);
@@ -213,8 +213,8 @@ namespace Netch.Servers.VMess.Utils
usersItem.alterId = vmess.AlterID;
usersItem.security = vmess.EncryptMethod;
outbound.mux.enabled = vmess.UseMux;
outbound.mux.concurrency = vmess.UseMux ? 8 : -1;
outbound.mux.enabled = vmess.UseMux ?? Global.Settings.V2RayConfig.UseMux;
outbound.mux.concurrency = vmess.UseMux ?? Global.Settings.V2RayConfig.UseMux ? 8 : -1;
var streamSettings = outbound.streamSettings;
boundStreamSettings(vmess, ref streamSettings);
@@ -224,7 +224,15 @@ namespace Netch.Servers.VMess.Utils
}
}
v2rayConfig.outbounds = new List<Outbounds> {outbound};
v2rayConfig.outbounds = new List<Outbounds>
{
outbound,
new Outbounds
{
tag = "direct",
protocol = "freedom"
}
};
}
catch
{
@@ -238,13 +246,13 @@ namespace Netch.Servers.VMess.Utils
{
streamSettings.network = server.TransferProtocol;
var host = server.Host;
if (server.TLSSecure ?? Global.Settings.V2RayConfig.AllowInsecure)
if (server.TLSSecure)
{
streamSettings.security = "tls";
var tlsSettings = new TlsSettings
{
allowInsecure = true
allowInsecure = Global.Settings.V2RayConfig.AllowInsecure
};
if (!string.IsNullOrWhiteSpace(host))
{
@@ -318,7 +326,7 @@ namespace Netch.Servers.VMess.Utils
type = server.FakeType
}
};
if (server.TLSSecure ?? Global.Settings.V2RayConfig.AllowInsecure)
if (server.TLSSecure)
{
streamSettings.tlsSettings.serverName = server.Hostname;
}
@@ -330,7 +338,7 @@ namespace Netch.Servers.VMess.Utils
var xtlsSettings = new TlsSettings
{
allowInsecure = true
allowInsecure = Global.Settings.V2RayConfig.AllowInsecure
};
if (!string.IsNullOrWhiteSpace(host))
{

View File

@@ -64,12 +64,12 @@ namespace Netch.Servers.VMess
/// <summary>
/// TLS 底层传输安全
/// </summary>
public bool? TLSSecure { get; set; }
public bool TLSSecure { get; set; } = false;
/// <summary>
/// Mux 多路复用
/// </summary>
public bool UseMux { get; set; } = true;
public bool? UseMux { get; set; } = true;
}
public class VMessGlobal

View File

@@ -13,7 +13,7 @@ namespace Netch.Servers.VMess
StoppedKeywords.AddRange(new[] {"config file not readable", "failed to"});
}
public override string Name { get; protected set; } = "V2Ray";
public override string Name { get; protected set; } = "VMess";
public override string MainFile { get; protected set; } = "v2ray.exe";
public Server Server { get; set; }
public ushort? Socks5LocalPort { get; set; }

View File

@@ -49,7 +49,7 @@ namespace Netch.Servers.VMess
type = server.FakeType,
host = server.Host,
path = server.Path,
tls = server.TLSSecure ?? Global.Settings.V2RayConfig.AllowInsecure ? "tls" : ""
tls = server.TLSSecure ? "tls" : ""
});
return "vmess://" + ShareLink.URLSafeBase64Encode(vmessJson);
}

View File

@@ -1,5 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Microsoft.Win32;
@@ -75,5 +77,24 @@ namespace Netch.Utils
}
set => AdapterRegistry(true).SetValue("NameServer", value, RegistryValueKind.String);
}
public static IEnumerable<string> Split(string dns)
{
return dns.Split(',').Where(ip => !string.IsNullOrWhiteSpace(ip)).Select(ip => ip.Trim());
}
public static bool TrySplit(string value, out IEnumerable<string> result, ushort maxCount = 0)
{
result = Split(value).ToArray();
return maxCount == 0 || result.Count() <= maxCount
&&
result.All(ip => IPAddress.TryParse(ip, out _));
}
public static string Join(IEnumerable<string> dns)
{
return string.Join(",", dns);
}
}
}

View File

@@ -47,6 +47,22 @@ namespace Netch.Utils
return memoryStream.ToArray();
}
/// <summary>
/// 异步下载并编码为字符串
/// </summary>
/// <param name="req"></param>
/// <param name="rep"></param>
/// <param name="encoding">编码默认UTF-8</param>
/// <returns></returns>
public static string DownloadString(HttpWebRequest req, out HttpWebResponse rep, string encoding = "UTF-8")
{
rep = (HttpWebResponse) req.GetResponse();
using var responseStream = rep.GetResponseStream();
using var streamReader = new StreamReader(responseStream, Encoding.GetEncoding(encoding));
return streamReader.ReadToEnd();
}
/// <summary>
/// 异步下载并编码为字符串
/// </summary>

View File

@@ -70,3 +70,5 @@ As well, Netch avoid the restricted NAT problem caused by SSTap. You can use an
- [Privoxy](https://www.privoxy.org/)
- [NatTypeTester](https://github.com/HMBSbige/NatTypeTester)
- [NetFilter SDK](https://netfiltersdk.com/)
[![Stargazers over time](https://starchart.cc/NetchX/Netch.svg)](https://starchart.cc/NetchX/Netch)