diff --git a/base/pref-new.yml b/base/pref-new.yml index e06619b..fa6008b 100644 --- a/base/pref-new.yml +++ b/base/pref-new.yml @@ -87,6 +87,9 @@ template: - {key: clash.socks_port, value: 7891} - {key: clash.allow_lan, value: true} - {key: clash.log_level, value: info} + +aliases: + - {uri: /v, target: /version} server: listen: 0.0.0.0 diff --git a/base/pref.ini b/base/pref.ini index 28db8ec..ddd8c46 100644 --- a/base/pref.ini +++ b/base/pref.ini @@ -174,6 +174,9 @@ clash.socks_port=7891 clash.allow_lan=true clash.log_level=info +[aliases] +/v=/version + [server] ;Address to bind on for Web Server listen=0.0.0.0 diff --git a/src/interfaces.cpp b/src/interfaces.cpp index a15b081..1d10394 100644 --- a/src/interfaces.cpp +++ b/src/interfaces.cpp @@ -31,6 +31,7 @@ bool print_debug_info = false, cfw_child_process = false, append_userinfo = true std::string access_token; extern std::string custom_group; extern int global_log_level; +string_map aliases_map; //global variables for template std::string template_path; @@ -541,9 +542,9 @@ void readYAMLConf(YAML::Node &node) if(node["template"]["globals"].IsSequence()) { eraseElements(global_vars); - std::string key, value; for(size_t i = 0; i < node["template"]["globals"].size(); i++) { + std::string key, value; node["template"]["globals"][i]["key"] >> key; node["template"]["globals"][i]["value"] >> value; global_vars[key] = value; @@ -551,6 +552,18 @@ void readYAMLConf(YAML::Node &node) } } + if(node["aliases"].IsSequence()) + { + reset_redirect(); + for(size_t i = 0; i < node["aliases"].size(); i++) + { + std::string uri, target; + node["aliases"][i]["uri"] >> uri; + node["aliases"][i]["target"] >> target; + append_redirect(uri, target); + } + } + if(node["server"].IsDefined()) { node["server"]["listen"] >> listen_address; @@ -767,6 +780,16 @@ void readConf() } global_vars["managed_config_prefix"] = managed_config_prefix; + if(ini.SectionExist("aliases")) + { + ini.EnterSection("aliases"); + string_multimap tempmap; + ini.GetItems(tempmap); + reset_redirect(); + for(auto &x : tempmap) + append_redirect(x.first, x.second); + } + ini.EnterSection("server"); ini.GetIfExist("listen", listen_address); ini.GetIntIfExist("port", listen_port); diff --git a/src/misc.h b/src/misc.h index 224b495..22e9729 100644 --- a/src/misc.h +++ b/src/misc.h @@ -18,6 +18,7 @@ typedef std::string::size_type string_size; typedef std::vector string_array; +typedef std::map string_map; typedef const std::string &refCnstStr; static const std::string base64_chars = diff --git a/src/printout.h b/src/printout.h index d793058..323288b 100644 --- a/src/printout.h +++ b/src/printout.h @@ -32,6 +32,7 @@ enum SPEEDTEST_MESSAGE_FOUNDSS, SPEEDTEST_MESSAGE_FOUNDSSR, SPEEDTEST_MESSAGE_FOUNDTROJAN, + SPEEDTEST_MESSAGE_FOUNDSNELL, SPEEDTEST_MESSAGE_WELCOME, SPEEDTEST_MESSAGE_FOUNDSUB, SPEEDTEST_MESSAGE_GOTSERVER, @@ -73,6 +74,7 @@ enum #define SOCKS_DEFAULT_GROUP "SocksProvider" #define HTTP_DEFAULT_GROUP "HTTPProvider" #define TROJAN_DEFAULT_GROUP "TrojanProvider" +#define SNELL_DEFAULT_GROUP "SnellProvider" void printMsg(int index, nodeInfo *node, bool rpcmode); void printMsgWithDict(int index, bool rpcmode, std::vector dict, std::vector trans); diff --git a/src/speedtestutil.cpp b/src/speedtestutil.cpp index 9bce783..3e4a43a 100644 --- a/src/speedtestutil.cpp +++ b/src/speedtestutil.cpp @@ -1079,6 +1079,18 @@ void explodeClash(Node yamlnode, const std::string &custom_port, std::vector> password; + if(singleproxy["obfs-opts"].IsDefined()) + { + singleproxy["obfs-opts"]["mode"] >> obfs; + singleproxy["obfs-opts"]["host"] >> host; + } + + node.linkType = SPEEDTEST_MESSAGE_FOUNDSNELL; + node.proxyStr = snellConstruct(ps, server, port, password, obfs, host); + break; default: continue; } @@ -1418,6 +1430,33 @@ bool explodeSurge(std::string surge, const std::string &custom_port, std::vector node.proxyStr = trojanConstruct(remarks, server, port, password, host, true); break; + case "snell"_hash: + node.linkType = SPEEDTEST_MESSAGE_FOUNDSNELL; + node.group = SNELL_DEFAULT_GROUP; + + server = trim(configs[1]); + port = custom_port.empty() ? trim(configs[2]) : custom_port; + + for(i = 3; i < configs.size(); i++) + { + vArray = split(configs[i], "="); + if(vArray.size() != 2) + continue; + itemName = trim(vArray[0]); + itemVal = trim(vArray[1]); + switch(hash_(itemName)) + { + case "psk"_hash: password = itemVal; break; + case "obfs"_hash: plugin = itemVal; break; + case "obfs-host"_hash: host = itemVal; break; + default: continue; + } + } + if(host.empty() && !isIPv4(server) && !isIPv6(server)) + host = server; + + node.proxyStr = snellConstruct(remarks, server, port, password, plugin, host); + break; default: switch(hash_(remarks)) { diff --git a/src/speedtestutil.h b/src/speedtestutil.h index 994e074..e7406c1 100644 --- a/src/speedtestutil.h +++ b/src/speedtestutil.h @@ -13,6 +13,7 @@ std::string ssConstruct(std::string server, std::string port, std::string passwo std::string socksConstruct(std::string remarks, std::string server, std::string port, std::string username, std::string password); std::string httpConstruct(std::string remarks, std::string server, std::string port, std::string username, std::string password, bool tls = false); std::string trojanConstruct(std::string remarks, std::string server, std::string port, std::string password, std::string host, bool tlssecure); +std::string snellConstruct(std::string remarks, std::string server, std::string port, std::string password, std::string obfs, std::string host); void explodeVmess(std::string vmess, const std::string &custom_port, nodeInfo &node); void explodeSSR(std::string ssr, bool ss_libev, bool libev, const std::string &custom_port, nodeInfo &node); void explodeSS(std::string ss, bool libev, const std::string &custom_port, nodeInfo &node); diff --git a/src/subexport.cpp b/src/subexport.cpp index 7a69b30..ff22464 100644 --- a/src/subexport.cpp +++ b/src/subexport.cpp @@ -251,6 +251,29 @@ std::string trojanConstruct(std::string remarks, std::string server, std::string return sb.GetString(); } +std::string snellConstruct(std::string remarks, std::string server, std::string port, std::string password, std::string obfs, std::string host) +{ + rapidjson::StringBuffer sb; + rapidjson::Writer writer(sb); + writer.StartObject(); + writer.Key("Type"); + writer.String("Snell"); + writer.Key("Remark"); + writer.String(remarks.data()); + writer.Key("Hostname"); + writer.String(server.data()); + writer.Key("Port"); + writer.Int(to_int(port)); + writer.Key("Password"); + writer.String(password.data()); + writer.Key("OBFS"); + writer.String(obfs.data()); + writer.Key("Host"); + writer.String(host.data()); + writer.EndObject(); + return sb.GetString(); +} + std::string vmessLinkConstruct(std::string remarks, std::string add, std::string port, std::string type, std::string id, std::string aid, std::string net, std::string path, std::string host, std::string tls) { rapidjson::StringBuffer sb; @@ -867,10 +890,15 @@ void netchToClash(std::vector &nodes, YAML::Node &yamlnode, string_arr if(ext.append_proxy_type) x.remarks = "[" + type + "] " + x.remarks; - while(std::count(remarks_list.begin(), remarks_list.end(), x.remarks) > 0) - x.remarks += "$"; - remark = x.remarks; + int cnt = 2; + while(std::count(remarks_list.begin(), remarks_list.end(), remark) > 0) + { + remark = x.remarks + " " + std::to_string(cnt); + cnt++; + } + x.remarks = remark; + hostname = GetMember(json, "Hostname"); port = GetMember(json, "Port"); username = GetMember(json, "Username"); @@ -1009,6 +1037,19 @@ void netchToClash(std::vector &nodes, YAML::Node &yamlnode, string_arr if(ext.skip_cert_verify) singleproxy["skip-cert-verify"] = true; break; + case SPEEDTEST_MESSAGE_FOUNDSNELL: + obfs = GetMember(json, "OBFS"); + host = GetMember(json, "Host"); + singleproxy["type"] = "snell"; + singleproxy["psk"] = password; + if(obfs.size()) + { + singleproxy["obfs-opts"]["mode"] = obfs; + singleproxy["obfs-opts"]["host"] = host; + } + if(std::all_of(password.begin(), password.end(), ::isdigit) && !password.empty()) + singleproxy["password"].SetTag("str"); + break; default: continue; } @@ -1173,10 +1214,14 @@ std::string netchToSurge(std::vector &nodes, std::string &base_conf, s x.remarks = "[" + type + "] " + x.remarks; remark = x.remarks; - while(std::count(remarks_list.begin(), remarks_list.end(), x.remarks) > 0) - x.remarks += "$"; + int cnt = 2; + while(std::count(remarks_list.begin(), remarks_list.end(), remark) > 0) + { + remark = x.remarks + " " + std::to_string(cnt); + cnt++; + } + x.remarks = remark; - remark = x.remarks; hostname = GetMember(json, "Hostname"); port = std::to_string((unsigned short)stoi(GetMember(json, "Port"))); username = GetMember(json, "Username"); @@ -1274,6 +1319,13 @@ std::string netchToSurge(std::vector &nodes, std::string &base_conf, s if(ext.skip_cert_verify) proxy += ", skip-cert-verify=1"; break; + case SPEEDTEST_MESSAGE_FOUNDSNELL: + obfs = GetMember(json, "OBFS"); + host = GetMember(json, "Host"); + proxy = "snell, " + hostname + ", " + port + ", psk=" + password; + if(obfs.size()) + proxy += ", obfs=" + obfs + ", obfs-host=" + host; + break; default: continue; } @@ -1719,10 +1771,14 @@ void netchToQuan(std::vector &nodes, INIReader &ini, std::vector 0) - x.remarks += "$"; - remark = x.remarks; + int cnt = 2; + while(std::count(remarks_list.begin(), remarks_list.end(), remark) > 0) + { + remark = x.remarks + " " + std::to_string(cnt); + cnt++; + } + x.remarks = remark; hostname = GetMember(json, "Hostname"); port = std::to_string((unsigned short)stoi(GetMember(json, "Port"))); @@ -1984,10 +2040,14 @@ void netchToQuanX(std::vector &nodes, INIReader &ini, std::vector 0) - x.remarks += "$"; - remark = x.remarks; + int cnt = 2; + while(std::count(remarks_list.begin(), remarks_list.end(), remark) > 0) + { + remark = x.remarks + " " + std::to_string(cnt); + cnt++; + } + x.remarks = remark; hostname = GetMember(json, "Hostname"); port = std::to_string((unsigned short)stoi(GetMember(json, "Port"))); @@ -2110,6 +2170,16 @@ void netchToQuanX(std::vector &nodes, INIReader &ini, std::vector 0) - remark = x.remarks = x.remarks + "$"; + { + remark = x.remarks + " " + std::to_string(cnt); + cnt++; + } + x.remarks = remark; + hostname = GetMember(json, "Hostname"); port = std::to_string((unsigned short)stoi(GetMember(json, "Port"))); username = GetMember(json, "Username"); @@ -2514,12 +2590,16 @@ std::string netchToLoon(std::vector &nodes, std::string &base_conf, st if(ext.append_proxy_type) x.remarks = "[" + type + "] " + x.remarks; - remark = x.remarks; - - while(std::count(remarks_list.begin(), remarks_list.end(), x.remarks) > 0) - x.remarks += "$"; remark = x.remarks; + int cnt = 2; + while(std::count(remarks_list.begin(), remarks_list.end(), remark) > 0) + { + remark = x.remarks + " " + std::to_string(cnt); + cnt++; + } + x.remarks = remark; + hostname = GetMember(json, "Hostname"); port = std::to_string((unsigned short)stoi(GetMember(json, "Port"))); username = GetMember(json, "Username"); diff --git a/src/webserver.h b/src/webserver.h index 92c9369..2c198de 100644 --- a/src/webserver.h +++ b/src/webserver.h @@ -14,6 +14,8 @@ struct listener_args }; void append_response(std::string method, std::string uri, std::string content_type, response_callback response); +void append_redirect(std::string uri, std::string target); +void reset_redirect(); int start_web_server(void *argv); int start_web_server_multi(void *argv); void stop_web_server(); diff --git a/src/webserver_libevent.cpp b/src/webserver_libevent.cpp index 33b6212..e841c91 100644 --- a/src/webserver_libevent.cpp +++ b/src/webserver_libevent.cpp @@ -30,6 +30,7 @@ struct responseRoute }; std::vector responses; +string_map redirect_map; static inline void buffer_cleanup(struct evbuffer *eb) { @@ -68,6 +69,14 @@ static inline int process_request(const char *method_str, std::string uri, std:: } } + auto iter = redirect_map.find(uri); + if(iter != redirect_map.end()) + { + return_data = iter->second; + content_type = "REDIRECT"; + return 0; + } + return -1; } @@ -290,3 +299,13 @@ void append_response(std::string method, std::string uri, std::string content_ty rr.rc = response; responses.emplace_back(rr); } + +void append_redirect(std::string uri, std::string target) +{ + redirect_map[uri] = target; +} + +void reset_redirect() +{ + eraseElements(redirect_map); +}