Enhancements

Add URL aliasing support to shorten request URL.
Add support for parsing and exporting Snell server in configurations.
Add numbering system to process duplicated node names.
Optimize codes.
This commit is contained in:
Tindy X 2020-04-21 22:29:16 +08:00
parent 4b5e0e1346
commit 52c8eff182
No known key found for this signature in database
GPG Key ID: C6AD413169968D58
10 changed files with 192 additions and 19 deletions

View File

@ -87,6 +87,9 @@ template:
- {key: clash.socks_port, value: 7891} - {key: clash.socks_port, value: 7891}
- {key: clash.allow_lan, value: true} - {key: clash.allow_lan, value: true}
- {key: clash.log_level, value: info} - {key: clash.log_level, value: info}
aliases:
- {uri: /v, target: /version}
server: server:
listen: 0.0.0.0 listen: 0.0.0.0

View File

@ -174,6 +174,9 @@ clash.socks_port=7891
clash.allow_lan=true clash.allow_lan=true
clash.log_level=info clash.log_level=info
[aliases]
/v=/version
[server] [server]
;Address to bind on for Web Server ;Address to bind on for Web Server
listen=0.0.0.0 listen=0.0.0.0

View File

@ -31,6 +31,7 @@ bool print_debug_info = false, cfw_child_process = false, append_userinfo = true
std::string access_token; std::string access_token;
extern std::string custom_group; extern std::string custom_group;
extern int global_log_level; extern int global_log_level;
string_map aliases_map;
//global variables for template //global variables for template
std::string template_path; std::string template_path;
@ -541,9 +542,9 @@ void readYAMLConf(YAML::Node &node)
if(node["template"]["globals"].IsSequence()) if(node["template"]["globals"].IsSequence())
{ {
eraseElements(global_vars); eraseElements(global_vars);
std::string key, value;
for(size_t i = 0; i < node["template"]["globals"].size(); i++) 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]["key"] >> key;
node["template"]["globals"][i]["value"] >> value; node["template"]["globals"][i]["value"] >> value;
global_vars[key] = 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()) if(node["server"].IsDefined())
{ {
node["server"]["listen"] >> listen_address; node["server"]["listen"] >> listen_address;
@ -767,6 +780,16 @@ void readConf()
} }
global_vars["managed_config_prefix"] = managed_config_prefix; 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.EnterSection("server");
ini.GetIfExist("listen", listen_address); ini.GetIfExist("listen", listen_address);
ini.GetIntIfExist("port", listen_port); ini.GetIntIfExist("port", listen_port);

View File

@ -18,6 +18,7 @@
typedef std::string::size_type string_size; typedef std::string::size_type string_size;
typedef std::vector<std::string> string_array; typedef std::vector<std::string> string_array;
typedef std::map<std::string, std::string> string_map;
typedef const std::string &refCnstStr; typedef const std::string &refCnstStr;
static const std::string base64_chars = static const std::string base64_chars =

View File

@ -32,6 +32,7 @@ enum
SPEEDTEST_MESSAGE_FOUNDSS, SPEEDTEST_MESSAGE_FOUNDSS,
SPEEDTEST_MESSAGE_FOUNDSSR, SPEEDTEST_MESSAGE_FOUNDSSR,
SPEEDTEST_MESSAGE_FOUNDTROJAN, SPEEDTEST_MESSAGE_FOUNDTROJAN,
SPEEDTEST_MESSAGE_FOUNDSNELL,
SPEEDTEST_MESSAGE_WELCOME, SPEEDTEST_MESSAGE_WELCOME,
SPEEDTEST_MESSAGE_FOUNDSUB, SPEEDTEST_MESSAGE_FOUNDSUB,
SPEEDTEST_MESSAGE_GOTSERVER, SPEEDTEST_MESSAGE_GOTSERVER,
@ -73,6 +74,7 @@ enum
#define SOCKS_DEFAULT_GROUP "SocksProvider" #define SOCKS_DEFAULT_GROUP "SocksProvider"
#define HTTP_DEFAULT_GROUP "HTTPProvider" #define HTTP_DEFAULT_GROUP "HTTPProvider"
#define TROJAN_DEFAULT_GROUP "TrojanProvider" #define TROJAN_DEFAULT_GROUP "TrojanProvider"
#define SNELL_DEFAULT_GROUP "SnellProvider"
void printMsg(int index, nodeInfo *node, bool rpcmode); void printMsg(int index, nodeInfo *node, bool rpcmode);
void printMsgWithDict(int index, bool rpcmode, std::vector<std::string> dict, std::vector<std::string> trans); void printMsgWithDict(int index, bool rpcmode, std::vector<std::string> dict, std::vector<std::string> trans);

