mirror of https://github.com/2dust/v2rayN
Add sing-box core config file support
parent
7b9c64c5a5
commit
a262c1e98d
|
@ -28,7 +28,7 @@
|
||||||
public const string ConfigDB = "guiNDB.db";
|
public const string ConfigDB = "guiNDB.db";
|
||||||
public const string coreConfigFileName = "config.json";
|
public const string coreConfigFileName = "config.json";
|
||||||
public const string v2raySampleClient = "v2rayN.Sample.SampleClientConfig";
|
public const string v2raySampleClient = "v2rayN.Sample.SampleClientConfig";
|
||||||
public const string v2raySampleServer = "v2rayN.Sample.SampleServerConfig";
|
public const string SingboxSampleClient = "v2rayN.Sample.SingboxSampleClientConfig";
|
||||||
public const string v2raySampleHttprequestFileName = "v2rayN.Sample.SampleHttprequest";
|
public const string v2raySampleHttprequestFileName = "v2rayN.Sample.SampleHttprequest";
|
||||||
public const string v2raySampleHttpresponseFileName = "v2rayN.Sample.SampleHttpresponse";
|
public const string v2raySampleHttpresponseFileName = "v2rayN.Sample.SampleHttpresponse";
|
||||||
public const string CustomRoutingFileName = "v2rayN.Sample.custom_routing_";
|
public const string CustomRoutingFileName = "v2rayN.Sample.custom_routing_";
|
||||||
|
@ -131,8 +131,8 @@
|
||||||
public static readonly List<string> flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
|
public static readonly List<string> flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
|
||||||
public static readonly List<string> networks = new() { "tcp", "kcp", "ws", "h2", "quic", "grpc" };
|
public static readonly List<string> networks = new() { "tcp", "kcp", "ws", "h2", "quic", "grpc" };
|
||||||
public static readonly List<string> kcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
|
public static readonly List<string> kcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
|
||||||
public static readonly List<string> coreTypes = new() { "v2fly", "SagerNet", "Xray", "v2fly_v5" };
|
public static readonly List<string> coreTypes = new() { "v2fly", "SagerNet", "Xray", "v2fly_v5", "sing_box" };
|
||||||
public static readonly List<string> coreTypes4VLESS = new() { "Xray" };
|
public static readonly List<string> coreTypes4VLESS = new() { "Xray", "sing_box" };
|
||||||
public static readonly List<string> domainStrategys = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
|
public static readonly List<string> domainStrategys = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
|
||||||
public static readonly List<string> domainMatchers = new() { "linear", "mph", "" };
|
public static readonly List<string> domainMatchers = new() { "linear", "mph", "" };
|
||||||
public static readonly List<string> fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
|
public static readonly List<string> fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,513 @@
|
||||||
|
using v2rayN.Base;
|
||||||
|
using v2rayN.Mode;
|
||||||
|
using v2rayN.Resx;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler
|
||||||
|
{
|
||||||
|
internal class CoreConfigSingbox
|
||||||
|
{
|
||||||
|
private string SampleClient = Global.SingboxSampleClient;
|
||||||
|
private Config _config;
|
||||||
|
|
||||||
|
public CoreConfigSingbox(Config config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GenerateClientConfigContent(ProfileItem node, out SingboxConfig? singboxConfig, out string msg)
|
||||||
|
{
|
||||||
|
singboxConfig = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (node == null
|
||||||
|
|| node.port <= 0)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = ResUI.InitialConfiguration;
|
||||||
|
|
||||||
|
string result = Utils.GetEmbedText(SampleClient);
|
||||||
|
if (Utils.IsNullOrEmpty(result))
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGetDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
singboxConfig = Utils.FromJson<SingboxConfig>(result);
|
||||||
|
if (singboxConfig == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(singboxConfig);
|
||||||
|
|
||||||
|
inbound(singboxConfig);
|
||||||
|
|
||||||
|
outbound(node, singboxConfig);
|
||||||
|
|
||||||
|
routing(singboxConfig);
|
||||||
|
|
||||||
|
//dns(singboxConfig);
|
||||||
|
|
||||||
|
//statistic(singboxConfig);
|
||||||
|
|
||||||
|
msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog("GenerateClientConfig4Singbox", ex);
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int log(SingboxConfig singboxConfig)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch (_config.coreBasicItem.loglevel)
|
||||||
|
{
|
||||||
|
case "debug":
|
||||||
|
case "info":
|
||||||
|
case "error":
|
||||||
|
singboxConfig.log.level = _config.coreBasicItem.loglevel;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (_config.coreBasicItem.loglevel == "none")
|
||||||
|
{
|
||||||
|
singboxConfig.log.disabled = true;
|
||||||
|
}
|
||||||
|
if (_config.coreBasicItem.logEnabled)
|
||||||
|
{
|
||||||
|
var dtNow = DateTime.Now;
|
||||||
|
singboxConfig.log.output = Utils.GetLogPath($"sbox_{dtNow:yyyy-MM-dd}.txt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int inbound(SingboxConfig singboxConfig)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var inbound = singboxConfig.inbounds[0];
|
||||||
|
inbound.listen_port = LazyConfig.Instance.GetLocalPort(Global.InboundSocks);
|
||||||
|
inbound.sniff = _config.inbound[0].sniffingEnabled;
|
||||||
|
inbound.sniff_override_destination = _config.inbound[0].sniffingEnabled;
|
||||||
|
|
||||||
|
//http
|
||||||
|
var inbound2 = Utils.DeepCopy(inbound);
|
||||||
|
inbound2.listen_port = LazyConfig.Instance.GetLocalPort(Global.InboundHttp);
|
||||||
|
inbound2.type = Global.InboundHttp;
|
||||||
|
inbound2.tag = Global.InboundHttp;
|
||||||
|
singboxConfig.inbounds.Add(inbound2);
|
||||||
|
|
||||||
|
if (_config.inbound[0].allowLANConn)
|
||||||
|
{
|
||||||
|
if (_config.inbound[0].newPort4LAN)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inbound.listen = "::";
|
||||||
|
inbound2.listen = "::";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region outbound private
|
||||||
|
|
||||||
|
private int outbound(ProfileItem node, SingboxConfig singboxConfig)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var outbound = singboxConfig.outbounds[0];
|
||||||
|
outbound.server = node.address;
|
||||||
|
outbound.server_port = node.port;
|
||||||
|
|
||||||
|
if (node.configType == EConfigType.VMess)
|
||||||
|
{
|
||||||
|
outbound.type = Global.vmessProtocolLite;
|
||||||
|
|
||||||
|
outbound.uuid = node.id;
|
||||||
|
outbound.alter_id = node.alterId;
|
||||||
|
if (Global.vmessSecuritys.Contains(node.security))
|
||||||
|
{
|
||||||
|
outbound.security = node.security;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outbound.security = Global.DefaultSecurity;
|
||||||
|
}
|
||||||
|
|
||||||
|
outboundMux(node, outbound);
|
||||||
|
}
|
||||||
|
else if (node.configType == EConfigType.Shadowsocks)
|
||||||
|
{
|
||||||
|
outbound.type = Global.ssProtocolLite;
|
||||||
|
|
||||||
|
outbound.method = LazyConfig.Instance.GetShadowsocksSecuritys(node).Contains(node.security) ? node.security : "none";
|
||||||
|
outbound.password = node.id;
|
||||||
|
|
||||||
|
outboundMux(node, outbound);
|
||||||
|
}
|
||||||
|
else if (node.configType == EConfigType.Socks)
|
||||||
|
{
|
||||||
|
outbound.type = Global.socksProtocolLite;
|
||||||
|
|
||||||
|
outbound.version = "5";
|
||||||
|
if (!Utils.IsNullOrEmpty(node.security)
|
||||||
|
&& !Utils.IsNullOrEmpty(node.id))
|
||||||
|
{
|
||||||
|
outbound.username = node.security;
|
||||||
|
outbound.password = node.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node.configType == EConfigType.VLESS)
|
||||||
|
{
|
||||||
|
outbound.type = Global.vlessProtocolLite;
|
||||||
|
|
||||||
|
outbound.uuid = node.id;
|
||||||
|
outbound.flow = node.flow;
|
||||||
|
|
||||||
|
outbound.packet_encoding = "xudp";
|
||||||
|
}
|
||||||
|
else if (node.configType == EConfigType.Trojan)
|
||||||
|
{
|
||||||
|
outbound.type = Global.trojanProtocolLite;
|
||||||
|
|
||||||
|
outbound.password = node.id;
|
||||||
|
|
||||||
|
outboundMux(node, outbound);
|
||||||
|
}
|
||||||
|
|
||||||
|
outboundTls(node, outbound);
|
||||||
|
|
||||||
|
outboundTransport(node, outbound);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int outboundMux(ProfileItem node, Outbound4Sbox outbound)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_config.coreBasicItem.muxEnabled)
|
||||||
|
{
|
||||||
|
var mux = new Multiplex4Sbox()
|
||||||
|
{
|
||||||
|
enabled = true,
|
||||||
|
protocol = "smux",
|
||||||
|
max_connections = 4,
|
||||||
|
min_streams = 4,
|
||||||
|
max_streams = 0,
|
||||||
|
};
|
||||||
|
outbound.multiplex = mux;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int outboundTls(ProfileItem node, Outbound4Sbox outbound)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (node.streamSecurity == Global.StreamSecurityReality || node.streamSecurity == Global.StreamSecurity)
|
||||||
|
{
|
||||||
|
var tls = new Tls4Sbox()
|
||||||
|
{
|
||||||
|
enabled = true,
|
||||||
|
server_name = node.sni,
|
||||||
|
insecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? _config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
|
||||||
|
alpn = node.GetAlpn(),
|
||||||
|
};
|
||||||
|
if (!Utils.IsNullOrEmpty(node.fingerprint))
|
||||||
|
{
|
||||||
|
tls.utls = new Utls4Sbox()
|
||||||
|
{
|
||||||
|
enabled = true,
|
||||||
|
fingerprint = node.fingerprint.IsNullOrEmpty() ? _config.coreBasicItem.defFingerprint : node.fingerprint
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (node.streamSecurity == Global.StreamSecurityReality)
|
||||||
|
{
|
||||||
|
tls.reality = new Reality4Sbox()
|
||||||
|
{
|
||||||
|
enabled = true,
|
||||||
|
public_key = node.publicKey,
|
||||||
|
short_id = node.shortId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
outbound.tls = tls;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int outboundTransport(ProfileItem node, Outbound4Sbox outbound)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var transport = new Transport4Sbox();
|
||||||
|
|
||||||
|
switch (node.GetNetwork())
|
||||||
|
{
|
||||||
|
case "h2":
|
||||||
|
transport.type = "http";
|
||||||
|
transport.host = Utils.IsNullOrEmpty(node.requestHost) ? null : Utils.String2List(node.requestHost);
|
||||||
|
transport.path = Utils.IsNullOrEmpty(node.path) ? null : node.path;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "ws":
|
||||||
|
transport.type = "ws";
|
||||||
|
transport.path = Utils.IsNullOrEmpty(node.path) ? null : node.path;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "quic":
|
||||||
|
transport.type = "quic";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "grpc":
|
||||||
|
transport.type = "grpc";
|
||||||
|
transport.service_name = node.path;
|
||||||
|
transport.idle_timeout = _config.grpcItem.idle_timeout.ToString("##s");
|
||||||
|
transport.ping_timeout = _config.grpcItem.health_check_timeout.ToString("##s");
|
||||||
|
transport.permit_without_stream = _config.grpcItem.permit_without_stream;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
transport = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
outbound.transport = transport;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion outbound private
|
||||||
|
|
||||||
|
#region routing rule private
|
||||||
|
|
||||||
|
private int routing(SingboxConfig singboxConfig)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var routing = ConfigHandler.GetDefaultRouting(ref _config);
|
||||||
|
if (routing != null)
|
||||||
|
{
|
||||||
|
var rules = Utils.FromJson<List<RulesItem>>(routing.ruleSet);
|
||||||
|
foreach (var item in rules!)
|
||||||
|
{
|
||||||
|
if (item.enabled)
|
||||||
|
{
|
||||||
|
routingUserRule(item, singboxConfig.route.rules);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int routingUserRule(RulesItem item, List<Rule4Sbox> rules)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rule = new Rule4Sbox()
|
||||||
|
{
|
||||||
|
outbound = item.outboundTag,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!Utils.IsNullOrEmpty(item.port))
|
||||||
|
{
|
||||||
|
if (item.port.Contains("-"))
|
||||||
|
{
|
||||||
|
rule.port_range = new List<string> { item.port.Replace("-", ":") };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rule.port = new List<int> { Utils.ToInt(item.port) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item.protocol?.Count > 0)
|
||||||
|
{
|
||||||
|
rule.protocol = item.protocol;
|
||||||
|
}
|
||||||
|
if (item.inboundTag?.Count >= 0)
|
||||||
|
{
|
||||||
|
rule.inbound = item.inboundTag;
|
||||||
|
}
|
||||||
|
var rule2 = Utils.DeepCopy(rule);
|
||||||
|
|
||||||
|
var hasDomainIp = false;
|
||||||
|
if (item.domain?.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var it in item.domain)
|
||||||
|
{
|
||||||
|
parseV2Domain(it, rule);
|
||||||
|
}
|
||||||
|
rules.Add(rule);
|
||||||
|
hasDomainIp = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.ip?.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var it in item.ip)
|
||||||
|
{
|
||||||
|
parseV2Address(it, rule2);
|
||||||
|
}
|
||||||
|
rules.Add(rule2);
|
||||||
|
hasDomainIp = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasDomainIp)
|
||||||
|
{
|
||||||
|
rules.Add(rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseV2Domain(string domain, Rule4Sbox rule)
|
||||||
|
{
|
||||||
|
if (domain.StartsWith("ext:") || domain.StartsWith("ext-domain:"))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (domain.StartsWith("geosite:"))
|
||||||
|
{
|
||||||
|
if (rule.geosite is null) { rule.geosite = new(); }
|
||||||
|
rule.geosite?.Add(domain.Substring(8));
|
||||||
|
}
|
||||||
|
else if (domain.StartsWith("regexp:"))
|
||||||
|
{
|
||||||
|
if (rule.domain_regex is null) { rule.domain_regex = new(); }
|
||||||
|
rule.domain_regex?.Add(domain.Replace(Global.RoutingRuleComma, ",").Substring(7));
|
||||||
|
}
|
||||||
|
else if (domain.StartsWith("domain:"))
|
||||||
|
{
|
||||||
|
if (rule.domain is null) { rule.domain = new(); }
|
||||||
|
if (rule.domain_suffix is null) { rule.domain_suffix = new(); }
|
||||||
|
rule.domain?.Add(domain.Substring(7));
|
||||||
|
rule.domain_suffix?.Add("." + domain.Substring(7));
|
||||||
|
}
|
||||||
|
else if (domain.StartsWith("full:"))
|
||||||
|
{
|
||||||
|
if (rule.domain is null) { rule.domain = new(); }
|
||||||
|
rule.domain?.Add(domain.Substring(5));
|
||||||
|
}
|
||||||
|
else if (domain.StartsWith("keyword:"))
|
||||||
|
{
|
||||||
|
if (rule.domain_keyword is null) { rule.domain_keyword = new(); }
|
||||||
|
rule.domain_keyword?.Add(domain.Substring(8));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rule.domain_keyword is null) { rule.domain_keyword = new(); }
|
||||||
|
rule.domain_keyword?.Add(domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseV2Address(string address, Rule4Sbox rule)
|
||||||
|
{
|
||||||
|
if (address.StartsWith("ext:") || address.StartsWith("ext-ip:"))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (address.StartsWith("geoip:!"))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (address.StartsWith("geoip:"))
|
||||||
|
{
|
||||||
|
if (rule.geoip is null) { rule.geoip = new(); }
|
||||||
|
rule.geoip?.Add(address.Substring(6));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rule.ip_cidr is null) { rule.ip_cidr = new(); }
|
||||||
|
rule.ip_cidr?.Add(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion routing rule private
|
||||||
|
|
||||||
|
private int dns(SingboxConfig singboxConfig)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//singboxConfig.dns = new();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int statistic(SingboxConfig singboxConfig)
|
||||||
|
{
|
||||||
|
if (_config.guiItem.enableStatistics)
|
||||||
|
{
|
||||||
|
singboxConfig.experimental = new Experimental4Sbox()
|
||||||
|
{
|
||||||
|
v2ray_api = new V2ray_Api4Sbox()
|
||||||
|
{
|
||||||
|
listen = $"{Global.Loopback}:{Global.statePort}",
|
||||||
|
stats = new Stats4Sbox()
|
||||||
|
{
|
||||||
|
enabled = true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,927 @@
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using v2rayN.Base;
|
||||||
|
using v2rayN.Mode;
|
||||||
|
using v2rayN.Resx;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler
|
||||||
|
{
|
||||||
|
internal class CoreConfigV2ray
|
||||||
|
{
|
||||||
|
private string SampleClient = Global.v2raySampleClient;
|
||||||
|
private Config _config;
|
||||||
|
|
||||||
|
public CoreConfigV2ray(Config config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GenerateClientConfigContent(ProfileItem node, out V2rayConfig? v2rayConfig, out string msg)
|
||||||
|
{
|
||||||
|
v2rayConfig = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (node == null
|
||||||
|
|| node.port <= 0)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = ResUI.InitialConfiguration;
|
||||||
|
|
||||||
|
string result = Utils.GetEmbedText(SampleClient);
|
||||||
|
if (Utils.IsNullOrEmpty(result))
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGetDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
v2rayConfig = Utils.FromJson<V2rayConfig>(result);
|
||||||
|
if (v2rayConfig == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(v2rayConfig);
|
||||||
|
|
||||||
|
inbound(v2rayConfig);
|
||||||
|
|
||||||
|
routing(v2rayConfig);
|
||||||
|
|
||||||
|
outbound(node, v2rayConfig);
|
||||||
|
|
||||||
|
dns(v2rayConfig);
|
||||||
|
|
||||||
|
statistic(v2rayConfig);
|
||||||
|
|
||||||
|
msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog("GenerateClientConfig4V2ray", ex);
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int log(V2rayConfig v2rayConfig)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_config.coreBasicItem.logEnabled)
|
||||||
|
{
|
||||||
|
var dtNow = DateTime.Now;
|
||||||
|
v2rayConfig.log.loglevel = _config.coreBasicItem.loglevel;
|
||||||
|
v2rayConfig.log.access = Utils.GetLogPath($"Vaccess_{dtNow:yyyy-MM-dd}.txt");
|
||||||
|
v2rayConfig.log.error = Utils.GetLogPath($"Verror_{dtNow:yyyy-MM-dd}.txt");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v2rayConfig.log.loglevel = _config.coreBasicItem.loglevel;
|
||||||
|
v2rayConfig.log.access = "";
|
||||||
|
v2rayConfig.log.error = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int inbound(V2rayConfig v2rayConfig)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
v2rayConfig.inbounds = new List<Inbounds>();
|
||||||
|
|
||||||
|
Inbounds? inbound = GetInbound(_config.inbound[0], Global.InboundSocks, 0, true);
|
||||||
|
v2rayConfig.inbounds.Add(inbound);
|
||||||
|
|
||||||
|
//http
|
||||||
|
Inbounds? inbound2 = GetInbound(_config.inbound[0], Global.InboundHttp, 1, false);
|
||||||
|
v2rayConfig.inbounds.Add(inbound2);
|
||||||
|
|
||||||
|
if (_config.inbound[0].allowLANConn)
|
||||||
|
{
|
||||||
|
if (_config.inbound[0].newPort4LAN)
|
||||||
|
{
|
||||||
|
Inbounds inbound3 = GetInbound(_config.inbound[0], Global.InboundSocks2, 2, true);
|
||||||
|
inbound3.listen = "0.0.0.0";
|
||||||
|
v2rayConfig.inbounds.Add(inbound3);
|
||||||
|
|
||||||
|
Inbounds inbound4 = GetInbound(_config.inbound[0], Global.InboundHttp2, 3, false);
|
||||||
|
inbound4.listen = "0.0.0.0";
|
||||||
|
v2rayConfig.inbounds.Add(inbound4);
|
||||||
|
|
||||||
|
//auth
|
||||||
|
if (!Utils.IsNullOrEmpty(_config.inbound[0].user) && !Utils.IsNullOrEmpty(_config.inbound[0].pass))
|
||||||
|
{
|
||||||
|
inbound3.settings.auth = "password";
|
||||||
|
inbound3.settings.accounts = new List<AccountsItem> { new AccountsItem() { user = _config.inbound[0].user, pass = _config.inbound[0].pass } };
|
||||||
|
|
||||||
|
inbound4.settings.auth = "password";
|
||||||
|
inbound4.settings.accounts = new List<AccountsItem> { new AccountsItem() { user = _config.inbound[0].user, pass = _config.inbound[0].pass } };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inbound.listen = "0.0.0.0";
|
||||||
|
inbound2.listen = "0.0.0.0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Inbounds? GetInbound(InItem inItem, string tag, int offset, bool bSocks)
|
||||||
|
{
|
||||||
|
string result = Utils.GetEmbedText(Global.v2raySampleInbound);
|
||||||
|
if (Utils.IsNullOrEmpty(result))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var inbound = Utils.FromJson<Inbounds>(result);
|
||||||
|
if (inbound == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
inbound.tag = tag;
|
||||||
|
inbound.port = inItem.localPort + offset;
|
||||||
|
inbound.protocol = bSocks ? Global.InboundSocks : Global.InboundHttp;
|
||||||
|
inbound.settings.udp = inItem.udpEnabled;
|
||||||
|
inbound.sniffing.enabled = inItem.sniffingEnabled;
|
||||||
|
inbound.sniffing.routeOnly = inItem.routeOnly;
|
||||||
|
|
||||||
|
return inbound;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int routing(V2rayConfig v2rayConfig)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (v2rayConfig.routing?.rules != null)
|
||||||
|
{
|
||||||
|
v2rayConfig.routing.domainStrategy = _config.routingBasicItem.domainStrategy;
|
||||||
|
v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(_config.routingBasicItem.domainMatcher) ? null : _config.routingBasicItem.domainMatcher;
|
||||||
|
|
||||||
|
if (_config.routingBasicItem.enableRoutingAdvanced)
|
||||||
|
{
|
||||||
|
var routing = ConfigHandler.GetDefaultRouting(ref _config);
|
||||||
|
if (routing != null)
|
||||||
|
{
|
||||||
|
if (!Utils.IsNullOrEmpty(routing.domainStrategy))
|
||||||
|
{
|
||||||
|
v2rayConfig.routing.domainStrategy = routing.domainStrategy;
|
||||||
|
}
|
||||||
|
var rules = Utils.FromJson<List<RulesItem>>(routing.ruleSet);
|
||||||
|
foreach (var item in rules)
|
||||||
|
{
|
||||||
|
if (item.enabled)
|
||||||
|
{
|
||||||
|
routingUserRule(item, v2rayConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var lockedItem = ConfigHandler.GetLockedRoutingItem(ref _config);
|
||||||
|
if (lockedItem != null)
|
||||||
|
{
|
||||||
|
var rules = Utils.FromJson<List<RulesItem>>(lockedItem.ruleSet);
|
||||||
|
foreach (var item in rules)
|
||||||
|
{
|
||||||
|
routingUserRule(item, v2rayConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int routingUserRule(RulesItem rules, V2rayConfig v2rayConfig)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (rules == null)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (Utils.IsNullOrEmpty(rules.port))
|
||||||
|
{
|
||||||
|
rules.port = null;
|
||||||
|
}
|
||||||
|
if (rules.domain?.Count == 0)
|
||||||
|
{
|
||||||
|
rules.domain = null;
|
||||||
|
}
|
||||||
|
if (rules.ip?.Count == 0)
|
||||||
|
{
|
||||||
|
rules.ip = null;
|
||||||
|
}
|
||||||
|
if (rules.protocol?.Count == 0)
|
||||||
|
{
|
||||||
|
rules.protocol = null;
|
||||||
|
}
|
||||||
|
if (rules.inboundTag?.Count == 0)
|
||||||
|
{
|
||||||
|
rules.inboundTag = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasDomainIp = false;
|
||||||
|
if (rules.domain?.Count > 0)
|
||||||
|
{
|
||||||
|
var it = Utils.DeepCopy(rules);
|
||||||
|
it.ip = null;
|
||||||
|
it.type = "field";
|
||||||
|
for (int k = it.domain.Count - 1; k >= 0; k--)
|
||||||
|
{
|
||||||
|
if (it.domain[k].StartsWith("#"))
|
||||||
|
{
|
||||||
|
it.domain.RemoveAt(k);
|
||||||
|
}
|
||||||
|
it.domain[k] = it.domain[k].Replace(Global.RoutingRuleComma, ",");
|
||||||
|
}
|
||||||
|
v2rayConfig.routing.rules.Add(it);
|
||||||
|
hasDomainIp = true;
|
||||||
|
}
|
||||||
|
if (rules.ip?.Count > 0)
|
||||||
|
{
|
||||||
|
var it = Utils.DeepCopy(rules);
|
||||||
|
it.domain = null;
|
||||||
|
it.type = "field";
|
||||||
|
v2rayConfig.routing.rules.Add(it);
|
||||||
|
hasDomainIp = true;
|
||||||
|
}
|
||||||
|
if (!hasDomainIp)
|
||||||
|
{
|
||||||
|
if (!Utils.IsNullOrEmpty(rules.port)
|
||||||
|
|| (rules.protocol?.Count > 0)
|
||||||
|
|| (rules.inboundTag?.Count > 0)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var it = Utils.DeepCopy(rules);
|
||||||
|
it.type = "field";
|
||||||
|
v2rayConfig.routing.rules.Add(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int outbound(ProfileItem node, V2rayConfig v2rayConfig)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Outbounds outbound = v2rayConfig.outbounds[0];
|
||||||
|
if (node.configType == EConfigType.VMess)
|
||||||
|
{
|
||||||
|
VnextItem vnextItem;
|
||||||
|
if (outbound.settings.vnext.Count <= 0)
|
||||||
|
{
|
||||||
|
vnextItem = new VnextItem();
|
||||||
|
outbound.settings.vnext.Add(vnextItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vnextItem = outbound.settings.vnext[0];
|
||||||
|
}
|
||||||
|
vnextItem.address = node.address;
|
||||||
|
vnextItem.port = node.port;
|
||||||
|
|
||||||
|
UsersItem usersItem;
|
||||||
|
if (vnextItem.users.Count <= 0)
|
||||||
|
{
|
||||||
|
usersItem = new UsersItem();
|
||||||
|
vnextItem.users.Add(usersItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
usersItem = vnextItem.users[0];
|
||||||
|
}
|
||||||
|
//远程服务器用户ID
|
||||||
|
usersItem.id = node.id;
|
||||||
|
usersItem.alterId = node.alterId;
|
||||||
|
usersItem.email = Global.userEMail;
|
||||||
|
if (Global.vmessSecuritys.Contains(node.security))
|
||||||
|
{
|
||||||
|
usersItem.security = node.security;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
usersItem.security = Global.DefaultSecurity;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Mux
|
||||||
|
outbound.mux.enabled = _config.coreBasicItem.muxEnabled;
|
||||||
|
outbound.mux.concurrency = _config.coreBasicItem.muxEnabled ? 8 : -1;
|
||||||
|
|
||||||
|
outbound.protocol = Global.vmessProtocolLite;
|
||||||
|
outbound.settings.servers = null;
|
||||||
|
}
|
||||||
|
else if (node.configType == EConfigType.Shadowsocks)
|
||||||
|
{
|
||||||
|
ServersItem serversItem;
|
||||||
|
if (outbound.settings.servers.Count <= 0)
|
||||||
|
{
|
||||||
|
serversItem = new ServersItem();
|
||||||
|
outbound.settings.servers.Add(serversItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serversItem = outbound.settings.servers[0];
|
||||||
|
}
|
||||||
|
serversItem.address = node.address;
|
||||||
|
serversItem.port = node.port;
|
||||||
|
serversItem.password = node.id;
|
||||||
|
serversItem.method = LazyConfig.Instance.GetShadowsocksSecuritys(node).Contains(node.security) ? node.security : "none";
|
||||||
|
|
||||||
|
serversItem.ota = false;
|
||||||
|
serversItem.level = 1;
|
||||||
|
|
||||||
|
outbound.mux.enabled = false;
|
||||||
|
outbound.mux.concurrency = -1;
|
||||||
|
|
||||||
|
outbound.protocol = Global.ssProtocolLite;
|
||||||
|
outbound.settings.vnext = null;
|
||||||
|
}
|
||||||
|
else if (node.configType == EConfigType.Socks)
|
||||||
|
{
|
||||||
|
ServersItem serversItem;
|
||||||
|
if (outbound.settings.servers.Count <= 0)
|
||||||
|
{
|
||||||
|
serversItem = new ServersItem();
|
||||||
|
outbound.settings.servers.Add(serversItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serversItem = outbound.settings.servers[0];
|
||||||
|
}
|
||||||
|
serversItem.address = node.address;
|
||||||
|
serversItem.port = node.port;
|
||||||
|
serversItem.method = null;
|
||||||
|
serversItem.password = null;
|
||||||
|
|
||||||
|
if (!Utils.IsNullOrEmpty(node.security)
|
||||||
|
&& !Utils.IsNullOrEmpty(node.id))
|
||||||
|
{
|
||||||
|
SocksUsersItem socksUsersItem = new()
|
||||||
|
{
|
||||||
|
user = node.security,
|
||||||
|
pass = node.id,
|
||||||
|
level = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
serversItem.users = new List<SocksUsersItem>() { socksUsersItem };
|
||||||
|
}
|
||||||
|
|
||||||
|
outbound.mux.enabled = false;
|
||||||
|
outbound.mux.concurrency = -1;
|
||||||
|
|
||||||
|
outbound.protocol = Global.socksProtocolLite;
|
||||||
|
outbound.settings.vnext = null;
|
||||||
|
}
|
||||||
|
else if (node.configType == EConfigType.VLESS)
|
||||||
|
{
|
||||||
|
VnextItem vnextItem;
|
||||||
|
if (outbound.settings.vnext.Count <= 0)
|
||||||
|
{
|
||||||
|
vnextItem = new VnextItem();
|
||||||
|
outbound.settings.vnext.Add(vnextItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vnextItem = outbound.settings.vnext[0];
|
||||||
|
}
|
||||||
|
vnextItem.address = node.address;
|
||||||
|
vnextItem.port = node.port;
|
||||||
|
|
||||||
|
UsersItem usersItem;
|
||||||
|
if (vnextItem.users.Count <= 0)
|
||||||
|
{
|
||||||
|
usersItem = new UsersItem();
|
||||||
|
vnextItem.users.Add(usersItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
usersItem = vnextItem.users[0];
|
||||||
|
}
|
||||||
|
usersItem.id = node.id;
|
||||||
|
usersItem.flow = string.Empty;
|
||||||
|
usersItem.email = Global.userEMail;
|
||||||
|
usersItem.encryption = node.security;
|
||||||
|
|
||||||
|
//Mux
|
||||||
|
outbound.mux.enabled = _config.coreBasicItem.muxEnabled;
|
||||||
|
outbound.mux.concurrency = _config.coreBasicItem.muxEnabled ? 8 : -1;
|
||||||
|
|
||||||
|
if (node.streamSecurity == Global.StreamSecurityReality
|
||||||
|
|| node.streamSecurity == Global.StreamSecurity)
|
||||||
|
{
|
||||||
|
if (!Utils.IsNullOrEmpty(node.flow))
|
||||||
|
{
|
||||||
|
usersItem.flow = node.flow;
|
||||||
|
|
||||||
|
outbound.mux.enabled = false;
|
||||||
|
outbound.mux.concurrency = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outbound.protocol = Global.vlessProtocolLite;
|
||||||
|
outbound.settings.servers = null;
|
||||||
|
}
|
||||||
|
else if (node.configType == EConfigType.Trojan)
|
||||||
|
{
|
||||||
|
ServersItem serversItem;
|
||||||
|
if (outbound.settings.servers.Count <= 0)
|
||||||
|
{
|
||||||
|
serversItem = new ServersItem();
|
||||||
|
outbound.settings.servers.Add(serversItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serversItem = outbound.settings.servers[0];
|
||||||
|
}
|
||||||
|
serversItem.address = node.address;
|
||||||
|
serversItem.port = node.port;
|
||||||
|
serversItem.password = node.id;
|
||||||
|
serversItem.flow = string.Empty;
|
||||||
|
|
||||||
|
serversItem.ota = false;
|
||||||
|
serversItem.level = 1;
|
||||||
|
|
||||||
|
outbound.mux.enabled = false;
|
||||||
|
outbound.mux.concurrency = -1;
|
||||||
|
|
||||||
|
outbound.protocol = Global.trojanProtocolLite;
|
||||||
|
outbound.settings.vnext = null;
|
||||||
|
}
|
||||||
|
boundStreamSettings(node, outbound.streamSettings);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int boundStreamSettings(ProfileItem node, StreamSettings streamSettings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
streamSettings.network = node.GetNetwork();
|
||||||
|
string host = node.requestHost.TrimEx();
|
||||||
|
string sni = node.sni;
|
||||||
|
string useragent = "";
|
||||||
|
if (!_config.coreBasicItem.defUserAgent.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
useragent = Global.userAgentTxt[_config.coreBasicItem.defUserAgent];
|
||||||
|
}
|
||||||
|
catch (KeyNotFoundException)
|
||||||
|
{
|
||||||
|
useragent = _config.coreBasicItem.defUserAgent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if tls
|
||||||
|
if (node.streamSecurity == Global.StreamSecurity)
|
||||||
|
{
|
||||||
|
streamSettings.security = node.streamSecurity;
|
||||||
|
|
||||||
|
TlsSettings tlsSettings = new()
|
||||||
|
{
|
||||||
|
allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? _config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
|
||||||
|
alpn = node.GetAlpn(),
|
||||||
|
fingerprint = node.fingerprint.IsNullOrEmpty() ? _config.coreBasicItem.defFingerprint : node.fingerprint
|
||||||
|
};
|
||||||
|
if (!string.IsNullOrWhiteSpace(sni))
|
||||||
|
{
|
||||||
|
tlsSettings.serverName = sni;
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrWhiteSpace(host))
|
||||||
|
{
|
||||||
|
tlsSettings.serverName = Utils.String2List(host)[0];
|
||||||
|
}
|
||||||
|
streamSettings.tlsSettings = tlsSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if Reality
|
||||||
|
if (node.streamSecurity == Global.StreamSecurityReality)
|
||||||
|
{
|
||||||
|
streamSettings.security = node.streamSecurity;
|
||||||
|
|
||||||
|
TlsSettings realitySettings = new()
|
||||||
|
{
|
||||||
|
fingerprint = node.fingerprint.IsNullOrEmpty() ? _config.coreBasicItem.defFingerprint : node.fingerprint,
|
||||||
|
serverName = sni,
|
||||||
|
publicKey = node.publicKey,
|
||||||
|
shortId = node.shortId,
|
||||||
|
spiderX = node.spiderX,
|
||||||
|
};
|
||||||
|
|
||||||
|
streamSettings.realitySettings = realitySettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
//streamSettings
|
||||||
|
switch (node.GetNetwork())
|
||||||
|
{
|
||||||
|
case "kcp":
|
||||||
|
KcpSettings kcpSettings = new()
|
||||||
|
{
|
||||||
|
mtu = _config.kcpItem.mtu,
|
||||||
|
tti = _config.kcpItem.tti
|
||||||
|
};
|
||||||
|
|
||||||
|
kcpSettings.uplinkCapacity = _config.kcpItem.uplinkCapacity;
|
||||||
|
kcpSettings.downlinkCapacity = _config.kcpItem.downlinkCapacity;
|
||||||
|
|
||||||
|
kcpSettings.congestion = _config.kcpItem.congestion;
|
||||||
|
kcpSettings.readBufferSize = _config.kcpItem.readBufferSize;
|
||||||
|
kcpSettings.writeBufferSize = _config.kcpItem.writeBufferSize;
|
||||||
|
kcpSettings.header = new Header
|
||||||
|
{
|
||||||
|
type = node.headerType
|
||||||
|
};
|
||||||
|
if (!Utils.IsNullOrEmpty(node.path))
|
||||||
|
{
|
||||||
|
kcpSettings.seed = node.path;
|
||||||
|
}
|
||||||
|
streamSettings.kcpSettings = kcpSettings;
|
||||||
|
break;
|
||||||
|
//ws
|
||||||
|
case "ws":
|
||||||
|
WsSettings wsSettings = new();
|
||||||
|
wsSettings.headers = new Headers();
|
||||||
|
string path = node.path;
|
||||||
|
if (!string.IsNullOrWhiteSpace(host))
|
||||||
|
{
|
||||||
|
wsSettings.headers.Host = host;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrWhiteSpace(path))
|
||||||
|
{
|
||||||
|
wsSettings.path = path;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrWhiteSpace(useragent))
|
||||||
|
{
|
||||||
|
wsSettings.headers.UserAgent = useragent;
|
||||||
|
}
|
||||||
|
streamSettings.wsSettings = wsSettings;
|
||||||
|
|
||||||
|
break;
|
||||||
|
//h2
|
||||||
|
case "h2":
|
||||||
|
HttpSettings httpSettings = new();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(host))
|
||||||
|
{
|
||||||
|
httpSettings.host = Utils.String2List(host);
|
||||||
|
}
|
||||||
|
httpSettings.path = node.path;
|
||||||
|
|
||||||
|
streamSettings.httpSettings = httpSettings;
|
||||||
|
|
||||||
|
break;
|
||||||
|
//quic
|
||||||
|
case "quic":
|
||||||
|
QuicSettings quicsettings = new()
|
||||||
|
{
|
||||||
|
security = host,
|
||||||
|
key = node.path,
|
||||||
|
header = new Header
|
||||||
|
{
|
||||||
|
type = node.headerType
|
||||||
|
}
|
||||||
|
};
|
||||||
|
streamSettings.quicSettings = quicsettings;
|
||||||
|
if (node.streamSecurity == Global.StreamSecurity)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(sni))
|
||||||
|
{
|
||||||
|
streamSettings.tlsSettings.serverName = sni;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
streamSettings.tlsSettings.serverName = node.address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "grpc":
|
||||||
|
GrpcSettings grpcSettings = new()
|
||||||
|
{
|
||||||
|
serviceName = node.path,
|
||||||
|
multiMode = (node.headerType == Global.GrpcmultiMode),
|
||||||
|
idle_timeout = _config.grpcItem.idle_timeout,
|
||||||
|
health_check_timeout = _config.grpcItem.health_check_timeout,
|
||||||
|
permit_without_stream = _config.grpcItem.permit_without_stream,
|
||||||
|
initial_windows_size = _config.grpcItem.initial_windows_size,
|
||||||
|
};
|
||||||
|
streamSettings.grpcSettings = grpcSettings;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
//tcp
|
||||||
|
if (node.headerType == Global.TcpHeaderHttp)
|
||||||
|
{
|
||||||
|
TcpSettings tcpSettings = new()
|
||||||
|
{
|
||||||
|
header = new Header
|
||||||
|
{
|
||||||
|
type = node.headerType
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//request Host
|
||||||
|
string request = Utils.GetEmbedText(Global.v2raySampleHttprequestFileName);
|
||||||
|
string[] arrHost = host.Split(',');
|
||||||
|
string host2 = string.Join("\",\"", arrHost);
|
||||||
|
request = request.Replace("$requestHost$", $"\"{host2}\"");
|
||||||
|
//request = request.Replace("$requestHost$", string.Format("\"{0}\"", config.requestHost()));
|
||||||
|
request = request.Replace("$requestUserAgent$", $"\"{useragent}\"");
|
||||||
|
//Path
|
||||||
|
string pathHttp = @"/";
|
||||||
|
if (!Utils.IsNullOrEmpty(node.path))
|
||||||
|
{
|
||||||
|
string[] arrPath = node.path.Split(',');
|
||||||
|
pathHttp = string.Join("\",\"", arrPath);
|
||||||
|
}
|
||||||
|
request = request.Replace("$requestPath$", $"\"{pathHttp}\"");
|
||||||
|
tcpSettings.header.request = Utils.FromJson<object>(request);
|
||||||
|
|
||||||
|
streamSettings.tcpSettings = tcpSettings;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int dns(V2rayConfig v2rayConfig)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(_config.remoteDNS))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Outbound Freedom domainStrategy
|
||||||
|
if (!string.IsNullOrWhiteSpace(_config.domainStrategy4Freedom))
|
||||||
|
{
|
||||||
|
var outbound = v2rayConfig.outbounds[1];
|
||||||
|
outbound.settings.domainStrategy = _config.domainStrategy4Freedom;
|
||||||
|
outbound.settings.userLevel = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var obj = Utils.ParseJson(_config.remoteDNS);
|
||||||
|
if (obj?.ContainsKey("servers") == true)
|
||||||
|
{
|
||||||
|
v2rayConfig.dns = obj;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<string> servers = new();
|
||||||
|
|
||||||
|
string[] arrDNS = _config.remoteDNS.Split(',');
|
||||||
|
foreach (string str in arrDNS)
|
||||||
|
{
|
||||||
|
//if (Utils.IsIP(str))
|
||||||
|
//{
|
||||||
|
servers.Add(str);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
//servers.Add("localhost");
|
||||||
|
v2rayConfig.dns = new Mode.Dns
|
||||||
|
{
|
||||||
|
servers = servers
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int statistic(V2rayConfig v2rayConfig)
|
||||||
|
{
|
||||||
|
if (_config.guiItem.enableStatistics)
|
||||||
|
{
|
||||||
|
string tag = Global.InboundAPITagName;
|
||||||
|
API apiObj = new();
|
||||||
|
Policy policyObj = new();
|
||||||
|
SystemPolicy policySystemSetting = new();
|
||||||
|
|
||||||
|
string[] services = { "StatsService" };
|
||||||
|
|
||||||
|
v2rayConfig.stats = new Stats();
|
||||||
|
|
||||||
|
apiObj.tag = tag;
|
||||||
|
apiObj.services = services.ToList();
|
||||||
|
v2rayConfig.api = apiObj;
|
||||||
|
|
||||||
|
policySystemSetting.statsOutboundDownlink = true;
|
||||||
|
policySystemSetting.statsOutboundUplink = true;
|
||||||
|
policyObj.system = policySystemSetting;
|
||||||
|
v2rayConfig.policy = policyObj;
|
||||||
|
|
||||||
|
if (!v2rayConfig.inbounds.Exists(item => item.tag == tag))
|
||||||
|
{
|
||||||
|
Inbounds apiInbound = new();
|
||||||
|
Inboundsettings apiInboundSettings = new();
|
||||||
|
apiInbound.tag = tag;
|
||||||
|
apiInbound.listen = Global.Loopback;
|
||||||
|
apiInbound.port = Global.statePort;
|
||||||
|
apiInbound.protocol = Global.InboundAPIProtocal;
|
||||||
|
apiInboundSettings.address = Global.Loopback;
|
||||||
|
apiInbound.settings = apiInboundSettings;
|
||||||
|
v2rayConfig.inbounds.Add(apiInbound);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!v2rayConfig.routing.rules.Exists(item => item.outboundTag == tag))
|
||||||
|
{
|
||||||
|
RulesItem apiRoutingRule = new()
|
||||||
|
{
|
||||||
|
inboundTag = new List<string> { tag },
|
||||||
|
outboundTag = tag,
|
||||||
|
type = "field"
|
||||||
|
};
|
||||||
|
v2rayConfig.routing.rules.Add(apiRoutingRule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Gen speedtest config
|
||||||
|
|
||||||
|
public string GenerateClientSpeedtestConfigString(List<ServerTestItem> selecteds, out string msg)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_config == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = ResUI.InitialConfiguration;
|
||||||
|
|
||||||
|
Config configCopy = Utils.DeepCopy(_config);
|
||||||
|
|
||||||
|
string result = Utils.GetEmbedText(SampleClient);
|
||||||
|
if (Utils.IsNullOrEmpty(result))
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGetDefaultConfiguration;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
|
||||||
|
if (v2rayConfig == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
List<IPEndPoint> lstIpEndPoints = new();
|
||||||
|
List<TcpConnectionInformation> lstTcpConns = new();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
|
||||||
|
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
|
||||||
|
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
log(v2rayConfig);
|
||||||
|
v2rayConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts.
|
||||||
|
|
||||||
|
int httpPort = LazyConfig.Instance.GetLocalPort("speedtest");
|
||||||
|
|
||||||
|
foreach (var it in selecteds)
|
||||||
|
{
|
||||||
|
if (it.configType == EConfigType.Custom)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (it.port <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
|
||||||
|
{
|
||||||
|
var item2 = LazyConfig.Instance.GetProfileItem(it.indexId);
|
||||||
|
if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//find unuse port
|
||||||
|
var port = httpPort;
|
||||||
|
for (int k = httpPort; k < Global.MaxPort; k++)
|
||||||
|
{
|
||||||
|
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//found
|
||||||
|
port = k;
|
||||||
|
httpPort = port + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Port In Used
|
||||||
|
if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
it.port = port;
|
||||||
|
it.allowTest = true;
|
||||||
|
|
||||||
|
//inbound
|
||||||
|
Inbounds inbound = new()
|
||||||
|
{
|
||||||
|
listen = Global.Loopback,
|
||||||
|
port = port,
|
||||||
|
protocol = Global.InboundHttp
|
||||||
|
};
|
||||||
|
inbound.tag = Global.InboundHttp + inbound.port.ToString();
|
||||||
|
v2rayConfig.inbounds.Add(inbound);
|
||||||
|
|
||||||
|
//outbound
|
||||||
|
V2rayConfig? v2rayConfigCopy = Utils.FromJson<V2rayConfig>(result);
|
||||||
|
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (item.configType == EConfigType.Shadowsocks
|
||||||
|
&& !Global.ssSecuritysInXray.Contains(item.security))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (item.configType == EConfigType.VLESS
|
||||||
|
&& !Global.flows.Contains(item.flow))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
outbound(item, v2rayConfigCopy);
|
||||||
|
v2rayConfigCopy.outbounds[0].tag = Global.agentTag + inbound.port.ToString();
|
||||||
|
v2rayConfig.outbounds.Add(v2rayConfigCopy.outbounds[0]);
|
||||||
|
|
||||||
|
//rule
|
||||||
|
RulesItem rule = new()
|
||||||
|
{
|
||||||
|
inboundTag = new List<string> { inbound.tag },
|
||||||
|
outboundTag = v2rayConfigCopy.outbounds[0].tag,
|
||||||
|
type = "field"
|
||||||
|
};
|
||||||
|
v2rayConfig.routing.rules.Add(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
//msg = string.Format(ResUI.SuccessfulConfiguration"), node.getSummary());
|
||||||
|
return Utils.ToJson(v2rayConfig);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utils.SaveLog(ex.Message, ex);
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Gen speedtest config
|
||||||
|
}
|
||||||
|
}
|
|
@ -144,9 +144,7 @@ namespace v2rayN.Handler
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//Config configCopy = Utils.DeepCopy(config);
|
if (CoreConfigHandler.GenerateClientConfig(item, fileName, out string msg, out string content) != 0)
|
||||||
//configCopy.index = index;
|
|
||||||
if (CoreConfigHandler.Export2ClientConfig(item, fileName, out string msg) != 0)
|
|
||||||
{
|
{
|
||||||
UI.Show(msg);
|
UI.Show(msg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
namespace v2rayN.Mode
|
||||||
|
{
|
||||||
|
public class SingboxConfig
|
||||||
|
{
|
||||||
|
public Log4Sbox log { get; set; }
|
||||||
|
public Dns4Sbox dns { get; set; }
|
||||||
|
public List<Inbound4Sbox> inbounds { get; set; }
|
||||||
|
public List<Outbound4Sbox> outbounds { get; set; }
|
||||||
|
public Route4Sbox route { get; set; }
|
||||||
|
public Experimental4Sbox experimental { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Log4Sbox
|
||||||
|
{
|
||||||
|
public bool? disabled { get; set; }
|
||||||
|
public string level { get; set; }
|
||||||
|
public string output { get; set; }
|
||||||
|
public bool timestamp { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Dns4Sbox
|
||||||
|
{
|
||||||
|
public List<Server4Sbox> servers { get; set; }
|
||||||
|
public List<Rule4Sbox> rules { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Route4Sbox
|
||||||
|
{
|
||||||
|
public List<Rule4Sbox> rules { get; set; }
|
||||||
|
public bool? auto_detect_interface { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class Rule4Sbox
|
||||||
|
{
|
||||||
|
public string outbound { get; set; }
|
||||||
|
public string server { get; set; }
|
||||||
|
public bool? disable_cache { get; set; }
|
||||||
|
public List<string>? inbound { get; set; }
|
||||||
|
public List<string>? protocol { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public string mode { get; set; }
|
||||||
|
public List<int>? port { get; set; }
|
||||||
|
public List<string>? port_range { get; set; }
|
||||||
|
public List<string>? geosite { get; set; }
|
||||||
|
public List<string>? domain { get; set; }
|
||||||
|
public List<string>? domain_suffix { get; set; }
|
||||||
|
public List<string>? domain_keyword { get; set; }
|
||||||
|
public List<string>? domain_regex { get; set; }
|
||||||
|
public List<string>? geoip { get; set; }
|
||||||
|
public List<string>? ip_cidr { get; set; }
|
||||||
|
|
||||||
|
public List<string>? process_name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class Inbound4Sbox
|
||||||
|
{
|
||||||
|
public string type { get; set; }
|
||||||
|
public string tag { get; set; }
|
||||||
|
public string listen { get; set; }
|
||||||
|
public int listen_port { get; set; }
|
||||||
|
public string domain_strategy { get; set; }
|
||||||
|
public string interface_name { get; set; }
|
||||||
|
public string inet4_address { get; set; }
|
||||||
|
public string inet6_address { get; set; }
|
||||||
|
public int? mtu { get; set; }
|
||||||
|
public bool? auto_route { get; set; }
|
||||||
|
public bool? strict_route { get; set; }
|
||||||
|
public bool? endpoint_independent_nat { get; set; }
|
||||||
|
public string? stack { get; set; }
|
||||||
|
public bool? sniff { get; set; }
|
||||||
|
public bool? sniff_override_destination { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Outbound4Sbox
|
||||||
|
{
|
||||||
|
public string type { get; set; }
|
||||||
|
public string tag { get; set; }
|
||||||
|
public string server { get; set; }
|
||||||
|
public int? server_port { get; set; }
|
||||||
|
public string uuid { get; set; }
|
||||||
|
public string security { get; set; }
|
||||||
|
public int? alter_id { get; set; }
|
||||||
|
public string flow { get; set; }
|
||||||
|
public int? up_mbps { get; set; }
|
||||||
|
public int? down_mbps { get; set; }
|
||||||
|
public string auth_str { get; set; }
|
||||||
|
public int? recv_window_conn { get; set; }
|
||||||
|
public int? recv_window { get; set; }
|
||||||
|
public bool? disable_mtu_discovery { get; set; }
|
||||||
|
public string detour { get; set; }
|
||||||
|
public string method { get; set; }
|
||||||
|
public string username { get; set; }
|
||||||
|
public string password { get; set; }
|
||||||
|
public string? version { get; set; }
|
||||||
|
public string? network { get; set; }
|
||||||
|
public string packet_encoding { get; set; }
|
||||||
|
public Tls4Sbox tls { get; set; }
|
||||||
|
public Multiplex4Sbox multiplex { get; set; }
|
||||||
|
public Transport4Sbox transport { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Tls4Sbox
|
||||||
|
{
|
||||||
|
public bool enabled { get; set; }
|
||||||
|
public string server_name { get; set; }
|
||||||
|
public bool? insecure { get; set; }
|
||||||
|
public List<string> alpn { get; set; }
|
||||||
|
public Utls4Sbox utls { get; set; }
|
||||||
|
public Reality4Sbox reality { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Multiplex4Sbox
|
||||||
|
{
|
||||||
|
public bool enabled { get; set; }
|
||||||
|
public string protocol { get; set; }
|
||||||
|
public int max_connections { get; set; }
|
||||||
|
public int min_streams { get; set; }
|
||||||
|
public int max_streams { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Utls4Sbox
|
||||||
|
{
|
||||||
|
public bool enabled { get; set; }
|
||||||
|
public string fingerprint { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Reality4Sbox
|
||||||
|
{
|
||||||
|
public bool enabled { get; set; }
|
||||||
|
public string public_key { get; set; }
|
||||||
|
public string short_id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Transport4Sbox
|
||||||
|
{
|
||||||
|
public string type { get; set; }
|
||||||
|
public List<string>? host { get; set; }
|
||||||
|
public string? path { get; set; }
|
||||||
|
public string service_name { get; set; }
|
||||||
|
public string idle_timeout { get; set; }
|
||||||
|
public string ping_timeout { get; set; }
|
||||||
|
public bool? permit_without_stream { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Server4Sbox
|
||||||
|
{
|
||||||
|
public string tag { get; set; }
|
||||||
|
public string address { get; set; }
|
||||||
|
public string address_resolver { get; set; }
|
||||||
|
public string strategy { get; set; }
|
||||||
|
public string detour { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Experimental4Sbox
|
||||||
|
{
|
||||||
|
public V2ray_Api4Sbox v2ray_api { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class V2ray_Api4Sbox
|
||||||
|
{
|
||||||
|
public string listen { get; set; }
|
||||||
|
public Stats4Sbox stats { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Stats4Sbox
|
||||||
|
{
|
||||||
|
public bool enabled { get; set; }
|
||||||
|
public List<string>? inbounds { get; set; }
|
||||||
|
public List<string>? outbounds { get; set; }
|
||||||
|
public List<string>? users { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,33 +0,0 @@
|
||||||
{
|
|
||||||
"log": {
|
|
||||||
"access": "/var/log/v2ray/access.log",
|
|
||||||
"error": "/var/log/v2ray/error.log",
|
|
||||||
"loglevel": "warning"
|
|
||||||
},
|
|
||||||
"inbounds": [{
|
|
||||||
"port": 10086,
|
|
||||||
"protocol": "vmess",
|
|
||||||
"settings": {
|
|
||||||
"clients": [{
|
|
||||||
"id": "23ad6b10-8d1a-40f7-8ad0-e3e35cd38297",
|
|
||||||
"level": 1,
|
|
||||||
"email": "t@t.tt"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"streamSettings": {
|
|
||||||
"network": "tcp"
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"outbounds": [{
|
|
||||||
"protocol": "freedom",
|
|
||||||
"settings": {}
|
|
||||||
}, {
|
|
||||||
"protocol": "blackhole",
|
|
||||||
"settings": {},
|
|
||||||
"tag": "block"
|
|
||||||
}],
|
|
||||||
"routing": {
|
|
||||||
"domainStrategy": "IPIfNonMatch",
|
|
||||||
"rules": []
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"log": {
|
||||||
|
"level": "debug",
|
||||||
|
"timestamp": true
|
||||||
|
},
|
||||||
|
"inbounds": [
|
||||||
|
{
|
||||||
|
"type": "socks",
|
||||||
|
"tag": "socks",
|
||||||
|
"listen": "127.0.0.1",
|
||||||
|
"listen_port": 10000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"type": "vless",
|
||||||
|
"tag": "proxy",
|
||||||
|
"server": "",
|
||||||
|
"server_port": 443
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "direct",
|
||||||
|
"tag": "direct"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "block",
|
||||||
|
"tag": "block"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"route": {
|
||||||
|
"rules": []
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,9 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AdditionalFiles Include="app.manifest" />
|
<AdditionalFiles Include="app.manifest" />
|
||||||
|
<EmbeddedResource Include="Sample\SingboxSampleClientConfig">
|
||||||
|
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||||
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Include="Sample\tun_singbox">
|
<EmbeddedResource Include="Sample\tun_singbox">
|
||||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
@ -64,9 +67,6 @@
|
||||||
<EmbeddedResource Include="Sample\SampleInbound">
|
<EmbeddedResource Include="Sample\SampleInbound">
|
||||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Include="Sample\SampleServerConfig">
|
|
||||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Include="v2rayN.ico">
|
<EmbeddedResource Include="v2rayN.ico">
|
||||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
|
Loading…
Reference in New Issue