Skip to content

Commit

Permalink
Fix implementation of v2ray-plugin in Quantumult X subscriptions
Browse files Browse the repository at this point in the history
Add example for using Clash proxy-provider.
Optimize codes.
  • Loading branch information
tindy2013 committed Jul 10, 2020
1 parent c4ef7ed commit dc4eae3
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 25 deletions.
17 changes: 17 additions & 0 deletions base/base/clash_provider_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
mixed-port: 7890
allow-lan: true
mode: Rule
log-level: info
external-controller: 127.0.0.1:9090
proxy-providers:
HK:
type: http
path: proxy-providers/HK.yaml
url: {{ getLink("/sub?target=clash&list=true&include=HK&url=https%3A%2F%2Fexample.com%2Fsubscription") }}
interval: 86400
health-check:
enable: true
url: http://www.gstatic.com/generate_204
interval: 300
rule-providers: ~
rules: ~
20 changes: 19 additions & 1 deletion src/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ class tribool

template <typename T> tribool(const T &value) { set(value); }

explicit tribool(const tribool &value) { *this = value; }
tribool(const tribool &value) { *this = value; }

~tribool() = default;

Expand Down Expand Up @@ -194,13 +194,31 @@ class tribool
return *this;
}

tribool reverse()
{
_M_VALUE = _M_VALUE == -1 ? -1 : (_M_VALUE == 0 ? 1 : 0);
return *this;
}

bool get(const bool &def_value = false)
{
if(_M_VALUE == -1)
return def_value;
return _M_VALUE;
}

std::string get_str()
{
switch(_M_VALUE)
{
case 0:
return "false";
case 1:
return "true";
}
return "undef";
}

