diff options
| author | crupest <crupest@outlook.com> | 2024-10-23 23:32:32 +0800 | 
|---|---|---|
| committer | crupest <crupest@outlook.com> | 2024-10-27 04:57:05 +0800 | 
| commit | ccafee054f3a934a8031c3cb5fc8280491bb8e1a (patch) | |
| tree | 55a02147ae47788f08ec7ad49dd35f1faf5694d4 | |
| parent | 572b0185c8bb8558069c929faed22f53a3a911a8 (diff) | |
| download | crupest-ccafee054f3a934a8031c3cb5fc8280491bb8e1a.tar.gz crupest-ccafee054f3a934a8031c3cb5fc8280491bb8e1a.tar.bz2 crupest-ccafee054f3a934a8031c3cb5fc8280491bb8e1a.zip  | |
fix(secret): fix a bunch of bugs in sing.
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  | 
