Skip to content

Commit

Permalink
Add support for WireGuard nodes in Clash, Surge and Loon configs
Browse files Browse the repository at this point in the history
  • Loading branch information
tindy2013 committed Oct 15, 2023
1 parent e7380d8 commit 80c2a96
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 19 deletions.
74 changes: 73 additions & 1 deletion src/generator/config/subexport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,20 @@ void proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGr
if(std::all_of(x.Password.begin(), x.Password.end(), ::isdigit) && !x.Password.empty())
singleproxy["password"].SetTag("str");
break;
case ProxyType::WireGuard:
singleproxy["type"] = "wireguard";
singleproxy["public-key"] = x.PublicKey;
singleproxy["private-key"] = x.PrivateKey;
singleproxy["ip"] = x.SelfIP;
if(!x.SelfIPv6.empty())
singleproxy["ipv6"] = x.SelfIPv6;
if(!x.PreSharedKey.empty())
singleproxy["preshared-key"] = x.PreSharedKey;
if(!x.DnsServers.empty())
singleproxy["dns"] = x.DnsServers;
if(x.Mtu > 0)
singleproxy["mtu"] = x.Mtu;
break;
default:
continue;
}
Expand Down Expand Up @@ -595,6 +609,24 @@ std::string proxyToClash(std::vector<Proxy> &nodes, const std::string &base_conf
return output_content;
}

// 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)
std::string generatePeer(Proxy &node, bool client_id_as_reserved = false)
{
std::string result;
result += "public-key = " + node.PublicKey;
result += ", endpoint = " + node.Hostname + ":" + std::to_string(node.Port);
if(!node.AllowedIPs.empty())
result += ", allowed-ips = \"" + node.AllowedIPs + "\"";
if(!node.ClientId.empty())
{
if(client_id_as_reserved)
result += ", reserved = [" + node.ClientId + "]";
else
result += ", client-id = " + node.ClientId;
}
return result;
}

std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, int surge_ver, extra_settings &ext)
{
INIReader ini;
Expand Down Expand Up @@ -644,7 +676,7 @@ std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf
scv.define(x.AllowInsecure);
tls13.define(x.TLS13);

std::string proxy;
std::string proxy, section, real_section;
string_array args, headers;

switch(x.Type)
Expand Down Expand Up @@ -770,6 +802,28 @@ std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf
if(x.SnellVersion != 0)
proxy += ", version=" + std::to_string(x.SnellVersion);
break;
case ProxyType::WireGuard:
if(surge_ver < 4 && surge_ver != -3)
continue;
section = randomStr(5);
real_section = "WireGuard " + section;
proxy = "wireguard, section-name=" + section;
if(!x.TestUrl.empty())
proxy += ", test-url=" + x.TestUrl;
ini.set(real_section, "private-key", x.PrivateKey);
ini.set(real_section, "self-ip", x.SelfIP);
if(!x.SelfIPv6.empty())
ini.set(real_section, "self-ip-v6", x.SelfIPv6);
if(!x.PreSharedKey.empty())
ini.set(real_section, "preshared-key", x.PreSharedKey);
if(!x.DnsServers.empty())
ini.set(real_section, "dns-server", join(x.DnsServers, ","));
if(x.Mtu > 0)
ini.set(real_section, "mtu", std::to_string(x.Mtu));
if(x.KeepAlive > 0)
ini.set(real_section, "keepalive", std::to_string(x.KeepAlive));
ini.set(real_section, "peer", "(" + generatePeer(x) + ")");
break;
default:
continue;
}
Expand Down Expand Up @@ -1866,6 +1920,24 @@ std::string proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf,
proxy += ",skip-cert-verify=" + std::string(scv.get() ? "true" : "false");
}
break;
case ProxyType::WireGuard:
proxy = "wireguard, interface-ip=" + x.SelfIP;
if(!x.SelfIPv6.empty())
proxy += ", interface-ipv6=" + x.SelfIPv6;
proxy += ", private-key=" + x.PrivateKey;
for(const auto &y : x.DnsServers)
{
if(isIPv4(y))
proxy += ", dns=" + y;
else if(isIPv6(y))
proxy += ", dnsv6=" + y;
}
if(x.Mtu > 0)
proxy += ", mtu=" + std::to_string(x.Mtu);
if(x.KeepAlive > 0)
proxy += ", keepalive=" + std::to_string(x.KeepAlive);
proxy += ", peers=[{" + generatePeer(x, true) + "}]";
break;
default:
continue;
}
Expand Down
18 changes: 17 additions & 1 deletion src/parser/config/proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
#define PROXY_H_INCLUDED