View File

@ -1079,6 +1079,18 @@ void explodeClash(Node yamlnode, const std::string &custom_port, std::vector<nod
node.linkType = SPEEDTEST_MESSAGE_FOUNDTROJAN; node.linkType = SPEEDTEST_MESSAGE_FOUNDTROJAN;
node.proxyStr = trojanConstruct(ps, server, port, password, host, true); node.proxyStr = trojanConstruct(ps, server, port, password, host, true);
break; break;
case "snell"_hash:
group = SNELL_DEFAULT_GROUP;
singleproxy["psk"] >> 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: default:
continue; 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); node.proxyStr = trojanConstruct(remarks, server, port, password, host, true);
break; 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: default:
switch(hash_(remarks)) switch(hash_(remarks))
{ {

View File

@ -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 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 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 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 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 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); void explodeSS(std::string ss, bool libev, const std::string &custom_port, nodeInfo &node);

View File

@ -251,6 +251,29 @@ std::string trojanConstruct(std::string remarks, std::string server, std::string
return sb.GetString(); 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<rapidjson::StringBuffer> 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) 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; rapidjson::StringBuffer sb;
@ -867,10 +890,15 @@ void netchToClash(std::vector<nodeInfo> &nodes, YAML::Node &yamlnode, string_arr
if(ext.append_proxy_type) if(ext.append_proxy_type)
x.remarks = "[" + type + "] " + x.remarks; x.remarks = "[" + type + "] " + x.remarks;
while(std::count(remarks_list.begin(), remarks_list.end(), x.remarks) > 0)
x.remarks += "$";
remark = 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"); hostname = GetMember(json, "Hostname");
port = GetMember(json, "Port"); port = GetMember(json, "Port");
username = GetMember(json, "Username"); username = GetMember(json, "Username");
@ -1009,6 +1037,19 @@ void netchToClash(std::vector<nodeInfo> &nodes, YAML::Node &yamlnode, string_arr
if(ext.skip_cert_verify) if(ext.skip_cert_verify)
singleproxy["skip-cert-verify"] = true; singleproxy["skip-cert-verify"] = true;
break; 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: default:
continue; continue;
} }
@ -1173,10 +1214,14 @@ std::string netchToSurge(std::vector<nodeInfo> &nodes, std::string &base_conf, s
x.remarks = "[" + type + "] " + x.remarks; x.remarks = "[" + type + "] " + x.remarks;
remark = x.remarks; remark = x.remarks;
while(std::count(remarks_list.begin(), remarks_list.end(), x.remarks) > 0) int cnt = 2;
x.remarks += "$"; 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"); hostname = GetMember(json, "Hostname");
port = std::to_string((unsigned short)stoi(GetMember(json, "Port"))); port = std::to_string((unsigned short)stoi(GetMember(json, "Port")));
username = GetMember(json, "Username"); username = GetMember(json, "Username");
@ -1274,6 +1319,13 @@ std::string netchToSurge(std::vector<nodeInfo> &nodes, std::string &base_conf, s
if(ext.skip_cert_verify) if(ext.skip_cert_verify)
proxy += ", skip-cert-verify=1"; proxy += ", skip-cert-verify=1";
break; 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: default:
continue; continue;
} }
@ -1719,10 +1771,14 @@ void netchToQuan(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<rules
if(ext.append_proxy_type) if(ext.append_proxy_type)
x.remarks = "[" + type + "] " + x.remarks; x.remarks = "[" + type + "] " + x.remarks;
while(std::count(remarks_list.begin(), remarks_list.end(), x.remarks) > 0)
x.remarks += "$";
remark = 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"); hostname = GetMember(json, "Hostname");
port = std::to_string((unsigned short)stoi(GetMember(json, "Port"))); port = std::to_string((unsigned short)stoi(GetMember(json, "Port")));
@ -1984,10 +2040,14 @@ void netchToQuanX(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<rule
if(ext.append_proxy_type) if(ext.append_proxy_type)
x.remarks = "[" + type + "] " + x.remarks; x.remarks = "[" + type + "] " + x.remarks;
while(std::count(remarks_list.begin(), remarks_list.end(), x.remarks) > 0)
x.remarks += "$";
remark = 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"); hostname = GetMember(json, "Hostname");
port = std::to_string((unsigned short)stoi(GetMember(json, "Port"))); port = std::to_string((unsigned short)stoi(GetMember(json, "Port")));
@ -2110,6 +2170,16 @@ void netchToQuanX(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<rule
continue; continue;
rules_upper_bound -= 2; rules_upper_bound -= 2;
break; break;
case "ssid"_hash:
if(rules_upper_bound < 4)
continue;
proxies = vArray[0] + ",";
proxies += std::accumulate(vArray.begin() + 3, vArray.end(), vArray[2], [](std::string a, std::string b)
{
return std::move(a) + "," + std::move(replace_all_distinct(b, "=", ":"));
});
ini.Set("{NONAME}", vArray[1] + "=" + proxies); //insert order
continue;
default: default:
continue; continue;
} }
@ -2361,10 +2431,16 @@ void netchToMellow(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<rul
if(ext.append_proxy_type) if(ext.append_proxy_type)
x.remarks = "[" + type + "] " + x.remarks; x.remarks = "[" + type + "] " + x.remarks;
remark = x.remarks;
remark = x.remarks;
int cnt = 2;
while(std::count(remarks_list.begin(), remarks_list.end(), remark) > 0) while(std::count(remarks_list.begin(), remarks_list.end(), remark) > 0)
remark = x.remarks = x.remarks + "$"; {
remark = x.remarks + " " + std::to_string(cnt);
cnt++;
}
x.remarks = remark;
hostname = GetMember(json, "Hostname"); hostname = GetMember(json, "Hostname");
port = std::to_string((unsigned short)stoi(GetMember(json, "Port"))); port = std::to_string((unsigned short)stoi(GetMember(json, "Port")));
username = GetMember(json, "Username"); username = GetMember(json, "Username");
@ -2514,12 +2590,16 @@ std::string netchToLoon(std::vector<nodeInfo> &nodes, std::string &base_conf, st
if(ext.append_proxy_type) if(ext.append_proxy_type)
x.remarks = "[" + type + "] " + x.remarks; 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; 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"); hostname = GetMember(json, "Hostname");
port = std::to_string((unsigned short)stoi(GetMember(json, "Port"))); port = std::to_string((unsigned short)stoi(GetMember(json, "Port")));
username = GetMember(json, "Username"); username = GetMember(json, "Username");

View File

@ -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_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(void *argv);
int start_web_server_multi(void *argv); int start_web_server_multi(void *argv);
void stop_web_server(); void stop_web_server();

View File

@ -30,6 +30,7 @@ struct responseRoute
}; };
std::vector<responseRoute> responses; std::vector<responseRoute> responses;
string_map redirect_map;
static inline void buffer_cleanup(struct evbuffer *eb) 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; return -1;
} }
@ -290,3 +299,13 @@ void append_response(std::string method, std::string uri, std::string content_ty
rr.rc = response; rr.rc = response;
responses.emplace_back(rr); responses.emplace_back(rr);
} }
void append_redirect(std::string uri, std::string target)
{
redirect_map[uri] = target;
}
void reset_redirect()
{
eraseElements(redirect_map);
}