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 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(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 GenerateClientMultipleLoadConfig(List 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(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(); 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(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 GenerateClientSpeedtestConfig(List 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(result); if (v2rayConfig == null) { ret.Msg = ResUI.FailedGenDefaultConfiguration; return ret; } List lstIpEndPoints = new(); List 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(txtOutbound); await GenOutbound(item, outbound); outbound.tag = Global.ProxyTag + inbound.port.ToString(); v2rayConfig.outbounds.Add(outbound); //rule RulesItem4Ray rule = new() { inboundTag = new List { 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; } } #endregion public gen function #region private gen function private async Task 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 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 { 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(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 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>(routing.RuleSet); foreach (var item in rules) { if (item.Enabled) { var item2 = JsonUtils.Deserialize(JsonUtils.Serialize(item)); await GenRoutingUserRule(item2, v2rayConfig); } } } } } catch (Exception ex) { Logging.SaveLog(_tag, ex); } return 0; } private async Task 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 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() { 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 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 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 }; 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(request); streamSettings.tcpSettings = tcpSettings; } break; } } catch (Exception ex) { Logging.SaveLog(_tag, ex); } return 0; } private async Task 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 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 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 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 { tag }, outboundTag = tag, type = "field" }; v2rayConfig.routing.rules.Add(apiRoutingRule); } } return await Task.FromResult(0); } private async Task 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(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(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 } }