mirror of
				https://github.com/2dust/v2rayN.git
				synced 2025-10-31 12:32:53 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1309 lines
		
	
	
	
		
			51 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			1309 lines
		
	
	
	
		
			51 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System.Net;
 | |
| using System.Net.NetworkInformation;
 | |
| using System.Text.Json.Nodes;
 | |
| 
 | |
| namespace ServiceLib.Services.CoreConfig
 | |
| {
 | |
|     public class CoreConfigV2rayService
 | |
|     {
 | |
|         private Config _config;
 | |
|         private static readonly string _tag = "CoreConfigV2rayService";
 | |
| 
 | |
|         public CoreConfigV2rayService(Config config)
 | |
|         {
 | |
|             _config = config;
 | |
|         }
 | |
| 
 | |
|         #region public gen function
 | |
| 
 | |
|         public async Task<RetResult> GenerateClientConfigContent(ProfileItem node)
 | |
|         {
 | |
|             var ret = new RetResult();
 | |
|             try
 | |
|             {
 | |
|                 if (node == null
 | |
|                     || node.Port <= 0)
 | |
|                 {
 | |
|                     ret.Msg = ResUI.CheckServerSettings;
 | |
|                     return ret;
 | |
|                 }
 | |
| 
 | |
|                 if (node.GetNetwork() is nameof(ETransport.quic))
 | |
|                 {
 | |
|                     ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}";
 | |
|                     return ret;
 | |
|                 }
 | |
| 
 | |
|                 ret.Msg = ResUI.InitialConfiguration;
 | |
| 
 | |
|                 var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient);
 | |
|                 if (Utils.IsNullOrEmpty(result))
 | |
|                 {
 | |
|                     ret.Msg = ResUI.FailedGetDefaultConfiguration;
 | |
|                     return ret;
 | |
|                 }
 | |
| 
 | |
|                 var v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(result);
 | |
|                 if (v2rayConfig == null)
 | |
|                 {
 | |
|                     ret.Msg = ResUI.FailedGenDefaultConfiguration;
 | |
|                     return ret;
 | |
|                 }
 | |
| 
 | |
|                 await GenLog(v2rayConfig);
 | |
| 
 | |
|                 await GenInbounds(v2rayConfig);
 | |
| 
 | |
|                 await GenRouting(v2rayConfig);
 | |
| 
 | |
|                 await GenOutbound(node, v2rayConfig.outbounds.First());
 | |
| 
 | |
|                 await GenMoreOutbounds(node, v2rayConfig);
 | |
| 
 | |
|                 await GenDns(node, v2rayConfig);
 | |
| 
 | |
|                 await GenStatistic(v2rayConfig);
 | |
| 
 | |
|                 ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
 | |
|                 ret.Success = true;
 | |
|                 ret.Data = JsonUtils.Serialize(v2rayConfig);
 | |
|                 return ret;
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 Logging.SaveLog(_tag, ex);
 | |
|                 ret.Msg = ResUI.FailedGenDefaultConfiguration;
 | |
|                 return ret;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public async Task<RetResult> GenerateClientMultipleLoadConfig(List<ProfileItem> selecteds)
 | |
|         {
 | |
|             var ret = new RetResult();
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 if (_config == null)
 | |
|                 {
 | |
|                     ret.Msg = ResUI.CheckServerSettings;
 | |
|                     return ret;
 | |
|                 }
 | |
| 
 | |
|                 ret.Msg = ResUI.InitialConfiguration;
 | |
| 
 | |
|                 string result = EmbedUtils.GetEmbedText(Global.V2raySampleClient);
 | |
|                 string txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
 | |
|                 if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
 | |
|                 {
 | |
|                     ret.Msg = ResUI.FailedGetDefaultConfiguration;
 | |
|                     return ret;
 | |
|                 }
 | |
| 
 | |
|                 var v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(result);
 | |
|                 if (v2rayConfig == null)
 | |
|                 {
 | |
|                     ret.Msg = ResUI.FailedGenDefaultConfiguration;
 | |
|                     return ret;
 | |
|                 }
 | |
| 
 | |
|                 await GenLog(v2rayConfig);
 | |
|                 await GenInbounds(v2rayConfig);
 | |
|                 await GenRouting(v2rayConfig);
 | |
|                 await GenDns(null, v2rayConfig);
 | |
|                 await GenStatistic(v2rayConfig);
 | |
|                 v2rayConfig.outbounds.RemoveAt(0);
 | |
| 
 | |
|                 var tagProxy = new List<string>();
 | |
|                 foreach (var it in selecteds)
 | |
|                 {
 | |
|                     if (it.ConfigType == EConfigType.Custom)
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
|                     if (it.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard)
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
|                     if (it.Port <= 0)
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
|                     var item = await AppHandler.Instance.GetProfileItem(it.IndexId);
 | |
|                     if (item is null)
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
|                     if (it.ConfigType is EConfigType.VMess or EConfigType.VLESS)
 | |
|                     {
 | |
|                         if (Utils.IsNullOrEmpty(item.Id) || !Utils.IsGuidByParse(item.Id))
 | |
|                         {
 | |
|                             continue;
 | |
|                         }
 | |
|                     }
 | |
|                     if (item.ConfigType == EConfigType.Shadowsocks
 | |
|                       && !Global.SsSecuritiesInSingbox.Contains(item.Security))
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
|                     if (item.ConfigType == EConfigType.VLESS && !Global.Flows.Contains(item.Flow))
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
| 
 | |
|                     //outbound
 | |
|                     var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
 | |
|                     await GenOutbound(item, outbound);
 | |
|                     outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}";
 | |
|                     v2rayConfig.outbounds.Insert(0, outbound);
 | |
|                     tagProxy.Add(outbound.tag);
 | |
|                 }
 | |
|                 if (tagProxy.Count <= 0)
 | |
|                 {
 | |
|                     ret.Msg = ResUI.FailedGenDefaultConfiguration;
 | |
|                     return ret;
 | |
|                 }
 | |
| 
 | |
|                 //add balancers
 | |
|                 var balancer = new BalancersItem4Ray
 | |
|                 {
 | |
|                     selector = [Global.ProxyTag],
 | |
|                     strategy = new() { type = "roundRobin" },
 | |
|                     tag = $"{Global.ProxyTag}-round",
 | |
|                 };
 | |
|                 v2rayConfig.routing.balancers = [balancer];
 | |
| 
 | |
|                 //add rule
 | |
|                 var rules = v2rayConfig.routing.rules.Where(t => t.outboundTag == Global.ProxyTag).ToList();
 | |
|                 if (rules?.Count > 0)
 | |
|                 {
 | |
|                     foreach (var rule in rules)
 | |
|                     {
 | |
|                         rule.outboundTag = null;
 | |
|                         rule.balancerTag = balancer.tag;
 | |
|                     }
 | |
|                 }
 | |
|                 v2rayConfig.routing.rules.Add(new()
 | |
|                 {
 | |
|                     network = "tcp,udp",
 | |
|                     balancerTag = balancer.tag,
 | |
|                     type = "field"
 | |
|                 });
 | |
| 
 | |
|                 ret.Success = true;
 | |
|                 ret.Data = JsonUtils.Serialize(v2rayConfig);
 | |
|                 return ret;
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 Logging.SaveLog(_tag, ex);
 | |
|                 ret.Msg = ResUI.FailedGenDefaultConfiguration;
 | |
|                 return ret;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public async Task<RetResult> GenerateClientSpeedtestConfig(List<ServerTestItem> selecteds)
 | |
|         {
 | |
|             var ret = new RetResult();
 | |
|             try
 | |
|             {
 | |
|                 if (_config == null)
 | |
|                 {
 | |
|                     ret.Msg = ResUI.CheckServerSettings;
 | |
|                     return ret;
 | |
|                 }
 | |
| 
 | |
|                 ret.Msg = ResUI.InitialConfiguration;
 | |
| 
 | |
|                 var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient);
 | |
|                 var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
 | |
|                 if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
 | |
|                 {
 | |
|                     ret.Msg = ResUI.FailedGetDefaultConfiguration;
 | |
|                     return ret;
 | |
|                 }
 | |
| 
 | |
|                 var v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(result);
 | |
|                 if (v2rayConfig == null)
 | |
|                 {
 | |
|                     ret.Msg = ResUI.FailedGenDefaultConfiguration;
 | |
|                     return ret;
 | |
|                 }
 | |
|                 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)
 | |
|                 {
 | |
|                     Logging.SaveLog(_tag, ex);
 | |
|                 }
 | |
| 
 | |
|                 await GenLog(v2rayConfig);
 | |
|                 v2rayConfig.inbounds.Clear();
 | |
|                 v2rayConfig.outbounds.Clear();
 | |
|                 v2rayConfig.routing.rules.Clear();
 | |
| 
 | |
|                 var initPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
 | |
| 
 | |
|                 foreach (var it in selecteds)
 | |
|                 {
 | |
|                     if (it.ConfigType == EConfigType.Custom)
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
|                     if (it.Port <= 0)
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
|                     var item = await AppHandler.Instance.GetProfileItem(it.IndexId);
 | |
|                     if (it.ConfigType is EConfigType.VMess or EConfigType.VLESS)
 | |
|                     {
 | |
|                         if (item is null || Utils.IsNullOrEmpty(item.Id) || !Utils.IsGuidByParse(item.Id))
 | |
|                         {
 | |
|                             continue;
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     //find unused port
 | |
|                     var port = initPort;
 | |
|                     for (var k = initPort; 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;
 | |
|                         initPort = port + 1;
 | |
|                         break;
 | |
|                     }
 | |
| 
 | |
|                     //Port In Used
 | |
|                     if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0)
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
|                     it.Port = port;
 | |
|                     it.AllowTest = true;
 | |
| 
 | |
|                     //outbound
 | |
|                     if (item is null)
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
|                     if (item.ConfigType == EConfigType.Shadowsocks
 | |
|                         && !Global.SsSecuritiesInXray.Contains(item.Security))
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
|                     if (item.ConfigType == EConfigType.VLESS
 | |
|                      && !Global.Flows.Contains(item.Flow))
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
|                     if (it.ConfigType is EConfigType.VLESS or EConfigType.Trojan
 | |
|                         && item.StreamSecurity == Global.StreamSecurityReality
 | |
|                         && item.PublicKey.IsNullOrEmpty())
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
| 
 | |
|                     //inbound
 | |
|                     Inbounds4Ray inbound = new()
 | |
|                     {
 | |
|                         listen = Global.Loopback,
 | |
|                         port = port,
 | |
|                         protocol = EInboundProtocol.socks.ToString(),
 | |
|                     };
 | |
|                     inbound.tag = inbound.protocol + inbound.port.ToString();
 | |
|                     v2rayConfig.inbounds.Add(inbound);
 | |
| 
 | |
|                     var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
 | |
|                     await GenOutbound(item, outbound);
 | |
|                     outbound.tag = Global.ProxyTag + inbound.port.ToString();
 | |
|                     v2rayConfig.outbounds.Add(outbound);
 | |
| 
 | |
|                     //rule
 | |
|                     RulesItem4Ray rule = new()
 | |
|                     {
 | |
|                         inboundTag = new List<string> { inbound.tag },
 | |
|                         outboundTag = outbound.tag,
 | |
|                         type = "field"
 | |
|                     };
 | |
|                     v2rayConfig.routing.rules.Add(rule);
 | |
|                 }
 | |
| 
 | |
|                 //ret.Msg =string.Format(ResUI.SuccessfulConfiguration"), node.getSummary());
 | |
|                 ret.Success = true;
 | |
|                 ret.Data = JsonUtils.Serialize(v2rayConfig);
 | |
|                 return ret;
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 Logging.SaveLog(_tag, ex);
 | |
|                 ret.Msg = ResUI.FailedGenDefaultConfiguration;
 | |
|                 return ret;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public async Task<RetResult> GenerateClientSpeedtestConfig(ProfileItem node, int port)
 | |
|         {
 | |
|             var ret = new RetResult();
 | |
|             try
 | |
|             {
 | |
|                 if (node is not { Port: > 0 })
 | |
|                 {
 | |
|                     ret.Msg = ResUI.CheckServerSettings;
 | |
|                     return ret;
 | |
|                 }
 | |
| 
 | |
|                 if (node.GetNetwork() is nameof(ETransport.quic))
 | |
|                 {
 | |
|                     ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}";
 | |
|                     return ret;
 | |
|                 }
 | |
| 
 | |
|                 var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient);
 | |
|                 if (Utils.IsNullOrEmpty(result))
 | |
|                 {
 | |
|                     ret.Msg = ResUI.FailedGetDefaultConfiguration;
 | |
|                     return ret;
 | |
|                 }
 | |
| 
 | |
|                 var v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(result);
 | |
|                 if (v2rayConfig == null)
 | |
|                 {
 | |
|                     ret.Msg = ResUI.FailedGenDefaultConfiguration;
 | |
|                     return ret;
 | |
|                 }
 | |
| 
 | |
|                 await GenLog(v2rayConfig);
 | |
|                 await GenOutbound(node, v2rayConfig.outbounds.First());
 | |
|                 await GenMoreOutbounds(node, v2rayConfig);
 | |
| 
 | |
|                 v2rayConfig.routing.rules.Clear();
 | |
|                 v2rayConfig.inbounds.Clear();
 | |
|                 v2rayConfig.inbounds.Add(new()
 | |
|                 {
 | |
|                     tag = $"{EInboundProtocol.socks}{port}",
 | |
|                     listen = Global.Loopback,
 | |
|                     port = port,
 | |
|                     protocol = EInboundProtocol.socks.ToString(),
 | |
|                 });
 | |
| 
 | |
|                 ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
 | |
|                 ret.Success = true;
 | |
|                 ret.Data = JsonUtils.Serialize(v2rayConfig);
 | |
|                 return ret;
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 Logging.SaveLog(_tag, ex);
 | |
|                 ret.Msg = ResUI.FailedGenDefaultConfiguration;
 | |
|                 return ret;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion public gen function
 | |
| 
 | |
|         #region private gen function
 | |
| 
 | |
|         private async Task<int> GenLog(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 = null;
 | |
|                     v2rayConfig.log.error = null;
 | |
|                 }
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 Logging.SaveLog(_tag, ex);
 | |
|             }
 | |
|             return await Task.FromResult(0);
 | |
|         }
 | |
| 
 | |
|         private async Task<int> GenInbounds(V2rayConfig v2rayConfig)
 | |
|         {
 | |
|             try
 | |
|             {
 | |
|                 var listen = "0.0.0.0";
 | |
|                 v2rayConfig.inbounds = [];
 | |
| 
 | |
|                 var inbound = GetInbound(_config.Inbound.First(), EInboundProtocol.socks, true);
 | |
|                 v2rayConfig.inbounds.Add(inbound);
 | |
| 
 | |
|                 if (_config.Inbound.First().SecondLocalPortEnabled)
 | |
|                 {
 | |
|                     var inbound2 = GetInbound(_config.Inbound.First(), EInboundProtocol.socks2, true);
 | |
|                     v2rayConfig.inbounds.Add(inbound2);
 | |
|                 }
 | |
| 
 | |
|                 if (_config.Inbound.First().AllowLANConn)
 | |
|                 {
 | |
|                     if (_config.Inbound.First().NewPort4LAN)
 | |
|                     {
 | |
|                         var inbound3 = GetInbound(_config.Inbound.First(), EInboundProtocol.socks3, true);
 | |
|                         inbound3.listen = listen;
 | |
|                         v2rayConfig.inbounds.Add(inbound3);
 | |
| 
 | |
|                         //auth
 | |
|                         if (Utils.IsNotEmpty(_config.Inbound.First().User) && Utils.IsNotEmpty(_config.Inbound.First().Pass))
 | |
|                         {
 | |
|                             inbound3.settings.auth = "password";
 | |
|                             inbound3.settings.accounts = new List<AccountsItem4Ray> { new AccountsItem4Ray() { user = _config.Inbound.First().User, pass = _config.Inbound.First().Pass } };
 | |
|                         }
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         inbound.listen = listen;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 Logging.SaveLog(_tag, ex);
 | |
|             }
 | |
|             return await Task.FromResult(0);
 | |
|         }
 | |
| 
 | |
|         private Inbounds4Ray GetInbound(InItem inItem, EInboundProtocol protocol, bool bSocks)
 | |
|         {
 | |
|             string result = EmbedUtils.GetEmbedText(Global.V2raySampleInbound);
 | |
|             if (Utils.IsNullOrEmpty(result))
 | |
|             {
 | |
|                 return new();
 | |
|             }
 | |
| 
 | |
|             var inbound = JsonUtils.Deserialize<Inbounds4Ray>(result);
 | |
|             if (inbound == null)
 | |
|             {
 | |
|                 return new();
 | |
|             }
 | |
|             inbound.tag = protocol.ToString();
 | |
|             inbound.port = inItem.LocalPort + (int)protocol;
 | |
|             inbound.protocol = EInboundProtocol.socks.ToString();
 | |
|             inbound.settings.udp = inItem.UdpEnabled;
 | |
|             inbound.sniffing.enabled = inItem.SniffingEnabled;
 | |
|             inbound.sniffing.destOverride = inItem.DestOverride;
 | |
|             inbound.sniffing.routeOnly = inItem.RouteOnly;
 | |
| 
 | |
|             return inbound;
 | |
|         }
 | |
| 
 | |
|         private async Task<int> GenRouting(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;
 | |
| 
 | |
|                     var routing = await ConfigHandler.GetDefaultRouting(_config);
 | |
|                     if (routing != null)
 | |
|                     {
 | |
|                         if (Utils.IsNotEmpty(routing.DomainStrategy))
 | |
|                         {
 | |
|                             v2rayConfig.routing.domainStrategy = routing.DomainStrategy;
 | |
|                         }
 | |
|                         var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
 | |
|                         foreach (var item in rules)
 | |
|                         {
 | |
|                             if (item.Enabled)
 | |
|                             {
 | |
|                                 var item2 = JsonUtils.Deserialize<RulesItem4Ray>(JsonUtils.Serialize(item));
 | |
|                                 await GenRoutingUserRule(item2, v2rayConfig);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 Logging.SaveLog(_tag, ex);
 | |
|             }
 | |
|             return 0;
 | |
|         }
 | |
| 
 | |
|         private async Task<int> GenRoutingUserRule(RulesItem4Ray? rule, V2rayConfig v2rayConfig)
 | |
|         {
 | |
|             try
 | |
|             {
 | |
|                 if (rule == null)
 | |
|                 {
 | |
|                     return 0;
 | |
|                 }
 | |
|                 if (Utils.IsNullOrEmpty(rule.port))
 | |
|                 {
 | |
|                     rule.port = null;
 | |
|                 }
 | |
|                 if (Utils.IsNullOrEmpty(rule.network))
 | |
|                 {
 | |
|                     rule.network = null;
 | |
|                 }
 | |
|                 if (rule.domain?.Count == 0)
 | |
|                 {
 | |
|                     rule.domain = null;
 | |
|                 }
 | |
|                 if (rule.ip?.Count == 0)
 | |
|                 {
 | |
|                     rule.ip = null;
 | |
|                 }
 | |
|                 if (rule.protocol?.Count == 0)
 | |
|                 {
 | |
|                     rule.protocol = null;
 | |
|                 }
 | |
|                 if (rule.inboundTag?.Count == 0)
 | |
|                 {
 | |
|                     rule.inboundTag = null;
 | |
|                 }
 | |
| 
 | |
|                 var hasDomainIp = false;
 | |
|                 if (rule.domain?.Count > 0)
 | |
|                 {
 | |
|                     var it = JsonUtils.DeepCopy(rule);
 | |
|                     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 (rule.ip?.Count > 0)
 | |
|                 {
 | |
|                     var it = JsonUtils.DeepCopy(rule);
 | |
|                     it.domain = null;
 | |
|                     it.type = "field";
 | |
|                     v2rayConfig.routing.rules.Add(it);
 | |
|                     hasDomainIp = true;
 | |
|                 }
 | |
|                 if (!hasDomainIp)
 | |
|                 {
 | |
|                     if (Utils.IsNotEmpty(rule.port)
 | |
|                         || rule.protocol?.Count > 0
 | |
|                         || rule.inboundTag?.Count > 0
 | |
|                         )
 | |
|                     {
 | |
|                         var it = JsonUtils.DeepCopy(rule);
 | |
|                         it.type = "field";
 | |
|                         v2rayConfig.routing.rules.Add(it);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 Logging.SaveLog(_tag, ex);
 | |
|             }
 | |
|             return await Task.FromResult(0);
 | |
|         }
 | |
| 
 | |
|         private async Task<int> GenOutbound(ProfileItem node, Outbounds4Ray outbound)
 | |
|         {
 | |
|             try
 | |
|             {
 | |
|                 var muxEnabled = _config.CoreBasicItem.MuxEnabled;
 | |
|                 switch (node.ConfigType)
 | |
|                 {
 | |
|                     case EConfigType.VMess:
 | |
|                         {
 | |
|                             VnextItem4Ray vnextItem;
 | |
|                             if (outbound.settings.vnext.Count <= 0)
 | |
|                             {
 | |
|                                 vnextItem = new VnextItem4Ray();
 | |
|                                 outbound.settings.vnext.Add(vnextItem);
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 vnextItem = outbound.settings.vnext.First();
 | |
|                             }
 | |
|                             vnextItem.address = node.Address;
 | |
|                             vnextItem.port = node.Port;
 | |
| 
 | |
|                             UsersItem4Ray usersItem;
 | |
|                             if (vnextItem.users.Count <= 0)
 | |
|                             {
 | |
|                                 usersItem = new UsersItem4Ray();
 | |
|                                 vnextItem.users.Add(usersItem);
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 usersItem = vnextItem.users.First();
 | |
|                             }
 | |
|                             //远程服务器用户ID
 | |
|                             usersItem.id = node.Id;
 | |
|                             usersItem.alterId = node.AlterId;
 | |
|                             usersItem.email = Global.UserEMail;
 | |
|                             if (Global.VmessSecurities.Contains(node.Security))
 | |
|                             {
 | |
|                                 usersItem.security = node.Security;
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 usersItem.security = Global.DefaultSecurity;
 | |
|                             }
 | |
| 
 | |
|                             await GenOutboundMux(node, outbound, muxEnabled, muxEnabled);
 | |
| 
 | |
|                             outbound.settings.servers = null;
 | |
|                             break;
 | |
|                         }
 | |
|                     case EConfigType.Shadowsocks:
 | |
|                         {
 | |
|                             ServersItem4Ray serversItem;
 | |
|                             if (outbound.settings.servers.Count <= 0)
 | |
|                             {
 | |
|                                 serversItem = new ServersItem4Ray();
 | |
|                                 outbound.settings.servers.Add(serversItem);
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 serversItem = outbound.settings.servers.First();
 | |
|                             }
 | |
|                             serversItem.address = node.Address;
 | |
|                             serversItem.port = node.Port;
 | |
|                             serversItem.password = node.Id;
 | |
|                             serversItem.method = AppHandler.Instance.GetShadowsocksSecurities(node).Contains(node.Security) ? node.Security : "none";
 | |
| 
 | |
|                             serversItem.ota = false;
 | |
|                             serversItem.level = 1;
 | |
| 
 | |
|                             await GenOutboundMux(node, outbound);
 | |
| 
 | |
|                             outbound.settings.vnext = null;
 | |
|                             break;
 | |
|                         }
 | |
|                     case EConfigType.SOCKS:
 | |
|                     case EConfigType.HTTP:
 | |
|                         {
 | |
|                             ServersItem4Ray serversItem;
 | |
|                             if (outbound.settings.servers.Count <= 0)
 | |
|                             {
 | |
|                                 serversItem = new ServersItem4Ray();
 | |
|                                 outbound.settings.servers.Add(serversItem);
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 serversItem = outbound.settings.servers.First();
 | |
|                             }
 | |
|                             serversItem.address = node.Address;
 | |
|                             serversItem.port = node.Port;
 | |
|                             serversItem.method = null;
 | |
|                             serversItem.password = null;
 | |
| 
 | |
|                             if (Utils.IsNotEmpty(node.Security)
 | |
|                                 && Utils.IsNotEmpty(node.Id))
 | |
|                             {
 | |
|                                 SocksUsersItem4Ray socksUsersItem = new()
 | |
|                                 {
 | |
|                                     user = node.Security,
 | |
|                                     pass = node.Id,
 | |
|                                     level = 1
 | |
|                                 };
 | |
| 
 | |
|                                 serversItem.users = new List<SocksUsersItem4Ray>() { socksUsersItem };
 | |
|                             }
 | |
| 
 | |
|                             await GenOutboundMux(node, outbound);
 | |
| 
 | |
|                             outbound.settings.vnext = null;
 | |
|                             break;
 | |
|                         }
 | |
|                     case EConfigType.VLESS:
 | |
|                         {
 | |
|                             VnextItem4Ray vnextItem;
 | |
|                             if (outbound.settings.vnext?.Count <= 0)
 | |
|                             {
 | |
|                                 vnextItem = new VnextItem4Ray();
 | |
|                                 outbound.settings.vnext.Add(vnextItem);
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 vnextItem = outbound.settings.vnext.First();
 | |
|                             }
 | |
|                             vnextItem.address = node.Address;
 | |
|                             vnextItem.port = node.Port;
 | |
| 
 | |
|                             UsersItem4Ray usersItem;
 | |
|                             if (vnextItem.users.Count <= 0)
 | |
|                             {
 | |
|                                 usersItem = new UsersItem4Ray();
 | |
|                                 vnextItem.users.Add(usersItem);
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 usersItem = vnextItem.users.First();
 | |
|                             }
 | |
|                             usersItem.id = node.Id;
 | |
|                             usersItem.email = Global.UserEMail;
 | |
|                             usersItem.encryption = node.Security;
 | |
| 
 | |
|                             if (node.Flow.IsNullOrEmpty())
 | |
|                             {
 | |
|                                 await GenOutboundMux(node, outbound, muxEnabled, muxEnabled);
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 usersItem.flow = node.Flow;
 | |
|                                 await GenOutboundMux(node, outbound, false, muxEnabled);
 | |
|                             }
 | |
|                             outbound.settings.servers = null;
 | |
|                             break;
 | |
|                         }
 | |
|                     case EConfigType.Trojan:
 | |
|                         {
 | |
|                             ServersItem4Ray serversItem;
 | |
|                             if (outbound.settings.servers.Count <= 0)
 | |
|                             {
 | |
|                                 serversItem = new ServersItem4Ray();
 | |
|                                 outbound.settings.servers.Add(serversItem);
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 serversItem = outbound.settings.servers.First();
 | |
|                             }
 | |
|                             serversItem.address = node.Address;
 | |
|                             serversItem.port = node.Port;
 | |
|                             serversItem.password = node.Id;
 | |
| 
 | |
|                             serversItem.ota = false;
 | |
|                             serversItem.level = 1;
 | |
| 
 | |
|                             await GenOutboundMux(node, outbound);
 | |
| 
 | |
|                             outbound.settings.vnext = null;
 | |
|                             break;
 | |
|                         }
 | |
|                 }
 | |
| 
 | |
|                 outbound.protocol = Global.ProtocolTypes[node.ConfigType];
 | |
|                 await GenBoundStreamSettings(node, outbound);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 Logging.SaveLog(_tag, ex);
 | |
|             }
 | |
|             return 0;
 | |
|         }
 | |
| 
 | |
|         private async Task<int> GenOutboundMux(ProfileItem node, Outbounds4Ray outbound, bool enabledTCP = false, bool enabledUDP = false)
 | |
|         {
 | |
|             try
 | |
|             {
 | |
|                 outbound.mux.enabled = false;
 | |
|                 outbound.mux.concurrency = -1;
 | |
| 
 | |
|                 if (enabledTCP)
 | |
|                 {
 | |
|                     outbound.mux.enabled = true;
 | |
|                     outbound.mux.concurrency = _config.Mux4RayItem.Concurrency;
 | |
|                 }
 | |
|                 else if (enabledUDP)
 | |
|                 {
 | |
|                     outbound.mux.enabled = true;
 | |
|                     outbound.mux.xudpConcurrency = _config.Mux4RayItem.XudpConcurrency;
 | |
|                     outbound.mux.xudpProxyUDP443 = _config.Mux4RayItem.XudpProxyUDP443;
 | |
|                 }
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 Logging.SaveLog(_tag, ex);
 | |
|             }
 | |
|             return await Task.FromResult(0);
 | |
|         }
 | |
| 
 | |
|         private async Task<int> GenBoundStreamSettings(ProfileItem node, Outbounds4Ray outbound)
 | |
|         {
 | |
|             try
 | |
|             {
 | |
|                 var streamSettings = outbound.streamSettings;
 | |
|                 streamSettings.network = node.GetNetwork();
 | |
|                 var host = node.RequestHost.TrimEx();
 | |
|                 var path = node.Path.TrimEx();
 | |
|                 var sni = node.Sni.TrimEx();
 | |
|                 var useragent = "";
 | |
|                 if (!_config.CoreBasicItem.DefUserAgent.IsNullOrEmpty())
 | |
|                 {
 | |
|                     try
 | |
|                     {
 | |
|                         useragent = Global.UserAgentTexts[_config.CoreBasicItem.DefUserAgent];
 | |
|                     }
 | |
|                     catch (KeyNotFoundException)
 | |
|                     {
 | |
|                         useragent = _config.CoreBasicItem.DefUserAgent;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 //if tls
 | |
|                 if (node.StreamSecurity == Global.StreamSecurity)
 | |
|                 {
 | |
|                     streamSettings.security = node.StreamSecurity;
 | |
| 
 | |
|                     TlsSettings4Ray 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 (Utils.IsNotEmpty(sni))
 | |
|                     {
 | |
|                         tlsSettings.serverName = sni;
 | |
|                     }
 | |
|                     else if (Utils.IsNotEmpty(host))
 | |
|                     {
 | |
|                         tlsSettings.serverName = Utils.String2List(host)?.First();
 | |
|                     }
 | |
|                     streamSettings.tlsSettings = tlsSettings;
 | |
|                 }
 | |
| 
 | |
|                 //if Reality
 | |
|                 if (node.StreamSecurity == Global.StreamSecurityReality)
 | |
|                 {
 | |
|                     streamSettings.security = node.StreamSecurity;
 | |
| 
 | |
|                     TlsSettings4Ray realitySettings = new()
 | |
|                     {
 | |
|                         fingerprint = node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : node.Fingerprint,
 | |
|                         serverName = sni,
 | |
|                         publicKey = node.PublicKey,
 | |
|                         shortId = node.ShortId,
 | |
|                         spiderX = node.SpiderX,
 | |
|                         show = false,
 | |
|                     };
 | |
| 
 | |
|                     streamSettings.realitySettings = realitySettings;
 | |
|                 }
 | |
| 
 | |
|                 //streamSettings
 | |
|                 switch (node.GetNetwork())
 | |
|                 {
 | |
|                     case nameof(ETransport.kcp):
 | |
|                         KcpSettings4Ray 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 Header4Ray
 | |
|                         {
 | |
|                             type = node.HeaderType,
 | |
|                             domain = host.IsNullOrEmpty() ? null : host
 | |
|                         };
 | |
|                         if (Utils.IsNotEmpty(path))
 | |
|                         {
 | |
|                             kcpSettings.seed = path;
 | |
|                         }
 | |
|                         streamSettings.kcpSettings = kcpSettings;
 | |
|                         break;
 | |
|                     //ws
 | |
|                     case nameof(ETransport.ws):
 | |
|                         WsSettings4Ray wsSettings = new();
 | |
|                         wsSettings.headers = new Headers4Ray();
 | |
| 
 | |
|                         if (Utils.IsNotEmpty(host))
 | |
|                         {
 | |
|                             wsSettings.host = host;
 | |
|                             wsSettings.headers.Host = host;
 | |
|                         }
 | |
|                         if (Utils.IsNotEmpty(path))
 | |
|                         {
 | |
|                             wsSettings.path = path;
 | |
|                         }
 | |
|                         if (Utils.IsNotEmpty(useragent))
 | |
|                         {
 | |
|                             wsSettings.headers.UserAgent = useragent;
 | |
|                         }
 | |
|                         streamSettings.wsSettings = wsSettings;
 | |
| 
 | |
|                         break;
 | |
|                     //httpupgrade
 | |
|                     case nameof(ETransport.httpupgrade):
 | |
|                         HttpupgradeSettings4Ray httpupgradeSettings = new();
 | |
| 
 | |
|                         if (Utils.IsNotEmpty(path))
 | |
|                         {
 | |
|                             httpupgradeSettings.path = path;
 | |
|                         }
 | |
|                         if (Utils.IsNotEmpty(host))
 | |
|                         {
 | |
|                             httpupgradeSettings.host = host;
 | |
|                         }
 | |
|                         streamSettings.httpupgradeSettings = httpupgradeSettings;
 | |
| 
 | |
|                         break;
 | |
|                     //xhttp
 | |
|                     case nameof(ETransport.xhttp):
 | |
|                         streamSettings.network = ETransport.xhttp.ToString();
 | |
|                         XhttpSettings4Ray xhttpSettings = new();
 | |
| 
 | |
|                         if (Utils.IsNotEmpty(path))
 | |
|                         {
 | |
|                             xhttpSettings.path = path;
 | |
|                         }
 | |
|                         if (Utils.IsNotEmpty(host))
 | |
|                         {
 | |
|                             xhttpSettings.host = host;
 | |
|                         }
 | |
|                         if (Utils.IsNotEmpty(node.HeaderType) && Global.XhttpMode.Contains(node.HeaderType))
 | |
|                         {
 | |
|                             xhttpSettings.mode = node.HeaderType;
 | |
|                         }
 | |
|                         if (Utils.IsNotEmpty(node.Extra))
 | |
|                         {
 | |
|                             xhttpSettings.extra = JsonUtils.ParseJson(node.Extra);
 | |
|                         }
 | |
| 
 | |
|                         streamSettings.xhttpSettings = xhttpSettings;
 | |
|                         await GenOutboundMux(node, outbound);
 | |
| 
 | |
|                         break;
 | |
|                     //h2
 | |
|                     case nameof(ETransport.h2):
 | |
|                         HttpSettings4Ray httpSettings = new();
 | |
| 
 | |
|                         if (Utils.IsNotEmpty(host))
 | |
|                         {
 | |
|                             httpSettings.host = Utils.String2List(host);
 | |
|                         }
 | |
|                         httpSettings.path = path;
 | |
| 
 | |
|                         streamSettings.httpSettings = httpSettings;
 | |
| 
 | |
|                         break;
 | |
|                     //quic
 | |
|                     case nameof(ETransport.quic):
 | |
|                         QuicSettings4Ray quicsettings = new()
 | |
|                         {
 | |
|                             security = host,
 | |
|                             key = path,
 | |
|                             header = new Header4Ray
 | |
|                             {
 | |
|                                 type = node.HeaderType
 | |
|                             }
 | |
|                         };
 | |
|                         streamSettings.quicSettings = quicsettings;
 | |
|                         if (node.StreamSecurity == Global.StreamSecurity)
 | |
|                         {
 | |
|                             if (Utils.IsNotEmpty(sni))
 | |
|                             {
 | |
|                                 streamSettings.tlsSettings.serverName = sni;
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 streamSettings.tlsSettings.serverName = node.Address;
 | |
|                             }
 | |
|                         }
 | |
|                         break;
 | |
| 
 | |
|                     case nameof(ETransport.grpc):
 | |
|                         GrpcSettings4Ray grpcSettings = new()
 | |
|                         {
 | |
|                             authority = Utils.IsNullOrEmpty(host) ? null : host,
 | |
|                             serviceName = path,
 | |
|                             multiMode = node.HeaderType == Global.GrpcMultiMode,
 | |
|                             idle_timeout = _config.GrpcItem.IdleTimeout,
 | |
|                             health_check_timeout = _config.GrpcItem.HealthCheckTimeout,
 | |
|                             permit_without_stream = _config.GrpcItem.PermitWithoutStream,
 | |
|                             initial_windows_size = _config.GrpcItem.InitialWindowsSize,
 | |
|                         };
 | |
|                         streamSettings.grpcSettings = grpcSettings;
 | |
|                         break;
 | |
| 
 | |
|                     default:
 | |
|                         //tcp
 | |
|                         if (node.HeaderType == Global.TcpHeaderHttp)
 | |
|                         {
 | |
|                             TcpSettings4Ray tcpSettings = new()
 | |
|                             {
 | |
|                                 header = new Header4Ray
 | |
|                                 {
 | |
|                                     type = node.HeaderType
 | |
|                                 }
 | |
|                             };
 | |
| 
 | |
|                             //request Host
 | |
|                             string request = EmbedUtils.GetEmbedText(Global.V2raySampleHttpRequestFileName);
 | |
|                             string[] arrHost = host.Split(',');
 | |
|                             string host2 = string.Join(",".AppendQuotes(), arrHost);
 | |
|                             request = request.Replace("$requestHost$", $"{host2.AppendQuotes()}");
 | |
|                             request = request.Replace("$requestUserAgent$", $"{useragent.AppendQuotes()}");
 | |
|                             //Path
 | |
|                             string pathHttp = @"/";
 | |
|                             if (Utils.IsNotEmpty(path))
 | |
|                             {
 | |
|                                 string[] arrPath = path.Split(',');
 | |
|                                 pathHttp = string.Join(",".AppendQuotes(), arrPath);
 | |
|                             }
 | |
|                             request = request.Replace("$requestPath$", $"{pathHttp.AppendQuotes()}");
 | |
|                             tcpSettings.header.request = JsonUtils.Deserialize<object>(request);
 | |
| 
 | |
|                             streamSettings.tcpSettings = tcpSettings;
 | |
|                         }
 | |
|                         break;
 | |
|                 }
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 Logging.SaveLog(_tag, ex);
 | |
|             }
 | |
|             return 0;
 | |
|         }
 | |
| 
 | |
|         private async Task<int> GenDns(ProfileItem? node, V2rayConfig v2rayConfig)
 | |
|         {
 | |
|             try
 | |
|             {
 | |
|                 var item = await AppHandler.Instance.GetDNSItem(ECoreType.Xray);
 | |
|                 var normalDNS = item?.NormalDNS;
 | |
|                 var domainStrategy4Freedom = item?.DomainStrategy4Freedom;
 | |
|                 if (Utils.IsNullOrEmpty(normalDNS))
 | |
|                 {
 | |
|                     normalDNS = EmbedUtils.GetEmbedText(Global.DNSV2rayNormalFileName);
 | |
|                 }
 | |
| 
 | |
|                 //Outbound Freedom domainStrategy
 | |
|                 if (Utils.IsNotEmpty(domainStrategy4Freedom))
 | |
|                 {
 | |
|                     var outbound = v2rayConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
 | |
|                     if (outbound != null)
 | |
|                     {
 | |
|                         outbound.settings = new();
 | |
|                         outbound.settings.domainStrategy = domainStrategy4Freedom;
 | |
|                         outbound.settings.userLevel = 0;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 var obj = JsonUtils.ParseJson(normalDNS);
 | |
|                 if (obj is null)
 | |
|                 {
 | |
|                     List<string> servers = [];
 | |
|                     string[] arrDNS = normalDNS.Split(',');
 | |
|                     foreach (string str in arrDNS)
 | |
|                     {
 | |
|                         servers.Add(str);
 | |
|                     }
 | |
|                     obj = JsonUtils.ParseJson("{}");
 | |
|                     obj["servers"] = JsonUtils.SerializeToNode(servers);
 | |
|                 }
 | |
| 
 | |
|                 // 追加至 dns 设置
 | |
|                 if (item.UseSystemHosts)
 | |
|                 {
 | |
|                     var systemHosts = Utils.GetSystemHosts();
 | |
|                     if (systemHosts.Count > 0)
 | |
|                     {
 | |
|                         var normalHost = obj["hosts"];
 | |
|                         if (normalHost != null)
 | |
|                         {
 | |
|                             foreach (var host in systemHosts)
 | |
|                             {
 | |
|                                 if (normalHost[host.Key] != null)
 | |
|                                     continue;
 | |
|                                 normalHost[host.Key] = host.Value;
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 await GenDnsDomains(node, obj, item);
 | |
| 
 | |
|                 v2rayConfig.dns = obj;
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 Logging.SaveLog(_tag, ex);
 | |
|             }
 | |
|             return 0;
 | |
|         }
 | |
| 
 | |
|         private async Task<int> GenDnsDomains(ProfileItem? node, JsonNode dns, DNSItem? dNSItem)
 | |
|         {
 | |
|             if (node == null)
 | |
|             { return 0; }
 | |
|             var servers = dns["servers"];
 | |
|             if (servers != null)
 | |
|             {
 | |
|                 if (Utils.IsDomain(node.Address))
 | |
|                 {
 | |
|                     var dnsServer = new DnsServer4Ray()
 | |
|                     {
 | |
|                         address = Utils.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.DomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress,
 | |
|                         domains = [node.Address]
 | |
|                     };
 | |
|                     servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer));
 | |
|                 }
 | |
|             }
 | |
|             return await Task.FromResult(0);
 | |
|         }
 | |
| 
 | |
|         private async Task<int> GenStatistic(V2rayConfig v2rayConfig)
 | |
|         {
 | |
|             if (_config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed)
 | |
|             {
 | |
|                 string tag = EInboundProtocol.api.ToString();
 | |
|                 Metrics4Ray apiObj = new();
 | |
|                 Policy4Ray policyObj = new();
 | |
|                 SystemPolicy4Ray policySystemSetting = new();
 | |
| 
 | |
|                 v2rayConfig.stats = new Stats4Ray();
 | |
| 
 | |
|                 apiObj.tag = tag;
 | |
|                 v2rayConfig.metrics = apiObj;
 | |
| 
 | |
|                 policySystemSetting.statsOutboundDownlink = true;
 | |
|                 policySystemSetting.statsOutboundUplink = true;
 | |
|                 policyObj.system = policySystemSetting;
 | |
|                 v2rayConfig.policy = policyObj;
 | |
| 
 | |
|                 if (!v2rayConfig.inbounds.Exists(item => item.tag == tag))
 | |
|                 {
 | |
|                     Inbounds4Ray apiInbound = new();
 | |
|                     Inboundsettings4Ray apiInboundSettings = new();
 | |
|                     apiInbound.tag = tag;
 | |
|                     apiInbound.listen = Global.Loopback;
 | |
|                     apiInbound.port = AppHandler.Instance.StatePort;
 | |
|                     apiInbound.protocol = Global.InboundAPIProtocol;
 | |
|                     apiInboundSettings.address = Global.Loopback;
 | |
|                     apiInbound.settings = apiInboundSettings;
 | |
|                     v2rayConfig.inbounds.Add(apiInbound);
 | |
|                 }
 | |
| 
 | |
|                 if (!v2rayConfig.routing.rules.Exists(item => item.outboundTag == tag))
 | |
|                 {
 | |
|                     RulesItem4Ray apiRoutingRule = new()
 | |
|                     {
 | |
|                         inboundTag = new List<string> { tag },
 | |
|                         outboundTag = tag,
 | |
|                         type = "field"
 | |
|                     };
 | |
| 
 | |
|                     v2rayConfig.routing.rules.Add(apiRoutingRule);
 | |
|                 }
 | |
|             }
 | |
|             return await Task.FromResult(0);
 | |
|         }
 | |
| 
 | |
|         private async Task<int> GenMoreOutbounds(ProfileItem node, V2rayConfig v2rayConfig)
 | |
|         {
 | |
|             //fragment proxy
 | |
|             if (_config.CoreBasicItem.EnableFragment
 | |
|                 && Utils.IsNotEmpty(v2rayConfig.outbounds.First().streamSettings?.security))
 | |
|             {
 | |
|                 var fragmentOutbound = new Outbounds4Ray
 | |
|                 {
 | |
|                     protocol = "freedom",
 | |
|                     tag = $"{Global.ProxyTag}3",
 | |
|                     settings = new()
 | |
|                     {
 | |
|                         fragment = new()
 | |
|                         {
 | |
|                             packets = _config.Fragment4RayItem?.Packets,
 | |
|                             length = _config.Fragment4RayItem?.Length,
 | |
|                             interval = _config.Fragment4RayItem?.Interval
 | |
|                         }
 | |
|                     }
 | |
|                 };
 | |
| 
 | |
|                 v2rayConfig.outbounds.Add(fragmentOutbound);
 | |
|                 v2rayConfig.outbounds.First().streamSettings.sockopt = new()
 | |
|                 {
 | |
|                     dialerProxy = fragmentOutbound.tag
 | |
|                 };
 | |
|                 return 0;
 | |
|             }
 | |
| 
 | |
|             if (node.Subid.IsNullOrEmpty())
 | |
|             {
 | |
|                 return 0;
 | |
|             }
 | |
|             try
 | |
|             {
 | |
|                 var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
 | |
|                 if (subItem is null)
 | |
|                 {
 | |
|                     return 0;
 | |
|                 }
 | |
| 
 | |
|                 //current proxy
 | |
|                 var outbound = v2rayConfig.outbounds.First();
 | |
|                 var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
 | |
| 
 | |
|                 //Previous proxy
 | |
|                 var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
 | |
|                 if (prevNode is not null
 | |
|                     && prevNode.ConfigType != EConfigType.Custom
 | |
|                     && prevNode.ConfigType != EConfigType.Hysteria2
 | |
|                     && prevNode.ConfigType != EConfigType.TUIC
 | |
|                     && prevNode.ConfigType != EConfigType.WireGuard)
 | |
|                 {
 | |
|                     var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
 | |
|                     await GenOutbound(prevNode, prevOutbound);
 | |
|                     prevOutbound.tag = $"{Global.ProxyTag}2";
 | |
|                     v2rayConfig.outbounds.Add(prevOutbound);
 | |
| 
 | |
|                     outbound.streamSettings.sockopt = new()
 | |
|                     {
 | |
|                         dialerProxy = prevOutbound.tag
 | |
|                     };
 | |
|                 }
 | |
| 
 | |
|                 //Next proxy
 | |
|                 var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
 | |
|                 if (nextNode is not null
 | |
|                     && nextNode.ConfigType != EConfigType.Custom
 | |
|                     && nextNode.ConfigType != EConfigType.Hysteria2
 | |
|                     && nextNode.ConfigType != EConfigType.TUIC
 | |
|                     && nextNode.ConfigType != EConfigType.WireGuard)
 | |
|                 {
 | |
|                     var nextOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
 | |
|                     await GenOutbound(nextNode, nextOutbound);
 | |
|                     nextOutbound.tag = Global.ProxyTag;
 | |
|                     v2rayConfig.outbounds.Insert(0, nextOutbound);
 | |
| 
 | |
|                     outbound.tag = $"{Global.ProxyTag}1";
 | |
|                     nextOutbound.streamSettings.sockopt = new()
 | |
|                     {
 | |
|                         dialerProxy = outbound.tag
 | |
|                     };
 | |
|                 }
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 Logging.SaveLog(_tag, ex);
 | |
|             }
 | |
| 
 | |
|             return 0;
 | |
|         }
 | |
| 
 | |
|         #endregion private gen function
 | |
|     }
 | |
| }
 | 
