diff --git a/v2rayMiniConsole/.gitattributes b/v2rayMiniConsole/.gitattributes
new file mode 100644
index 00000000..1ff0c423
--- /dev/null
+++ b/v2rayMiniConsole/.gitattributes
@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln merge=binary
+#*.csproj merge=binary
+#*.vbproj merge=binary
+#*.vcxproj merge=binary
+#*.vcproj merge=binary
+#*.dbproj merge=binary
+#*.fsproj merge=binary
+#*.lsproj merge=binary
+#*.wixproj merge=binary
+#*.modelproj merge=binary
+#*.sqlproj merge=binary
+#*.wwaproj merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg binary
+#*.png binary
+#*.gif binary
+
+###############################################################################
+# diff behavior for common document formats
+#
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the
+# entries below.
+###############################################################################
+#*.doc diff=astextplain
+#*.DOC diff=astextplain
+#*.docx diff=astextplain
+#*.DOCX diff=astextplain
+#*.dot diff=astextplain
+#*.DOT diff=astextplain
+#*.pdf diff=astextplain
+#*.PDF diff=astextplain
+#*.rtf diff=astextplain
+#*.RTF diff=astextplain
diff --git a/v2rayMiniConsole/.gitignore b/v2rayMiniConsole/.gitignore
new file mode 100644
index 00000000..9491a2fd
--- /dev/null
+++ b/v2rayMiniConsole/.gitignore
@@ -0,0 +1,363 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Oo]ut/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
\ No newline at end of file
diff --git a/v2rayMiniConsole/PacLib/PacHandler.cs b/v2rayMiniConsole/PacLib/PacHandler.cs
new file mode 100644
index 00000000..2e32f1f7
--- /dev/null
+++ b/v2rayMiniConsole/PacLib/PacHandler.cs
@@ -0,0 +1,102 @@
+using System;
+using System.IO;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PacLib;
+
+public class PacHandler
+{
+ private static string _configPath;
+ private static int _httpPort;
+ private static int _pacPort;
+ private static TcpListener? _tcpListener;
+ private static string _pacText;
+ private static bool _isRunning;
+ private static bool _needRestart = true;
+
+ public static void Start(string configPath, int httpPort, int pacPort)
+ {
+ _needRestart = (configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning);
+
+ _configPath = configPath;
+ _httpPort = httpPort;
+ _pacPort = pacPort;
+
+ InitText();
+
+ if (_needRestart)
+ {
+ Stop();
+ RunListener();
+ }
+ }
+
+ private static void InitText()
+ {
+ var path = Path.Combine(_configPath, "pac.txt");
+ if (!File.Exists(path))
+ {
+ File.AppendAllText(path, Resources.ResourceManager.GetString("pac"));
+ }
+
+ _pacText = File.ReadAllText(path).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;");
+ }
+
+ private static void RunListener()
+ {
+ _tcpListener = TcpListener.Create(_pacPort);
+ _isRunning = true;
+ _tcpListener.Start();
+ Task.Factory.StartNew(async () =>
+ {
+ while (_isRunning)
+ {
+ try
+ {
+ if (!_tcpListener.Pending())
+ {
+ await Task.Delay(10);
+ continue;
+ }
+
+ var client = _tcpListener.AcceptTcpClient();
+ await Task.Run(() =>
+ {
+ var stream = client.GetStream();
+ var sb = new StringBuilder();
+ sb.AppendLine("HTTP/1.0 200 OK");
+ sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
+ sb.AppendLine("Connection:close");
+ sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(_pacText));
+ sb.AppendLine();
+ sb.Append(_pacText);
+ var content = Encoding.UTF8.GetBytes(sb.ToString());
+ stream.Write(content, 0, content.Length);
+ stream.Flush();
+ });
+ }
+ catch (Exception e)
+ {
+ }
+ }
+ }, TaskCreationOptions.LongRunning);
+ }
+
+ public static void Stop()
+ {
+ if (_tcpListener != null)
+ {
+ try
+ {
+ _isRunning = false;
+ _tcpListener.Stop();
+ _tcpListener = null;
+ }
+ catch (Exception e)
+ {
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/PacLib/PacLib.csproj b/v2rayMiniConsole/PacLib/PacLib.csproj
new file mode 100644
index 00000000..feb6e55d
--- /dev/null
+++ b/v2rayMiniConsole/PacLib/PacLib.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net8.0
+ enable
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
diff --git a/v2rayMiniConsole/PacLib/Resources.Designer.cs b/v2rayMiniConsole/PacLib/Resources.Designer.cs
new file mode 100644
index 00000000..e7bfd02c
--- /dev/null
+++ b/v2rayMiniConsole/PacLib/Resources.Designer.cs
@@ -0,0 +1,95 @@
+//------------------------------------------------------------------------------
+//
+// 此代码由工具生成。
+// 运行时版本:4.0.30319.42000
+//
+// 对此文件的更改可能会导致不正确的行为,并且如果
+// 重新生成代码,这些更改将会丢失。
+//
+//------------------------------------------------------------------------------
+
+namespace PacLib {
+ using System;
+
+
+ ///
+ /// 一个强类型的资源类,用于查找本地化的字符串等。
+ ///
+ // 此类是由 StronglyTypedResourceBuilder
+ // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
+ // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
+ // (以 /str 作为命令选项),或重新生成 VS 项目。
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// 返回此类使用的缓存的 ResourceManager 实例。
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PacLib.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// 重写当前线程的 CurrentUICulture 属性,对
+ /// 使用此强类型资源类的所有资源查找执行重写。
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// 查找类似 var proxy = '__PROXY__';
+ ///var rules = [
+ /// [
+ /// [],
+ /// []
+ /// ],
+ /// [
+ /// [
+ /// "aftygh.gov.tw",
+ /// "aide.gov.tw",
+ /// "aliyun.com",
+ /// "arte.gov.tw",
+ /// "baidu.com",
+ /// "chinaso.com",
+ /// "chinaz.com",
+ /// "chukuang.gov.tw",
+ /// "cycab.gov.tw",
+ /// "dbnsa.gov.tw",
+ /// "df.gov.tw",
+ /// "eastcoast-nsa.gov.tw",
+ /// "erv-nsa.gov.tw",
+ /// "grb.gov.tw",
+ /// "haosou.com",
+ /// [字符串的其余部分被截断]"; 的本地化字符串。
+ ///
+ internal static string pac {
+ get {
+ return ResourceManager.GetString("pac", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/v2rayMiniConsole/PacLib/Resources.resx b/v2rayMiniConsole/PacLib/Resources.resx
new file mode 100644
index 00000000..1fffd5af
--- /dev/null
+++ b/v2rayMiniConsole/PacLib/Resources.resx
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+ Resources\pac.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312
+
+
\ No newline at end of file
diff --git a/v2rayMiniConsole/PacLib/Resources/pac.txt b/v2rayMiniConsole/PacLib/Resources/pac.txt
new file mode 100644
index 00000000..02576524
--- /dev/null
+++ b/v2rayMiniConsole/PacLib/Resources/pac.txt
@@ -0,0 +1,6024 @@
+var proxy = '__PROXY__';
+var rules = [
+ [
+ [],
+ []
+ ],
+ [
+ [
+ "aftygh.gov.tw",
+ "aide.gov.tw",
+ "aliyun.com",
+ "arte.gov.tw",
+ "baidu.com",
+ "chinaso.com",
+ "chinaz.com",
+ "chukuang.gov.tw",
+ "cycab.gov.tw",
+ "dbnsa.gov.tw",
+ "df.gov.tw",
+ "eastcoast-nsa.gov.tw",
+ "erv-nsa.gov.tw",
+ "grb.gov.tw",
+ "haosou.com",
+ "haygo.com",
+ "hchcc.gov.tw",
+ "hsinchu-cc.gov.tw",
+ "iner.gov.tw",
+ "ip.cn",
+ "jike.com",
+ "jpush.cn",
+ "klsio.gov.tw",
+ "kmseh.gov.tw",
+ "locql.com",
+ "lungtanhr.gov.tw",
+ "maolin-nsa.gov.tw",
+ "matsu-news.gov.tw",
+ "matsu-nsa.gov.tw",
+ "matsucc.gov.tw",
+ "moe.gov.tw",
+ "nankan.gov.tw",
+ "ncree.gov.tw",
+ "necoast-nsa.gov.tw",
+ "ner.gov.tw",
+ "nmmba.gov.tw",
+ "nmp.gov.tw",
+ "nmvttc.gov.tw",
+ "northguan-nsa.gov.tw",
+ "npm.gov.tw",
+ "nstm.gov.tw",
+ "ntdmh.gov.tw",
+ "ntl.gov.tw",
+ "ntsec.gov.tw",
+ "ntuh.gov.tw",
+ "nvri.gov.tw",
+ "nyc.gov.tw",
+ "penghu-nsa.gov.tw",
+ "post.gov.tw",
+ "qq.com",
+ "simplecd.me",
+ "sina.cn",
+ "sina.com.cn",
+ "siraya-nsa.gov.tw",
+ "sl-reverse.com",
+ "so.com",
+ "sogou.com",
+ "soso.com",
+ "stdtime.gov.tw",
+ "sunmoonlake.gov.tw",
+ "syniumsoftware.com",
+ "taitung-house.gov.tw",
+ "taoyuan.gov.tw",
+ "tphcc.gov.tw",
+ "trimt-nsa.gov.tw",
+ "uluai.com.cn",
+ "vghks.gov.tw",
+ "vghtc.gov.tw",
+ "vghtpe.gov.tw",
+ "wallproxy.com.cn",
+ "wanfang.gov.tw",
+ "weibo.com",
+ "yahoo.cn",
+ "yatsen.gov.tw",
+ "yda.gov.tw",
+ "youdao.com",
+ "zhongsou.com"
+ ],
+ [
+ "000webhost.com",
+ "030buy.com",
+ "0rz.tw",
+ "1-apple.com.tw",
+ "10.tt",
+ "1000giri.net",
+ "100ke.org",
+ "10beasts.net",
+ "10conditionsoflove.com",
+ "10musume.com",
+ "123rf.com",
+ "12bet.com",
+ "12vpn.com",
+ "12vpn.net",
+ "1337x.to",
+ "138.com",
+ "141hongkong.com",
+ "141jj.com",
+ "141tube.com",
+ "1688.com.au",
+ "173ng.com",
+ "177pic.info",
+ "17t17p.com",
+ "18board.com",
+ "18board.info",
+ "18onlygirls.com",
+ "18p2p.com",
+ "18virginsex.com",
+ "1949er.org",
+ "1984.city",
+ "1984bbs.com",
+ "1984bbs.org",
+ "1991way.com",
+ "1998cdp.org",
+ "1bao.org",
+ "1dumb.com",
+ "1e100.net",
+ "1eew.com",
+ "1mobile.com",
+ "1mobile.tw",
+ "1pondo.tv",
+ "2-hand.info",
+ "2000fun.com",
+ "2008xianzhang.info",
+ "2017.hk",
+ "2021hkcharter.com",
+ "2047.name",
+ "21andy.com",
+ "21join.com",
+ "21pron.com",
+ "21sextury.com",
+ "228.net.tw",
+ "233abc.com",
+ "24hrs.ca",
+ "24smile.org",
+ "25u.com",
+ "2lipstube.com",
+ "2shared.com",
+ "2waky.com",
+ "3-a.net",
+ "30boxes.com",
+ "315lz.com",
+ "32red.com",
+ "36rain.com",
+ "3a5a.com",
+ "3arabtv.com",
+ "3boys2girls.com",
+ "3d-game.com",
+ "3proxy.ru",
+ "3ren.ca",
+ "3tui.net",
+ "404museum.com",
+ "43110.cf",
+ "466453.com",
+ "4bluestones.biz",
+ "4chan.com",
+ "4dq.com",
+ "4everproxy.com",
+ "4irc.com",
+ "4mydomain.com",
+ "4pu.com",
+ "4rbtv.com",
+ "4shared.com",
+ "4sqi.net",
+ "50webs.com",
+ "51.ca",
+ "51jav.org",
+ "51luoben.com",
+ "5278.cc",
+ "5299.tv",
+ "5aimiku.com",
+ "5i01.com",
+ "5isotoi5.org",
+ "5maodang.com",
+ "63i.com",
+ "64museum.org",
+ "64tianwang.com",
+ "64wiki.com",
+ "66.ca",
+ "666kb.com",
+ "6do.news",
+ "6park.com",
+ "6parkbbs.com",
+ "6parker.com",
+ "6parknews.com",
+ "7-zip.org",
+ "7capture.com",
+ "7cow.com",
+ "8-d.com",
+ "85cc.net",
+ "85cc.us",
+ "85st.com",
+ "881903.com",
+ "888.com",
+ "888poker.com",
+ "89-64.org",
+ "8964museum.com",
+ "8news.com.tw",
+ "8z1.net",
+ "9001700.com",
+ "908taiwan.org",
+ "91porn.com",
+ "91vps.club",
+ "92ccav.com",
+ "991.com",
+ "99btgc01.com",
+ "99cn.info",
+ "9bis.com",
+ "9bis.net",
+ "9cache.com",
+ "9gag.com",
+ "9news.com.au",
+ "a-normal-day.com",
+ "aamacau.com",
+ "abc.com",
+ "abc.net.au",
+ "abc.xyz",
+ "abchinese.com",
+ "abclite.net",
+ "abebooks.com",
+ "ablwang.com",
+ "aboluowang.com",
+ "about.google",
+ "aboutgfw.com",
+ "abs.edu",
+ "acast.com",
+ "accim.org",
+ "accountkit.com",
+ "aceros-de-hispania.com",
+ "acevpn.com",
+ "acg18.me",
+ "acgbox.org",
+ "acgkj.com",
+ "acgnx.se",
+ "acmedia365.com",
+ "acmetoy.com",
+ "acnw.com.au",
+ "actfortibet.org",
+ "actimes.com.au",
+ "activpn.com",
+ "aculo.us",
+ "adcex.com",
+ "addictedtocoffee.de",
+ "addyoutube.com",
+ "adelaidebbs.com",
+ "admob.com",
+ "adpl.org.hk",
+ "ads-twitter.com",
+ "adsense.com",
+ "adult-sex-games.com",
+ "adultfriendfinder.com",
+ "adultkeep.net",
+ "advanscene.com",
+ "advertfan.com",
+ "advertisercommunity.com",
+ "ae.org",
+ "aenhancers.com",
+ "aex.com",
+ "af.mil",
+ "afantibbs.com",
+ "afr.com",
+ "afreecatv.com",
+ "agnesb.fr",
+ "agoogleaday.com",
+ "agro.hk",
+ "ai-kan.net",
+ "ai-wen.net",
+ "ai.google",
+ "aiph.net",
+ "airasia.com",
+ "airconsole.com",
+ "aircrack-ng.org",
+ "airvpn.org",
+ "aisex.com",
+ "ait.org.tw",
+ "aiweiwei.com",
+ "aiweiweiblog.com",
+ "ajsands.com",
+ "akademiye.org",
+ "akamai.net",
+ "akamaihd.net",
+ "akamaistream.net",
+ "akamaized.net",
+ "akiba-online.com",
+ "akiba-web.com",
+ "akow.org",
+ "al-islam.com",
+ "al-qimmah.net",
+ "alabout.com",
+ "alanhou.com",
+ "alarab.qa",
+ "alasbarricadas.org",
+ "alexlur.org",
+ "alforattv.net",
+ "alhayat.com",
+ "alicejapan.co.jp",
+ "aliengu.com",
+ "alive.bar",
+ "alkasir.com",
+ "all4mom.org",
+ "allcoin.com",
+ "allconnected.co",
+ "alldrawnsex.com",
+ "allervpn.com",
+ "allfinegirls.com",
+ "allgirlmassage.com",
+ "allgirlsallowed.org",
+ "allgravure.com",
+ "alliance.org.hk",
+ "allinfa.com",
+ "alljackpotscasino.com",
+ "allmovie.com",
+ "allowed.org",
+ "almasdarnews.com",
+ "almostmy.com",
+ "alphaporno.com",
+ "alternate-tools.com",
+ "alternativeto.net",
+ "altrec.com",
+ "alvinalexander.com",
+ "alwaysdata.com",
+ "alwaysdata.net",
+ "alwaysvpn.com",
+ "am730.com.hk",
+ "amazon.co.jp",
+ "amazon.com",
+ "amazonaws.com",
+ "ameblo.jp",
+ "america.gov",
+ "american.edu",
+ "americangreencard.com",
+ "americanunfinished.com",
+ "americorps.gov",
+ "amiblockedornot.com",
+ "amigobbs.net",
+ "amitabhafoundation.us",
+ "amnesty.org",
+ "amnesty.org.hk",
+ "amnesty.tw",
+ "amnestyusa.org",
+ "amnyemachen.org",
+ "amoiist.com",
+ "ampproject.org",
+ "amtb-taipei.org",
+ "anchor.fm",
+ "anchorfree.com",
+ "ancsconf.org",
+ "andfaraway.net",
+ "android-x86.org",
+ "android.com",
+ "androidify.com",
+ "androidplus.co",
+ "androidtv.com",
+ "andygod.com",
+ "angela-merkel.de",
+ "angelfire.com",
+ "angola.org",
+ "angularjs.org",
+ "animecrazy.net",
+ "aniscartujo.com",
+ "annatam.com",
+ "anobii.com",
+ "anontext.com",
+ "anonymitynetwork.com",
+ "anonymizer.com",
+ "anonymouse.org",
+ "anpopo.com",
+ "answering-islam.org",
+ "antd.org",
+ "anthonycalzadilla.com",
+ "anti1984.com",
+ "antichristendom.com",
+ "antiwave.net",
+ "anws.gov.tw",
+ "anyporn.com",
+ "anysex.com",
+ "ao3.org",
+ "aobo.com.au",
+ "aofriend.com",
+ "aofriend.com.au",
+ "aojiao.org",
+ "aol.ca",
+ "aol.co.uk",
+ "aol.com",
+ "aolnews.com",
+ "aomiwang.com",
+ "ap.org",
+ "apartmentratings.com",
+ "apartments.com",
+ "apat1989.org",
+ "apetube.com",
+ "api.ai",
+ "apiary.io",
+ "apigee.com",
+ "apk-dl.com",
+ "apk.support",
+ "apkcombo.com",
+ "apkmirror.com",
+ "apkmonk.com",
+ "apkplz.com",
+ "apkpure.com",
+ "aplusvpn.com",
+ "appbrain.com",
+ "appdownloader.net",
+ "appledaily.com",
+ "appledaily.com.hk",
+ "appledaily.com.tw",
+ "appshopper.com",
+ "appsocks.net",
+ "appspot.com",
+ "appsto.re",
+ "aptoide.com",
+ "archive.fo",
+ "archive.is",
+ "archive.li",
+ "archive.org",
+ "archive.ph",
+ "archive.today",
+ "archiveofourown.com",
+ "archiveofourown.org",
+ "archives.gov",
+ "archives.gov.tw",
+ "arctosia.com",
+ "areca-backup.org",
+ "arena.taipei",
+ "arethusa.su",
+ "arlingtoncemetery.mil",
+ "army.mil",
+ "art4tibet1998.org",
+ "arte.tv",
+ "artofpeacefoundation.org",
+ "artstation.com",
+ "artsy.net",
+ "asacp.org",
+ "asdfg.jp",
+ "asg.to",
+ "asia-gaming.com",
+ "asiaharvest.org",
+ "asianage.com",
+ "asianews.it",
+ "asianfreeforum.com",
+ "asiansexdiary.com",
+ "asianspiss.com",
+ "asianwomensfilm.de",
+ "asiaone.com",
+ "asiatgp.com",
+ "asiatoday.us",
+ "askstudent.com",
+ "askynz.net",
+ "aspi.org.au",
+ "aspistrategist.org.au",
+ "assembla.com",
+ "assimp.org",
+ "astrill.com",
+ "atc.org.au",
+ "atchinese.com",
+ "atdmt.com",
+ "atgfw.org",
+ "athenaeizou.com",
+ "atlanta168.com",
+ "atlaspost.com",
+ "atnext.com",
+ "audionow.com",
+ "authorizeddns.net",
+ "authorizeddns.org",
+ "authorizeddns.us",
+ "autodraw.com",
+ "av-e-body.com",
+ "av.com",
+ "av.movie",
+ "avaaz.org",
+ "avbody.tv",
+ "avcity.tv",
+ "avcool.com",
+ "avdb.in",
+ "avdb.tv",
+ "avfantasy.com",
+ "avg.com",
+ "avgle.com",
+ "avidemux.org",
+ "avmo.pw",
+ "avmoo.com",
+ "avmoo.net",
+ "avmoo.pw",
+ "avoision.com",
+ "avyahoo.com",
+ "axios.com",
+ "axureformac.com",
+ "azerbaycan.tv",
+ "azerimix.com",
+ "azubu.tv",
+ "azurewebsites.net",
+ "b-ok.cc",
+ "b0ne.com",
+ "baby-kingdom.com",
+ "babylonbee.com",
+ "babynet.com.hk",
+ "backchina.com",
+ "backpackers.com.tw",
+ "backtotiananmen.com",
+ "badiucao.com",
+ "badjojo.com",
+ "badoo.com",
+ "baidu.jp",
+ "baijie.org",
+ "bailandaily.com",
+ "baixing.me",
+ "bakgeekhome.tk",
+ "banana-vpn.com",
+ "band.us",
+ "bandcamp.com",
+ "bandwagonhost.com",
+ "bangbrosnetwork.com",
+ "bangchen.net",
+ "bangdream.space",
+ "bangkokpost.com",
+ "bangyoulater.com",
+ "bankmobilevibe.com",
+ "bannedbook.org",
+ "bannednews.org",
+ "banorte.com",
+ "baramangaonline.com",
+ "barenakedislam.com",
+ "barnabu.co.uk",
+ "barton.de",
+ "bastillepost.com",
+ "bayvoice.net",
+ "baywords.com",
+ "bb-chat.tv",
+ "bbc.co.uk",
+ "bbc.com",
+ "bbc.in",
+ "bbcchinese.com",
+ "bbchat.tv",
+ "bbci.co.uk",
+ "bbg.gov",
+ "bbkz.com",
+ "bbnradio.org",
+ "bbs-tw.com",
+ "bbsdigest.com",
+ "bbsfeed.com",
+ "bbsland.com",
+ "bbsmo.com",
+ "bbsone.com",
+ "bbtoystore.com",
+ "bcast.co.nz",
+ "bcc.com.tw",
+ "bcchinese.net",
+ "bcex.ca",
+ "bcmorning.com",
+ "bdsmvideos.net",
+ "beaconevents.com",
+ "bebo.com",
+ "beeg.com",
+ "beevpn.com",
+ "behance.net",
+ "behindkink.com",
+ "beijing1989.com",
+ "beijing2022.art",
+ "beijingspring.com",
+ "beijingzx.org",
+ "belamionline.com",
+ "bell.wiki",
+ "bemywife.cc",
+ "beric.me",
+ "berlinerbericht.de",
+ "berlintwitterwall.com",
+ "berm.co.nz",
+ "bestforchina.org",
+ "bestgore.com",
+ "bestpornstardb.com",
+ "bestvpn.com",
+ "bestvpnanalysis.com",
+ "bestvpnserver.com",
+ "bestvpnservice.com",
+ "bestvpnusa.com",
+ "bet365.com",
+ "betfair.com",
+ "betternet.co",
+ "bettervpn.com",
+ "bettween.com",
+ "betvictor.com",
+ "bewww.net",
+ "beyondfirewall.com",
+ "bfnn.org",
+ "bfsh.hk",
+ "bgvpn.com",
+ "bianlei.com",
+ "biantailajiao.com",
+ "biantailajiao.in",
+ "biblesforamerica.org",
+ "bibox.com",
+ "bic2011.org",
+ "biedian.me",
+ "big.one",
+ "bigfools.com",
+ "bigjapanesesex.com",
+ "bigmoney.biz",
+ "bignews.org",
+ "bigone.com",
+ "bigsound.org",
+ "bild.de",
+ "biliworld.com",
+ "billypan.com",
+ "binance.com",
+ "bing.com",
+ "binux.me",
+ "binwang.me",
+ "bird.so",
+ "bit-z.com",
+ "bit.do",
+ "bit.ly",
+ "bitbay.net",
+ "bitchute.com",
+ "bitcointalk.org",
+ "bitcoinworld.com",
+ "bitfinex.com",
+ "bithumb.com",
+ "bitinka.com.ar",
+ "bitmex.com",
+ "bitshare.com",
+ "bitsnoop.com",
+ "bitterwinter.org",
+ "bitvise.com",
+ "bitz.ai",
+ "bizhat.com",
+ "bjnewlife.org",
+ "bjs.org",
+ "bjzc.org",
+ "bl-doujinsouko.com",
+ "blacklogic.com",
+ "blackvpn.com",
+ "blewpass.com",
+ "blingblingsquad.net",
+ "blinkx.com",
+ "blinw.com",
+ "blip.tv",
+ "blockcast.it",
+ "blockcn.com",
+ "blockedbyhk.com",
+ "blockless.com",
+ "blog.de",
+ "blog.google",
+ "blog.jp",
+ "blogblog.com",
+ "blogcatalog.com",
+ "blogcity.me",
+ "blogdns.org",
+ "blogger.com",
+ "blogimg.jp",
+ "bloglines.com",
+ "bloglovin.com",
+ "blogs.com",
+ "blogspot.com",
+ "blogspot.hk",
+ "blogspot.jp",
+ "blogspot.tw",
+ "blogtd.net",
+ "blogtd.org",
+ "bloodshed.net",
+ "bloomberg.cn",
+ "bloomberg.com",
+ "bloomberg.de",
+ "bloombergview.com",
+ "bloomfortune.com",
+ "blubrry.com",
+ "blueangellive.com",
+ "bmfinn.com",
+ "bnews.co",
+ "bnext.com.tw",
+ "bnn.co",
+ "bnrmetal.com",
+ "boardreader.com",
+ "bod.asia",
+ "bodog88.com",
+ "bolehvpn.net",
+ "bonbonme.com",
+ "bonbonsex.com",
+ "bonfoundation.org",
+ "bongacams.com",
+ "boobstagram.com",
+ "book.com.tw",
+ "bookdepository.com",
+ "bookepub.com",
+ "books.com.tw",
+ "booktopia.com.au",
+ "boomssr.com",
+ "borgenmagazine.com",
+ "bot.nu",
+ "botanwang.com",
+ "bowenpress.com",
+ "box.com",
+ "box.net",
+ "boxpn.com",
+ "boxun.com",
+ "boxun.tv",
+ "boxunblog.com",
+ "boxunclub.com",
+ "boyangu.com",
+ "boyfriendtv.com",
+ "boysfood.com",
+ "boysmaster.com",
+ "br.st",
+ "brainyquote.com",
+ "brandonhutchinson.com",
+ "braumeister.org",
+ "brave.com",
+ "bravotube.net",
+ "brazzers.com",
+ "breached.to",
+ "break.com",
+ "breakgfw.com",
+ "breaking911.com",
+ "breakingtweets.com",
+ "breakwall.net",
+ "briefdream.com",
+ "briian.com",
+ "brill.com",
+ "brizzly.com",
+ "brkmd.com",
+ "broadbook.com",
+ "broadpressinc.com",
+ "brockbbs.com",
+ "brookings.edu",
+ "brucewang.net",
+ "brutaltgp.com",
+ "bt2mag.com",
+ "bt95.com",
+ "btaia.com",
+ "btbtav.com",
+ "btc98.com",
+ "btcbank.bank",
+ "btctrade.im",
+ "btdigg.org",
+ "btku.me",
+ "btku.org",
+ "btspread.com",
+ "btsynckeys.com",
+ "budaedu.org",
+ "buddhanet.com.tw",
+ "buddhistchannel.tv",
+ "buffered.com",
+ "bullguard.com",
+ "bullog.org",
+ "bullogger.com",
+ "bunbunhk.com",
+ "busayari.com",
+ "business-humanrights.org",
+ "business.page",
+ "businessinsider.com",
+ "businessinsider.com.au",
+ "businesstoday.com.tw",
+ "businessweek.com",
+ "busu.org",
+ "busytrade.com",
+ "buugaa.com",
+ "buzzhand.com",
+ "buzzhand.net",
+ "buzzorange.com",
+ "bvpn.com",
+ "bwbx.io",
+ "bwgyhw.com",
+ "bwh1.net",
+ "bwsj.hk",
+ "bx.in.th",
+ "bx.tl",
+ "bybit.com",
+ "bynet.co.il",
+ "bypasscensorship.org",
+ "byrut.org",
+ "c-est-simple.com",
+ "c-span.org",
+ "c-spanvideo.org",
+ "c100tibet.org",
+ "c2cx.com",
+ "cablegatesearch.net",
+ "cachinese.com",
+ "cacnw.com",
+ "cactusvpn.com",
+ "cafepress.com",
+ "cahr.org.tw",
+ "caijinglengyan.com",
+ "calameo.com",
+ "calebelston.com",
+ "calgarychinese.ca",
+ "calgarychinese.com",
+ "calgarychinese.net",
+ "calibre-ebook.com",
+ "caltech.edu",
+ "cam4.com",
+ "cam4.jp",
+ "cam4.sg",
+ "camfrog.com",
+ "campaignforuyghurs.org",
+ "cams.com",
+ "cams.org.sg",
+ "canadameet.com",
+ "canalporno.com",
+ "cantonese.asia",
+ "canyu.org",
+ "cao.im",
+ "caobian.info",
+ "caochangqing.com",
+ "cap.org.hk",
+ "carabinasypistolas.com",
+ "cardinalkungfoundation.org",
+ "careerengine.us",
+ "carfax.com",
+ "cari.com.my",
+ "caribbeancom.com",
+ "carmotorshow.com",
+ "carrd.co",
+ "carryzhou.com",
+ "cartoonmovement.com",
+ "casadeltibetbcn.org",
+ "casatibet.org.mx",
+ "casinobellini.com",
+ "casinoking.com",
+ "casinoriva.com",
+ "castbox.fm",
+ "catch22.net",
+ "catchgod.com",
+ "catfightpayperview.xxx",
+ "catholic.org.hk",
+ "catholic.org.tw",
+ "cathvoice.org.tw",
+ "cato.org",
+ "cattt.com",
+ "cbc.ca",
+ "cbsnews.com",
+ "cbtc.org.hk",
+ "cc.com",
+ "cccat.cc",
+ "cccat.co",
+ "ccdtr.org",
+ "cchere.com",
+ "ccim.org",
+ "cclife.ca",
+ "cclife.org",
+ "cclifefl.org",
+ "ccthere.com",
+ "ccthere.net",
+ "cctmweb.net",
+ "cctongbao.com",
+ "ccue.ca",
+ "ccue.com",
+ "ccvoice.ca",
+ "ccw.org.tw",
+ "cdbook.org",
+ "cdcparty.com",
+ "cdef.org",
+ "cdig.info",
+ "cdjp.org",
+ "cdnews.com.tw",
+ "cdninstagram.com",
+ "cdp1989.org",
+ "cdp1998.org",
+ "cdp2006.org",
+ "cdpeu.org",
+ "cdpusa.org",
+ "cdpweb.org",
+ "cdpwu.org",
+ "cdw.com",
+ "cecc.gov",
+ "cellulo.info",
+ "cenews.eu",
+ "centauro.com.br",
+ "centerforhumanreprod.com",
+ "centralnation.com",
+ "centurys.net",
+ "certificate-transparency.org",
+ "cfhks.org.hk",
+ "cfos.de",
+ "cfr.org",
+ "cftfc.com",
+ "cgdepot.org",
+ "cgst.edu",
+ "change.org",
+ "changeip.name",
+ "changeip.net",
+ "changeip.org",
+ "changp.com",
+ "changsa.net",
+ "channelnewsasia.com",
+ "chaoex.com",
+ "chapm25.com",
+ "chatnook.com",
+ "chaturbate.com",
+ "checkgfw.com",
+ "chengmingmag.com",
+ "chenguangcheng.com",
+ "chenpokong.com",
+ "chenpokong.net",
+ "chenpokongvip.com",
+ "cherrysave.com",
+ "chhongbi.org",
+ "chicagoncmtv.com",
+ "china-mmm.net",
+ "china-review.com.ua",
+ "china-week.com",
+ "china101.com",
+ "china18.org",
+ "china21.com",
+ "china21.org",
+ "china5000.us",
+ "chinaaffairs.org",
+ "chinaaid.me",
+ "chinaaid.net",
+ "chinaaid.org",
+ "chinaaid.us",
+ "chinachange.org",
+ "chinachannel.hk",
+ "chinacitynews.be",
+ "chinacomments.org",
+ "chinadialogue.net",
+ "chinadigitaltimes.net",
+ "chinaelections.org",
+ "chinaeweekly.com",
+ "chinafreepress.org",
+ "chinagate.com",
+ "chinageeks.org",
+ "chinagfw.org",
+ "chinagonet.com",
+ "chinagreenparty.org",
+ "chinahorizon.org",
+ "chinahush.com",
+ "chinainperspective.com",
+ "chinainterimgov.org",
+ "chinalaborwatch.org",
+ "chinalawandpolicy.com",
+ "chinalawtranslate.com",
+ "chinamule.com",
+ "chinamz.org",
+ "chinanewscenter.com",
+ "chinapost.com.tw",
+ "chinapress.com.my",
+ "chinarightsia.org",
+ "chinasmile.net",
+ "chinasocialdemocraticparty.com",
+ "chinasoul.org",
+ "chinasucks.net",
+ "chinatimes.com",
+ "chinatopsex.com",
+ "chinatown.com.au",
+ "chinatweeps.com",
+ "chinaway.org",
+ "chinaworker.info",
+ "chinaxchina.com",
+ "chinayouth.org.hk",
+ "chinayuanmin.org",
+ "chinese-hermit.net",
+ "chinese-leaders.org",
+ "chinese-memorial.org",
+ "chinesedaily.com",
+ "chinesedailynews.com",
+ "chinesedemocracy.com",
+ "chinesegay.org",
+ "chinesen.de",
+ "chinesenews.net.au",
+ "chinesepen.org",
+ "chineseradioseattle.com",
+ "chinesetalks.net",
+ "chineseupress.com",
+ "chingcheong.com",
+ "chinman.net",
+ "chithu.org",
+ "chobit.cc",
+ "chosun.com",
+ "chrdnet.com",
+ "christianfreedom.org",
+ "christianstudy.com",
+ "christiantimes.org.hk",
+ "christusrex.org",
+ "chrlawyers.hk",
+ "chrome.com",
+ "chromecast.com",
+ "chromeenterprise.google",
+ "chromeexperiments.com",
+ "chromercise.com",
+ "chromestatus.com",
+ "chromium.org",
+ "chuang-yen.org",
+ "chubold.com",
+ "chubun.com",
+ "churchinhongkong.org",
+ "chushigangdrug.ch",
+ "cienen.com",
+ "cineastentreff.de",
+ "cipfg.org",
+ "circlethebayfortibet.org",
+ "cirosantilli.com",
+ "citizencn.com",
+ "citizenlab.ca",
+ "citizenlab.org",
+ "citizenscommission.hk",
+ "citizensradio.org",
+ "city365.ca",
+ "city9x.com",
+ "citypopulation.de",
+ "citytalk.tw",
+ "civicparty.hk",
+ "civildisobediencemovement.org",
+ "civilhrfront.org",
+ "civiliangunner.com",
+ "civilmedia.tw",
+ "civisec.org",
+ "cjb.net",
+ "ck101.com",
+ "clarionproject.org",
+ "classicalguitarblog.net",
+ "clb.org.hk",
+ "cleansite.biz",
+ "cleansite.info",
+ "cleansite.us",
+ "clearharmony.net",
+ "clearsurance.com",
+ "clearwisdom.net",
+ "clementine-player.org",
+ "clinica-tibet.ru",
+ "clipfish.de",
+ "cloakpoint.com",
+ "cloudcone.com",
+ "cloudflare-ipfs.com",
+ "cloudfront.net",
+ "club1069.com",
+ "clubhouseapi.com",
+ "clyp.it",
+ "cmcn.org",
+ "cmi.org.tw",
+ "cmoinc.org",
+ "cms.gov",
+ "cmu.edu",
+ "cmule.com",
+ "cmule.org",
+ "cmx.im",
+ "cn-proxy.com",
+ "cn.com",
+ "cn6.eu",
+ "cna.com.tw",
+ "cnabc.com",
+ "cnd.org",
+ "cnet.com",
+ "cnex.org.cn",
+ "cnineu.com",
+ "cnitter.com",
+ "cnn.com",
+ "cnpolitics.org",
+ "cnproxy.com",
+ "cnyes.com",
+ "co.tv",
+ "coat.co.jp",
+ "cobinhood.com",
+ "cochina.co",
+ "cochina.org",
+ "code1984.com",
+ "codeplex.com",
+ "codeshare.io",
+ "codeskulptor.org",
+ "coin2co.in",
+ "coinbene.com",
+ "coinegg.com",
+ "coinex.com",
+ "coingecko.com",
+ "coingi.com",
+ "coinmarketcap.com",
+ "coinrail.co.kr",
+ "cointiger.com",
+ "cointobe.com",
+ "coinut.com",
+ "collateralmurder.com",
+ "collateralmurder.org",
+ "com.google",
+ "com.ru",
+ "com.uk",
+ "comedycentral.com",
+ "comefromchina.com",
+ "comic-mega.me",
+ "comico.tw",
+ "commandarms.com",
+ "commentshk.com",
+ "communistcrimes.org",
+ "communitychoicecu.com",
+ "comparitech.com",
+ "compileheart.com",
+ "compress.to",
+ "compython.net",
+ "conoha.jp",
+ "constitutionalism.solutions",
+ "contactmagazine.net",
+ "convio.net",
+ "coobay.com",
+ "cool18.com",
+ "coolaler.com",
+ "coolder.com",
+ "coolloud.org.tw",
+ "coolncute.com",
+ "coolstuffinc.com",
+ "corumcollege.com",
+ "cos-moe.com",
+ "cosplayjav.pl",
+ "costco.com",
+ "cotweet.com",
+ "counter.social",
+ "coursehero.com",
+ "cpj.org",
+ "cq99.us",
+ "crackle.com",
+ "crazys.cc",
+ "crazyshit.com",
+ "crbug.com",
+ "crchina.org",
+ "crd-net.org",
+ "creaders.net",
+ "creadersnet.com",
+ "creativelab5.com",
+ "crisisresponse.google",
+ "cristyli.com",
+ "crocotube.com",
+ "crossfire.co.kr",
+ "crossthewall.net",
+ "crossvpn.net",
+ "croxyproxy.com",
+ "crrev.com",
+ "crucial.com",
+ "crunchyroll.com",
+ "cryptographyengineering.com",
+ "csdparty.com",
+ "csis.org",
+ "csmonitor.com",
+ "csuchen.de",
+ "csw.org.uk",
+ "ct.org.tw",
+ "ctao.org",
+ "ctfriend.net",
+ "ctitv.com.tw",
+ "ctowc.org",
+ "cts.com.tw",
+ "ctwant.com",
+ "cuhk.edu.hk",
+ "cuhkacs.org",
+ "cuihua.org",
+ "cuiweiping.net",
+ "culture.tw",
+ "cumlouder.com",
+ "curvefish.com",
+ "cusp.hk",
+ "cusu.hk",
+ "cutscenes.net",
+ "cw.com.tw",
+ "cwb.gov.tw",
+ "cyberctm.com",
+ "cyberghostvpn.com",
+ "cynscribe.com",
+ "cytode.us",
+ "cz.cc",
+ "d-fukyu.com",
+ "d0z.net",
+ "d100.net",
+ "d2bay.com",
+ "d2pass.com",
+ "dabr.co.uk",
+ "dabr.eu",
+ "dabr.me",
+ "dabr.mobi",
+ "dadazim.com",
+ "dadi360.com",
+ "dafabet.com",
+ "dafagood.com",
+ "dafahao.com",
+ "dafoh.org",
+ "daftporn.com",
+ "dagelijksestandaard.nl",
+ "daidostup.ru",
+ "dailidaili.com",
+ "dailymail.co.uk",
+ "dailymotion.com",
+ "dailysabah.com",
+ "dailyview.tw",
+ "daiphapinfo.net",
+ "dajiyuan.com",
+ "dajiyuan.de",
+ "dajiyuan.eu",
+ "dalailama-archives.org",
+ "dalailama.com",
+ "dalailama.mn",
+ "dalailama.ru",
+ "dalailama80.org",
+ "dalailamacenter.org",
+ "dalailamafellows.org",
+ "dalailamafilm.com",
+ "dalailamafoundation.org",
+ "dalailamahindi.com",
+ "dalailamainaustralia.org",
+ "dalailamajapanese.com",
+ "dalailamaprotesters.info",
+ "dalailamaquotes.org",
+ "dalailamatrust.org",
+ "dalailamavisit.org.nz",
+ "dalailamaworld.com",
+ "dalianmeng.org",
+ "daliulian.org",
+ "danke4china.net",
+ "daolan.net",
+ "darktech.org",
+ "darktoy.net",
+ "darpa.mil",
+ "darrenliuwei.com",
+ "dastrassi.org",
+ "data-vocabulary.org",
+ "data.gov.tw",
+ "daum.net",
+ "david-kilgour.com",
+ "dawangidc.com",
+ "daxa.cn",
+ "dayabook.com",
+ "daylife.com",
+ "db.tt",
+ "dbc.hk",
+ "dbgjd.com",
+ "dcard.tw",
+ "dcmilitary.com",
+ "ddc.com.tw",
+ "ddhw.info",
+ "ddns.info",
+ "ddns.me.uk",
+ "ddns.mobi",
+ "ddns.ms",
+ "ddns.name",
+ "ddns.net",
+ "ddns.us",
+ "de-sci.org",
+ "deadline.com",
+ "deaftone.com",
+ "debug.com",
+ "deck.ly",
+ "decodet.co",
+ "deepmind.com",
+ "deezer.com",
+ "definebabe.com",
+ "deja.com",
+ "delcamp.net",
+ "delicious.com",
+ "democrats.org",
+ "demosisto.hk",
+ "depositphotos.com",
+ "desc.se",
+ "design.google",
+ "desipro.de",
+ "dessci.com",
+ "destroy-china.jp",
+ "deutsche-welle.de",
+ "deviantart.com",
+ "deviantart.net",
+ "devio.us",
+ "devpn.com",
+ "dfas.mil",
+ "dfn.org",
+ "dharamsalanet.com",
+ "dharmakara.net",
+ "dhcp.biz",
+ "diaoyuislands.org",
+ "difangwenge.org",
+ "digiland.tw",
+ "digisfera.com",
+ "digitalnomadsproject.org",
+ "diigo.com",
+ "dilber.se",
+ "dingchin.com.tw",
+ "dipity.com",
+ "directcreative.com",
+ "discoins.com",
+ "disconnect.me",
+ "discord.com",
+ "discord.gg",
+ "discordapp.com",
+ "discordapp.net",
+ "discuss.com.hk",
+ "discuss4u.com",
+ "dish.com",
+ "disp.cc",
+ "disqus.com",
+ "dit-inc.us",
+ "dizhidizhi.com",
+ "dizhuzhishang.com",
+ "djangosnippets.org",
+ "djorz.com",
+ "dl-laby.jp",
+ "dlive.tv",
+ "dlsite.com",
+ "dlsite.jp",
+ "dlyoutube.com",
+ "dm530.net",
+ "dmc.nico",
+ "dmcdn.net",
+ "dmhy.org",
+ "dmm.co.jp",
+ "dmm.com",
+ "dns-dns.com",
+ "dns-stuff.com",
+ "dns.google",
+ "dns04.com",
+ "dns05.com",
+ "dns1.us",
+ "dns2.us",
+ "dns2go.com",
+ "dnscrypt.org",
+ "dnset.com",
+ "dnsrd.com",
+ "dnssec.net",
+ "dnvod.tv",
+ "doctorvoice.org",
+ "documentingreality.com",
+ "dogfartnetwork.com",
+ "dojin.com",
+ "dok-forum.net",
+ "dolc.de",
+ "dolf.org.hk",
+ "dollf.com",
+ "domain.club.tw",
+ "domains.google",
+ "domaintoday.com.au",
+ "donga.com",
+ "dongtaiwang.com",
+ "dongtaiwang.net",
+ "dongyangjing.com",
+ "donmai.us",
+ "dontfilter.us",
+ "dontmovetochina.com",
+ "dorjeshugden.com",
+ "dotplane.com",
+ "dotsub.com",
+ "dotvpn.com",
+ "doub.io",
+ "doubibackup.com",
+ "doubmirror.cf",
+ "dougscripts.com",
+ "douhokanko.net",
+ "doujincafe.com",
+ "dowei.org",
+ "dowjones.com",
+ "dphk.org",
+ "dpp.org.tw",
+ "dpr.info",
+ "dragonex.io",
+ "dragonsprings.org",
+ "dreamamateurs.com",
+ "drepung.org",
+ "drgan.net",
+ "drmingxia.org",
+ "dropbooks.tv",
+ "dropbox.com",
+ "dropboxapi.com",
+ "dropboxusercontent.com",
+ "drsunacademy.com",
+ "drtuber.com",
+ "dscn.info",
+ "dsmtp.com",
+ "dstk.dk",
+ "dtdns.net",
+ "dtiblog.com",
+ "dtic.mil",
+ "dtwang.org",
+ "duanzhihu.com",
+ "dubox.com",
+ "duck.com",
+ "duckdns.org",
+ "duckduckgo.com",
+ "duckload.com",
+ "duckmylife.com",
+ "duga.jp",
+ "duihua.org",
+ "duihuahrjournal.org",
+ "dumb1.com",
+ "dunyabulteni.net",
+ "duoweitimes.com",
+ "duping.net",
+ "duplicati.com",
+ "dupola.com",
+ "dupola.net",
+ "dushi.ca",
+ "duyaoss.com",
+ "dvdpac.com",
+ "dvorak.org",
+ "dw-world.com",
+ "dw-world.de",
+ "dw.com",
+ "dw.de",
+ "dwheeler.com",
+ "dwnews.com",
+ "dwnews.net",
+ "dxiong.com",
+ "dynamic-dns.net",
+ "dynamicdns.biz",
+ "dynamicdns.co.uk",
+ "dynamicdns.me.uk",
+ "dynamicdns.org.uk",
+ "dynawebinc.com",
+ "dyndns-ip.com",
+ "dyndns-pics.com",
+ "dyndns.org",
+ "dyndns.pro",
+ "dynssl.com",
+ "dynu.com",
+ "dynu.net",
+ "dysfz.cc",
+ "dzze.com",
+ "e-classical.com.tw",
+ "e-gold.com",
+ "e-hentai.org",
+ "e-hentaidb.com",
+ "e-info.org.tw",
+ "e-traderland.net",
+ "e-zone.com.hk",
+ "e123.hk",
+ "earlytibet.com",
+ "earthcam.com",
+ "earthvpn.com",
+ "eastern-ark.com",
+ "easternlightning.org",
+ "eastturkestan.com",
+ "eastturkistan-gov.org",
+ "eastturkistan.net",
+ "eastturkistancc.org",
+ "eastturkistangovernmentinexile.us",
+ "easyca.ca",
+ "easypic.com",
+ "ebc.net.tw",
+ "ebony-beauty.com",
+ "ebookbrowse.com",
+ "ebookee.com",
+ "ebtcbank.com",
+ "ecfa.org.tw",
+ "echainhost.com",
+ "echofon.com",
+ "ecimg.tw",
+ "ecministry.net",
+ "economist.com",
+ "ecstart.com",
+ "edgecastcdn.net",
+ "edgesuite.net",
+ "edicypages.com",
+ "edmontonchina.cn",
+ "edmontonservice.com",
+ "edns.biz",
+ "edoors.com",
+ "edubridge.com",
+ "edupro.org",
+ "eesti.ee",
+ "eevpn.com",
+ "efcc.org.hk",
+ "effers.com",
+ "efksoft.com",
+ "efukt.com",
+ "eic-av.com",
+ "eireinikotaerukai.com",
+ "eisbb.com",
+ "eksisozluk.com",
+ "electionsmeter.com",
+ "elgoog.im",
+ "ellawine.org",
+ "elpais.com",
+ "eltondisney.com",
+ "emaga.com",
+ "emanna.com",
+ "emilylau.org.hk",
+ "emory.edu",
+ "empfil.com",
+ "emule-ed2k.com",
+ "emulefans.com",
+ "emuparadise.me",
+ "enanyang.my",
+ "encrypt.me",
+ "encyclopedia.com",
+ "enewstree.com",
+ "enfal.de",
+ "engadget.com",
+ "engagedaily.org",
+ "englishforeveryone.org",
+ "englishfromengland.co.uk",
+ "englishpen.org",
+ "enlighten.org.tw",
+ "entermap.com",
+ "environment.google",
+ "epa.gov.tw",
+ "epac.to",
+ "episcopalchurch.org",
+ "epochhk.com",
+ "epochtimes-bg.com",
+ "epochtimes-romania.com",
+ "epochtimes.co.il",
+ "epochtimes.co.kr",
+ "epochtimes.com",
+ "epochtimes.cz",
+ "epochtimes.de",
+ "epochtimes.fr",
+ "epochtimes.ie",
+ "epochtimes.it",
+ "epochtimes.jp",
+ "epochtimes.ru",
+ "epochtimes.se",
+ "epochtimestr.com",
+ "epochweek.com",
+ "epochweekly.com",
+ "eporner.com",
+ "equinenow.com",
+ "erabaru.net",
+ "eracom.com.tw",
+ "eraysoft.com.tr",
+ "erepublik.com",
+ "erights.net",
+ "eriversoft.com",
+ "erktv.com",
+ "ernestmandel.org",
+ "erodaizensyu.com",
+ "erodoujinlog.com",
+ "erodoujinworld.com",
+ "eromanga-kingdom.com",
+ "eromangadouzin.com",
+ "eromon.net",
+ "eroprofile.com",
+ "eroticsaloon.net",
+ "eslite.com",
+ "esmtp.biz",
+ "esu.dog",
+ "esu.im",
+ "esurance.com",
+ "etaa.org.au",
+ "etadult.com",
+ "etaiwannews.com",
+ "etherdelta.com",
+ "etherscan.io",
+ "etizer.org",
+ "etokki.com",
+ "etowns.net",
+ "etowns.org",
+ "etsy.com",
+ "ettoday.net",
+ "etvonline.hk",
+ "eu.org",
+ "eucasino.com",
+ "eulam.com",
+ "eurekavpt.com",
+ "euronews.com",
+ "europa.eu",
+ "evozi.com",
+ "evschool.net",
+ "exblog.co.jp",
+ "exblog.jp",
+ "exchristian.hk",
+ "excite.co.jp",
+ "exhentai.org",
+ "exmo.com",
+ "exmormon.org",
+ "expatshield.com",
+ "expecthim.com",
+ "expekt.com",
+ "experts-univers.com",
+ "exploader.net",
+ "expofutures.com",
+ "expressvpn.com",
+ "exrates.me",
+ "extmatrix.com",
+ "extremetube.com",
+ "exx.com",
+ "eyevio.jp",
+ "eyny.com",
+ "ezpc.tk",
+ "ezpeer.com",
+ "ezua.com",
+ "f8.com",
+ "fa.gov.tw",
+ "facebook.br",
+ "facebook.com",
+ "facebook.design",
+ "facebook.hu",
+ "facebook.in",
+ "facebook.net",
+ "facebook.nl",
+ "facebook.se",
+ "facebookmail.com",
+ "facebookquotes4u.com",
+ "faceless.me",
+ "facesofnyfw.com",
+ "facesoftibetanselfimmolators.info",
+ "factpedia.org",
+ "fail.hk",
+ "faith100.org",
+ "faithfuleye.com",
+ "faiththedog.info",
+ "fakku.net",
+ "fallenark.com",
+ "falsefire.com",
+ "falun-co.org",
+ "falun-ny.net",
+ "falunart.org",
+ "falunasia.info",
+ "falunau.org",
+ "falunaz.net",
+ "falundafa-dc.org",
+ "falundafa-florida.org",
+ "falundafa-nc.org",
+ "falundafa-pa.net",
+ "falundafa-sacramento.org",
+ "falundafa.org",
+ "falundafaindia.org",
+ "falundafamuseum.org",
+ "falungong.club",
+ "falungong.de",
+ "falungong.org.uk",
+ "falunhr.org",
+ "faluninfo.de",
+ "faluninfo.net",
+ "falunpilipinas.net",
+ "falunworld.net",
+ "familyfed.org",
+ "famunion.com",
+ "fan-qiang.com",
+ "fandom.com",
+ "fangbinxing.com",
+ "fangeming.com",
+ "fangeqiang.com",
+ "fanglizhi.info",
+ "fangmincn.org",
+ "fangong.org",
+ "fangongheike.com",
+ "fanhaodang.com",
+ "fanhaolou.com",
+ "fanqiang.network",
+ "fanqiang.tk",
+ "fanqiangdang.com",
+ "fanqianghou.com",
+ "fanqiangyakexi.net",
+ "fanqiangzhe.com",
+ "fanswong.com",
+ "fantv.hk",
+ "fanyue.info",
+ "fapdu.com",
+ "faproxy.com",
+ "faqserv.com",
+ "fartit.com",
+ "farwestchina.com",
+ "fastestvpn.com",
+ "fastly.net",
+ "fastpic.ru",
+ "fastssh.com",
+ "faststone.org",
+ "fatbtc.com",
+ "favotter.net",
+ "favstar.fm",
+ "fawanghuihui.org",
+ "faydao.com",
+ "faz.net",
+ "fb.com",
+ "fb.me",
+ "fb.watch",
+ "fbaddins.com",
+ "fbcdn.net",
+ "fbsbx.com",
+ "fbworkmail.com",
+ "fc2.com",
+ "fc2blog.net",
+ "fc2china.com",
+ "fc2cn.com",
+ "fc2web.com",
+ "fda.gov.tw",
+ "fdbox.com",
+ "fdc64.de",
+ "fdc64.org",
+ "fdc89.jp",
+ "feedburner.com",
+ "feeder.co",
+ "feedly.com",
+ "feedx.net",
+ "feelssh.com",
+ "feer.com",
+ "feifeiss.com",
+ "feitian-california.org",
+ "feitianacademy.org",
+ "feixiaohao.com",
+ "feministteacher.com",
+ "fengzhenghu.com",
+ "fengzhenghu.net",
+ "fevernet.com",
+ "ff.im",
+ "fffff.at",
+ "fflick.com",
+ "ffvpn.com",
+ "fgmtv.net",
+ "fgmtv.org",
+ "fhreports.net",
+ "figprayer.com",
+ "fileflyer.com",
+ "fileforum.com",
+ "files2me.com",
+ "fileserve.com",
+ "filesor.com",
+ "fillthesquare.org",
+ "filmingfortibet.org",
+ "filthdump.com",
+ "financetwitter.com",
+ "finchvpn.com",
+ "findmespot.com",
+ "findyoutube.com",
+ "findyoutube.net",
+ "fingerdaily.com",
+ "finler.net",
+ "firearmsworld.net",
+ "firebaseio.com",
+ "firefox.com",
+ "fireofliberty.org",
+ "firetweet.io",
+ "firstfivefollowers.com",
+ "firstpost.com",
+ "firstrade.com",
+ "fizzik.com",
+ "flagsonline.it",
+ "flecheinthepeche.fr",
+ "fleshbot.com",
+ "fleursdeslettres.com",
+ "flgg.us",
+ "flgjustice.org",
+ "flickr.com",
+ "flickrhivemind.net",
+ "flickriver.com",
+ "fling.com",
+ "flipboard.com",
+ "flipkart.com",
+ "flitto.com",
+ "flnet.org",
+ "flog.tw",
+ "flurry.com",
+ "flyvpn.com",
+ "flyzy2005.com",
+ "fmnnow.com",
+ "fnac.be",
+ "fnac.com",
+ "fochk.org",
+ "focustaiwan.tw",
+ "focusvpn.com",
+ "fofg-europe.net",
+ "fofg.org",
+ "fofldfradio.org",
+ "foolsmountain.com",
+ "fooooo.com",
+ "foreignaffairs.com",
+ "foreignpolicy.com",
+ "forum4hk.com",
+ "forums-free.com",
+ "fotile.me",
+ "fourthinternational.org",
+ "foxbusiness.com",
+ "foxdie.us",
+ "foxgay.com",
+ "foxsub.com",
+ "foxtang.com",
+ "fpmt-osel.org",
+ "fpmt.org",
+ "fpmt.tw",
+ "fpmtmexico.org",
+ "fqok.org",
+ "fqrouter.com",
+ "franklc.com",
+ "freakshare.com",
+ "free-gate.org",
+ "free-hada-now.org",
+ "free-proxy.cz",
+ "free-ss.site",
+ "free-ssh.com",
+ "free.fr",
+ "free4u.com.ar",
+ "freealim.com",
+ "freebeacon.com",
+ "freebearblog.org",
+ "freebrowser.org",
+ "freechal.com",
+ "freechina.net",
+ "freechina.news",
+ "freechinaforum.org",
+ "freechinaweibo.com",
+ "freeddns.com",
+ "freeddns.org",
+ "freedomchina.info",
+ "freedomcollection.org",
+ "freedomhouse.org",
+ "freedomsherald.org",
+ "freeforums.org",
+ "freefq.com",
+ "freefuckvids.com",
+ "freegao.com",
+ "freehongkong.org",
+ "freeilhamtohti.org",
+ "freekazakhs.org",
+ "freekwonpyong.org",
+ "freelotto.com",
+ "freeman2.com",
+ "freemoren.com",
+ "freemorenews.com",
+ "freemuse.org",
+ "freenet-china.org",
+ "freenetproject.org",
+ "freenewscn.com",
+ "freeones.com",
+ "freeopenvpn.com",
+ "freeoz.org",
+ "freerk.com",
+ "freessh.us",
+ "freetcp.com",
+ "freetibet.net",
+ "freetibet.org",
+ "freetibetanheroes.org",
+ "freetribe.me",
+ "freeviewmovies.com",
+ "freevpn.me",
+ "freevpn.nl",
+ "freewallpaper4.me",
+ "freewebs.com",
+ "freewechat.com",
+ "freeweibo.com",
+ "freewww.biz",
+ "freewww.info",
+ "freexinwen.com",
+ "freeyellow.com",
+ "freeyoutubeproxy.net",
+ "frienddy.com",
+ "friendfeed-media.com",
+ "friendfeed.com",
+ "friendfinder.com",
+ "friends-of-tibet.org",
+ "friendsoftibet.org",
+ "fring.com",
+ "fringenetwork.com",
+ "from-pr.com",
+ "from-sd.com",
+ "fromchinatousa.net",
+ "frommel.net",
+ "frontlinedefenders.org",
+ "frootvpn.com",
+ "fscked.org",
+ "fsurf.com",
+ "ftchinese.com",
+ "ftp1.biz",
+ "ftpserver.biz",
+ "ftv.com.tw",
+ "ftvnews.com.tw",
+ "ftx.com",
+ "fucd.com",
+ "fuckcnnic.net",
+ "fuckgfw.org",
+ "fuckgfw233.org",
+ "fulione.com",
+ "fullerconsideration.com",
+ "fulue.com",
+ "funf.tw",
+ "funkyimg.com",
+ "funp.com",
+ "fuq.com",
+ "furbo.org",
+ "furhhdl.org",
+ "furinkan.com",
+ "furl.net",
+ "futurechinaforum.org",
+ "futuremessage.org",
+ "fux.com",
+ "fuyin.net",
+ "fuyindiantai.org",
+ "fuyu.org.tw",
+ "fw.cm",
+ "fxcm-chinese.com",
+ "fxnetworks.com",
+ "fzh999.com",
+ "fzh999.net",
+ "fzlm.com",
+ "g-area.org",
+ "g-queen.com",
+ "g.co",
+ "g0v.social",
+ "g6hentai.com",
+ "gab.com",
+ "gabocorp.com",
+ "gaeproxy.com",
+ "gaforum.org",
+ "gagaoolala.com",
+ "galaxymacau.com",
+ "galenwu.com",
+ "galstars.net",
+ "game735.com",
+ "gamebase.com.tw",
+ "gamejolt.com",
+ "gamer.com.tw",
+ "gamerp.jp",
+ "gamez.com.tw",
+ "gamousa.com",
+ "ganges.com",
+ "ganjingworld.com",
+ "gaoming.net",
+ "gaopi.net",
+ "gaozhisheng.net",
+ "gaozhisheng.org",
+ "gardennetworks.com",
+ "gardennetworks.org",
+ "gartlive.com",
+ "gate-project.com",
+ "gate.io",
+ "gatecoin.com",
+ "gather.com",
+ "gatherproxy.com",
+ "gati.org.tw",
+ "gaybubble.com",
+ "gaycn.net",
+ "gayhub.com",
+ "gaymap.cc",
+ "gaymenring.com",
+ "gaytube.com",
+ "gaywatch.com",
+ "gazotube.com",
+ "gcc.org.hk",
+ "gclooney.com",
+ "gclubs.com",
+ "gcmasia.com",
+ "gcpnews.com",
+ "gcr.io",
+ "gdbt.net",
+ "gdzf.org",
+ "geek-art.net",
+ "geekerhome.com",
+ "geekheart.info",
+ "gekikame.com",
+ "gelbooru.com",
+ "genius.com",
+ "geocities.co.jp",
+ "geocities.com",
+ "geocities.jp",
+ "geph.io",
+ "gerefoundation.org",
+ "get.app",
+ "get.dev",
+ "get.how",
+ "get.page",
+ "getastrill.com",
+ "getchu.com",
+ "getcloak.com",
+ "getfoxyproxy.org",
+ "getfreedur.com",
+ "getgom.com",
+ "geti2p.net",
+ "getiton.com",
+ "getjetso.com",
+ "getlantern.org",
+ "getmalus.com",
+ "getmdl.io",
+ "getoutline.org",
+ "getsocialscope.com",
+ "getsync.com",
+ "gettr.com",
+ "gettrials.com",
+ "gettyimages.com",
+ "getuploader.com",
+ "gfbv.de",
+ "gfgold.com.hk",
+ "gfsale.com",
+ "gfw.org.ua",
+ "gfw.press",
+ "gfw.report",
+ "ggpht.com",
+ "ggssl.com",
+ "ghidra-sre.org",
+ "ghostpath.com",
+ "ghut.org",
+ "giantessnight.com",
+ "gifree.com",
+ "giga-web.jp",
+ "gigacircle.com",
+ "giganews.com",
+ "gigporno.ru",
+ "girlbanker.com",
+ "git.io",
+ "gitbooks.io",
+ "githack.com",
+ "github.blog",
+ "github.com",
+ "github.io",
+ "githubassets.com",
+ "githubusercontent.com",
+ "gizlen.net",
+ "gjczz.com",
+ "glass8.eu",
+ "globaljihad.net",
+ "globalmediaoutreach.com",
+ "globalmuseumoncommunism.org",
+ "globalrescue.net",
+ "globaltm.org",
+ "globalvoices.org",
+ "globalvoicesonline.org",
+ "globalvpn.net",
+ "glock.com",
+ "gloryhole.com",
+ "glorystar.me",
+ "gluckman.com",
+ "glype.com",
+ "gmail.com",
+ "gmgard.com",
+ "gmhz.org",
+ "gmiddle.com",
+ "gmiddle.net",
+ "gmll.org",
+ "gmodules.com",
+ "gmx.net",
+ "gnci.org.hk",
+ "gnews.org",
+ "go-pki.com",
+ "go141.com",
+ "goagent.biz",
+ "goagentplus.com",
+ "gobet.cc",
+ "godfootsteps.org",
+ "godns.work",
+ "godoc.org",
+ "godsdirectcontact.co.uk",
+ "godsdirectcontact.org",
+ "godsdirectcontact.org.tw",
+ "godsimmediatecontact.com",
+ "gofundme.com",
+ "gogotunnel.com",
+ "gohappy.com.tw",
+ "gokbayrak.com",
+ "golang.org",
+ "goldbet.com",
+ "goldbetsports.com",
+ "golden-ages.org",
+ "goldeneyevault.com",
+ "goldenfrog.com",
+ "goldjizz.com",
+ "goldstep.net",
+ "goldwave.com",
+ "gongm.in",
+ "gongmeng.info",
+ "gongminliliang.com",
+ "gongwt.com",
+ "goo.gl",
+ "goo.gle",
+ "goo.ne.jp",
+ "gooday.xyz",
+ "gooddns.info",
+ "goodhope.school",
+ "goodreaders.com",
+ "goodreads.com",
+ "goodtv.com.tw",
+ "goodtv.tv",
+ "goofind.com",
+ "google.ac",
+ "google.ad",
+ "google.ae",
+ "google.af",
+ "google.ai",
+ "google.al",
+ "google.am",
+ "google.as",
+ "google.at",
+ "google.az",
+ "google.ba",
+ "google.be",
+ "google.bf",
+ "google.bg",
+ "google.bi",
+ "google.bj",
+ "google.bs",
+ "google.bt",
+ "google.by",
+ "google.ca",
+ "google.cat",
+ "google.cd",
+ "google.cf",
+ "google.cg",
+ "google.ch",
+ "google.ci",
+ "google.cl",
+ "google.cm",
+ "google.cn",
+ "google.co.ao",
+ "google.co.bw",
+ "google.co.ck",
+ "google.co.cr",
+ "google.co.id",
+ "google.co.il",
+ "google.co.in",
+ "google.co.jp",
+ "google.co.ke",
+ "google.co.kr",
+ "google.co.ls",
+ "google.co.ma",
+ "google.co.mz",
+ "google.co.nz",
+ "google.co.th",
+ "google.co.tz",
+ "google.co.ug",
+ "google.co.uk",
+ "google.co.uz",
+ "google.co.ve",
+ "google.co.vi",
+ "google.co.za",
+ "google.co.zm",
+ "google.co.zw",
+ "google.com",
+ "google.com.af",
+ "google.com.ag",
+ "google.com.ai",
+ "google.com.ar",
+ "google.com.au",
+ "google.com.bd",
+ "google.com.bh",
+ "google.com.bn",
+ "google.com.bo",
+ "google.com.br",
+ "google.com.bz",
+ "google.com.co",
+ "google.com.cu",
+ "google.com.cy",
+ "google.com.do",
+ "google.com.ec",
+ "google.com.eg",
+ "google.com.et",
+ "google.com.fj",
+ "google.com.gh",
+ "google.com.gi",
+ "google.com.gt",
+ "google.com.hk",
+ "google.com.jm",
+ "google.com.kh",
+ "google.com.kw",
+ "google.com.lb",
+ "google.com.ly",
+ "google.com.mm",
+ "google.com.mt",
+ "google.com.mx",
+ "google.com.my",
+ "google.com.na",
+ "google.com.nf",
+ "google.com.ng",
+ "google.com.ni",
+ "google.com.np",
+ "google.com.om",
+ "google.com.pa",
+ "google.com.pe",
+ "google.com.pg",
+ "google.com.ph",
+ "google.com.pk",
+ "google.com.pr",
+ "google.com.py",
+ "google.com.qa",
+ "google.com.sa",
+ "google.com.sb",
+ "google.com.sg",
+ "google.com.sl",
+ "google.com.sv",
+ "google.com.tj",
+ "google.com.tr",
+ "google.com.tw",
+ "google.com.ua",
+ "google.com.uy",
+ "google.com.vc",
+ "google.com.vn",
+ "google.cv",
+ "google.cz",
+ "google.de",
+ "google.dev",
+ "google.dj",
+ "google.dk",
+ "google.dm",
+ "google.dz",
+ "google.ee",
+ "google.es",
+ "google.eu",
+ "google.fi",
+ "google.fm",
+ "google.fr",
+ "google.ga",
+ "google.ge",
+ "google.gg",
+ "google.gl",
+ "google.gm",
+ "google.gp",
+ "google.gr",
+ "google.gy",
+ "google.hk",
+ "google.hn",
+ "google.hr",
+ "google.ht",
+ "google.hu",
+ "google.ie",
+ "google.im",
+ "google.iq",
+ "google.is",
+ "google.it",
+ "google.it.ao",
+ "google.je",
+ "google.jo",
+ "google.kg",
+ "google.ki",
+ "google.kz",
+ "google.la",
+ "google.li",
+ "google.lk",
+ "google.lt",
+ "google.lu",
+ "google.lv",
+ "google.md",
+ "google.me",
+ "google.mg",
+ "google.mk",
+ "google.ml",
+ "google.mn",
+ "google.ms",
+ "google.mu",
+ "google.mv",
+ "google.mw",
+ "google.mx",
+ "google.ne",
+ "google.nl",
+ "google.no",
+ "google.nr",
+ "google.nu",
+ "google.org",
+ "google.pl",
+ "google.pn",
+ "google.ps",
+ "google.pt",
+ "google.ro",
+ "google.rs",
+ "google.ru",
+ "google.rw",
+ "google.sc",
+ "google.se",
+ "google.sh",
+ "google.si",
+ "google.sk",
+ "google.sm",
+ "google.sn",
+ "google.so",
+ "google.sr",
+ "google.st",
+ "google.td",
+ "google.tg",
+ "google.tk",
+ "google.tl",
+ "google.tm",
+ "google.tn",
+ "google.to",
+ "google.tt",
+ "google.us",
+ "google.vg",
+ "google.vn",
+ "google.vu",
+ "google.ws",
+ "googleapis.cn",
+ "googleapis.com",
+ "googleapps.com",
+ "googlearth.com",
+ "googleartproject.com",
+ "googleblog.com",
+ "googlebot.com",
+ "googlechinawebmaster.com",
+ "googlecode.com",
+ "googlecommerce.com",
+ "googledomains.com",
+ "googledrive.com",
+ "googleearth.com",
+ "googlefiber.net",
+ "googlegroups.com",
+ "googlehosted.com",
+ "googleideas.com",
+ "googleinsidesearch.com",
+ "googlelabs.com",
+ "googlemail.com",
+ "googlemashups.com",
+ "googlepagecreator.com",
+ "googleplay.com",
+ "googleplus.com",
+ "googlesile.com",
+ "googlesource.com",
+ "googleusercontent.com",
+ "googlevideo.com",
+ "googleweblight.com",
+ "googlezip.net",
+ "gopetition.com",
+ "goproxing.net",
+ "goreforum.com",
+ "goregrish.com",
+ "gospelherald.com",
+ "got-game.org",
+ "gotdns.ch",
+ "gotgeeks.com",
+ "gotrusted.com",
+ "gotw.ca",
+ "gov.taipei",
+ "gr8domain.biz",
+ "gr8name.biz",
+ "gradconnection.com",
+ "grammaly.com",
+ "grandtrial.org",
+ "grangorz.org",
+ "graphis.ne.jp",
+ "graphql.org",
+ "gravatar.com",
+ "greasespot.net",
+ "great-firewall.com",
+ "great-roc.org",
+ "greatfire.org",
+ "greatfirewall.biz",
+ "greatfirewallofchina.net",
+ "greatfirewallofchina.org",
+ "greatroc.org",
+ "greatroc.tw",
+ "greatzhonghua.org",
+ "greenfieldbookstore.com.hk",
+ "greenparty.org.tw",
+ "greenpeace.com.tw",
+ "greenpeace.org",
+ "greenreadings.com",
+ "greenvpn.net",
+ "greenvpn.org",
+ "grotty-monday.com",
+ "grow.google",
+ "gs-discuss.com",
+ "gsearch.media",
+ "gstatic.com",
+ "gtricks.com",
+ "gts-vpn.com",
+ "gtv.org",
+ "gtv1.org",
+ "gu-chu-sum.org",
+ "guaguass.com",
+ "guaguass.org",
+ "guancha.org",
+ "guaneryu.com",
+ "guangming.com.my",
+ "guangnianvpn.com",
+ "guardster.com",
+ "guishan.org",
+ "gumroad.com",
+ "gun-world.net",
+ "gunsamerica.com",
+ "gunsandammo.com",
+ "guo.media",
+ "guruonline.hk",
+ "gutteruncensored.com",
+ "gvlib.com",
+ "gvm.com.tw",
+ "gvt0.com",
+ "gvt1.com",
+ "gvt3.com",
+ "gwins.org",
+ "gwtproject.org",
+ "gyalwarinpoche.com",
+ "gyatsostudio.com",
+ "gzm.tv",
+ "gzone-anime.info",
+ "h-china.org",
+ "h-moe.com",
+ "h1n1china.org",
+ "h528.com",
+ "h5dm.com",
+ "h5galgame.me",
+ "hacg.club",
+ "hacg.in",
+ "hacg.li",
+ "hacg.me",
+ "hacg.red",
+ "hacken.cc",
+ "hacker.org",
+ "hackmd.io",
+ "hackthatphone.net",
+ "hahlo.com",
+ "hakkatv.org.tw",
+ "handcraftedsoftware.org",
+ "hanime.tv",
+ "hanminzu.org",
+ "hanunyi.com",
+ "hao.news",
+ "hao123.com",
+ "hao123img.com",
+ "happy-vpn.com",
+ "haproxy.org",
+ "hardsextube.com",
+ "harunyahya.com",
+ "hasi.wang",
+ "hautelook.com",
+ "hautelookcdn.com",
+ "have8.com",
+ "hbg.com",
+ "hbo.com",
+ "hclips.com",
+ "hdlt.me",
+ "hdtvb.net",
+ "hdzog.com",
+ "he.net",
+ "heartyit.com",
+ "heavy-r.com",
+ "hec.su",
+ "hecaitou.net",
+ "hechaji.com",
+ "heeact.edu.tw",
+ "hegre-art.com",
+ "helixstudios.net",
+ "helloandroid.com",
+ "helloqueer.com",
+ "helloss.pw",
+ "hellotxt.com",
+ "hellouk.org",
+ "helpeachpeople.com",
+ "helplinfen.com",
+ "helpster.de",
+ "helpuyghursnow.org",
+ "helpzhuling.org",
+ "hentai.to",
+ "hentaitube.tv",
+ "hentaivideoworld.com",
+ "heqinglian.net",
+ "here.com",
+ "heritage.org",
+ "heroku.com",
+ "heungkongdiscuss.com",
+ "hexieshe.com",
+ "hexieshe.xyz",
+ "hexxeh.net",
+ "heyuedi.com",
+ "heywire.com",
+ "heyzo.com",
+ "hgseav.com",
+ "hhdcb3office.org",
+ "hhthesakyatrizin.org",
+ "hi-on.org.tw",
+ "hidden-advent.org",
+ "hide.me",
+ "hidecloud.com",
+ "hidein.net",
+ "hideipvpn.com",
+ "hideman.net",
+ "hideme.nl",
+ "hidemy.name",
+ "hidemyass.com",
+ "hidemycomp.com",
+ "higfw.com",
+ "highpeakspureearth.com",
+ "highrockmedia.com",
+ "hightail.com",
+ "hihiforum.com",
+ "hihistory.net",
+ "hiitch.com",
+ "hikinggfw.org",
+ "hilive.tv",
+ "himalayan-foundation.org",
+ "himalayanglacier.com",
+ "himemix.com",
+ "himemix.net",
+ "hinet.net",
+ "hitbtc.com",
+ "hitomi.la",
+ "hiwifi.com",
+ "hizb-ut-tahrir.info",
+ "hizb-ut-tahrir.org",
+ "hizbuttahrir.org",
+ "hjclub.info",
+ "hk-pub.com",
+ "hk01.com",
+ "hk32168.com",
+ "hkacg.com",
+ "hkacg.net",
+ "hkatvnews.com",
+ "hkbc.net",
+ "hkbf.org",
+ "hkbookcity.com",
+ "hkchronicles.com",
+ "hkchurch.org",
+ "hkci.org.hk",
+ "hkcmi.edu",
+ "hkcnews.com",
+ "hkcoc.com",
+ "hkctu.org.hk",
+ "hkdailynews.com.hk",
+ "hkday.net",
+ "hkdc.us",
+ "hkdf.org",
+ "hkej.com",
+ "hkepc.com",
+ "hket.com",
+ "hkfaa.com",
+ "hkfreezone.com",
+ "hkfront.org",
+ "hkgalden.com",
+ "hkgolden.com",
+ "hkgpao.com",
+ "hkgreenradio.org",
+ "hkheadline.com",
+ "hkhkhk.com",
+ "hkhrc.org.hk",
+ "hkhrm.org.hk",
+ "hkip.org.uk",
+ "hkja.org.hk",
+ "hkjc.com",
+ "hkjp.org",
+ "hklft.com",
+ "hklts.org.hk",
+ "hkmap.live",
+ "hkopentv.com",
+ "hkpeanut.com",
+ "hkptu.org",
+ "hkreporter.com",
+ "hku.hk",
+ "hkusu.net",
+ "hkvwet.com",
+ "hkwcc.org.hk",
+ "hkzone.org",
+ "hmoegirl.com",
+ "hmonghot.com",
+ "hmv.co.jp",
+ "hmvdigital.ca",
+ "hmvdigital.com",
+ "hnjhj.com",
+ "hnntube.com",
+ "hola.com",
+ "hola.org",
+ "holymountaincn.com",
+ "holyspiritspeaks.org",
+ "homedepot.com",
+ "homeip.net",
+ "homeperversion.com",
+ "homeservershow.com",
+ "honeynet.org",
+ "hongkongfp.com",
+ "hongmeimei.com",
+ "hongzhi.li",
+ "honven.xyz",
+ "hootsuite.com",
+ "hoover.org",
+ "hoovers.com",
+ "hopedialogue.org",
+ "hopto.org",
+ "hornygamer.com",
+ "hornytrip.com",
+ "horrorporn.com",
+ "hotair.com",
+ "hotav.tv",
+ "hotels.cn",
+ "hotfrog.com.tw",
+ "hotgoo.com",
+ "hotpornshow.com",
+ "hotpot.hk",
+ "hotshame.com",
+ "hotspotshield.com",
+ "hottg.com",
+ "hotvpn.com",
+ "hougaige.com",
+ "howtoforge.com",
+ "hoxx.com",
+ "hpa.gov.tw",
+ "hqcdp.org",
+ "hqjapanesesex.com",
+ "hqmovies.com",
+ "hrcchina.org",
+ "hrcir.com",
+ "hrea.org",
+ "hrichina.org",
+ "hrtsea.com",
+ "hrw.org",
+ "hrweb.org",
+ "hsjp.net",
+ "hsselite.com",
+ "hst.net.tw",
+ "hstern.net",
+ "hstt.net",
+ "ht.ly",
+ "htkou.net",
+ "htl.li",
+ "html5rocks.com",
+ "https443.net",
+ "https443.org",
+ "hua-yue.net",
+ "huaglad.com",
+ "huanghuagang.org",
+ "huangyiyu.com",
+ "huaren.us",
+ "huaren4us.com",
+ "huashangnews.com",
+ "huasing.org",
+ "huaxia-news.com",
+ "huaxiabao.org",
+ "huaxin.ph",
+ "huayuworld.org",
+ "hudatoriq.web.id",
+ "hudson.org",
+ "huffingtonpost.com",
+ "hugoroy.eu",
+ "huhaitai.com",
+ "huhamhire.com",
+ "huhangfei.com",
+ "huiyi.in",
+ "hulkshare.com",
+ "hulu.com",
+ "huluim.com",
+ "hung-ya.com",
+ "hungerstrikeforaids.org",
+ "huobi.co",
+ "huobi.com",
+ "huobi.me",
+ "huobi.pro",
+ "huobi.sc",
+ "huobipro.com",
+ "huping.net",
+ "hurgokbayrak.com",
+ "hurriyet.com.tr",
+ "hustler.com",
+ "hustlercash.com",
+ "hut2.ru",
+ "hutianyi.net",
+ "hutong9.net",
+ "huyandex.com",
+ "hwadzan.tw",
+ "hwayue.org.tw",
+ "hwinfo.com",
+ "hxwk.org",
+ "hxwq.org",
+ "hybrid-analysis.com",
+ "hyperrate.com",
+ "hyread.com.tw",
+ "i-cable.com",
+ "i-part.com.tw",
+ "i-scmp.com",
+ "i1.hk",
+ "i2p2.de",
+ "i2runner.com",
+ "i818hk.com",
+ "iam.soy",
+ "iamtopone.com",
+ "iask.bz",
+ "iask.ca",
+ "iav19.com",
+ "ibiblio.org",
+ "ibit.am",
+ "iblist.com",
+ "iblogserv-f.net",
+ "ibros.org",
+ "ibtimes.com",
+ "ibvpn.com",
+ "icams.com",
+ "icerocket.com",
+ "icij.org",
+ "icl-fi.org",
+ "icoco.com",
+ "iconfactory.net",
+ "iconpaper.org",
+ "icu-project.org",
+ "idaiwan.com",
+ "idemocracy.asia",
+ "identi.ca",
+ "idiomconnection.com",
+ "idlcoyote.com",
+ "idouga.com",
+ "idreamx.com",
+ "idsam.com",
+ "ieasy5.com",
+ "ied2k.net",
+ "ienergy1.com",
+ "iepl.us",
+ "ifanqiang.com",
+ "ifcss.org",
+ "ifjc.org",
+ "ifreewares.com",
+ "ift.tt",
+ "igcd.net",
+ "igfw.net",
+ "igfw.tech",
+ "igmg.de",
+ "ignitedetroit.net",
+ "igoogle.com",
+ "igotmail.com.tw",
+ "igvita.com",
+ "ihakka.net",
+ "ihao.org",
+ "iicns.com",
+ "ikstar.com",
+ "ikwb.com",
+ "ilbe.com",
+ "ilhamtohtiinstitute.org",
+ "illusionfactory.com",
+ "ilove80.be",
+ "ilovelongtoes.com",
+ "im.tv",
+ "im88.tw",
+ "imageab.com",
+ "imagefap.com",
+ "imageflea.com",
+ "images-gaytube.com",
+ "imageshack.us",
+ "imagevenue.com",
+ "imagezilla.net",
+ "imb.org",
+ "imdb.com",
+ "img.ly",
+ "imgchili.net",
+ "imgmega.com",
+ "imgur.com",
+ "imkev.com",
+ "imlive.com",
+ "immigration.gov.tw",
+ "immoral.jp",
+ "impact.org.au",
+ "impp.mn",
+ "in-disguise.com",
+ "in.com",
+ "in99.org",
+ "incapdns.net",
+ "incloak.com",
+ "incredibox.fr",
+ "independent.co.uk",
+ "indiablooms.com",
+ "indianarrative.com",
+ "indiandefensenews.in",
+ "indiatimes.com",
+ "indiemerch.com",
+ "info-graf.fr",
+ "informer.com",
+ "initiativesforchina.org",
+ "inkui.com",
+ "inmediahk.net",
+ "innermongolia.org",
+ "inoreader.com",
+ "inote.tw",
+ "insecam.org",
+ "inside.com.tw",
+ "insidevoa.com",
+ "instagram.com",
+ "instanthq.com",
+ "institut-tibetain.org",
+ "internet.org",
+ "internetdefenseleague.org",
+ "internetfreedom.org",
+ "internetpopculture.com",
+ "inthenameofconfuciusmovie.com",
+ "inxian.com",
+ "iownyour.biz",
+ "iownyour.org",
+ "ipalter.com",
+ "ipfire.org",
+ "ipfs.io",
+ "iphone4hongkong.com",
+ "iphonehacks.com",
+ "iphonetaiwan.org",
+ "iphonix.fr",
+ "ipicture.ru",
+ "ipjetable.net",
+ "ipobar.com",
+ "ipoock.com",
+ "iportal.me",
+ "ippotv.com",
+ "ipredator.se",
+ "iptv.com.tw",
+ "iptvbin.com",
+ "ipvanish.com",
+ "iqiyi.com",
+ "iredmail.org",
+ "irib.ir",
+ "ironpython.net",
+ "ironsocket.com",
+ "is-a-hunter.com",
+ "is.gd",
+ "isaacmao.com",
+ "isasecret.com",
+ "isgreat.org",
+ "islahhaber.net",
+ "islam.org.hk",
+ "islamawareness.net",
+ "islamhouse.com",
+ "islamicity.com",
+ "islamicpluralism.org",
+ "islamtoday.net",
+ "ismaelan.com",
+ "ismalltits.com",
+ "ismprofessional.net",
+ "isohunt.com",
+ "israbox.com",
+ "issuu.com",
+ "istars.co.nz",
+ "istarshine.com",
+ "istef.info",
+ "istiqlalhewer.com",
+ "istockphoto.com",
+ "isunaffairs.com",
+ "isuntv.com",
+ "isupportuyghurs.org",
+ "itaboo.info",
+ "itaiwan.gov.tw",
+ "italiatibet.org",
+ "itasoftware.com",
+ "itemdb.com",
+ "ithome.com.tw",
+ "itsaol.com",
+ "itshidden.com",
+ "itsky.it",
+ "itweet.net",
+ "iu45.com",
+ "iuhrdf.org",
+ "iuksky.com",
+ "ivacy.com",
+ "iverycd.com",
+ "ivpn.net",
+ "ixquick.com",
+ "ixxx.com",
+ "iyouport.com",
+ "iyouport.org",
+ "izaobao.us",
+ "izihost.org",
+ "izles.net",
+ "izlesem.org",
+ "j.mp",
+ "jable.tv",
+ "jackjia.com",
+ "jamaat.org",
+ "jamestown.org",
+ "jamyangnorbu.com",
+ "jandyx.com",
+ "janwongphoto.com",
+ "japan-whores.com",
+ "japantimes.co.jp",
+ "jav.com",
+ "jav101.com",
+ "jav2be.com",
+ "jav68.tv",
+ "javakiba.org",
+ "javbus.com",
+ "javfor.me",
+ "javhd.com",
+ "javhip.com",
+ "javhub.net",
+ "javhuge.com",
+ "javlibrary.com",
+ "javmobile.net",
+ "javmoo.com",
+ "javmoo.xyz",
+ "javseen.com",
+ "javtag.com",
+ "javzoo.com",
+ "jbtalks.cc",
+ "jbtalks.com",
+ "jbtalks.my",
+ "jcpenney.com",
+ "jdwsy.com",
+ "jeanyim.com",
+ "jetos.com",
+ "jex.com",
+ "jfqu36.club",
+ "jfqu37.xyz",
+ "jgoodies.com",
+ "jiangweiping.com",
+ "jiaoyou8.com",
+ "jichangtj.com",
+ "jiehua.cz",
+ "jiepang.com",
+ "jieshibaobao.com",
+ "jigglegifs.com",
+ "jigong1024.com",
+ "jigsy.com",
+ "jihadology.net",
+ "jiji.com",
+ "jims.net",
+ "jinbushe.org",
+ "jingpin.org",
+ "jingsim.org",
+ "jinhai.de",
+ "jinpianwang.com",
+ "jinroukong.com",
+ "jintian.net",
+ "jinx.com",
+ "jiruan.net",
+ "jitouch.com",
+ "jizzthis.com",
+ "jjgirls.com",
+ "jkb.cc",
+ "jkforum.net",
+ "jkub.com",
+ "jma.go.jp",
+ "jmscult.com",
+ "joachims.org",
+ "jobso.tv",
+ "joinbbs.net",
+ "joinclubhouse.com",
+ "joinmastodon.org",
+ "joins.com",
+ "jornaldacidadeonline.com.br",
+ "journalchretien.net",
+ "journalofdemocracy.org",
+ "joymiihub.com",
+ "joyourself.com",
+ "jp.net",
+ "jpopforum.net",
+ "jqueryui.com",
+ "jsdelivr.net",
+ "jshell.net",
+ "jtvnw.net",
+ "jubushoushen.com",
+ "juhuaren.com",
+ "jukujo-club.com",
+ "juliepost.com",
+ "juliereyc.com",
+ "junauza.com",
+ "june4commemoration.org",
+ "junefourth-20.net",
+ "jungleheart.com",
+ "junglobal.net",
+ "juoaa.com",
+ "justdied.com",
+ "justfreevpn.com",
+ "justicefortenzin.org",
+ "justmysocks1.net",
+ "justpaste.it",
+ "justtristan.com",
+ "juyuange.org",
+ "juziyue.com",
+ "jwmusic.org",
+ "jyxf.net",
+ "k-doujin.net",
+ "ka-wai.com",
+ "kadokawa.co.jp",
+ "kagyu.org",
+ "kagyu.org.za",
+ "kagyumonlam.org",
+ "kagyunews.com.hk",
+ "kagyuoffice.org",
+ "kagyuoffice.org.tw",
+ "kaiyuan.de",
+ "kakao.com",
+ "kalachakralugano.org",
+ "kangye.org",
+ "kankan.today",
+ "kannewyork.com",
+ "kanshifang.com",
+ "kantie.org",
+ "kanzhongguo.com",
+ "kanzhongguo.eu",
+ "kaotic.com",
+ "karayou.com",
+ "karkhung.com",
+ "karmapa-teachings.org",
+ "karmapa.org",
+ "kawaiikawaii.jp",
+ "kawase.com",
+ "kba-tx.org",
+ "kcoolonline.com",
+ "kebrum.com",
+ "kechara.com",
+ "keepandshare.com",
+ "keezmovies.com",
+ "kendatire.com",
+ "kendincos.net",
+ "kenengba.com",
+ "keontech.net",
+ "kepard.com",
+ "keso.cn",
+ "kex.com",
+ "keycdn.com",
+ "khabdha.org",
+ "khatrimaza.org",
+ "khmusic.com.tw",
+ "kichiku-doujinko.com",
+ "kik.com",
+ "killwall.com",
+ "kimy.com.tw",
+ "kindleren.com",
+ "kingdomsalvation.org",
+ "kinghost.com",
+ "kingstone.com.tw",
+ "kink.com",
+ "kinmen.org.tw",
+ "kinmen.travel",
+ "kinokuniya.com",
+ "kir.jp",
+ "kissbbao.cn",
+ "kiwi.kz",
+ "kk-whys.co.jp",
+ "kkbox.com",
+ "kknews.cc",
+ "klip.me",
+ "kmuh.org.tw",
+ "knowledgerush.com",
+ "knowyourmeme.com",
+ "kobo.com",
+ "kobobooks.com",
+ "kodingen.com",
+ "kompozer.net",
+ "konachan.com",
+ "kone.com",
+ "koolsolutions.com",
+ "koornk.com",
+ "koranmandarin.com",
+ "korenan2.com",
+ "kqes.net",
+ "krtco.com.tw",
+ "ksdl.org",
+ "ksnews.com.tw",
+ "kspcoin.com",
+ "ktzhk.com",
+ "kucoin.com",
+ "kui.name",
+ "kukuku.uk",
+ "kun.im",
+ "kurashsultan.com",
+ "kurtmunger.com",
+ "kusocity.com",
+ "kwcg.ca",
+ "kwok7.com",
+ "kwongwah.com.my",
+ "kxsw.life",
+ "kyofun.com",
+ "kyohk.net",
+ "kyoyue.com",
+ "kyzyhello.com",
+ "kzeng.info",
+ "la-forum.org",
+ "labiennale.org",
+ "ladbrokes.com",
+ "lagranepoca.com",
+ "lala.im",
+ "lalulalu.com",
+ "lama.com.tw",
+ "lamayeshe.com",
+ "lamenhu.com",
+ "lamnia.co.uk",
+ "lamrim.com",
+ "landofhope.tv",
+ "lanterncn.cn",
+ "lantosfoundation.org",
+ "laod.cn",
+ "laogai.org",
+ "laogairesearch.org",
+ "laomiu.com",
+ "laoyang.info",
+ "laptoplockdown.com",
+ "laqingdan.net",
+ "larsgeorge.com",
+ "lastcombat.com",
+ "lastfm.es",
+ "latelinenews.com",
+ "lausan.hk",
+ "law.com",
+ "lbank.info",
+ "le-vpn.com",
+ "leafyvpn.net",
+ "lecloud.net",
+ "leeao.com.cn",
+ "lefora.com",
+ "left21.hk",
+ "legalporno.com",
+ "legsjapan.com",
+ "leirentv.ca",
+ "leisurecafe.ca",
+ "leisurepro.com",
+ "lematin.ch",
+ "lemonde.fr",
+ "lenwhite.com",
+ "leorockwell.com",
+ "lerosua.org",
+ "lers.google",
+ "lesoir.be",
+ "lester850.info",
+ "letou.com",
+ "letscorp.net",
+ "letsencrypt.org",
+ "levyhsu.com",
+ "lflink.com",
+ "lflinkup.com",
+ "lflinkup.net",
+ "lflinkup.org",
+ "lfpcontent.com",
+ "lhakar.org",
+ "lhasocialwork.org",
+ "liangyou.net",
+ "liangzhichuanmei.com",
+ "lianyue.net",
+ "liaowangxizang.net",
+ "liberal.org.hk",
+ "libertytimes.com.tw",
+ "libraryinformationtechnology.com",
+ "libredd.it",
+ "lifemiles.com",
+ "lighten.org.tw",
+ "lighti.me",
+ "lightnovel.cn",
+ "lightyearvpn.com",
+ "lihkg.com",
+ "like.com",
+ "limiao.net",
+ "line-apps.com",
+ "line-scdn.net",
+ "line.me",
+ "linglingfa.com",
+ "lingvodics.com",
+ "link-o-rama.com",
+ "linkedin.com",
+ "linkideo.com",
+ "linksalpha.com",
+ "linkuswell.com",
+ "linpie.com",
+ "linux.org.hk",
+ "linuxtoy.org",
+ "lionsroar.com",
+ "lipuman.com",
+ "liquiditytp.com",
+ "liquidvpn.com",
+ "list-manage.com",
+ "listennotes.com",
+ "listentoyoutube.com",
+ "listorious.com",
+ "lithium.com",
+ "liu-xiaobo.org",
+ "liudejun.com",
+ "liuhanyu.com",
+ "liujianshu.com",
+ "liuxiaobo.net",
+ "liuxiaotong.com",
+ "live.com",
+ "livecoin.net",
+ "livedoor.jp",
+ "liveleak.com",
+ "livemint.com",
+ "livestation.com",
+ "livestream.com",
+ "livevideo.com",
+ "livingonline.us",
+ "livingstream.com",
+ "liwangyang.com",
+ "lizhizhuangbi.com",
+ "lkcn.net",
+ "llss.me",
+ "lncn.org",
+ "load.to",
+ "lobsangwangyal.com",
+ "localbitcoins.com",
+ "localdomain.ws",
+ "localpresshk.com",
+ "lockestek.com",
+ "logbot.net",
+ "logiqx.com",
+ "logmein.com",
+ "logos.com.hk",
+ "londonchinese.ca",
+ "longhair.hk",
+ "longmusic.com",
+ "longtermly.net",
+ "longtoes.com",
+ "lookpic.com",
+ "looktoronto.com",
+ "lotsawahouse.org",
+ "lotuslight.org.hk",
+ "lotuslight.org.tw",
+ "loved.hk",
+ "lovetvshow.com",
+ "lpsg.com",
+ "lrfz.com",
+ "lrip.org",
+ "lsd.org.hk",
+ "lsforum.net",
+ "lsm.org",
+ "lsmchinese.org",
+ "lsmkorean.org",
+ "lsmradio.com",
+ "lsmwebcast.com",
+ "lsxszzg.com",
+ "ltn.com.tw",
+ "luckydesigner.space",
+ "luke54.com",
+ "luke54.org",
+ "lupm.org",
+ "lushstories.com",
+ "luxebc.com",
+ "lvhai.org",
+ "lvv2.com",
+ "lyfhk.net",
+ "lzjscript.com",
+ "lzmtnews.org",
+ "m-sport.co.uk",
+ "m-team.cc",
+ "m.me",
+ "macgamestore.com",
+ "macrovpn.com",
+ "macts.com.tw",
+ "mad-ar.ch",
+ "madewithcode.com",
+ "madonna-av.com",
+ "madrau.com",
+ "madthumbs.com",
+ "magic-net.info",
+ "mahabodhi.org",
+ "maiio.net",
+ "mail-archive.com",
+ "mail.ru",
+ "mailchimp.com",
+ "maildns.xyz",
+ "maiplus.com",
+ "maizhong.org",
+ "makemymood.com",
+ "makkahnewspaper.com",
+ "malaysiakini.com",
+ "mamingzhe.com",
+ "manchukuo.net",
+ "mandiant.com",
+ "mangafox.com",
+ "mangafox.me",
+ "maniash.com",
+ "manicur4ik.ru",
+ "mansion.com",
+ "mansionpoker.com",
+ "manta.com",
+ "manyvoices.news",
+ "maplew.com",
+ "marc.info",
+ "marguerite.su",
+ "martau.com",
+ "martincartoons.com",
+ "martinoei.com",
+ "martsangkagyuofficial.org",
+ "maruta.be",
+ "marxist.com",
+ "marxist.net",
+ "marxists.org",
+ "mash.to",
+ "maskedip.com",
+ "mastodon.cloud",
+ "mastodon.host",
+ "mastodon.social",
+ "mastodon.xyz",
+ "matainja.com",
+ "material.io",
+ "mathable.io",
+ "mathiew-badimon.com",
+ "matome-plus.com",
+ "matome-plus.net",
+ "matrix.org",
+ "matsushimakaede.com",
+ "matters.news",
+ "mattwilcox.net",
+ "maturejp.com",
+ "maxing.jp",
+ "mayimayi.com",
+ "mcadforums.com",
+ "mcaf.ee",
+ "mcfog.com",
+ "mcreasite.com",
+ "md-t.org",
+ "me.me",
+ "meansys.com",
+ "media.org.hk",
+ "mediachinese.com",
+ "mediafire.com",
+ "mediafreakcity.com",
+ "medium.com",
+ "meetav.com",
+ "meetup.com",
+ "mefeedia.com",
+ "meforum.org",
+ "mefound.com",
+ "mega.co.nz",
+ "mega.io",
+ "mega.nz",
+ "megaproxy.com",
+ "megarotic.com",
+ "megavideo.com",
+ "megurineluka.com",
+ "meizhong.blog",
+ "meizhong.report",
+ "meltoday.com",
+ "memehk.com",
+ "memorybbs.com",
+ "memri.org",
+ "memrijttm.org",
+ "mercatox.com",
+ "mercdn.net",
+ "mercyprophet.org",
+ "mergersandinquisitions.org",
+ "meridian-trust.org",
+ "meripet.biz",
+ "meripet.com",
+ "merit-times.com.tw",
+ "meshrep.com",
+ "mesotw.com",
+ "messenger.com",
+ "metacafe.com",
+ "metafilter.com",
+ "metart.com",
+ "metarthunter.com",
+ "meteorshowersonline.com",
+ "metro.taipei",
+ "metrohk.com.hk",
+ "metrolife.ca",
+ "metroradio.com.hk",
+ "mewe.com",
+ "meyou.jp",
+ "meyul.com",
+ "mfxmedia.com",
+ "mgoon.com",
+ "mgstage.com",
+ "mh4u.org",
+ "mhradio.org",
+ "michaelanti.com",
+ "michaelmarketl.com",
+ "microvpn.com",
+ "middle-way.net",
+ "mihk.hk",
+ "mihr.com",
+ "mihua.org",
+ "mikesoltys.com",
+ "mikocon.com",
+ "milph.net",
+ "milsurps.com",
+ "mimiai.net",
+ "mimivip.com",
+ "mimivv.com",
+ "mindrolling.org",
+ "mingdemedia.org",
+ "minghui-a.org",
+ "minghui-b.org",
+ "minghui-school.org",
+ "minghui.or.kr",
+ "minghui.org",
+ "mingjinglishi.com",
+ "mingjingnews.com",
+ "mingjingtimes.com",
+ "mingpao.com",
+ "mingpaocanada.com",
+ "mingpaomonthly.com",
+ "mingpaonews.com",
+ "mingpaony.com",
+ "mingpaosf.com",
+ "mingpaotor.com",
+ "mingpaovan.com",
+ "mingshengbao.com",
+ "minhhue.net",
+ "miniforum.org",
+ "ministrybooks.org",
+ "minzhuhua.net",
+ "minzhuzhanxian.com",
+ "minzhuzhongguo.org",
+ "miroguide.com",
+ "mirrorbooks.com",
+ "mirrormedia.mg",
+ "mist.vip",
+ "mit.edu",
+ "mitao.com.tw",
+ "mitbbs.com",
+ "mitbbsau.com",
+ "mixero.com",
+ "mixi.jp",
+ "mixpod.com",
+ "mixx.com",
+ "mizzmona.com",
+ "mjib.gov.tw",
+ "mk5000.com",
+ "mlcool.com",
+ "mlzs.work",
+ "mm-cg.com",
+ "mmaaxx.com",
+ "mmmca.com",
+ "mnewstv.com",
+ "mobatek.net",
+ "mobile01.com",
+ "mobileways.de",
+ "moby.to",
+ "mobypicture.com",
+ "mod.io",
+ "modernchinastudies.org",
+ "moeaic.gov.tw",
+ "moeerolibrary.com",
+ "moegirl.org",
+ "mofa.gov.tw",
+ "mofaxiehui.com",
+ "mofos.com",
+ "mog.com",
+ "mohu.club",
+ "mohu.ml",
+ "mohu.rocks",
+ "mojim.com",
+ "mol.gov.tw",
+ "molihua.org",
+ "monar.ch",
+ "mondex.org",
+ "money-link.com.tw",
+ "moneyhome.biz",
+ "monitorchina.org",
+ "monitorware.com",
+ "monlamit.org",
+ "monster.com",
+ "moodyz.com",
+ "moon.fm",
+ "moonbbs.com",
+ "moonbingo.com",
+ "moptt.tw",
+ "morbell.com",
+ "morningsun.org",
+ "moroneta.com",
+ "mos.ru",
+ "motherless.com",
+ "motiyun.com",
+ "motor4ik.ru",
+ "mousebreaker.com",
+ "movements.org",
+ "moviefap.com",
+ "moztw.org",
+ "mp3buscador.com",
+ "mpettis.com",
+ "mpfinance.com",
+ "mpinews.com",
+ "mponline.hk",
+ "mqxd.org",
+ "mrbasic.com",
+ "mrbonus.com",
+ "mrface.com",
+ "mrslove.com",
+ "mrtweet.com",
+ "msa-it.org",
+ "msguancha.com",
+ "msha.gov",
+ "msn.com",
+ "msn.com.tw",
+ "mswe1.org",
+ "mthruf.com",
+ "mtw.tl",
+ "mubi.com",
+ "muchosucko.com",
+ "mullvad.net",
+ "multiply.com",
+ "multiproxy.org",
+ "multiupload.com",
+ "mummysgold.com",
+ "murmur.tw",
+ "musicade.net",
+ "muslimvideo.com",
+ "muzi.com",
+ "muzi.net",
+ "muzu.tv",
+ "mvdis.gov.tw",
+ "mvg.jp",
+ "mx981.com",
+ "my-formosa.com",
+ "my-private-network.co.uk",
+ "my-proxy.com",
+ "my03.com",
+ "my903.com",
+ "myactimes.com",
+ "myanniu.com",
+ "myaudiocast.com",
+ "myav.com.tw",
+ "mybbs.us",
+ "mybet.com",
+ "myca168.com",
+ "mycanadanow.com",
+ "mychat.to",
+ "mychinamyhome.com",
+ "mychinanet.com",
+ "mychinanews.com",
+ "mychinese.news",
+ "mycnnews.com",
+ "mycould.com",
+ "mydad.info",
+ "myddns.com",
+ "myeasytv.com",
+ "myeclipseide.com",
+ "myforum.com.hk",
+ "myfreecams.com",
+ "myfreepaysite.com",
+ "myfreshnet.com",
+ "myftp.info",
+ "myftp.name",
+ "myiphide.com",
+ "mykomica.org",
+ "mylftv.com",
+ "mymaji.com",
+ "mymediarom.com",
+ "mymoe.moe",
+ "mymom.info",
+ "mymusic.net.tw",
+ "mynetav.net",
+ "mynetav.org",
+ "mynumber.org",
+ "myparagliding.com",
+ "mypicture.info",
+ "mypikpak.com",
+ "mypop3.net",
+ "mypop3.org",
+ "mypopescu.com",
+ "myradio.hk",
+ "myreadingmanga.info",
+ "mysecondarydns.com",
+ "mysinablog.com",
+ "myspace.com",
+ "myspacecdn.com",
+ "mytalkbox.com",
+ "mytizi.com",
+ "mywww.biz",
+ "myz.info",
+ "naacoalition.org",
+ "nabble.com",
+ "naitik.net",
+ "nakido.com",
+ "nakuz.com",
+ "nalandabodhi.org",
+ "nalandawest.org",
+ "namgyal.org",
+ "namgyalmonastery.org",
+ "namsisi.com",
+ "nanyang.com",
+ "nanyangpost.com",
+ "nanzao.com",
+ "naol.ca",
+ "naol.cc",
+ "narod.ru",
+ "nasa.gov",
+ "nat.gov.tw",
+ "nat.moe",
+ "natado.com",
+ "national-lottery.co.uk",
+ "nationalawakening.org",
+ "nationalgeographic.com",
+ "nationalinterest.org",
+ "nationalreview.com",
+ "nationsonline.org",
+ "nationwide.com",
+ "naughtyamerica.com",
+ "naver.jp",
+ "navy.mil",
+ "naweeklytimes.com",
+ "nbc.com",
+ "nbcnews.com",
+ "nbtvpn.com",
+ "nccwatch.org.tw",
+ "nch.com.tw",
+ "nchrd.org",
+ "ncn.org",
+ "ncol.com",
+ "nde.de",
+ "ndi.org",
+ "ndr.de",
+ "ned.org",
+ "nekoslovakia.net",
+ "neo-miracle.com",
+ "neowin.net",
+ "nepusoku.com",
+ "nesnode.com",
+ "net-fits.pro",
+ "netalert.me",
+ "netbig.com",
+ "netbirds.com",
+ "netcolony.com",
+ "netfirms.com",
+ "netflav.com",
+ "netflix.com",
+ "netflix.net",
+ "netme.cc",
+ "netsarang.com",
+ "netsneak.com",
+ "network54.com",
+ "networkedblogs.com",
+ "networktunnel.net",
+ "neverforget8964.org",
+ "new-3lunch.net",
+ "new-akiba.com",
+ "new96.ca",
+ "newcenturymc.com",
+ "newcenturynews.com",
+ "newchen.com",
+ "newgrounds.com",
+ "newhighlandvision.com",
+ "newipnow.com",
+ "newlandmagazine.com.au",
+ "newnews.ca",
+ "news100.com.tw",
+ "newsancai.com",
+ "newschinacomment.org",
+ "newscn.org",
+ "newsdetox.ca",
+ "newsdh.com",
+ "newsmagazine.asia",
+ "newsmax.com",
+ "newspeak.cc",
+ "newstamago.com",
+ "newstapa.org",
+ "newstarnet.com",
+ "newstatesman.com",
+ "newsweek.com",
+ "newtaiwan.com.tw",
+ "newtalk.tw",
+ "newyorker.com",
+ "newyorktimes.com",
+ "nexon.com",
+ "next11.co.jp",
+ "nextdigital.com.hk",
+ "nextmag.com.tw",
+ "nextmedia.com",
+ "nexton-net.jp",
+ "nexttv.com.tw",
+ "nf.id.au",
+ "nfjtyd.com",
+ "nflxext.com",
+ "nflximg.com",
+ "nflximg.net",
+ "nflxso.net",
+ "nflxvideo.net",
+ "ng.mil",
+ "nga.mil",
+ "ngensis.com",
+ "ngodupdongchung.com",
+ "nhentai.net",
+ "nhi.gov.tw",
+ "nhk-ondemand.jp",
+ "nic.google",
+ "nic.gov",
+ "nicovideo.jp",
+ "nighost.org",
+ "nightlife141.com",
+ "nike.com",
+ "nikkei.com",
+ "ninecommentaries.com",
+ "ning.com",
+ "ninjacloak.com",
+ "ninjaproxy.ninja",
+ "nintendium.com",
+ "ninth.biz",
+ "nitter.cc",
+ "nitter.net",
+ "niu.moe",
+ "niusnews.com",
+ "njactb.org",
+ "njuice.com",
+ "nlfreevpn.com",
+ "nmsl.website",
+ "nnews.eu",
+ "no-ip.com",
+ "no-ip.org",
+ "nobel.se",
+ "nobelprize.org",
+ "nobodycanstop.us",
+ "nodesnoop.com",
+ "nofile.io",
+ "nokogiri.org",
+ "nokola.com",
+ "noodlevpn.com",
+ "norbulingka.org",
+ "nordstrom.com",
+ "nordstromimage.com",
+ "nordstromrack.com",
+ "nordvpn.com",
+ "notepad-plus-plus.org",
+ "nottinghampost.com",
+ "novelasia.com",
+ "now.com",
+ "now.im",
+ "nownews.com",
+ "nowtorrents.com",
+ "noxinfluencer.com",
+ "noypf.com",
+ "npa.go.jp",
+ "npa.gov.tw",
+ "npnt.me",
+ "nps.gov",
+ "npsboost.com",
+ "nradio.me",
+ "nrk.no",
+ "ns01.biz",
+ "ns01.info",
+ "ns01.us",
+ "ns02.biz",
+ "ns02.info",
+ "ns02.us",
+ "ns1.name",
+ "ns2.name",
+ "ns3.name",
+ "nsc.gov.tw",
+ "ntbk.gov.tw",
+ "ntbna.gov.tw",
+ "ntbt.gov.tw",
+ "ntd.tv",
+ "ntdtv.ca",
+ "ntdtv.co.kr",
+ "ntdtv.com",
+ "ntdtv.com.tw",
+ "ntdtv.cz",
+ "ntdtv.org",
+ "ntdtv.ru",
+ "ntdtvla.com",
+ "ntrfun.com",
+ "ntsna.gov.tw",
+ "ntu.edu.tw",
+ "nu.nl",
+ "nubiles.net",
+ "nudezz.com",
+ "nuexpo.com",
+ "nukistream.com",
+ "nurgo-software.com",
+ "nusatrip.com",
+ "nutaku.net",
+ "nutsvpn.work",
+ "nuuvem.com",
+ "nuvid.com",
+ "nuzcom.com",
+ "nvdst.com",
+ "nvquan.org",
+ "nvtongzhisheng.org",
+ "nwtca.org",
+ "nyaa.eu",
+ "nyaa.si",
+ "nybooks.com",
+ "nydus.ca",
+ "nylon-angel.com",
+ "nylonstockingsonline.com",
+ "nypost.com",
+ "nyt.com",
+ "nytchina.com",
+ "nytcn.me",
+ "nytco.com",
+ "nyti.ms",
+ "nytimes.com",
+ "nytimg.com",
+ "nytlog.com",
+ "nytstyle.com",
+ "nzchinese.com",
+ "nzchinese.net.nz",
+ "oanda.com",
+ "oann.com",
+ "oauth.net",
+ "observechina.net",
+ "obutu.com",
+ "ocaspro.com",
+ "occupytiananmen.com",
+ "oclp.hk",
+ "ocreampies.com",
+ "ocry.com",
+ "october-review.org",
+ "oculus.com",
+ "oculuscdn.com",
+ "odysee.com",
+ "oex.com",
+ "offbeatchina.com",
+ "officeoftibet.com",
+ "ofile.org",
+ "ogaoga.org",
+ "ogate.org",
+ "ohchr.org",
+ "ohmyrss.com",
+ "oikos.com.tw",
+ "oiktv.com",
+ "oizoblog.com",
+ "ok.ru",
+ "okayfreedom.com",
+ "okex.com",
+ "okk.tw",
+ "okx.com",
+ "olabloga.pl",
+ "old-cat.net",
+ "olevod.com",
+ "olumpo.com",
+ "olympicwatch.org",
+ "omct.org",
+ "omgili.com",
+ "omni7.jp",
+ "omnitalk.com",
+ "omnitalk.org",
+ "omny.fm",
+ "omy.sg",
+ "on.cc",
+ "on2.com",
+ "onapp.com",
+ "onedumb.com",
+ "onejav.com",
+ "onion.city",
+ "onion.ly",
+ "onlinecha.com",
+ "onlineyoutube.com",
+ "onlygayvideo.com",
+ "onlytweets.com",
+ "onmoon.com",
+ "onmoon.net",
+ "onmypc.biz",
+ "onmypc.info",
+ "onmypc.net",
+ "onmypc.org",
+ "onmypc.us",
+ "onthehunt.com",
+ "ontrac.com",
+ "oopsforum.com",
+ "open.com.hk",
+ "openallweb.com",
+ "opendemocracy.net",
+ "opendn.xyz",
+ "openervpn.in",
+ "openid.net",
+ "openleaks.org",
+ "opensea.io",
+ "opensource.google",
+ "opentech.fund",
+ "openvpn.net",
+ "openvpn.org",
+ "openwebster.com",
+ "openwrt.org.cn",
+ "opera-mini.net",
+ "opera.com",
+ "opus-gaming.com",
+ "orchidbbs.com",
+ "organcare.org.tw",
+ "organharvestinvestigation.net",
+ "organiccrap.com",
+ "orgasm.com",
+ "orgfree.com",
+ "oricon.co.jp",
+ "orient-doll.com",
+ "orientaldaily.com.my",
+ "orn.jp",
+ "orzdream.com",
+ "orzistic.org",
+ "osfoora.com",
+ "otcbtc.com",
+ "otnd.org",
+ "otto.de",
+ "otzo.com",
+ "ourdearamy.com",
+ "ourhobby.com",
+ "oursogo.com",
+ "oursteps.com.au",
+ "oursweb.net",
+ "ourtv.hk",
+ "over-blog.com",
+ "overcast.fm",
+ "overdaily.org",
+ "overplay.net",
+ "ovi.com",
+ "ovpn.com",
+ "ow.ly",
+ "owind.com",
+ "owl.li",
+ "owltail.com",
+ "oxfordscholarship.com",
+ "oxid.it",
+ "oyax.com",
+ "oyghan.com",
+ "ozchinese.com",
+ "ozvoice.org",
+ "ozxw.com",
+ "ozyoyo.com",
+ "pachosting.com",
+ "pacificpoker.com",
+ "packetix.net",
+ "pacopacomama.com",
+ "padmanet.com",
+ "page.tl",
+ "page2rss.com",
+ "pages.dev",
+ "pagodabox.com",
+ "palacemoon.com",
+ "paldengyal.com",
+ "paljorpublications.com",
+ "palmislife.com",
+ "paltalk.com",
+ "pandapow.co",
+ "pandapow.net",
+ "pandavpn-jp.com",
+ "pandavpnpro.com",
+ "pandora.com",
+ "pandora.tv",
+ "panluan.net",
+ "panoramio.com",
+ "pao-pao.net",
+ "paper.li",
+ "paperb.us",
+ "paradisehill.cc",
+ "paradisepoker.com",
+ "parkansky.com",
+ "parler.com",
+ "parse.com",
+ "parsevideo.com",
+ "partycasino.com",
+ "partypoker.com",
+ "passion.com",
+ "passiontimes.hk",
+ "paste.ee",
+ "pastebin.com",
+ "pastie.org",
+ "pathtosharepoint.com",
+ "patreon.com",
+ "paxful.com",
+ "pbs.org",
+ "pbwiki.com",
+ "pbworks.com",
+ "pbxes.com",
+ "pbxes.org",
+ "pcanywhere.net",
+ "pcc.gov.tw",
+ "pcdvd.com.tw",
+ "pchome.com.tw",
+ "pcij.org",
+ "pcloud.com",
+ "pcstore.com.tw",
+ "pct.org.tw",
+ "pdetails.com",
+ "pdproxy.com",
+ "peace.ca",
+ "peacefire.org",
+ "peacehall.com",
+ "pearlher.org",
+ "peeasian.com",
+ "peing.net",
+ "pekingduck.org",
+ "pemulihan.or.id",
+ "pen.io",
+ "penchinese.com",
+ "penchinese.net",
+ "pengyulong.com",
+ "penisbot.com",
+ "pentalogic.net",
+ "penthouse.com",
+ "pentoy.hk",
+ "peoplebookcafe.com",
+ "peoplenews.tw",
+ "peopo.org",
+ "percy.in",
+ "perfect-privacy.com",
+ "perfectgirls.net",
+ "periscope.tv",
+ "persecutionblog.com",
+ "persiankitty.com",
+ "phapluan.org",
+ "phayul.com",
+ "philborges.com",
+ "philly.com",
+ "phmsociety.org",
+ "phncdn.com",
+ "phonegap.com",
+ "photodharma.net",
+ "photofocus.com",
+ "phuquocservices.com",
+ "picacomic.com",
+ "picacomiccn.com",
+ "picasaweb.com",
+ "picidae.net",
+ "picturedip.com",
+ "picturesocial.com",
+ "pimg.tw",
+ "pin-cong.com",
+ "pin6.com",
+ "pincong.rocks",
+ "ping.fm",
+ "pinimg.com",
+ "pinkrod.com",
+ "pinoy-n.com",
+ "pinterest.at",
+ "pinterest.ca",
+ "pinterest.co.kr",
+ "pinterest.co.uk",
+ "pinterest.com",
+ "pinterest.com.mx",
+ "pinterest.de",
+ "pinterest.dk",
+ "pinterest.fr",
+ "pinterest.jp",
+ "pinterest.nl",
+ "pinterest.se",
+ "pipii.tv",
+ "piposay.com",
+ "piraattilahti.org",
+ "piring.com",
+ "pixelqi.com",
+ "pixiv.net",
+ "pixnet.in",
+ "pixnet.net",
+ "pk.com",
+ "pki.goog",
+ "placemix.com",
+ "playboy.com",
+ "playboyplus.com",
+ "player.fm",
+ "playno1.com",
+ "playpcesor.com",
+ "plays.com.tw",
+ "plexvpn.pro",
+ "plixi.com",
+ "plm.org.hk",
+ "plunder.com",
+ "plurk.com",
+ "plus.codes",
+ "plus28.com",
+ "plusbb.com",
+ "pmatehunter.com",
+ "pmates.com",
+ "po2b.com",
+ "pobieramy.top",
+ "podbean.com",
+ "podcast.co",
+ "podictionary.com",
+ "pokerstars.com",
+ "pokerstars.net",
+ "pokerstrategy.com",
+ "politicalchina.org",
+ "politicalconsultation.org",
+ "politiscales.net",
+ "poloniex.com",
+ "polymer-project.org",
+ "polymerhk.com",
+ "poolin.com",
+ "popo.tw",
+ "popvote.hk",
+ "popxi.click",
+ "popyard.com",
+ "popyard.org",
+ "porn.com",
+ "porn2.com",
+ "porn5.com",
+ "pornbase.org",
+ "pornerbros.com",
+ "pornhd.com",
+ "pornhost.com",
+ "pornhub.com",
+ "pornhubdeutsch.net",
+ "pornmm.net",
+ "pornoxo.com",
+ "pornrapidshare.com",
+ "pornsharing.com",
+ "pornsocket.com",
+ "pornstarclub.com",
+ "porntube.com",
+ "porntubenews.com",
+ "porntvblog.com",
+ "pornvisit.com",
+ "port25.biz",
+ "portablevpn.nl",
+ "poskotanews.com",
+ "post01.com",
+ "post76.com",
+ "post852.com",
+ "postadult.com",
+ "postimg.org",
+ "potato.im",
+ "potvpn.com",
+ "power.com",
+ "powerapple.com",
+ "powercx.com",
+ "powerphoto.org",
+ "powerpointninja.com",
+ "pp.ru",
+ "prayforchina.net",
+ "premeforwindows7.com",
+ "premproxy.com",
+ "presentationzen.com",
+ "presidentlee.tw",
+ "prestige-av.com",
+ "pride.google",
+ "printfriendly.com",
+ "prism-break.org",
+ "prisoneralert.com",
+ "pritunl.com",
+ "privacybox.de",
+ "private.com",
+ "privateinternetaccess.com",
+ "privatepaste.com",
+ "privatetunnel.com",
+ "privatevpn.com",
+ "privoxy.org",
+ "procopytips.com",
+ "project-syndicate.org",
+ "prosiben.de",
+ "proton.me",
+ "protonvpn.com",
+ "provideocoalition.com",
+ "provpnaccounts.com",
+ "proxfree.com",
+ "proxifier.com",
+ "proxlet.com",
+ "proxomitron.info",
+ "proxpn.com",
+ "proxyanonimo.es",
+ "proxydns.com",
+ "proxylist.org.uk",
+ "proxynetwork.org.uk",
+ "proxypy.net",
+ "proxyroad.com",
+ "proxytunnel.net",
+ "proyectoclubes.com",
+ "prozz.net",
+ "psblog.name",
+ "pscp.tv",
+ "pshvpn.com",
+ "psiphon.ca",
+ "psiphon3.com",
+ "psiphontoday.com",
+ "pt.im",
+ "pts.org.tw",
+ "ptt.cc",
+ "pttgame.com",
+ "pttvan.org",
+ "pubu.com.tw",
+ "puffinbrowser.com",
+ "puffstore.com",
+ "pullfolio.com",
+ "punyu.com",
+ "pure18.com",
+ "pureapk.com",
+ "pureconcepts.net",
+ "pureinsight.org",
+ "purepdf.com",
+ "purevpn.com",
+ "purplelotus.org",
+ "pursuestar.com",
+ "pushchinawall.com",
+ "pussthecat.org",
+ "pussyspace.com",
+ "putihome.org",
+ "putlocker.com",
+ "putty.org",
+ "puuko.com",
+ "pwned.com",
+ "pximg.net",
+ "python.com",
+ "python.com.tw",
+ "pythonhackers.com",
+ "pythonic.life",
+ "pytorch.org",
+ "qanote.com",
+ "qgirl.com.tw",
+ "qhigh.com",
+ "qi-gong.me",
+ "qianbai.tw",
+ "qiandao.today",
+ "qiangwaikan.com",
+ "qiangyou.org",
+ "qidian.ca",
+ "qienkuen.org",
+ "qiwen.lu",
+ "qixianglu.cn",
+ "qkshare.com",
+ "qmzdd.com",
+ "qoos.com",
+ "qooza.hk",
+ "qpoe.com",
+ "qq.co.za",
+ "qstatus.com",
+ "qtrac.eu",
+ "qtweeter.com",
+ "quannengshen.org",
+ "quantumbooter.net",
+ "questvisual.com",
+ "quitccp.net",
+ "quitccp.org",
+ "quora.com",
+ "quoracdn.net",
+ "quran.com",
+ "quranexplorer.com",
+ "qusi8.net",
+ "qvodzy.org",
+ "qx.net",
+ "qxbbs.org",
+ "qz.com",
+ "r0.ru",
+ "r18.com",
+ "ra.gg",
+ "radicalparty.org",
+ "radiko.jp",
+ "radio.garden",
+ "radioaustralia.net.au",
+ "radiohilight.net",
+ "radioline.co",
+ "radiotime.com",
+ "radiovaticana.org",
+ "radiovncr.com",
+ "rael.org",
+ "raggedbanner.com",
+ "raidcall.com.tw",
+ "raidtalk.com.tw",
+ "rainbowplan.org",
+ "raindrop.io",
+ "raizoji.or.jp",
+ "ramcity.com.au",
+ "rangwang.biz",
+ "rangzen.com",
+ "rangzen.net",
+ "rangzen.org",
+ "ranxiang.com",
+ "ranyunfei.com",
+ "rapbull.net",
+ "rapidgator.net",
+ "rapidmoviez.com",
+ "rapidvpn.com",
+ "rarbgprx.org",
+ "raremovie.cc",
+ "raremovie.net",
+ "rateyourmusic.com",
+ "rationalwiki.org",
+ "rawgit.com",
+ "rawgithub.com",
+ "raxcdn.com",
+ "razyboard.com",
+ "rcinet.ca",
+ "rd.com",
+ "rdio.com",
+ "read01.com",
+ "read100.com",
+ "readingtimes.com.tw",
+ "readmoo.com",
+ "readydown.com",
+ "realcourage.org",
+ "realitykings.com",
+ "realraptalk.com",
+ "realsexpass.com",
+ "reason.com",
+ "rebatesrule.net",
+ "recaptcha.net",
+ "recordhistory.org",
+ "recovery.org.tw",
+ "recoveryversion.com.tw",
+ "recoveryversion.org",
+ "red-lang.org",
+ "redballoonsolidarity.org",
+ "redbubble.com",
+ "redchinacn.net",
+ "redchinacn.org",
+ "redd.it",
+ "reddit.com",
+ "redditlist.com",
+ "redditmedia.com",
+ "redditstatic.com",
+ "redhotlabs.com",
+ "redtube.com",
+ "referer.us",
+ "reflectivecode.com",
+ "registry.google",
+ "relaxbbs.com",
+ "relay.com.tw",
+ "releaseinternational.org",
+ "religionnews.com",
+ "religioustolerance.org",
+ "renminbao.com",
+ "renyurenquan.org",
+ "rerouted.org",
+ "research.google",
+ "resilio.com",
+ "resistchina.org",
+ "retweeteffect.com",
+ "retweetist.com",
+ "retweetrank.com",
+ "reuters.com",
+ "reutersmedia.net",
+ "revleft.com",
+ "revocationcheck.com",
+ "revver.com",
+ "rfa.org",
+ "rfachina.com",
+ "rfamobile.org",
+ "rfaweb.org",
+ "rferl.org",
+ "rfi.fr",
+ "rfi.my",
+ "rightbtc.com",
+ "rightster.com",
+ "rigpa.org",
+ "riku.me",
+ "rileyguide.com",
+ "riseup.net",
+ "ritouki.jp",
+ "ritter.vg",
+ "rixcloud.com",
+ "rixcloud.us",
+ "rlwlw.com",
+ "rmjdw.com",
+ "rmjdw132.info",
+ "roadshow.hk",
+ "roboforex.com",
+ "robustnessiskey.com",
+ "rocket-inc.net",
+ "rocketbbs.com",
+ "rocksdb.org",
+ "rojo.com",
+ "rolfoundation.org",
+ "rolia.net",
+ "rolsociety.org",
+ "ronjoneswriter.com",
+ "roodo.com",
+ "rosechina.net",
+ "rotten.com",
+ "rsdlmonitor.com",
+ "rsf-chinese.org",
+ "rsf.org",
+ "rsgamen.org",
+ "rsshub.app",
+ "rssing.com",
+ "rssmeme.com",
+ "rtalabel.org",
+ "rthk.hk",
+ "rthk.org.hk",
+ "rti.org.tw",
+ "rti.tw",
+ "rtycminnesota.org",
+ "ruanyifeng.com",
+ "rukor.org",
+ "rule34.xxx",
+ "runbtx.com",
+ "rushbee.com",
+ "rusvpn.com",
+ "ruten.com.tw",
+ "rutracker.net",
+ "rutube.ru",
+ "ruyiseek.com",
+ "rxhj.net",
+ "s-cute.com",
+ "s-dragon.org",
+ "s1heng.com",
+ "s1s1s1.com",
+ "s4miniarchive.com",
+ "s8forum.com",
+ "sa.com",
+ "saboom.com",
+ "sacks.com",
+ "sacom.hk",
+ "sadistic-v.com",
+ "sadpanda.us",
+ "safechat.com",
+ "safeguarddefenders.com",
+ "safervpn.com",
+ "safety.google",
+ "saintyculture.com",
+ "saiq.me",
+ "sakuralive.com",
+ "sakya.org",
+ "salvation.org.hk",
+ "samair.ru",
+ "sambhota.org",
+ "sandscotaicentral.com",
+ "sankei.com",
+ "sanmin.com.tw",
+ "sans.edu",
+ "sapikachu.net",
+ "saveliuxiaobo.com",
+ "savemedia.com",
+ "savethedate.foo",
+ "savethesounds.info",
+ "savetibet.de",
+ "savetibet.fr",
+ "savetibet.nl",
+ "savetibet.org",
+ "savetibet.ru",
+ "savetibetstore.org",
+ "saveuighur.org",
+ "savevid.com",
+ "say2.info",
+ "sbme.me",
+ "sbs.com.au",
+ "scasino.com",
+ "schema.org",
+ "sciencemag.org",
+ "sciencenets.com",
+ "scieron.com",
+ "scmp.com",
+ "scmpchinese.com",
+ "scramble.io",
+ "scribd.com",
+ "scriptspot.com",
+ "search.com",
+ "search.xxx",
+ "searchtruth.com",
+ "searx.me",
+ "seatguru.com",
+ "seattlefdc.com",
+ "secretchina.com",
+ "secretgarden.no",
+ "secretsline.biz",
+ "secureservercdn.net",
+ "securetunnel.com",
+ "securityinabox.org",
+ "securitykiss.com",
+ "seed4.me",
+ "seehua.com",
+ "seesmic.com",
+ "seevpn.com",
+ "seezone.net",
+ "sejie.com",
+ "sellclassics.com",
+ "sendsmtp.com",
+ "sendspace.com",
+ "sensortower.com",
+ "seraph.me",
+ "servehttp.com",
+ "serveuser.com",
+ "serveusers.com",
+ "sesawe.net",
+ "sesawe.org",
+ "sethwklein.net",
+ "setn.com",
+ "settv.com.tw",
+ "setty.com.tw",
+ "sevenload.com",
+ "sex-11.com",
+ "sex.com",
+ "sex3.com",
+ "sex8.cc",
+ "sexandsubmission.com",
+ "sexbot.com",
+ "sexhu.com",
+ "sexhuang.com",
+ "sexidude.com",
+ "sexinsex.net",
+ "sextvx.com",
+ "sexxxy.biz",
+ "sf.net",
+ "sfileydy.com",
+ "sfshibao.com",
+ "sftindia.org",
+ "sftuk.org",
+ "shadeyouvpn.com",
+ "shadow.ma",
+ "shadowsky.xyz",
+ "shadowsocks-r.com",
+ "shadowsocks.asia",
+ "shadowsocks.be",
+ "shadowsocks.com",
+ "shadowsocks.com.hk",
+ "shadowsocks.org",
+ "shadowsocks9.com",
+ "shafaqna.com",
+ "shahit.biz",
+ "shambalapost.com",
+ "shambhalasun.com",
+ "shangfang.org",
+ "shapeservices.com",
+ "sharebee.com",
+ "sharecool.org",
+ "sharpdaily.com.hk",
+ "sharpdaily.hk",
+ "sharpdaily.tw",
+ "shat-tibet.com",
+ "shattered.io",
+ "sheikyermami.com",
+ "shellfire.de",
+ "shemalez.com",
+ "shenshou.org",
+ "shenyun.com",
+ "shenyunperformingarts.org",
+ "shenyunshop.com",
+ "shenzhoufilm.com",
+ "shenzhouzhengdao.org",
+ "sherabgyaltsen.com",
+ "shiatv.net",
+ "shicheng.org",
+ "shiksha.com",
+ "shinychan.com",
+ "shipcamouflage.com",
+ "shireyishunjian.com",
+ "shitaotv.org",
+ "shixiao.org",
+ "shizhao.org",
+ "shkspr.mobi",
+ "shodanhq.com",
+ "shooshtime.com",
+ "shop2000.com.tw",
+ "shopee.tw",
+ "shopping.com",
+ "showhaotu.com",
+ "showtime.jp",
+ "showwe.tw",
+ "shutterstock.com",
+ "shvoong.com",
+ "shwchurch.org",
+ "shwchurch3.com",
+ "siddharthasintent.org",
+ "sidelinesnews.com",
+ "sidelinessportseatery.com",
+ "sierrafriendsoftibet.org",
+ "signal.org",
+ "sijihuisuo.club",
+ "sijihuisuo.com",
+ "silkbook.com",
+ "simbolostwitter.com",
+ "simplecd.org",
+ "simpleproductivityblog.com",
+ "sina.com",
+ "sina.com.hk",
+ "sina.com.tw",
+ "sinchew.com.my",
+ "singaporepools.com.sg",
+ "singfortibet.com",
+ "singpao.com.hk",
+ "singtao.ca",
+ "singtao.com",
+ "singtaousa.com",
+ "sino-monthly.com",
+ "sinoants.com",
+ "sinoca.com",
+ "sinocast.com",
+ "sinocism.com",
+ "sinoinsider.com",
+ "sinomontreal.ca",
+ "sinonet.ca",
+ "sinopitt.info",
+ "sinoquebec.com",
+ "sipml5.org",
+ "sis.xxx",
+ "sis001.com",
+ "sis001.us",
+ "site2unblock.com",
+ "site90.net",
+ "sitebro.tw",
+ "sitekreator.com",
+ "sitemaps.org",
+ "six-degrees.io",
+ "sixth.biz",
+ "sjrt.org",
+ "sjum.cn",
+ "sketchappsources.com",
+ "skimtube.com",
+ "skk.moe",
+ "skybet.com",
+ "skyking.com.tw",
+ "skykiwi.com",
+ "skynet.be",
+ "skype.com",
+ "skyvegas.com",
+ "skyxvpn.com",
+ "slacker.com",
+ "slandr.net",
+ "slaytizle.com",
+ "sleazydream.com",
+ "slheng.com",
+ "slickvpn.com",
+ "slideshare.net",
+ "slime.com.tw",
+ "slinkset.com",
+ "slutload.com",
+ "slutmoonbeam.com",
+ "slyip.com",
+ "slyip.net",
+ "sm-miracle.com",
+ "smartdnsproxy.com",
+ "smarthide.com",
+ "smartmailcloud.com",
+ "smchbooks.com",
+ "smh.com.au",
+ "smhric.org",
+ "smith.edu",
+ "smyxy.org",
+ "snapchat.com",
+ "snaptu.com",
+ "sndcdn.com",
+ "sneakme.net",
+ "snowlionpub.com",
+ "so-net.net.tw",
+ "sobees.com",
+ "soc.mil",
+ "socialblade.com",
+ "socialwhale.com",
+ "socks-proxy.net",
+ "sockscap64.com",
+ "sockslist.net",
+ "socrec.org",
+ "sod.co.jp",
+ "softether-download.com",
+ "softether.co.jp",
+ "softether.org",
+ "softfamous.com",
+ "softlayer.net",
+ "softnology.biz",
+ "softsmirror.cf",
+ "softwarebychuck.com",
+ "sogclub.com",
+ "sogoo.org",
+ "sogrady.me",
+ "soh.tw",
+ "sohcradio.com",
+ "sohfrance.org",
+ "soifind.com",
+ "sokamonline.com",
+ "sokmil.com",
+ "solana.com",
+ "solidaritetibet.org",
+ "solidfiles.com",
+ "solv.finance",
+ "somee.com",
+ "songjianjun.com",
+ "sonicbbs.cc",
+ "sonidodelaesperanza.org",
+ "sopcast.com",
+ "sopcast.org",
+ "sophos.com",
+ "sorazone.net",
+ "sorting-algorithms.com",
+ "sos.org",
+ "sosreader.com",
+ "sostibet.org",
+ "sou-tong.org",
+ "soubory.com",
+ "soul-plus.net",
+ "soulcaliburhentai.net",
+ "soumo.info",
+ "soundcloud.com",
+ "soundofhope.kr",
+ "soundofhope.org",
+ "soup.io",
+ "soupofmedia.com",
+ "sourceforge.net",
+ "sourcewadio.com",
+ "south-plus.org",
+ "southnews.com.tw",
+ "sowers.org.hk",
+ "sowiki.net",
+ "soylent.com",
+ "soylentnews.org",
+ "spankbang.com",
+ "spankingtube.com",
+ "spankwire.com",
+ "spb.com",
+ "speakerdeck.com",
+ "speedify.com",
+ "spem.at",
+ "spencertipping.com",
+ "spendee.com",
+ "spicevpn.com",
+ "spideroak.com",
+ "spike.com",
+ "spotflux.com",
+ "spotify.com",
+ "spreadshirt.es",
+ "spring4u.info",
+ "springboardplatform.com",
+ "sprite.org",
+ "sproutcore.com",
+ "sproxy.info",
+ "squirly.info",
+ "squirrelvpn.com",
+ "srocket.us",
+ "ss-link.com",
+ "ssglobal.co",
+ "ssglobal.me",
+ "ssh91.com",
+ "ssl443.org",
+ "sspanel.net",
+ "sspro.ml",
+ "ssr.tools",
+ "ssrshare.com",
+ "sss.camp",
+ "sstm.moe",
+ "sstmlt.moe",
+ "sstmlt.net",
+ "stackoverflow.com",
+ "stage64.hk",
+ "standupfortibet.org",
+ "standwithhk.org",
+ "stanford.edu",
+ "starfishfx.com",
+ "starp2p.com",
+ "startpage.com",
+ "startuplivingchina.com",
+ "stat.gov.tw",
+ "state.gov",
+ "static-economist.com",
+ "staticflickr.com",
+ "statueofdemocracy.org",
+ "stboy.net",
+ "stc.com.sa",
+ "steamcommunity.com",
+ "steampowered.com",
+ "steel-storm.com",
+ "steemit.com",
+ "steganos.com",
+ "steganos.net",
+ "stepchina.com",
+ "stephaniered.com",
+ "stgloballink.com",
+ "stheadline.com",
+ "sthoo.com",
+ "stickam.com",
+ "stickeraction.com",
+ "stileproject.com",
+ "sto.cc",
+ "stoporganharvesting.org",
+ "stoptibetcrisis.net",
+ "storagenewsletter.com",
+ "stories.google",
+ "storify.com",
+ "storm.mg",
+ "stormmediagroup.com",
+ "stoweboyd.com",
+ "straitstimes.com",
+ "stranabg.com",
+ "straplessdildo.com",
+ "streamable.com",
+ "streamate.com",
+ "streamingthe.net",
+ "streema.com",
+ "streetvoice.com",
+ "strikingly.com",
+ "strongvpn.com",
+ "strongwindpress.com",
+ "student.tw",
+ "studentsforafreetibet.org",
+ "stumbleupon.com",
+ "stupidvideos.com",
+ "substack.com",
+ "successfn.com",
+ "sueddeutsche.de",
+ "sugarsync.com",
+ "sugobbs.com",
+ "sugumiru18.com",
+ "suissl.com",
+ "sulian.me",
+ "summify.com",
+ "sumrando.com",
+ "sun1911.com",
+ "sundayguardianlive.com",
+ "sunmedia.ca",
+ "sunporno.com",
+ "sunskyforum.com",
+ "sunta.com.tw",
+ "sunvpn.net",
+ "suoluo.org",
+ "supchina.com",
+ "superfreevpn.com",
+ "superokayama.com",
+ "superpages.com",
+ "supervpn.net",
+ "superzooi.com",
+ "suppig.net",
+ "suprememastertv.com",
+ "surfeasy.com",
+ "surfeasy.com.au",
+ "surfshark.com",
+ "suroot.com",
+ "surrenderat20.net",
+ "sustainability.google",
+ "svsfx.com",
+ "swagbucks.com",
+ "swissinfo.ch",
+ "swissvpn.net",
+ "switch1.jp",
+ "switchvpn.net",
+ "sydneytoday.com",
+ "sylfoundation.org",
+ "syncback.com",
+ "synergyse.com",
+ "sysresccd.org",
+ "sytes.net",
+ "syx86.cn",
+ "syx86.com",
+ "szbbs.net",
+ "szetowah.org.hk",
+ "t-g.com",
+ "t.co",
+ "t.me",
+ "t35.com",
+ "t66y.com",
+ "t91y.com",
+ "taa-usa.org",
+ "taaze.tw",
+ "tablesgenerator.com",
+ "tabtter.jp",
+ "tacem.org",
+ "taconet.com.tw",
+ "taedp.org.tw",
+ "tafm.org",
+ "tagwa.org.au",
+ "tagwalk.com",
+ "tahr.org.tw",
+ "taipei.gov.tw",
+ "taipeisociety.org",
+ "taipeitimes.com",
+ "taiwan-sex.com",
+ "taiwanbible.com",
+ "taiwancon.com",
+ "taiwandaily.net",
+ "taiwandc.org",
+ "taiwanhot.net",
+ "taiwanjobs.gov.tw",
+ "taiwanjustice.com",
+ "taiwanjustice.net",
+ "taiwankiss.com",
+ "taiwannation.com",
+ "taiwannation.com.tw",
+ "taiwanncf.org.tw",
+ "taiwannews.com.tw",
+ "taiwanonline.cc",
+ "taiwantp.net",
+ "taiwantt.org.tw",
+ "taiwanus.net",
+ "taiwanyes.com",
+ "talk853.com",
+ "talkboxapp.com",
+ "talkcc.com",
+ "talkonly.net",
+ "tamiaode.tk",
+ "tampabay.com",
+ "tanc.org",
+ "tangben.com",
+ "tangren.us",
+ "taoism.net",
+ "taolun.info",
+ "tapanwap.com",
+ "tapatalk.com",
+ "taragana.com",
+ "target.com",
+ "tascn.com.au",
+ "taup.net",
+ "taup.org.tw",
+ "taweet.com",
+ "tbcollege.org",
+ "tbi.org.hk",
+ "tbicn.org",
+ "tbjyt.org",
+ "tbpic.info",
+ "tbrc.org",
+ "tbs-rainbow.org",
+ "tbsec.org",
+ "tbsmalaysia.org",
+ "tbsn.org",
+ "tbsseattle.org",
+ "tbssqh.org",
+ "tbswd.org",
+ "tbtemple.org.uk",
+ "tbthouston.org",
+ "tccwonline.org",
+ "tcewf.org",
+ "tchrd.org",
+ "tcnynj.org",
+ "tcpspeed.co",
+ "tcpspeed.com",
+ "tcsofbc.org",
+ "tcsovi.org",
+ "tdesktop.com",
+ "tdm.com.mo",
+ "teachparentstech.org",
+ "teamamericany.com",
+ "technews.tw",
+ "techspot.com",
+ "techviz.net",
+ "teck.in",
+ "teco-hk.org",
+ "teco-mo.org",
+ "teddysun.com",
+ "teeniefuck.net",
+ "teensinasia.com",
+ "tehrantimes.com",
+ "telecomspace.com",
+ "telegra.ph",
+ "telegram.dog",
+ "telegram.me",
+ "telegram.org",
+ "telegramdownload.com",
+ "telegraph.co.uk",
+ "telesco.pe",
+ "tellme.pw",
+ "tenacy.com",
+ "tensorflow.org",
+ "tenzinpalmo.com",
+ "terabox.com",
+ "tew.org",
+ "textnow.me",
+ "tfhub.dev",
+ "tfiflve.com",
+ "thaicn.com",
+ "thb.gov.tw",
+ "theatlantic.com",
+ "theatrum-belli.com",
+ "theaustralian.com.au",
+ "thebcomplex.com",
+ "theblaze.com",
+ "theblemish.com",
+ "thebobs.com",
+ "thebodyshop-usa.com",
+ "thechinabeat.org",
+ "thechinacollection.org",
+ "thechinastory.org",
+ "theconversation.com",
+ "thedalailamamovie.com",
+ "thediplomat.com",
+ "thedw.us",
+ "theepochtimes.com",
+ "thefacebook.com",
+ "thefrontier.hk",
+ "thegay.com",
+ "thegioitinhoc.vn",
+ "thegly.com",
+ "theguardian.com",
+ "thehots.info",
+ "thehousenews.com",
+ "thehun.net",
+ "theinitium.com",
+ "themoviedb.org",
+ "thenewslens.com",
+ "thepiratebay.org",
+ "theporndude.com",
+ "theportalwiki.com",
+ "theprint.in",
+ "thereallove.kr",
+ "therock.net.nz",
+ "thesaturdaypaper.com.au",
+ "thestandnews.com",
+ "thetibetcenter.org",
+ "thetibetconnection.org",
+ "thetibetmuseum.org",
+ "thetibetpost.com",
+ "thetinhat.com",
+ "thetrotskymovie.com",
+ "thetvdb.com",
+ "thevivekspot.com",
+ "thewgo.org",
+ "theync.com",
+ "thinkgeek.com",
+ "thinkingtaiwan.com",
+ "thinkwithgoogle.com",
+ "thisav.com",
+ "thlib.org",
+ "thomasbernhard.org",
+ "thongdreams.com",
+ "threatchaos.com",
+ "throughnightsfire.com",
+ "thumbzilla.com",
+ "thywords.com",
+ "thywords.com.tw",
+ "tiananmenduizhi.com",
+ "tiananmenmother.org",
+ "tiananmenuniv.com",
+ "tiananmenuniv.net",
+ "tiandixing.org",
+ "tianhuayuan.com",
+ "tianlawoffice.com",
+ "tianti.io",
+ "tiantibooks.org",
+ "tianyantong.org.cn",
+ "tianzhu.org",
+ "tibet-envoy.eu",
+ "tibet-foundation.org",
+ "tibet-house-trust.co.uk",
+ "tibet-initiative.de",
+ "tibet-munich.de",
+ "tibet.a.se",
+ "tibet.at",
+ "tibet.ca",
+ "tibet.com",
+ "tibet.fr",
+ "tibet.net",
+ "tibet.nu",
+ "tibet.org",
+ "tibet.org.tw",
+ "tibet.sk",
+ "tibet.to",
+ "tibet3rdpole.org",
+ "tibetaction.net",
+ "tibetaid.org",
+ "tibetalk.com",
+ "tibetan-alliance.org",
+ "tibetan.fr",
+ "tibetanaidproject.org",
+ "tibetanarts.org",
+ "tibetanbuddhistinstitute.org",
+ "tibetancommunity.org",
+ "tibetancommunityuk.net",
+ "tibetanculture.org",
+ "tibetanentrepreneurs.org",
+ "tibetanfeministcollective.org",
+ "tibetanhealth.org",
+ "tibetanjournal.com",
+ "tibetanlanguage.org",
+ "tibetanliberation.org",
+ "tibetanpaintings.com",
+ "tibetanphotoproject.com",
+ "tibetanpoliticalreview.org",
+ "tibetanreview.net",
+ "tibetansports.org",
+ "tibetanwomen.org",
+ "tibetanyouth.org",
+ "tibetanyouthcongress.org",
+ "tibetcharity.dk",
+ "tibetcharity.in",
+ "tibetchild.org",
+ "tibetcity.com",
+ "tibetcollection.com",
+ "tibetcorps.org",
+ "tibetexpress.net",
+ "tibetfocus.com",
+ "tibetfund.org",
+ "tibetgermany.com",
+ "tibetgermany.de",
+ "tibethaus.com",
+ "tibetheritagefund.org",
+ "tibethouse.jp",
+ "tibethouse.org",
+ "tibethouse.us",
+ "tibetinfonet.net",
+ "tibetjustice.org",
+ "tibetkomite.dk",
+ "tibetmuseum.org",
+ "tibetnetwork.org",
+ "tibetoffice.ch",
+ "tibetoffice.com.au",
+ "tibetoffice.eu",
+ "tibetoffice.org",
+ "tibetonline.com",
+ "tibetonline.tv",
+ "tibetoralhistory.org",
+ "tibetpolicy.eu",
+ "tibetrelieffund.co.uk",
+ "tibetsites.com",
+ "tibetsociety.com",
+ "tibetsun.com",
+ "tibetsupportgroup.org",
+ "tibetswiss.ch",
+ "tibettelegraph.com",
+ "tibettimes.net",
+ "tibetwrites.org",
+ "ticket.com.tw",
+ "tigervpn.com",
+ "tiktok.com",
+ "tiltbrush.com",
+ "timdir.com",
+ "time.com",
+ "timesnownews.com",
+ "timsah.com",
+ "timtales.com",
+ "tinc-vpn.org",
+ "tiney.com",
+ "tineye.com",
+ "tintuc101.com",
+ "tiny.cc",
+ "tinychat.com",
+ "tinypaste.com",
+ "tipas.net",
+ "tipo.gov.tw",
+ "tistory.com",
+ "tkcs-collins.com",
+ "tl.gd",
+ "tma.co.jp",
+ "tmagazine.com",
+ "tmdfish.com",
+ "tmi.me",
+ "tmpp.org",
+ "tnaflix.com",
+ "tngrnow.com",
+ "tngrnow.net",
+ "tnp.org",
+ "to-porno.com",
+ "togetter.com",
+ "toh.info",
+ "tokyo-247.com",
+ "tokyo-hot.com",
+ "tokyo-porn-tube.com",
+ "tokyocn.com",
+ "tomonews.net",
+ "tongil.or.kr",
+ "tono-oka.jp",
+ "tonyyan.net",
+ "toodoc.com",
+ "toonel.net",
+ "top.tv",
+ "top10vpn.com",
+ "top81.ws",
+ "topbtc.com",
+ "topnews.in",
+ "toppornsites.com",
+ "topshareware.com",
+ "topsy.com",
+ "toptip.ca",
+ "tora.to",
+ "torcn.com",
+ "torguard.net",
+ "torlock.com",
+ "torproject.org",
+ "torrentkitty.tv",
+ "torrentprivacy.com",
+ "torrentproject.se",
+ "torrenty.org",
+ "torrentz.eu",
+ "torvpn.com",
+ "totalvpn.com",
+ "toutiaoabc.com",
+ "towngain.com",
+ "toypark.in",
+ "toythieves.com",
+ "toytractorshow.com",
+ "tparents.org",
+ "tpi.org.tw",
+ "tracfone.com",
+ "tradingview.com",
+ "translate.goog",
+ "translate.google",
+ "transparency.org",
+ "treemall.com.tw",
+ "trendsmap.com",
+ "trialofccp.org",
+ "trickip.net",
+ "trickip.org",
+ "trimondi.de",
+ "tronscan.org",
+ "trouw.nl",
+ "trt.net.tr",
+ "trtc.com.tw",
+ "truebuddha-md.org",
+ "trulyergonomic.com",
+ "truthontour.org",
+ "truthsocial.com",
+ "truveo.com",
+ "tryheart.jp",
+ "tsctv.net",
+ "tsemtulku.com",
+ "tsquare.tv",
+ "tsu.org.tw",
+ "tsunagarumon.com",
+ "tt1069.com",
+ "tttan.com",
+ "ttv.com.tw",
+ "ttvnw.net",
+ "tu8964.com",
+ "tubaholic.com",
+ "tube.com",
+ "tube8.com",
+ "tube911.com",
+ "tubecup.com",
+ "tubegals.com",
+ "tubeislam.com",
+ "tubepornclassic.com",
+ "tubestack.com",
+ "tubewolf.com",
+ "tuibeitu.net",
+ "tuidang.net",
+ "tuidang.org",
+ "tuidang.se",
+ "tuitui.info",
+ "tuitwit.com",
+ "tumblr.com",
+ "tumutanzi.com",
+ "tumview.com",
+ "tunein.com",
+ "tunnelbear.com",
+ "tunnelblick.net",
+ "tunnelr.com",
+ "tunsafe.com",
+ "turansam.org",
+ "turbobit.net",
+ "turbohide.com",
+ "turbotwitter.com",
+ "turkistantimes.com",
+ "turntable.fm",
+ "tushycash.com",
+ "tutanota.com",
+ "tuvpn.com",
+ "tuzaijidi.com",
+ "tv.com",
+ "tv.google",
+ "tvants.com",
+ "tvb.com",
+ "tvboxnow.com",
+ "tvbs.com.tw",
+ "tvider.com",
+ "tvmost.com.hk",
+ "tvplayvideos.com",
+ "tvunetworks.com",
+ "tw-blog.com",
+ "tw-npo.org",
+ "tw01.org",
+ "twaitter.com",
+ "twapperkeeper.com",
+ "twaud.io",
+ "twavi.com",
+ "twbbs.net.tw",
+ "twbbs.org",
+ "twbbs.tw",
+ "twblogger.com",
+ "tweepguide.com",
+ "tweeplike.me",
+ "tweepmag.com",
+ "tweepml.org",
+ "tweetbackup.com",
+ "tweetboard.com",
+ "tweetboner.biz",
+ "tweetcs.com",
+ "tweetdeck.com",
+ "tweetedtimes.com",
+ "tweetmylast.fm",
+ "tweetphoto.com",
+ "tweetrans.com",
+ "tweetree.com",
+ "tweettunnel.com",
+ "tweetwally.com",
+ "tweetymail.com",
+ "tweez.net",
+ "twelve.today",
+ "twerkingbutt.com",
+ "twftp.org",
+ "twgreatdaily.com",
+ "twibase.com",
+ "twibble.de",
+ "twibbon.com",
+ "twibs.com",
+ "twicountry.org",
+ "twicsy.com",
+ "twiends.com",
+ "twifan.com",
+ "twiffo.com",
+ "twiggit.org",
+ "twilightsex.com",
+ "twilio.com",
+ "twilog.org",
+ "twimbow.com",
+ "twimg.com",
+ "twindexx.com",
+ "twip.me",
+ "twipple.jp",
+ "twishort.com",
+ "twistar.cc",
+ "twister.net.co",
+ "twisterio.com",
+ "twisternow.com",
+ "twistory.net",
+ "twit2d.com",
+ "twitbrowser.net",
+ "twitcause.com",
+ "twitch.tv",
+ "twitchcdn.net",
+ "twitgether.com",
+ "twitgoo.com",
+ "twitiq.com",
+ "twitlonger.com",
+ "twitmania.com",
+ "twitoaster.com",
+ "twitonmsn.com",
+ "twitpic.com",
+ "twitstat.com",
+ "twittbot.net",
+ "twitter.com",
+ "twitter.jp",
+ "twitter4j.org",
+ "twittercounter.com",
+ "twitterfeed.com",
+ "twittergadget.com",
+ "twitterkr.com",
+ "twittermail.com",
+ "twitterrific.com",
+ "twittertim.es",
+ "twitthat.com",
+ "twitturk.com",
+ "twitturly.com",
+ "twitvid.com",
+ "twitzap.com",
+ "twiyia.com",
+ "twnorth.org.tw",
+ "twreporter.org",
+ "twskype.com",
+ "twstar.net",
+ "twt.tl",
+ "twtkr.com",
+ "twtrland.com",
+ "twttr.com",
+ "twurl.nl",
+ "twyac.org",
+ "txxx.com",
+ "tycool.com",
+ "typepad.com",
+ "typora.io",
+ "u15.info",
+ "u9un.com",
+ "ub0.cc",
+ "ubddns.org",
+ "uberproxy.net",
+ "uc-japan.org",
+ "ucam.org",
+ "ucanews.com",
+ "ucdc1998.org",
+ "uchicago.edu",
+ "uderzo.it",
+ "udn.com",
+ "udn.com.tw",
+ "udnbkk.com",
+ "uforadio.com.tw",
+ "ufreevpn.com",
+ "ugo.com",
+ "uhdwallpapers.org",
+ "uhrp.org",
+ "uighur.nl",
+ "uighurbiz.net",
+ "uk.to",
+ "ukcdp.co.uk",
+ "ukliferadio.co.uk",
+ "uku.im",
+ "ulike.net",
+ "ulop.net",
+ "ultravpn.fr",
+ "ultraxs.com",
+ "umich.edu",
+ "unblock-us.com",
+ "unblockdmm.com",
+ "unblocker.yt",
+ "unblocksit.es",
+ "uncyclomedia.org",
+ "uncyclopedia.hk",
+ "uncyclopedia.tw",
+ "underwoodammo.com",
+ "unholyknight.com",
+ "uni.cc",
+ "unicode.org",
+ "unification.net",
+ "unification.org.tw",
+ "unirule.cloud",
+ "unitedsocialpress.com",
+ "unix100.com",
+ "unknownspace.org",
+ "unodedos.com",
+ "unpo.org",
+ "unseen.is",
+ "unstable.icu",
+ "untraceable.us",
+ "uocn.org",
+ "updatestar.com",
+ "upghsbc.com",
+ "upholdjustice.org",
+ "upload4u.info",
+ "uploaded.net",
+ "uploaded.to",
+ "uploadstation.com",
+ "upmedia.mg",
+ "upornia.com",
+ "uproxy.org",
+ "uptodown.com",
+ "upwill.org",
+ "ur7s.com",
+ "uraban.me",
+ "urbandictionary.com",
+ "urbansurvival.com",
+ "urchin.com",
+ "url.com.tw",
+ "url.tw",
+ "urlborg.com",
+ "urlparser.com",
+ "us.to",
+ "usacn.com",
+ "usaip.eu",
+ "usc.edu",
+ "uscnpm.org",
+ "usembassy.gov",
+ "usfk.mil",
+ "usma.edu",
+ "usmc.mil",
+ "usocctn.com",
+ "uspto.gov",
+ "ustibetcommittee.org",
+ "ustream.tv",
+ "usus.cc",
+ "utopianpal.com",
+ "uu-gg.com",
+ "uukanshu.com",
+ "uvwxyz.xyz",
+ "uwants.com",
+ "uwants.net",
+ "uyghur-j.org",
+ "uyghur.co.uk",
+ "uyghuraa.org",
+ "uyghuramerican.org",
+ "uyghurbiz.org",
+ "uyghurcanadian.ca",
+ "uyghurcongress.org",
+ "uyghurpen.org",
+ "uyghurpress.com",
+ "uyghurstudies.org",
+ "uyghurtribunal.com",
+ "uygur.org",
+ "uymaarip.com",
+ "v2ex.com",
+ "v2fly.org",
+ "v2ray.com",
+ "v2raycn.com",
+ "v2raytech.com",
+ "valeursactuelles.com",
+ "van001.com",
+ "van698.com",
+ "vanemu.cn",
+ "vanilla-jp.com",
+ "vanpeople.com",
+ "vansky.com",
+ "vaticannews.va",
+ "vatn.org",
+ "vcf-online.org",
+ "vcfbuilder.org",
+ "vegasred.com",
+ "velkaepocha.sk",
+ "venbbs.com",
+ "venchina.com",
+ "venetianmacao.com",
+ "ventureswell.com",
+ "veoh.com",
+ "vercel.app",
+ "verizon.net",
+ "vermonttibet.org",
+ "versavpn.com",
+ "verybs.com",
+ "vevo.com",
+ "vft.com.tw",
+ "viber.com",
+ "vica.info",
+ "victimsofcommunism.org",
+ "vid.me",
+ "vidble.com",
+ "videobam.com",
+ "videodetective.com",
+ "videomega.tv",
+ "videomo.com",
+ "videopediaworld.com",
+ "videopress.com",
+ "vidinfo.org",
+ "vietdaikynguyen.com",
+ "vijayatemple.org",
+ "vilavpn.com",
+ "vimeo.com",
+ "vimperator.org",
+ "vincnd.com",
+ "vine.co",
+ "vinniev.com",
+ "vip-enterprise.com",
+ "virginia.edu",
+ "virtualrealporn.com",
+ "visibletweets.com",
+ "visiontimes.com",
+ "vital247.org",
+ "viu.com",
+ "viu.tv",
+ "vivahentai4u.net",
+ "vivaldi.com",
+ "vivatube.com",
+ "vivthomas.com",
+ "vizvaz.com",
+ "vjav.com",
+ "vjmedia.com.hk",
+ "vllcs.org",
+ "vmixcore.com",
+ "vmpsoft.com",
+ "vnet.link",
+ "voa.mobi",
+ "voacambodia.com",
+ "voacantonese.com",
+ "voachinese.com",
+ "voachineseblog.com",
+ "voagd.com",
+ "voaindonesia.com",
+ "voanews.com",
+ "voatibetan.com",
+ "voatibetanenglish.com",
+ "vocativ.com",
+ "vocn.tv",
+ "vocus.cc",
+ "voicettank.org",
+ "vot.org",
+ "vovo2000.com",
+ "voxer.com",
+ "voy.com",
+ "vpn.ac",
+ "vpn4all.com",
+ "vpnaccount.org",
+ "vpnaccounts.com",
+ "vpnbook.com",
+ "vpncomparison.org",
+ "vpncoupons.com",
+ "vpncup.com",
+ "vpndada.com",
+ "vpnfan.com",
+ "vpnfire.com",
+ "vpnfires.biz",
+ "vpnforgame.net",
+ "vpngate.jp",
+ "vpngate.net",
+ "vpngratis.net",
+ "vpnhq.com",
+ "vpnhub.com",
+ "vpninja.net",
+ "vpnintouch.com",
+ "vpnintouch.net",
+ "vpnjack.com",
+ "vpnmaster.com",
+ "vpnmentor.com",
+ "vpnpick.com",
+ "vpnpop.com",
+ "vpnpronet.com",
+ "vpnreactor.com",
+ "vpnreviewz.com",
+ "vpnsecure.me",
+ "vpnshazam.com",
+ "vpnshieldapp.com",
+ "vpnsp.com",
+ "vpntraffic.com",
+ "vpntunnel.com",
+ "vpnuk.info",
+ "vpnunlimitedapp.com",
+ "vpnvip.com",
+ "vpnworldwide.com",
+ "vporn.com",
+ "vpser.net",
+ "vraiesagesse.net",
+ "vrmtr.com",
+ "vrsmash.com",
+ "vs.com",
+ "vtunnel.com",
+ "vuku.cc",
+ "vultryhw.com",
+ "vzw.com",
+ "w3.org",
+ "w3schools.com",
+ "waffle1999.com",
+ "wahas.com",
+ "waigaobu.com",
+ "waikeung.org",
+ "wailaike.net",
+ "wainao.me",
+ "waiwaier.com",
+ "wallmama.com",
+ "wallornot.org",
+ "wallpapercasa.com",
+ "wallproxy.com",
+ "wallsttv.com",
+ "waltermartin.com",
+ "waltermartin.org",
+ "wan-press.org",
+ "wanderinghorse.net",
+ "wangafu.net",
+ "wangjinbo.org",
+ "wanglixiong.com",
+ "wango.org",
+ "wangruoshui.net",
+ "wangruowang.org",
+ "want-daily.com",
+ "wanz-factory.com",
+ "wapedia.mobi",
+ "warehouse333.com",
+ "warroom.org",
+ "waselpro.com",
+ "washeng.net",
+ "washingtonpost.com",
+ "watch8x.com",
+ "watchinese.com",
+ "watchmygf.net",
+ "watchout.tw",
+ "wattpad.com",
+ "wav.tv",
+ "waveprotocol.org",
+ "waymo.com",
+ "wda.gov.tw",
+ "wdf5.com",
+ "wealth.com.tw",
+ "wearehairy.com",
+ "wearn.com",
+ "weather.com.hk",
+ "web.dev",
+ "web2project.net",
+ "webbang.net",
+ "webevader.org",
+ "webfreer.com",
+ "webjb.org",
+ "weblagu.com",
+ "webmproject.org",
+ "webpack.de",
+ "webrtc.org",
+ "webrush.net",
+ "webs-tv.net",
+ "websitepulse.com",
+ "websnapr.com",
+ "webwarper.net",
+ "webworkerdaily.com",
+ "wechatlawsuit.com",
+ "weekmag.info",
+ "wefightcensorship.org",
+ "wefong.com",
+ "weiboleak.com",
+ "weihuo.org",
+ "weijingsheng.org",
+ "weiming.info",
+ "weiquanwang.org",
+ "weisuo.ws",
+ "welovecock.com",
+ "welt.de",
+ "wemigrate.org",
+ "wengewang.com",
+ "wengewang.org",
+ "wenhui.ch",
+ "wenweipo.com",
+ "wenxuecity.com",
+ "wenyunchao.com",
+ "wenzhao.ca",
+ "westca.com",
+ "westernshugdensociety.org",
+ "westernwolves.com",
+ "westkit.net",
+ "westpoint.edu",
+ "wetplace.com",
+ "wetpussygames.com",
+ "wexiaobo.org",
+ "wezhiyong.org",
+ "wezone.net",
+ "wforum.com",
+ "wha.la",
+ "whatblocked.com",
+ "whatbrowser.org",
+ "whatsapp.com",
+ "whatsapp.net",
+ "whatsonweibo.com",
+ "wheatseeds.org",
+ "wheelockslatin.com",
+ "whereiswerner.com",
+ "wheretowatch.com",
+ "whippedass.com",
+ "whispersystems.org",
+ "whodns.xyz",
+ "whoer.net",
+ "whotalking.com",
+ "whylover.com",
+ "whyx.org",
+ "widevine.com",
+ "wikaba.com",
+ "wikia.com",
+ "wikileaks-forum.com",
+ "wikileaks.ch",
+ "wikileaks.com",
+ "wikileaks.de",
+ "wikileaks.eu",
+ "wikileaks.lu",
+ "wikileaks.org",
+ "wikileaks.pl",
+ "wikilivres.info",
+ "wikimapia.org",
+ "wikimedia.org",
+ "wikinews.org",
+ "wikipedia.org",
+ "wikiquote.org",
+ "wikisource.org",
+ "wikiwand.com",
+ "wikiwiki.jp",
+ "wildammo.com",
+ "williamhill.com",
+ "willw.net",
+ "windowsphoneme.com",
+ "windscribe.com",
+ "windy.com",
+ "wingamestore.com",
+ "wingy.site",
+ "winning11.com",
+ "winwhispers.info",
+ "wionews.com",
+ "wire.com",
+ "wiredbytes.com",
+ "wiredpen.com",
+ "wireguard.com",
+ "wisdompubs.org",
+ "wisevid.com",
+ "wistia.com",
+ "withgoogle.com",
+ "withyoutube.com",
+ "witnessleeteaching.com",
+ "witopia.net",
+ "wizcrafts.net",
+ "wjbk.org",
+ "wn.com",
+ "wnacg.com",
+ "wnacg.org",
+ "wo.tc",
+ "woeser.com",
+ "woesermiddle-way.net",
+ "wokar.org",
+ "wolfax.com",
+ "wombo.ai",
+ "woolyss.com",
+ "woopie.jp",
+ "woopie.tv",
+ "wordpress.com",
+ "workatruna.com",
+ "workerdemo.org.hk",
+ "workerempowerment.org",
+ "workers.dev",
+ "workersthebig.net",
+ "workflow.is",
+ "worldcat.org",
+ "worldjournal.com",
+ "worldvpn.net",
+ "wow-life.net",
+ "wow.com",
+ "wowgirls.com",
+ "wowhead.com",
+ "wowlegacy.ml",
+ "wowporn.com",
+ "wowrk.com",
+ "woxinghuiguo.com",
+ "woyaolian.org",
+ "wozy.in",
+ "wp.com",
+ "wpoforum.com",
+ "wqyd.org",
+ "wrchina.org",
+ "wretch.cc",
+ "wsj.com",
+ "wsj.net",
+ "wsjhk.com",
+ "wtbn.org",
+ "wtfpeople.com",
+ "wuerkaixi.com",
+ "wufafangwen.com",
+ "wufi.org.tw",
+ "wuguoguang.com",
+ "wujie.net",
+ "wujieliulan.com",
+ "wukangrui.net",
+ "wuw.red",
+ "wuyanblog.com",
+ "wwe.com",
+ "wwitv.com",
+ "www1.biz",
+ "wwwhost.biz",
+ "wzyboy.im",
+ "x-art.com",
+ "x-berry.com",
+ "x-wall.org",
+ "x.co",
+ "x.company",
+ "x1949x.com",
+ "x24hr.com",
+ "x365x.com",
+ "xanga.com",
+ "xbabe.com",
+ "xbookcn.com",
+ "xbtce.com",
+ "xcafe.in",
+ "xcity.jp",
+ "xcritic.com",
+ "xda-developers.com",
+ "xerotica.com",
+ "xfiles.to",
+ "xfinity.com",
+ "xgmyd.com",
+ "xhamster.com",
+ "xianba.net",
+ "xianchawang.net",
+ "xianjian.tw",
+ "xianqiao.net",
+ "xiaobaiwu.com",
+ "xiaochuncnjp.com",
+ "xiaod.in",
+ "xiaohexie.com",
+ "xiaolan.me",
+ "xiaoma.org",
+ "xiaxiaoqiang.net",
+ "xiezhua.com",
+ "xihua.es",
+ "xinbao.de",
+ "xing.com",
+ "xinhuanet.org",
+ "xinjiangpolicefiles.org",
+ "xinmiao.com.hk",
+ "xinsheng.net",
+ "xinshijue.com",
+ "xinyubbs.net",
+ "xiongpian.com",
+ "xiuren.org",
+ "xixicui.icu",
+ "xizang-zhiye.org",
+ "xjp.cc",
+ "xjtravelguide.com",
+ "xkiwi.tk",
+ "xlfmtalk.com",
+ "xlfmwz.info",
+ "xm.com",
+ "xml-training-guide.com",
+ "xmovies.com",
+ "xn--4gq171p.com",
+ "xn--9pr62r24a.com",
+ "xn--czq75pvv1aj5c.org",
+ "xn--i2ru8q2qg.com",
+ "xn--ngstr-lra8j.com",
+ "xn--oiq.cc",
+ "xn--p8j9a0d9c9a.xn--q9jyb4c",
+ "xnxx.com",
+ "xpdo.net",
+ "xpud.org",
+ "xrentdvd.com",
+ "xsden.info",
+ "xskywalker.com",
+ "xskywalker.net",
+ "xtube.com",
+ "xuchao.net",
+ "xuchao.org",
+ "xuehua.us",
+ "xuite.net",
+ "xuzhiyong.net",
+ "xvbelink.com",
+ "xvideo.cc",
+ "xvideos-cdn.com",
+ "xvideos.com",
+ "xvideos.es",
+ "xvinlink.com",
+ "xxbbx.com",
+ "xxlmovies.com",
+ "xxuz.com",
+ "xxx.com",
+ "xxx.xxx",
+ "xxxfuckmom.com",
+ "xxxx.com.au",
+ "xxxy.biz",
+ "xxxy.info",
+ "xxxymovies.com",
+ "xys.org",
+ "xysblogs.org",
+ "xyy69.com",
+ "xyy69.info",
+ "y2mate.com",
+ "yadi.sk",
+ "yahoo.co.jp",
+ "yahoo.com",
+ "yahoo.com.hk",
+ "yahoo.com.tw",
+ "yahoo.net",
+ "yakbutterblues.com",
+ "yam.com",
+ "yam.org.tw",
+ "yande.re",
+ "yandex.com",
+ "yanghengjun.com",
+ "yangjianli.com",
+ "yasni.co.uk",
+ "yayabay.com",
+ "ycombinator.com",
+ "ydy.com",
+ "yeahteentube.com",
+ "yecl.net",
+ "yeelou.com",
+ "yeeyi.com",
+ "yegle.net",
+ "yes-news.com",
+ "yes.xxx",
+ "yes123.com.tw",
+ "yesasia.com",
+ "yesasia.com.hk",
+ "yespornplease.com",
+ "yeyeclub.com",
+ "ygto.com",
+ "yhcw.net",
+ "yibada.com",
+ "yibaochina.com",
+ "yidio.com",
+ "yigeni.com",
+ "yilubbs.com",
+ "yimg.com",
+ "yingsuoss.com",
+ "yinlei.org",
+ "yipub.com",
+ "yiyechat.com",
+ "yizhihongxing.com",
+ "yobit.net",
+ "yobt.com",
+ "yobt.tv",
+ "yogichen.org",
+ "yolasite.com",
+ "yomiuri.co.jp",
+ "yong.hu",
+ "yorkbbs.ca",
+ "you-get.org",
+ "youdontcare.com",
+ "youjizz.com",
+ "youmaker.com",
+ "youngpornvideos.com",
+ "youngspiration.hk",
+ "youpai.org",
+ "youporn.com",
+ "youporngay.com",
+ "your-freedom.net",
+ "yourepeat.com",
+ "yourlisten.com",
+ "yourlust.com",
+ "yourprivatevpn.com",
+ "yourtrap.com",
+ "yousendit.com",
+ "youshun12.com",
+ "youthforfreechina.org",
+ "youthnetradio.org",
+ "youthwant.com.tw",
+ "youtu.be",
+ "youtube-nocookie.com",
+ "youtube.com",
+ "youtubecn.com",
+ "youtubeeducation.com",
+ "youtubegaming.com",
+ "youtubekids.com",
+ "youversion.com",
+ "youwin.com",
+ "youxu.info",
+ "yt.be",
+ "ytht.net",
+ "ytimg.com",
+ "ytn.co.kr",
+ "yuanming.net",
+ "yuanzhengtang.org",
+ "yulghun.com",
+ "yunchao.net",
+ "yuntipub.com",
+ "yuvutu.com",
+ "yvesgeleyn.com",
+ "ywpw.com",
+ "yx51.net",
+ "yyii.org",
+ "yyjlymb.xyz",
+ "yzzk.com",
+ "z-lib.org",
+ "zacebook.com",
+ "zalmos.com",
+ "zannel.com",
+ "zaobao.com",
+ "zaobao.com.sg",
+ "zaozon.com",
+ "zapto.org",
+ "zattoo.com",
+ "zb.com",
+ "zdnet.com.tw",
+ "zello.com",
+ "zengjinyan.org",
+ "zenmate.com",
+ "zerohedge.com",
+ "zeronet.io",
+ "zeutch.com",
+ "zfreet.com",
+ "zgsddh.com",
+ "zgzcjj.net",
+ "zhanbin.net",
+ "zhangboli.net",
+ "zhangtianliang.com",
+ "zhanlve.org",
+ "zhenghui.org",
+ "zhengjian.org",
+ "zhengwunet.org",
+ "zhenlibu.info",
+ "zhenlibu1984.com",
+ "zhenxiang.biz",
+ "zhinengluyou.com",
+ "zhongguo.ca",
+ "zhongguorenquan.org",
+ "zhongguotese.net",
+ "zhongmeng.org",
+ "zhoushuguang.com",
+ "zhreader.com",
+ "zhuangbi.me",
+ "zhuanxing.cn",
+ "zhuatieba.com",
+ "zhuichaguoji.org",
+ "zi.media",
+ "zi5.me",
+ "ziddu.com",
+ "zillionk.com",
+ "zim.vn",
+ "zinio.com",
+ "ziporn.com",
+ "zippyshare.com",
+ "zkaip.com",
+ "zkiz.com",
+ "zmw.cn",
+ "zodgame.us",
+ "zoho.com",
+ "zomobo.net",
+ "zonaeuropa.com",
+ "zonghexinwen.com",
+ "zonghexinwen.net",
+ "zoogvpn.com",
+ "zootool.com",
+ "zoozle.net",
+ "zophar.net",
+ "zorrovpn.com",
+ "zozotown.com",
+ "zpn.im",
+ "zspeeder.me",
+ "zsrhao.com",
+ "zuo.la",
+ "zuobiao.me",
+ "zuola.com",
+ "zvereff.com",
+ "zynaima.com",
+ "zynamics.com",
+ "zyns.com",
+ "zyxel.com",
+ "zyzc9.com",
+ "zzcartoon.com",
+ "zzcloud.me",
+ "zzux.com",
+ "chat.openai.com"
+ ]
+ ]
+];
+
+var lastRule = '';
+
+function FindProxyForURL(url, host) {
+ for (var i = 0; i < rules.length; i++) {
+ ret = testHost(host, i);
+ if (ret != undefined)
+ return ret;
+ }
+ return 'DIRECT';
+}
+
+function testHost(host, index) {
+ for (var i = 0; i < rules[index].length; i++) {
+ for (var j = 0; j < rules[index][i].length; j++) {
+ lastRule = rules[index][i][j];
+ if (host == lastRule || host.endsWith('.' + lastRule))
+ return i % 2 == 0 ? 'DIRECT' : proxy;
+ }
+ }
+ lastRule = '';
+}
+
+// REF: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith
+if (!String.prototype.endsWith) {
+ String.prototype.endsWith = function(searchString, position) {
+ var subjectString = this.toString();
+ if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) {
+ position = subjectString.length;
+ }
+ position -= searchString.length;
+ var lastIndex = subjectString.indexOf(searchString, position);
+ return lastIndex !== -1 && lastIndex === position;
+ };
+}
diff --git a/v2rayMiniConsole/ProtosLib/ProtosLib.csproj b/v2rayMiniConsole/ProtosLib/ProtosLib.csproj
new file mode 100644
index 00000000..81cc41f9
--- /dev/null
+++ b/v2rayMiniConsole/ProtosLib/ProtosLib.csproj
@@ -0,0 +1,20 @@
+
+
+ net8.0
+ enable
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
diff --git a/v2rayMiniConsole/ProtosLib/Statistics.proto b/v2rayMiniConsole/ProtosLib/Statistics.proto
new file mode 100644
index 00000000..db96ac02
--- /dev/null
+++ b/v2rayMiniConsole/ProtosLib/Statistics.proto
@@ -0,0 +1,53 @@
+syntax = "proto3";
+
+package v2ray.core.app.stats.command;
+option csharp_namespace = "ProtosLib.Statistics";
+
+message GetStatsRequest {
+ // Name of the stat counter.
+ string name = 1;
+ // Whether or not to reset the counter to fetching its value.
+ bool reset = 2;
+}
+
+message Stat {
+ string name = 1;
+ int64 value = 2;
+}
+
+message GetStatsResponse {
+ Stat stat = 1;
+}
+
+message QueryStatsRequest {
+ string pattern = 1;
+ bool reset = 2;
+}
+
+message QueryStatsResponse {
+ repeated Stat stat = 1;
+}
+
+message SysStatsRequest {
+}
+
+message SysStatsResponse {
+ uint32 NumGoroutine = 1;
+ uint32 NumGC = 2;
+ uint64 Alloc = 3;
+ uint64 TotalAlloc = 4;
+ uint64 Sys = 5;
+ uint64 Mallocs = 6;
+ uint64 Frees = 7;
+ uint64 LiveObjects = 8;
+ uint64 PauseTotalNs = 9;
+ uint32 Uptime = 10;
+}
+
+service StatsService {
+ rpc GetStats(GetStatsRequest) returns (GetStatsResponse) {}
+ rpc QueryStats(QueryStatsRequest) returns (QueryStatsResponse) {}
+ rpc GetSysStats(SysStatsRequest) returns (SysStatsResponse) {}
+}
+
+message Config {}
diff --git a/v2rayMiniConsole/ProtosLib/Tests.cs b/v2rayMiniConsole/ProtosLib/Tests.cs
new file mode 100644
index 00000000..e1eb85b1
--- /dev/null
+++ b/v2rayMiniConsole/ProtosLib/Tests.cs
@@ -0,0 +1,13 @@
+using ProtosLib.Statistics;
+
+namespace ProtosLib
+{
+ public class Tests
+ {
+ private StatsService.StatsServiceClient client_;
+
+ public Tests()
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/build.ps1 b/v2rayMiniConsole/build.ps1
new file mode 100644
index 00000000..506888d7
--- /dev/null
+++ b/v2rayMiniConsole/build.ps1
@@ -0,0 +1,39 @@
+param (
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $OutputPath = '.\bin\v2rayMiniConsole'
+)
+
+Write-Host 'Building'
+
+dotnet publish `
+ .\v2rayMiniConsole\v2rayMiniConsole.csproj `
+ -c Release `
+ --self-contained false `
+ -p:PublishReadyToRun=true `
+ -p:PublishSingleFile=true `
+ -o $OutputPath
+
+dotnet publish `
+ .\v2rayUpgrade\v2rayUpgrade.csproj `
+ -c Release `
+ --self-contained false `
+ -p:PublishReadyToRun=true `
+ -p:PublishSingleFile=true `
+ -o $OutputPath
+
+if ( -Not $? ) {
+ exit $lastExitCode
+ }
+
+if ( Test-Path -Path .\bin\v2rayMiniConsole ) {
+ rm -Force "$OutputPath\*.pdb"
+ rm -Force "$OutputPath\*.xml"
+}
+
+Write-Host 'Build done'
+
+ls $OutputPath
+7z.exe a v2rayMiniConsole.zip $OutputPath
+exit 0
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole.sln b/v2rayMiniConsole/v2rayMiniConsole.sln
new file mode 100644
index 00000000..167e3870
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole.sln
@@ -0,0 +1,42 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34511.84
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "v2rayMiniConsole", "v2rayMiniConsole\v2rayMiniConsole.csproj", "{C8323215-8D45-4358-84EA-C4EA3257A72E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PacLib", "PacLib\PacLib.csproj", "{42DAD4B6-7B75-4924-85DA-4BF143F11278}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtosLib", "ProtosLib\ProtosLib.csproj", "{B8338E4D-728C-4BC8-9E4C-5707903B6DDD}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{A915ED0D-4CA4-405C-A342-D7AD4DF567D3}"
+ ProjectSection(SolutionItems) = preProject
+ .gitignore = .gitignore
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C8323215-8D45-4358-84EA-C4EA3257A72E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C8323215-8D45-4358-84EA-C4EA3257A72E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C8323215-8D45-4358-84EA-C4EA3257A72E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C8323215-8D45-4358-84EA-C4EA3257A72E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {42DAD4B6-7B75-4924-85DA-4BF143F11278}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {42DAD4B6-7B75-4924-85DA-4BF143F11278}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {42DAD4B6-7B75-4924-85DA-4BF143F11278}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {42DAD4B6-7B75-4924-85DA-4BF143F11278}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B8338E4D-728C-4BC8-9E4C-5707903B6DDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B8338E4D-728C-4BC8-9E4C-5707903B6DDD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B8338E4D-728C-4BC8-9E4C-5707903B6DDD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B8338E4D-728C-4BC8-9E4C-5707903B6DDD}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {19B3D25E-4C3A-4FAC-A76F-BFBD2EF88ECA}
+ EndGlobalSection
+EndGlobal
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Common/DownloaderHelper.cs b/v2rayMiniConsole/v2rayMiniConsole/Common/DownloaderHelper.cs
new file mode 100644
index 00000000..335727eb
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Common/DownloaderHelper.cs
@@ -0,0 +1,186 @@
+using Downloader;
+using System.IO;
+using System.Net;
+
+namespace v2rayN
+{
+ internal class DownloaderHelper
+ {
+ private static readonly Lazy _instance = new(() => new());
+ public static DownloaderHelper Instance => _instance.Value;
+
+ public async Task DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout)
+ {
+ if (Utils.IsNullOrEmpty(url))
+ {
+ return null;
+ }
+
+ Uri uri = new(url);
+ //Authorization Header
+ var headers = new WebHeaderCollection();
+ if (!Utils.IsNullOrEmpty(uri.UserInfo))
+ {
+ headers.Add(HttpRequestHeader.Authorization, "Basic " + Utils.Base64Encode(uri.UserInfo));
+ }
+
+ var downloadOpt = new DownloadConfiguration()
+ {
+ Timeout = timeout * 1000,
+ MaxTryAgainOnFailover = 2,
+ RequestConfiguration =
+ {
+ Headers = headers,
+ UserAgent = userAgent,
+ Timeout = timeout * 1000,
+ Proxy = webProxy
+ }
+ };
+
+ using var downloader = new DownloadService(downloadOpt);
+ downloader.DownloadFileCompleted += (sender, value) =>
+ {
+ if (value.Error != null)
+ {
+ throw value.Error;
+ }
+ };
+
+ using var cts = new CancellationTokenSource();
+ using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token);
+ using StreamReader reader = new(stream);
+
+ downloadOpt = null;
+
+ return reader.ReadToEnd();
+ }
+
+ public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress progress, int timeout)
+ {
+ if (Utils.IsNullOrEmpty(url))
+ {
+ throw new ArgumentNullException(nameof(url));
+ }
+
+ var downloadOpt = new DownloadConfiguration()
+ {
+ Timeout = timeout * 1000,
+ MaxTryAgainOnFailover = 2,
+ RequestConfiguration =
+ {
+ Timeout= timeout * 1000,
+ Proxy = webProxy
+ }
+ };
+
+ DateTime totalDatetime = DateTime.Now;
+ int totalSecond = 0;
+ var hasValue = false;
+ double maxSpeed = 0;
+ using var downloader = new DownloadService(downloadOpt);
+ //downloader.DownloadStarted += (sender, value) =>
+ //{
+ // if (progress != null)
+ // {
+ // progress.Report("Start download data...");
+ // }
+ //};
+ downloader.DownloadProgressChanged += (sender, value) =>
+ {
+ TimeSpan ts = (DateTime.Now - totalDatetime);
+ if (progress != null && ts.Seconds > totalSecond)
+ {
+ hasValue = true;
+ totalSecond = ts.Seconds;
+ if (value.BytesPerSecondSpeed > maxSpeed)
+ {
+ maxSpeed = value.BytesPerSecondSpeed;
+ var speed = (maxSpeed / 1000 / 1000).ToString("#0.0");
+ progress.Report(speed);
+ }
+ }
+ };
+ downloader.DownloadFileCompleted += (sender, value) =>
+ {
+ if (progress != null)
+ {
+ if (!hasValue && value.Error != null)
+ {
+ progress.Report(value.Error?.Message);
+ }
+ }
+ };
+ //progress.Report("......");
+ using var cts = new CancellationTokenSource();
+ cts.CancelAfter(timeout * 1000);
+ // downloader库的这个调用可能有内存泄露,是导致测速过程中内存持续增加的原因
+ using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token);
+ downloadOpt = null;
+ await downloader.Clear();
+ downloader?.Dispose();
+ stream?.Close();
+ stream?.Dispose();
+ GC.Collect();
+ }
+
+ public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress progress, int timeout)
+ {
+ if (Utils.IsNullOrEmpty(url))
+ {
+ throw new ArgumentNullException(nameof(url));
+ }
+ if (Utils.IsNullOrEmpty(fileName))
+ {
+ throw new ArgumentNullException(nameof(fileName));
+ }
+ if (File.Exists(fileName))
+ {
+ File.Delete(fileName);
+ }
+
+ var downloadOpt = new DownloadConfiguration()
+ {
+ Timeout = timeout * 1000,
+ MaxTryAgainOnFailover = 2,
+ RequestConfiguration =
+ {
+ Timeout= timeout * 1000,
+ Proxy = webProxy
+ }
+ };
+
+ var progressPercentage = 0;
+ var hasValue = false;
+ using var downloader = new DownloadService(downloadOpt);
+ downloader.DownloadStarted += (sender, value) =>
+ {
+ progress?.Report(0);
+ };
+ downloader.DownloadProgressChanged += (sender, value) =>
+ {
+ hasValue = true;
+ var percent = (int)value.ProgressPercentage;// Convert.ToInt32((totalRead * 1d) / (total * 1d) * 100);
+ if (progressPercentage != percent && percent % 10 == 0)
+ {
+ progressPercentage = percent;
+ progress.Report(percent);
+ }
+ };
+ downloader.DownloadFileCompleted += (sender, value) =>
+ {
+ if (progress != null)
+ {
+ if (hasValue && value.Error == null)
+ {
+ progress.Report(101);
+ }
+ }
+ };
+
+ using var cts = new CancellationTokenSource();
+ await downloader.DownloadFileTaskAsync(url, fileName, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token);
+
+ downloadOpt = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Common/FileManager.cs b/v2rayMiniConsole/v2rayMiniConsole/Common/FileManager.cs
new file mode 100644
index 00000000..b721f5db
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Common/FileManager.cs
@@ -0,0 +1,90 @@
+using System.IO;
+using System.IO.Compression;
+using System.Text;
+
+namespace v2rayN
+{
+ public static class FileManager
+ {
+ public static bool ByteArrayToFile(string fileName, byte[] content)
+ {
+ try
+ {
+ File.WriteAllBytes(fileName, content);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ return false;
+ }
+
+ public static void UncompressedFile(string fileName, byte[] content)
+ {
+ try
+ {
+ using FileStream fs = File.Create(fileName);
+ using GZipStream input = new(new MemoryStream(content), CompressionMode.Decompress, false);
+ input.CopyTo(fs);
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ }
+
+ public static string NonExclusiveReadAllText(string path)
+ {
+ return NonExclusiveReadAllText(path, Encoding.Default);
+ }
+
+ public static string NonExclusiveReadAllText(string path, Encoding encoding)
+ {
+ try
+ {
+ using FileStream fs = new(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+ using StreamReader sr = new(fs, encoding);
+ return sr.ReadToEnd();
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ throw;
+ }
+ }
+
+ public static bool ZipExtractToFile(string fileName, string toPath, string ignoredName)
+ {
+ try
+ {
+ using ZipArchive archive = ZipFile.OpenRead(fileName);
+ foreach (ZipArchiveEntry entry in archive.Entries)
+ {
+ if (entry.Length == 0)
+ {
+ continue;
+ }
+ try
+ {
+ if (!Utils.IsNullOrEmpty(ignoredName) && entry.Name.Contains(ignoredName))
+ {
+ continue;
+ }
+ entry.ExtractToFile(Path.Combine(toPath, entry.Name), true);
+ }
+ catch (IOException ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ return false;
+ }
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Common/HttpClientHelper.cs b/v2rayMiniConsole/v2rayMiniConsole/Common/HttpClientHelper.cs
new file mode 100644
index 00000000..60f9ad2b
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Common/HttpClientHelper.cs
@@ -0,0 +1,188 @@
+using System.IO;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Net.Mime;
+using System.Text;
+
+namespace v2rayN
+{
+ ///
+ ///
+ public class HttpClientHelper
+ {
+ private static readonly Lazy _instance = new(() =>
+ {
+ HttpClientHandler handler = new() { UseCookies = false };
+ HttpClientHelper helper = new(new HttpClient(handler));
+ return helper;
+ });
+
+ public static HttpClientHelper Instance => _instance.Value;
+ private readonly HttpClient httpClient;
+
+ private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient;
+
+ public async Task TryGetAsync(string url)
+ {
+ if (string.IsNullOrEmpty(url))
+ return null;
+
+ try
+ {
+ HttpResponseMessage response = await httpClient.GetAsync(url);
+ return await response.Content.ReadAsStringAsync();
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
+ public async Task GetAsync(string url)
+ {
+ if (Utils.IsNullOrEmpty(url)) return null;
+ return await httpClient.GetStringAsync(url);
+ }
+
+ public async Task GetAsync(HttpClient client, string url, CancellationToken token = default)
+ {
+ if (Utils.IsNullOrEmpty(url)) return null;
+ return await client.GetStringAsync(url, token);
+ }
+
+ public async Task PutAsync(string url, Dictionary headers)
+ {
+ var jsonContent = JsonUtils.Serialize(headers);
+ var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json);
+
+ var result = await httpClient.PutAsync(url, content);
+ }
+
+ public async Task PatchAsync(string url, Dictionary headers)
+ {
+ var myContent = JsonUtils.Serialize(headers);
+ var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
+ var byteContent = new ByteArrayContent(buffer);
+ byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
+
+ await httpClient.PatchAsync(url, byteContent);
+ }
+
+ public async Task DeleteAsync(string url)
+ {
+ await httpClient.DeleteAsync(url);
+ }
+
+ public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress? progress, CancellationToken token = default)
+ {
+ ArgumentNullException.ThrowIfNull(url);
+ ArgumentNullException.ThrowIfNull(fileName);
+ if (File.Exists(fileName)) File.Delete(fileName);
+
+ using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
+
+ if (!response.IsSuccessStatusCode) throw new Exception(response.StatusCode.ToString());
+
+ var total = response.Content.Headers.ContentLength ?? -1L;
+ var canReportProgress = total != -1 && progress != null;
+
+ using var stream = await response.Content.ReadAsStreamAsync(token);
+ using var file = File.Create(fileName);
+ var totalRead = 0L;
+ var buffer = new byte[1024 * 1024];
+ var progressPercentage = 0;
+
+ while (true)
+ {
+ token.ThrowIfCancellationRequested();
+
+ var read = await stream.ReadAsync(buffer, token);
+ totalRead += read;
+
+ if (read == 0) break;
+ file.Write(buffer, 0, read);
+
+ if (canReportProgress)
+ {
+ var percent = (int)(100.0 * totalRead / total);
+ //if (progressPercentage != percent && percent % 10 == 0)
+ {
+ progressPercentage = percent;
+ progress?.Report(percent);
+ }
+ }
+ }
+ if (canReportProgress)
+ {
+ progress?.Report(101);
+ }
+ }
+
+ public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress progress, CancellationToken token = default)
+ {
+ if (Utils.IsNullOrEmpty(url))
+ {
+ throw new ArgumentNullException(nameof(url));
+ }
+
+ var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ throw new Exception(response.StatusCode.ToString());
+ }
+
+ //var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L;
+ //var canReportProgress = total != -1 && progress != null;
+
+ using var stream = await response.Content.ReadAsStreamAsync(token);
+ var totalRead = 0L;
+ var buffer = new byte[1024 * 64];
+ var isMoreToRead = true;
+ string progressSpeed = string.Empty;
+ DateTime totalDatetime = DateTime.Now;
+ int totalSecond = 0;
+
+ do
+ {
+ if (token.IsCancellationRequested)
+ {
+ if (totalRead > 0)
+ {
+ return;
+ }
+ else
+ {
+ token.ThrowIfCancellationRequested();
+ }
+ }
+
+ var read = await stream.ReadAsync(buffer, token);
+
+ if (read == 0)
+ {
+ isMoreToRead = false;
+ }
+ else
+ {
+ var data = new byte[read];
+ buffer.ToList().CopyTo(0, data, 0, read);
+
+ totalRead += read;
+
+ TimeSpan ts = (DateTime.Now - totalDatetime);
+ if (progress != null && ts.Seconds > totalSecond)
+ {
+ totalSecond = ts.Seconds;
+ var speed = (totalRead * 1d / ts.TotalMilliseconds / 1000).ToString("#0.0");
+ if (progressSpeed != speed)
+ {
+ progressSpeed = speed;
+ progress.Report(speed);
+ }
+ }
+ }
+ } while (isMoreToRead);
+ }
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Common/Job.cs b/v2rayMiniConsole/v2rayMiniConsole/Common/Job.cs
new file mode 100644
index 00000000..c25a2221
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Common/Job.cs
@@ -0,0 +1,176 @@
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+namespace v2rayN
+{
+ /*
+ * See:
+ * http://stackoverflow.com/questions/6266820/working-example-of-createjobobject-setinformationjobobject-pinvoke-in-net
+ */
+
+ public class Job : IDisposable
+ {
+ private IntPtr handle = IntPtr.Zero;
+
+ public Job()
+ {
+ handle = CreateJobObject(IntPtr.Zero, null);
+ IntPtr extendedInfoPtr = IntPtr.Zero;
+ JOBOBJECT_BASIC_LIMIT_INFORMATION info = new()
+ {
+ LimitFlags = 0x2000
+ };
+
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new()
+ {
+ BasicLimitInformation = info
+ };
+
+ try
+ {
+ int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
+ extendedInfoPtr = Marshal.AllocHGlobal(length);
+ Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);
+
+ if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr,
+ (uint)length))
+ throw new Exception(string.Format("Unable to set information. Error: {0}",
+ Marshal.GetLastWin32Error()));
+ }
+ finally
+ {
+ if (extendedInfoPtr != IntPtr.Zero)
+ {
+ Marshal.FreeHGlobal(extendedInfoPtr);
+ }
+ }
+ }
+
+ public bool AddProcess(IntPtr processHandle)
+ {
+ bool succ = AssignProcessToJobObject(handle, processHandle);
+
+ if (!succ)
+ {
+ Logging.SaveLog("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error());
+ }
+
+ return succ;
+ }
+
+ public bool AddProcess(int processId)
+ {
+ return AddProcess(Process.GetProcessById(processId).Handle);
+ }
+
+ #region IDisposable
+
+ private bool disposed;
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposed) return;
+ disposed = true;
+
+ if (disposing)
+ {
+ // no managed objects to free
+ }
+
+ if (handle != IntPtr.Zero)
+ {
+ CloseHandle(handle);
+ handle = IntPtr.Zero;
+ }
+ }
+
+ ~Job()
+ {
+ Dispose(false);
+ }
+
+ #endregion IDisposable
+
+ #region Interop
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
+ private static extern IntPtr CreateJobObject(IntPtr a, string? lpName);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool CloseHandle(IntPtr hObject);
+
+ #endregion Interop
+ }
+
+ #region Helper classes
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct IO_COUNTERS
+ {
+ public UInt64 ReadOperationCount;
+ public UInt64 WriteOperationCount;
+ public UInt64 OtherOperationCount;
+ public UInt64 ReadTransferCount;
+ public UInt64 WriteTransferCount;
+ public UInt64 OtherTransferCount;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct JOBOBJECT_BASIC_LIMIT_INFORMATION
+ {
+ public Int64 PerProcessUserTimeLimit;
+ public Int64 PerJobUserTimeLimit;
+ public UInt32 LimitFlags;
+ public UIntPtr MinimumWorkingSetSize;
+ public UIntPtr MaximumWorkingSetSize;
+ public UInt32 ActiveProcessLimit;
+ public UIntPtr Affinity;
+ public UInt32 PriorityClass;
+ public UInt32 SchedulingClass;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SECURITY_ATTRIBUTES
+ {
+ public UInt32 nLength;
+ public IntPtr lpSecurityDescriptor;
+ public Int32 bInheritHandle;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
+ {
+ public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
+ public IO_COUNTERS IoInfo;
+ public UIntPtr ProcessMemoryLimit;
+ public UIntPtr JobMemoryLimit;
+ public UIntPtr PeakProcessMemoryUsed;
+ public UIntPtr PeakJobMemoryUsed;
+ }
+
+ public enum JobObjectInfoType
+ {
+ AssociateCompletionPortInformation = 7,
+ BasicLimitInformation = 2,
+ BasicUIRestrictions = 4,
+ EndOfJobTimeInformation = 6,
+ ExtendedLimitInformation = 9,
+ SecurityLimitInformation = 5,
+ GroupInformation = 11
+ }
+
+ #endregion Helper classes
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Common/JsonUtils.cs b/v2rayMiniConsole/v2rayMiniConsole/Common/JsonUtils.cs
new file mode 100644
index 00000000..ab81d41e
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Common/JsonUtils.cs
@@ -0,0 +1,134 @@
+using System.IO;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using System.Text.Json.Serialization;
+
+namespace v2rayN
+{
+ internal class JsonUtils
+ {
+ ///
+ /// DeepCopy
+ ///
+ ///
+ ///
+ ///
+ public static T DeepCopy(T obj)
+ {
+ return Deserialize(Serialize(obj, false))!;
+ }
+
+ ///
+ /// Deserialize to object
+ ///
+ ///
+ ///
+ ///
+ public static T? Deserialize(string? strJson)
+ {
+ try
+ {
+ if (string.IsNullOrWhiteSpace(strJson))
+ {
+ return default;
+ }
+ return JsonSerializer.Deserialize(strJson);
+ }
+ catch
+ {
+ return default;
+ }
+ }
+
+ ///
+ /// parse
+ ///
+ ///
+ ///
+ public static JsonNode? ParseJson(string strJson)
+ {
+ try
+ {
+ if (string.IsNullOrWhiteSpace(strJson))
+ {
+ return null;
+ }
+ return JsonNode.Parse(strJson);
+ }
+ catch
+ {
+ //SaveLog(ex.Message, ex);
+ return null;
+ }
+ }
+
+ ///
+ /// Serialize Object to Json string
+ ///
+ ///
+ ///
+ ///
+ public static string Serialize(object? obj, bool indented = true)
+ {
+ string result = string.Empty;
+ try
+ {
+ if (obj == null)
+ {
+ return result;
+ }
+ var options = new JsonSerializerOptions
+ {
+ WriteIndented = indented ? true : false,
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
+ };
+ result = JsonSerializer.Serialize(obj, options);
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ return result;
+ }
+
+ ///
+ /// SerializeToNode
+ ///
+ ///
+ ///
+ public static JsonNode? SerializeToNode(object? obj) => JsonSerializer.SerializeToNode(obj);
+
+ ///
+ /// Save as json file
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int ToFile(object? obj, string? filePath, bool nullValue = true)
+ {
+ if (filePath is null)
+ {
+ return -1;
+ }
+ try
+ {
+ using FileStream file = File.Create(filePath);
+
+ var options = new JsonSerializerOptions
+ {
+ WriteIndented = true,
+ DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull
+ };
+
+ JsonSerializer.Serialize(file, obj, options);
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ return -1;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Common/Logging.cs b/v2rayMiniConsole/v2rayMiniConsole/Common/Logging.cs
new file mode 100644
index 00000000..ba5b97e7
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Common/Logging.cs
@@ -0,0 +1,78 @@
+using NLog;
+using NLog.Config;
+using NLog.Targets;
+using System.IO;
+
+namespace v2rayN
+{
+ public class Logging
+ {
+ public static void Setup()
+ {
+ LoggingConfiguration config = new();
+ FileTarget fileTarget = new();
+ config.AddTarget("file", fileTarget);
+ fileTarget.Layout = "${longdate}-${level:uppercase=true} ${message}";
+ fileTarget.FileName = Utils.GetLogPath("${shortdate}.txt");
+ config.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, fileTarget));
+ LogManager.Configuration = config;
+ }
+
+ public static void LoggingEnabled(bool enable)
+ {
+ if (!enable)
+ {
+ LogManager.SuspendLogging();
+ }
+ }
+
+ public static void ClearLogs()
+ {
+ Task.Run(() =>
+ {
+ try
+ {
+ var now = DateTime.Now.AddMonths(-1);
+ var dir = Utils.GetLogPath();
+ var files = Directory.GetFiles(dir, "*.txt");
+ foreach (var filePath in files)
+ {
+ var file = new FileInfo(filePath);
+ if (file.CreationTime < now)
+ {
+ try
+ {
+ file.Delete();
+ }
+ catch { }
+ }
+ }
+ }
+ catch { }
+ });
+ }
+
+ public static void SaveLog(string strContent)
+ {
+ if (LogManager.IsLoggingEnabled())
+ {
+ var logger = LogManager.GetLogger("Log1");
+ logger.Info(strContent);
+ }
+ }
+
+ public static void SaveLog(string strTitle, Exception ex)
+ {
+ if (LogManager.IsLoggingEnabled())
+ {
+ var logger = LogManager.GetLogger("Log2");
+ logger.Debug($"{strTitle},{ex.Message}");
+ logger.Debug(ex.StackTrace);
+ if (ex?.InnerException != null)
+ {
+ logger.Error(ex.InnerException);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Common/QueryableExtension.cs b/v2rayMiniConsole/v2rayMiniConsole/Common/QueryableExtension.cs
new file mode 100644
index 00000000..113f2824
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Common/QueryableExtension.cs
@@ -0,0 +1,50 @@
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace v2rayN
+{
+ public static class QueryableExtension
+ {
+ public static IOrderedQueryable OrderBy(this IQueryable query, string propertyName)
+ {
+ return _OrderBy(query, propertyName, false);
+ }
+
+ public static IOrderedQueryable OrderByDescending(this IQueryable query, string propertyName)
+ {
+ return _OrderBy(query, propertyName, true);
+ }
+
+ private static IOrderedQueryable _OrderBy(IQueryable query, string propertyName, bool isDesc)
+ {
+ string methodname = (isDesc) ? "OrderByDescendingInternal" : "OrderByInternal";
+
+ var memberProp = typeof(T).GetProperty(propertyName);
+
+ var method = typeof(QueryableExtension).GetMethod(methodname)
+ .MakeGenericMethod(typeof(T), memberProp.PropertyType);
+
+ return (IOrderedQueryable)method.Invoke(null, new object[] { query, memberProp });
+ }
+
+ public static IOrderedQueryable OrderByInternal(IQueryable query, PropertyInfo memberProperty)
+ {//public
+ return query.OrderBy(_GetLambda(memberProperty));
+ }
+
+ public static IOrderedQueryable OrderByDescendingInternal(IQueryable query, PropertyInfo memberProperty)
+ {//public
+ return query.OrderByDescending(_GetLambda(memberProperty));
+ }
+
+ private static Expression> _GetLambda(PropertyInfo memberProperty)
+ {
+ if (memberProperty.PropertyType != typeof(TProp)) throw new Exception();
+
+ var thisArg = Expression.Parameter(typeof(T));
+ var lambda = Expression.Lambda>(Expression.Property(thisArg, memberProperty), thisArg);
+
+ return lambda;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Common/SemanticVersion.cs b/v2rayMiniConsole/v2rayMiniConsole/Common/SemanticVersion.cs
new file mode 100644
index 00000000..597ed970
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Common/SemanticVersion.cs
@@ -0,0 +1,180 @@
+namespace v2rayN
+{
+ public class SemanticVersion
+ {
+ private int major;
+ private int minor;
+ private int patch;
+ private string version;
+
+ public SemanticVersion(int major, int minor, int patch)
+ {
+ this.major = major;
+ this.minor = minor;
+ this.patch = patch;
+ this.version = $"{major}.{minor}.{patch}";
+ }
+
+ public SemanticVersion(string version)
+ {
+ this.version = version.RemovePrefix('v');
+ try
+ {
+ string[] parts = this.version.Split('.');
+ if (parts.Length == 2)
+ {
+ this.major = int.Parse(parts[0]);
+ this.minor = int.Parse(parts[1]);
+ this.patch = 0;
+ }
+ else if (parts.Length == 3)
+ {
+ this.major = int.Parse(parts[0]);
+ this.minor = int.Parse(parts[1]);
+ this.patch = int.Parse(parts[2]);
+ }
+ else
+ {
+ throw new ArgumentException("Invalid version string");
+ }
+ }
+ catch
+ {
+ this.major = 0;
+ this.minor = 0;
+ this.patch = 0;
+ //this.version = "0.0.0";
+ }
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (obj is SemanticVersion other)
+ {
+ return this.major == other.major && this.minor == other.minor && this.patch == other.patch;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ return this.major.GetHashCode() ^ this.minor.GetHashCode() ^ this.patch.GetHashCode();
+ }
+
+ ///
+ /// Use ToVersionString(string? prefix) instead if possible.
+ ///
+ /// major.minor.patch
+ public override string ToString()
+ {
+ return this.version;
+ }
+
+ public string ToVersionString(string? prefix = null)
+ {
+ if (prefix == null)
+ {
+ return this.version;
+ }
+ else
+ {
+ return $"{prefix}{this.version}";
+ }
+ }
+
+ public static bool operator ==(SemanticVersion v1, SemanticVersion v2)
+ { return v1.Equals(v2); }
+
+ public static bool operator !=(SemanticVersion v1, SemanticVersion v2)
+ { return !v1.Equals(v2); }
+
+ public static bool operator >=(SemanticVersion v1, SemanticVersion v2)
+ { return v1.GreaterEquals(v2); }
+
+ public static bool operator <=(SemanticVersion v1, SemanticVersion v2)
+ { return v1.LessEquals(v2); }
+
+ #region Private
+
+ private bool GreaterEquals(SemanticVersion other)
+ {
+ if (this.major < other.major)
+ {
+ return false;
+ }
+ else if (this.major > other.major)
+ {
+ return true;
+ }
+ else
+ {
+ if (this.minor < other.minor)
+ {
+ return false;
+ }
+ else if (this.minor > other.minor)
+ {
+ return true;
+ }
+ else
+ {
+ if (this.patch < other.patch)
+ {
+ return false;
+ }
+ else if (this.patch > other.patch)
+ {
+ return true;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ private bool LessEquals(SemanticVersion other)
+ {
+ if (this.major < other.major)
+ {
+ return true;
+ }
+ else if (this.major > other.major)
+ {
+ return false;
+ }
+ else
+ {
+ if (this.minor < other.minor)
+ {
+ return true;
+ }
+ else if (this.minor > other.minor)
+ {
+ return false;
+ }
+ else
+ {
+ if (this.patch < other.patch)
+ {
+ return true;
+ }
+ else if (this.patch > other.patch)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ #endregion Private
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Common/SqliteHelper.cs b/v2rayMiniConsole/v2rayMiniConsole/Common/SqliteHelper.cs
new file mode 100644
index 00000000..70beb810
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Common/SqliteHelper.cs
@@ -0,0 +1,123 @@
+using SQLite;
+using System.Collections;
+
+namespace v2rayN
+{
+ public sealed class SQLiteHelper
+ {
+ private static readonly Lazy _instance = new(() => new());
+ public static SQLiteHelper Instance => _instance.Value;
+ private string _connstr;
+ private SQLiteConnection _db;
+ private SQLiteAsyncConnection _dbAsync;
+ private static readonly object objLock = new();
+ public readonly string _configDB = "guiNDB.db";
+
+ public SQLiteHelper()
+ {
+ _connstr = Utils.GetConfigPath(_configDB);
+ _db = new SQLiteConnection(_connstr, false);
+ _dbAsync = new SQLiteAsyncConnection(_connstr, false);
+ }
+
+ public CreateTableResult CreateTable()
+ {
+ return _db.CreateTable();
+ }
+
+ public int Insert(object model)
+ {
+ return _db.Insert(model);
+ }
+
+ public int InsertAll(IEnumerable models)
+ {
+ lock (objLock)
+ {
+ return _db.InsertAll(models);
+ }
+ }
+
+ public async Task InsertAsync(object model)
+ {
+ return await _dbAsync.InsertAsync(model);
+ }
+
+ public int Replace(object model)
+ {
+ lock (objLock)
+ {
+ return _db.InsertOrReplace(model);
+ }
+ }
+
+ public async Task ReplaceAsync(object model)
+ {
+ return await _dbAsync.InsertOrReplaceAsync(model);
+ }
+
+ public int Update(object model)
+ {
+ lock (objLock)
+ {
+ return _db.Update(model);
+ }
+ }
+
+ public async Task UpdateAsync(object model)
+ {
+ return await _dbAsync.UpdateAsync(model);
+ }
+
+ public int UpdateAll(IEnumerable models)
+ {
+ lock (objLock)
+ {
+ return _db.UpdateAll(models);
+ }
+ }
+
+ public int Delete(object model)
+ {
+ lock (objLock)
+ {
+ return _db.Delete(model);
+ }
+ }
+
+ public async Task DeleteAsync(object model)
+ {
+ return await _dbAsync.DeleteAsync(model);
+ }
+
+ public List Query(string sql) where T : new()
+ {
+ return _db.Query(sql);
+ }
+
+ public async Task> QueryAsync(string sql) where T : new()
+ {
+ return await _dbAsync.QueryAsync(sql);
+ }
+
+ public int Execute(string sql)
+ {
+ return _db.Execute(sql);
+ }
+
+ public async Task ExecuteAsync(string sql)
+ {
+ return await _dbAsync.ExecuteAsync(sql);
+ }
+
+ public TableQuery Table() where T : new()
+ {
+ return _db.Table();
+ }
+
+ public AsyncTableQuery TableAsync() where T : new()
+ {
+ return _dbAsync.Table();
+ }
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Common/StringEx.cs b/v2rayMiniConsole/v2rayMiniConsole/Common/StringEx.cs
new file mode 100644
index 00000000..9a751ce9
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Common/StringEx.cs
@@ -0,0 +1,94 @@
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+
+namespace v2rayN
+{
+ internal static class StringEx
+ {
+ public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
+ {
+ return string.IsNullOrEmpty(value);
+ }
+
+ public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value)
+ {
+ return string.IsNullOrWhiteSpace(value);
+ }
+
+ public static bool BeginWithAny(this string s, IEnumerable chars)
+ {
+ if (s.IsNullOrEmpty()) return false;
+ return chars.Contains(s[0]);
+ }
+
+ public static bool IsWhiteSpace(this string value)
+ {
+ foreach (char c in value)
+ {
+ if (char.IsWhiteSpace(c)) continue;
+
+ return false;
+ }
+ return true;
+ }
+
+ public static IEnumerable NonWhiteSpaceLines(this TextReader reader)
+ {
+ string? line;
+ while ((line = reader.ReadLine()) != null)
+ {
+ if (line.IsWhiteSpace()) continue;
+ yield return line;
+ }
+ }
+
+ public static string TrimEx(this string? value)
+ {
+ return value == null ? string.Empty : value.Trim();
+ }
+
+ public static string RemovePrefix(this string value, char prefix)
+ {
+ if (value.StartsWith(prefix))
+ {
+ return value.Substring(1);
+ }
+ else
+ {
+ return value;
+ }
+ }
+
+ public static string RemovePrefix(this string value, string prefix)
+ {
+ if (value.StartsWith(prefix))
+ {
+ return value.Substring(prefix.Length);
+ }
+ else
+ {
+ return value;
+ }
+ }
+
+ public static string UpperFirstChar(this string value)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ return string.Empty;
+ }
+
+ return char.ToUpper(value[0]) + value.Substring(1);
+ }
+
+ public static string AppendQuotes(this string value)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ return string.Empty;
+ }
+
+ return $"\"{value}\"";
+ }
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Common/Utils.cs b/v2rayMiniConsole/v2rayMiniConsole/Common/Utils.cs
new file mode 100644
index 00000000..c430370a
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Common/Utils.cs
@@ -0,0 +1,1127 @@
+using Microsoft.Win32;
+using Microsoft.Win32.TaskScheduler;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.Drawing;
+using System.IO;
+using System.IO.Compression;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Net.Sockets;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Principal;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Windows.Forms;
+
+
+namespace v2rayN
+{
+ internal class Utils
+ {
+ #region 资源Json操作
+
+ ///
+ /// 获取嵌入文本资源
+ ///
+ ///
+ ///
+ public static string GetEmbedText(string res)
+ {
+ string result = string.Empty;
+
+ try
+ {
+ Assembly assembly = Assembly.GetExecutingAssembly();
+ using Stream? stream = assembly.GetManifestResourceStream(res);
+ ArgumentNullException.ThrowIfNull(stream);
+ using StreamReader reader = new(stream);
+ result = reader.ReadToEnd();
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ return result;
+ }
+
+ ///
+ /// 取得存储资源
+ ///
+ ///
+ public static string? LoadResource(string? res)
+ {
+ try
+ {
+ if (!File.Exists(res))
+ {
+ return null;
+ }
+ return File.ReadAllText(res);
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ return null;
+ }
+
+ #endregion 资源Json操作
+
+ #region 转换函数
+
+ ///
+ /// List转逗号分隔的字符串
+ ///
+ ///
+ ///
+ public static string List2String(List? lst, bool wrap = false)
+ {
+ try
+ {
+ if (lst == null)
+ {
+ return string.Empty;
+ }
+ if (wrap)
+ {
+ return string.Join("," + Environment.NewLine, lst);
+ }
+ else
+ {
+ return string.Join(",", lst);
+ }
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ return string.Empty;
+ }
+ }
+
+ ///
+ /// 逗号分隔的字符串,转List
+ ///
+ ///
+ ///
+ public static List String2List(string str)
+ {
+ try
+ {
+ str = str.Replace(Environment.NewLine, "");
+ return new List(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ return new List();
+ }
+ }
+
+ ///
+ /// 逗号分隔的字符串,先排序后转List
+ ///
+ ///
+ ///
+ public static List String2ListSorted(string str)
+ {
+ try
+ {
+ str = str.Replace(Environment.NewLine, "");
+ List list = new(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
+ list.Sort();
+ return list;
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ return new List();
+ }
+ }
+
+ ///
+ /// Base64编码
+ ///
+ ///
+ ///
+ public static string Base64Encode(string plainText)
+ {
+ try
+ {
+ byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
+ return Convert.ToBase64String(plainTextBytes);
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog("Base64Encode", ex);
+ return string.Empty;
+ }
+ }
+
+ ///
+ /// Base64解码
+ ///
+ ///
+ ///
+ public static string Base64Decode(string plainText)
+ {
+ try
+ {
+ plainText = plainText.Trim()
+ .Replace(Environment.NewLine, "")
+ .Replace("\n", "")
+ .Replace("\r", "")
+ .Replace('_', '/')
+ .Replace('-', '+')
+ .Replace(" ", "");
+
+ if (plainText.Length % 4 > 0)
+ {
+ plainText = plainText.PadRight(plainText.Length + 4 - plainText.Length % 4, '=');
+ }
+
+ byte[] data = Convert.FromBase64String(plainText);
+ return Encoding.UTF8.GetString(data);
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog("Base64Decode", ex);
+ return string.Empty;
+ }
+ }
+
+ ///
+ /// 转Int
+ ///
+ ///
+ ///
+ public static int ToInt(object? obj)
+ {
+ try
+ {
+ return Convert.ToInt32(obj ?? string.Empty);
+ }
+ catch //(Exception ex)
+ {
+ //SaveLog(ex.Message, ex);
+ return 0;
+ }
+ }
+
+ public static bool ToBool(object obj)
+ {
+ try
+ {
+ return Convert.ToBoolean(obj);
+ }
+ catch //(Exception ex)
+ {
+ //SaveLog(ex.Message, ex);
+ return false;
+ }
+ }
+
+ public static string ToString(object obj)
+ {
+ try
+ {
+ return obj?.ToString() ?? string.Empty;
+ }
+ catch// (Exception ex)
+ {
+ //SaveLog(ex.Message, ex);
+ return string.Empty;
+ }
+ }
+
+ ///
+ /// byte 转成 有两位小数点的 方便阅读的数据
+ /// 比如 2.50 MB
+ ///
+ /// bytes
+ /// 转换之后的数据
+ /// 单位
+ public static void ToHumanReadable(long amount, out double result, out string unit)
+ {
+ uint factor = 1024u;
+ //long KBs = amount / factor;
+ long KBs = amount;
+ if (KBs > 0)
+ {
+ // multi KB
+ long MBs = KBs / factor;
+ if (MBs > 0)
+ {
+ // multi MB
+ long GBs = MBs / factor;
+ if (GBs > 0)
+ {
+ // multi GB
+ long TBs = GBs / factor;
+ if (TBs > 0)
+ {
+ result = TBs + ((GBs % factor) / (factor + 0.0));
+ unit = "TB";
+ return;
+ }
+ result = GBs + ((MBs % factor) / (factor + 0.0));
+ unit = "GB";
+ return;
+ }
+ result = MBs + ((KBs % factor) / (factor + 0.0));
+ unit = "MB";
+ return;
+ }
+ result = KBs + ((amount % factor) / (factor + 0.0));
+ unit = "KB";
+ return;
+ }
+ else
+ {
+ result = amount;
+ unit = "B";
+ }
+ }
+
+ public static string HumanFy(long amount)
+ {
+ ToHumanReadable(amount, out double result, out string unit);
+ return $"{string.Format("{0:f1}", result)} {unit}";
+ }
+
+ public static string UrlEncode(string url)
+ {
+ return Uri.EscapeDataString(url);
+ //return HttpUtility.UrlEncode(url);
+ }
+
+ public static string UrlDecode(string url)
+ {
+ return Uri.UnescapeDataString(url);
+ //return HttpUtility.UrlDecode(url);
+ }
+
+ public static NameValueCollection ParseQueryString(string query)
+ {
+ var result = new NameValueCollection(StringComparer.OrdinalIgnoreCase);
+ if (IsNullOrEmpty(query))
+ {
+ return result;
+ }
+
+ var parts = query[1..].Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
+ foreach (var part in parts)
+ {
+ var keyValue = part.Split(['=']);
+ if (keyValue.Length != 2)
+ {
+ continue;
+ }
+ var key = Uri.UnescapeDataString(keyValue[0]);
+ var val = Uri.UnescapeDataString(keyValue[1]);
+
+ if (result[key] is null)
+ {
+ result.Add(key, val);
+ }
+ }
+
+ return result;
+ }
+
+ public static string GetMD5(string str)
+ {
+ byte[] byteOld = Encoding.UTF8.GetBytes(str);
+ byte[] byteNew = MD5.HashData(byteOld);
+ StringBuilder sb = new(32);
+ foreach (byte b in byteNew)
+ {
+ sb.Append(b.ToString("x2"));
+ }
+ return sb.ToString();
+ }
+
+ ///
+ /// idn to idc
+ ///
+ ///
+ ///
+ public static string GetPunycode(string url)
+ {
+ if (Utils.IsNullOrEmpty(url))
+ {
+ return url;
+ }
+ try
+ {
+ Uri uri = new(url);
+ if (uri.Host == uri.IdnHost || uri.Host == $"[{uri.IdnHost}]")
+ {
+ return url;
+ }
+ else
+ {
+ return url.Replace(uri.Host, uri.IdnHost);
+ }
+ }
+ catch
+ {
+ return url;
+ }
+ }
+
+ public static bool IsBase64String(string plainText)
+ {
+ var buffer = new Span(new byte[plainText.Length]);
+ return Convert.TryFromBase64String(plainText, buffer, out int _);
+ }
+
+ public static string Convert2Comma(string text)
+ {
+ if (Utils.IsNullOrEmpty(text))
+ {
+ return text;
+ }
+ return text.Replace(",", ",").Replace(Environment.NewLine, ",");
+ }
+
+ #endregion 转换函数
+
+ #region 数据检查
+
+ ///
+ /// 判断输入的是否是数字
+ ///
+ ///
+ ///
+ public static bool IsNumeric(string oText)
+ {
+ try
+ {
+ int var1 = ToInt(oText);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ return false;
+ }
+ }
+
+ ///
+ /// 文本
+ ///
+ ///
+ ///
+ public static bool IsNullOrEmpty(string? text)
+ {
+ if (string.IsNullOrWhiteSpace(text))
+ {
+ return true;
+ }
+ if (text == "null")
+ {
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// 验证IP地址是否合法
+ ///
+ ///
+ public static bool IsIP(string ip)
+ {
+ //如果为空
+ if (IsNullOrEmpty(ip))
+ {
+ return false;
+ }
+
+ //清除要验证字符串中的空格
+ //ip = ip.TrimEx();
+ //可能是CIDR
+ if (ip.IndexOf(@"/") > 0)
+ {
+ string[] cidr = ip.Split('/');
+ if (cidr.Length == 2)
+ {
+ if (!IsNumeric(cidr[0]))
+ {
+ return false;
+ }
+ ip = cidr[0];
+ }
+ }
+
+ //模式字符串
+ string pattern = @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$";
+
+ //验证
+ return IsMatch(ip, pattern);
+ }
+
+ ///
+ /// 验证Domain地址是否合法
+ ///
+ ///
+ public static bool IsDomain(string? domain)
+ {
+ //如果为空
+ if (IsNullOrEmpty(domain))
+ {
+ return false;
+ }
+
+ return Uri.CheckHostName(domain) == UriHostNameType.Dns;
+ }
+
+ public static bool IsValidUrl(string? url)
+ {
+ if (string.IsNullOrWhiteSpace(url))
+ {
+ return false;
+ }
+
+ Uri result;
+ // 尝试将字符串转换为Uri实例
+ bool success = Uri.TryCreate(url, UriKind.Absolute, out result)
+ && (result.Scheme == Uri.UriSchemeHttp || result.Scheme == Uri.UriSchemeHttps);
+
+ // 注意:这里还检查了URL是否是HTTP或HTTPS协议
+ // 如果需要接受其他协议,请删除或修改此检查
+ return success;
+ }
+
+ ///
+ /// 验证输入字符串是否与模式字符串匹配,匹配返回true
+ ///
+ /// 输入字符串
+ /// 模式字符串
+ public static bool IsMatch(string input, string pattern)
+ {
+ return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
+ }
+
+ public static bool IsIpv6(string ip)
+ {
+ if (IPAddress.TryParse(ip, out IPAddress? address))
+ {
+ return address.AddressFamily switch
+ {
+ AddressFamily.InterNetwork => false,
+ AddressFamily.InterNetworkV6 => true,
+ _ => false,
+ };
+ }
+ return false;
+ }
+
+ #endregion 数据检查
+
+ #region 测速
+
+ ///
+ /// 取得本机 IP Address
+ ///
+ ///
+ //public static List GetHostIPAddress()
+ //{
+ // List lstIPAddress = new List();
+ // try
+ // {
+ // IPHostEntry IpEntry = Dns.GetHostEntry(Dns.GetHostName());
+ // foreach (IPAddress ipa in IpEntry.AddressList)
+ // {
+ // if (ipa.AddressFamily == AddressFamily.InterNetwork)
+ // lstIPAddress.Add(ipa.ToString());
+ // }
+ // }
+ // catch (Exception ex)
+ // {
+ // SaveLog(ex.Message, ex);
+ // }
+ // return lstIPAddress;
+ //}
+
+ public static void SetSecurityProtocol(bool enableSecurityProtocolTls13)
+ {
+ if (enableSecurityProtocolTls13)
+ {
+ ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;
+ }
+ else
+ {
+ ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
+ }
+ ServicePointManager.DefaultConnectionLimit = 256;
+ }
+
+ public static bool PortInUse(int port)
+ {
+ bool inUse = false;
+ try
+ {
+ IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
+ IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners();
+
+ var lstIpEndPoints = new List(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
+
+ foreach (IPEndPoint endPoint in ipEndPoints)
+ {
+ if (endPoint.Port == port)
+ {
+ inUse = true;
+ break;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ return inUse;
+ }
+
+ public static int GetFreePort(int defaultPort = 9090)
+ {
+ try
+ {
+ if (!Utils.PortInUse(defaultPort))
+ {
+ return defaultPort;
+ }
+
+ TcpListener l = new(IPAddress.Loopback, 0);
+ l.Start();
+ int port = ((IPEndPoint)l.LocalEndpoint).Port;
+ l.Stop();
+ return port;
+ }
+ catch
+ {
+ }
+ return 59090;
+ }
+
+ #endregion 测速
+
+ #region 杂项
+
+ ///
+ /// 取得版本
+ ///
+ ///
+ public static string GetVersion(bool blFull = true)
+ {
+ try
+ {
+ string location = GetExePath();
+ if (blFull)
+ {
+ return string.Format("v2rayMiniConsole - V{0} - {1}",
+ FileVersionInfo.GetVersionInfo(location).FileVersion?.ToString(),
+ File.GetLastWriteTime(location).ToString("yyyy/MM/dd"));
+ }
+ else
+ {
+ return string.Format("v2rayMiniConsole - V{0}",
+ FileVersionInfo.GetVersionInfo(location).FileVersion?.ToString());
+ }
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ return string.Empty;
+ }
+ }
+
+ ///
+ /// 获取剪贴板数
+ ///
+ ///
+ public static string? GetClipboardData()
+ {
+ string? strData = string.Empty;
+ try
+ {
+ IDataObject data = Clipboard.GetDataObject();
+ if (data.GetDataPresent(DataFormats.UnicodeText))
+ {
+ strData = data.GetData(DataFormats.UnicodeText)?.ToString();
+ }
+ return strData;
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ return strData;
+ }
+
+ ///
+ /// 拷贝至剪贴板
+ ///
+ ///
+ public static void SetClipboardData(string strData)
+ {
+ try
+ {
+ Clipboard.SetText(strData);
+ }
+ catch
+ {
+ }
+ }
+
+ ///
+ /// 取得GUID
+ ///
+ ///
+ public static string GetGUID(bool full = true)
+ {
+ try
+ {
+ if (full)
+ {
+ return Guid.NewGuid().ToString("D");
+ }
+ else
+ {
+ return BitConverter.ToInt64(Guid.NewGuid().ToByteArray(), 0).ToString();
+ }
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ return string.Empty;
+ }
+
+ ///
+ /// IsAdministrator
+ ///
+ ///
+ public static bool IsAdministrator()
+ {
+ try
+ {
+ WindowsIdentity current = WindowsIdentity.GetCurrent();
+ WindowsPrincipal windowsPrincipal = new WindowsPrincipal(current);
+ //WindowsBuiltInRole可以枚举出很多权限,例如系统用户、User、Guest等等
+ return windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ return false;
+ }
+ }
+
+ public static string GetDownloadFileName(string url)
+ {
+ var fileName = Path.GetFileName(url);
+ fileName += "_temp";
+
+ return fileName;
+ }
+
+ public static IPAddress? GetDefaultGateway()
+ {
+ return NetworkInterface
+ .GetAllNetworkInterfaces()
+ .Where(n => n.OperationalStatus == OperationalStatus.Up)
+ .Where(n => n.NetworkInterfaceType != NetworkInterfaceType.Loopback)
+ .SelectMany(n => n.GetIPProperties()?.GatewayAddresses)
+ .Select(g => g?.Address)
+ .Where(a => a != null)
+ // .Where(a => a.AddressFamily == AddressFamily.InterNetwork)
+ // .Where(a => Array.FindIndex(a.GetAddressBytes(), b => b != 0) >= 0)
+ .FirstOrDefault();
+ }
+
+ public static bool IsGuidByParse(string strSrc)
+ {
+ return Guid.TryParse(strSrc, out Guid g);
+ }
+
+ public static void ProcessStart(string fileName, string arguments = "")
+ {
+ try
+ {
+ Process.Start(new ProcessStartInfo(fileName, arguments) { UseShellExecute = true });
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ }
+
+ public static bool IsLightTheme()
+ {
+ using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
+ var value = key?.GetValue("AppsUseLightTheme");
+ return value is int i && i > 0;
+ }
+
+ ///
+ /// 获取系统hosts
+ ///
+ ///
+ public static Dictionary GetSystemHosts()
+ {
+ var systemHosts = new Dictionary();
+ var hostfile = @"C:\Windows\System32\drivers\etc\hosts";
+ try
+ {
+ if (File.Exists(hostfile))
+ {
+ var hosts = File.ReadAllText(hostfile).Replace("\r", "");
+ var hostsList = hosts.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
+
+ foreach (var host in hostsList)
+ {
+ if (host.StartsWith("#")) continue;
+ var hostItem = host.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
+ if (hostItem.Length < 2) continue;
+ systemHosts.Add(hostItem[1], hostItem[0]);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ return systemHosts;
+ }
+
+ #endregion 杂项
+
+ #region TempPath
+
+ ///
+ /// 获取启动了应用程序的可执行文件的路径
+ ///
+ ///
+ public static string GetPath(string fileName)
+ {
+ string startupPath = StartupPath();
+ if (IsNullOrEmpty(fileName))
+ {
+ return startupPath;
+ }
+ return Path.Combine(startupPath, fileName);
+ }
+
+ ///
+ /// 获取启动了应用程序的可执行文件的路径及文件名
+ ///
+ ///
+ public static string GetExePath()
+ {
+ return Environment.ProcessPath ?? string.Empty;
+ }
+
+ public static string StartupPath()
+ {
+ return AppDomain.CurrentDomain.BaseDirectory;
+ }
+
+ public static string GetTempPath(string filename = "")
+ {
+ string _tempPath = Path.Combine(StartupPath(), "guiTemps");
+ if (!Directory.Exists(_tempPath))
+ {
+ Directory.CreateDirectory(_tempPath);
+ }
+ if (Utils.IsNullOrEmpty(filename))
+ {
+ return _tempPath;
+ }
+ else
+ {
+ return Path.Combine(_tempPath, filename);
+ }
+ }
+
+ public static string UnGzip(byte[] buf)
+ {
+ using MemoryStream sb = new();
+ using GZipStream input = new(new MemoryStream(buf), CompressionMode.Decompress, false);
+ input.CopyTo(sb);
+ sb.Position = 0;
+ return new StreamReader(sb, Encoding.UTF8).ReadToEnd();
+ }
+
+ public static string GetBackupPath(string filename)
+ {
+ string _tempPath = Path.Combine(StartupPath(), "guiBackups");
+ if (!Directory.Exists(_tempPath))
+ {
+ Directory.CreateDirectory(_tempPath);
+ }
+ return Path.Combine(_tempPath, filename);
+ }
+
+ public static string GetConfigPath(string filename = "")
+ {
+ string _tempPath = Path.Combine(StartupPath(), "guiConfigs");
+ if (!Directory.Exists(_tempPath))
+ {
+ Directory.CreateDirectory(_tempPath);
+ }
+ if (Utils.IsNullOrEmpty(filename))
+ {
+ return _tempPath;
+ }
+ else
+ {
+ return Path.Combine(_tempPath, filename);
+ }
+ }
+
+ public static string GetBinPath(string filename, string? coreType = null)
+ {
+ string _tempPath = Path.Combine(StartupPath(), "bin");
+ if (!Directory.Exists(_tempPath))
+ {
+ Directory.CreateDirectory(_tempPath);
+ }
+ if (coreType != null)
+ {
+ _tempPath = Path.Combine(_tempPath, coreType.ToString()!);
+ if (!Directory.Exists(_tempPath))
+ {
+ Directory.CreateDirectory(_tempPath);
+ }
+ }
+ if (Utils.IsNullOrEmpty(filename))
+ {
+ return _tempPath;
+ }
+ else
+ {
+ return Path.Combine(_tempPath, filename);
+ }
+ }
+
+ public static string GetLogPath(string filename = "")
+ {
+ string _tempPath = Path.Combine(StartupPath(), "guiLogs");
+ if (!Directory.Exists(_tempPath))
+ {
+ Directory.CreateDirectory(_tempPath);
+ }
+ if (Utils.IsNullOrEmpty(filename))
+ {
+ return _tempPath;
+ }
+ else
+ {
+ return Path.Combine(_tempPath, filename);
+ }
+ }
+
+ public static string GetFontsPath(string filename = "")
+ {
+ string _tempPath = Path.Combine(StartupPath(), "guiFonts");
+ if (!Directory.Exists(_tempPath))
+ {
+ Directory.CreateDirectory(_tempPath);
+ }
+ if (Utils.IsNullOrEmpty(filename))
+ {
+ return _tempPath;
+ }
+ else
+ {
+ return Path.Combine(_tempPath, filename);
+ }
+ }
+
+ #endregion TempPath
+
+ #region 开机自动启动等
+
+ ///
+ /// 开机自动启动
+ ///
+ ///
+ ///
+ public static void SetAutoRun(string AutoRunRegPath, string AutoRunName, bool run)
+ {
+ try
+ {
+ var autoRunName = $"{AutoRunName}_{GetMD5(StartupPath())}";
+
+ //delete first
+ RegWriteValue(AutoRunRegPath, autoRunName, "");
+ if (IsAdministrator())
+ {
+ AutoStart(autoRunName, "", "");
+ }
+
+ if (run)
+ {
+ string exePath = GetExePath();
+ if (IsAdministrator())
+ {
+ AutoStart(autoRunName, exePath, "");
+ }
+ else
+ {
+ RegWriteValue(AutoRunRegPath, autoRunName, exePath.AppendQuotes());
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ }
+
+ public static string? RegReadValue(string path, string name, string def)
+ {
+ RegistryKey? regKey = null;
+ try
+ {
+ regKey = Registry.CurrentUser.OpenSubKey(path, false);
+ string? value = regKey?.GetValue(name) as string;
+ if (IsNullOrEmpty(value))
+ {
+ return def;
+ }
+ else
+ {
+ return value;
+ }
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ finally
+ {
+ regKey?.Close();
+ }
+ return def;
+ }
+
+ public static void RegWriteValue(string path, string name, object value)
+ {
+ RegistryKey? regKey = null;
+ try
+ {
+ regKey = Registry.CurrentUser.CreateSubKey(path);
+ if (IsNullOrEmpty(value.ToString()))
+ {
+ regKey?.DeleteValue(name, false);
+ }
+ else
+ {
+ regKey?.SetValue(name, value);
+ }
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ finally
+ {
+ regKey?.Close();
+ }
+ }
+
+ ///
+ /// Auto Start via TaskService
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static void AutoStart(string taskName, string fileName, string description)
+ {
+ if (Utils.IsNullOrEmpty(taskName))
+ {
+ return;
+ }
+ string TaskName = taskName;
+ var logonUser = WindowsIdentity.GetCurrent().Name;
+ string taskDescription = description;
+ string deamonFileName = fileName;
+
+ using var taskService = new TaskService();
+ var tasks = taskService.RootFolder.GetTasks(new Regex(TaskName));
+ foreach (var t in tasks)
+ {
+ taskService.RootFolder.DeleteTask(t.Name);
+ }
+ if (Utils.IsNullOrEmpty(fileName))
+ {
+ return;
+ }
+
+ var task = taskService.NewTask();
+ task.RegistrationInfo.Description = taskDescription;
+ task.Settings.DisallowStartIfOnBatteries = false;
+ task.Settings.StopIfGoingOnBatteries = false;
+ task.Settings.RunOnlyIfIdle = false;
+ task.Settings.IdleSettings.StopOnIdleEnd = false;
+ task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
+ task.Triggers.Add(new LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(10) });
+ task.Principal.RunLevel = TaskRunLevel.Highest;
+ task.Actions.Add(new ExecAction(deamonFileName.AppendQuotes(), null, Path.GetDirectoryName(deamonFileName)));
+
+ taskService.RootFolder.RegisterTaskDefinition(TaskName, task);
+ }
+
+ public static void RemoveTunDevice()
+ {
+ try
+ {
+ var sum = MD5.HashData(Encoding.UTF8.GetBytes("wintunsingbox_tun"));
+ var guid = new Guid(sum);
+ string pnputilPath = @"C:\Windows\System32\pnputil.exe";
+ string arg = $$""" /remove-device "SWD\Wintun\{{{guid}}}" """;
+
+ // Try to remove the device
+ Process proc = new()
+ {
+ StartInfo = new()
+ {
+ FileName = pnputilPath,
+ Arguments = arg,
+ RedirectStandardOutput = true,
+ UseShellExecute = false,
+ CreateNoWindow = true
+ }
+ };
+
+ proc.Start();
+ var output = proc.StandardOutput.ReadToEnd();
+ proc.WaitForExit();
+ }
+ catch
+ {
+ }
+ }
+
+ #endregion 开机自动启动等
+
+ #region Windows API
+
+ [Flags]
+ public enum DWMWINDOWATTRIBUTE : uint
+ {
+ DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19,
+ DWMWA_USE_IMMERSIVE_DARK_MODE = 20,
+ }
+
+ [DllImport("dwmapi.dll")]
+ public static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref int attributeValue, uint attributeSize);
+
+ #endregion Windows API
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Common/YamlUtils.cs b/v2rayMiniConsole/v2rayMiniConsole/Common/YamlUtils.cs
new file mode 100644
index 00000000..57af2119
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Common/YamlUtils.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using YamlDotNet.Serialization;
+using YamlDotNet.Serialization.NamingConventions;
+
+namespace v2rayN.Common
+{
+ internal class YamlUtils
+ {
+ #region YAML
+
+ ///
+ /// 反序列化成对象
+ ///
+ ///
+ ///
+ ///
+ public static T FromYaml(string str)
+ {
+ var deserializer = new DeserializerBuilder()
+ .WithNamingConvention(PascalCaseNamingConvention.Instance)
+ .Build();
+ try
+ {
+ T obj = deserializer.Deserialize(str);
+ return obj;
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog("FromYaml", ex);
+ return deserializer.Deserialize("");
+ }
+ }
+
+ ///
+ /// 序列化
+ ///
+ ///
+ ///
+ public static string ToYaml(Object obj)
+ {
+ var serializer = new SerializerBuilder()
+ .WithNamingConvention(HyphenatedNamingConvention.Instance)
+ .Build();
+
+ string result = string.Empty;
+ try
+ {
+ result = serializer.Serialize(obj);
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ return result;
+ }
+
+ #endregion YAML
+ }
+}
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Enums/EConfigType.cs b/v2rayMiniConsole/v2rayMiniConsole/Enums/EConfigType.cs
new file mode 100644
index 00000000..60ef796a
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Enums/EConfigType.cs
@@ -0,0 +1,16 @@
+namespace v2rayN.Enums
+{
+ public enum EConfigType
+ {
+ VMess = 1,
+ Custom = 2,
+ Shadowsocks = 3,
+ Socks = 4,
+ VLESS = 5,
+ Trojan = 6,
+ Hysteria2 = 7,
+ Tuic = 8,
+ Wireguard = 9,
+ Http = 10
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Enums/ECoreType.cs b/v2rayMiniConsole/v2rayMiniConsole/Enums/ECoreType.cs
new file mode 100644
index 00000000..54c07887
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Enums/ECoreType.cs
@@ -0,0 +1,20 @@
+namespace v2rayN.Enums
+{
+ public enum ECoreType
+ {
+ v2fly = 1,
+ Xray = 2,
+ SagerNet = 3,
+ v2fly_v5 = 4,
+ clash = 11,
+ clash_meta = 12,
+ mihomo = 13,
+ hysteria = 21,
+ naiveproxy = 22,
+ tuic = 23,
+ sing_box = 24,
+ juicity = 25,
+ hysteria2 = 26,
+ v2rayN = 99
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Enums/EGlobalHotkey.cs b/v2rayMiniConsole/v2rayMiniConsole/Enums/EGlobalHotkey.cs
new file mode 100644
index 00000000..f4a92bdb
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Enums/EGlobalHotkey.cs
@@ -0,0 +1,11 @@
+namespace v2rayN.Enums
+{
+ public enum EGlobalHotkey
+ {
+ ShowForm = 0,
+ SystemProxyClear = 1,
+ SystemProxySet = 2,
+ SystemProxyUnchanged = 3,
+ SystemProxyPac = 4,
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Enums/EInboundProtocol.cs b/v2rayMiniConsole/v2rayMiniConsole/Enums/EInboundProtocol.cs
new file mode 100644
index 00000000..07cd1369
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Enums/EInboundProtocol.cs
@@ -0,0 +1,14 @@
+namespace v2rayN.Enums
+{
+ public enum EInboundProtocol
+ {
+ socks = 0,
+ http,
+ socks2,
+ http2,
+ pac,
+ api,
+ api2,
+ speedtest = 21
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Enums/EMove.cs b/v2rayMiniConsole/v2rayMiniConsole/Enums/EMove.cs
new file mode 100644
index 00000000..fcbc23dc
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Enums/EMove.cs
@@ -0,0 +1,11 @@
+namespace v2rayN.Enums
+{
+ public enum EMove
+ {
+ Top = 1,
+ Up = 2,
+ Down = 3,
+ Bottom = 4,
+ Position = 5
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Enums/ERuleMode.cs b/v2rayMiniConsole/v2rayMiniConsole/Enums/ERuleMode.cs
new file mode 100644
index 00000000..59a01430
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Enums/ERuleMode.cs
@@ -0,0 +1,10 @@
+namespace v2rayN.Enums
+{
+ public enum ERuleMode
+ {
+ Rule = 0,
+ Global = 1,
+ Direct = 2,
+ Unchanged = 3
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Enums/EServerColName.cs b/v2rayMiniConsole/v2rayMiniConsole/Enums/EServerColName.cs
new file mode 100644
index 00000000..453dbe88
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Enums/EServerColName.cs
@@ -0,0 +1,21 @@
+namespace v2rayN.Enums
+{
+ public enum EServerColName
+ {
+ def = 0,
+ configType,
+ remarks,
+ address,
+ port,
+ network,
+ streamSecurity,
+ subRemarks,
+ delayVal,
+ speedVal,
+
+ todayDown,
+ todayUp,
+ totalDown,
+ totalUp
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Enums/ESpeedActionType.cs b/v2rayMiniConsole/v2rayMiniConsole/Enums/ESpeedActionType.cs
new file mode 100644
index 00000000..e0663d92
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Enums/ESpeedActionType.cs
@@ -0,0 +1,10 @@
+namespace v2rayN.Enums
+{
+ public enum ESpeedActionType
+ {
+ Tcping,
+ Realping,
+ Speedtest,
+ Mixedtest
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Enums/ESysProxyType.cs b/v2rayMiniConsole/v2rayMiniConsole/Enums/ESysProxyType.cs
new file mode 100644
index 00000000..3991940e
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Enums/ESysProxyType.cs
@@ -0,0 +1,10 @@
+namespace v2rayN.Enums
+{
+ public enum ESysProxyType
+ {
+ ForcedClear = 0, // "清除系统代理"
+ ForcedChange = 1, // "自动配置系统代理"
+ Unchanged = 2, // "不改变系统代理"
+ Pac = 3 // "pac"
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Enums/ETransport.cs b/v2rayMiniConsole/v2rayMiniConsole/Enums/ETransport.cs
new file mode 100644
index 00000000..349d68e7
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Enums/ETransport.cs
@@ -0,0 +1,15 @@
+namespace v2rayN.Enums
+{
+ public enum ETransport
+ {
+ tcp,
+ kcp,
+ ws,
+ httpupgrade,
+ splithttp,
+ h2,
+ http,
+ quic,
+ grpc
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Enums/EViewAction.cs b/v2rayMiniConsole/v2rayMiniConsole/Enums/EViewAction.cs
new file mode 100644
index 00000000..8a5a4641
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Enums/EViewAction.cs
@@ -0,0 +1,8 @@
+namespace v2rayN.Enums
+{
+ public enum EViewAction
+ {
+ AdjustMainLvColWidth,
+ ProfilesFocus
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Global.cs b/v2rayMiniConsole/v2rayMiniConsole/Global.cs
new file mode 100644
index 00000000..2b012c70
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Global.cs
@@ -0,0 +1,199 @@
+using v2rayN.Enums;
+
+namespace v2rayN
+{
+ internal class Global
+ {
+ #region const
+
+ public const string GithubUrl = "https://github.com";
+ public const string GithubApiUrl = "https://api.github.com/repos";
+ public const string V2flyCoreUrl = "https://github.com/v2fly/v2ray-core/releases";
+ public const string XrayCoreUrl = "https://github.com/XTLS/Xray-core/releases";
+ public const string SagerNetCoreUrl = "https://github.com/SagerNet/v2ray-core/releases";
+ public const string NUrl = @"https://github.com/2dust/v2rayN/releases";
+ public const string ClashCoreUrl = "https://github.com/Dreamacro/clash/releases";
+ public const string ClashMetaCoreUrl = "https://github.com/MetaCubeX/Clash.Meta/releases";
+ public const string MihomoCoreUrl = "https://github.com/MetaCubeX/mihomo/releases";
+ public const string HysteriaCoreUrl = "https://github.com/apernet/hysteria/releases";
+ public const string NaiveproxyCoreUrl = "https://github.com/klzgrad/naiveproxy/releases";
+ public const string TuicCoreUrl = "https://github.com/EAimTY/tuic/releases";
+ public const string SingboxCoreUrl = "https://github.com/SagerNet/sing-box/releases";
+ public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
+ public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
+ public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
+ public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
+ public const string SingboxRulesetUrlGeosite = @"https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/{0}.srs";
+ public const string SingboxRulesetUrlGeoip = @"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/srs/{0}.srs";
+
+ public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
+ public const string ConfigFileName = "guiNConfig.json";
+ public const string CoreConfigFileName = "config.json";
+ public const string CorePreConfigFileName = "configPre.json";
+ public const string CoreSpeedtestConfigFileName = "configSpeedtest.json";
+ public const string ClashMixinConfigFileName = "Mixin.yaml";
+ public const string V2raySampleClient = "v2rayMiniConsole.Sample.SampleClientConfig";
+ public const string SingboxSampleClient = "v2rayMiniConsole.Sample.SingboxSampleClientConfig";
+ public const string V2raySampleHttpRequestFileName = "v2rayMiniConsole.Sample.SampleHttpRequest";
+ public const string V2raySampleHttpResponseFileName = "v2rayMiniConsole.Sample.SampleHttpResponse";
+ public const string V2raySampleInbound = "v2rayMiniConsole.Sample.SampleInbound";
+ public const string V2raySampleOutbound = "v2rayMiniConsole.Sample.SampleOutbound";
+ public const string SingboxSampleOutbound = "v2rayMiniConsole.Sample.SingboxSampleOutbound";
+ public const string CustomRoutingFileName = "v2rayMiniConsole.Sample.custom_routing_";
+ public const string TunSingboxDNSFileName = "v2rayMiniConsole.Sample.tun_singbox_dns";
+ public const string TunSingboxInboundFileName = "v2rayMiniConsole.Sample.tun_singbox_inbound";
+ public const string TunSingboxRulesFileName = "v2rayMiniConsole.Sample.tun_singbox_rules";
+ public const string DNSV2rayNormalFileName = "v2rayMiniConsole.Sample.dns_v2ray_normal";
+ public const string DNSSingboxNormalFileName = "v2rayMiniConsole.Sample.dns_singbox_normal";
+ public const string ClashMixinYaml = "v2rayMiniConsole.Sample.clash_mixin_yaml";
+ public const string ClashTunYaml = "v2rayMiniConsole.Sample.clash_tun_yaml";
+
+ public const string DefaultSecurity = "auto";
+ public const string DefaultNetwork = "tcp";
+ public const string TcpHeaderHttp = "http";
+ public const string None = "none";
+ public const string ProxyTag = "proxy";
+ public const string DirectTag = "direct";
+ public const string BlockTag = "block";
+ public const string StreamSecurity = "tls";
+ public const string StreamSecurityReality = "reality";
+ public const string Loopback = "127.0.0.1";
+ public const string InboundAPIProtocol = "dokodemo-door";
+ public const string HttpProtocol = "http://";
+ public const string HttpsProtocol = "https://";
+
+ public const string UserEMail = "t@t.tt";
+ public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
+ public const string AutoRunName = "v2rayNAutoRun";
+ public const string CustomIconName = "v2rayN.ico";
+ public const string IEProxyExceptions = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*";
+ public const string RoutingRuleComma = "";
+ public const string GrpcGunMode = "gun";
+ public const string GrpcMultiMode = "multi";
+ public const int MaxPort = 65536;
+ public const string CommandClearMsg = "CommandClearMsg";
+ public const string CommandSendMsgView = "CommandSendMsgView";
+ public const string CommandStopSpeedTest = "CommandStopSpeedTest";
+ public const string DelayUnit = "";
+ public const string SpeedUnit = "";
+ public const int MinFontSize = 10;
+ public const string RebootAs = "rebootas";
+
+ public static readonly List IEProxyProtocols = new() {
+ "{ip}:{http_port}",
+ "socks={ip}:{socks_port}",
+ "http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
+ "http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
+ ""
+ };
+
+ public static readonly List SubConvertUrls = new List {
+ @"https://sub.xeton.dev/sub?url={0}",
+ @"https://api.dler.io/sub?url={0}",
+ @"http://127.0.0.1:25500/sub?url={0}",
+ ""
+ };
+
+ public const string StatusTemplate = "[current server:{0}] / [current proxy mode:{1}] / [current routing:{2}]";
+ public const string DefaultStatusStr = "[current server:-] / [current proxy mode:-] / [current routing:-]";
+
+ public static readonly List SubConvertConfig = new List {
+ @"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"
+ };
+
+ public static readonly List SubConvertTargets = new List {
+ "",
+ "mixed",
+ "v2ray",
+ "clash",
+ "ss",
+ };
+
+ public static readonly List SpeedTestUrls = new() {
+ @"https://speed.cloudflare.com/__down?bytes=100000000",
+ @"https://speed.cloudflare.com/__down?bytes=10000000",
+ @"http://cachefly.cachefly.net/50mb.test",
+ @"http://cachefly.cachefly.net/10mb.test"
+ };
+
+ public static readonly List SpeedPingTestUrls = new() {
+ @"https://www.google.com/generate_204",
+ @"https://www.youtube.com",
+ @"https://www.apple.com/library/test/success.html",
+ @"http://www.msftconnecttest.com/connecttest.txt",
+ };
+
+ public static readonly Dictionary UserAgentTexts = 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",""}
+ };
+
+ public const string Hysteria2ProtocolShare = "hy2://";
+
+ public static readonly Dictionary ProtocolShares = new()
+ {
+ {EConfigType.VMess,"vmess://"},
+ {EConfigType.Shadowsocks,"ss://"},
+ {EConfigType.Socks,"socks://"},
+ {EConfigType.VLESS,"vless://"},
+ {EConfigType.Trojan,"trojan://"},
+ {EConfigType.Hysteria2,"hysteria2://"},
+ {EConfigType.Tuic,"tuic://"},
+ {EConfigType.Wireguard,"wireguard://"}
+ };
+
+ public static readonly Dictionary ProtocolTypes = new()
+ {
+ {EConfigType.VMess,"vmess"},
+ {EConfigType.Shadowsocks,"shadowsocks"},
+ {EConfigType.Socks,"socks"},
+ {EConfigType.Http,"http"},
+ {EConfigType.VLESS,"vless"},
+ {EConfigType.Trojan,"trojan"},
+ {EConfigType.Hysteria2,"hysteria2"},
+ {EConfigType.Tuic,"tuic"},
+ {EConfigType.Wireguard,"wireguard"}
+ };
+
+ public static readonly List VmessSecurities = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
+ public static readonly List SsSecurities = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
+ public static readonly List SsSecuritiesInSagerNet = new() { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" };
+ public static readonly List SsSecuritiesInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
+ public static readonly List SsSecuritiesInSingbox = new() { "aes-256-gcm", "aes-192-gcm", "aes-128-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20" };
+ public static readonly List Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
+ public static readonly List Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "splithttp", "h2", "quic", "grpc" };
+ public static readonly List KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
+ public static readonly List CoreTypes = new() { "v2fly", "SagerNet", "Xray", "sing_box" };
+ public static readonly List CoreTypes4VLESS = new() { "Xray", "sing_box" };
+ public static readonly List DomainStrategies = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
+ public static readonly List DomainStrategies4Singbox = new() { "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6", "" };
+ public static readonly List DomainMatchers = new() { "linear", "mph", "" };
+ public static readonly List Fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
+ public static readonly List UserAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
+
+ public static readonly List AllowInsecure = new() { "true", "false", "" };
+ public static readonly List DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
+ public static readonly List Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" };
+ public static readonly List Alpns = new() { "h3", "h2", "http/1.1", "h3,h2,http/1.1", "h3,h2", "h2,http/1.1", "" };
+ public static readonly List LogLevels = new() { "debug", "info", "warning", "error", "none" };
+ public static readonly List InboundTags = new() { "socks", "http", "socks2", "http2" };
+ public static readonly List RuleProtocols = new() { "http", "tls", "bittorrent" };
+ public static readonly List RuleNetworks = new() { "", "tcp", "udp", "tcp,udp" };
+ public static readonly List destOverrideProtocols = ["http", "tls", "quic", "fakedns", "fakedns+others"];
+ public static readonly List TunMtus = new() { "1280", "1408", "1500", "9000" };
+ public static readonly List TunStacks = new() { "gvisor", "system" };
+ public static readonly List PresetMsgFilters = new() { "proxy", "direct", "block", "" };
+ public static readonly List SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
+ public static readonly List TuicCongestionControls = new() { "cubic", "new_reno", "bbr" };
+
+ public static readonly List allowSelectType = new List { "selector", "urltest", "loadbalance", "fallback" };
+ public static readonly List notAllowTestType = new List { "selector", "urltest", "direct", "reject", "compatible", "pass", "loadbalance", "fallback" };
+ public static readonly List proxyVehicleType = new List { "file", "http" };
+
+ #endregion const
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Handler/ClashApiHandler.cs b/v2rayMiniConsole/v2rayMiniConsole/Handler/ClashApiHandler.cs
new file mode 100644
index 00000000..1e04bf1e
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Handler/ClashApiHandler.cs
@@ -0,0 +1,218 @@
+using v2rayN.Models;
+using static v2rayN.Models.ClashProxies;
+
+namespace v2rayN.Handler
+{
+ public sealed class ClashApiHandler
+ {
+ private static readonly Lazy instance = new(() => new());
+ public static ClashApiHandler Instance => instance.Value;
+
+ private Dictionary _proxies;
+ public Dictionary ProfileContent { get; set; }
+
+ public void SetProxies(Dictionary proxies)
+ {
+ _proxies = proxies;
+ }
+
+ public Dictionary GetProxies()
+ {
+ return _proxies;
+ }
+
+ public void GetClashProxies(Config config, Action update)
+ {
+ Task.Run(() => GetClashProxiesAsync(config, update));
+ }
+
+ private async Task GetClashProxiesAsync(Config config, Action update)
+ {
+ for (var i = 0; i < 5; i++)
+ {
+ var url = $"{GetApiUrl()}/proxies";
+ var result = await HttpClientHelper.Instance.TryGetAsync(url);
+ var clashProxies = JsonUtils.Deserialize(result);
+
+ var url2 = $"{GetApiUrl()}/providers/proxies";
+ var result2 = await HttpClientHelper.Instance.TryGetAsync(url2);
+ var clashProviders = JsonUtils.Deserialize(result2);
+
+ if (clashProxies != null || clashProviders != null)
+ {
+ update(clashProxies, clashProviders);
+ return;
+ }
+ Thread.Sleep(5000);
+ }
+ update(null, null);
+ }
+
+ public void ClashProxiesDelayTest(bool blAll, List lstProxy, Action update)
+ {
+ Task.Run(() =>
+ {
+ if (blAll)
+ {
+ for (int i = 0; i < 5; i++)
+ {
+ if (GetProxies() != null)
+ {
+ break;
+ }
+ Thread.Sleep(5000);
+ }
+ var proxies = GetProxies();
+ if (proxies == null)
+ {
+ return;
+ }
+ lstProxy = new List();
+ foreach (KeyValuePair kv in proxies)
+ {
+ if (Global.notAllowTestType.Contains(kv.Value.type.ToLower()))
+ {
+ continue;
+ }
+ lstProxy.Add(new ClashProxyModel()
+ {
+ name = kv.Value.name,
+ type = kv.Value.type.ToLower(),
+ });
+ }
+ }
+
+ if (lstProxy == null)
+ {
+ return;
+ }
+ var urlBase = $"{GetApiUrl()}/proxies";
+ urlBase += @"/{0}/delay?timeout=10000&url=" + LazyConfig.Instance.GetConfig().speedTestItem.speedPingTestUrl;
+
+ List tasks = new List();
+ foreach (var it in lstProxy)
+ {
+ if (Global.notAllowTestType.Contains(it.type.ToLower()))
+ {
+ continue;
+ }
+ var name = it.name;
+ var url = string.Format(urlBase, name);
+ tasks.Add(Task.Run(async () =>
+ {
+ var result = await HttpClientHelper.Instance.TryGetAsync(url);
+ update(it, result);
+ }));
+ }
+ Task.WaitAll(tasks.ToArray());
+
+ Thread.Sleep(1000);
+ update(null, "");
+ });
+ }
+
+ public List? GetClashProxyGroups()
+ {
+ try
+ {
+ var fileContent = ProfileContent;
+ if (fileContent is null || fileContent?.ContainsKey("proxy-groups") == false)
+ {
+ return null;
+ }
+ return JsonUtils.Deserialize>(JsonUtils.Serialize(fileContent["proxy-groups"]));
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog("GetClashProxyGroups", ex);
+ return null;
+ }
+ }
+
+ public async void ClashSetActiveProxy(string name, string nameNode)
+ {
+ try
+ {
+ var url = $"{GetApiUrl()}/proxies/{name}";
+ Dictionary headers = new Dictionary();
+ headers.Add("name", nameNode);
+ await HttpClientHelper.Instance.PutAsync(url, headers);
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ }
+
+ public void ClashConfigUpdate(Dictionary headers)
+ {
+ Task.Run(async () =>
+ {
+ var proxies = GetProxies();
+ if (proxies == null)
+ {
+ return;
+ }
+
+ var urlBase = $"{GetApiUrl()}/configs";
+
+ await HttpClientHelper.Instance.PatchAsync(urlBase, headers);
+ });
+ }
+
+ public async void ClashConfigReload(string filePath)
+ {
+ ClashConnectionClose("");
+ try
+ {
+ var url = $"{GetApiUrl()}/configs?force=true";
+ Dictionary headers = new Dictionary();
+ headers.Add("path", filePath);
+ await HttpClientHelper.Instance.PutAsync(url, headers);
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ }
+
+ public void GetClashConnections(Config config, Action update)
+ {
+ Task.Run(() => GetClashConnectionsAsync(config, update));
+ }
+
+ private async Task GetClashConnectionsAsync(Config config, Action update)
+ {
+ try
+ {
+ var url = $"{GetApiUrl()}/connections";
+ var result = await HttpClientHelper.Instance.TryGetAsync(url);
+ var clashConnections = JsonUtils.Deserialize(result);
+
+ update(clashConnections);
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ }
+
+ public async void ClashConnectionClose(string id)
+ {
+ try
+ {
+ var url = $"{GetApiUrl()}/connections/{id}";
+ await HttpClientHelper.Instance.DeleteAsync(url);
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ }
+ }
+
+ private string GetApiUrl()
+ {
+ return $"{Global.HttpProtocol}{Global.Loopback}:{LazyConfig.Instance.StatePort2}";
+ }
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Handler/ConfigHandler.cs b/v2rayMiniConsole/v2rayMiniConsole/Handler/ConfigHandler.cs
new file mode 100644
index 00000000..0cae007a
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Handler/ConfigHandler.cs
@@ -0,0 +1,1730 @@
+using System.Data;
+using System.IO;
+using System.Text.RegularExpressions;
+using System.Web;
+using v2rayMiniConsole;
+using v2rayN.Enums;
+using v2rayN.Handler.Fmt;
+using v2rayN.Models;
+
+namespace v2rayN.Handler
+{
+ ///
+ /// 本软件配置文件处理类
+ ///
+ internal class ConfigHandler
+ {
+ private static string configRes = Global.ConfigFileName;
+ private static readonly object objLock = new();
+
+ #region ConfigHandler
+
+ ///
+ /// 载入配置文件
+ ///
+ ///
+ ///
+ public static int LoadConfig(ref Config? config)
+ {
+ //载入配置文件
+ var result = Utils.LoadResource(Utils.GetConfigPath(configRes));
+ if (!Utils.IsNullOrEmpty(result))
+ {
+ //转成Json
+ config = JsonUtils.Deserialize(result);
+ }
+ else
+ {
+ if (File.Exists(Utils.GetConfigPath(configRes)))
+ {
+ Logging.SaveLog("LoadConfig Exception");
+ return -1;
+ }
+ }
+
+ if (config == null)
+ {
+ config = new Config
+ {
+ };
+ }
+ if (config.coreBasicItem == null)
+ {
+ config.coreBasicItem = new()
+ {
+ logEnabled = false,
+ loglevel = "warning",
+ muxEnabled = false,
+ };
+ }
+
+ //本地监听
+ if (config.inbound == null)
+ {
+ config.inbound = new List();
+ InItem inItem = new()
+ {
+ protocol = EInboundProtocol.socks.ToString(),
+ localPort = 10808,
+ udpEnabled = true,
+ sniffingEnabled = true,
+ routeOnly = false,
+ };
+
+ config.inbound.Add(inItem);
+ }
+ else
+ {
+ if (config.inbound.Count > 0)
+ {
+ config.inbound[0].protocol = EInboundProtocol.socks.ToString();
+ }
+ }
+ if (config.routingBasicItem == null)
+ {
+ config.routingBasicItem = new()
+ {
+ enableRoutingAdvanced = true
+ };
+ }
+ //路由规则
+ if (Utils.IsNullOrEmpty(config.routingBasicItem.domainStrategy))
+ {
+ config.routingBasicItem.domainStrategy = Global.DomainStrategies[0];//"IPIfNonMatch";
+ }
+ //if (Utile.IsNullOrEmpty(config.domainMatcher))
+ //{
+ // config.domainMatcher = "linear";
+ //}
+
+ //kcp
+ if (config.kcpItem == null)
+ {
+ config.kcpItem = new KcpItem
+ {
+ mtu = 1350,
+ tti = 50,
+ uplinkCapacity = 12,
+ downlinkCapacity = 100,
+ readBufferSize = 2,
+ writeBufferSize = 2,
+ congestion = false
+ };
+ }
+ if (config.grpcItem == null)
+ {
+ config.grpcItem = new GrpcItem
+ {
+ idle_timeout = 60,
+ health_check_timeout = 20,
+ permit_without_stream = false,
+ initial_windows_size = 0,
+ };
+ }
+ if (config.tunModeItem == null)
+ {
+ config.tunModeItem = new TunModeItem
+ {
+ enableTun = false,
+ mtu = 9000,
+ };
+ }
+ if (config.guiItem == null)
+ {
+ config.guiItem = new()
+ {
+ enableStatistics = false,
+ };
+ }
+ if (config.uiItem == null)
+ {
+ config.uiItem = new UIItem()
+ {
+ enableAutoAdjustMainLvColWidth = true
+ };
+ }
+ if (config.uiItem.mainColumnItem == null)
+ {
+ config.uiItem.mainColumnItem = new();
+ }
+ if (Utils.IsNullOrEmpty(config.uiItem.currentLanguage))
+ {
+ config.uiItem.currentLanguage = Global.Languages[0];
+ }
+
+ if (config.constItem == null)
+ {
+ config.constItem = new ConstItem();
+ }
+ if (Utils.IsNullOrEmpty(config.constItem.defIEProxyExceptions))
+ {
+ config.constItem.defIEProxyExceptions = Global.IEProxyExceptions;
+ }
+
+ if (config.speedTestItem == null)
+ {
+ config.speedTestItem = new();
+ }
+ if (config.speedTestItem.speedTestTimeout < 10)
+ {
+ config.speedTestItem.speedTestTimeout = 10;
+ }
+ if (Utils.IsNullOrEmpty(config.speedTestItem.speedTestUrl))
+ {
+ config.speedTestItem.speedTestUrl = Global.SpeedTestUrls[0];
+ }
+ if (Utils.IsNullOrEmpty(config.speedTestItem.speedPingTestUrl))
+ {
+ //config.speedTestItem.speedPingTestUrl = Global.SpeedPingTestUrl;
+ config.speedTestItem.speedPingTestUrl = Global.SpeedPingTestUrls[1];
+ }
+
+ if (config.mux4SboxItem == null)
+ {
+ config.mux4SboxItem = new()
+ {
+ protocol = Global.SingboxMuxs[0],
+ max_connections = 8
+ };
+ }
+
+ if (config.hysteriaItem == null)
+ {
+ config.hysteriaItem = new()
+ {
+ up_mbps = 100,
+ down_mbps = 100
+ };
+ }
+ config.clashUIItem ??= new();
+
+ LazyConfig.Instance.SetConfig(config);
+ return 0;
+ }
+
+ ///
+ /// 保参数
+ ///
+ ///
+ ///
+ public static int SaveConfig(Config config, bool reload = true)
+ {
+ ToJsonFile(config);
+
+ return 0;
+ }
+
+ ///
+ /// 存储文件
+ ///
+ ///
+ private static void ToJsonFile(Config config)
+ {
+ lock (objLock)
+ {
+ try
+ {
+ //save temp file
+ var resPath = Utils.GetConfigPath(configRes);
+ var tempPath = $"{resPath}_temp";
+ if (JsonUtils.ToFile(config, tempPath) != 0)
+ {
+ return;
+ }
+
+ if (File.Exists(resPath))
+ {
+ File.Delete(resPath);
+ }
+ //rename
+ File.Move(tempPath, resPath);
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog("ToJsonFile", ex);
+ }
+ }
+ }
+
+ //public static int ImportOldGuiConfig(Config config, string fileName)
+ //{
+ // var result = Utils.LoadResource(fileName);
+ // if (Utils.IsNullOrEmpty(result))
+ // {
+ // return -1;
+ // }
+
+ // var configOld = JsonUtils.Deserialize(result);
+ // if (configOld == null)
+ // {
+ // return -1;
+ // }
+
+ // var subItem = JsonUtils.Deserialize>(JsonUtils.Serialize(configOld.subItem));
+ // foreach (var it in subItem)
+ // {
+ // if (Utils.IsNullOrEmpty(it.id))
+ // {
+ // it.id = Utils.GetGUID(false);
+ // }
+ // SQLiteHelper.Instance.Replace(it);
+ // }
+
+ // var profileItems = JsonUtils.Deserialize>(JsonUtils.Serialize(configOld.vmess));
+ // foreach (var it in profileItems)
+ // {
+ // if (Utils.IsNullOrEmpty(it.indexId))
+ // {
+ // it.indexId = Utils.GetGUID(false);
+ // }
+ // SQLiteHelper.Instance.Replace(it);
+ // }
+
+ // foreach (var it in configOld.routings)
+ // {
+ // if (it.locked)
+ // {
+ // continue;
+ // }
+ // var routing = JsonUtils.Deserialize(JsonUtils.Serialize(it));
+ // foreach (var it2 in it.rules)
+ // {
+ // it2.id = Utils.GetGUID(false);
+ // }
+ // routing.ruleNum = it.rules.Count;
+ // routing.ruleSet = JsonUtils.Serialize(it.rules, false);
+
+ // if (Utils.IsNullOrEmpty(routing.id))
+ // {
+ // routing.id = Utils.GetGUID(false);
+ // }
+ // SQLiteHelper.Instance.Replace(routing);
+ // }
+
+ // config = JsonUtils.Deserialize(JsonUtils.Serialize(configOld));
+
+ // if (config.coreBasicItem == null)
+ // {
+ // config.coreBasicItem = new()
+ // {
+ // logEnabled = configOld.logEnabled,
+ // loglevel = configOld.loglevel,
+ // muxEnabled = configOld.muxEnabled,
+ // };
+ // }
+
+ // if (config.routingBasicItem == null)
+ // {
+ // config.routingBasicItem = new()
+ // {
+ // enableRoutingAdvanced = configOld.enableRoutingAdvanced,
+ // domainStrategy = configOld.domainStrategy
+ // };
+ // }
+
+ // if (config.guiItem == null)
+ // {
+ // config.guiItem = new()
+ // {
+ // enableStatistics = configOld.enableStatistics,
+ // keepOlderDedupl = configOld.keepOlderDedupl,
+ // ignoreGeoUpdateCore = configOld.ignoreGeoUpdateCore,
+ // autoUpdateInterval = configOld.autoUpdateInterval,
+ // checkPreReleaseUpdate = configOld.checkPreReleaseUpdate,
+ // enableSecurityProtocolTls13 = configOld.enableSecurityProtocolTls13,
+ // trayMenuServersLimit = configOld.trayMenuServersLimit,
+ // };
+ // }
+
+ // GetDefaultServer(config);
+ // GetDefaultRouting(config);
+ // SaveConfig(config);
+ // LoadConfig(ref config);
+
+ // return 0;
+ //}
+
+ #endregion ConfigHandler
+
+ #region Server
+
+ ///
+ /// Add or edit server
+ ///
+ ///
+ ///
+ ///
+ public static int AddServer(Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configType = EConfigType.VMess;
+
+ profileItem.address = profileItem.address.TrimEx();
+ profileItem.id = profileItem.id.TrimEx();
+ profileItem.security = profileItem.security.TrimEx();
+ profileItem.network = profileItem.network.TrimEx();
+ profileItem.headerType = profileItem.headerType.TrimEx();
+ profileItem.requestHost = profileItem.requestHost.TrimEx();
+ profileItem.path = profileItem.path.TrimEx();
+ profileItem.streamSecurity = profileItem.streamSecurity.TrimEx();
+
+ if (!Global.VmessSecurities.Contains(profileItem.security))
+ {
+ return -1;
+ }
+ if (profileItem.id.IsNullOrEmpty())
+ {
+ return -1;
+ }
+
+ AddServerCommon(config, profileItem, toFile);
+
+ return 0;
+ }
+
+ ///
+ /// 移除服务器
+ ///
+ ///
+ ///
+ ///
+ public static int RemoveServer(Config config, List indexes)
+ {
+ var subid = "TempRemoveSubId";
+ foreach (var item in indexes)
+ {
+ item.subid = subid;
+ }
+
+ SQLiteHelper.Instance.UpdateAll(indexes);
+ RemoveServerViaSubid(config, subid, false);
+
+ return 0;
+ }
+
+ ///
+ /// 克隆服务器
+ ///
+ ///
+ ///
+ ///
+ public static int CopyServer(Config config, List indexes)
+ {
+ foreach (var it in indexes)
+ {
+ var item = LazyConfig.Instance.GetProfileItem(it.indexId);
+ if (item is null)
+ {
+ continue;
+ }
+
+ ProfileItem profileItem = JsonUtils.DeepCopy(item);
+ profileItem.indexId = string.Empty;
+ profileItem.remarks = $"{item.remarks}-clone";
+
+ if (profileItem.configType == EConfigType.Custom)
+ {
+ profileItem.address = Utils.GetConfigPath(profileItem.address);
+ if (AddCustomServer(config, profileItem, false) == 0)
+ {
+ }
+ }
+ else
+ {
+ AddServerCommon(config, profileItem, true);
+ }
+ }
+
+ return 0;
+ }
+
+ ///
+ /// 设置活动服务器
+ ///
+ ///
+ ///
+ ///
+ public static int SetDefaultServerIndex(Config config, string? indexId)
+ {
+ if (Utils.IsNullOrEmpty(indexId))
+ {
+ return -1;
+ }
+
+ config.indexId = indexId;
+
+ ToJsonFile(config);
+
+ return 0;
+ }
+
+ public static int SetDefaultServer(Config config, List lstProfile)
+ {
+ if (lstProfile.Exists(t => t.indexId == config.indexId))
+ {
+ return 0;
+ }
+ if (SQLiteHelper.Instance.Table().Where(t => t.indexId == config.indexId).Any())
+ {
+ return 0;
+ }
+ if (lstProfile.Count > 0)
+ {
+ return SetDefaultServerIndex(config, lstProfile.Where(t => t.port > 0).FirstOrDefault()?.indexId);
+ }
+ return SetDefaultServerIndex(config, SQLiteHelper.Instance.Table().Where(t => t.port > 0).Select(t => t.indexId).FirstOrDefault());
+ }
+
+ public static ProfileItem? GetDefaultServer(Config config)
+ {
+ var item = LazyConfig.Instance.GetProfileItem(config.indexId);
+ if (item is null)
+ {
+ var item2 = SQLiteHelper.Instance.Table().FirstOrDefault();
+ SetDefaultServerIndex(config, item2?.indexId);
+ return item2;
+ }
+
+ return item;
+ }
+
+ ///
+ /// 移动服务器
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int MoveServer(Config config, ref List lstProfile, int index, EMove eMove, int pos = -1)
+ {
+ int count = lstProfile.Count;
+ if (index < 0 || index > lstProfile.Count - 1)
+ {
+ return -1;
+ }
+
+ for (int i = 0; i < lstProfile.Count; i++)
+ {
+ ProfileExHandler.Instance.SetSort(lstProfile[i].indexId, (i + 1) * 10);
+ }
+
+ var sort = 0;
+ switch (eMove)
+ {
+ case EMove.Top:
+ {
+ if (index == 0)
+ {
+ return 0;
+ }
+ sort = ProfileExHandler.Instance.GetSort(lstProfile[0].indexId) - 1;
+
+ break;
+ }
+ case EMove.Up:
+ {
+ if (index == 0)
+ {
+ return 0;
+ }
+ sort = ProfileExHandler.Instance.GetSort(lstProfile[index - 1].indexId) - 1;
+
+ break;
+ }
+
+ case EMove.Down:
+ {
+ if (index == count - 1)
+ {
+ return 0;
+ }
+ sort = ProfileExHandler.Instance.GetSort(lstProfile[index + 1].indexId) + 1;
+
+ break;
+ }
+ case EMove.Bottom:
+ {
+ if (index == count - 1)
+ {
+ return 0;
+ }
+ sort = ProfileExHandler.Instance.GetSort(lstProfile[^1].indexId) + 1;
+
+ break;
+ }
+ case EMove.Position:
+ sort = pos * 10 + 1;
+ break;
+ }
+
+ ProfileExHandler.Instance.SetSort(lstProfile[index].indexId, sort);
+ return 0;
+ }
+
+ ///
+ /// 添加自定义服务器
+ ///
+ ///
+ ///
+ ///
+ public static int AddCustomServer(Config config, ProfileItem profileItem, bool blDelete)
+ {
+ var fileName = profileItem.address;
+ if (!File.Exists(fileName))
+ {
+ return -1;
+ }
+ var ext = Path.GetExtension(fileName);
+ string newFileName = $"{Utils.GetGUID()}{ext}";
+ //newFileName = Path.Combine(Utile.GetTempPath(), newFileName);
+
+ try
+ {
+ File.Copy(fileName, Utils.GetConfigPath(newFileName));
+ if (blDelete)
+ {
+ File.Delete(fileName);
+ }
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(ex.Message, ex);
+ return -1;
+ }
+
+ profileItem.address = newFileName;
+ profileItem.configType = EConfigType.Custom;
+ if (Utils.IsNullOrEmpty(profileItem.remarks))
+ {
+ profileItem.remarks = $"import custom@{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}";
+ }
+
+ AddServerCommon(config, profileItem, true);
+
+ return 0;
+ }
+
+ ///
+ /// Add or edit server
+ ///
+ ///
+ ///
+ ///
+ public static int EditCustomServer(Config config, ProfileItem profileItem)
+ {
+ if (SQLiteHelper.Instance.Update(profileItem) > 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+
+ //ToJsonFile(config);
+ }
+
+ ///
+ /// Add or edit server
+ ///
+ ///
+ ///
+ ///
+ public static int AddShadowsocksServer(Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configType = EConfigType.Shadowsocks;
+
+ profileItem.address = profileItem.address.TrimEx();
+ profileItem.id = profileItem.id.TrimEx();
+ profileItem.security = profileItem.security.TrimEx();
+
+ if (!LazyConfig.Instance.GetShadowsocksSecurities(profileItem).Contains(profileItem.security))
+ {
+ return -1;
+ }
+ if (profileItem.id.IsNullOrEmpty())
+ {
+ return -1;
+ }
+
+ AddServerCommon(config, profileItem, toFile);
+
+ return 0;
+ }
+
+ ///
+ /// Add or edit server
+ ///
+ ///
+ ///
+ ///
+ public static int AddSocksServer(Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configType = EConfigType.Socks;
+
+ profileItem.address = profileItem.address.TrimEx();
+
+ AddServerCommon(config, profileItem, toFile);
+
+ return 0;
+ }
+
+ ///
+ /// Add or edit server
+ ///
+ ///
+ ///
+ ///
+ public static int AddHttpServer(Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configType = EConfigType.Http;
+
+ profileItem.address = profileItem.address.TrimEx();
+
+ AddServerCommon(config, profileItem, toFile);
+
+ return 0;
+ }
+
+ ///
+ /// Add or edit server
+ ///
+ ///
+ ///
+ ///
+ public static int AddTrojanServer(Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configType = EConfigType.Trojan;
+
+ profileItem.address = profileItem.address.TrimEx();
+ profileItem.id = profileItem.id.TrimEx();
+ if (Utils.IsNullOrEmpty(profileItem.streamSecurity))
+ {
+ profileItem.streamSecurity = Global.StreamSecurity;
+ }
+ if (profileItem.id.IsNullOrEmpty())
+ {
+ return -1;
+ }
+
+ AddServerCommon(config, profileItem, toFile);
+
+ return 0;
+ }
+
+ ///
+ /// Add or edit server
+ ///
+ ///
+ ///
+ ///
+ public static int AddHysteria2Server(Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configType = EConfigType.Hysteria2;
+ profileItem.coreType = ECoreType.sing_box;
+
+ profileItem.address = profileItem.address.TrimEx();
+ profileItem.id = profileItem.id.TrimEx();
+ profileItem.path = profileItem.path.TrimEx();
+ profileItem.network = string.Empty;
+
+ if (Utils.IsNullOrEmpty(profileItem.streamSecurity))
+ {
+ profileItem.streamSecurity = Global.StreamSecurity;
+ }
+ if (profileItem.id.IsNullOrEmpty())
+ {
+ return -1;
+ }
+
+ AddServerCommon(config, profileItem, toFile);
+
+ return 0;
+ }
+
+ ///
+ /// Add or edit server
+ ///
+ ///
+ ///
+ ///
+ public static int AddTuicServer(Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configType = EConfigType.Tuic;
+ profileItem.coreType = ECoreType.sing_box;
+
+ profileItem.address = profileItem.address.TrimEx();
+ profileItem.id = profileItem.id.TrimEx();
+ profileItem.security = profileItem.security.TrimEx();
+ profileItem.network = string.Empty;
+
+ if (!Global.TuicCongestionControls.Contains(profileItem.headerType))
+ {
+ profileItem.headerType = Global.TuicCongestionControls.FirstOrDefault()!;
+ }
+
+ if (Utils.IsNullOrEmpty(profileItem.streamSecurity))
+ {
+ profileItem.streamSecurity = Global.StreamSecurity;
+ }
+ if (Utils.IsNullOrEmpty(profileItem.alpn))
+ {
+ profileItem.alpn = "h3";
+ }
+ if (profileItem.id.IsNullOrEmpty())
+ {
+ return -1;
+ }
+
+ AddServerCommon(config, profileItem, toFile);
+
+ return 0;
+ }
+
+ ///
+ /// Add or edit server
+ ///
+ ///
+ ///
+ ///
+ public static int AddWireguardServer(Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configType = EConfigType.Wireguard;
+ profileItem.coreType = ECoreType.sing_box;
+
+ profileItem.address = profileItem.address.TrimEx();
+ profileItem.id = profileItem.id.TrimEx();
+ profileItem.publicKey = profileItem.publicKey.TrimEx();
+ profileItem.path = profileItem.path.TrimEx();
+ profileItem.requestHost = profileItem.requestHost.TrimEx();
+ profileItem.network = string.Empty;
+ if (profileItem.shortId.IsNullOrEmpty())
+ {
+ profileItem.shortId = Global.TunMtus.FirstOrDefault();
+ }
+
+ if (profileItem.id.IsNullOrEmpty())
+ {
+ return -1;
+ }
+
+ AddServerCommon(config, profileItem, toFile);
+
+ return 0;
+ }
+
+ public static int SortServers(Config config, string subId, string colName, bool asc)
+ {
+ var lstModel = LazyConfig.Instance.ProfileItems(subId, "");
+ if (lstModel.Count <= 0)
+ {
+ return -1;
+ }
+ var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
+ var lstProfile = (from t in lstModel
+ join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b
+ from t33 in t3b.DefaultIfEmpty()
+ select new ProfileItemModel
+ {
+ indexId = t.indexId,
+ configType = t.configType,
+ remarks = t.remarks,
+ address = t.address,
+ port = t.port,
+ security = t.security,
+ network = t.network,
+ streamSecurity = t.streamSecurity,
+ delay = t33 == null ? 0 : t33.delay,
+ speed = t33 == null ? 0 : t33.speed,
+ sort = t33 == null ? 0 : t33.sort
+ }).ToList();
+
+ Enum.TryParse(colName, true, out EServerColName name);
+ var propertyName = string.Empty;
+ switch (name)
+ {
+ case EServerColName.configType:
+ case EServerColName.remarks:
+ case EServerColName.address:
+ case EServerColName.port:
+ case EServerColName.network:
+ case EServerColName.streamSecurity:
+ propertyName = name.ToString();
+ break;
+
+ case EServerColName.delayVal:
+ propertyName = "delay";
+ break;
+
+ case EServerColName.speedVal:
+ propertyName = "speed";
+ break;
+
+ case EServerColName.subRemarks:
+ propertyName = "subid";
+ break;
+
+ default:
+ return -1;
+ }
+
+ var items = lstProfile.AsQueryable();
+
+ if (asc)
+ {
+ lstProfile = items.OrderBy(propertyName).ToList();
+ }
+ else
+ {
+ lstProfile = items.OrderByDescending(propertyName).ToList();
+ }
+ for (int i = 0; i < lstProfile.Count; i++)
+ {
+ ProfileExHandler.Instance.SetSort(lstProfile[i].indexId, (i + 1) * 10);
+ }
+ if (name == EServerColName.delayVal)
+ {
+ var maxSort = lstProfile.Max(t => t.sort) + 10;
+ foreach (var item in lstProfile)
+ {
+ if (item.delay <= 0)
+ {
+ ProfileExHandler.Instance.SetSort(item.indexId, maxSort);
+ }
+ }
+ }
+ if (name == EServerColName.speedVal)
+ {
+ var maxSort = lstProfile.Max(t => t.sort) + 10;
+ foreach (var item in lstProfile)
+ {
+ if (item.speed <= 0)
+ {
+ ProfileExHandler.Instance.SetSort(item.indexId, maxSort);
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ ///
+ /// Add or edit server
+ ///
+ ///
+ ///
+ ///
+ public static int AddVlessServer(Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configType = EConfigType.VLESS;
+
+ profileItem.address = profileItem.address.TrimEx();
+ profileItem.id = profileItem.id.TrimEx();
+ profileItem.security = profileItem.security.TrimEx();
+ profileItem.network = profileItem.network.TrimEx();
+ profileItem.headerType = profileItem.headerType.TrimEx();
+ profileItem.requestHost = profileItem.requestHost.TrimEx();
+ profileItem.path = profileItem.path.TrimEx();
+ profileItem.streamSecurity = profileItem.streamSecurity.TrimEx();
+
+ if (!Global.Flows.Contains(profileItem.flow))
+ {
+ profileItem.flow = Global.Flows.First();
+ }
+ if (profileItem.id.IsNullOrEmpty())
+ {
+ return -1;
+ }
+ if (!Utils.IsNullOrEmpty(profileItem.security) && profileItem.security != Global.None)
+ {
+ profileItem.security = Global.None;
+ }
+
+ AddServerCommon(config, profileItem, toFile);
+
+ return 0;
+ }
+
+ public static List DedupServerList(List profiles)
+ {
+ var availProfiles = LazyConfig.Instance.ProfileItems();
+ int profile_nums = profiles.Count;
+
+ profiles.RemoveAll(t => availProfiles.Exists(item => CompareProfileItem(t, item, false)));
+
+ return profiles;
+ }
+
+ public static int AddServerCommon(Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configVersion = 2;
+
+ if (!Utils.IsNullOrEmpty(profileItem.streamSecurity))
+ {
+ if (profileItem.streamSecurity != Global.StreamSecurity
+ && profileItem.streamSecurity != Global.StreamSecurityReality)
+ {
+ profileItem.streamSecurity = string.Empty;
+ }
+ else
+ {
+ if (Utils.IsNullOrEmpty(profileItem.allowInsecure))
+ {
+ profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower();
+ }
+ if (Utils.IsNullOrEmpty(profileItem.fingerprint) && profileItem.streamSecurity == Global.StreamSecurityReality)
+ {
+ profileItem.fingerprint = config.coreBasicItem.defFingerprint;
+ }
+ }
+ }
+
+ if (!Utils.IsNullOrEmpty(profileItem.network) && !Global.Networks.Contains(profileItem.network))
+ {
+ profileItem.network = Global.DefaultNetwork;
+ }
+
+ var maxSort = -1;
+ if (Utils.IsNullOrEmpty(profileItem.indexId))
+ {
+ profileItem.indexId = Utils.GetGUID(false);
+ maxSort = ProfileExHandler.Instance.GetMaxSort();
+ }
+ if (!toFile && maxSort < 0)
+ {
+ maxSort = ProfileExHandler.Instance.GetMaxSort();
+ }
+ if (maxSort > 0)
+ {
+ ProfileExHandler.Instance.SetSort(profileItem.indexId, maxSort + 1);
+ }
+
+ if (toFile)
+ {
+ //SQLiteHelper.Instance.Replace(profileItem);
+ if (!RunningObjects.Instance.ProfileItems.Contains(profileItem))
+ {
+ RunningObjects.Instance.ProfileItems.Add(profileItem);
+ }
+
+ }
+ return 0;
+ }
+
+ private static bool CompareProfileItem(ProfileItem o, ProfileItem n, bool remarks)
+ {
+ if (o == null || n == null)
+ {
+ return false;
+ }
+
+ return o.configType == n.configType
+ && o.address == n.address
+ && o.port == n.port
+ && o.id == n.id
+ && o.alterId == n.alterId
+ && o.security == n.security
+ && o.network == n.network
+ && o.headerType == n.headerType
+ && o.requestHost == n.requestHost
+ && o.path == n.path
+ && (o.configType == EConfigType.Trojan || o.streamSecurity == n.streamSecurity)
+ && o.flow == n.flow
+ && o.sni == n.sni
+ && (!remarks || o.remarks == n.remarks);
+ }
+
+ private static int RemoveProfileItem(Config config, string indexId)
+ {
+ try
+ {
+ var item = LazyConfig.Instance.GetProfileItem(indexId);
+ if (item == null)
+ {
+ return 0;
+ }
+ if (item.configType == EConfigType.Custom)
+ {
+ File.Delete(Utils.GetConfigPath(item.address));
+ }
+
+ SQLiteHelper.Instance.Delete(item);
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog("Remove Item", ex);
+ }
+
+ return 0;
+ }
+
+ #endregion Server
+
+ #region Batch add servers
+
+ ///
+ /// 批量添加服务器
+ ///
+ ///
+ ///
+ ///
+ /// 成功导入的数量
+ private static int AddBatchServers(Config config, string strData, string subid, bool isSub, List lstOriSub)
+ {
+ if (Utils.IsNullOrEmpty(strData))
+ {
+ return -1;
+ }
+
+ string subFilter = string.Empty;
+ //remove sub items
+ if (isSub && !Utils.IsNullOrEmpty(subid))
+ {
+ //RemoveServerViaSubid(config, subid, isSub);
+ subFilter = LazyConfig.Instance.GetSubItem(subid)?.filter ?? "";
+ }
+
+ int countServers = 0;
+ //Check for duplicate indexId
+ List? lstDbIndexId = null;
+ List lstAdd = new();
+ var arrData = strData.Split(Environment.NewLine.ToCharArray()).Where(t => !t.IsNullOrEmpty());
+ if (isSub)
+ {
+ arrData = arrData.Distinct();
+ }
+ foreach (string str in arrData)
+ {
+ //maybe sub
+ if (!isSub && (str.StartsWith(Global.HttpsProtocol) || str.StartsWith(Global.HttpProtocol)))
+ {
+ if (AddSubItem(config, str) == 0)
+ {
+ countServers++;
+ }
+ continue;
+ }
+ var profileItem = FmtHandler.ResolveConfig(str, out string msg);
+ if (profileItem is null)
+ {
+ continue;
+ }
+
+ //exist sub items
+ if (isSub && !Utils.IsNullOrEmpty(subid))
+ {
+ var existItem = lstOriSub?.FirstOrDefault(t => t.isSub == isSub
+ && config.uiItem.enableUpdateSubOnlyRemarksExist ? t.remarks == profileItem.remarks : CompareProfileItem(t, profileItem, true));
+ if (existItem != null)
+ {
+ //Check for duplicate indexId
+ if (lstDbIndexId is null)
+ {
+ lstDbIndexId = LazyConfig.Instance.ProfileItemIndexes("");
+ }
+ if (lstAdd.Any(t => t.indexId == existItem.indexId)
+ || lstDbIndexId.Any(t => t == existItem.indexId))
+ {
+ profileItem.indexId = string.Empty;
+ }
+ else
+ {
+ profileItem.indexId = existItem.indexId;
+ }
+ }
+ //filter
+ if (!Utils.IsNullOrEmpty(subFilter))
+ {
+ if (!Regex.IsMatch(profileItem.remarks, subFilter))
+ {
+ continue;
+ }
+ }
+ }
+ profileItem.subid = subid;
+ profileItem.isSub = isSub;
+
+ var addStatus = profileItem.configType switch
+ {
+ EConfigType.VMess => AddServer(config, profileItem, false),
+ EConfigType.Shadowsocks => AddShadowsocksServer(config, profileItem, false),
+ EConfigType.Socks => AddSocksServer(config, profileItem, false),
+ EConfigType.Trojan => AddTrojanServer(config, profileItem, false),
+ EConfigType.VLESS => AddVlessServer(config, profileItem, false),
+ EConfigType.Hysteria2 => AddHysteria2Server(config, profileItem, false),
+ EConfigType.Tuic => AddTuicServer(config, profileItem, false),
+ EConfigType.Wireguard => AddWireguardServer(config, profileItem, false),
+ _ => -1,
+ };
+
+ if (addStatus == 0)
+ {
+ countServers++;
+ lstAdd.Add(profileItem);
+ }
+ }
+
+
+ foreach (var item in lstAdd)
+ {
+ RunningObjects.Instance.ProfileItems.Add(item);
+ }
+
+ ToJsonFile(config);
+ return countServers;
+ }
+
+ private static int AddBatchServers4Custom(Config config, string strData, string subid, bool isSub, List lstOriSub)
+ {
+ if (Utils.IsNullOrEmpty(strData))
+ {
+ return -1;
+ }
+ var subRemarks = LazyConfig.Instance.GetSubItem(subid)?.remarks;
+
+ List? lstProfiles = null;
+ //Is sing-box array configuration
+ if (lstProfiles is null || lstProfiles.Count <= 0)
+ {
+ lstProfiles = SingboxFmt.ResolveFullArray(strData, subRemarks);
+ }
+ //Is v2ray array configuration
+ if (lstProfiles is null || lstProfiles.Count <= 0)
+ {
+ lstProfiles = V2rayFmt.ResolveFullArray(strData, subRemarks);
+ }
+ if (lstProfiles != null && lstProfiles.Count > 0)
+ {
+ //if (isSub && !Utils.IsNullOrEmpty(subid))
+ //{
+ // RemoveServerViaSubid(config, subid, isSub);
+ //}
+ int count = 0;
+ foreach (var it in lstProfiles)
+ {
+ it.subid = subid;
+ it.isSub = isSub;
+ if (AddCustomServer(config, it, true) == 0)
+ {
+ count++;
+ }
+ }
+ if (count > 0)
+ {
+ return count;
+ }
+ }
+
+ ProfileItem? profileItem = null;
+ //Is sing-box configuration
+ if (profileItem is null)
+ {
+ profileItem = SingboxFmt.ResolveFull(strData, subRemarks);
+ }
+ //Is v2ray configuration
+ if (profileItem is null)
+ {
+ profileItem = V2rayFmt.ResolveFull(strData, subRemarks);
+ }
+ //Is Clash configuration
+ if (profileItem is null)
+ {
+ profileItem = ClashFmt.ResolveFull(strData, subRemarks);
+ }
+ //Is hysteria configuration
+ if (profileItem is null)
+ {
+ profileItem = Hysteria2Fmt.ResolveFull2(strData, subRemarks);
+ }
+ if (profileItem is null)
+ {
+ profileItem = Hysteria2Fmt.ResolveFull(strData, subRemarks);
+ }
+ //Is naiveproxy configuration
+ if (profileItem is null)
+ {
+ profileItem = NaiveproxyFmt.ResolveFull(strData, subRemarks);
+ }
+ if (profileItem is null || Utils.IsNullOrEmpty(profileItem.address))
+ {
+ return -1;
+ }
+
+ //if (isSub && !Utils.IsNullOrEmpty(subid))
+ //{
+ // RemoveServerViaSubid(config, subid, isSub);
+ //}
+ if (isSub && lstOriSub?.Count == 1)
+ {
+ profileItem.indexId = lstOriSub[0].indexId;
+ }
+ profileItem.subid = subid;
+ profileItem.isSub = isSub;
+ if (AddCustomServer(config, profileItem, true) == 0)
+ {
+ return 1;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ private static int AddBatchServers4SsSIP008(Config config, string strData, string subid, bool isSub, List lstOriSub)
+ {
+ if (Utils.IsNullOrEmpty(strData))
+ {
+ return -1;
+ }
+
+ //if (isSub && !Utils.IsNullOrEmpty(subid))
+ //{
+ // RemoveServerViaSubid(config, subid, isSub);
+ //}
+
+ var lstSsServer = ShadowsocksFmt.ResolveSip008(strData);
+ if (lstSsServer?.Count > 0)
+ {
+ int counter = 0;
+ foreach (var ssItem in lstSsServer)
+ {
+ ssItem.subid = subid;
+ ssItem.isSub = isSub;
+ if (AddShadowsocksServer(config, ssItem) == 0)
+ {
+ counter++;
+ }
+ }
+ ToJsonFile(config);
+ return counter;
+ }
+
+ return -1;
+ }
+
+ public static int AddBatchServers(Config config, string strData, string subid, bool isSub)
+ {
+ List? lstOriSub = null;
+ if (isSub && !Utils.IsNullOrEmpty(subid))
+ {
+ lstOriSub = LazyConfig.Instance.ProfileItems(subid);
+ }
+
+ var counter = 0;
+ if (Utils.IsBase64String(strData))
+ {
+ counter = AddBatchServers(config, Utils.Base64Decode(strData), subid, isSub, lstOriSub);
+ }
+ if (counter < 1)
+ {
+ counter = AddBatchServers(config, strData, subid, isSub, lstOriSub);
+ }
+ if (counter < 1)
+ {
+ counter = AddBatchServers(config, Utils.Base64Decode(strData), subid, isSub, lstOriSub);
+ }
+
+ if (counter < 1)
+ {
+ counter = AddBatchServers4SsSIP008(config, strData, subid, isSub, lstOriSub);
+ }
+
+ //maybe other sub
+ if (counter < 1)
+ {
+ counter = AddBatchServers4Custom(config, strData, subid, isSub, lstOriSub);
+ }
+
+ return counter;
+ }
+
+ #endregion Batch add servers
+
+ #region Sub & Group
+
+ ///
+ /// add sub
+ ///
+ ///
+ ///
+ ///
+ public static int AddSubItem(Config config, string url)
+ {
+ //already exists
+ if (SQLiteHelper.Instance.Table().Any(e => e.url == url))
+ {
+ return 0;
+ }
+ SubItem subItem = new()
+ {
+ id = string.Empty,
+ url = url
+ };
+
+ try
+ {
+ var uri = new Uri(url);
+ var queryVars = HttpUtility.ParseQueryString(uri.Query);
+ subItem.remarks = queryVars["remarks"] ?? "import_sub";
+ }
+ catch (UriFormatException)
+ {
+ return 0;
+ }
+
+ return AddSubItem(config, subItem);
+ }
+
+ public static int AddSubItem(Config config, SubItem subItem)
+ {
+ if (Utils.IsNullOrEmpty(subItem.id))
+ {
+ subItem.id = Utils.GetGUID(false);
+
+ if (subItem.sort <= 0)
+ {
+ var maxSort = 0;
+ if (SQLiteHelper.Instance.Table().Count() > 0)
+ {
+ maxSort = SQLiteHelper.Instance.Table().Max(t => t == null ? 0 : t.sort);
+ }
+ subItem.sort = maxSort + 1;
+ }
+ }
+ if (SQLiteHelper.Instance.Replace(subItem) > 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ ///
+ /// 移除服务器
+ ///
+ ///
+ ///
+ ///
+ public static int RemoveServerViaSubid(Config config, string subid, bool isSub)
+ {
+ if (Utils.IsNullOrEmpty(subid))
+ {
+ return -1;
+ }
+ var customProfile = SQLiteHelper.Instance.Table().Where(t => t.subid == subid && t.configType == EConfigType.Custom).ToList();
+ if (isSub)
+ {
+ SQLiteHelper.Instance.Execute($"delete from ProfileItem where isSub = 1 and subid = '{subid}'");
+ }
+ else
+ {
+ SQLiteHelper.Instance.Execute($"delete from ProfileItem where subid = '{subid}'");
+ }
+ foreach (var item in customProfile)
+ {
+ File.Delete(Utils.GetConfigPath(item.address));
+ }
+
+ return 0;
+ }
+
+ public static int DeleteSubItem(Config config, string id)
+ {
+ var item = LazyConfig.Instance.GetSubItem(id);
+ if (item is null)
+ {
+ return 0;
+ }
+ SQLiteHelper.Instance.Delete(item);
+ RemoveServerViaSubid(config, id, false);
+
+ return 0;
+ }
+
+ public static int MoveToGroup(Config config, List lstProfile, string subid)
+ {
+ foreach (var item in lstProfile)
+ {
+ item.subid = subid;
+ }
+ SQLiteHelper.Instance.UpdateAll(lstProfile);
+
+ return 0;
+ }
+
+ #endregion Sub & Group
+
+ #region Routing
+
+ public static int SaveRoutingItem(Config config, RoutingItem item)
+ {
+ if (Utils.IsNullOrEmpty(item.id))
+ {
+ item.id = Utils.GetGUID(false);
+ }
+
+ if (SQLiteHelper.Instance.Replace(item) > 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ ///
+ /// AddBatchRoutingRules
+ ///
+ ///
+ ///
+ ///
+ public static int AddBatchRoutingRules(ref RoutingItem routingItem, string strData)
+ {
+ if (Utils.IsNullOrEmpty(strData))
+ {
+ return -1;
+ }
+
+ var lstRules = JsonUtils.Deserialize>(strData);
+ if (lstRules == null)
+ {
+ return -1;
+ }
+
+ foreach (var item in lstRules)
+ {
+ item.id = Utils.GetGUID(false);
+ }
+ routingItem.ruleNum = lstRules.Count;
+ routingItem.ruleSet = JsonUtils.Serialize(lstRules, false);
+
+ if (Utils.IsNullOrEmpty(routingItem.id))
+ {
+ routingItem.id = Utils.GetGUID(false);
+ }
+
+ if (SQLiteHelper.Instance.Replace(routingItem) > 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ ///
+ /// MoveRoutingRule
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int MoveRoutingRule(List rules, int index, EMove eMove, int pos = -1)
+ {
+ int count = rules.Count;
+ if (index < 0 || index > rules.Count - 1)
+ {
+ return -1;
+ }
+ switch (eMove)
+ {
+ case EMove.Top:
+ {
+ if (index == 0)
+ {
+ return 0;
+ }
+ var item = JsonUtils.DeepCopy(rules[index]);
+ rules.RemoveAt(index);
+ rules.Insert(0, item);
+
+ break;
+ }
+ case EMove.Up:
+ {
+ if (index == 0)
+ {
+ return 0;
+ }
+ var item = JsonUtils.DeepCopy(rules[index]);
+ rules.RemoveAt(index);
+ rules.Insert(index - 1, item);
+
+ break;
+ }
+
+ case EMove.Down:
+ {
+ if (index == count - 1)
+ {
+ return 0;
+ }
+ var item = JsonUtils.DeepCopy(rules[index]);
+ rules.RemoveAt(index);
+ rules.Insert(index + 1, item);
+
+ break;
+ }
+ case EMove.Bottom:
+ {
+ if (index == count - 1)
+ {
+ return 0;
+ }
+ var item = JsonUtils.DeepCopy(rules[index]);
+ rules.RemoveAt(index);
+ rules.Add(item);
+
+ break;
+ }
+ case EMove.Position:
+ {
+ var removeItem = rules[index];
+ var item = JsonUtils.DeepCopy(rules[index]);
+ rules.Insert(pos, item);
+ rules.Remove(removeItem);
+ break;
+ }
+ }
+ return 0;
+ }
+
+ public static int SetDefaultRouting(Config config, RoutingItem routingItem)
+ {
+ if (SQLiteHelper.Instance.Table().Where(t => t.id == routingItem.id).Count() > 0)
+ {
+ config.routingBasicItem.routingIndexId = routingItem.id;
+ }
+
+ ToJsonFile(config);
+
+ return 0;
+ }
+
+ public static RoutingItem GetDefaultRouting(Config config)
+ {
+ var item = LazyConfig.Instance.GetRoutingItem(config.routingBasicItem.routingIndexId);
+ if (item is null)
+ {
+ var item2 = SQLiteHelper.Instance.Table().FirstOrDefault(t => t.locked == false);
+ SetDefaultRouting(config, item2);
+ return item2;
+ }
+
+ return item;
+ }
+
+ public static int InitBuiltinRouting(Config config, bool blImportAdvancedRules = false)
+ {
+ var ver = "V3-";
+ var items = LazyConfig.Instance.RoutingItems();
+ if (blImportAdvancedRules || items.Where(t => t.remarks.StartsWith(ver)).ToList().Count <= 0)
+ {
+ var maxSort = items.Count;
+ //Bypass the mainland
+ var item2 = new RoutingItem()
+ {
+ remarks = $"{ver}绕过大陆(Whitelist)",
+ url = string.Empty,
+ sort = maxSort + 1,
+ };
+ AddBatchRoutingRules(ref item2, Utils.GetEmbedText(Global.CustomRoutingFileName + "white"));
+
+ //Blacklist
+ var item3 = new RoutingItem()
+ {
+ remarks = $"{ver}黑名单(Blacklist)",
+ url = string.Empty,
+ sort = maxSort + 2,
+ };
+ AddBatchRoutingRules(ref item3, Utils.GetEmbedText(Global.CustomRoutingFileName + "black"));
+
+ //Global
+ var item1 = new RoutingItem()
+ {
+ remarks = $"{ver}全局(Global)",
+ url = string.Empty,
+ sort = maxSort + 3,
+ };
+ AddBatchRoutingRules(ref item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "global"));
+
+ if (!blImportAdvancedRules)
+ {
+ SetDefaultRouting(config, item2);
+ }
+ }
+
+ if (GetLockedRoutingItem(config) == null)
+ {
+ var item1 = new RoutingItem()
+ {
+ remarks = "locked",
+ url = string.Empty,
+ locked = true,
+ };
+ AddBatchRoutingRules(ref item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "locked"));
+ }
+ return 0;
+ }
+
+ public static RoutingItem GetLockedRoutingItem(Config config)
+ {
+ return SQLiteHelper.Instance.Table().FirstOrDefault(it => it.locked == true);
+ }
+
+ public static void RemoveRoutingItem(RoutingItem routingItem)
+ {
+ SQLiteHelper.Instance.Delete(routingItem);
+ }
+
+ #endregion Routing
+
+ #region DNS
+
+ public static int InitBuiltinDNS(Config config)
+ {
+ var items = LazyConfig.Instance.DNSItems();
+ if (items.Count <= 0)
+ {
+ var item = new DNSItem()
+ {
+ remarks = "V2ray",
+ coreType = ECoreType.Xray,
+ };
+ SaveDNSItems(config, item);
+
+ var item2 = new DNSItem()
+ {
+ remarks = "sing-box",
+ coreType = ECoreType.sing_box,
+ };
+ SaveDNSItems(config, item2);
+ }
+
+ return 0;
+ }
+
+ public static int SaveDNSItems(Config config, DNSItem item)
+ {
+ if (Utils.IsNullOrEmpty(item.id))
+ {
+ item.id = Utils.GetGUID(false);
+ }
+
+ if (SQLiteHelper.Instance.Replace(item) > 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ #endregion DNS
+ }
+}
\ No newline at end of file
diff --git a/v2rayMiniConsole/v2rayMiniConsole/Handler/CoreConfig/CoreConfigClash.cs b/v2rayMiniConsole/v2rayMiniConsole/Handler/CoreConfig/CoreConfigClash.cs
new file mode 100644
index 00000000..1ea4c5d3
--- /dev/null
+++ b/v2rayMiniConsole/v2rayMiniConsole/Handler/CoreConfig/CoreConfigClash.cs
@@ -0,0 +1,271 @@
+using System.IO;
+using v2rayN.Common;
+using v2rayN.Enums;
+using v2rayN.Models;
+using v2rayMiniConsole.Resx;
+
+namespace v2rayN.Handler.CoreConfig
+{
+ ///
+ /// Core configuration file processing class
+ ///
+ internal class CoreConfigClash
+ {
+ private Config _config;
+
+ public CoreConfigClash(Config config)
+ {
+ _config = config;
+ }
+
+ ///
+ /// 生成配置文件
+ ///
+ ///
+ ///
+ ///
+ ///
+ public int GenerateClientConfig(ProfileItem node, string? fileName, out string msg)
+ {
+ if (node == null || fileName is null)
+ {
+ msg = ResUI.CheckServerSettings;
+ return -1;
+ }
+
+ msg = ResUI.InitialConfiguration;
+
+ try
+ {
+ if (node == null)
+ {
+ msg = ResUI.CheckServerSettings;
+ return -1;
+ }
+
+ if (File.Exists(fileName))
+ {
+ File.Delete(fileName);
+ }
+
+ string addressFileName = node.address;
+ if (string.IsNullOrEmpty(addressFileName))
+ {
+ msg = ResUI.FailedGetDefaultConfiguration;
+ return -1;
+ }
+ if (!File.Exists(addressFileName))
+ {
+ addressFileName = Path.Combine(Utils.GetConfigPath(), addressFileName);
+ }
+ if (!File.Exists(addressFileName))
+ {
+ msg = ResUI.FailedReadConfiguration + "1";
+ return -1;
+ }
+
+ string tagYamlStr1 = "!";
+ string tagYamlStr2 = "__strn__";
+ string tagYamlStr3 = "!!str";
+ var txtFile = File.ReadAllText(addressFileName);
+ txtFile = txtFile.Replace(tagYamlStr1, tagYamlStr2);
+
+ var fileContent = YamlUtils.FromYaml>(txtFile);
+ if (fileContent == null)
+ {
+ msg = ResUI.FailedConversionConfiguration;
+ return -1;
+ }
+
+ //port
+ fileContent["port"] = LazyConfig.Instance.GetLocalPort(EInboundProtocol.http);
+ //socks-port
+ fileContent["socks-port"] = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks);
+ //log-level
+ fileContent["log-level"] = GetLogLevel(_config.coreBasicItem.loglevel);
+
+ //external-controller
+ fileContent["external-controller"] = $"{Global.Loopback}:{LazyConfig.Instance.StatePort2}";
+ //allow-lan
+ if (_config.inbound[0].allowLANConn)
+ {
+ fileContent["allow-lan"] = "true";
+ fileContent["bind-address"] = "*";
+ }
+ else
+ {
+ fileContent["allow-lan"] = "false";
+ }
+
+ //ipv6
+ fileContent["ipv6"] = _config.clashUIItem.enableIPv6;
+
+ //mode
+ if (!fileContent.ContainsKey("mode"))
+ {
+ fileContent["mode"] = ERuleMode.Rule.ToString().ToLower();
+ }
+ else
+ {
+ if (_config.clashUIItem.ruleMode != ERuleMode.Unchanged)
+ {
+ fileContent["mode"] = _config.clashUIItem.ruleMode.ToString().ToLower();
+ }
+ }
+
+ //enable tun mode
+ if (_config.tunModeItem.enableTun)
+ {
+ string tun = Utils.GetEmbedText(Global.ClashTunYaml);
+ if (!string.IsNullOrEmpty(tun))
+ {
+ var tunContent = YamlUtils.FromYaml>(tun);
+ if (tunContent != null)
+ fileContent["tun"] = tunContent["tun"];
+ }
+ }
+
+ //Mixin
+ try
+ {
+ MixinContent(fileContent, node);
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog("GenerateClientConfigClash-Mixin", ex);
+ }
+
+ var txtFileNew = YamlUtils.ToYaml(fileContent).Replace(tagYamlStr2, tagYamlStr3);
+ File.WriteAllText(fileName, txtFileNew);
+ //check again
+ if (!File.Exists(fileName))
+ {
+ msg = ResUI.FailedReadConfiguration + "2";
+ return -1;
+ }
+
+ ClashApiHandler.Instance.ProfileContent = fileContent;
+
+ msg = string.Format(ResUI.SuccessfulConfiguration, $"{node.GetSummary()}");
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog("GenerateClientConfigClash", ex);
+ msg = ResUI.FailedGenDefaultConfiguration;
+ return -1;
+ }
+ return 0;
+ }
+
+ private void MixinContent(Dictionary fileContent, ProfileItem node)
+ {
+ //if (!_config.clashUIItem.enableMixinContent)
+ //{
+ // return;
+ //}
+
+ var path = Utils.GetConfigPath(Global.ClashMixinConfigFileName);
+ if (!File.Exists(path))
+ {
+ return;
+ }
+
+ var txtFile = File.ReadAllText(Utils.GetConfigPath(Global.ClashMixinConfigFileName));
+
+ var mixinContent = YamlUtils.FromYaml>(txtFile);
+ if (mixinContent == null)
+ {
+ return;
+ }
+ foreach (var item in mixinContent)
+ {
+ if (!_config.tunModeItem.enableTun && item.Key == "tun")
+ {
+ continue;
+ }
+
+ if (item.Key.StartsWith("prepend-")
+ || item.Key.StartsWith("append-")
+ || item.Key.StartsWith("removed-"))
+ {
+ ModifyContentMerge(fileContent, item.Key, item.Value);
+ }
+ else
+ {
+ fileContent[item.Key] = item.Value;
+ }
+ }
+ return;
+ }
+
+ private void ModifyContentMerge(Dictionary fileContent, string key, object value)
+ {
+ bool blPrepend = false;
+ bool blRemoved = false;
+ if (key.StartsWith("prepend-"))
+ {
+ blPrepend = true;
+ key = key.Replace("prepend-", "");
+ }
+ else if (key.StartsWith("append-"))
+ {
+ blPrepend = false;
+ key = key.Replace("append-", "");
+ }
+ else if (key.StartsWith("removed-"))
+ {
+ blRemoved = true;
+ key = key.Replace("removed-", "");
+ }
+ else
+ {
+ return;
+ }
+
+ if (!blRemoved && !fileContent.ContainsKey(key))
+ {
+ fileContent.Add(key, value);
+ return;
+ }
+ var lstOri = (List