#include <string>
#include <vector>

#include "../../utils/tribool.h"

using String = std::string;
using StringArray = std::vector<String>;

enum ProxyType
{
Expand All @@ -17,7 +19,8 @@ enum ProxyType
Snell,
HTTP,
HTTPS,
SOCKS5
SOCKS5,
WireGuard
};

inline String getProxyTypeName(int type)
Expand Down Expand Up @@ -84,6 +87,18 @@ struct Proxy

uint16_t SnellVersion = 0;
String ServerName;

String SelfIP;
String SelfIPv6;
String PublicKey;
String PrivateKey;
String PreSharedKey;
StringArray DnsServers;
uint16_t Mtu = 0;
String AllowedIPs = "0.0.0.0/0, ::/0";
uint16_t KeepAlive = 0;
String TestUrl;
String ClientId;
};

#define SS_DEFAULT_GROUP "SSProvider"
Expand All @@ -93,5 +108,6 @@ struct Proxy
#define HTTP_DEFAULT_GROUP "HTTPProvider"
#define TROJAN_DEFAULT_GROUP "TrojanProvider"
#define SNELL_DEFAULT_GROUP "SnellProvider"
#define WG_DEFAULT_GROUP "WireGuardProvider"

#endif // PROXY_H_INCLUDED
126 changes: 125 additions & 1 deletion src/parser/subparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,20 @@ void snellConstruct(Proxy &node, const std::string &group, const std::string &re
node.SnellVersion = version;
}

void wireguardConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &selfIp, const std::string &selfIpv6, const std::string &privKey, const std::string &pubKey, const std::string &psk, const string_array &dns, const std::string &mtu, const std::string &keepalive, const std::string &testUrl, const std::string &clientId, const tribool &udp) {
commonConstruct(node, ProxyType::WireGuard, group, remarks, server, port, udp, tribool(), tribool(), tribool());
node.SelfIP = selfIp;
node.SelfIPv6 = selfIpv6;
node.PrivateKey = privKey;
node.PublicKey = pubKey;
node.PreSharedKey = psk;
node.DnsServers = dns;
node.Mtu = to_int(mtu);
node.KeepAlive = to_int(keepalive);
node.TestUrl = testUrl;
node.ClientId = clientId;
}

void explodeVmess(std::string vmess, Proxy &node)
{
std::string version, ps, add, port, type, id, aid, net, path, host, tls, sni;
Expand Down Expand Up @@ -953,6 +967,8 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes)
std::string plugin, pluginopts, pluginopts_mode, pluginopts_host, pluginopts_mux; //ss
std::string protocol, protoparam, obfs, obfsparam; //ssr
std::string user; //socks
std::string ip, ipv6, private_key, public_key, mtu; //wireguard
string_array dns_server;
tribool udp, tfo, scv;
Node singleproxy;
uint32_t index = nodes.size();
Expand Down Expand Up @@ -1151,6 +1167,18 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes)

snellConstruct(node, group, ps, server, port, password, obfs, host, to_int(aid, 0), udp, tfo, scv);
break;
case "wireguard"_hash:
group = WG_DEFAULT_GROUP;
singleproxy["public-key"] >>= public_key;
singleproxy["private-key"] >>= private_key;
singleproxy["dns"] >>= dns_server;
singleproxy["mtu"] >>= mtu;
singleproxy["preshared-key"] >>= password;
singleproxy["ip"] >>= ip;
singleproxy["ipv6"] >>= ipv6;

