feat: Add wireguard support

This commit is contained in:
unknown 2024-08-07 02:02:48 +03:30
parent 4c203ef443
commit c3f184eb9d
No known key found for this signature in database
GPG Key ID: C2CA486E4F771093
13 changed files with 300 additions and 0 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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();
};

View File

@ -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;

View File

@ -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

View File

@ -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

45
fmt/WireguardBean.h Normal file
View File

@ -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<int> 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;i<reserved.size();i++) {
res += Int2String(reserved[i]);
if (i != reserved.size() - 1) {
res += "-";
}
}
return res;
}
QString DisplayType() override { return "Wireguard"; };
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
bool TryParseLink(const QString &link);
QString ToShareLink() override;
};
} // namespace NekoGui_fmt

View File

@ -7,4 +7,5 @@
#include "TrojanVLESSBean.hpp"
#include "NaiveBean.hpp"
#include "QUICBean.hpp"
#include "WireguardBean.h"
#include "CustomBean.hpp"

View File

@ -202,6 +202,14 @@ namespace NekoGui_sub {
if (!ok) return;
}
// Wireguard
if (str.startsWith("wg://")) {
needFix = false;
ent = NekoGui::ProfileManager::NewProxyEntity("wireguard");
auto ok = ent->WireguardBean()->TryParseLink(str);
if (!ok) return;
}
if (ent == nullptr) return;
// Fix

View File

@ -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;

View File

@ -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<NekoGui::ProxyEntity> _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;
}

27
ui/edit/edit_wireguard.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include <QWidget>
#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<NekoGui::ProxyEntity> _ent) override;
bool onEnd() override;
private:
Ui::EditWireguard *ui;
std::shared_ptr<NekoGui::ProxyEntity> ent;
};

89
ui/edit/edit_wireguard.ui Normal file
View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditWireguard</class>
<widget class="QWidget" name="EditWireguard">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>EditWireguard</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="5" column="1">
<widget class="QLineEdit" name="reserved"/>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="public_key"/>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="private_key"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="public_key_l">
<property name="text">
<string>Public Key</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="preshared_key"/>
</item>
<item row="8" column="1">
<widget class="QCheckBox" name="enable_gso">
<property name="text">
<string>Enable GSO</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="preshared_key_l">
<property name="text">
<string>Pre Shared Key</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="private_key_l">
<property name="text">
<string>Private Key</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QCheckBox" name="sys_ifc">
<property name="text">
<string>Use System Interface</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="reserved_l">
<property name="text">
<string>Reserved</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="mtu">
<property name="text">
<string>1420</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="mtu_l">
<property name="text">
<string>MTU</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>