Skip to content

Commit 5abcec1

Browse files
committed
Add VLESS reality support
1 parent 6f7e56e commit 5abcec1

File tree

4 files changed

+233
-3
lines changed

4 files changed

+233
-3
lines changed

src/generator/config/subexport.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,30 @@ void proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGr
609609
if (!scv.is_undef())
610610
singleproxy["skip-cert-verify"] = scv.get();
611611
break;
612+
case ProxyType::VLESS:
613+
singleproxy["type"] = "vless";
614+
singleproxy["packet-encoding"] = "xudp";
615+
singleproxy["tls"] = true;
616+
if (!x.UUID.empty())
617+
singleproxy["uuid"] = x.UUID;
618+
if (!x.SNI.empty())
619+
singleproxy["servername"] = x.SNI;
620+
if (!x.Alpn.empty())
621+
singleproxy["alpn"] = x.Alpn;
622+
if (!x.Fingerprint.empty())
623+
singleproxy["fingerprint"] = x.Fingerprint;
624+
if (!x.Flow.empty())
625+
singleproxy["flow"] = x.Flow;
626+
if (x.XTLS == 2) {
627+
singleproxy["flow"] = "xtls-rprx-vision";
628+
}
629+
if (!x.PublicKey.empty() && !x.ShortID.empty()) {
630+
singleproxy["reality-opts"]["public-key"] = x.PublicKey;
631+
singleproxy["reality-opts"]["short-id"] = x.ShortID;
632+
}
633+
if (!scv.is_undef())
634+
singleproxy["skip-cert-verify"] = scv.get();
635+
break;
612636
default:
613637
continue;
614638
}
@@ -2590,6 +2614,52 @@ void proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::v
25902614

25912615
break;
25922616
}
2617+
2618+
case ProxyType::VLESS:
2619+
{
2620+
addSingBoxCommonMembers(proxy, x, "vless", allocator);
2621+
proxy.AddMember("packet_encoding", "xudp", allocator);
2622+
2623+
if (!x.UUID.empty())
2624+
proxy.AddMember("uuid", rapidjson::StringRef(x.UUID.c_str()), allocator);
2625+
2626+
if (!x.SNI.empty())
2627+
proxy.AddMember("sni", rapidjson::StringRef(x.SNI.c_str()), allocator);
2628+
2629+
if (!x.Flow.empty())
2630+
proxy.AddMember("flow", rapidjson::StringRef(x.Flow.c_str()), allocator);
2631+
2632+
// TLS 配置
2633+
rapidjson::Value tls(rapidjson::kObjectType);
2634+
tls.AddMember("enabled", true, allocator);
2635+
2636+
if (!scv.is_undef())
2637+
tls.AddMember("insecure", scv.get(), allocator);
2638+
if (!x.Fingerprint.empty())
2639+
tls.AddMember("fingerprint", rapidjson::StringRef(x.Fingerprint.c_str()), allocator);
2640+
if (!x.Alpn.empty()) {
2641+
rapidjson::Value alpn(rapidjson::kArrayType);
2642+
for (const auto& item : x.Alpn)
2643+
alpn.PushBack(rapidjson::StringRef(item.c_str()), allocator);
2644+
tls.AddMember("alpn", alpn, allocator);
2645+
}
2646+
if (x.XTLS == 2){
2647+
if (!x.PublicKey.empty() && !x.ShortID.empty()) {
2648+
rapidjson::Value reality(rapidjson::kObjectType);
2649+
reality.AddMember("enabled", true, allocator);
2650+
if (!x.PublicKey.empty())
2651+
reality.AddMember("public_key", rapidjson::StringRef(x.PublicKey.c_str()), allocator);
2652+
if (!x.ShortID.empty())
2653+
reality.AddMember("short_id", rapidjson::StringRef(x.ShortID.c_str()), allocator);
2654+
tls.AddMember("reality", reality, allocator);
2655+
}
2656+
}
2657+
2658+
proxy.AddMember("tls", tls, allocator);
2659+
2660+
break;
2661+
}
2662+
25932663
case ProxyType::HTTP:
25942664
case ProxyType::HTTPS:
25952665
{

src/parser/config/proxy.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ enum class ProxyType
1515
Shadowsocks,
1616
ShadowsocksR,
1717
VMess,
18+
VLESS,
1819
Trojan,
1920
Snell,
2021
HTTP,
@@ -37,6 +38,8 @@ inline String getProxyTypeName(ProxyType type)
3738
return "SSR";
3839
case ProxyType::VMess:
3940
return "VMess";
41+
case ProxyType::VLESS:
42+
return "VLESS";
4043
case ProxyType::Trojan:
4144
return "Trojan";
4245
case ProxyType::Snell:
@@ -149,11 +152,18 @@ struct Proxy
149152
uint32_t IdleSessionCheckInterval;
150153
uint32_t IdleSessionTimeout;
151154
uint32_t MinIdleSession;
155+
156+
String Flow;
157+
uint32_t XTLS;
158+
String PacketEncoding;
159+
String ShortID;
160+
152161
};
153162

