Skip to content

Commit 62c8d98

Browse files
committed
Improve VLESS support
1 parent 2e12c1c commit 62c8d98

File tree

4 files changed

+160
-9
lines changed

4 files changed

+160
-9
lines changed

src/generator/config/subexport.cpp

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,58 @@ void proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGr
620620
singleproxy["servername"] = x.SNI;
621621
if (!x.Alpn.empty())
622622
singleproxy["alpn"] = x.Alpn;
623+
624+
switch(hash_(x.TransferProtocol))
625+
{
626+
case "tcp"_hash:
627+
if(!x.Host.empty())
628+
singleproxy["host"] = x.Host;
629+
if(!x.Path.empty())
630+
singleproxy["path"] = x.Path;
631+
break;
632+
case "ws"_hash:
633+
singleproxy["network"] = x.TransferProtocol;
634+
if(ext.clash_new_field_name)
635+
{
636+
singleproxy["ws-opts"]["path"] = x.Path.empty() ? "/" : x.Path;
637+
if(!x.Host.empty())
638+
singleproxy["ws-opts"]["headers"]["Host"] = x.Host;
639+
if(!x.Edge.empty())
640+
singleproxy["ws-opts"]["headers"]["Edge"] = x.Edge;
641+
}
642+
else
643+
{
644+
singleproxy["ws-path"] = x.Path.empty() ? "/" : x.Path;
645+
if(!x.Host.empty())
646+
singleproxy["ws-headers"]["Host"] = x.Host;
647+
if(!x.Edge.empty())
648+
singleproxy["ws-headers"]["Edge"] = x.Edge;
649+
}
650+
break;
651+
case "http"_hash:
652+
singleproxy["network"] = x.TransferProtocol;
653+
singleproxy["http-opts"]["method"] = "GET";
654+
singleproxy["http-opts"]["path"].push_back(x.Path.empty() ? "/" : x.Path);
655+
if(!x.Host.empty())
656+
singleproxy["http-opts"]["headers"]["Host"].push_back(x.Host);
657+
if(!x.Edge.empty())
658+
singleproxy["http-opts"]["headers"]["Edge"].push_back(x.Edge);
659+
break;
660+
case "h2"_hash:
661+
singleproxy["network"] = x.TransferProtocol;
662+
singleproxy["h2-opts"]["path"] = x.Path.empty() ? "/" : x.Path;
663+
if(!x.Host.empty())
664+
singleproxy["h2-opts"]["host"].push_back(x.Host);
665+
break;
666+
case "grpc"_hash:
667+
singleproxy["network"] = x.TransferProtocol;
668+
singleproxy["grpc-opts"]["grpc-mode"] = x.GRPCMode;
669+
singleproxy["grpc-opts"]["grpc-service-name"] = x.GRPCServiceName;
670+
break;
671+
default:
672+
continue;
673+
}
674+
623675
if (!x.Fingerprint.empty())
624676
singleproxy["fingerprint"] = x.Fingerprint;
625677
if (x.XTLS == 2) {
@@ -2668,14 +2720,18 @@ void proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::v
26682720
tls.AddMember("reality", reality, allocator);
26692721

26702722
rapidjson::Value utls(rapidjson::kObjectType);
2671-
utls.AddMember("enable",true,allocator);
2723+
utls.AddMember("enabled",true,allocator);
26722724
std::array<std::string, 6> fingerprints = {"chrome", "firefox", "safari", "ios", "edge", "qq"};
26732725
utls.AddMember("fingerprint", rapidjson::Value(fingerprints[rand() % fingerprints.size()].c_str(), allocator), allocator);
26742726
tls.AddMember("utls", utls, allocator);
26752727
}
26762728

26772729
proxy.AddMember("tls", tls, allocator);
2678-
2730+
2731+
auto transport = buildSingBoxTransport(x, allocator);
2732+
if (!transport.ObjectEmpty())
2733+
proxy.AddMember("transport", transport, allocator);
2734+
26792735
break;
26802736
}
26812737

src/parser/config/proxy.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ struct Proxy
9797
String QUICSecure;
9898
String QUICSecret;
9999

100+
String GRPCServiceName;
101+
String GRPCMode;
102+
100103
tribool UDP;
101104
tribool TCPFastOpen;
102105
tribool AllowInsecure;

src/parser/subparser.cpp

