Skip to content

Commit dc4eae3

Browse files
committed
Fix implementation of v2ray-plugin in Quantumult X subscriptions
Add example for using Clash proxy-provider. Optimize codes.
1 parent c4ef7ed commit dc4eae3

File tree

5 files changed

+142
-25
lines changed

5 files changed

+142
-25
lines changed

base/base/clash_provider_test.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
mixed-port: 7890
2+
allow-lan: true
3+
mode: Rule
4+
log-level: info
5+
external-controller: 127.0.0.1:9090
6+
proxy-providers:
7+
HK:
8+
type: http
9+
path: proxy-providers/HK.yaml
10+
url: {{ getLink("/sub?target=clash&list=true&include=HK&url=https%3A%2F%2Fexample.com%2Fsubscription") }}
11+
interval: 86400
12+
health-check:
13+
enable: true
14+
url: http://www.gstatic.com/generate_204
15+
interval: 300
16+
rule-providers: ~
17+
rules: ~

src/misc.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class tribool
162162

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

165-
explicit tribool(const tribool &value) { *this = value; }
165+
tribool(const tribool &value) { *this = value; }
166166

167167
~tribool() = default;
168168

@@ -194,13 +194,31 @@ class tribool
194194
return *this;
195195
}
196196

197+
tribool reverse()
198+
{
199+
_M_VALUE = _M_VALUE == -1 ? -1 : (_M_VALUE == 0 ? 1 : 0);
200+
return *this;
201+
}
202+
197203
bool get(const bool &def_value = false)
198204
{
199205
if(_M_VALUE == -1)
200206
return def_value;
201207
return _M_VALUE;
202208
}
203209