154163
#define SS_DEFAULT_GROUP "SSProvider"
155164
#define SSR_DEFAULT_GROUP "SSRProvider"
156165
#define V2RAY_DEFAULT_GROUP "V2RayProvider"
166+
#define VLESS_DEFAULT_GROUP "VLESSProvider"
157167
#define SOCKS_DEFAULT_GROUP "SocksProvider"
158168
#define HTTP_DEFAULT_GROUP "HTTPProvider"
159169
#define TROJAN_DEFAULT_GROUP "TrojanProvider"

src/parser/subparser.cpp

Lines changed: 133 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,37 @@ void anytlsConstruct(
323323
node.MinIdleSession = to_int(min_idle_session);
324324
}
325325

326+
void vlessConstruct(
327+
Proxy &node,
328+
const std::string &group,
329+
const std::string &remarks,
330+
const std::string &server,
331+
const std::string &port,
332+
const std::string &uuid,
333+
const std::string &sni,
334+
const std::string &alpn,
335+
const std::string &fingerprint,
336+
const std::string &flow,
337+
const std::string &xtls,
338+
const std::string &public_key,
339+
const std::string &short_id,
340+
tribool tfo,
341+
tribool scv,
342+
const std::string &underlying_proxy
343+
) {
344+
commonConstruct(node, ProxyType::VLESS, group, remarks, server, port, tribool(), tfo, scv, tribool(), underlying_proxy);
345+
node.UUID = uuid;
346+
node.SNI = sni;
347+
if (!alpn.empty()) {
348+
node.Alpn = StringArray{alpn};
349+
}
350+
node.Fingerprint = fingerprint;
351+
node.Flow = flow;
352+
node.XTLS = to_int(xtls);
353+
node.PublicKey = public_key;
354+
node.ShortID = short_id;
355+
}
356+
326357
void explodeVmess(std::string vmess, Proxy &node)
327358
{
328359
std::string version, ps, add, port, type, id, aid, net, path, host, tls, sni;
@@ -1176,6 +1207,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes)
11761207
std::string obfs_password, cwnd; //hysteria2
11771208
std::string uuid,/*ip , password*/ heartbeat_interval, disable_sni, reduce_rtt, request_timeout, udp_relay_mode, congestion_controller, max_udp_relay_packet_size, max_open_streams, fast_open; //TUIC
11781209
std::string idle_session_check_interval, idle_session_timeout, min_idle_session;
1210+
std::string flow, xtls, short_id;
11791211

11801212
string_array dns_server;
11811213
tribool udp, tfo, scv;
@@ -1242,7 +1274,24 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes)
12421274

12431275
vmessConstruct(node, group, ps, server, port, "", id, aid, net, cipher, path, host, edge, tls, sni, udp, tfo, scv, tribool(), underlying_proxy);
12441276
break;
1245-
case "ss"_hash:
1277+
case "vless"_hash: {
1278+
group = VLESS_DEFAULT_GROUP;
1279+
singleproxy["uuid"] >>= uuid;
1280+
singleproxy["servername"] >>= sni;
1281+
if (singleproxy["alpn"].IsSequence())
1282+
singleproxy["alpn"][0] >>= alpn;
1283+
else
1284+
singleproxy["alpn"] >>= alpn;
1285+
singleproxy["fingerprint"] >>= fingerprint;
1286+
singleproxy["flow"] >>= flow;
1287+
if (singleproxy["reality-opts"].IsDefined()) {
1288+
singleproxy["reality-opts"]["public-key"] >>= public_key;
1289+
singleproxy["reality-opts"]["short-id"] >>= short_id;
1290+
}
1291+
vlessConstruct(node, group, ps, server, port, uuid, sni, alpn, fingerprint, flow, xtls, public_key, short_id, tfo, scv, underlying_proxy);
1292+
break;
1293+
}
1294+
case "ss"_hash:
12461295
group = SS_DEFAULT_GROUP;
12471296

12481297
singleproxy["cipher"] >>= cipher;
@@ -1801,6 +1850,85 @@ void explodeAnyTLS(std::string anytls, Proxy &node) {
18011850
}
18021851
}
18031852