Lines changed: 94 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,11 @@ void vlessConstruct(
332332
const std::string &uuid,
333333
const std::string &sni,
334334
const std::string &alpn,
335+
const std::string &type,
336+
const std::string &net,
337+
const std::string &mode,
338+
const std::string &host,
339+
const std::string &path,
335340
const std::string &fingerprint,
336341
const std::string &flow,
337342
const std::string &xtls,
@@ -344,6 +349,23 @@ void vlessConstruct(
344349
commonConstruct(node, ProxyType::VLESS, group, remarks, server, port, tribool(), tfo, scv, tribool(), underlying_proxy);
345350
node.UUID = uuid;
346351
node.SNI = sni;
352+
node.TransferProtocol = net.empty() ? "tcp" : net;
353+
switch(hash_(net))
354+
{
355+
case "grpc"_hash:
356+
node.Host = host;
357+
node.GRPCMode = mode.empty() ? "gun" : mode;
358+
node.GRPCServiceName = path.empty() ? "/" : urlEncode(urlDecode(trim(path)));
359+
break;
360+
case "quic"_hash:
361+
node.QUICSecure = host;
362+
node.QUICSecret = path.empty() ? "/" : trim(path);
363+
break;
364+
default:
365+
node.Host = (host.empty() && !isIPv4(server) && !isIPv6(server)) ? server.data() : trim(host);
366+
node.Path = path.empty() ? "/" : urlDecode(trim(path));
367+
break;
368+
}
347369
if (!alpn.empty()) {
348370
node.Alpn = StringArray{alpn};
349371
}
@@ -1198,7 +1220,7 @@ void explodeNetch(std::string netch, Proxy &node)
11981220
void explodeClash(Node yamlnode, std::vector<Proxy> &nodes)
11991221
{
12001222
std::string proxytype, ps, server, port, cipher, group, password, underlying_proxy; //common
1201-
std::string type = "none", id, aid = "0", net = "tcp", path, host, edge, tls, sni; //vmess
1223+
std::string type = "none", id, aid = "0", net = "tcp", path, host, edge, tls, sni, mode; //vmess/vless
12021224
std::string plugin, pluginopts, pluginopts_mode, pluginopts_host, pluginopts_mux; //ss
12031225
std::string protocol, protoparam, obfs, obfsparam; //ssr
12041226
std::string user; //socks
@@ -1274,10 +1296,11 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes)
12741296

12751297
vmessConstruct(node, group, ps, server, port, "", id, aid, net, cipher, path, host, edge, tls, sni, udp, tfo, scv, tribool(), underlying_proxy);
12761298
break;
1277-
case "vless"_hash: {
1299+
case "vless"_hash: {
12781300
group = VLESS_DEFAULT_GROUP;
12791301
singleproxy["uuid"] >>= uuid;
12801302
singleproxy["servername"] >>= sni;
1303+
net = singleproxy["network"].IsDefined() ? safe_as<std::string>(singleproxy["network"]) : "tcp";
12811304
if (singleproxy["alpn"].IsSequence())
12821305
singleproxy["alpn"][0] >>= alpn;
12831306
else
@@ -1288,10 +1311,47 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes)
12881311
singleproxy["reality-opts"]["public-key"] >>= public_key;
12891312
singleproxy["reality-opts"]["short-id"] >>= short_id;
12901313
}
1291-
vlessConstruct(node, group, ps, server, port, uuid, sni, alpn, fingerprint, flow, xtls, public_key, short_id, tfo, scv, underlying_proxy);
1314+
switch (hash_(net))
1315+
{
1316+
case "ws"_hash:
1317+
if (singleproxy["ws-opts"].IsDefined())
1318+
{
1319+
path = singleproxy["ws-opts"]["path"].IsDefined() ? safe_as<std::string>(singleproxy["ws-opts"]["path"]) : "/";
1320+
singleproxy["ws-opts"]["headers"]["Host"] >>= host;
1321+
}
1322+
else
1323+
{
1324+
path = singleproxy["ws-path"].IsDefined() ? safe_as<std::string>(singleproxy["ws-path"]) : "/";
1325+
singleproxy["ws-headers"]["Host"] >>= host;
1326+
}
1327+
break;
1328+
case "http"_hash:
1329+
path = singleproxy["http-opts"]["path"][0].IsDefined() ? safe_as<std::string>(singleproxy["http-opts"]["path"][0]) : "/";
1330+
if (singleproxy["http-opts"]["headers"]["Host"][0].IsDefined())
1331+
singleproxy["http-opts"]["headers"]["Host"][0] >>= host;
1332+
break;
1333+
case "h2"_hash:
1334+
singleproxy["h2-opts"]["path"] >>= path;
1335+
singleproxy["h2-opts"]["host"][0] >>= host;
1336+
break;
1337+
case "grpc"_hash:
1338+
singleproxy["servername"] >>= host;
1339+
singleproxy["grpc-opts"]["grpc-service-name"] >>= path;
1340+
singleproxy["grpc-opts"]["grpc-mode"] >>= mode;
1341+
break;
1342+
case "quic"_hash:
1343+
singleproxy["quic-opts"]["security"] >>= host;
1344+
singleproxy["quic-opts"]["key"] >>= path;
1345+
break;
1346+
default:
1347+
singleproxy["host"] >>= host;
1348+
singleproxy["path"] >>= path;
1349+
break;
1350+
}
1351+
vlessConstruct(node, group, ps, server, port, uuid, sni, alpn, type, net, mode, host, path, fingerprint, flow, xtls, public_key, short_id, tfo, scv, underlying_proxy);
12921352
break;
12931353
}
1294-
case "ss"_hash:
1354+
case "ss"_hash:
12951355
group = SS_DEFAULT_GROUP;
12961356

12971357
singleproxy["cipher"] >>= cipher;
@@ -1851,7 +1911,7 @@ void explodeAnyTLS(std::string anytls, Proxy &node) {
18511911
}
18521912

18531913
void explodeStdVLESS(std::string vless, Proxy &node) {
1854-
std::string add, port, uuid, sni, alpn, fingerprint, remarks, addition, flow, xtls, public_key, short_id;
1914+
std::string add, port, uuid, sni, alpn, net, type, mode, host, path, fingerprint, remarks, addition, flow, xtls, public_key, short_id;
18551915
tribool tfo, scv;
18561916
std::string decoded, userinfo, hostinfo;
18571917
string_array user_parts;
@@ -1906,14 +1966,41 @@ void explodeStdVLESS(std::string vless, Proxy &node) {
19061966
if (sni.empty()) {
19071967
sni = getUrlArg(addition, "peer");
19081968
}
1969+
net = getUrlArg(addition,"type");
19091970
alpn = getUrlArg(addition, "alpn");
19101971
fingerprint = getUrlArg(addition, "hpkp");
19111972
flow = getUrlArg(addition, "flow");
19121973
xtls = getUrlArg(addition, "xtls");
19131974
public_key = getUrlArg(addition, "pbk");
19141975
short_id = getUrlArg(addition, "sid");
19151976
tfo = tribool(getUrlArg(addition, "tfo"));
1916-
scv = tribool(getUrlArg(addition, "insecure"));
1977+
std::string insecure_val = getUrlArg(addition, "insecure");
1978+
if (insecure_val.empty())
1979+
insecure_val = getUrlArg(addition, "allowInsecure");
1980+
scv = tribool(insecure_val);
1981+
1982+
switch(hash_(net))
1983+
{
1984+
case "tcp"_hash:
1985+
case "ws"_hash:
1986+
case "h2"_hash:
1987+
type = getUrlArg(addition, "headerType");
1988+
host = getUrlArg(addition, strFind(addition,"sni") ? "sni" : "host");
1989+
path = getUrlArg(addition, "path");
1990+
break;
1991+
case "grpc"_hash:
1992+
host = getUrlArg(addition, "sni");
1993+
path = getUrlArg(addition, "serviceName");
1994+
mode = getUrlArg(addition, "mode");
1995+
break;
1996+
case "quic"_hash:
1997+
type = getUrlArg(addition, "headerType");
1998+
host = getUrlArg(addition, strFind(addition,"sni") ? "sni" : "quicSecurity");
1999+
path = getUrlArg(addition, "key");
2000+
break;
2001+
default:
2002+
return;
2003+
}
19172004

19182005
if (remarks.empty()) {
19192006
remarks = urlDecode(getUrlArg(addition, "remark"));
@@ -1925,7 +2012,7 @@ void explodeStdVLESS(std::string vless, Proxy &node) {
19252012
if (remarks.empty())
19262013
remarks = add + ":" + port;
19272014

1928-
vlessConstruct(node, VLESS_DEFAULT_GROUP, remarks, add, port, uuid, sni, alpn, fingerprint, flow, xtls, public_key, short_id, tfo, scv, "");
2015+
vlessConstruct(node, VLESS_DEFAULT_GROUP, remarks, add, port, uuid, sni, alpn, type, net, mode, host, path, fingerprint, flow, xtls, public_key, short_id, tfo, scv, "");
19292016
}
19302017

19312018
void explodeVLESS(std::string vless, Proxy &node) {

src/parser/subparser.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ void vlessConstruct(
135135
const std::string &uuid,
136136
const std::string &sni,
137137
const std::string &alpn,
138+
const std::string &type,
139+
const std::string &net,
140+
const std::string &mode,
141+
const std::string &host,
142+
const std::string &path,
138143
const std::string &fingerprint,
139144
const std::string &flow,
140145
const std::string &xtls,

0 commit comments

Comments
 (0)