template <typename T> bool set(const T &value)
{
_M_VALUE = value;
Expand Down
47 changes: 39 additions & 8 deletions src/speedtestutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,7 @@ void explodeNetch(std::string netch, bool ss_libev, bool ssr_libev, const std::s
if(group.empty())
group = HTTP_DEFAULT_GROUP;
node.group = group;
node.proxyStr = httpConstruct(group, remark, address, port, username, password, type == "HTTPS", scv);
node.proxyStr = httpConstruct(group, remark, address, port, username, password, type == "HTTPS", tfo, scv);
break;
case "Trojan"_hash:
host = GetMember(json, "Host");
Expand Down Expand Up @@ -1081,7 +1081,7 @@ void explodeClash(Node yamlnode, const std::string &custom_port, std::vector<nod
singleproxy["tls"] >>= tls;

node.linkType = SPEEDTEST_MESSAGE_FOUNDHTTP;
node.proxyStr = httpConstruct(group, ps, server, port, user, password, tls == "true", scv);
node.proxyStr = httpConstruct(group, ps, server, port, user, password, tls == "true", tfo, scv);
break;
case "trojan"_hash:
group = TROJAN_DEFAULT_GROUP;
Expand Down Expand Up @@ -1242,7 +1242,7 @@ bool explodeSurge(std::string surge, const std::string &custom_port, std::vector
for(auto &x : proxies)
{
std::string remarks, server, port, method, username, password; //common
std::string plugin, pluginopts, pluginopts_mode, pluginopts_host = "cloudfront.net", mod_url, mod_md5; //ss
std::string plugin, pluginopts, pluginopts_mode, pluginopts_host, mod_url, mod_md5; //ss
std::string id, net, tls, host, edge, path; //v2
std::string protocol, protoparam; //ssr
std::string itemName, itemVal, config;
Expand Down Expand Up @@ -1458,7 +1458,7 @@ bool explodeSurge(std::string surge, const std::string &custom_port, std::vector
default: continue;
}
}
node.proxyStr = httpConstruct(node.group, remarks, server, port, username, password, false, scv);
node.proxyStr = httpConstruct(node.group, remarks, server, port, username, password, false, tfo, scv);
break;
case "trojan"_hash: // surge 4 style trojan proxy
node.linkType = SPEEDTEST_MESSAGE_FOUNDTROJAN;
Expand Down Expand Up @@ -1546,10 +1546,28 @@ bool explodeSurge(std::string surge, const std::string &custom_port, std::vector
case "ssr-protocol"_hash: protocol = itemVal; break;
case "ssr-protocol-param"_hash: protoparam = itemVal; break;
case "obfs"_hash:
plugin = "simple-obfs";
pluginopts_mode = itemVal;
{
switch(hash_(itemVal))
{
case "http"_hash:
case "tls"_hash:
plugin = "simple-obfs";
pluginopts_mode = itemVal;
break;
case "wss"_hash:
tls = "tls";
[[fallthrough]];
case "ws"_hash:
pluginopts_mode = "websocket";
plugin = "v2ray-plugin";
break;
default:
pluginopts_mode = itemVal;
}
break;
}
case "obfs-host"_hash: pluginopts_host = itemVal; break;
case "obfs-uri"_hash: path = itemVal; break;
case "udp-relay"_hash: udp = itemVal; break;
case "fast-open"_hash: tfo = itemVal; break;
case "tls13"_hash: tls13 = itemVal; break;
Expand All @@ -1558,11 +1576,23 @@ bool explodeSurge(std::string surge, const std::string &custom_port, std::vector
}
if(remarks.empty())
remarks = server + ":" + port;
if(plugin.size())
switch(hash_(plugin))
{
case "simple-obfs"_hash:
pluginopts = "obfs=" + pluginopts_mode;
if(pluginopts_host.size())
pluginopts += ";obfs-host=" + pluginopts_host;
break;
case "v2ray-plugin"_hash:
if(pluginopts_host.empty() && !isIPv4(server) && !isIPv6(server))
pluginopts_host = server;
pluginopts = "mode=" + pluginopts_mode;
if(pluginopts_host.size())
pluginopts += ";host=" + pluginopts_host;
if(path.size())
pluginopts += ";path=" + path;
pluginopts += ";" + tls;
break;
}

if(protocol.size())
Expand Down Expand Up @@ -1681,6 +1711,7 @@ bool explodeSurge(std::string surge, const std::string &custom_port, std::vector
case "over-tls"_hash: tls = itemVal; break;
case "tls-verification"_hash: scv = itemVal == "false"; break;
case "tls13"_hash: tls13 = itemVal; break;
case "fast-open"_hash: tfo = itemVal; break;
default: continue;
}
}
Expand All @@ -1697,7 +1728,7 @@ bool explodeSurge(std::string surge, const std::string &custom_port, std::vector

node.linkType = SPEEDTEST_MESSAGE_FOUNDHTTP;
node.group = HTTP_DEFAULT_GROUP;
node.proxyStr = httpConstruct(node.group, remarks, server, port, username, password, tls == "true", scv, tls13);
node.proxyStr = httpConstruct(node.group, remarks, server, port, username, password, tls == "true", tfo, scv, tls13);
break;
default:
continue;
Expand Down
2 changes: 1 addition & 1 deletion src/speedtestutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ std::string vmessConstruct(const std::string &group, const std::string &remarks,
std::string ssrConstruct(const std::string &group, const std::string &remarks, const std::string &remarks_base64, const std::string &server, const std::string &port, const std::string &protocol, const std::string &method, const std::string &obfs, const std::string &password, const std::string &obfsparam, const std::string &protoparam, bool libev, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool());
std::string ssConstruct(const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &method, const std::string &plugin, const std::string &pluginopts, bool libev, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
std::string socksConstruct(const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &username, const std::string &password, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool());
std::string httpConstruct(const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &username, const std::string &password, bool tls, tribool scv = tribool(), tribool tls13 = tribool());
std::string httpConstruct(const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &username, const std::string &password, bool tls, tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
std::string trojanConstruct(const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &host, bool tlssecure, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
std::string snellConstruct(const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &obfs, const std::string &host, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool());
void explodeVmess(std::string vmess, const std::string &custom_port, nodeInfo &node);
Expand Down
81 changes: 66 additions & 15 deletions src/subexport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ std::string socksConstruct(const std::string &group, const std::string &remarks,
return sb.GetString();
}

std::string httpConstruct(const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &username, const std::string &password, bool tls, tribool scv, tribool tls13)
std::string httpConstruct(const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &username, const std::string &password, bool tls, tribool tfo, tribool scv, tribool tls13)
{
rapidjson::StringBuffer sb;
rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
Expand All @@ -292,6 +292,13 @@ std::string httpConstruct(const std::string &group, const std::string &remarks,
writer.String(username.data());
writer.Key("Password");
writer.String(password.data());
writer.Key("TLSSecure");
writer.Bool(tls);
if(!tfo.is_undef())
{
writer.Key("EnableTFO");
writer.Bool(tfo);
}
if(!scv.is_undef())
{
writer.Key("AllowInsecure");
Expand Down Expand Up @@ -1540,8 +1547,18 @@ std::string netchToSurge(std::vector<nodeInfo> &nodes, const std::string &base_c
{
proxy = "custom, " + hostname + ", " + port + ", " + method + ", " + password + ", https://github.com/ConnersHua/SSEncrypt/raw/master/SSEncrypt.module";
}
if(plugin.size() && pluginopts.size())
proxy += "," + replace_all_distinct(pluginopts, ";", ",");
if(plugin.size())
{
switch(hash_(plugin))
{
case "simple-obfs"_hash:
if(pluginopts.size())
proxy += "," + replace_all_distinct(pluginopts, ";", ",");
break;
default:
continue;
}
}
break;
case SPEEDTEST_MESSAGE_FOUNDVMESS:
if(surge_ver < 4 && surge_ver != -3)
Expand Down Expand Up @@ -1638,10 +1655,10 @@ std::string netchToSurge(std::vector<nodeInfo> &nodes, const std::string &base_c
continue;
}

if(tfo)
proxy += ", tfo=true";
if(udp)
proxy += ", udp-relay=true";
if(!tfo.is_undef())
proxy += ", tfo=" + tfo.get_str();
if(!udp.is_undef())
proxy += ", udp-relay=" + udp.get_str();

if(ext.nodelist)
output_nodelist += remark + " = " + proxy + "\n";
Expand Down Expand Up @@ -2278,8 +2295,36 @@ void netchToQuanX(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<rule
plugin = GetMember(json, "Plugin");
pluginopts = GetMember(json, "PluginOption");
proxyStr = "shadowsocks = " + hostname + ":" + port + ", method=" + method + ", password=" + password;
if(plugin.size() && pluginopts.size())
proxyStr += ", " + replace_all_distinct(pluginopts, ";", ", ");
if(plugin.size())
{
switch(hash_(plugin))
{
case "simple-obfs"_hash:
if(pluginopts.size())
proxyStr += ", " + replace_all_distinct(pluginopts, ";", ", ");
break;
case "v2ray-plugin"_hash:
pluginopts = replace_all_distinct(pluginopts, ";", "&");
plugin = getUrlArg(pluginopts, "mode") == "websocket" ? "ws" : "";
host = getUrlArg(pluginopts, "host");
path = getUrlArg(pluginopts, "path");
tlssecure = pluginopts.find("tls") != pluginopts.npos;
if(tlssecure && plugin == "ws")
{
plugin += 's';
if(!tls13.is_undef())
proxyStr += ", tls13=" + std::string(tls13 ? "true" : "false");
}
proxyStr += ", obfs=" + plugin;
if(host.size())
proxyStr += ", obfs-host=" + host;
if(path.size())
proxyStr += ", obfs-uri=" + path;
break;
default: continue;
}
}

break;
case SPEEDTEST_MESSAGE_FOUNDSSR:
password = GetMember(json, "Password");
Expand All @@ -2301,7 +2346,11 @@ void netchToQuanX(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<rule

proxyStr = "http = " + hostname + ":" + port + ", username=" + (id.size() ? id : "none") + ", password=" + (password.size() ? password : "none");
if(tlssecure)
{
proxyStr += ", over-tls=true";
if(!tls13.is_undef())
proxyStr += ", tls13=" + std::string(tls13 ? "true" : "false");
}
break;
case SPEEDTEST_MESSAGE_FOUNDTROJAN:
password = GetMember(json, "Password");
Expand All @@ -2312,17 +2361,19 @@ void netchToQuanX(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<rule
if(tlssecure)
{
proxyStr += ", over-tls=true, tls-host=" + host;
if(!tls13.is_undef())
proxyStr += ", tls13=" + std::string(tls13 ? "true" : "false");
}
break;
default:
continue;
}
if(tfo)
proxyStr += ", fast-open=true";
if(udp)
proxyStr += ", udp-relay=true";
if(scv && (x.linkType == SPEEDTEST_MESSAGE_FOUNDHTTP || x.linkType == SPEEDTEST_MESSAGE_FOUNDTROJAN))
proxyStr += ", tls-verification=false";
if(!tfo.is_undef())
proxyStr += ", fast-open=" + tfo.get_str();
if(!udp.is_undef())
proxyStr += ", udp-relay=" + tfo.get_str();
if(!scv.is_undef() && (x.linkType == SPEEDTEST_MESSAGE_FOUNDHTTP || x.linkType == SPEEDTEST_MESSAGE_FOUNDTROJAN))
proxyStr += ", tls-verification=" + scv.reverse().get_str();
proxyStr += ", tag=" + remark;

ini.Set("{NONAME}", proxyStr);
Expand Down

0 comments on commit dc4eae3

Please sign in to comment.