From c3f184eb9d0c098e33b0a0edef3bad3f7c4554a1 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Aug 2024 02:02:48 +0330 Subject: [PATCH] feat: Add wireguard support --- CMakeLists.txt | 4 ++ db/Database.cpp | 2 + db/ProxyEntity.hpp | 6 +++ fmt/Bean2CoreObj_box.cpp | 25 +++++++++ fmt/Bean2Link.cpp | 17 +++++++ fmt/Link2Bean.cpp | 21 ++++++++ fmt/WireguardBean.h | 45 +++++++++++++++++ fmt/includes.h | 1 + sub/GroupUpdater.cpp | 8 +++ ui/edit/dialog_edit_profile.cpp | 6 +++ ui/edit/edit_wireguard.cpp | 49 ++++++++++++++++++ ui/edit/edit_wireguard.h | 27 ++++++++++ ui/edit/edit_wireguard.ui | 89 +++++++++++++++++++++++++++++++++ 13 files changed, 300 insertions(+) create mode 100644 fmt/WireguardBean.h create mode 100644 ui/edit/edit_wireguard.cpp create mode 100644 ui/edit/edit_wireguard.h create mode 100644 ui/edit/edit_wireguard.ui diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c3d01f..a9e9be5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,6 +159,10 @@ set(PROJECT_SOURCES ui/edit/edit_custom.cpp ui/edit/edit_custom.ui + ui/edit/edit_wireguard.h + ui/edit/edit_wireguard.cpp + ui/edit/edit_wireguard.ui + ui/dialog_basic_settings.cpp ui/dialog_basic_settings.h ui/dialog_basic_settings.ui diff --git a/db/Database.cpp b/db/Database.cpp index c44c230..59cad5e 100644 --- a/db/Database.cpp +++ b/db/Database.cpp @@ -223,6 +223,8 @@ namespace NekoGui { bean = new NekoGui_fmt::QUICBean(NekoGui_fmt::QUICBean::proxy_Hysteria2); } else if (type == "tuic") { bean = new NekoGui_fmt::QUICBean(NekoGui_fmt::QUICBean::proxy_TUIC); + } else if (type == "wireguard") { + bean = new NekoGui_fmt::WireguardBean(NekoGui_fmt::WireguardBean()); } else if (type == "custom") { bean = new NekoGui_fmt::CustomBean(); } else { diff --git a/db/ProxyEntity.hpp b/db/ProxyEntity.hpp index f0cded9..bc5911e 100644 --- a/db/ProxyEntity.hpp +++ b/db/ProxyEntity.hpp @@ -17,6 +17,8 @@ namespace NekoGui_fmt { class QUICBean; + class WireguardBean; + class CustomBean; class ChainBean; @@ -69,6 +71,10 @@ namespace NekoGui { return (NekoGui_fmt::QUICBean *) bean.get(); }; + [[nodiscard]] NekoGui_fmt::WireguardBean *WireguardBean() const { + return (NekoGui_fmt::WireguardBean *) bean.get(); + }; + [[nodiscard]] NekoGui_fmt::CustomBean *CustomBean() const { return (NekoGui_fmt::CustomBean *) bean.get(); }; diff --git a/fmt/Bean2CoreObj_box.cpp b/fmt/Bean2CoreObj_box.cpp index ba7ff11..040c3bb 100644 --- a/fmt/Bean2CoreObj_box.cpp +++ b/fmt/Bean2CoreObj_box.cpp @@ -242,6 +242,31 @@ namespace NekoGui_fmt { return result; } + CoreObjOutboundBuildResult WireguardBean::BuildCoreObjSingBox() { + CoreObjOutboundBuildResult result; + + auto tun_name = "nekoray-tunwg"; +#ifdef Q_OS_MACOS + tun_name = "utunwg9"; +#endif + + QJsonObject outbound{ + {"type", "wireguard"}, + {"server", serverAddress}, + {"server_port", serverPort}, + {"interface_name", tun_name}, + {"local_address", QJsonArray{"172.20.0.1/24", "fdfe:dcba:9876::1/96"}}, + {"private_key", privateKey}, + {"peer_public_key", publicKey}, + {"pre_shared_key", preSharedKey}, + {"reserved", QListInt2QJsonArray(reserved)}, + {"mtu", MTU}, + }; + + result.outbound = outbound; + return result; + } + CoreObjOutboundBuildResult CustomBean::BuildCoreObjSingBox() { CoreObjOutboundBuildResult result; diff --git a/fmt/Bean2Link.cpp b/fmt/Bean2Link.cpp index dbcde89..a37a36b 100644 --- a/fmt/Bean2Link.cpp +++ b/fmt/Bean2Link.cpp @@ -242,4 +242,21 @@ namespace NekoGui_fmt { return url.toString(QUrl::FullyEncoded); } + QString WireguardBean::ToShareLink() { + QUrl url; + url.setScheme("wg"); + url.setHost(serverAddress); + url.setPort(serverPort); + if (!name.isEmpty()) url.setFragment(name); + QUrlQuery q; + q.addQueryItem("private_key", privateKey); + q.addQueryItem("peer_public_key", publicKey); + q.addQueryItem("pre_shared_key", preSharedKey); + q.addQueryItem("reserved", FormatReserved()); + q.addQueryItem("mtu", Int2String(MTU)); + q.addQueryItem("use_system_interface", useSystemInterface ? "true":"false"); + url.setQuery(q); + return url.toString(QUrl::FullyEncoded); + } + } // namespace NekoGui_fmt \ No newline at end of file diff --git a/fmt/Link2Bean.cpp b/fmt/Link2Bean.cpp index c8f1867..ebd64a2 100644 --- a/fmt/Link2Bean.cpp +++ b/fmt/Link2Bean.cpp @@ -333,4 +333,25 @@ namespace NekoGui_fmt { return true; } + bool WireguardBean::TryParseLink(const QString &link) { + auto url = QUrl(link); + if (!url.isValid()) return false; + auto query = GetQuery(url); + + name = url.fragment(QUrl::FullyDecoded); + serverAddress = url.host(); + serverPort = url.port(); + privateKey = query.queryItemValue("private_key"); + publicKey = query.queryItemValue("peer_public_key"); + preSharedKey = query.queryItemValue("pre_shared_key"); + auto rawReserved = query.queryItemValue("reserved"); + if (!rawReserved.isEmpty()) { + for (const auto &item: rawReserved.split("-")) reserved += item.toInt(); + } + MTU = query.queryItemValue("mtu").toInt(); + useSystemInterface = query.queryItemValue("use_system_interface") == "true"; + + return true; + } + } // namespace NekoGui_fmt \ No newline at end of file diff --git a/fmt/WireguardBean.h b/fmt/WireguardBean.h new file mode 100644 index 0000000..fc8ca58 --- /dev/null +++ b/fmt/WireguardBean.h @@ -0,0 +1,45 @@ +#pragma once + +#include "fmt/AbstractBean.hpp" + +namespace NekoGui_fmt { + class WireguardBean : public AbstractBean { + public: + QString privateKey; + QString publicKey; + QString preSharedKey; + QList reserved; + int MTU = 1420; + bool useSystemInterface = false; + bool enableGSO = false; + + WireguardBean() : AbstractBean(0) { + _add(new configItem("private_key", &privateKey, itemType::string)); + _add(new configItem("public_key", &publicKey, itemType::string)); + _add(new configItem("pre_shared_key", &preSharedKey, itemType::string)); + _add(new configItem("reserved", &reserved, itemType::integerList)); + _add(new configItem("mtu", &MTU, itemType::integer)); + _add(new configItem("use_system_proxy", &useSystemInterface, itemType::boolean)); + _add(new configItem("enable_gso", &enableGSO, itemType::boolean)); + }; + + QString FormatReserved() { + QString res = ""; + for (int i=0;iWireguardBean()->TryParseLink(str); + if (!ok) return; + } + if (ent == nullptr) return; // Fix diff --git a/ui/edit/dialog_edit_profile.cpp b/ui/edit/dialog_edit_profile.cpp index 78ee01e..a1a9186 100644 --- a/ui/edit/dialog_edit_profile.cpp +++ b/ui/edit/dialog_edit_profile.cpp @@ -8,6 +8,7 @@ #include "ui/edit/edit_trojan_vless.h" #include "ui/edit/edit_naive.h" #include "ui/edit/edit_quic.h" +#include "ui/edit/edit_wireguard.h" #include "ui/edit/edit_custom.h" #include "fmt/includes.h" @@ -140,6 +141,7 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId, LOAD_TYPE("hysteria") LOAD_TYPE("hysteria2") LOAD_TYPE("tuic") + LOAD_TYPE("wireguard") ui->type->addItem(tr("Custom (%1 outbound)").arg(software_core_name), "internal"); ui->type->addItem(tr("Custom (%1 config)").arg(software_core_name), "internal-full"); ui->type->addItem(tr("Custom (Extra Core)"), "custom"); @@ -199,6 +201,10 @@ void DialogEditProfile::typeSelected(const QString &newType) { auto _innerWidget = new EditQUIC(this); innerWidget = _innerWidget; innerEditor = _innerWidget; + } else if (type == "wireguard") { + auto _innerWidget = new EditWireguard(this); + innerWidget = _innerWidget; + innerEditor = _innerWidget; } else if (type == "custom" || type == "internal" || type == "internal-full") { auto _innerWidget = new EditCustom(this); innerWidget = _innerWidget; diff --git a/ui/edit/edit_wireguard.cpp b/ui/edit/edit_wireguard.cpp new file mode 100644 index 0000000..5264559 --- /dev/null +++ b/ui/edit/edit_wireguard.cpp @@ -0,0 +1,49 @@ +#include "edit_wireguard.h" +#include "ui_edit_wireguard.h" + +#include "fmt/WireguardBean.h" + +EditWireguard::EditWireguard(QWidget *parent) : QWidget(parent), ui(new Ui::EditWireguard) { + ui->setupUi(this); +} + +EditWireguard::~EditWireguard() { + delete ui; +} + +void EditWireguard::onStart(std::shared_ptr _ent) { + this->ent = _ent; + auto bean = this->ent->WireguardBean(); + +#ifndef Q_OS_LINUX + ui->enable_gso->hide(); + adjustSize(); +#endif + + ui->private_key->setText(bean->privateKey); + ui->public_key->setText(bean->publicKey); + ui->preshared_key->setText(bean->preSharedKey); + auto reservedStr = bean->FormatReserved().replace("-", ","); + ui->reserved->setText(reservedStr); + ui->mtu->setText(Int2String(bean->MTU)); + ui->sys_ifc->setChecked(bean->useSystemInterface); + ui->enable_gso->setChecked(bean->enableGSO); +} + +bool EditWireguard::onEnd() { + auto bean = this->ent->WireguardBean(); + + bean->privateKey = ui->private_key->text(); + bean->publicKey = ui->public_key->text(); + bean->preSharedKey = ui->preshared_key->text(); + auto rawReserved = ui->reserved->text(); + bean->reserved = {}; + for (const auto& item: rawReserved.split(",")) { + bean->reserved += item.trimmed().toInt(); + } + bean->MTU = ui->mtu->text().toInt(); + bean->useSystemInterface = ui->sys_ifc->isChecked(); + bean->enableGSO = ui->enable_gso->isChecked(); + + return true; +} \ No newline at end of file diff --git a/ui/edit/edit_wireguard.h b/ui/edit/edit_wireguard.h new file mode 100644 index 0000000..3b6d3d4 --- /dev/null +++ b/ui/edit/edit_wireguard.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include "profile_editor.h" + +QT_BEGIN_NAMESPACE +namespace Ui { + class EditWireguard; +} +QT_END_NAMESPACE + +class EditWireguard : public QWidget, public ProfileEditor { + Q_OBJECT + +public: + explicit EditWireguard(QWidget *parent = nullptr); + + ~EditWireguard() override; + + void onStart(std::shared_ptr _ent) override; + + bool onEnd() override; + +private: + Ui::EditWireguard *ui; + std::shared_ptr ent; +}; diff --git a/ui/edit/edit_wireguard.ui b/ui/edit/edit_wireguard.ui new file mode 100644 index 0000000..f72da99 --- /dev/null +++ b/ui/edit/edit_wireguard.ui @@ -0,0 +1,89 @@ + + + EditWireguard + + + + 0 + 0 + 400 + 300 + + + + EditWireguard + + + + + + + + + + + + + + + Public Key + + + + + + + + + + Enable GSO + + + + + + + Pre Shared Key + + + + + + + Private Key + + + + + + + Use System Interface + + + + + + + Reserved + + + + + + + 1420 + + + + + + + MTU + + + + + + + +