nekoray_Mahdi-zarei/src/configs/outbounds/wireguard.cpp
Nova 70c0ecd926 Fix process path &&
Some more fixes
2025-11-17 18:22:26 +03:30

288 lines
14 KiB
C++

#include "include/configs/outbounds/wireguard.h"
#include <QJsonArray>
#include <QUrlQuery>
#include <include/global/Utils.hpp>
#include "include/configs/common/utils.h"
namespace Configs {
bool Peer::ParseFromLink(const QString& link)
{
auto url = QUrl(link);
if (!url.isValid()) return false;
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
if (query.hasQueryItem("address")) address = query.queryItemValue("address");
if (query.hasQueryItem("port")) port = query.queryItemValue("port").toInt();
if (query.hasQueryItem("public_key")) public_key = query.queryItemValue("public_key");
if (query.hasQueryItem("peer_public_key")) public_key = query.queryItemValue("peer_public_key");
if (query.hasQueryItem("pre_shared_key")) pre_shared_key = query.queryItemValue("pre_shared_key");
if (query.hasQueryItem("reserved")) {
QString rawReserved = query.queryItemValue("reserved");
if (!rawReserved.isEmpty()) {
for (const auto& item : rawReserved.split("-")) {
int val = item.toInt();
if (val > 0) reserved.append(val);
}
}
}
if (query.hasQueryItem("persistent_keepalive_interval")) persistent_keepalive = query.queryItemValue("persistent_keepalive").toInt();
return true;
}
bool Peer::ParseFromJson(const QJsonObject& object)
{
if (object.isEmpty()) return false;
if (object.contains("address")) address = object["address"].toString();
if (object.contains("port")) port = object["port"].toInt();
if (object.contains("public_key")) public_key = object["public_key"].toString();
if (object.contains("pre_shared_key")) pre_shared_key = object["pre_shared_key"].toString();
if (object.contains("reserved")) {
reserved = QJsonArray2QListInt(object["reserved"].toArray());
}
if (object.contains("persistent_keepalive_interval")) persistent_keepalive = object["persistent_keepalive"].toInt();
return true;
}
QString Peer::ExportToLink()
{
QUrlQuery query;
if (!address.isEmpty()) query.addQueryItem("address", address);
if (port > 0) query.addQueryItem("port", QString::number(port));
if (!public_key.isEmpty()) query.addQueryItem("public_key", public_key);
if (!pre_shared_key.isEmpty()) query.addQueryItem("pre_shared_key", pre_shared_key);
if (!reserved.isEmpty()) {
QStringList reservedStr;
for (auto val : reserved) {
reservedStr.append(QString::number(val));
}
query.addQueryItem("reserved", reservedStr.join("-"));
}
if (persistent_keepalive > 0) query.addQueryItem("persistent_keepalive_interval", QString::number(persistent_keepalive));
return query.toString();
}
QJsonObject Peer::ExportToJson()
{
QJsonObject object;
if (!address.isEmpty()) object["address"] = address;
if (port > 0) object["port"] = port;
if (!public_key.isEmpty()) object["public_key"] = public_key;
if (!pre_shared_key.isEmpty()) object["pre_shared_key"] = pre_shared_key;
if (!reserved.isEmpty()) object["reserved"] = QListInt2QJsonArray(reserved);
if (persistent_keepalive > 0) object["persistent_keepalive_interval"] = persistent_keepalive;
return object;
}
BuildResult Peer::Build()
{
QJsonObject object;
if (!address.isEmpty()) object["address"] = address;
if (port > 0) object["port"] = port;
if (!public_key.isEmpty()) object["public_key"] = public_key;
if (!pre_shared_key.isEmpty()) object["pre_shared_key"] = pre_shared_key;
if (!reserved.isEmpty()) object["reserved"] = QListInt2QJsonArray(reserved);
if (persistent_keepalive > 0) object["persistent_keepalive_interval"] = persistent_keepalive;
object["allowed_ips"] = QListStr2QJsonArray({"0.0.0.0/0", "::/0"});
return {object, ""};
}
bool wireguard::ParseFromLink(const QString& link)
{
// Try WireGuard config file format first
if (link.contains("[Interface]") && link.contains("[Peer]")) {
auto lines = link.split("\n");
for (const auto& line : lines) {
QString trimmed = line.trimmed();
if (trimmed.isEmpty()) continue;
if (trimmed == "[Peer]" || trimmed == "[Interface]") {
continue;
}
if (!trimmed.contains("=")) continue;
auto eqIdx = trimmed.indexOf("=");
QString key = trimmed.left(eqIdx).trimmed();
QString value = trimmed.mid(eqIdx + 1).trimmed();
if (key == "PrivateKey") private_key = value;
if (key == "Address") address = value.replace(" ", "").split(",");
if (key == "MTU") mtu = value.toInt();
if (key == "PublicKey") peer->public_key = value;
if (key == "PresharedKey") peer->pre_shared_key = value;
if (key == "PersistentKeepalive") peer->persistent_keepalive = value.toInt();
if (key == "Endpoint") {
QStringList parts = value.split(":");
if (parts.size() >= 2) {
peer->address = parts[0].trimmed();
peer->port = parts.last().trimmed().toInt();
server = peer->address;
server_port = peer->port;
}
}
if (key == "S1") enable_amnezia = true, init_packet_junk_size = value.toInt();
if (key == "S2") enable_amnezia = true, response_packet_junk_size = value.toInt();
if (key == "Jc") enable_amnezia = true, junk_packet_count = value.toInt();
if (key == "Jmin") enable_amnezia = true, junk_packet_min_size = value.toInt();
if (key == "Jmax") enable_amnezia = true, junk_packet_max_size = value.toInt();
if (key == "H1") enable_amnezia = true, init_packet_magic_header = value.toInt();
if (key == "H2") enable_amnezia = true, response_packet_magic_header = value.toInt();
if (key == "H3") enable_amnezia = true, underload_packet_magic_header = value.toInt();
if (key == "H4") enable_amnezia = true, transport_packet_magic_header = value.toInt();
}
return !private_key.isEmpty() && !peer->public_key.isEmpty();
}
// Standard wg:// URL format
auto url = QUrl(link);
if (!url.isValid()) return false;
auto query = QUrlQuery(url.query(QUrl::ComponentFormattingOption::FullyDecoded));
outbound::ParseFromLink(link);
if (query.hasQueryItem("private_key")) private_key = query.queryItemValue("private_key");
peer->ParseFromLink(link);
QString rawLocalAddr = query.queryItemValue("local_address");
if (!rawLocalAddr.isEmpty()) {
address = rawLocalAddr.split("-");
}
if (query.hasQueryItem("mtu")) mtu = query.queryItemValue("mtu").toInt();
if (query.hasQueryItem("use_system_interface")) system = query.queryItemValue("use_system_interface") == "true";
if (query.hasQueryItem("workers")) worker_count = query.queryItemValue("workers").toInt();
if (query.hasQueryItem("udp_timeout")) udp_timeout = query.queryItemValue("udp_timeout");
enable_amnezia = query.queryItemValue("enable_amnezia") == "true";
if (enable_amnezia) {
if (query.hasQueryItem("junk_packet_count")) junk_packet_count = query.queryItemValue("junk_packet_count").toInt();
if (query.hasQueryItem("junk_packet_min_size")) junk_packet_min_size = query.queryItemValue("junk_packet_min_size").toInt();
if (query.hasQueryItem("junk_packet_max_size")) junk_packet_max_size = query.queryItemValue("junk_packet_max_size").toInt();
if (query.hasQueryItem("init_packet_junk_size")) init_packet_junk_size = query.queryItemValue("init_packet_junk_size").toInt();
if (query.hasQueryItem("response_packet_junk_size")) response_packet_junk_size = query.queryItemValue("response_packet_junk_size").toInt();
if (query.hasQueryItem("init_packet_magic_header")) init_packet_magic_header = query.queryItemValue("init_packet_magic_header").toInt();
if (query.hasQueryItem("response_packet_magic_header")) response_packet_magic_header = query.queryItemValue("response_packet_magic_header").toInt();
if (query.hasQueryItem("underload_packet_magic_header")) underload_packet_magic_header = query.queryItemValue("underload_packet_magic_header").toInt();
if (query.hasQueryItem("transport_packet_magic_header")) transport_packet_magic_header = query.queryItemValue("transport_packet_magic_header").toInt();
}
return !(private_key.isEmpty() || peer->public_key.isEmpty() || server.isEmpty());
}
bool wireguard::ParseFromJson(const QJsonObject& object)
{
if (object.isEmpty() || object["type"].toString() != "wireguard") return false;
outbound::ParseFromJson(object);
if (object.contains("private_key")) private_key = object["private_key"].toString();
if (object.contains("peer") && object["peer"].isObject()) peer->ParseFromJson(object["peer"].toObject());
if (object.contains("address")) address = QJsonArray2QListString(object["address"].toArray());
if (object.contains("mtu")) mtu = object["mtu"].toInt();
if (object.contains("system")) system = object["system"].toBool();
if (object.contains("worker_count")) worker_count = object["worker_count"].toInt();
if (object.contains("udp_timeout")) udp_timeout = object["udp_timeout"].toString();
return true;
}
QString wireguard::ExportToLink()
{
QUrl url;
QUrlQuery query;
url.setScheme("wg");
url.setHost(peer->address);
url.setPort(peer->port);
if (!name.isEmpty()) url.setFragment(name);
if (!private_key.isEmpty()) query.addQueryItem("private_key", private_key);
if (!address.isEmpty()) query.addQueryItem("local_address", address.join("-"));
if (mtu > 0 && mtu != 1420) query.addQueryItem("mtu", QString::number(mtu));
if (system) query.addQueryItem("use_system_interface", "true");
if (worker_count > 0) query.addQueryItem("workers", QString::number(worker_count));
if (!udp_timeout.isEmpty()) query.addQueryItem("udp_timeout", udp_timeout);
if (enable_amnezia) {
query.addQueryItem("enable_amnezia", "true");
if (junk_packet_count > 0) query.addQueryItem("junk_packet_count", QString::number(junk_packet_count));
if (junk_packet_min_size > 0) query.addQueryItem("junk_packet_min_size", QString::number(junk_packet_min_size));
if (junk_packet_max_size > 0) query.addQueryItem("junk_packet_max_size", QString::number(junk_packet_max_size));
if (init_packet_junk_size > 0) query.addQueryItem("init_packet_junk_size", QString::number(init_packet_junk_size));
if (response_packet_junk_size > 0) query.addQueryItem("response_packet_junk_size", QString::number(response_packet_junk_size));
if (init_packet_magic_header > 0) query.addQueryItem("init_packet_magic_header", QString::number(init_packet_magic_header));
if (response_packet_magic_header > 0) query.addQueryItem("response_packet_magic_header", QString::number(response_packet_magic_header));
if (underload_packet_magic_header > 0) query.addQueryItem("underload_packet_magic_header", QString::number(underload_packet_magic_header));
if (transport_packet_magic_header > 0) query.addQueryItem("transport_packet_magic_header", QString::number(transport_packet_magic_header));
}
mergeUrlQuery(query, outbound::ExportToLink());
mergeUrlQuery(query, peer->ExportToLink());
if (!query.isEmpty()) url.setQuery(query);
return url.toString();
}
QJsonObject wireguard::ExportToJson()
{
QJsonObject object;
object["type"] = "wireguard";
if (!name.isEmpty()) object["tag"] = name;
mergeJsonObjects(object, dialFields->ExportToJson());
if (!private_key.isEmpty()) object["private_key"] = private_key;
if (!address.isEmpty()) object["address"] = QListStr2QJsonArray(address);
if (mtu > 0) object["mtu"] = mtu;
if (system) object["system"] = system;
if (worker_count > 0) object["worker_count"] = worker_count;
if (!udp_timeout.isEmpty()) object["udp_timeout"] = udp_timeout;
auto peerObj = peer->ExportToJson();
if (!peerObj.isEmpty()) {
object["peers"] = QJsonArray({peerObj});
}
return object;
}
BuildResult wireguard::Build()
{
QJsonObject object;
object["type"] = "wireguard";
if (!name.isEmpty()) object["tag"] = name;
mergeJsonObjects(object, dialFields->Build().object);
if (!private_key.isEmpty()) object["private_key"] = private_key;
if (!address.isEmpty()) object["address"] = QListStr2QJsonArray(address);
if (mtu > 0) object["mtu"] = mtu;
if (system) object["system"] = system;
if (worker_count > 0) object["worker_count"] = worker_count;
if (!udp_timeout.isEmpty()) object["udp_timeout"] = udp_timeout;
auto peerObj = peer->Build().object;
if (!peerObj.isEmpty()) {
object["peers"] = QJsonArray({peerObj});
}
return {object, ""};
}
void wireguard::SetAddress(QString newAddr) {
peer->address = newAddr;
}
QString wireguard::GetAddress() {
return peer->address;
}
QString wireguard::DisplayAddress()
{
return ::DisplayAddress(peer->address, peer->port);
}
QString wireguard::DisplayType()
{
return "WireGuard";
}
bool wireguard::IsEndpoint()
{
return true;
}
}