/// <summary> /// 添加服务器或编辑 /// </summary> /// <param name="config"></param> /// <param name="vmessItem"></param> /// <param name="index"></param> /// <returns></returns> public static int AddTrojanServer(ref Config config, VmessItem vmessItem, int index, bool toFile = true) { vmessItem.configType = (int)EConfigType.Trojan; vmessItem.address = vmessItem.address.TrimEx(); vmessItem.id = vmessItem.id.TrimEx(); if (Utils.IsNullOrEmpty(vmessItem.streamSecurity)) { vmessItem.streamSecurity = Global.StreamSecurity; } if (Utils.IsNullOrEmpty(vmessItem.allowInsecure)) { vmessItem.allowInsecure = config.defAllowInsecure.ToString(); } if (index >= 0) { //修改 config.vmess[index] = vmessItem; if (config.index.Equals(index)) { Global.reloadV2ray = true; } } else { AddServerCommon(ref config, vmessItem); } if (toFile) { ToJsonFile(config); } return(0); }
/// <summary> /// 刷新托盘服务器菜单 /// </summary> private void RefreshServersMenu() { menuServers.DropDownItems.Clear(); List <ToolStripMenuItem> lst = new List <ToolStripMenuItem>(); for (int k = 0; k < config.vmess.Count; k++) { VmessItem item = config.vmess[k]; string name = item.getSummary(); ToolStripMenuItem ts = new ToolStripMenuItem(name) { Tag = k }; if (config.index.Equals(k)) { ts.Checked = true; } ts.Click += new EventHandler(ts_Click); lst.Add(ts); } menuServers.DropDownItems.AddRange(lst.ToArray()); }
/// <summary> /// 添加服务器或编辑 /// </summary> /// <param name="config"></param> /// <param name="vmessItem"></param> /// <returns></returns> public static int AddTrojanServer(ref Config config, VmessItem vmessItem, bool toFile = true) { vmessItem.configType = EConfigType.Trojan; vmessItem.address = vmessItem.address.TrimEx(); vmessItem.id = vmessItem.id.TrimEx(); if (Utils.IsNullOrEmpty(vmessItem.streamSecurity)) { vmessItem.streamSecurity = Global.StreamSecurity; } if (Utils.IsNullOrEmpty(vmessItem.allowInsecure)) { vmessItem.allowInsecure = config.defAllowInsecure.ToString(); } AddServerCommon(ref config, vmessItem); if (toFile) { ToJsonFile(config); } return(0); }
/// <summary> /// 从剪贴板导入URL /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MenuItemImportClipboard_Click(object sender, EventArgs e) { ClearServer(); string msg; VmessItem vmessItem = V2rayConfigHandler.ImportFromClipboardConfig(Utils.GetClipboardData(), out msg); if (vmessItem == null) { UI.Show(msg); return; } txtAddress.Text = vmessItem.address; txtPort.Text = vmessItem.port.ToString(); txtId.Text = vmessItem.id; txtAlterId.Text = vmessItem.alterId.ToString(); txtRemarks.Text = vmessItem.remarks; cmbNetwork.Text = vmessItem.network; cmbHeaderType.Text = vmessItem.headerType; txtRequestHost.Text = vmessItem.requestHost; txtPath.Text = vmessItem.path; cmbStreamSecurity.Text = vmessItem.streamSecurity; }
public static int AddServerCommon(ref Config config, VmessItem vmessItem) { if (Utils.IsNullOrEmpty(vmessItem.indexId)) { vmessItem.indexId = Utils.GetGUID(false); } vmessItem.configVersion = 2; if (Utils.IsNullOrEmpty(vmessItem.allowInsecure)) { vmessItem.allowInsecure = config.defAllowInsecure.ToString(); } if (!Utils.IsNullOrEmpty(vmessItem.network) && !Global.networks.Contains(vmessItem.network)) { vmessItem.network = Global.DefaultNetwork; } config.vmess.Add(vmessItem); if (config.vmess.Count == 1) { config.index = 0; Global.reloadV2ray = true; } return(0); }
/// <summary> /// 刷新服务器列表 /// </summary> private void RefreshServersView() { lvServers.Items.Clear(); for (int k = 0; k < config.vmess.Count; k++) { string def = string.Empty; string totalUp = string.Empty, totalDown = string.Empty, todayUp = string.Empty, todayDown = string.Empty; if (config.index.Equals(k)) { def = "√"; } VmessItem item = config.vmess[k]; void _addSubItem(ListViewItem i, string name, string text) { i.SubItems.Add(new ListViewItem.ListViewSubItem() { Name = name, Text = text }); } bool stats = statistics != null && statistics.Enable; if (stats) { ServerStatItem sItem = statistics.Statistic.Find(item_ => item_.itemId == item.getItemId()); if (sItem != null) { totalUp = Utils.HumanFy(sItem.totalUp); totalDown = Utils.HumanFy(sItem.totalDown); todayUp = Utils.HumanFy(sItem.todayUp); todayDown = Utils.HumanFy(sItem.todayDown); } } ListViewItem lvItem = new ListViewItem(def); _addSubItem(lvItem, "type", ((EConfigType)item.configType).ToString()); _addSubItem(lvItem, "remarks", item.remarks); _addSubItem(lvItem, "address", item.address); _addSubItem(lvItem, "port", item.port.ToString()); //_addSubItem(lvItem, "id", item.id); //_addSubItem(lvItem, "alterId", item.alterId.ToString()); _addSubItem(lvItem, "security", item.security); _addSubItem(lvItem, "network", item.network); _addSubItem(lvItem, "SubRemarks", item.getSubRemarks(config)); _addSubItem(lvItem, "testResult", item.testResult); if (stats) { _addSubItem(lvItem, "todayDown", todayDown); _addSubItem(lvItem, "todayUp", todayUp); _addSubItem(lvItem, "totalDown", totalDown); _addSubItem(lvItem, "totalUp", totalUp); } if (k % 2 == 1) // 隔行着色 { lvItem.BackColor = Color.WhiteSmoke; } if (config.index.Equals(k)) { //lvItem.Checked = true; lvItem.ForeColor = Color.DodgerBlue; lvItem.Font = new Font(lvItem.Font, FontStyle.Bold); } if (lvItem != null) { lvServers.Items.Add(lvItem); } } //if (lvServers.Items.Count > 0) //{ // if (lvServers.Items.Count <= testConfigIndex) // { // testConfigIndex = lvServers.Items.Count - 1; // } // lvServers.Items[testConfigIndex].Selected = true; // lvServers.Select(); //} }
/// <summary> /// 移动服务器 /// </summary> /// <param name="config"></param> /// <param name="index"></param> /// <param name="eMove"></param> /// <returns></returns> public static int MoveServer(ref Config config, int index, EMove eMove) { int count = config.vmess.Count; if (index < 0 || index > config.vmess.Count - 1) { return(-1); } switch (eMove) { case EMove.Top: { if (index == 0) { return(0); } VmessItem vmess = Utils.DeepCopy <VmessItem>(config.vmess[index]); config.vmess.RemoveAt(index); config.vmess.Insert(0, vmess); if (index < config.index) { // } else if (config.index == index) { config.index = 0; } else { config.index++; } break; } case EMove.Up: { if (index == 0) { return(0); } VmessItem vmess = Utils.DeepCopy <VmessItem>(config.vmess[index]); config.vmess.RemoveAt(index); config.vmess.Insert(index - 1, vmess); if (index == config.index + 1) { config.index++; } else if (config.index == index) { config.index--; } break; } case EMove.Down: { if (index == count - 1) { return(0); } VmessItem vmess = Utils.DeepCopy <VmessItem>(config.vmess[index]); config.vmess.RemoveAt(index); config.vmess.Insert(index + 1, vmess); if (index == config.index - 1) { config.index--; } else if (config.index == index) { config.index++; } break; } case EMove.Bottom: { if (index == count - 1) { return(0); } VmessItem vmess = Utils.DeepCopy <VmessItem>(config.vmess[index]); config.vmess.RemoveAt(index); config.vmess.Add(vmess); if (index < config.index) { config.index--; } else if (config.index == index) { config.index = count - 1; } else { // } break; } } Global.reloadV2ray = true; ToJsonFile(config); return(0); }
/// <summary> /// 载入配置文件 /// </summary> /// <param name="config"></param> /// <returns></returns> public static int LoadConfig(ref Config config) { //载入配置文件 string result = Utils.LoadResource(Utils.GetPath(configRes)); if (!Utils.IsNullOrEmpty(result)) { //转成Json config = Utils.FromJson <Config>(result); } if (config == null) { config = new Config(); config.index = -1; config.logEnabled = false; config.loglevel = "warning"; config.vmess = new List <VmessItem>(); //Mux config.muxEnabled = true; ////默认监听端口 //config.pacPort = 8888; // 默认缓存七天 config.CacheDays = 7; // 默认不开启统计 config.enableStatistics = false; // 默认中等刷新率 config.statisticsFreshRate = (int)Global.StatisticsFreshRate.medium; } //本地监听 if (config.inbound == null) { config.inbound = new List <InItem>(); InItem inItem = new InItem(); inItem.protocol = "socks"; inItem.localPort = 10808; inItem.udpEnabled = true; inItem.sniffingEnabled = true; config.inbound.Add(inItem); //inItem = new InItem(); //inItem.protocol = "http"; //inItem.localPort = 1081; //inItem.udpEnabled = true; //config.inbound.Add(inItem); } else { //http协议不由core提供,只保留socks if (config.inbound.Count > 0) { config.inbound[0].protocol = "socks"; } } //路由规则 if (Utils.IsNullOrEmpty(config.domainStrategy)) { config.domainStrategy = "IPIfNonMatch"; } if (Utils.IsNullOrEmpty(config.routingMode)) { config.routingMode = "0"; } if (config.useragent == null) { config.useragent = new List <string>(); } if (config.userdirect == null) { config.userdirect = new List <string>(); } if (config.userblock == null) { config.userblock = new List <string>(); } //kcp if (config.kcpItem == null) { config.kcpItem = new KcpItem(); config.kcpItem.mtu = 1350; config.kcpItem.tti = 50; config.kcpItem.uplinkCapacity = 12; config.kcpItem.downlinkCapacity = 100; config.kcpItem.readBufferSize = 2; config.kcpItem.writeBufferSize = 2; config.kcpItem.congestion = false; } if (config.uiItem == null) { config.uiItem = new UIItem(); } //// 如果是用户升级,首次会有端口号为0的情况,不可用,这里处理 //if (config.pacPort == 0) //{ // config.pacPort = 8888; //} if (config.subItem == null) { config.subItem = new List <SubItem>(); } if (config == null || config.index < 0 || config.vmess.Count <= 0 || config.index > config.vmess.Count - 1 ) { Global.reloadV2ray = false; } else { Global.reloadV2ray = true; //版本升级 for (int i = 0; i < config.vmess.Count; i++) { VmessItem vmessItem = config.vmess[i]; UpgradeServerVersion(ref vmessItem); } } return(0); }
/// <summary> /// 从剪贴板导入URL /// </summary> /// <param name="fileName"></param> /// <param name="msg"></param> /// <returns></returns> public static VmessItem ImportFromClipboardConfig(string clipboardData, out string msg) { msg = string.Empty; VmessItem vmessItem = new VmessItem(); try { //载入配置文件 string result = clipboardData.Trim();// Utils.GetClipboardData(); if (Utils.IsNullOrEmpty(result)) { msg = "读取配置文件失败"; return(null); } if (result.StartsWith(Global.vmessProtocol)) { int indexSplit = result.IndexOf("?"); if (indexSplit > 0) { vmessItem = ResolveVmess4Kitsunebi(result); } else { vmessItem.configType = (int)EConfigType.Vmess; result = result.Substring(Global.vmessProtocol.Length); result = Utils.Base64Decode(result); //转成Json VmessQRCode vmessQRCode = Utils.FromJson <VmessQRCode>(result); if (vmessQRCode == null) { msg = "转换配置文件失败"; return(null); } vmessItem.security = Global.DefaultSecurity; vmessItem.network = Global.DefaultNetwork; vmessItem.headerType = Global.None; vmessItem.configVersion = Utils.ToInt(vmessQRCode.v); vmessItem.remarks = vmessQRCode.ps; vmessItem.address = vmessQRCode.add; vmessItem.port = Utils.ToInt(vmessQRCode.port); vmessItem.id = vmessQRCode.id; vmessItem.alterId = Utils.ToInt(vmessQRCode.aid); vmessItem.network = vmessQRCode.net; vmessItem.headerType = vmessQRCode.type; vmessItem.requestHost = vmessQRCode.host; vmessItem.path = vmessQRCode.path; vmessItem.streamSecurity = vmessQRCode.tls; } ConfigHandler.UpgradeServerVersion(ref vmessItem); } else if (result.StartsWith(Global.ssProtocol)) { msg = "配置格式不正确"; vmessItem.configType = (int)EConfigType.Shadowsocks; result = result.Substring(Global.ssProtocol.Length); //remark int indexRemark = result.IndexOf("#"); if (indexRemark > 0) { try { vmessItem.remarks = WebUtility.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1)); } catch { } result = result.Substring(0, indexRemark); } //part decode int indexS = result.IndexOf("@"); if (indexS > 0) { result = Utils.Base64Decode(result.Substring(0, indexS)) + result.Substring(indexS, result.Length - indexS); } else { result = Utils.Base64Decode(result); } string[] arr1 = result.Split('@'); if (arr1.Length != 2) { return(null); } string[] arr21 = arr1[0].Split(':'); string[] arr22 = arr1[1].Split(':'); if (arr21.Length != 2 || arr21.Length != 2) { return(null); } vmessItem.address = arr22[0]; vmessItem.port = Utils.ToInt(arr22[1]); vmessItem.security = arr21[0]; vmessItem.id = arr21[1]; } else { msg = "非vmess或ss协议"; return(null); } } catch { msg = "异常,不是正确的配置,请检查"; return(null); } return(vmessItem); }
/// <summary> /// 批量添加服务器 /// </summary> /// <param name="config"></param> /// <param name="clipboardData"></param> /// <param name="subid"></param> /// <returns>成功导入的数量</returns> private static int AddBatchServers(ref Config config, string clipboardData, string subid, List <VmessItem> lstOriSub, string groupId) { if (Utils.IsNullOrEmpty(clipboardData)) { return(-1); } //copy sub items if (!Utils.IsNullOrEmpty(subid)) { RemoveServerViaSubid(ref config, subid); } //if (clipboardData.IndexOf("vmess") >= 0 && clipboardData.IndexOf("vmess") == clipboardData.LastIndexOf("vmess")) //{ // clipboardData = clipboardData.Replace("\r\n", "").Replace("\n", ""); //} int countServers = 0; //string[] arrData = clipboardData.Split(new string[] { "\r\n" }, StringSplitOptions.None); string[] arrData = clipboardData.Split(Environment.NewLine.ToCharArray()); foreach (string str in arrData) { //maybe sub if (Utils.IsNullOrEmpty(subid) && (str.StartsWith(Global.httpsProtocol) || str.StartsWith(Global.httpProtocol))) { if (AddSubItem(ref config, str) == 0) { countServers++; } continue; } VmessItem vmessItem = ShareHandler.ImportFromClipboardConfig(str, out string msg); if (vmessItem == null) { continue; } //exist sub items if (!Utils.IsNullOrEmpty(subid)) { var existItem = lstOriSub?.FirstOrDefault(t => CompareVmessItem(t, vmessItem, true)); if (existItem != null) { vmessItem = existItem; } vmessItem.subid = subid; } //groupId vmessItem.groupId = groupId; if (vmessItem.configType == EConfigType.Vmess) { if (AddServer(ref config, vmessItem, false) == 0) { countServers++; } } else if (vmessItem.configType == EConfigType.Shadowsocks) { if (AddShadowsocksServer(ref config, vmessItem, false) == 0) { countServers++; } } else if (vmessItem.configType == EConfigType.Socks) { if (AddSocksServer(ref config, vmessItem, false) == 0) { countServers++; } } else if (vmessItem.configType == EConfigType.Trojan) { if (AddTrojanServer(ref config, vmessItem, false) == 0) { countServers++; } } else if (vmessItem.configType == EConfigType.VLESS) { if (AddVlessServer(ref config, vmessItem, false) == 0) { countServers++; } } } ToJsonFile(config); return(countServers); }
/// <summary> /// 载入配置文件 /// </summary> /// <param name="config"></param> /// <returns></returns> public static int LoadConfig(ref Config config) { //载入配置文件 string result = Utils.LoadResource(Utils.GetPath(configRes)); if (!Utils.IsNullOrEmpty(result)) { //转成Json config = Utils.FromJson <Config>(result); } else { if (File.Exists(Utils.GetPath(configRes))) { Utils.SaveLog("LoadConfig Exception"); return(-1); } } if (config == null) { config = new Config { logEnabled = false, loglevel = "warning", vmess = new List <VmessItem>(), //Mux muxEnabled = false, // 默认不开启统计 enableStatistics = false, // 默认中等刷新率 statisticsFreshRate = (int)Global.StatisticsFreshRate.medium, enableRoutingAdvanced = true }; } //本地监听 if (config.inbound == null) { config.inbound = new List <InItem>(); InItem inItem = new InItem { protocol = Global.InboundSocks, localPort = 10808, udpEnabled = true, sniffingEnabled = true }; config.inbound.Add(inItem); //inItem = new InItem(); //inItem.protocol = "http"; //inItem.localPort = 1081; //inItem.udpEnabled = true; //config.inbound.Add(inItem); } else { if (config.inbound.Count > 0) { config.inbound[0].protocol = Global.InboundSocks; } } //路由规则 if (Utils.IsNullOrEmpty(config.domainStrategy)) { config.domainStrategy = "IPIfNonMatch"; } if (Utils.IsNullOrEmpty(config.domainMatcher)) { config.domainMatcher = "linear"; } //kcp if (config.kcpItem == null) { config.kcpItem = new KcpItem { mtu = 1350, tti = 50, uplinkCapacity = 12, downlinkCapacity = 100, readBufferSize = 2, writeBufferSize = 2, congestion = false }; } if (config.uiItem == null) { config.uiItem = new UIItem() { enableAutoAdjustMainLvColWidth = true }; } if (config.uiItem.mainLvColWidth == null) { config.uiItem.mainLvColWidth = new Dictionary <string, int>(); } if (config.constItem == null) { config.constItem = new ConstItem(); } if (Utils.IsNullOrEmpty(config.constItem.speedTestUrl)) { config.constItem.speedTestUrl = Global.SpeedTestUrl; } if (Utils.IsNullOrEmpty(config.constItem.speedPingTestUrl)) { config.constItem.speedPingTestUrl = Global.SpeedPingTestUrl; } if (Utils.IsNullOrEmpty(config.constItem.defIEProxyExceptions)) { config.constItem.defIEProxyExceptions = Global.IEProxyExceptions; } //if (Utils.IsNullOrEmpty(config.remoteDNS)) //{ // config.remoteDNS = "1.1.1.1"; //} if (config.subItem == null) { config.subItem = new List <SubItem>(); } if (config.groupItem == null) { config.groupItem = new List <GroupItem>(); } if (config == null || config.vmess.Count <= 0 ) { Global.reloadV2ray = false; } else { Global.reloadV2ray = true; //版本升级 for (int i = 0; i < config.vmess.Count; i++) { VmessItem vmessItem = config.vmess[i]; UpgradeServerVersion(ref vmessItem); if (Utils.IsNullOrEmpty(vmessItem.indexId)) { vmessItem.indexId = Utils.GetGUID(false); } } } LazyConfig.Instance.SetConfig(ref config); return(0); }
/// <summary> /// GetShareUrl /// </summary> /// <param name="config"></param> /// <param name="index"></param> /// <returns></returns> public static string GetShareUrl(Config config, int index) { try { string url = string.Empty; VmessItem item = config.vmess[index]; if (item.configType == (int)EConfigType.Vmess) { VmessQRCode vmessQRCode = new VmessQRCode { v = item.configVersion.ToString(), ps = item.remarks.TrimEx(), //备注也许很长 ; add = item.address, port = item.port.ToString(), id = item.id, aid = item.alterId.ToString(), net = item.network, type = item.headerType, host = item.requestHost, path = item.path, tls = item.streamSecurity, sni = item.sni }; url = Utils.ToJson(vmessQRCode); url = Utils.Base64Encode(url); url = string.Format("{0}{1}", Global.vmessProtocol, url); } else if (item.configType == (int)EConfigType.Shadowsocks) { string remark = string.Empty; if (!Utils.IsNullOrEmpty(item.remarks)) { remark = "#" + Utils.UrlEncode(item.remarks); } url = string.Format("{0}:{1}@{2}:{3}", item.security, item.id, item.address, item.port); url = Utils.Base64Encode(url); url = string.Format("{0}{1}{2}", Global.ssProtocol, url, remark); } else if (item.configType == (int)EConfigType.Socks) { string remark = string.Empty; if (!Utils.IsNullOrEmpty(item.remarks)) { remark = "#" + Utils.UrlEncode(item.remarks); } url = string.Format("{0}:{1}@{2}:{3}", item.security, item.id, item.address, item.port); url = Utils.Base64Encode(url); url = string.Format("{0}{1}{2}", Global.socksProtocol, url, remark); } else if (item.configType == (int)EConfigType.Trojan) { string remark = string.Empty; if (!Utils.IsNullOrEmpty(item.remarks)) { remark = "#" + Utils.UrlEncode(item.remarks); } string query = string.Empty; if (!Utils.IsNullOrEmpty(item.sni)) { query = string.Format("?sni={0}", Utils.UrlEncode(item.sni)); } url = string.Format("{0}@{1}:{2}", item.id, GetIpv6(item.address), item.port); url = string.Format("{0}{1}{2}{3}", Global.trojanProtocol, url, query, remark); } else if (item.configType == (int)EConfigType.VLESS) { string remark = string.Empty; if (!Utils.IsNullOrEmpty(item.remarks)) { remark = "#" + Utils.UrlEncode(item.remarks); } var dicQuery = new Dictionary <string, string>(); if (!Utils.IsNullOrEmpty(item.flow)) { dicQuery.Add("flow", item.flow); } if (!Utils.IsNullOrEmpty(item.security)) { dicQuery.Add("encryption", item.security); } else { dicQuery.Add("encryption", "none"); } if (!Utils.IsNullOrEmpty(item.streamSecurity)) { dicQuery.Add("security", item.streamSecurity); } else { dicQuery.Add("security", "none"); } if (!Utils.IsNullOrEmpty(item.sni)) { dicQuery.Add("sni", item.sni); } if (!Utils.IsNullOrEmpty(item.network)) { dicQuery.Add("type", item.network); } else { dicQuery.Add("type", "tcp"); } switch (item.network) { case "tcp": if (!Utils.IsNullOrEmpty(item.headerType)) { dicQuery.Add("headerType", item.headerType); } else { dicQuery.Add("headerType", "none"); } if (!Utils.IsNullOrEmpty(item.requestHost)) { dicQuery.Add("host", Utils.UrlEncode(item.requestHost)); } break; case "kcp": if (!Utils.IsNullOrEmpty(item.headerType)) { dicQuery.Add("headerType", item.headerType); } else { dicQuery.Add("headerType", "none"); } if (!Utils.IsNullOrEmpty(item.path)) { dicQuery.Add("seed", Utils.UrlEncode(item.path)); } break; case "ws": if (!Utils.IsNullOrEmpty(item.requestHost)) { dicQuery.Add("host", Utils.UrlEncode(item.requestHost)); } if (!Utils.IsNullOrEmpty(item.path)) { dicQuery.Add("path", Utils.UrlEncode(item.path)); } break; case "http": case "h2": dicQuery["type"] = "http"; if (!Utils.IsNullOrEmpty(item.requestHost)) { dicQuery.Add("host", Utils.UrlEncode(item.requestHost)); } if (!Utils.IsNullOrEmpty(item.path)) { dicQuery.Add("path", Utils.UrlEncode(item.path)); } break; case "quic": if (!Utils.IsNullOrEmpty(item.headerType)) { dicQuery.Add("headerType", item.headerType); } else { dicQuery.Add("headerType", "none"); } dicQuery.Add("quicSecurity", Utils.UrlEncode(item.requestHost)); dicQuery.Add("key", Utils.UrlEncode(item.path)); break; } string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()); url = string.Format("{0}@{1}:{2}", item.id, GetIpv6(item.address), item.port); url = string.Format("{0}{1}{2}{3}", Global.vlessProtocol, url, query, remark); } else { } return(url); } catch { return(""); } }
/// <summary> /// 取得服务器QRCode配置 /// </summary> /// <param name="config"></param> /// <param name="index"></param> /// <returns></returns> public static string GetVmessQRCode(Config config, int index) { try { string url = string.Empty; VmessItem vmessItem = config.vmess[index]; if (vmessItem.configType == (int)EConfigType.Vmess) { VmessQRCode vmessQRCode = new VmessQRCode { v = vmessItem.configVersion.ToString(), ps = vmessItem.remarks.TrimEx(), //备注也许很长 ; add = vmessItem.address, port = vmessItem.port.ToString(), id = vmessItem.id, aid = vmessItem.alterId.ToString(), net = vmessItem.network, type = vmessItem.headerType, host = vmessItem.requestHost, path = vmessItem.path, tls = vmessItem.streamSecurity }; url = Utils.ToJson(vmessQRCode); url = Utils.Base64Encode(url); url = string.Format("{0}{1}", Global.vmessProtocol, url); } else if (vmessItem.configType == (int)EConfigType.Shadowsocks) { string remark = string.Empty; if (!Utils.IsNullOrEmpty(vmessItem.remarks)) { remark = "#" + WebUtility.UrlEncode(vmessItem.remarks); } url = string.Format("{0}:{1}@{2}:{3}", vmessItem.security, vmessItem.id, vmessItem.address, vmessItem.port); url = Utils.Base64Encode(url); url = string.Format("{0}{1}{2}", Global.ssProtocol, url, remark); } else if (vmessItem.configType == (int)EConfigType.Socks) { string remark = string.Empty; if (!Utils.IsNullOrEmpty(vmessItem.remarks)) { remark = "#" + WebUtility.UrlEncode(vmessItem.remarks); } url = string.Format("{0}:{1}@{2}:{3}", vmessItem.security, vmessItem.id, vmessItem.address, vmessItem.port); url = Utils.Base64Encode(url); url = string.Format("{0}{1}{2}", Global.socksProtocol, url, remark); } else if (vmessItem.configType == (int)EConfigType.Trojan) { string remark = string.Empty; if (!Utils.IsNullOrEmpty(vmessItem.remarks)) { remark = "#" + WebUtility.UrlEncode(vmessItem.remarks); } string query = string.Empty; if (!Utils.IsNullOrEmpty(vmessItem.requestHost)) { query = string.Format("?sni={0}", vmessItem.requestHost); } url = string.Format("{0}@{1}:{2}", vmessItem.id, vmessItem.address, vmessItem.port); url = string.Format("{0}{1}{2}{3}", Global.trojanProtocol, url, query, remark); } else { } return(url); } catch { return(""); } }
/// <summary> /// 刷新服务器列表 /// </summary> private void RefreshServersView() { lvServers.Items.Clear(); for (int k = 0; k < config.vmess.Count; k++) { string def = string.Empty; string totalUp = string.Empty, totalDown = string.Empty, todayUp = string.Empty, todayDown = string.Empty; if (config.index.Equals(k)) { def = "√"; } VmessItem item = config.vmess[k]; ListViewItem lvItem = null; if (statistics != null && statistics.Enable) { var index = statistics.Statistic.FindIndex(item_ => item_.address == item.address); if (index != -1) { Func <ulong, string> human_fy = (amount) => { double result; string unit; Utils.ToHumanReadable(amount, out result, out unit); return($"{string.Format("{0:f2}", result)}{unit}"); }; totalUp = human_fy(statistics.Statistic[index].totalUp); totalDown = human_fy(statistics.Statistic[index].totalDown); todayUp = human_fy(statistics.Statistic[index].todayUp); todayDown = human_fy(statistics.Statistic[index].todayDown); } lvItem = new ListViewItem(new string[] { def, ((EConfigType)item.configType).ToString(), item.remarks, item.address, item.port.ToString(), //item.id, //item.alterId.ToString(), item.security, item.network, totalUp, totalDown, todayUp, todayDown, item.getSubRemarks(config), item.testResult }); } else { lvItem = new ListViewItem(new string[] { def, ((EConfigType)item.configType).ToString(), item.remarks, item.address, item.port.ToString(), //item.id, //item.alterId.ToString(), item.security, item.network, //totalUp, //totalDown, //todayUp, //todayDown, item.getSubRemarks(config), item.testResult }); } if (lvItem != null) { lvServers.Items.Add(lvItem); } } //if (lvServers.Items.Count > 0) //{ // if (lvServers.Items.Count <= testConfigIndex) // { // testConfigIndex = lvServers.Items.Count - 1; // } // lvServers.Items[testConfigIndex].Selected = true; // lvServers.Select(); //} }
private static VmessItem ResolveSip002(string result) { Uri parsedUrl; try { parsedUrl = new Uri(result); } catch (UriFormatException) { return(null); } VmessItem server = new VmessItem { remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped), address = parsedUrl.IdnHost, port = parsedUrl.Port, }; string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped); //2022-blake3 if (rawUserInfo.Contains(":")) { string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2); if (userInfoParts.Length != 2) { return(null); } server.security = userInfoParts[0]; server.id = Utils.UrlDecode(userInfoParts[1]); } else { // parse base64 UserInfo string userInfo = Utils.Base64Decode(rawUserInfo); string[] userInfoParts = userInfo.Split(new[] { ':' }, 2); if (userInfoParts.Length != 2) { return(null); } server.security = userInfoParts[0]; server.id = userInfoParts[1]; } NameValueCollection queryParameters = HttpUtility.ParseQueryString(parsedUrl.Query); if (queryParameters["plugin"] != null) { //obfs-host exists var obfsHost = queryParameters["plugin"].Split(';').FirstOrDefault(t => t.Contains("obfs-host")); if (queryParameters["plugin"].Contains("obfs=http") && !Utils.IsNullOrEmpty(obfsHost)) { obfsHost = obfsHost.Replace("obfs-host=", ""); server.network = Global.DefaultNetwork; server.headerType = Global.TcpHeaderHttp; server.requestHost = obfsHost; } else { return(null); } } return(server); }
/// <summary> /// 载入配置文件 /// </summary> /// <param name="config"></param> /// <returns></returns> public static int LoadConfig(ref Config config) { //载入配置文件 string result = Utils.LoadResource(Utils.GetPath(configRes)); if (!Utils.IsNullOrEmpty(result)) { //转成Json config = Utils.FromJson <Config>(result); } if (config == null) { config = new Config { index = -1, logEnabled = false, loglevel = "warning", vmess = new List <VmessItem>(), //Mux muxEnabled = true, ////默认监听端口 //config.pacPort = 8888; // 默认不开启统计 enableStatistics = false, // 默认中等刷新率 statisticsFreshRate = (int)Global.StatisticsFreshRate.medium }; } //本地监听 if (config.inbound == null) { config.inbound = new List <InItem>(); InItem inItem = new InItem { protocol = Global.InboundSocks, localPort = 10808, udpEnabled = true, sniffingEnabled = true }; config.inbound.Add(inItem); //inItem = new InItem(); //inItem.protocol = "http"; //inItem.localPort = 1081; //inItem.udpEnabled = true; //config.inbound.Add(inItem); } else { //http协议不由core提供,只保留socks if (config.inbound.Count > 0) { config.inbound[0].protocol = Global.InboundSocks; } } //路由规则 if (Utils.IsNullOrEmpty(config.domainStrategy)) { config.domainStrategy = "IPIfNonMatch"; } if (Utils.IsNullOrEmpty(config.routingMode)) { config.routingMode = "0"; } if (config.useragent == null) { config.useragent = new List <string>(); } if (config.userdirect == null) { config.userdirect = new List <string>(); } if (config.userblock == null) { config.userblock = new List <string>(); } //kcp if (config.kcpItem == null) { config.kcpItem = new KcpItem { mtu = 1350, tti = 50, uplinkCapacity = 12, downlinkCapacity = 100, readBufferSize = 2, writeBufferSize = 2, congestion = false }; } if (config.uiItem == null) { config.uiItem = new UIItem(); } if (config.uiItem.mainLvColWidth == null) { config.uiItem.mainLvColWidth = new Dictionary <string, int>(); } //// 如果是用户升级,首次会有端口号为0的情况,不可用,这里处理 //if (config.pacPort == 0) //{ // config.pacPort = 8888; //} if (Utils.IsNullOrEmpty(config.speedTestUrl)) { config.speedTestUrl = Global.SpeedTestUrl; } if (Utils.IsNullOrEmpty(config.speedPingTestUrl)) { config.speedPingTestUrl = Global.SpeedPingTestUrl; } if (Utils.IsNullOrEmpty(config.urlGFWList)) { config.urlGFWList = Global.GFWLIST_URL; } //if (Utils.IsNullOrEmpty(config.remoteDNS)) //{ // config.remoteDNS = "1.1.1.1"; //} if (Utils.IsNullOrEmpty(config.defaultAllowInsecure)) { config.defaultAllowInsecure = "false"; } if (config.subItem == null) { config.subItem = new List <SubItem>(); } if (config.userPacRule == null) { config.userPacRule = new List <string>(); } if (config == null || config.index < 0 || config.vmess.Count <= 0 || config.index > config.vmess.Count - 1 ) { Global.reloadV2ray = false; } else { Global.reloadV2ray = true; //版本升级 for (int i = 0; i < config.vmess.Count; i++) { VmessItem vmessItem = config.vmess[i]; UpgradeServerVersion(ref vmessItem); } } return(0); }
/// <summary> /// 批量添加服务器 /// </summary> /// <param name="config"></param> /// <param name="clipboardData"></param> /// <param name="subid"></param> /// <returns>成功导入的数量</returns> public static int AddBatchServers(ref Config config, string clipboardData, string subid = "") { if (Utils.IsNullOrEmpty(clipboardData)) { return(-1); } //if (clipboardData.IndexOf("vmess") >= 0 && clipboardData.IndexOf("vmess") == clipboardData.LastIndexOf("vmess")) //{ // clipboardData = clipboardData.Replace("\r\n", "").Replace("\n", ""); //} int countServers = 0; //string[] arrData = clipboardData.Split(new string[] { "\r\n" }, StringSplitOptions.None); string[] arrData = clipboardData.Split(Environment.NewLine.ToCharArray()); foreach (string str in arrData) { //maybe sub if (str.StartsWith(Global.httpsProtocol) || str.StartsWith(Global.httpProtocol)) { if (AddSubItem(ref config, str) == 0) { countServers++; } continue; } VmessItem vmessItem = ShareHandler.ImportFromClipboardConfig(str, out string msg); if (vmessItem == null) { continue; } vmessItem.subid = subid; if (vmessItem.configType == (int)EConfigType.Vmess) { if (AddServer(ref config, vmessItem, -1, false) == 0) { countServers++; } } else if (vmessItem.configType == (int)EConfigType.Shadowsocks) { if (AddShadowsocksServer(ref config, vmessItem, -1, false) == 0) { countServers++; } } else if (vmessItem.configType == (int)EConfigType.Socks) { if (AddSocksServer(ref config, vmessItem, -1, false) == 0) { countServers++; } } else if (vmessItem.configType == (int)EConfigType.Trojan) { if (AddTrojanServer(ref config, vmessItem, -1, false) == 0) { countServers++; } } else if (vmessItem.configType == (int)EConfigType.VLESS) { if (AddVlessServer(ref config, vmessItem, -1, false) == 0) { countServers++; } } } ToJsonFile(config); return(countServers); }
/// <summary> /// 从剪贴板导入URL /// </summary> /// <param name="fileName"></param> /// <param name="msg"></param> /// <returns></returns> public static VmessItem ImportFromClipboardConfig(string clipboardData, out string msg) { msg = string.Empty; VmessItem vmessItem = new VmessItem(); try { //载入配置文件 string result = clipboardData.TrimEx();// Utils.GetClipboardData(); if (Utils.IsNullOrEmpty(result)) { msg = UIRes.I18N("FailedReadConfiguration"); return(null); } if (result.StartsWith(Global.vmessProtocol)) { int indexSplit = result.IndexOf("?"); if (indexSplit > 0) { vmessItem = ResolveStdVmess(result) ?? ResolveVmess4Kitsunebi(result); } else { vmessItem.configType = (int)EConfigType.Vmess; result = result.Substring(Global.vmessProtocol.Length); result = Utils.Base64Decode(result); //转成Json VmessQRCode vmessQRCode = Utils.FromJson <VmessQRCode>(result); if (vmessQRCode == null) { msg = UIRes.I18N("FailedConversionConfiguration"); return(null); } vmessItem.security = Global.DefaultSecurity; vmessItem.network = Global.DefaultNetwork; vmessItem.headerType = Global.None; vmessItem.configVersion = Utils.ToInt(vmessQRCode.v); vmessItem.remarks = Utils.ToString(vmessQRCode.ps); vmessItem.address = Utils.ToString(vmessQRCode.add); vmessItem.port = Utils.ToInt(vmessQRCode.port); vmessItem.id = Utils.ToString(vmessQRCode.id); vmessItem.alterId = Utils.ToInt(vmessQRCode.aid); if (!Utils.IsNullOrEmpty(vmessQRCode.net)) { vmessItem.network = vmessQRCode.net; } if (!Utils.IsNullOrEmpty(vmessQRCode.type)) { vmessItem.headerType = vmessQRCode.type; } vmessItem.requestHost = Utils.ToString(vmessQRCode.host); vmessItem.path = Utils.ToString(vmessQRCode.path); vmessItem.streamSecurity = Utils.ToString(vmessQRCode.tls); vmessItem.sni = Utils.ToString(vmessQRCode.sni); } ConfigHandler.UpgradeServerVersion(ref vmessItem); } else if (result.StartsWith(Global.ssProtocol)) { msg = UIRes.I18N("ConfigurationFormatIncorrect"); vmessItem = ResolveSSLegacy(result); if (vmessItem == null) { vmessItem = ResolveSip002(result); } if (vmessItem == null) { return(null); } if (vmessItem.address.Length == 0 || vmessItem.port == 0 || vmessItem.security.Length == 0 || vmessItem.id.Length == 0) { return(null); } vmessItem.configType = (int)EConfigType.Shadowsocks; } else if (result.StartsWith(Global.socksProtocol)) { msg = UIRes.I18N("ConfigurationFormatIncorrect"); vmessItem.configType = (int)EConfigType.Socks; result = result.Substring(Global.socksProtocol.Length); //remark int indexRemark = result.IndexOf("#"); if (indexRemark > 0) { try { vmessItem.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1)); } catch { } result = result.Substring(0, indexRemark); } //part decode int indexS = result.IndexOf("@"); if (indexS > 0) { } else { result = Utils.Base64Decode(result); } string[] arr1 = result.Split('@'); if (arr1.Length != 2) { return(null); } string[] arr21 = arr1[0].Split(':'); //string[] arr22 = arr1[1].Split(':'); int indexPort = arr1[1].LastIndexOf(":"); if (arr21.Length != 2 || indexPort < 0) { return(null); } vmessItem.address = arr1[1].Substring(0, indexPort); vmessItem.port = Utils.ToInt(arr1[1].Substring(indexPort + 1, arr1[1].Length - (indexPort + 1))); vmessItem.security = arr21[0]; vmessItem.id = arr21[1]; } else if (result.StartsWith(Global.trojanProtocol)) { msg = UIRes.I18N("ConfigurationFormatIncorrect"); vmessItem.configType = (int)EConfigType.Trojan; Uri uri = new Uri(result); vmessItem.address = uri.IdnHost; vmessItem.port = uri.Port; vmessItem.id = uri.UserInfo; var qurery = HttpUtility.ParseQueryString(uri.Query); vmessItem.sni = qurery["sni"] ?? ""; var remarks = uri.Fragment.Replace("#", ""); if (Utils.IsNullOrEmpty(remarks)) { vmessItem.remarks = "NONE"; } else { vmessItem.remarks = Utils.UrlDecode(remarks); } } else if (result.StartsWith(Global.vlessProtocol)) { vmessItem = ResolveStdVLESS(result); ConfigHandler.UpgradeServerVersion(ref vmessItem); } else { msg = UIRes.I18N("NonvmessOrssProtocol"); return(null); } } catch { msg = UIRes.I18N("Incorrectconfiguration"); return(null); } return(vmessItem); }
/// <summary> /// 添加服务器或编辑 /// </summary> /// <param name="config"></param> /// <param name="vmessItem"></param> /// <returns></returns> public static int EditCustomServer(ref Config config, VmessItem vmessItem) { ToJsonFile(config); return(0); }
/// <summary> /// 导入v2ray客户端配置 /// </summary> /// <param name="fileName"></param> /// <param name="msg"></param> /// <returns></returns> public static VmessItem ImportFromClientConfig(string fileName, out string msg) { msg = string.Empty; VmessItem vmessItem = new VmessItem(); try { //载入配置文件 string result = Utils.LoadResource(fileName); if (Utils.IsNullOrEmpty(result)) { msg = UIRes.I18N("FailedReadConfiguration"); return(null); } //转成Json V2rayConfig v2rayConfig = Utils.FromJson <V2rayConfig>(result); if (v2rayConfig == null) { msg = UIRes.I18N("FailedConversionConfiguration"); return(null); } if (v2rayConfig.outbounds == null || v2rayConfig.outbounds.Count <= 0) { msg = UIRes.I18N("IncorrectClientConfiguration"); return(null); } var outbound = v2rayConfig.outbounds[0]; if (outbound == null || Utils.IsNullOrEmpty(outbound.protocol) || outbound.protocol != "vmess" || outbound.settings == null || outbound.settings.vnext == null || outbound.settings.vnext.Count <= 0 || outbound.settings.vnext[0].users == null || outbound.settings.vnext[0].users.Count <= 0) { msg = UIRes.I18N("IncorrectClientConfiguration"); return(null); } vmessItem.security = Global.DefaultSecurity; vmessItem.network = Global.DefaultNetwork; vmessItem.headerType = Global.None; vmessItem.address = outbound.settings.vnext[0].address; vmessItem.port = outbound.settings.vnext[0].port; vmessItem.id = outbound.settings.vnext[0].users[0].id; vmessItem.alterId = outbound.settings.vnext[0].users[0].alterId; vmessItem.remarks = string.Format("import@{0}", DateTime.Now.ToShortDateString()); //tcp or kcp if (outbound.streamSettings != null && outbound.streamSettings.network != null && !Utils.IsNullOrEmpty(outbound.streamSettings.network)) { vmessItem.network = outbound.streamSettings.network; } //tcp伪装http if (outbound.streamSettings != null && outbound.streamSettings.tcpSettings != null && outbound.streamSettings.tcpSettings.header != null && !Utils.IsNullOrEmpty(outbound.streamSettings.tcpSettings.header.type)) { if (outbound.streamSettings.tcpSettings.header.type.Equals(Global.TcpHeaderHttp)) { vmessItem.headerType = outbound.streamSettings.tcpSettings.header.type; string request = Convert.ToString(outbound.streamSettings.tcpSettings.header.request); if (!Utils.IsNullOrEmpty(request)) { V2rayTcpRequest v2rayTcpRequest = Utils.FromJson <V2rayTcpRequest>(request); if (v2rayTcpRequest != null && v2rayTcpRequest.headers != null && v2rayTcpRequest.headers.Host != null && v2rayTcpRequest.headers.Host.Count > 0) { vmessItem.requestHost = v2rayTcpRequest.headers.Host[0]; } } } } //kcp伪装 if (outbound.streamSettings != null && outbound.streamSettings.kcpSettings != null && outbound.streamSettings.kcpSettings.header != null && !Utils.IsNullOrEmpty(outbound.streamSettings.kcpSettings.header.type)) { vmessItem.headerType = outbound.streamSettings.kcpSettings.header.type; } //ws if (outbound.streamSettings != null && outbound.streamSettings.wsSettings != null) { if (!Utils.IsNullOrEmpty(outbound.streamSettings.wsSettings.path)) { vmessItem.path = outbound.streamSettings.wsSettings.path; } if (outbound.streamSettings.wsSettings.headers != null && !Utils.IsNullOrEmpty(outbound.streamSettings.wsSettings.headers.Host)) { vmessItem.requestHost = outbound.streamSettings.wsSettings.headers.Host; } } //h2 if (outbound.streamSettings != null && outbound.streamSettings.httpSettings != null) { if (!Utils.IsNullOrEmpty(outbound.streamSettings.httpSettings.path)) { vmessItem.path = outbound.streamSettings.httpSettings.path; } if (outbound.streamSettings.httpSettings.host != null && outbound.streamSettings.httpSettings.host.Count > 0) { vmessItem.requestHost = Utils.List2String(outbound.streamSettings.httpSettings.host); } } } catch { msg = UIRes.I18N("IncorrectClientConfiguration"); return(null); } return(vmessItem); }
private static int AddBatchServers4Custom(ref Config config, string clipboardData, string subid, List <VmessItem> lstOriSub, string groupId) { if (Utils.IsNullOrEmpty(clipboardData)) { return(-1); } VmessItem vmessItem = new VmessItem(); //Is v2ray configuration V2rayConfig v2rayConfig = Utils.FromJson <V2rayConfig>(clipboardData); if (v2rayConfig != null && v2rayConfig.inbounds != null && v2rayConfig.inbounds.Count > 0 && v2rayConfig.outbounds != null && v2rayConfig.outbounds.Count > 0) { var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json"); File.WriteAllText(fileName, clipboardData); vmessItem.coreType = ECoreType.Xray; vmessItem.address = fileName; vmessItem.remarks = "v2ray_custom"; } //Is Clash configuration else if (clipboardData.IndexOf("port") >= 0 && clipboardData.IndexOf("socks-port") >= 0 && clipboardData.IndexOf("proxies") >= 0) { var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.yaml"); File.WriteAllText(fileName, clipboardData); vmessItem.coreType = ECoreType.clash; vmessItem.address = fileName; vmessItem.remarks = "clash_custom"; } if (!Utils.IsNullOrEmpty(subid)) { RemoveServerViaSubid(ref config, subid); } if (lstOriSub != null && lstOriSub.Count == 1) { vmessItem.indexId = lstOriSub[0].indexId; } vmessItem.subid = subid; vmessItem.groupId = groupId; if (Utils.IsNullOrEmpty(vmessItem.address)) { return(-1); } if (AddCustomServer(ref config, vmessItem, true) == 0) { return(1); } else { return(-1); } }
private static string ShareVLESS(VmessItem item) { string url = string.Empty; string remark = string.Empty; if (!Utils.IsNullOrEmpty(item.remarks)) { remark = "#" + Utils.UrlEncode(item.remarks); } var dicQuery = new Dictionary <string, string>(); if (!Utils.IsNullOrEmpty(item.flow)) { dicQuery.Add("flow", item.flow); } if (!Utils.IsNullOrEmpty(item.security)) { dicQuery.Add("encryption", item.security); } else { dicQuery.Add("encryption", "none"); } if (!Utils.IsNullOrEmpty(item.streamSecurity)) { dicQuery.Add("security", item.streamSecurity); } else { dicQuery.Add("security", "none"); } if (!Utils.IsNullOrEmpty(item.sni)) { dicQuery.Add("sni", item.sni); } if (!Utils.IsNullOrEmpty(item.network)) { dicQuery.Add("type", item.network); } else { dicQuery.Add("type", "tcp"); } switch (item.network) { case "tcp": if (!Utils.IsNullOrEmpty(item.headerType)) { dicQuery.Add("headerType", item.headerType); } else { dicQuery.Add("headerType", "none"); } if (!Utils.IsNullOrEmpty(item.requestHost)) { dicQuery.Add("host", Utils.UrlEncode(item.requestHost)); } break; case "kcp": if (!Utils.IsNullOrEmpty(item.headerType)) { dicQuery.Add("headerType", item.headerType); } else { dicQuery.Add("headerType", "none"); } if (!Utils.IsNullOrEmpty(item.path)) { dicQuery.Add("seed", Utils.UrlEncode(item.path)); } break; case "ws": if (!Utils.IsNullOrEmpty(item.requestHost)) { dicQuery.Add("host", Utils.UrlEncode(item.requestHost)); } if (!Utils.IsNullOrEmpty(item.path)) { dicQuery.Add("path", Utils.UrlEncode(item.path)); } break; case "http": case "h2": dicQuery["type"] = "http"; if (!Utils.IsNullOrEmpty(item.requestHost)) { dicQuery.Add("host", Utils.UrlEncode(item.requestHost)); } if (!Utils.IsNullOrEmpty(item.path)) { dicQuery.Add("path", Utils.UrlEncode(item.path)); } break; case "quic": if (!Utils.IsNullOrEmpty(item.headerType)) { dicQuery.Add("headerType", item.headerType); } else { dicQuery.Add("headerType", "none"); } dicQuery.Add("quicSecurity", Utils.UrlEncode(item.requestHost)); dicQuery.Add("key", Utils.UrlEncode(item.path)); break; case "grpc": if (!Utils.IsNullOrEmpty(item.path)) { dicQuery.Add("serviceName", Utils.UrlEncode(item.path)); if (item.headerType == Global.GrpcgunMode || item.headerType == Global.GrpcmultiMode) { dicQuery.Add("mode", Utils.UrlEncode(item.headerType)); } } break; } string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()); url = string.Format("{0}@{1}:{2}", item.id, GetIpv6(item.address), item.port); url = string.Format("{0}{1}{2}{3}", Global.vlessProtocol, url, query, remark); return(url); }
/// <summary> /// 导入v2ray服务端配置 /// </summary> /// <param name="fileName"></param> /// <param name="msg"></param> /// <returns></returns> public static VmessItem ImportFromServerConfig(string fileName, out string msg) { msg = string.Empty; VmessItem vmessItem = new VmessItem(); try { //载入配置文件 string result = Utils.LoadResource(fileName); if (Utils.IsNullOrEmpty(result)) { msg = "读取配置文件失败"; return(null); } //转成Json V2rayConfig v2rayConfig = Utils.FromJson <V2rayConfig>(result); if (v2rayConfig == null) { msg = "转换配置文件失败"; return(null); } if (v2rayConfig.inbound == null || Utils.IsNullOrEmpty(v2rayConfig.inbound.protocol) || v2rayConfig.inbound.protocol != "vmess" || v2rayConfig.inbound.settings == null || v2rayConfig.inbound.settings.clients == null || v2rayConfig.inbound.settings.clients.Count <= 0) { msg = "不是正确的服务端配置文件,请检查"; return(null); } vmessItem.security = Global.DefaultSecurity; vmessItem.network = Global.DefaultNetwork; vmessItem.headerType = Global.None; vmessItem.address = string.Empty; vmessItem.port = v2rayConfig.inbound.port; vmessItem.id = v2rayConfig.inbound.settings.clients[0].id; vmessItem.alterId = v2rayConfig.inbound.settings.clients[0].alterId; vmessItem.remarks = string.Format("import@{0}", DateTime.Now.ToShortDateString()); //tcp or kcp if (v2rayConfig.inbound.streamSettings != null && v2rayConfig.inbound.streamSettings.network != null && !Utils.IsNullOrEmpty(v2rayConfig.inbound.streamSettings.network)) { vmessItem.network = v2rayConfig.inbound.streamSettings.network; } //tcp伪装http if (v2rayConfig.inbound.streamSettings != null && v2rayConfig.inbound.streamSettings.tcpSettings != null && v2rayConfig.inbound.streamSettings.tcpSettings.header != null && !Utils.IsNullOrEmpty(v2rayConfig.inbound.streamSettings.tcpSettings.header.type)) { if (v2rayConfig.inbound.streamSettings.tcpSettings.header.type.Equals(Global.TcpHeaderHttp)) { vmessItem.headerType = v2rayConfig.inbound.streamSettings.tcpSettings.header.type; string request = Convert.ToString(v2rayConfig.inbound.streamSettings.tcpSettings.header.request); if (!Utils.IsNullOrEmpty(request)) { V2rayTcpRequest v2rayTcpRequest = Utils.FromJson <V2rayTcpRequest>(request); if (v2rayTcpRequest != null && v2rayTcpRequest.headers != null && v2rayTcpRequest.headers.Host != null && v2rayTcpRequest.headers.Host.Count > 0) { vmessItem.requestHost = v2rayTcpRequest.headers.Host[0]; } } } } //kcp伪装 //if (v2rayConfig.outbound.streamSettings != null // && v2rayConfig.outbound.streamSettings.kcpSettings != null // && v2rayConfig.outbound.streamSettings.kcpSettings.header != null // && !Utils.IsNullOrEmpty(v2rayConfig.outbound.streamSettings.kcpSettings.header.type)) //{ // cmbHeaderType.Text = v2rayConfig.outbound.streamSettings.kcpSettings.header.type; //} //ws if (v2rayConfig.inbound.streamSettings != null && v2rayConfig.inbound.streamSettings.wsSettings != null) { if (!Utils.IsNullOrEmpty(v2rayConfig.inbound.streamSettings.wsSettings.path)) { vmessItem.path = v2rayConfig.inbound.streamSettings.wsSettings.path; } if (v2rayConfig.inbound.streamSettings.wsSettings.headers != null && !Utils.IsNullOrEmpty(v2rayConfig.inbound.streamSettings.wsSettings.headers.Host)) { vmessItem.requestHost = v2rayConfig.inbound.streamSettings.wsSettings.headers.Host; } } //h2 if (v2rayConfig.inbound.streamSettings != null && v2rayConfig.inbound.streamSettings.httpSettings != null) { if (!Utils.IsNullOrEmpty(v2rayConfig.inbound.streamSettings.httpSettings.path)) { vmessItem.path = v2rayConfig.inbound.streamSettings.httpSettings.path; } if (v2rayConfig.inbound.streamSettings.httpSettings.host != null && v2rayConfig.inbound.streamSettings.httpSettings.host.Count > 0) { vmessItem.requestHost = Utils.List2String(v2rayConfig.inbound.streamSettings.httpSettings.host); } } } catch { msg = "异常,不是正确的客户端配置文件,请检查"; return(null); } return(vmessItem); }
/// <summary> /// 从剪贴板导入URL /// </summary> /// <param name="fileName"></param> /// <param name="msg"></param> /// <returns></returns> public static VmessItem ImportFromClipboardConfig(string clipboardData, out string msg) { msg = string.Empty; VmessItem vmessItem = new VmessItem(); try { //载入配置文件 string result = clipboardData.TrimEx();// Utils.GetClipboardData(); if (Utils.IsNullOrEmpty(result)) { msg = UIRes.I18N("FailedReadConfiguration"); return(null); } if (result.StartsWith(Global.vmessProtocol)) { int indexSplit = result.IndexOf("?"); if (indexSplit > 0) { vmessItem = ResolveStdVmess(result) ?? ResolveVmess4Kitsunebi(result); } else { vmessItem = ResolveVmess(result, out msg); } ConfigHandler.UpgradeServerVersion(ref vmessItem); } else if (result.StartsWith(Global.ssProtocol)) { msg = UIRes.I18N("ConfigurationFormatIncorrect"); vmessItem = ResolveSSLegacy(result); if (vmessItem == null) { vmessItem = ResolveSip002(result); } if (vmessItem == null) { return(null); } if (vmessItem.address.Length == 0 || vmessItem.port == 0 || vmessItem.security.Length == 0 || vmessItem.id.Length == 0) { return(null); } vmessItem.configType = (int)EConfigType.Shadowsocks; } else if (result.StartsWith(Global.socksProtocol)) { msg = UIRes.I18N("ConfigurationFormatIncorrect"); vmessItem = ResolveSocks(result); } else if (result.StartsWith(Global.trojanProtocol)) { msg = UIRes.I18N("ConfigurationFormatIncorrect"); vmessItem = ResolveTrojan(result); } else if (result.StartsWith(Global.vlessProtocol)) { vmessItem = ResolveStdVLESS(result); ConfigHandler.UpgradeServerVersion(ref vmessItem); } else { msg = UIRes.I18N("NonvmessOrssProtocol"); return(null); } } catch { msg = UIRes.I18N("Incorrectconfiguration"); return(null); } return(vmessItem); }
/// <summary> /// 取得服务器QRCode配置 /// </summary> /// <param name="config"></param> /// <param name="index"></param> /// <returns></returns> public static string GetVmessQRCode(Config config, int index) { try { string url = string.Empty; VmessItem vmessItem = config.vmess[index]; if (vmessItem.configType == (int)EConfigType.Vmess) { VmessQRCode vmessQRCode = new VmessQRCode(); vmessQRCode.v = vmessItem.configVersion.ToString(); vmessQRCode.ps = vmessItem.remarks.TrimEx(); //备注也许很长 ; vmessQRCode.add = vmessItem.address; vmessQRCode.port = vmessItem.port.ToString(); vmessQRCode.id = vmessItem.id; vmessQRCode.aid = vmessItem.alterId.ToString(); vmessQRCode.net = vmessItem.network; vmessQRCode.type = vmessItem.headerType; vmessQRCode.host = vmessItem.requestHost; vmessQRCode.path = vmessItem.path; vmessQRCode.tls = vmessItem.streamSecurity; url = Utils.ToJson(vmessQRCode); url = Utils.Base64Encode(url); url = string.Format("{0}{1}", Global.vmessProtocol, url); } else if (vmessItem.configType == (int)EConfigType.Shadowsocks) { var remark = string.Empty; if (!Utils.IsNullOrEmpty(vmessItem.remarks)) { remark = "#" + WebUtility.UrlEncode(vmessItem.remarks); } url = string.Format("{0}:{1}@{2}:{3}", vmessItem.security, vmessItem.id, vmessItem.address, vmessItem.port); url = Utils.Base64Encode(url); url = string.Format("{0}{1}{2}", Global.ssProtocol, url, remark); } else if (vmessItem.configType == (int)EConfigType.Socks) { var remark = string.Empty; if (!Utils.IsNullOrEmpty(vmessItem.remarks)) { remark = "#" + WebUtility.UrlEncode(vmessItem.remarks); } url = string.Format("{0}:{1}@{2}:{3}", vmessItem.security, vmessItem.id, vmessItem.address, vmessItem.port); url = Utils.Base64Encode(url); url = string.Format("{0}{1}{2}", Global.socksProtocol, url, remark); } else { } return(url); } catch { return(""); } }
private static VmessItem ResolveStdVmess(string result) { VmessItem i = new VmessItem { configType = (int)EConfigType.Vmess, security = "auto" }; Uri u = new Uri(result); i.address = u.IdnHost; i.port = u.Port; i.remarks = Utils.UrlDecode(u.GetComponents(UriComponents.Fragment, UriFormat.Unescaped)); var q = HttpUtility.ParseQueryString(u.Query); var m = StdVmessUserInfo.Match(u.UserInfo); if (!m.Success) { return(null); } i.id = m.Groups["id"].Value; if (!int.TryParse(m.Groups["alterId"].Value, out int aid)) { return(null); } i.alterId = aid; if (m.Groups["streamSecurity"].Success) { i.streamSecurity = m.Groups["streamSecurity"].Value; } switch (i.streamSecurity) { case "tls": // TODO tls config break; default: if (!string.IsNullOrWhiteSpace(i.streamSecurity)) { return(null); } break; } i.network = m.Groups["network"].Value; switch (i.network) { case "tcp": string t1 = q["type"] ?? "none"; i.headerType = t1; // TODO http option break; case "kcp": i.headerType = q["type"] ?? "none"; // TODO kcp seed break; case "ws": string p1 = q["path"] ?? "/"; string h1 = q["host"] ?? ""; i.requestHost = Utils.UrlDecode(h1); i.path = p1; break; case "http": case "h2": i.network = "h2"; string p2 = q["path"] ?? "/"; string h2 = q["host"] ?? ""; i.requestHost = Utils.UrlDecode(h2); i.path = p2; break; case "quic": string s = q["security"] ?? "none"; string k = q["key"] ?? ""; string t3 = q["type"] ?? "none"; i.headerType = t3; i.requestHost = Utils.UrlDecode(s); i.path = k; break; default: return(null); } return(i); }
/// <summary> /// 配置文件版本升级 /// </summary> /// <param name="vmessItem"></param> /// <returns></returns> public static int UpgradeServerVersion(ref VmessItem vmessItem) { try { if (vmessItem == null || vmessItem.configVersion == 2) { return(0); } if (vmessItem.configType == (int)EConfigType.Vmess) { string path = ""; string host = ""; string[] arrParameter; switch (vmessItem.network) { case "kcp": break; case "ws": //*ws(path+host),它们中间分号(;)隔开 arrParameter = vmessItem.requestHost.Replace(" ", "").Split(';'); if (arrParameter.Length > 0) { path = arrParameter[0]; } if (arrParameter.Length > 1) { path = arrParameter[0]; host = arrParameter[1]; } vmessItem.path = path; vmessItem.requestHost = host; break; case "h2": //*h2 path arrParameter = vmessItem.requestHost.Replace(" ", "").Split(';'); if (arrParameter.Length > 0) { path = arrParameter[0]; } if (arrParameter.Length > 1) { path = arrParameter[0]; host = arrParameter[1]; } vmessItem.path = path; vmessItem.requestHost = host; break; default: break; } } vmessItem.configVersion = 2; } catch { } return(0); }
private static VmessItem ResolveStdVLESS(string result) { VmessItem item = new VmessItem { configType = (int)EConfigType.VLESS, security = "none" }; Uri url = new Uri(result); item.address = url.IdnHost; item.port = url.Port; item.remarks = Utils.UrlDecode(url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped)); item.id = url.UserInfo; var query = HttpUtility.ParseQueryString(url.Query); item.flow = query["flow"] ?? ""; item.security = query["encryption"] ?? "none"; item.streamSecurity = query["security"] ?? ""; item.sni = query["sni"] ?? ""; item.network = query["type"] ?? "tcp"; switch (item.network) { case "tcp": item.headerType = query["headerType"] ?? "none"; item.requestHost = Utils.UrlDecode(query["host"] ?? ""); break; case "kcp": item.headerType = query["headerType"] ?? "none"; item.path = Utils.UrlDecode(query["seed"] ?? ""); break; case "ws": item.requestHost = Utils.UrlDecode(query["host"] ?? ""); item.path = Utils.UrlDecode(query["path"] ?? "/"); break; case "http": case "h2": item.network = "h2"; item.requestHost = Utils.UrlDecode(query["host"] ?? ""); item.path = Utils.UrlDecode(query["path"] ?? "/"); break; case "quic": item.headerType = query["headerType"] ?? "none"; item.requestHost = query["quicSecurity"] ?? "none"; item.path = Utils.UrlDecode(query["key"] ?? ""); break; case "grpc": item.path = Utils.UrlDecode(query["serviceName"] ?? ""); item.headerType = Utils.UrlDecode(query["mode"] ?? Global.GrpcgunMode); break; default: return(null); } return(item); }
/// <summary> /// 刷新服务器列表 /// </summary> private void RefreshServersView() { lvServers.Items.Clear(); for (int k = 0; k < config.vmess.Count; k++) { string def = string.Empty; string totalUp = string.Empty, totalDown = string.Empty, todayUp = string.Empty, todayDown = string.Empty; if (config.index.Equals(k)) { def = "√"; } VmessItem item = config.vmess[k]; ListViewItem lvItem = null; if (statistics != null && statistics.Enable) { var index = statistics.Statistic.FindIndex(item_ => item_.itemId == item.getItemId()); if (index != -1) { totalUp = Utils.HumanFy(statistics.Statistic[index].totalUp); totalDown = Utils.HumanFy(statistics.Statistic[index].totalDown); todayUp = Utils.HumanFy(statistics.Statistic[index].todayUp); todayDown = Utils.HumanFy(statistics.Statistic[index].todayDown); } lvItem = new ListViewItem(new string[] { def, ((EConfigType)item.configType).ToString(), item.remarks, item.address, item.port.ToString(), //item.id, //item.alterId.ToString(), item.security, item.network, item.getSubRemarks(config), item.testResult, totalUp, totalDown, todayUp, todayDown }); } else { lvItem = new ListViewItem(new string[] { def, ((EConfigType)item.configType).ToString(), item.remarks, item.address, item.port.ToString(), //item.id, //item.alterId.ToString(), item.security, item.network, item.getSubRemarks(config), item.testResult //totalUp, //totalDown, //todayUp, //todayDown, }); } if (lvItem != null) { lvServers.Items.Add(lvItem); } } //if (lvServers.Items.Count > 0) //{ // if (lvServers.Items.Count <= testConfigIndex) // { // testConfigIndex = lvServers.Items.Count - 1; // } // lvServers.Items[testConfigIndex].Selected = true; // lvServers.Select(); //} }
/// <summary> /// 刷新服务器列表 /// </summary> private void RefreshServersView() { int index = lvServers.SelectedIndices.Count > 0 ? lvServers.SelectedIndices[0] : -1; lvServers.BeginUpdate(); lvServers.Items.Clear(); for (int k = 0; k < config.vmess.Count; k++) { string def = string.Empty; string totalUp = string.Empty, totalDown = string.Empty, todayUp = string.Empty, todayDown = string.Empty; if (config.index.Equals(k)) { def = "√"; } VmessItem item = config.vmess[k]; void _addSubItem(ListViewItem i, string name, string text) { i.SubItems.Add(new ListViewItem.ListViewSubItem() { Name = name, Text = text }); } bool stats = statistics != null && statistics.Enable; if (stats) { ServerStatItem sItem = statistics.Statistic.Find(item_ => item_.itemId == item.getItemId()); if (sItem != null) { totalUp = Utils.HumanFy(sItem.totalUp); totalDown = Utils.HumanFy(sItem.totalDown); todayUp = Utils.HumanFy(sItem.todayUp); todayDown = Utils.HumanFy(sItem.todayDown); } } ListViewItem lvItem = new ListViewItem(def); _addSubItem(lvItem, EServerColName.configType.ToString(), ((EConfigType)item.configType).ToString()); _addSubItem(lvItem, EServerColName.remarks.ToString(), item.remarks); _addSubItem(lvItem, EServerColName.address.ToString(), item.address); _addSubItem(lvItem, EServerColName.port.ToString(), item.port.ToString()); _addSubItem(lvItem, EServerColName.security.ToString(), item.security); _addSubItem(lvItem, EServerColName.network.ToString(), item.network); _addSubItem(lvItem, EServerColName.subRemarks.ToString(), item.getSubRemarks(config)); _addSubItem(lvItem, EServerColName.testResult.ToString(), item.testResult); if (stats) { _addSubItem(lvItem, EServerColName.todayDown.ToString(), todayDown); _addSubItem(lvItem, EServerColName.todayUp.ToString(), todayUp); _addSubItem(lvItem, EServerColName.totalDown.ToString(), totalDown); _addSubItem(lvItem, EServerColName.totalUp.ToString(), totalUp); } if (k % 2 == 1) // 隔行着色 { lvItem.BackColor = Color.WhiteSmoke; } if (config.index.Equals(k)) { //lvItem.Checked = true; lvItem.ForeColor = Color.DodgerBlue; lvItem.Font = new Font(lvItem.Font, FontStyle.Bold); } if (lvItem != null) { lvServers.Items.Add(lvItem); } } lvServers.EndUpdate(); if (index >= 0 && index < lvServers.Items.Count && lvServers.Items.Count > 0) { lvServers.Items[index].Selected = true; lvServers.EnsureVisible(index); // workaround } }