1853+
void explodeStdVLESS(std::string vless, Proxy &node) {
1854+
std::string add, port, uuid, sni, alpn, fingerprint, remarks, addition, flow, xtls, public_key, short_id;
1855+
tribool tfo, scv;
1856+
std::string decoded, userinfo, hostinfo;
1857+
string_array user_parts;
1858+
1859+
vless = vless.substr(8);
1860+
string_size pos;
1861+
1862+
pos = vless.rfind("#");
1863+
if (pos != vless.npos) {
1864+
remarks = urlDecode(vless.substr(pos + 1));
1865+
vless.erase(pos);
1866+
}
1867+
1868+
pos = vless.rfind("?");
1869+
if (pos != vless.npos) {
1870+
addition = vless.substr(pos + 1);
1871+
vless.erase(pos);
1872+
}
1873+
1874+
decoded = urlSafeBase64Decode(vless);
1875+
1876+
// 尝试从URL参数中获取uuid
1877+
uuid = getUrlArg(addition, "uuid");
1878+
1879+
// 如果URL参数中没有uuid,尝试从decoded中解析
1880+
if (uuid.empty() && strFind(decoded, "@") && strFind(decoded, ":")) {
1881+
userinfo = decoded.substr(0, decoded.find('@'));
1882+
hostinfo = decoded.substr(decoded.find('@') + 1);
1883+
1884+
if (strFind(userinfo, ":")) {
1885+
user_parts = split(userinfo, ":");
1886+
if (user_parts.size() >= 2) {
1887+
uuid = user_parts[1];
1888+
}
1889+
} else {
1890+
uuid = userinfo;
1891+
}
1892+
1893+
if (regGetMatch(hostinfo, R"(^(.*?):(\d+)$)", 3, 0, &add, &port) != 0)
1894+
return;
1895+
} else if (regGetMatch(vless, R"(^(.*?):(\d+)$)", 3, 0, &add, &port) != 0) {
1896+
return;
1897+
}
1898+
1899+
if (uuid.empty()) return;
1900+
1901+
if (!addition.empty()) {
1902+
sni = getUrlArg(addition, "peer");
1903+
alpn = getUrlArg(addition, "alpn");
1904+
fingerprint = getUrlArg(addition, "hpkp");
1905+
flow = getUrlArg(addition, "flow");
1906+
xtls = getUrlArg(addition, "xtls");
1907+
public_key = getUrlArg(addition, "pbk");
1908+
short_id = getUrlArg(addition, "sid");
1909+
tfo = tribool(getUrlArg(addition, "tfo"));
1910+
scv = tribool(getUrlArg(addition, "insecure"));
1911+
1912+
if (remarks.empty()) {
1913+
remarks = urlDecode(getUrlArg(addition, "remark"));
1914+
if (remarks.empty())
1915+
remarks = urlDecode(getUrlArg(addition, "remarks"));
1916+
}
1917+
}
1918+
1919+
if (remarks.empty())
1920+
remarks = add + ":" + port;
1921+
1922+
vlessConstruct(node, VLESS_DEFAULT_GROUP, remarks, add, port, uuid, sni, alpn, fingerprint, flow, xtls, public_key, short_id, tfo, scv, "");
1923+
}
1924+
1925+
void explodeVLESS(std::string vless, Proxy &node) {
1926+
vless = regReplace(vless, "(vless)://", "vless://");
1927+
// replace /? with ?
1928+
vless = regReplace(vless, "/\\?", "?", true, false);
1929+
explodeStdVLESS(vless, node);
1930+
}
1931+
18041932
// peer = (public-key = bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=, allowed-ips = "0.0.0.0/0, ::/0", endpoint = engage.cloudflareclient.com:2408, client-id = 139/184/125),(public-key = bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=, endpoint = engage.cloudflareclient.com:2408)
18051933
void parsePeers(Proxy &node, const std::string &data)
18061934
{
@@ -2698,10 +2826,12 @@ void explode(const std::string &link, Proxy &node)
26982826
explodeTrojan(link, node);
26992827
else if (strFind(link, "hysteria2://") || strFind(link, "hy2://"))
27002828
explodeHysteria2(link, node);
2701-
else if (strFind(link, "tuic://") || strFind(link, "tuic://"))
2829+
else if (strFind(link, "tuic://"))
27022830
explodeTUIC(link, node);
2703-
else if (strFind(link, "anytls://") || strFind(link, "anytls://"))
2831+
else if (strFind(link, "anytls://"))
27042832
explodeAnyTLS(link, node);
2833+
else if (strFind(link, "vless://"))
2834+
explodeVLESS(link, node);
27052835
else if(isLink(link))
27062836
explodeHTTPSub(link, node);
27072837
}

src/parser/subparser.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,25 @@ void anytlsConstruct(
126126
const std::string &underlying_proxy = ""
127127
);
128128

129+
void vlessConstruct(
130+
Proxy &node,
131+
const std::string &group,
132+
const std::string &remarks,
133+
const std::string &server,
134+
const std::string &port,
135+
const std::string &uuid,
136+
const std::string &sni,
137+
const std::string &alpn,
138+
const std::string &fingerprint,
139+
const std::string &flow,
140+
const std::string &xtls,
141+
const std::string &public_key,
142+
const std::string &short_id,
143+
tribool tfo,
144+
tribool scv,
145+
const std::string &underlying_proxy = ""
146+
);
147+
129148
void explodeVmess(std::string vmess, Proxy &node);
130149
void explodeSSR(std::string ssr, Proxy &node);
131150
void explodeSS(std::string ss, Proxy &node);
@@ -137,6 +156,7 @@ void explodeKitsunebi(std::string kit, Proxy &node);
137156
void explodeHysteria2(std::string hysteria2, Proxy &node);
138157
void explodeTUIC(std::string tuic, Proxy &node);
139158
void explodeAnyTLS(std::string anytls, Proxy &node);
159+
void explodeVLESS(std::string vless, Proxy &node);
140160

141161
/// Parse a link
142162
void explode(const std::string &link, Proxy &node);

0 commit comments

Comments
 (0)