210+
std::string get_str()
211+
{
212+
switch(_M_VALUE)
213+
{
214+
case 0:
215+
return "false";
216+
case 1:
217+
return "true";
218+
}
219+
return "undef";
220+
}
221+
204222
template <typename T> bool set(const T &value)
205223
{
206224
_M_VALUE = value;

src/speedtestutil.cpp

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -903,7 +903,7 @@ void explodeNetch(std::string netch, bool ss_libev, bool ssr_libev, const std::s
903903
if(group.empty())
904904
group = HTTP_DEFAULT_GROUP;
905905
node.group = group;
906-
node.proxyStr = httpConstruct(group, remark, address, port, username, password, type == "HTTPS", scv);
906+
node.proxyStr = httpConstruct(group, remark, address, port, username, password, type == "HTTPS", tfo, scv);
907907
break;
908908
case "Trojan"_hash:
909909
host = GetMember(json, "Host");
@@ -1081,7 +1081,7 @@ void explodeClash(Node yamlnode, const std::string &custom_port, std::vector<nod
10811081
singleproxy["tls"] >>= tls;
10821082

10831083
node.linkType = SPEEDTEST_MESSAGE_FOUNDHTTP;
1084-
node.proxyStr = httpConstruct(group, ps, server, port, user, password, tls == "true", scv);
1084+
node.proxyStr = httpConstruct(group, ps, server, port, user, password, tls == "true", tfo, scv);
10851085
break;
10861086
case "trojan"_hash:
10871087
group = TROJAN_DEFAULT_GROUP;
@@ -1242,7 +1242,7 @@ bool explodeSurge(std::string surge, const std::string &custom_port, std::vector
12421242
for(auto &x : proxies)
12431243
{
12441244
std::string remarks, server, port, method, username, password; //common
1245-
std::string plugin, pluginopts, pluginopts_mode, pluginopts_host = "cloudfront.net", mod_url, mod_md5; //ss
1245+
std::string plugin, pluginopts, pluginopts_mode, pluginopts_host, mod_url, mod_md5; //ss
12461246
std::string id, net, tls, host, edge, path; //v2
12471247
std::string protocol, protoparam; //ssr
12481248
std::string itemName, itemVal, config;
@@ -1458,7 +1458,7 @@ bool explodeSurge(std::string surge, const std::string &custom_port, std::vector
14581458
default: continue;
14591459
}
14601460
}
1461-
node.proxyStr = httpConstruct(node.group, remarks, server, port, username, password, false, scv);
1461+
node.proxyStr = httpConstruct(node.group, remarks, server, port, username, password, false, tfo, scv);
14621462
break;
14631463
case "trojan"_hash: // surge 4 style trojan proxy
14641464
node.linkType = SPEEDTEST_MESSAGE_FOUNDTROJAN;
@@ -1546,10 +1546,28 @@ bool explodeSurge(std::string surge, const std::string &custom_port, std::vector
15461546
case "ssr-protocol"_hash: protocol = itemVal; break;
15471547
case "ssr-protocol-param"_hash: protoparam = itemVal; break;
15481548
case "obfs"_hash:
1549-
plugin = "simple-obfs";
1550-
pluginopts_mode = itemVal;
1549+
{
1550+
switch(hash_(itemVal))
1551+
{
1552+
case "http"_hash:
1553+
case "tls"_hash:
1554+
plugin = "simple-obfs";
1555+
pluginopts_mode = itemVal;
1556+
break;
1557+
case "wss"_hash:
1558+
tls = "tls";
1559+
[[fallthrough]];
1560+
case "ws"_hash:
1561+
pluginopts_mode = "websocket";
1562+
plugin = "v2ray-plugin";
1563+
break;
1564+
default:
1565+
pluginopts_mode = itemVal;
1566+
}
15511567
break;
1568+
}
15521569
case "obfs-host"_hash: pluginopts_host = itemVal; break;
1570+
case "obfs-uri"_hash: path = itemVal; break;
15531571
case "udp-relay"_hash: udp = itemVal; break;
15541572
case "fast-open"_hash: tfo = itemVal; break;
15551573
case "tls13"_hash: tls13 = itemVal; break;
@@ -1558,11 +1576,23 @@ bool explodeSurge(std::string surge, const std::string &custom_port, std::vector
15581576
}
15591577
if(remarks.empty())
15601578
remarks = server + ":" + port;
1561-
if(plugin.size())
1579+
switch(hash_(plugin))
15621580
{
1581+
case "simple-obfs"_hash:
15631582
pluginopts = "obfs=" + pluginopts_mode;
15641583
if(pluginopts_host.size())
15651584
pluginopts += ";obfs-host=" + pluginopts_host;
1585+
break;
1586+
case "v2ray-plugin"_hash:
1587+
if(pluginopts_host.empty() && !isIPv4(server) && !isIPv6(server))
1588+
pluginopts_host = server;
1589+
pluginopts = "mode=" + pluginopts_mode;
1590+
if(pluginopts_host.size())
1591+
pluginopts += ";host=" + pluginopts_host;
1592+
if(path.size())
1593+
pluginopts += ";path=" + path;
1594+
pluginopts += ";" + tls;
1595+
break;
15661596
}
15671597

15681598
if(protocol.size())
@@ -1681,6 +1711,7 @@ bool explodeSurge(std::string surge, const std::string &custom_port, std::vector
16811711
case "over-tls"_hash: tls = itemVal; break;
16821712
case "tls-verification"_hash: scv = itemVal == "false"; break;
16831713
case "tls13"_hash: tls13 = itemVal; break;
1714+
case "fast-open"_hash: tfo = itemVal; break;
16841715
default: continue;
16851716
}
16861717
}
@@ -1697,7 +1728,7 @@ bool explodeSurge(std::string surge, const std::string &custom_port, std::vector
16971728

16981729
node.linkType = SPEEDTEST_MESSAGE_FOUNDHTTP;
16991730
node.group = HTTP_DEFAULT_GROUP;
1700-
node.proxyStr = httpConstruct(node.group, remarks, server, port, username, password, tls == "true", scv, tls13);
1731+
node.proxyStr = httpConstruct(node.group, remarks, server, port, username, password, tls == "true", tfo, scv, tls13);
17011732
break;
17021733
default:
17031734
continue;

src/speedtestutil.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ std::string vmessConstruct(const std::string &group, const std::string &remarks,
1111
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());
1212
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());
1313
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());
14-
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());
14+
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());
1515
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());
1616
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());
1717
void explodeVmess(std::string vmess, const std::string &custom_port, nodeInfo &node);

src/subexport.cpp

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ std::string socksConstruct(const std::string &group, const std::string &remarks,
273273
return sb.GetString();
274274
}
275275