wireguardConstruct(node, group, ps, server, port, ip, ipv6, private_key, public_key, password, dns_server, mtu, "0", "", "", udp);
break;
default:
continue;
}
Expand Down Expand Up @@ -1288,6 +1316,41 @@ void explodeKitsunebi(std::string kit, Proxy &node)
vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, cipher, path, host, "", tls, "");
}

// 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)
void parsePeers(Proxy &node, const std::string &data)
{
auto peers = regGetAllMatch(data, R"(\((.*?)\))", true);
if(peers.empty())
return;
auto peer = peers[0];
auto peerdata = regGetAllMatch(peer, R"(([a-z-]+) ?= ?([^" ),]+|".*?"),? ?)", true);
if(peerdata.size() % 2 != 0)
return;
for(size_t i = 0; i < peerdata.size(); i += 2)
{
auto key = peerdata[i];
auto val = peerdata[i + 1];
switch(hash_(key))
{
case "public-key"_hash:
node.PublicKey = val;
break;
case "endpoint"_hash:
node.Hostname = val.substr(0, val.rfind(':'));
node.Port = to_int(val.substr(val.rfind(':') + 1));
break;
case "client-id"_hash:
node.ClientId = val;
break;
case "allowed-ips"_hash:
node.AllowedIPs = trimOf(val, '"');
break;
default:
break;
}
}
}

bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
{
std::multimap<std::string, std::string> proxies;
Expand All @@ -1303,7 +1366,6 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
ini.keep_empty_section = false;
ini.allow_dup_section_titles = true;
ini.set_isolated_items_section("Proxy");
ini.include_section("Proxy");
ini.add_direct_save_section("Proxy");
if(surge.find("[Proxy]") != surge.npos)
surge = regReplace(surge, R"(^[\S\s]*?\[)", "[", false);
Expand All @@ -1322,6 +1384,9 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
std::string plugin, pluginopts, pluginopts_mode, pluginopts_host, mod_url, mod_md5; //ss
std::string id, net, tls, host, edge, path; //v2
std::string protocol, protoparam; //ssr
std::string section, ip, ipv6, private_key, public_key, mtu, test_url, client_id, peer, keepalive; //wireguard
string_array dns_servers;
string_multimap wireguard_config;
std::string version, aead = "1";
std::string itemName, itemVal, config;
std::vector<std::string> configs, vArray, headers, header;
Expand Down Expand Up @@ -1660,6 +1725,65 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)

snellConstruct(node, SNELL_DEFAULT_GROUP, remarks, server, port, password, plugin, host, to_int(version, 0), udp, tfo, scv);
break;
case "wireguard"_hash:
for (i = 1; i < configs.size(); i++)
{
vArray = split(trim(configs[i]), "=");
if(vArray.size() != 2)
continue;
itemName = trim(vArray[0]);
itemVal = trim(vArray[1]);
switch(hash_(itemName))
{
case "section-name"_hash:
section = itemVal;
break;
case "test-url"_hash:
test_url = itemVal;
break;
}
}
if(section.empty())
continue;
ini.get_items("WireGuard " + section, wireguard_config);
if(wireguard_config.empty())
continue;

for (auto &c : wireguard_config)
{
itemName = trim(c.first);
itemVal = trim(c.second);
switch(hash_(itemName))
{
case "self-ip"_hash:
ip = itemVal;
break;
case "self-ip-v6"_hash:
ipv6 = itemVal;
break;
case "private-key"_hash:
private_key = itemVal;
break;
case "dns-server"_hash:
vArray = split(itemVal, ",");
for (auto &y : vArray)
dns_servers.emplace_back(trim(y));
break;
case "mtu"_hash:
mtu = itemVal;
break;
case "peer"_hash:
peer = itemVal;
break;
case "keepalive"_hash:
keepalive = itemVal;
break;
}
}

wireguardConstruct(node, WG_DEFAULT_GROUP, remarks, "", "0", ip, ipv6, private_key, "", "", dns_servers, mtu, keepalive, test_url, "", udp);
parsePeers(node, peer);
break;
default:
switch(hash_(remarks))
{
Expand Down
Loading

0 comments on commit 80c2a96

Please sign in to comment.