mirror of
https://github.com/asdlokj1qpi233/subconverter.git
synced 2025-10-29 04:42:33 +00:00
Add TUIC protocol support to Clash and Singbox.(#23)
This commit is contained in:
@@ -486,6 +486,36 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
|
||||
if (!x.Ports.empty())
|
||||
singleproxy["ports"] = x.Ports;
|
||||
break;
|
||||
case ProxyType::TUIC:
|
||||
singleproxy["type"] = "tuic";
|
||||
if (!x.Password.empty()) {
|
||||
singleproxy["password"] = x.Password;
|
||||
}
|
||||
if (!x.UserId.empty()) {
|
||||
singleproxy["uuid"] = x.UserId;
|
||||
}
|
||||
if (!x.token.empty()) {
|
||||
singleproxy["token"] = x.token;
|
||||
}
|
||||
if (!x.ServerName.empty()) {
|
||||
singleproxy["sni"] = x.ServerName;
|
||||
}
|
||||
if (!scv.is_undef())
|
||||
singleproxy["skip-cert-verify"] = scv.get();
|
||||
if (!x.Alpn.empty())
|
||||
singleproxy["alpn"].push_back(x.Alpn);
|
||||
singleproxy["disable-sni"] = x.DisableSni.get();
|
||||
singleproxy["reduce-rtt"] = x.ReduceRtt.get();
|
||||
singleproxy["request-timeout"] = x.RequestTimeout;
|
||||
if (!x.UdpRelayMode.empty()) {
|
||||
if (x.UdpRelayMode == "native" || x.UdpRelayMode == "quic") {
|
||||
singleproxy["udp-relay-mode"] = x.UdpRelayMode;
|
||||
}
|
||||
}
|
||||
if (!x.CongestionControl.empty()) {
|
||||
singleproxy["congestion-controller"] = x.CongestionControl;
|
||||
}
|
||||
break;
|
||||
case ProxyType::VLESS:
|
||||
singleproxy["type"] = "vless";
|
||||
singleproxy["uuid"] = x.UserId;
|
||||
@@ -559,7 +589,7 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
|
||||
|
||||
// UDP is not supported yet in clash using snell
|
||||
// sees in https://dreamacro.github.io/clash/configuration/outbound.html#snell
|
||||
if (udp && x.Type != ProxyType::Snell)
|
||||
if (udp && x.Type != ProxyType::Snell && x.Type != ProxyType::TUIC)
|
||||
singleproxy["udp"] = true;
|
||||
if (block)
|
||||
singleproxy.SetStyle(YAML::EmitterStyle::Block);
|
||||
@@ -1536,7 +1566,8 @@ void proxyToQuanX(std::vector<Proxy> &nodes, INIReader &ini, std::vector<Ruleset
|
||||
proxyStr += ", fast-open=" + tfo.get_str();
|
||||
if (!udp.is_undef())
|
||||
proxyStr += ", udp-relay=" + udp.get_str();
|
||||
if (tlssecure && !scv.is_undef() && (x.Type != ProxyType::Shadowsocks && x.Type != ProxyType::ShadowsocksR && x.Type != ProxyType::VLESS))
|
||||
if (tlssecure && !scv.is_undef() &&
|
||||
(x.Type != ProxyType::Shadowsocks && x.Type != ProxyType::ShadowsocksR && x.Type != ProxyType::VLESS))
|
||||
proxyStr += ", tls-verification=" + scv.reverse().get_str();
|
||||
proxyStr += ", tag=" + x.Remark;
|
||||
|
||||
@@ -1986,23 +2017,23 @@ proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector
|
||||
break;
|
||||
case ProxyType::Hysteria2:
|
||||
proxy = "Hysteria2," + hostname + "," + port + ",\"" + password + "\"";
|
||||
if(!x.ServerName.empty()){
|
||||
proxy += ",sni="+x.ServerName;
|
||||
if (!x.ServerName.empty()) {
|
||||
proxy += ",sni=" + x.ServerName;
|
||||
}
|
||||
if(!x.UpMbps.empty()){
|
||||
if (!x.UpMbps.empty()) {
|
||||
std::string search = " Mbps";
|
||||
size_t pos = x.UpMbps.find(search);
|
||||
if (pos != std::string::npos) {
|
||||
x.UpMbps.replace(pos, search.length(), "");
|
||||
} else{
|
||||
} else {
|
||||
search = "Mbps";
|
||||
pos = x.UpMbps.find(search);
|
||||
if (pos != std::string::npos) {
|
||||
x.UpMbps.replace(pos, search.length(), "");
|
||||
}
|
||||
}
|
||||
proxy += ",download-bandwidth="+x.UpMbps;
|
||||
}else{
|
||||
proxy += ",download-bandwidth=" + x.UpMbps;
|
||||
} else {
|
||||
proxy += ",download-bandwidth=100";
|
||||
}
|
||||
if (!scv.is_undef())
|
||||
@@ -2012,17 +2043,17 @@ proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ext.tfo){
|
||||
if (ext.tfo) {
|
||||
proxy += ",fast-open=true";
|
||||
} else {
|
||||
if (x.Type == ProxyType::Hysteria2){
|
||||
if (x.Type == ProxyType::Hysteria2) {
|
||||
proxy += ",fast-open=false";
|
||||
}
|
||||
}
|
||||
if (ext.udp){
|
||||
if (ext.udp) {
|
||||
proxy += ",udp=true";
|
||||
} else {
|
||||
if (x.Type == ProxyType::Hysteria2){
|
||||
if (x.Type == ProxyType::Hysteria2) {
|
||||
proxy += ",udp=true";
|
||||
}
|
||||
}
|
||||
@@ -2470,6 +2501,32 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ProxyType::TUIC: {
|
||||
addSingBoxCommonMembers(proxy, x, "tuic", allocator);
|
||||
proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator);
|
||||
proxy.AddMember("uuid", rapidjson::StringRef(x.UserId.c_str()), allocator);
|
||||
if (!x.TLSSecure && !x.Alpn.empty()) {
|
||||
rapidjson::Value tls(rapidjson::kObjectType);
|
||||
tls.AddMember("enabled", true, allocator);
|
||||
if (!x.ServerName.empty())
|
||||
tls.AddMember("server_name", rapidjson::StringRef(""), allocator);
|
||||
if (!x.Alpn.empty()) {
|
||||
auto alpns = stringArrayToJsonArray(x.Alpn, ",", allocator);
|
||||
tls.AddMember("alpn", alpns, allocator);
|
||||
}
|
||||
proxy.AddMember("tls", tls, allocator);
|
||||
}
|
||||
if (!x.CongestionControl.empty()){
|
||||
proxy.AddMember("congestion_control", rapidjson::StringRef(x.CongestionControl.c_str()), allocator);
|
||||
}
|
||||
if (!x.UdpRelayMode.empty()){
|
||||
proxy.AddMember("udp_relay_mode", rapidjson::StringRef(x.UdpRelayMode.c_str()), allocator);
|
||||
}
|
||||
if (!x.ReduceRtt.is_undef()){
|
||||
proxy.AddMember("zero_rtt_handshake", buildBooleanValue(x.ReduceRtt), allocator);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@ enum class ProxyType {
|
||||
WireGuard,
|
||||
VLESS,
|
||||
Hysteria,
|
||||
Hysteria2
|
||||
Hysteria2,
|
||||
TUIC
|
||||
};
|
||||
|
||||
inline String getProxyTypeName(ProxyType type) {
|
||||
@@ -51,6 +52,8 @@ inline String getProxyTypeName(ProxyType type) {
|
||||
return "Hysteria";
|
||||
case ProxyType::Hysteria2:
|
||||
return "Hysteria2";
|
||||
case ProxyType::TUIC:
|
||||
return "Tuic";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
@@ -64,7 +67,7 @@ struct Proxy {
|
||||
String Remark;
|
||||
String Hostname;
|
||||
uint16_t Port = 0;
|
||||
|
||||
String CongestionControl;
|
||||
String Username;
|
||||
String Password;
|
||||
String EncryptMethod;
|
||||
@@ -122,6 +125,11 @@ struct Proxy {
|
||||
String ShortId;
|
||||
String Flow;
|
||||
bool FlowShow = false;
|
||||
tribool DisableSni;
|
||||
tribool ReduceRtt;
|
||||
String UdpRelayMode = "native";
|
||||
uint16_t RequestTimeout = 15000;
|
||||
String token;
|
||||
};
|
||||
|
||||
#define SS_DEFAULT_GROUP "SSProvider"
|
||||
@@ -135,5 +143,6 @@ struct Proxy {
|
||||
#define XRAY_DEFAULT_GROUP "XRayProvider"
|
||||
#define HYSTERIA_DEFAULT_GROUP "HysteriaProvider"
|
||||
#define HYSTERIA2_DEFAULT_GROUP "Hysteria2Provider"
|
||||
#define TUIC_DEFAULT_GROUP "TuicProvider"
|
||||
|
||||
#endif // PROXY_H_INCLUDED
|
||||
|
||||
@@ -239,6 +239,25 @@ void hysteria2Construct(Proxy &node, const std::string &group, const std::string
|
||||
node.Ports = ports;
|
||||
}
|
||||
|
||||
void tuicConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add,
|
||||
const std::string &port, const std::string &password, const std::string &congestion_control,
|
||||
const std::string &alpn,
|
||||
const std::string &sni, const std::string &uuid, const std::string &udpRelayMode,const std::string &token,
|
||||
tribool udp, tribool tfo,
|
||||
tribool scv, tribool reduceRtt, tribool disableSni) {
|
||||
commonConstruct(node, ProxyType::TUIC, group, remarks, add, port, udp, tfo, scv, tribool());
|
||||
node.Password = password;
|
||||
node.Alpn = alpn;
|
||||
node.ServerName = sni;
|
||||
node.CongestionControl = congestion_control;
|
||||
node.ReduceRtt = reduceRtt;
|
||||
node.DisableSni = disableSni;
|
||||
node.UserId = uuid;
|
||||
node.UdpRelayMode = udpRelayMode;
|
||||
node.token = token;
|
||||
}
|
||||
|
||||
|
||||
void explodeVmess(std::string vmess, Proxy &node) {
|
||||
std::string version, ps, add, port, type, id, aid, net, path, host, tls, sni;
|
||||
Document jsondata;
|
||||
@@ -1072,8 +1091,10 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
|
||||
std::string ip, ipv6, private_key, public_key, mtu; //wireguard
|
||||
std::string auth, up, down, obfsParam, insecure, alpn;//hysteria
|
||||
std::string obfsPassword;//hysteria2
|
||||
std::string congestion_control, udp_relay_mode,token;// tuic
|
||||
string_array dns_server;
|
||||
tribool udp, tfo, scv;
|
||||
bool reduceRtt, disableSni;//tuic
|
||||
Proxy node;
|
||||
singleproxy = yamlnode[section][i];
|
||||
singleproxy["type"] >>= proxytype;
|
||||
@@ -1361,6 +1382,24 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
|
||||
hysteria2Construct(node, group, ps, server, port, password, host, up, down, alpn, obfsParam,
|
||||
obfsPassword, sni, public_key, ports, udp, tfo, scv);
|
||||
break;
|
||||
case "tuic"_hash:
|
||||
group = TUIC_DEFAULT_GROUP;
|
||||
singleproxy["password"] >>= password;
|
||||
singleproxy["uuid"] >>= password;
|
||||
singleproxy["congestion-controller"] >>= congestion_control;
|
||||
singleproxy["sni"] >>= sni;
|
||||
if (!singleproxy["alpn"].IsNull()) {
|
||||
singleproxy["alpn"][0] >>= alpn;
|
||||
}
|
||||
singleproxy["disable-sni"] >>= disableSni;
|
||||
singleproxy["reduce-rtt"] >>= reduceRtt;
|
||||
singleproxy["token"] >>= token;
|
||||
tuicConstruct(node, TUIC_DEFAULT_GROUP, ps, server, port, password, congestion_control, alpn, sni, id,
|
||||
udp_relay_mode,token,
|
||||
tribool(),
|
||||
tribool(), scv, reduceRtt, disableSni);
|
||||
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
@@ -1447,7 +1486,7 @@ void explodeStdHysteria(std::string hysteria, Proxy &node) {
|
||||
}
|
||||
|
||||
void explodeStdHysteria2(std::string hysteria2, Proxy &node) {
|
||||
std::string add, port, password, host, insecure, up, down, alpn, obfsParam, obfsPassword, remarks, sni ,ports;
|
||||
std::string add, port, password, host, insecure, up, down, alpn, obfsParam, obfsPassword, remarks, sni, ports;
|
||||
std::string addition;
|
||||
tribool scv;
|
||||
hysteria2 = hysteria2.substr(12);
|
||||
@@ -2593,7 +2632,8 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
|
||||
std::string auth, up, down, obfsParam, insecure, alpn;//hysteria
|
||||
std::string obfsPassword;//hysteria2
|
||||
string_array dns_server;
|
||||
tribool udp, tfo, scv;
|
||||
std::string congestion_control,udp_relay_mode;//quic
|
||||
tribool udp, tfo, scv,rrt;
|
||||
rapidjson::Value singboxNode = outbounds[i].GetObject();
|
||||
if (singboxNode.HasMember("type") && singboxNode["type"].IsString()) {
|
||||
Proxy node;
|
||||
@@ -2762,6 +2802,19 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
|
||||
hysteria2Construct(node, group, ps, server, port, password, host, up, down, alpn, obfsParam,
|
||||
obfsPassword, sni, public_key, "", udp, tfo, scv);
|
||||
break;
|
||||
case "tuic"_hash:
|
||||
group = TUIC_DEFAULT_GROUP;
|
||||
password = GetMember(singboxNode, "password");
|
||||
id = GetMember(singboxNode, "uuid");
|
||||
congestion_control = GetMember(singboxNode, "congestion_control");
|
||||
if (singboxNode.HasMember("zero_rtt_handshake") && singboxNode["zero_rtt_handshake"].IsBool()) {
|
||||
rrt = singboxNode["zero_rtt_handshake"].GetBool();
|
||||
}
|
||||
udp_relay_mode = GetMember(singboxNode, "udp_relay_mode");
|
||||
tuicConstruct(node, TUIC_DEFAULT_GROUP, ps, server, port, password, congestion_control, alpn, sni, id, udp_relay_mode, "",
|
||||
tribool(),
|
||||
tribool(), scv,rrt);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
@@ -2773,6 +2826,66 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
|
||||
}
|
||||
}
|
||||
|
||||
void explodeTuic(const std::string &tuic, Proxy &node) {
|
||||
std::string add, port, password, host, insecure, alpn, remarks, sni, ports, congestion_control;
|
||||
std::string addition;
|
||||
tribool scv;
|
||||
std::string link = tuic.substr(7);
|
||||
string_size pos;
|
||||
|
||||
pos = link.rfind("#");
|
||||
if (pos != std::string::npos) {
|
||||
remarks = urlDecode(link.substr(pos + 1));
|
||||
link.erase(pos);
|
||||
}
|
||||
|
||||
pos = link.rfind("?");
|
||||
if (pos != std::string::npos) {
|
||||
addition = link.substr(pos + 1);
|
||||
link.erase(pos);
|
||||
}
|
||||
|
||||
std::string uuid;
|
||||
pos = link.find(":");
|
||||
if (pos != std::string::npos) {
|
||||
uuid = link.substr(0, pos);
|
||||
link = link.substr(pos + 1);
|
||||
if (strFind(link, "@")) {
|
||||
pos = link.find("@");
|
||||
if (pos != std::string::npos) {
|
||||
password = link.substr(0, pos);
|
||||
link = link.substr(pos + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pos = link.find(":");
|
||||
if (pos != std::string::npos) {
|
||||
add = link.substr(0, pos);
|
||||
link = link.substr(pos + 1);
|
||||
pos = link.find("?");
|
||||
if (pos != std::string::npos) {
|
||||
port = link.substr(0, pos);
|
||||
addition = link.substr(pos + 1);
|
||||
} else {
|
||||
port = link;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
scv = getUrlArg(addition, "insecure");
|
||||
alpn = getUrlArg(addition, "alpn");
|
||||
sni = getUrlArg(addition, "sni");
|
||||
congestion_control = getUrlArg(addition, "congestion_control");
|
||||
if (remarks.empty())
|
||||
remarks = add + ":" + port;
|
||||
tuicConstruct(node, TUIC_DEFAULT_GROUP, remarks, add, port, password, congestion_control, alpn, sni, uuid, "native", "",
|
||||
tribool(),
|
||||
tribool(), scv);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void explode(const std::string &link, Proxy &node) {
|
||||
if (startsWith(link, "ssr://"))
|
||||
explodeSSR(link, node);
|
||||
@@ -2792,6 +2905,8 @@ void explode(const std::string &link, Proxy &node) {
|
||||
explodeVless(link, node);
|
||||
else if (strFind(link, "hysteria://") || strFind(link, "hy://"))
|
||||
explodeHysteria(link, node);
|
||||
else if (strFind(link, "tuic://"))
|
||||
explodeTuic(link, node);
|
||||
else if (strFind(link, "hysteria2://") || strFind(link, "hy2://"))
|
||||
explodeHysteria2(link, node);
|
||||
else if (isLink(link))
|
||||
|
||||
@@ -78,7 +78,12 @@ void snellConstruct(Proxy &node, const std::string &group, const std::string &re
|
||||
const std::string &port, const std::string &password, const std::string &obfs,
|
||||
const std::string &host, uint16_t version = 0, tribool udp = tribool(), tribool tfo = tribool(),
|
||||
tribool scv = tribool());
|
||||
|
||||
void tuicConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add,
|
||||
const std::string &port, const std::string &password, const std::string &congestion_control,
|
||||
const std::string &alpn,
|
||||
const std::string &sni,const std::string & uuid,const std::string &udpRelayMode,const std::string &token,
|
||||
tribool udp = tribool(), tribool tfo = tribool(),
|
||||
tribool scv = tribool(),tribool reduceRtt = tribool(),tribool disableSni = tribool());
|
||||
void explodeVmess(std::string vmess, Proxy &node);
|
||||
|
||||
void explodeSSR(std::string ssr, Proxy &node);
|
||||
|
||||
Reference in New Issue
Block a user