276-
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)
276+
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)
277277
{
278278
rapidjson::StringBuffer sb;
279279
rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
@@ -292,6 +292,13 @@ std::string httpConstruct(const std::string &group, const std::string &remarks,
292292
writer.String(username.data());
293293
writer.Key("Password");
294294
writer.String(password.data());
295+
writer.Key("TLSSecure");
296+
writer.Bool(tls);
297+
if(!tfo.is_undef())
298+
{
299+
writer.Key("EnableTFO");
300+
writer.Bool(tfo);
301+
}
295302
if(!scv.is_undef())
296303
{
297304
writer.Key("AllowInsecure");
@@ -1540,8 +1547,18 @@ std::string netchToSurge(std::vector<nodeInfo> &nodes, const std::string &base_c
15401547
{
15411548
proxy = "custom, " + hostname + ", " + port + ", " + method + ", " + password + ", https://github.com/ConnersHua/SSEncrypt/raw/master/SSEncrypt.module";
15421549
}
1543-
if(plugin.size() && pluginopts.size())
1544-
proxy += "," + replace_all_distinct(pluginopts, ";", ",");
1550+
if(plugin.size())
1551+
{
1552+
switch(hash_(plugin))
1553+
{
1554+
case "simple-obfs"_hash:
1555+
if(pluginopts.size())
1556+
proxy += "," + replace_all_distinct(pluginopts, ";", ",");
1557+
break;
1558+
default:
1559+
continue;
1560+
}
1561+
}
15451562
break;
15461563
case SPEEDTEST_MESSAGE_FOUNDVMESS:
15471564
if(surge_ver < 4 && surge_ver != -3)
@@ -1638,10 +1655,10 @@ std::string netchToSurge(std::vector<nodeInfo> &nodes, const std::string &base_c
16381655
continue;
16391656
}
16401657

1641-
if(tfo)
1642-
proxy += ", tfo=true";
1643-
if(udp)
1644-
proxy += ", udp-relay=true";
1658+
if(!tfo.is_undef())
1659+
proxy += ", tfo=" + tfo.get_str();
1660+
if(!udp.is_undef())
1661+
proxy += ", udp-relay=" + udp.get_str();
16451662

16461663
if(ext.nodelist)
16471664
output_nodelist += remark + " = " + proxy + "\n";
@@ -2278,8 +2295,36 @@ void netchToQuanX(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<rule
22782295
plugin = GetMember(json, "Plugin");
22792296
pluginopts = GetMember(json, "PluginOption");
22802297
proxyStr = "shadowsocks = " + hostname + ":" + port + ", method=" + method + ", password=" + password;
2281-
if(plugin.size() && pluginopts.size())
2282-
proxyStr += ", " + replace_all_distinct(pluginopts, ";", ", ");
2298+
if(plugin.size())
2299+
{
2300+
switch(hash_(plugin))
2301+
{
2302+
case "simple-obfs"_hash:
2303+
if(pluginopts.size())
2304+
proxyStr += ", " + replace_all_distinct(pluginopts, ";", ", ");
2305+
break;
2306+
case "v2ray-plugin"_hash:
2307+
pluginopts = replace_all_distinct(pluginopts, ";", "&");
2308+
plugin = getUrlArg(pluginopts, "mode") == "websocket" ? "ws" : "";
2309+
host = getUrlArg(pluginopts, "host");
2310+
path = getUrlArg(pluginopts, "path");
2311+
tlssecure = pluginopts.find("tls") != pluginopts.npos;
2312+
if(tlssecure && plugin == "ws")
2313+
{
2314+
plugin += 's';
2315+
if(!tls13.is_undef())
2316+
proxyStr += ", tls13=" + std::string(tls13 ? "true" : "false");
2317+
}
2318+
proxyStr += ", obfs=" + plugin;
2319+
if(host.size())
2320+
proxyStr += ", obfs-host=" + host;
2321+
if(path.size())
2322+
proxyStr += ", obfs-uri=" + path;
2323+
break;
2324+
default: continue;
2325+
}
2326+
}
2327+
22832328
break;
22842329
case SPEEDTEST_MESSAGE_FOUNDSSR:
22852330
password = GetMember(json, "Password");
@@ -2301,7 +2346,11 @@ void netchToQuanX(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<rule
23012346

23022347
proxyStr = "http = " + hostname + ":" + port + ", username=" + (id.size() ? id : "none") + ", password=" + (password.size() ? password : "none");
23032348
if(tlssecure)
2349+
{
23042350
proxyStr += ", over-tls=true";
2351+
if(!tls13.is_undef())
2352+
proxyStr += ", tls13=" + std::string(tls13 ? "true" : "false");
2353+
}
23052354
break;
23062355
case SPEEDTEST_MESSAGE_FOUNDTROJAN:
23072356
password = GetMember(json, "Password");
@@ -2312,17 +2361,19 @@ void netchToQuanX(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<rule
23122361
if(tlssecure)
23132362
{
23142363
proxyStr += ", over-tls=true, tls-host=" + host;
2364+
if(!tls13.is_undef())
2365+
proxyStr += ", tls13=" + std::string(tls13 ? "true" : "false");
23152366
}
23162367
break;
23172368
default:
23182369
continue;
23192370
}
2320-
if(tfo)
2321-
proxyStr += ", fast-open=true";
2322-
if(udp)
2323-
proxyStr += ", udp-relay=true";
2324-
if(scv && (x.linkType == SPEEDTEST_MESSAGE_FOUNDHTTP || x.linkType == SPEEDTEST_MESSAGE_FOUNDTROJAN))
2325-
proxyStr += ", tls-verification=false";
2371+
if(!tfo.is_undef())
2372+
proxyStr += ", fast-open=" + tfo.get_str();
2373+
if(!udp.is_undef())
2374+
proxyStr += ", udp-relay=" + tfo.get_str();
2375+
if(!scv.is_undef() && (x.linkType == SPEEDTEST_MESSAGE_FOUNDHTTP || x.linkType == SPEEDTEST_MESSAGE_FOUNDTROJAN))
2376+
proxyStr += ", tls-verification=" + scv.reverse().get_str();
23262377
proxyStr += ", tag=" + remark;
23272378

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

0 commit comments

Comments
 (0)