aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/Crupest.SecretTool/Crupest.SecretTool/Crupest.SecretTool.csproj6
-rw-r--r--tools/Crupest.SecretTool/Crupest.SecretTool/Program.cs19
-rw-r--r--tools/Crupest.SecretTool/Crupest.SecretTool/Proxy.cs2
-rw-r--r--tools/Crupest.SecretTool/Crupest.SecretTool/Routing.cs2
-rw-r--r--tools/Crupest.SecretTool/Crupest.SecretTool/SingConfigJsonObjects.cs2
-rw-r--r--tools/Crupest.SecretTool/Crupest.SecretTool/ToolConfig.cs155
-rw-r--r--tools/Crupest.SecretTool/Crupest.SecretTool/sing-config.json.template24
-rw-r--r--tools/Crupest.SecretTool/Crupest.SecretTool/sing-inbounds-mobile.json11
-rw-r--r--tools/Crupest.SecretTool/Crupest.SecretTool/sing-inbounds-pc.json14
-rw-r--r--tools/Crupest.SecretTool/build-secret.ps125
10 files changed, 168 insertions, 92 deletions
diff --git a/tools/Crupest.SecretTool/Crupest.SecretTool/Crupest.SecretTool.csproj b/tools/Crupest.SecretTool/Crupest.SecretTool/Crupest.SecretTool.csproj
index 1e011b1..2502e74 100644
--- a/tools/Crupest.SecretTool/Crupest.SecretTool/Crupest.SecretTool.csproj
+++ b/tools/Crupest.SecretTool/Crupest.SecretTool/Crupest.SecretTool.csproj
@@ -23,6 +23,12 @@
<None Update="sing-config.json.template">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
+ <None Update="sing-inbounds-mobile.json">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
+ <None Update="sing-inbounds-pc.json">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
</ItemGroup>
</Project>
diff --git a/tools/Crupest.SecretTool/Crupest.SecretTool/Program.cs b/tools/Crupest.SecretTool/Crupest.SecretTool/Program.cs
index 310143d..18b1ac0 100644
--- a/tools/Crupest.SecretTool/Crupest.SecretTool/Program.cs
+++ b/tools/Crupest.SecretTool/Crupest.SecretTool/Program.cs
@@ -64,18 +64,22 @@ public static class Program
{
if (args.Length != 0)
{
- if (args.Length != 1)
- {
- throw new Exception("Invalid command line arguments.");
- }
var verb = args[0].ToLower();
if (verb == "download-geodata" || verb == "dg")
{
+ if (args.Length != 1)
+ {
+ throw new Exception("Invalid command line arguments. download-geodata requires no arguments.");
+ }
GeoDataManager.Instance.Download(CrupestSecretToolDirectory, false);
return;
}
else if (verb == "generate-surge-rule-set" || verb == "gsr")
{
+ if (args.Length != 1)
+ {
+ throw new Exception("Invalid command line arguments. download-geodata requires no arguments.");
+ }
SurgeConfigGenerator.GenerateTo(
CrupestSecretToolDirectory,
Path.Join(CrupestSecretToolDirectory, SurgeRuleSetChinaOutputFileName),
@@ -86,7 +90,12 @@ public static class Program
}
else if (verb == "generate-sing-config" || verb == "gs")
{
- var config = ToolConfig.FromDirectoryForSing(CrupestSecretToolDirectory, true, true);
+ if (args.Length != 2 || args[1].ToLower() is not ("pc" or "mobile"))
+ {
+ throw new Exception("Invalid command line arguments. generate-sing-config requires 1 argument. The argument must be either 'pc' or 'mobile'.");
+ }
+
+ var config = SingToolConfig.FromDirectory(CrupestSecretToolDirectory, args[1].ToLower() == "mobile", true, true);
Console.Out.WriteLine(config.ToSingConfigString());
return;
}
diff --git a/tools/Crupest.SecretTool/Crupest.SecretTool/Proxy.cs b/tools/Crupest.SecretTool/Crupest.SecretTool/Proxy.cs
index ddbbde8..d2703ba 100644
--- a/tools/Crupest.SecretTool/Crupest.SecretTool/Proxy.cs
+++ b/tools/Crupest.SecretTool/Crupest.SecretTool/Proxy.cs
@@ -48,7 +48,7 @@ public class VmessProxy(string host, int port, string userId, string path, strin
public override SingConfigJsonObjects.OutboundBase ToJsonObjectSing()
{
return new SingConfigJsonObjects.VmessOutbound(Tag, Host, Port, UserId,
- Transport: new SingConfigJsonObjects.V2rayWebsocketTransport(Path),
+ Transport: new SingConfigJsonObjects.V2rayWebsocketTransport(Path, new Dictionary<string, string> { { "Host", Host } }),
Tls: new SingConfigJsonObjects.OutboundTls(true));
}
diff --git a/tools/Crupest.SecretTool/Crupest.SecretTool/Routing.cs b/tools/Crupest.SecretTool/Crupest.SecretTool/Routing.cs
index 9c247a2..fdf1b93 100644
--- a/tools/Crupest.SecretTool/Crupest.SecretTool/Routing.cs
+++ b/tools/Crupest.SecretTool/Crupest.SecretTool/Routing.cs
@@ -108,7 +108,7 @@ public record Routing(List<RoutingRule> Rules) : IV4ConfigObject, ISingConfigObj
public SingConfigJsonObjects.Route ToJsonObjectSing()
{
- List<SingConfigJsonObjects.RouteRule> ruleJsonObjects = [];
+ List<SingConfigJsonObjects.RouteRule> ruleJsonObjects = [ new SingConfigJsonObjects.RouteRule(Outbound: "dns-out", Protocol: "dns")];
ruleJsonObjects.AddRange(RoutingRule.GroupByOutboundTag(Rules).Values.Select(RoutingRule.ListToJsonObjectSing));
return new SingConfigJsonObjects.Route(ruleJsonObjects);
}
diff --git a/tools/Crupest.SecretTool/Crupest.SecretTool/SingConfigJsonObjects.cs b/tools/Crupest.SecretTool/Crupest.SecretTool/SingConfigJsonObjects.cs
index 6af0cd1..56b5563 100644
--- a/tools/Crupest.SecretTool/Crupest.SecretTool/SingConfigJsonObjects.cs
+++ b/tools/Crupest.SecretTool/Crupest.SecretTool/SingConfigJsonObjects.cs
@@ -12,7 +12,7 @@ public static class SingConfigJsonObjects
V2rayTransportBase? Transport = null, OutboundTls? Tls = null): OutboundBase(Tag, "vmess");
public record RouteRule(List<string>? Domain = null, List<string>? DomainSuffix = null, List<string>? DomainKeyword = null,
- List<string>? DomainRegex = null, List<string>? IpCidr = null, List<string>? SourceIpCidr = null,
+ List<string>? DomainRegex = null, List<string>? IpCidr = null, List<string>? SourceIpCidr = null, string? Protocol = null,
List<int>? Port = null, List<int>? SourcePort = null, List<string>? PortRange = null, List<string>? SourcePortRange = null,
string? Network = null, List<string>? Inbound = null, string? Outbound = null) : IObject;
diff --git a/tools/Crupest.SecretTool/Crupest.SecretTool/ToolConfig.cs b/tools/Crupest.SecretTool/Crupest.SecretTool/ToolConfig.cs
index 534bd65..809fba1 100644
--- a/tools/Crupest.SecretTool/Crupest.SecretTool/ToolConfig.cs
+++ b/tools/Crupest.SecretTool/Crupest.SecretTool/ToolConfig.cs
@@ -13,9 +13,9 @@ public interface ISingConfigObject
object ToJsonObjectSing();
}
-public class ToolConfig(Template template, List<Proxy> proxies, Routing router, StaticHosts? hosts)
+public class ToolConfigBase(Template template, List<Proxy> proxies, Routing router)
{
- private class JsonInterfaceConverter<Interface> : JsonConverter<Interface>
+ protected class JsonInterfaceConverter<Interface> : JsonConverter<Interface>
{
public override Interface Read(
ref Utf8JsonReader reader,
@@ -34,20 +34,24 @@ public class ToolConfig(Template template, List<Proxy> proxies, Routing router,
}
}
-
- public const string ConfigTemplateFileName = "config.json.template";
public const string VmessConfigFileName = "vmess.txt";
public const string ProxyConfigFileName = "proxy.txt";
- public const string HostsConfigFileName = "hosts.txt";
- public const string SingConfigTemplateFileName = "sing-config.json.template";
+ public Template Template { get; set; } = template;
+ public List<Proxy> Proxies { get; set; } = proxies;
+ public Routing Routing { get; set; } = router;
+}
+
+public class ToolConfig(Template template, List<Proxy> proxies, Routing router, StaticHosts? hosts) : ToolConfigBase(template, proxies, router)
+{
+ public const string ConfigTemplateFileName = "config.json.template";
+ public const string HostsConfigFileName = "hosts.txt";
public static List<string> RequiredConfigFileNames { get; } = [ConfigTemplateFileName, VmessConfigFileName, ProxyConfigFileName];
public static List<string> ConfigFileNames { get; } = [ConfigTemplateFileName, VmessConfigFileName, ProxyConfigFileName, HostsConfigFileName];
private const string ProxyAnchor = "PROXY_ANCHOR";
private const string RoutingAnchor = "ROUTING_ANCHOR";
- private const string SingRouteAnchor = "ROUTE_ANCHOR";
private const string HostsAnchor = "HOSTS_ANCHOR";
public const string AddCnAttributeToGeositeEnvironmentVariable = "CRUPEST_V2RAY_GEOSITE_USE_CN";
@@ -58,45 +62,8 @@ public class ToolConfig(Template template, List<Proxy> proxies, Routing router,
_ => true
};
- public Template Template { get; set; } = template;
- public List<Proxy> Proxies { get; set; } = proxies;
- public Routing Routing { get; set; } = router;
public StaticHosts Hosts { get; set; } = hosts is null ? new StaticHosts([]) : hosts;
- public string ToSingConfigString(bool pretty = true)
- {
- var jsonOptions = new JsonSerializerOptions(new JsonSerializerOptions
- {
- PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
- DictionaryKeyPolicy = JsonNamingPolicy.SnakeCaseLower,
- DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
- });
- // TODO: Make interface converter generic.
- jsonOptions.Converters.Add(new JsonInterfaceConverter<SingConfigJsonObjects.OutboundBase>());
- jsonOptions.Converters.Add(new JsonInterfaceConverter<SingConfigJsonObjects.V2rayTransportBase>());
-
- var templateValues = new Dictionary<string, string>
- {
- [ProxyAnchor] = string.Join(',', Proxies.Select(p => JsonSerializer.Serialize(p.ToJsonObjectSing(), jsonOptions))),
- [SingRouteAnchor] = JsonSerializer.Serialize(Routing.ToJsonObjectSing(), jsonOptions),
- };
-
- var configString = Template.Generate(templateValues);
-
- if (pretty)
- {
- var jsonOptionsPretty = new JsonSerializerOptions(jsonOptions)
- {
- WriteIndented = true,
- };
- return JsonSerializer.Serialize(JsonSerializer.Deserialize<object>(configString, jsonOptionsPretty), jsonOptionsPretty);
- }
- else
- {
- return configString;
- }
- }
-
public string ToJsonStringV4(string domainStrategy = "IpOnDemand", bool directGeositeCn = true, bool pretty = true)
{
var jsonOptions = new JsonSerializerOptions(new JsonSerializerOptions
@@ -178,9 +145,76 @@ public class ToolConfig(Template template, List<Proxy> proxies, Routing router,
}
}
- public static ToolConfig FromFilesForSing(string templatePath, string vmessPath, string proxyPath, bool clean, bool silent)
+ public static ToolConfig FromDirectory(string directory)
{
- foreach (var path in new List<string>([templatePath, vmessPath, proxyPath]))
+ return FromFiles(
+ Path.Join(directory, ConfigTemplateFileName),
+ Path.Join(directory, VmessConfigFileName),
+ Path.Join(directory, ProxyConfigFileName),
+ Path.Join(directory, HostsConfigFileName)
+ );
+ }
+
+ public static void FromDirectoryAndWriteToFile(string directory, string outputPath)
+ {
+ var config = FromDirectory(directory);
+ File.WriteAllText(outputPath, config.ToJsonStringV4());
+ }
+}
+
+public class SingToolConfig(Template template, List<Proxy> proxies, Routing router, string inboundsString) : ToolConfigBase(template, proxies, router)
+{
+
+ public const string ConfigTemplateFileName = "sing-config.json.template";
+ public const string ConfigInboundsPcFileName = "sing-inbounds-pc.json";
+ public const string ConfigInboundsMobileFileName = "sing-inbounds-mobile.json";
+
+ public static List<string> RequiredConfigFileNames { get; } = [ConfigTemplateFileName, VmessConfigFileName, ProxyConfigFileName, ConfigInboundsMobileFileName, ConfigInboundsPcFileName];
+
+ private const string ProxyAnchor = "PROXY_ANCHOR";
+ private const string RouteAnchor = "ROUTE_ANCHOR";
+ private const string InboundsAnchor = "INBOUNDS_ANCHOR";
+
+ public string InboundsString { get; } = inboundsString;
+
+ public string ToSingConfigString(bool pretty = true)
+ {
+ var jsonOptions = new JsonSerializerOptions(new JsonSerializerOptions
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
+ DictionaryKeyPolicy = JsonNamingPolicy.SnakeCaseLower,
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
+ });
+ // TODO: Make interface converter generic.
+ jsonOptions.Converters.Add(new JsonInterfaceConverter<SingConfigJsonObjects.OutboundBase>());
+ jsonOptions.Converters.Add(new JsonInterfaceConverter<SingConfigJsonObjects.V2rayTransportBase>());
+
+ var templateValues = new Dictionary<string, string>
+ {
+ [ProxyAnchor] = string.Join(',', Proxies.Select(p => JsonSerializer.Serialize(p.ToJsonObjectSing(), jsonOptions))),
+ [RouteAnchor] = JsonSerializer.Serialize(Routing.ToJsonObjectSing(), jsonOptions),
+ [InboundsAnchor] = InboundsString
+ };
+
+ var configString = Template.Generate(templateValues);
+
+ if (pretty)
+ {
+ var jsonOptionsPretty = new JsonSerializerOptions(jsonOptions)
+ {
+ WriteIndented = true,
+ };
+ return JsonSerializer.Serialize(JsonSerializer.Deserialize<object>(configString, jsonOptionsPretty), jsonOptionsPretty);
+ }
+ else
+ {
+ return configString;
+ }
+ }
+
+ public static SingToolConfig FromFiles(string templatePath, string vmessPath, string proxyPath, string inboundsPath, bool clean, bool silent)
+ {
+ foreach (var path in new List<string>([templatePath, vmessPath, proxyPath, inboundsPath]))
{
if (!File.Exists(path))
{
@@ -191,7 +225,7 @@ public class ToolConfig(Template template, List<Proxy> proxies, Routing router,
var geoSiteData = GeoDataManager.Instance.GetOrCreateGeoSiteData(clean, silent);
ProxyFile proxyFile = new(proxyPath);
- string templateString, vmessString;
+ string templateString, vmessString, inboundsString;
string file = "";
try
@@ -200,6 +234,8 @@ public class ToolConfig(Template template, List<Proxy> proxies, Routing router,
templateString = File.ReadAllText(templatePath);
file = vmessPath;
vmessString = File.ReadAllText(vmessPath);
+ file = inboundsPath;
+ inboundsString = File.ReadAllText(inboundsPath);
}
catch (Exception e)
{
@@ -211,10 +247,10 @@ public class ToolConfig(Template template, List<Proxy> proxies, Routing router,
file = templatePath;
var template = new Template(templateString);
file = vmessPath;
- var vmess = VmessProxy.CreateFromConfigString(vmessString, "proxy");
+ var vmess = VmessProxy.CreateFromConfigString(vmessString, "proxy-out");
file = proxyPath;
- var routing = Routing.FromProxyFileForSing(proxyFile, geoSiteData, "proxy", "direct");
- return new ToolConfig(template, [vmess], routing, null);
+ var routing = Routing.FromProxyFileForSing(proxyFile, geoSiteData, "proxy-out", "direct-out");
+ return new SingToolConfig(template, [vmess], routing, inboundsString);
}
catch (Exception e)
{
@@ -222,29 +258,14 @@ public class ToolConfig(Template template, List<Proxy> proxies, Routing router,
}
}
- public static ToolConfig FromDirectory(string directory)
+ public static SingToolConfig FromDirectory(string directory, bool isMobile, bool clean, bool silent)
{
return FromFiles(
Path.Join(directory, ConfigTemplateFileName),
Path.Join(directory, VmessConfigFileName),
Path.Join(directory, ProxyConfigFileName),
- Path.Join(directory, HostsConfigFileName)
- );
- }
-
- public static ToolConfig FromDirectoryForSing(string directory, bool clean, bool silent)
- {
- return FromFilesForSing(
- Path.Join(directory, SingConfigTemplateFileName),
- Path.Join(directory, VmessConfigFileName),
- Path.Join(directory, ProxyConfigFileName),
+ isMobile ? Path.Join(directory, ConfigInboundsMobileFileName) : Path.Join(directory, ConfigInboundsPcFileName),
clean, silent
);
}
-
- public static void FromDirectoryAndWriteToFile(string directory, string outputPath)
- {
- var config = FromDirectory(directory);
- File.WriteAllText(outputPath, config.ToJsonStringV4());
- }
}
diff --git a/tools/Crupest.SecretTool/Crupest.SecretTool/sing-config.json.template b/tools/Crupest.SecretTool/Crupest.SecretTool/sing-config.json.template
index 429bd1d..d7e55a0 100644
--- a/tools/Crupest.SecretTool/Crupest.SecretTool/sing-config.json.template
+++ b/tools/Crupest.SecretTool/Crupest.SecretTool/sing-config.json.template
@@ -23,31 +23,21 @@
"tag": "google",
"address": "8.8.8.8"
}
-
]
},
- "inbounds": [
- {
- "tag": "http-in",
- "type": "http",
- "listen": "127.0.0.1",
- "listen_port": 3080
- },
- {
- "tag": "socks-in",
- "type": "socks",
- "listen": "127.0.0.1",
- "listen_port": 3081
- }
- ],
+ "inbounds": ${INBOUNDS_ANCHOR},
"outbounds": [
{
"type": "direct",
- "tag": "direct"
+ "tag": "direct-out"
},
{
"type": "block",
- "tag": "block"
+ "tag": "block-out"
+ },
+ {
+ "tag": "dns-out",
+ "type": "dns"
},
${PROXY_ANCHOR}
],
diff --git a/tools/Crupest.SecretTool/Crupest.SecretTool/sing-inbounds-mobile.json b/tools/Crupest.SecretTool/Crupest.SecretTool/sing-inbounds-mobile.json
new file mode 100644
index 0000000..5038c40
--- /dev/null
+++ b/tools/Crupest.SecretTool/Crupest.SecretTool/sing-inbounds-mobile.json
@@ -0,0 +1,11 @@
+[
+ {
+ "tag": "tun-in",
+ "type": "tun",
+ "auto_route": true,
+ "strict_route": true,
+ "address": [ "172.23.0.1/30", "fdfe:acbd:9876::1/126"],
+ "sniff": true,
+ "sniff_override_destination": true
+ }
+]
diff --git a/tools/Crupest.SecretTool/Crupest.SecretTool/sing-inbounds-pc.json b/tools/Crupest.SecretTool/Crupest.SecretTool/sing-inbounds-pc.json
new file mode 100644
index 0000000..956d751
--- /dev/null
+++ b/tools/Crupest.SecretTool/Crupest.SecretTool/sing-inbounds-pc.json
@@ -0,0 +1,14 @@
+[
+ {
+ "tag": "http-in",
+ "type": "http",
+ "listen": "127.0.0.1",
+ "listen_port": 3080
+ },
+ {
+ "tag": "socks-in",
+ "type": "socks",
+ "listen": "127.0.0.1",
+ "listen_port": 3081
+ }
+] \ No newline at end of file
diff --git a/tools/Crupest.SecretTool/build-secret.ps1 b/tools/Crupest.SecretTool/build-secret.ps1
new file mode 100644
index 0000000..8aa7987
--- /dev/null
+++ b/tools/Crupest.SecretTool/build-secret.ps1
@@ -0,0 +1,25 @@
+if ($args.Count -ne 1 || $args[0] -notmatch "^win-x64|linux-x64|osx-x64$")
+{
+ Write-Error "You must specify exactly one argument, the build target (win-x64 | linux-x64 | osx-x64)."
+ exit 1
+}
+
+Write-Output "Secret dir: $PSScriptRoot"
+
+Write-Output "Check dotnet..."
+dotnet --version
+if ($LASTEXITCODE -ne 0)
+{
+ Write-Error "dotnet not found."
+ exit 2
+}
+
+Write-Output "Enter `"secret`" dir..."
+Push-Location $PSScriptRoot
+
+Write-Output "Begin to build..."
+dotnet publish Crupest.SecretTool -c Release -o "$secret_dir/publish" --sc -r $args[0]
+
+Pop-Location
+
+Write-Host "Finish!" -ForegroundColor Green