Enhancements

Fix a potential bug which will cause SSD subscription to be ignored.
Add experimental Surge subscription output.
Change the default generate options.
Update build scripts.
This commit is contained in:
Tindy X committed 2019-11-08 14:50:28 +08:00
1 parent 46b78ce250
commit 6533df2792
8 files changed
+358 -35

No files matched your search

+4 -4
View File
@@ -9,18 +9,18 @@ git clone https://github.com/curl/curl
cd curl
./buildconf
./configure --with-ssl --disable-ldap --disable-ldaps --disable-rtsp --without-libidn2 > /dev/null
make install -j4
make install -j4 > /dev/null
cd ..
git clone https://github.com/jbeder/yaml-cpp
cd yaml-cpp
cmake .
make install -j4
cmake . > /dev/null
make install -j4 > /dev/null
cd ..
git clone git://sourceware.org/git/bzip2.git
cd bzip2
make install -j4
make install -j4 > /dev/null
cd ..
g++ -Wall -std=c++17 -fexceptions -DCURL_STATICLIB -c logger.cpp -o obj\logger.o
+3 -3
View File
@@ -6,15 +6,15 @@ brew reinstall yaml-cpp rapidjson libevent zlib
git clone https://github.com/curl/curl
cd curl
./buildconf
./buildconf > /dev/null
./configure --with-ssl=/usr/local/opt/openssl@1.1 --without-mbedtls --disable-ldap --disable-ldaps --disable-rtsp --without-libidn2 > /dev/null
make -j8
make -j8 > /dev/null
cd ..
curl -L -o bzip2-1.0.6.tar.gz https://sourceforge.net/projects/bzip2/files/bzip2-1.0.6.tar.gz/download
tar xvf bzip2-1.0.6.tar.gz
cd bzip2-1.0.6
make -j8
make -j8 > /dev/null
cd ..
cp /usr/local/lib/libevent.a .
+34 -1
View File
@@ -150,7 +150,7 @@ void readConf()
}
std::string netchToClash(std::vector<nodeInfo> &nodes, std::string &baseConf, std::vector<ruleset_content> &ruleset_content_array, string_array &extra_proxy_group, bool clashR);
std::string netchToSurge(std::vector<nodeInfo> &nodes, std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, string_array &extra_proxy_group, int surge_ver);
std::string netchToSurge(std::vector<nodeInfo> &nodes, std::string &base_conf, string_array &ruleset_array, string_array &extra_proxy_group, int surge_ver);
int main()
{
@@ -239,6 +239,39 @@ int main()
return netchToClash(nodes, clash_base_content, ruleset_content_array, clash_extra_group, true);
});
append_response("GET", "/surge", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string
{
if(!api_mode)
readConf();
std::string surge_base_content;
std::string url = UrlDecode(getUrlArg(argument, "url")), include = UrlDecode(getUrlArg(argument, "regex")), group = UrlDecode(getUrlArg(argument, "group"));
int surge_ver = stoi(getUrlArg(argument, "ver"));
if(!url.size()) url = default_url;
string_array urls = split(url, "|");
std::vector<nodeInfo> nodes;
if(include.size())
{
eraseElements(def_include_remarks);
def_include_remarks.emplace_back(include);
}
if(group.size()) custom_group = group;
for(std::string &x : urls)
{
std::cerr<<"Fetching node data from url '"<<x<<"'. Generate target: Surge "<<surge_ver<<std::endl;
addNodes(x, nodes);
}
if(fileExist(surge_rule_base))
{
surge_base_content = fileGet(surge_rule_base, false);
}
else
surge_base_content = webGet(surge_rule_base, getSystemProxy());
if(update_ruleset_on_request)
refreshRulesets();
return netchToSurge(nodes, surge_base_content, rulesets, clash_extra_group, surge_ver);
});
if(!api_mode)
{
append_response("GET", "/get", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string
+29 -22
View File
@@ -3,7 +3,7 @@
default_url=
;Exclude nodes which remarks match the following patterns. Supports regular expression.
exclude_remarks=(剩余流量|到期时间|过期时间|官网地址|产品名称)
exclude_remarks=(流量|时间|官网|产品)
;exclude_remarks=(other rule)
;Only include nodes which remarks match the following patterns. Supports regular expression.
@@ -12,6 +12,9 @@ exclude_remarks=(剩余流量|到期时间|过期时间|官网地址|产品名
;Clash config base used by the generator, supports local files/URL
clash_rule_base=simple_base.yml
;Surge config base used by the generator, supports local files/URL
surge_rule_base=surge.conf
;Rename remarks with the following patterns. Supports regular expression.
;Format: Search_Pattern@Replace_Pattern
;rename_node=IPLC@专线
@@ -76,19 +79,19 @@ update_ruleset_on_request=false
; Group name,[]Rule
surge_ruleset=DIRECT,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Unbreak.list
surge_ruleset=Advertising,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Advertising.list
surge_ruleset=Hijacking,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Hijacking.list
surge_ruleset=YouTube,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/YouTube.list
surge_ruleset=Netflix,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/Netflix.list
surge_ruleset=⛔️ 广告拦截,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Advertising.list
surge_ruleset=🚫 运营劫持,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Hijacking.list
surge_ruleset=🌌 YouTube,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/YouTube.list
surge_ruleset=🎥 NETFLIX,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/Netflix.list
;surge_ruleset=HBO,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/HBO.list
;surge_ruleset=Fox,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/Fox.list
surge_ruleset=GlobalMedia,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/GlobalMedia.list
surge_ruleset=HKMTMedia,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/HKMTMedia.list
surge_ruleset=Telegram,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Telegram.list
surge_ruleset=PROXY,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Global.list
surge_ruleset=Apple,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Apple.list
surge_ruleset=🌍 国外媒体,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/GlobalMedia.list
surge_ruleset=🌏 港台媒体,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/HKMTMedia.list
surge_ruleset=📲 电报信息,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Telegram.list
surge_ruleset=🔰 节点选择,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Global.list
surge_ruleset=🍎 苹果服务,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Apple.list
surge_ruleset=DIRECT,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/China.list
surge_ruleset=Final,[]MATCH
surge_ruleset=💕 规则自选,[]MATCH
[clash_proxy_group]
;Generate Clash Proxy Group with the following patterns. Node filterting rule supports regular expression.
@@ -101,7 +104,8 @@ surge_ruleset=Final,[]MATCH
;custom_proxy_group=LoadBalance`load-balance`.*`http://www.gstatic.com/generate_204`300
;for forcerule.yml
;custom_proxy_group=Proxy`select`.*
;custom_proxy_group=Proxy`select`.*[]AUTO`[]DIRECT`.*
;custom_proxy_group=AUTO`url-test`.*`http://www.gstatic.com/generate_204`300
;custom_proxy_group=google`select`.*
;custom_proxy_group=netflix`select`.*
;custom_proxy_group=动画疯`select`(深台|彰化|新北|台)
@@ -116,16 +120,19 @@ surge_ruleset=Final,[]MATCH
;custom_proxy_group=Telegram`select`新加坡`[]Proxy
;for DivineEngine_Profiles
custom_proxy_group=PROXY`select`.*
custom_proxy_group=YouTube`select`.*
custom_proxy_group=Netflix`select`.*
custom_proxy_group=Advertising`select`[]REJECT`[]DIRECT`[]PROXY
custom_proxy_group=Hijacking`select`[]REJECT`[]DIRECT`[]PROXY
custom_proxy_group=GlobalMedia`select`.*
custom_proxy_group=HKMTMedia`select`(HGC|HKBN|PCCW|HKT|深台|彰化|新北|台|新加坡|sg|hk|tw)
custom_proxy_group=Telegram`select`新加坡`[]PROXY
custom_proxy_group=Apple`select`[]DIRECT`[]PROXY
custom_proxy_group=Final`select`[]PROXY`[]DIRECT
custom_proxy_group=🔰 节点选择`select`[]♻️ 自动选择`[]🎯 全球直连`.*
custom_proxy_group=♻️ 自动选择`url-test`.*`http://www.gstatic.com/generate_204`300
custom_proxy_group=🌌 YouTube`select`[]🔰 节点选择`[]♻️ 自动选择`[]🎯 全球直连`.*
custom_proxy_group=🎥 NETFLIX`select`[]🔰 节点选择`[]♻️ 自动选择`[]🎯 全球直连`.*
custom_proxy_group=⛔️ 广告拦截`select`[]🛑 全球拦截`[]🎯 全球直连`[]🔰 节点选择
custom_proxy_group=🚫 运营劫持`select`[]🛑 全球拦截`[]🎯 全球直连`[]🔰 节点选择
custom_proxy_group=🌍 国外媒体`select`[]♻️ 自动选择`[]🎯 全球直连`.*
custom_proxy_group=🌏 港台媒体`select`(HGC|HKBN|PCCW|HKT|深台|彰化|新北|台|hk|香港|tw)
custom_proxy_group=📲 电报信息`select`[]🔰 节点选择`[]♻️ 自动选择`[]DIRECT`(美|新加坡|sg|us)`.*
custom_proxy_group=🍎 苹果服务`select`[]🔰 节点选择`[]🎯 全球直连`[]♻️ 自动选择`.*
custom_proxy_group=💕 规则自选`select`[]🔰 节点选择`[]🎯 全球直连`[]♻️ 自动选择`.*
custom_proxy_group=🎯 全球直连`select`[]DIRECT
custom_proxy_group=🛑 全球拦截`select`[]REJECT
[server]
;Address to bind on for Web Server
+5 -5
View File
@@ -1486,9 +1486,10 @@ void explodeSub(std::string sub, bool sslibev, bool ssrlibev, std::string custom
std::string strLink;
nodeInfo node;
//try to parse as surge configuration
if(explodeSurge(sub, custom_port, local_port, nodes, sslibev))
//try to parse as SSD configuration
if(strFind(sub, "ssd://"))
{
explodeSSD(sub, sslibev, custom_port, local_port, nodes);
return;
}
@@ -1510,10 +1511,9 @@ void explodeSub(std::string sub, bool sslibev, bool ssrlibev, std::string custom
//ignore
}
//try to parse as SSD configuration
if(strFind(sub, "ssd://"))
//try to parse as surge configuration
if(explodeSurge(sub, custom_port, local_port, nodes, sslibev))
{
explodeSSD(sub, sslibev, custom_port, local_port, nodes);
return;
}
+213
View File
@@ -14,6 +14,7 @@
extern bool overwrite_original_rules;
extern string_array renames, emojis;
extern bool add_emoji, remove_old_emoji;
extern bool api_mode;
std::string vmessConstruct(std::string add, std::string port, std::string type, std::string id, std::string aid, std::string net, std::string cipher, std::string path, std::string host, std::string tls, int local_port)
{
@@ -216,6 +217,67 @@ void rulesetToClash(YAML::Node &base_rule, std::vector<ruleset_content> &ruleset
base_rule["Rule"] = Rules;
}
void rulesetToSurge(INIReader &base_rule, string_array &ruleset_array, int surge_ver)
{
string_array allRules, vArray;
std::string rule_group, rule_path, retrived_rules, strLine;
std::stringstream strStrm;
base_rule.SetCurrentSection("Rule");
if(overwrite_original_rules)
base_rule.EraseSection();
for(std::string &x : ruleset_array)
{
vArray = split(x, ",");
if(vArray.size() != 2)
continue;
rule_group = trim(vArray[0]);
rule_path = trim(vArray[1]);
if(rule_path.find("[]") == 0)
{
strLine = rule_path.substr(2);
if(strLine == "MATCH")
strLine = "FINAL";
allRules.emplace_back(strLine + "," + rule_group);
continue;
}
else
{
if(fileExist(rule_path))
{
if(api_mode)
continue;
retrived_rules = fileGet(rule_path, false);
char delimiter = count(retrived_rules.begin(), retrived_rules.end(), '\n') <= 1 ? '\r' : '\n';
strStrm.clear();
strStrm<<retrived_rules;
while(getline(strStrm, strLine, delimiter))
{
strLine = replace_all_distinct(strLine, "\r", ""); //remove line break
if(!strLine.size() || strLine.find("#") == 0 || strLine.find(";") == 0) //remove comments
continue;
if(surge_ver < 4 && strLine.find("IP-CIDR") == 0)
strLine = replace_all_distinct(strLine, ",no-resolve", "");
strLine += "," + rule_group;
allRules.emplace_back(strLine);
}
}
else
{
allRules.emplace_back("RULESET," + rule_path + "," + rule_group);
}
}
}
for(std::string &x : allRules)
{
base_rule.Set("{NONAME}", x);
}
}
std::string netchToClash(std::vector<nodeInfo> &nodes, std::string &baseConf, std::vector<ruleset_content> &ruleset_content_array, string_array &extra_proxy_group, bool clashR)
{
YAML::Node yamlnode, proxies, singleproxy, singlegroup, original_groups;
@@ -413,3 +475,154 @@ std::string netchToClash(std::vector<nodeInfo> &nodes, std::string &baseConf, st
return to_string(yamlnode);
}
std::string netchToSurge(std::vector<nodeInfo> &nodes, std::string &base_conf, string_array &ruleset_array, string_array &extra_proxy_group, int surge_ver)
{
rapidjson::Document json;
INIReader ini;
std::string proxy;
std::string type, remark, hostname, port, username, password, method;
std::string plugin, pluginopts;
std::string id, aid, transproto, faketype, host, path, quicsecure, quicsecret;
std::string url;
std::vector<std::string> nodelist;
bool tlssecure;
string_array vArray, filtered_nodelist;
ini.store_any_line = true;
if(ini.Parse(base_conf) != 0)
return std::string();
ini.SetCurrentSection("Proxy");
ini.EraseSection();
ini.Set("DIRECT", "direct");
for(nodeInfo &x : nodes)
{
json.Parse(x.proxyStr.data());
type = GetMember(json, "Type");
remark = addEmoji(trim(removeEmoji(nodeRename(x.remarks))));
hostname = GetMember(json, "Hostname");
port = std::__cxx11::to_string((unsigned short)stoi(GetMember(json, "Port")));
username = GetMember(json, "Username");
password = GetMember(json, "Password");
method = GetMember(json, "EncryptMethod");
proxy = "";
if(type == "SS")
{
if(surge_ver >= 3)
{
plugin = GetMember(json, "Plugin");
pluginopts = GetMember(json, "PluginOption");
proxy = "ss," + hostname + "," + port + ",encrypt-method=" + method + ",password=" + password;
if(plugin.size() && pluginopts.size())
{
proxy += "," + replace_all_distinct(pluginopts, ";", ",");
}
}
else
{
if(GetMember(json, "Plugin") == "")
{
proxy = "custom," + hostname + "," + port + "," + method + "," + password + ",https://github.com/ConnersHua/SSEncrypt/raw/master/SSEncrypt.module";
}
else
continue;
}
}
else if(type == "VMess")
{
if(surge_ver < 4)
continue;
id = GetMember(json, "UserID");
aid = GetMember(json, "AlterID");
transproto = GetMember(json, "TransferProtocol");
host = GetMember(json, "Host");
path = GetMember(json, "Path");
tlssecure = GetMember(json, "TLSSecure") == "true";
proxy = "vmess," + hostname + "," + port + "," + method + ",username=" + id + ",tls=" + (tlssecure ? "true" : "false");
if(transproto == "ws")
{
proxy += ",ws=true,ws-path=" + path;
}
else if(transproto == "kcp" || transproto == "h2" || transproto == "quic")
continue;
}
else if(type == "Socks5")
{
proxy = "socks5," + hostname + "," + port;
if(username != "" && password != "")
proxy += "," + username + "," + password;
}
else if(type == "HTTP" || type == "HTTPS")
{
proxy = "http," + hostname + "," + port;
if(username != "" && password != "")
proxy += "," + username + "," + password;
proxy += std::string(",tls=") + (type == "HTTPS" ? "true" : "false");
}
else
continue;
ini.Set(remark, proxy);
nodelist.emplace_back(remark);
}
ini.SetCurrentSection("Proxy Group");
for(std::string &x : extra_proxy_group)
{
eraseElements(filtered_nodelist);
unsigned int rules_upper_bound = 0;
url = "";
proxy = "";
vArray = split(x, "`");
if(vArray.size() < 3)
continue;
if(vArray[1] == "select")
{
rules_upper_bound = vArray.size();
}
else if(vArray[1] == "url-test" || vArray[1] == "fallback" || vArray[1] == "load-balance")
{
if(vArray.size() < 5)
continue;
rules_upper_bound = vArray.size() - 2;
url = vArray[vArray.size() - 2];
}
else
continue;
for(unsigned int i = 2; i < rules_upper_bound; i++)
{
if(vArray[i].find("[]") == 0)
{
filtered_nodelist.emplace_back(vArray[i].substr(2));
}
else
{
for(std::string &y : nodelist)
{
if(regFind(y, vArray[i]) && std::find(filtered_nodelist.begin(), filtered_nodelist.end(), y) == filtered_nodelist.end())
filtered_nodelist.emplace_back(y);
}
}
}
if(!filtered_nodelist.size())
filtered_nodelist.emplace_back("DIRECT");
proxy = vArray[1];
for(std::string &x : filtered_nodelist)
proxy += "," + x;
if(vArray[1] == "url-test" || vArray[1] == "fallback" || vArray[1] == "load-balance")
proxy += ",url=" + url;
ini.Set("{NONAME}", vArray[0] + " = " + proxy); //insert order
}
rulesetToSurge(ini, ruleset_array, surge_ver);
return ini.ToString();
}
+7
View File
@@ -0,0 +1,7 @@
[General]
loglevel = notify
bypass-system = true
skip-proxy = 127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,100.64.0.0/10,localhost,*.local,e.crashlytics.com,captive.apple.com,::ffff:0:0:0:0/1,::ffff:128:0:0:0/1
#DNS设置或根据自己网络情况进行相应设置
bypass-tun = 192.168.0.0/16,10.0.0.0/8,172.16.0.0/12
dns-server = 119.29.29.29,223.5.5.5
+63
View File
@@ -55,3 +55,66 @@ std::string webGet(std::string url, std::string proxy)
{
return curlGet(url, proxy);
}
long curlPost(std::string url, std::string data, std::string proxy)
{
CURL *curl_handle;
double retVal = 0.0;
CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
curl_handle = curl_easy_init();
curl_easy_setopt(curl_handle, CURLOPT_URL, url.data());
curl_easy_setopt(curl_handle, CURLOPT_HEADER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(curl_handle, CURLOPT_POST, 1L);
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, data.data());
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, data.size());
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 10L);
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
if(proxy != "")
curl_easy_setopt(curl_handle, CURLOPT_PROXY, proxy.data());
res = curl_easy_perform(curl_handle);
if(res == CURLE_OK)
{
res = curl_easy_getinfo(curl_handle, CURLINFO_SPEED_UPLOAD, &retVal);
}
curl_easy_cleanup(curl_handle);
curl_global_cleanup();
return retVal;
}
int curlPatch(std::string url, std::string data, std::string proxy)
{
CURL *curl_handle;
int retVal = 0;
CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
curl_handle = curl_easy_init();
curl_easy_setopt(curl_handle, CURLOPT_URL, url.data());
curl_easy_setopt(curl_handle, CURLOPT_HEADER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, data.data());
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, data.size());
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 10L);
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
if(proxy != "")
curl_easy_setopt(curl_handle, CURLOPT_PROXY, proxy.data());
res = curl_easy_perform(curl_handle);
if(res != CURLE_OK)
retVal = -1;
curl_easy_cleanup(curl_handle);
curl_global_cleanup();
return retVal;
}