Merge pull request #77 from fortressme/master

keep dialer-proxy when converting Clash subscriptions
This commit is contained in:
asdlokj1qpi23
2026-03-18 16:16:13 +08:00
committed by GitHub
2 changed files with 52 additions and 34 deletions

View File

@@ -705,6 +705,8 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
// sees in https://dreamacro.github.io/clash/configuration/outbound.html#snell
if (udp && x.Type != ProxyType::Snell && x.Type != ProxyType::TUIC)
singleproxy["udp"] = true;
if (!clashR && !x.UnderlyingProxy.empty())
singleproxy["dialer-proxy"] = x.UnderlyingProxy;
if (proxy_block)
singleproxy.SetStyle(YAML::EmitterStyle::Block);
else
@@ -2960,6 +2962,9 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json,
}
proxy.AddMember("tls", tls, allocator);
}
if (!x.UnderlyingProxy.empty()) {
proxy.AddMember("detour", rapidjson::Value(x.UnderlyingProxy.c_str(), allocator), allocator);
}
if (!udp.is_undef() && !udp) {
proxy.AddMember("network", "tcp", allocator);
}

View File

@@ -1196,6 +1196,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
std::string auth, up, down, obfsParam, insecure, alpn; //hysteria
std::string obfsPassword; //hysteria2
std::string congestion_control, udp_relay_mode, token; // tuic
std::string underlying_proxy;
string_array dns_server;
std::vector<String> alpns;
String alpn2;
@@ -1216,6 +1217,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
continue;
udp = safe_as<std::string>(singleproxy["udp"]);
scv = safe_as<std::string>(singleproxy["skip-cert-verify"]);
singleproxy["dialer-proxy"] >>= underlying_proxy;
switch (hash_(proxytype)) {
case "vmess"_hash:
singleproxy["uuid"] >>= id;
@@ -1267,7 +1269,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["alpn"] >>= alpnList;
vmessConstruct(node, group, ps, server, port, "", id, aid, net, cipher, path, host, edge, tls, sni,
alpnList, udp,
tfo, scv);
tfo, scv, tribool(), underlying_proxy);
break;
case "ss"_hash:
group = SS_DEFAULT_GROUP;
@@ -1328,7 +1330,8 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
std::transform(cipher.begin(), cipher.end(), cipher.begin(), ::tolower);
}
ssConstruct(node, group, ps, server, port, password, cipher, plugin, pluginopts, udp, tfo, scv);
ssConstruct(node, group, ps, server, port, password, cipher, plugin, pluginopts, udp, tfo, scv,
tribool(), underlying_proxy);
break;
case "socks5"_hash:
group = SOCKS_DEFAULT_GROUP;
@@ -1336,7 +1339,8 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["username"] >>= user;
singleproxy["password"] >>= password;
socksConstruct(node, group, ps, server, port, user, password);
socksConstruct(node, group, ps, server, port, user, password, tribool(), tribool(), tribool(),
underlying_proxy);
break;
case "ssr"_hash:
group = SSR_DEFAULT_GROUP;
@@ -1356,7 +1360,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["obfsparam"] >>= obfsparam;
ssrConstruct(node, group, ps, server, port, protocol, cipher, obfs, password, obfsparam, protoparam,
udp, tfo, scv);
udp, tfo, scv, underlying_proxy);
break;
case "http"_hash:
group = HTTP_DEFAULT_GROUP;
@@ -1365,7 +1369,8 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["password"] >>= password;
singleproxy["tls"] >>= tls;
httpConstruct(node, group, ps, server, port, user, password, tls == "true", tfo, scv);
httpConstruct(node, group, ps, server, port, user, password, tls == "true", tfo, scv, tribool(),
underlying_proxy);
break;
case "trojan"_hash:
group = TROJAN_DEFAULT_GROUP;
@@ -1387,8 +1392,8 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
}
singleproxy["alpn"] >>= alpnList;
trojanConstruct(node, group, ps, server, port, password, net, host, path, fp, sni, alpnList, true, udp,
tfo, scv);
trojanConstruct(node, group, ps, server, port, password, net, host, path, fp, sni, alpnList, true,
udp, tfo, scv, tribool(), underlying_proxy);
break;
case "snell"_hash:
group = SNELL_DEFAULT_GROUP;
@@ -1397,7 +1402,8 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["obfs-opts"]["host"] >>= host;
singleproxy["version"] >>= aid;
snellConstruct(node, group, ps, server, port, password, obfs, host, to_int(aid, 0), udp, tfo, scv);
snellConstruct(node, group, ps, server, port, password, obfs, host, to_int(aid, 0), udp, tfo, scv,
underlying_proxy);
break;
case "wireguard"_hash:
group = WG_DEFAULT_GROUP;
@@ -1410,7 +1416,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["ipv6"] >>= ipv6;
wireguardConstruct(node, group, ps, server, port, ip, ipv6, private_key, public_key, password,
dns_server, mtu, "0", "", "", udp, "");
dns_server, mtu, "0", "", "", udp, underlying_proxy);
break;
case "vless"_hash:
group = XRAY_DEFAULT_GROUP;
@@ -1481,9 +1487,9 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["encryption"] >>= encryption;
bool vless_udp;
singleproxy["udp"] >> vless_udp;
vlessConstruct(node, XRAY_DEFAULT_GROUP, ps, server, port, type, id, aid, net, "auto", flow, mode, path,
host, "", tls, pbk, sid, fp, sni, alpnList, packet_encoding, encryption, udp, tribool(), tribool(),
tribool(), "", v2ray_http_upgrade);
vlessConstruct(node, XRAY_DEFAULT_GROUP, ps, server, port, type, id, aid, net, "auto", flow, mode,
path, host, "", tls, pbk, sid, fp, sni, alpnList, packet_encoding, encryption, udp,
tribool(), tribool(), tribool(), underlying_proxy, v2ray_http_upgrade);
break;
case "hysteria"_hash:
group = HYSTERIA_DEFAULT_GROUP;
@@ -1506,7 +1512,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
sni = host;
hysteriaConstruct(node, group, ps, server, port, type, auth, "", host, up, down, alpn, obfsParam,
insecure, ports, sni,
udp, tfo, scv);
udp, tfo, scv, tribool(), underlying_proxy);
break;
case "hysteria2"_hash:
group = HYSTERIA2_DEFAULT_GROUP;
@@ -1538,7 +1544,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["ports"] >> ports;
sni = host;
hysteria2Construct(node, group, ps, server, port, password, host, up, down, alpn, obfsParam,
obfsPassword, sni, public_key, ports, udp, tfo, scv);
obfsPassword, sni, public_key, ports, udp, tfo, scv, underlying_proxy);
break;
case "tuic"_hash:
group = TUIC_DEFAULT_GROUP;
@@ -1558,7 +1564,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
tuicConstruct(node, TUIC_DEFAULT_GROUP, ps, server, port, password, congestion_control, alpn, sni, id,
udp_relay_mode, token,
tribool(),
tribool(), scv, reduceRtt, disableSni, request_timeout);
tribool(), scv, reduceRtt, disableSni, request_timeout, underlying_proxy);
break;
case "anytls"_hash:
@@ -1577,7 +1583,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["fingerprint"] >>= fingerprint;
anyTlSConstruct(node, ANYTLS_DEFAULT_GROUP, ps, port, password, server, alpns, fingerprint, sni,
udp,
tribool(), scv, tribool(), "", 30, 30, 0);
tribool(), scv, tribool(), underlying_proxy, 30, 30, 0);
break;
case "mieru"_hash:
group = MIERU_DEFAULT_GROUP;
@@ -1594,7 +1600,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
mieruConstruct(node, MIERU_DEFAULT_GROUP, ps, port, password, server, ports, user, multiplexing,
transfer_protocol,
udp,
tribool(), scv, tribool(), "");
tribool(), scv, tribool(), underlying_proxy);
break;
default:
continue;
@@ -2908,6 +2914,7 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
string_array dns_server;
std::string fingerprint;
std::string congestion_control, udp_relay_mode; //quic
std::string underlying_proxy;
tribool udp, tfo, scv, rrt, disableSni;
rapidjson::Value singboxNode = outbounds[i].GetObject();
if (singboxNode.HasMember("type") && singboxNode["type"].IsString()) {
@@ -2916,6 +2923,7 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
ps = GetMember(singboxNode, "tag");
server = GetMember(singboxNode, "server");
port = GetMember(singboxNode, "server_port");
underlying_proxy = GetMember(singboxNode, "detour");
tfo = GetMember(singboxNode, "tcp_fast_open");
std::vector<std::string> alpnList;
if (singboxNode.HasMember("tls") && singboxNode["tls"].IsObject()) {
@@ -2975,9 +2983,9 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
aid = GetMember(singboxNode, "alter_id");
cipher = GetMember(singboxNode, "security");
explodeSingboxTransport(singboxNode, net, host, path, edge);
vmessConstruct(node, group, ps, server, port, "", id, aid, net, cipher, path, host, edge, tls,
sni, alpnList, udp,
tfo, scv);
vmessConstruct(node, group, ps, server, port, "", id, aid, net, cipher, path, host, edge,
tls, sni, alpnList, udp,
tfo, scv, tribool(), underlying_proxy);
break;
case "shadowsocks"_hash:
group = SS_DEFAULT_GROUP;
@@ -2985,7 +2993,8 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
password = GetMember(singboxNode, "password");
plugin = GetMember(singboxNode, "plugin");
pluginopts = GetMember(singboxNode, "plugin_opts");
ssConstruct(node, group, ps, server, port, password, cipher, plugin, pluginopts, udp, tfo, scv);
ssConstruct(node, group, ps, server, port, password, cipher, plugin, pluginopts, udp, tfo,
scv, tribool(), underlying_proxy);
break;
case "trojan"_hash:
group = TROJAN_DEFAULT_GROUP;
@@ -2994,7 +3003,7 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
trojanConstruct(node, group, ps, server, port, password, net, host, path, fp, sni, alpnList,
true, udp,
tfo,
scv);
scv, tribool(), underlying_proxy);
break;
case "vless"_hash:
group = XRAY_DEFAULT_GROUP;
@@ -3040,12 +3049,14 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
}
vlessConstruct(node, group, ps, server, port, type, id, aid, net, "auto", flow, mode, path,
host, "", tls, pbk, sid, fp, sni, alpnList, packet_encoding, encryption, udp);
host, "", tls, pbk, sid, fp, sni, alpnList, packet_encoding, encryption,
udp, tribool(), tribool(), tribool(), underlying_proxy);
break;
case "http"_hash:
password = GetMember(singboxNode, "password");
user = GetMember(singboxNode, "username");
httpConstruct(node, group, ps, server, port, user, password, tls == "tls", tfo, scv);
httpConstruct(node, group, ps, server, port, user, password, tls == "tls", tfo, scv,
tribool(), underlying_proxy);
break;
case "wireguard"_hash:
group = WG_DEFAULT_GROUP;
@@ -3056,14 +3067,15 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
mtu = GetMember(singboxNode, "mtu");
password = GetMember(singboxNode, "pre_shared_key");
dns_server = {"8.8.8.8"};
wireguardConstruct(node, group, ps, server, port, ip, ipv6, private_key, public_key, password,
dns_server, mtu, "0", "", "", udp, "");
wireguardConstruct(node, group, ps, server, port, ip, ipv6, private_key, public_key,
password, dns_server, mtu, "0", "", "", udp, underlying_proxy);
break;
case "socks"_hash:
group = SOCKS_DEFAULT_GROUP;
user = GetMember(singboxNode, "username");
password = GetMember(singboxNode, "password");
socksConstruct(node, group, ps, server, port, user, password);
socksConstruct(node, group, ps, server, port, user, password, tribool(), tribool(),
tribool(), underlying_proxy);
break;
case "hysteria"_hash:
group = HYSTERIA_DEFAULT_GROUP;
@@ -3080,15 +3092,15 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
obfsParam = GetMember(singboxNode, "obfs");
hysteriaConstruct(node, group, ps, server, port, type, auth, "", host, up, down, alpn,
obfsParam, insecure, ports, sni,
udp, tfo, scv);
udp, tfo, scv, tribool(), underlying_proxy);
break;
case "anytls"_hash:
group = ANYTLS_DEFAULT_GROUP;
password = GetMember(singboxNode, "password");
anyTlSConstruct(node, ANYTLS_DEFAULT_GROUP, ps, port, password, server, alpnList, fingerprint,
sni,
anyTlSConstruct(node, ANYTLS_DEFAULT_GROUP, ps, port, password, server, alpnList,
fingerprint, sni,
udp,
tribool(), scv, tribool(), "", 30, 30, 0);
tribool(), scv, tribool(), underlying_proxy, 30, 30, 0);
break;
case "hysteria2"_hash:
group = HYSTERIA2_DEFAULT_GROUP;
@@ -3100,8 +3112,9 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
obfsParam = GetMember(obfsOpt, "type");
obfsPassword = GetMember(obfsOpt, "password");
}
hysteria2Construct(node, group, ps, server, port, password, host, up, down, alpn, obfsParam,
obfsPassword, sni, public_key, "", udp, tfo, scv);
hysteria2Construct(node, group, ps, server, port, password, host, up, down, alpn,
obfsParam, obfsPassword, sni, public_key, "", udp, tfo, scv,
underlying_proxy);
break;
case "tuic"_hash:
group = TUIC_DEFAULT_GROUP;
@@ -3115,7 +3128,7 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
tuicConstruct(node, TUIC_DEFAULT_GROUP, ps, server, port, password, congestion_control, alpn,
sni, id, udp_relay_mode, "",
tribool(),
tribool(), scv, rrt, disableSni);
tribool(), scv, rrt, disableSni, 15000, underlying_proxy);
break;
default:
continue;