aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2023-09-04 23:15:49 +0800
committercrupest <crupest@outlook.com>2023-09-04 23:15:49 +0800
commit4f1862ca278020930631548726477ec1ebb8ecbf (patch)
treea836da089d6bd61218852e002927466e738a7934 /tools
parent0814c4da82fb022a92aede87019f0100e7eb6923 (diff)
downloadcrupest-4f1862ca278020930631548726477ec1ebb8ecbf.tar.gz
crupest-4f1862ca278020930631548726477ec1ebb8ecbf.tar.bz2
crupest-4f1862ca278020930631548726477ec1ebb8ecbf.zip
Add a mysterious tool.
Diffstat (limited to 'tools')
-rwxr-xr-xtools/V2rayConfigGen/.gitignore2
-rwxr-xr-xtools/V2rayConfigGen/V2rayConfigGen.sln30
-rwxr-xr-xtools/V2rayConfigGen/V2rayConfigGen/.gitignore1
-rwxr-xr-xtools/V2rayConfigGen/V2rayConfigGen/FileUtility.cs94
-rwxr-xr-xtools/V2rayConfigGen/V2rayConfigGen/Program.cs22
-rwxr-xr-xtools/V2rayConfigGen/V2rayConfigGen/V2rayConfig.cs48
-rwxr-xr-xtools/V2rayConfigGen/V2rayConfigGen/V2rayConfigGen.csproj22
-rwxr-xr-xtools/V2rayConfigGen/V2rayConfigGen/V2rayRouting.cs52
-rwxr-xr-xtools/V2rayConfigGen/V2rayConfigGen/V2rayRoutingRule.cs27
-rwxr-xr-xtools/V2rayConfigGen/V2rayConfigGen/V2rayRoutingRuleMatcher.cs72
-rwxr-xr-xtools/V2rayConfigGen/V2rayConfigGen/V2rayVmessProxy.cs52
-rwxr-xr-xtools/V2rayConfigGen/V2rayConfigGen/config.json.template63
-rwxr-xr-xtools/V2rayConfigGen/V2rayConfigGen/proxy.txt16
13 files changed, 501 insertions, 0 deletions
diff --git a/tools/V2rayConfigGen/.gitignore b/tools/V2rayConfigGen/.gitignore
new file mode 100755
index 0000000..1746e32
--- /dev/null
+++ b/tools/V2rayConfigGen/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/tools/V2rayConfigGen/V2rayConfigGen.sln b/tools/V2rayConfigGen/V2rayConfigGen.sln
new file mode 100755
index 0000000..e864a06
--- /dev/null
+++ b/tools/V2rayConfigGen/V2rayConfigGen.sln
@@ -0,0 +1,30 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.7.34024.191
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "V2rayConfigGen", "V2rayConfigGen\V2rayConfigGen.csproj", "{05719320-C91F-4D2A-82A5-1D0247DDB389}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F4C2CE80-CDF8-4B08-8912-D1F0F14196AD}"
+ 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
+ {05719320-C91F-4D2A-82A5-1D0247DDB389}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {05719320-C91F-4D2A-82A5-1D0247DDB389}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {05719320-C91F-4D2A-82A5-1D0247DDB389}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {05719320-C91F-4D2A-82A5-1D0247DDB389}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {B1E8FD9C-9157-4F4E-8265-4B37F30EEC5E}
+ EndGlobalSection
+EndGlobal
diff --git a/tools/V2rayConfigGen/V2rayConfigGen/.gitignore b/tools/V2rayConfigGen/V2rayConfigGen/.gitignore
new file mode 100755
index 0000000..c936492
--- /dev/null
+++ b/tools/V2rayConfigGen/V2rayConfigGen/.gitignore
@@ -0,0 +1 @@
+vmess.txt
diff --git a/tools/V2rayConfigGen/V2rayConfigGen/FileUtility.cs b/tools/V2rayConfigGen/V2rayConfigGen/FileUtility.cs
new file mode 100755
index 0000000..08de673
--- /dev/null
+++ b/tools/V2rayConfigGen/V2rayConfigGen/FileUtility.cs
@@ -0,0 +1,94 @@
+using System.Text.Json;
+using System.Text.RegularExpressions;
+
+namespace Crupest.V2ray;
+
+public static partial class FileUtility
+{
+ public static List<string> ReadList(string str)
+ {
+ return str.Split("\n", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList();
+ }
+
+ public static Dictionary<string, string> ReadDictionary(string str, bool keyToLower = true)
+ {
+ var lines = str.Split("\n", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
+ var result = new Dictionary<string, string>();
+ for (int lineNumber = 0; lineNumber < lines.Length; lineNumber++)
+ {
+ var line = lines[lineNumber];
+ if (!line.Contains('='))
+ {
+ throw new FormatException($"Line {lineNumber + 1} does not contain a '='.");
+ }
+ var equalIndex = line.IndexOf('=');
+ var key = line[..equalIndex].Trim();
+ if (keyToLower) key = key.ToLower();
+ var value = line[(equalIndex + 1)..].Trim();
+ result[key] = value;
+ }
+ return result;
+ }
+
+ public static List<string> ReadListFile(string path, bool required = true)
+ {
+ if (File.Exists(path))
+ {
+ return ReadList(File.ReadAllText(path));
+ }
+ else
+ {
+ if (required)
+ {
+ throw new FileNotFoundException($"File {path} is required but it does not exist.");
+ }
+ return new();
+ }
+ }
+
+ public static Dictionary<string, string> ReadDictionaryFile(string path, bool required = true, bool keyToLower = true)
+ {
+ if (File.Exists(path))
+ {
+ return ReadDictionary(File.ReadAllText(path), keyToLower);
+ }
+ else
+ {
+ if (required)
+ {
+ throw new FileNotFoundException($"File {path} is required but it does not exist.");
+ }
+ return new();
+ }
+ }
+
+ private static Regex TemplateValuePattern { get; } = CreateTemplateValuePattern();
+
+ [GeneratedRegex(@"\$\{\s*([_a-zA-Z][_a-zA-Z0-9]*)\s*\}")]
+ private static partial Regex CreateTemplateValuePattern();
+
+ public static string TextFromTemplate(string template, Dictionary<string, string> dict)
+ {
+ return TemplateValuePattern.Replace(template, (match) =>
+ {
+ var key = match.Groups[1].Value;
+ if (dict.ContainsKey(key))
+ {
+ return dict[key];
+ }
+ return match.Value;
+ });
+ }
+
+ public static string JsonFormat(string json)
+ {
+ var options = new JsonSerializerOptions
+ {
+ WriteIndented = true,
+ AllowTrailingCommas = true,
+ ReadCommentHandling = JsonCommentHandling.Skip
+ };
+
+ return JsonSerializer.Serialize(JsonSerializer.Deserialize<JsonDocument>(json, options), options);
+ }
+}
diff --git a/tools/V2rayConfigGen/V2rayConfigGen/Program.cs b/tools/V2rayConfigGen/V2rayConfigGen/Program.cs
new file mode 100755
index 0000000..bebdc7a
--- /dev/null
+++ b/tools/V2rayConfigGen/V2rayConfigGen/Program.cs
@@ -0,0 +1,22 @@
+using System.Reflection;
+
+namespace Crupest.V2ray;
+
+public static class Program
+{
+ public const string ConfigTemplateFile = "config.json.template";
+ public const string VmessConfigFile = "vmess.txt";
+ public const string ProxyGeoSitesFile = "proxy.txt";
+
+ public static void Main(string[] args)
+ {
+ var exeLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+ var config = V2rayConfig.FromFiles(
+ Path.Combine(exeLocation, ConfigTemplateFile),
+ Path.Combine(exeLocation, VmessConfigFile),
+ Path.Combine(exeLocation, ProxyGeoSitesFile)
+ );
+
+ Console.Write(config.ToJson());
+ }
+}
diff --git a/tools/V2rayConfigGen/V2rayConfigGen/V2rayConfig.cs b/tools/V2rayConfigGen/V2rayConfigGen/V2rayConfig.cs
new file mode 100755
index 0000000..0d8b0bb
--- /dev/null
+++ b/tools/V2rayConfigGen/V2rayConfigGen/V2rayConfig.cs
@@ -0,0 +1,48 @@
+using System.Text.Json;
+
+namespace Crupest.V2ray;
+
+public class V2rayConfig
+{
+ private const string VmessAnchor = "VMESS_PROXY_ANCHOR";
+ private const string RoutingAnchor = "ROUTING_ANCHOR";
+
+ public V2rayConfig(string template, V2rayVmessProxy vmess, V2rayRouting router) {
+ Template = template;
+ Vmess = vmess;
+ Routing = router;
+ }
+
+ public string Template { get; set; }
+ public V2rayVmessProxy Vmess { get; set; }
+ public V2rayRouting Routing { get; set; }
+
+ public string ToJson(bool pretty = true)
+ {
+ var jsonOptions = new JsonSerializerOptions(new JsonSerializerOptions
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
+ });
+
+ var templateValues = new Dictionary<string, string>
+ {
+ [VmessAnchor] = JsonSerializer.Serialize(Vmess.ToOutboundJsonObject(), jsonOptions),
+ [RoutingAnchor] = JsonSerializer.Serialize(Routing.ToJsonObject(), jsonOptions)
+ };
+
+ return FileUtility.JsonFormat(FileUtility.TextFromTemplate(Template, templateValues));
+ }
+
+ public static V2rayConfig FromFiles(string templatePath, string vmessPath, string routingPath)
+ {
+ var template = File.ReadAllText(templatePath);
+ var vmessDict = FileUtility.ReadDictionaryFile(vmessPath);
+ var proxyRoutingList = FileUtility.ReadListFile(routingPath);
+
+ var vmess = V2rayVmessProxy.FromDictionary(vmessDict);
+ var routing = V2rayRouting.FromStringList(proxyRoutingList);
+
+ return new V2rayConfig(template, vmess, routing);
+ }
+}
diff --git a/tools/V2rayConfigGen/V2rayConfigGen/V2rayConfigGen.csproj b/tools/V2rayConfigGen/V2rayConfigGen/V2rayConfigGen.csproj
new file mode 100755
index 0000000..38f0937
--- /dev/null
+++ b/tools/V2rayConfigGen/V2rayConfigGen/V2rayConfigGen.csproj
@@ -0,0 +1,22 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFramework>net7.0</TargetFramework>
+ <ImplicitUsings>enable</ImplicitUsings>
+ <Nullable>enable</Nullable>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <None Update="config.json.template">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
+ <None Update="proxy.txt">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
+ <None Update="vmess.txt">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
+ </ItemGroup>
+
+</Project>
diff --git a/tools/V2rayConfigGen/V2rayConfigGen/V2rayRouting.cs b/tools/V2rayConfigGen/V2rayConfigGen/V2rayRouting.cs
new file mode 100755
index 0000000..fe59491
--- /dev/null
+++ b/tools/V2rayConfigGen/V2rayConfigGen/V2rayRouting.cs
@@ -0,0 +1,52 @@
+namespace Crupest.V2ray;
+
+public record V2rayRouting(List<V2rayRoutingRule> Rules, string DomainStrategy = "IpOnDemand")
+{
+ public record DomainRuleJsonObject(List<string> Domains, string OutboundTag, string Type = "field");
+
+ public record IpRuleJsonObject(List<string> Ip, string OutboundTag, string Type = "field");
+
+ public record RoutingJsonObject(string DomainStrategy, List<object> Rules);
+
+ public V2rayRouting() : this(new List<V2rayRoutingRule>())
+ {
+
+ }
+
+ public RoutingJsonObject ToJsonObject()
+ {
+ var ruleJsonObjects = new List<object>();
+
+ foreach (var(outBoundTag, proxyRules) in V2rayRoutingRule.GroupByOutboundTag(Rules))
+ {
+ foreach (var (matchByKind, rules) in V2rayRoutingRule.GroupByMatchByKind(proxyRules))
+ {
+ ruleJsonObjects.Add(
+ matchByKind switch
+ {
+ V2rayRoutingRuleMatcher.MatchByKind.Ip => new IpRuleJsonObject(rules.Select(r => r.Matcher.ToString()).ToList(), outBoundTag),
+ V2rayRoutingRuleMatcher.MatchByKind.Domain => new DomainRuleJsonObject(rules.Select(r => r.Matcher.ToString()).ToList(), outBoundTag),
+ _ => throw new Exception("Unknown match by kind."),
+ }
+ );
+ }
+ }
+
+ return new RoutingJsonObject(DomainStrategy ,ruleJsonObjects);
+ }
+
+ public static V2rayRouting FromStringList(List<string> list, string outboundTag = "proxy")
+ {
+ var router = new V2rayRouting();
+
+ foreach (var line in list)
+ {
+ var matcher = V2rayRoutingRuleMatcher.Parse(line);
+ if (matcher != null)
+ router.Rules.Add(new V2rayRoutingRule(matcher, outboundTag));
+ }
+
+ return router;
+ }
+}
+
diff --git a/tools/V2rayConfigGen/V2rayConfigGen/V2rayRoutingRule.cs b/tools/V2rayConfigGen/V2rayConfigGen/V2rayRoutingRule.cs
new file mode 100755
index 0000000..23c08e7
--- /dev/null
+++ b/tools/V2rayConfigGen/V2rayConfigGen/V2rayRoutingRule.cs
@@ -0,0 +1,27 @@
+using System.Linq;
+
+namespace Crupest.V2ray;
+
+public record V2rayRoutingRule(V2rayRoutingRuleMatcher Matcher, string OutboundTag)
+{
+ public static Dictionary<string, List<V2rayRoutingRule>> GroupByOutboundTag(List<V2rayRoutingRule> rules)
+ {
+ var result = new Dictionary<string, List<V2rayRoutingRule>>();
+ foreach (var group in rules.GroupBy(r => r.OutboundTag))
+ {
+ result[group.Key] = group.ToList();
+ }
+ return result;
+ }
+
+ public static Dictionary<V2rayRoutingRuleMatcher.MatchByKind, List<V2rayRoutingRule>> GroupByMatchByKind(List<V2rayRoutingRule> rules)
+ {
+ var result = new Dictionary<V2rayRoutingRuleMatcher.MatchByKind, List<V2rayRoutingRule>>();
+ foreach (var group in rules.GroupBy(r => r.Matcher.MatchBy))
+ {
+ result[group.Key] = group.ToList();
+ }
+ return result;
+ }
+}
+
diff --git a/tools/V2rayConfigGen/V2rayConfigGen/V2rayRoutingRuleMatcher.cs b/tools/V2rayConfigGen/V2rayConfigGen/V2rayRoutingRuleMatcher.cs
new file mode 100755
index 0000000..be27231
--- /dev/null
+++ b/tools/V2rayConfigGen/V2rayConfigGen/V2rayRoutingRuleMatcher.cs
@@ -0,0 +1,72 @@
+namespace Crupest.V2ray;
+
+public record V2rayRoutingRuleMatcher(V2rayRoutingRuleMatcher.MatchKind Kind, string Value)
+{
+ public enum MatchByKind
+ {
+ Domain,
+ Ip
+ }
+
+ public enum MatchKind
+ {
+ GeoIp,
+ GeoSite,
+ DomainPlain,
+ DomainSuffix,
+ DomainRegex,
+ DomainFull,
+ }
+
+ public MatchByKind MatchBy
+ {
+ get
+ {
+ return Kind switch
+ {
+ MatchKind.GeoIp => MatchByKind.Ip,
+ _ => MatchByKind.Domain
+ };
+ }
+ }
+
+ public static V2rayRoutingRuleMatcher? Parse(string line)
+ {
+ if (line.IndexOf('#') != -1)
+ {
+ line = line[..line.IndexOf('#')];
+ }
+
+ line = line.Trim();
+
+ if (line.Length == 0) { return null; }
+
+ var kind = MatchKind.DomainSuffix;
+
+ foreach (var name in Enum.GetNames<MatchKind>()) {
+ if (line.StartsWith(name)) {
+ kind = Enum.Parse<MatchKind>(name);
+ line = line[name.Length..];
+ line = line.Trim();
+ break;
+ }
+ }
+
+ return new V2rayRoutingRuleMatcher(kind, line);
+ }
+
+
+ public override string ToString()
+ {
+ return Kind switch
+ {
+ MatchKind.GeoSite => $"geosite:{Value}",
+ MatchKind.GeoIp => $"geoip:{Value}",
+ MatchKind.DomainPlain => Value,
+ MatchKind.DomainSuffix => $"domain:{Value}",
+ MatchKind.DomainFull => $"full:{Value}",
+ MatchKind.DomainRegex => $"regexp:{Value}",
+ _ => throw new Exception("Unknown matcher kind."),
+ };
+ }
+}
diff --git a/tools/V2rayConfigGen/V2rayConfigGen/V2rayVmessProxy.cs b/tools/V2rayConfigGen/V2rayConfigGen/V2rayVmessProxy.cs
new file mode 100755
index 0000000..25d466e
--- /dev/null
+++ b/tools/V2rayConfigGen/V2rayConfigGen/V2rayVmessProxy.cs
@@ -0,0 +1,52 @@
+namespace Crupest.V2ray;
+
+public class V2rayVmessProxy
+{
+ public record VmessOutboundJsonObject(string Protocol, SettingsJsonObject Settings, string Tag, StreamSettingsJsonObject StreamSettings)
+ {
+ public static VmessOutboundJsonObject ByWs(string address, int port, string uuid, string tag, string path)
+ {
+ return new VmessOutboundJsonObject("vmess", new SettingsJsonObject(
+ new List<VnextJsonObject>{ new VnextJsonObject(address, port, new List<VnextUserJsonObject> { new VnextUserJsonObject(uuid) }) }
+ ), tag, StreamSettingsJsonObject.Ws(path));
+ }
+ }
+
+ public record SettingsJsonObject(List<VnextJsonObject> Vnext);
+
+ public record VnextJsonObject(string Address, int Port, List<VnextUserJsonObject> Users);
+
+ public record VnextUserJsonObject(string Id, int AlterId = 0, string Security = "auto", int Level = 0);
+
+ public record StreamSettingsJsonObject(string Network, string Security, WsSettingsJsonObject WsSettings) {
+ public static StreamSettingsJsonObject Ws(string path)
+ {
+ return new StreamSettingsJsonObject("ws", "tls", new WsSettingsJsonObject(path, new()));
+ }
+ }
+
+ public record WsSettingsJsonObject(string Path, Dictionary<string, string> Headers);
+
+ public string Host { get; set; }
+ public int Port { get; set; }
+ public string Path { get; set; }
+ public string UserId { get; set; }
+
+
+ public V2rayVmessProxy(string host, int port, string userId, string path) {
+ Host = host;
+ Port = port;
+ UserId = userId;
+ Path = path;
+ }
+
+ public VmessOutboundJsonObject ToOutboundJsonObject(string tag = "proxy")
+ {
+ return VmessOutboundJsonObject.ByWs(Host, Port, UserId, tag, Path);
+ }
+
+ public static V2rayVmessProxy FromDictionary(Dictionary<string, string> dict)
+ {
+ return new V2rayVmessProxy(dict["host"], int.Parse(dict["port"]), dict["userid"], dict["path"]);
+ }
+}
diff --git a/tools/V2rayConfigGen/V2rayConfigGen/config.json.template b/tools/V2rayConfigGen/V2rayConfigGen/config.json.template
new file mode 100755
index 0000000..9ba8af6
--- /dev/null
+++ b/tools/V2rayConfigGen/V2rayConfigGen/config.json.template
@@ -0,0 +1,63 @@
+{
+ "log": {
+ "loglevel": "warning"
+ },
+ "inbounds": [
+ {
+ "port": 2081,
+ "listen": "127.0.0.1",
+ "tag": "socks-inbound",
+ "protocol": "socks",
+ "settings": {
+ "auth": "noauth"
+ }
+ },
+ {
+ "port": 2080,
+ "listen": "127.0.0.1",
+ "tag": "http-inbound",
+ "protocol": "http",
+ "settings": {
+ "auth": "noauth"
+ }
+ }
+ ],
+ "outbounds": [
+ {
+ "protocol": "freedom",
+ "settings": {},
+ "tag": "direct"
+ },
+ {
+ "protocol": "blackhole",
+ "settings": {},
+ "tag": "blocked"
+ },
+ ${VMESS_PROXY_ANCHOR}
+ ],
+ "routing": ${ROUTING_ANCHOR},
+ "dns": {
+ "hosts": {},
+ "servers": [
+ "https://doh.pub/dns-query",
+ "1.1.1.1",
+ "8.8.8.8",
+ "localhost"
+ ]
+ },
+ "policy": {
+ "levels": {
+ "0": {
+ "uplinkOnly": 0,
+ "downlinkOnly": 0
+ }
+ },
+ "system": {
+ "statsInboundUplink": false,
+ "statsInboundDownlink": false,
+ "statsOutboundUplink": false,
+ "statsOutboundDownlink": false
+ }
+ },
+ "other": {}
+}
diff --git a/tools/V2rayConfigGen/V2rayConfigGen/proxy.txt b/tools/V2rayConfigGen/V2rayConfigGen/proxy.txt
new file mode 100755
index 0000000..4e9d3e8
--- /dev/null
+++ b/tools/V2rayConfigGen/V2rayConfigGen/proxy.txt
@@ -0,0 +1,16 @@
+GeoSite github
+GeoSite google
+GeoSite youtube
+GeoSite twitter
+GeoSite facebook
+GeoSite discord
+GeoSite reddit
+GeoSite wikimedia
+GeoSite stackexchange
+GeoSite libgen
+GeoSite python
+GeoSite ruby
+GeoSite creativecommons
+GeoSite sci-hub
+GeoSite v2ray
+GeoSite imgur