mirror of
https://github.com/MatsuriDayo/nekoray.git
synced 2025-12-17 20:44:38 +03:00
feat: macos vpn
feat: macos & linux autorun
This commit is contained in:
@@ -760,6 +760,11 @@ namespace NekoRay {
|
|||||||
{"ip_cidr", QList2QJsonArray(arr)}};
|
{"ip_cidr", QList2QJsonArray(arr)}};
|
||||||
cidr_rule = "," + QJsonObject2QString(rule, false);
|
cidr_rule = "," + QJsonObject2QString(rule, false);
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
auto tun_name = "nekoray_tun";
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
tun_name = "utun9";
|
||||||
|
#endif
|
||||||
// gen config
|
// gen config
|
||||||
auto configFn = ":/neko/vpn/sing-box-vpn.json";
|
auto configFn = ":/neko/vpn/sing-box-vpn.json";
|
||||||
if (QFile::exists("vpn/sing-box-vpn.json")) configFn = "vpn/sing-box-vpn.json";
|
if (QFile::exists("vpn/sing-box-vpn.json")) configFn = "vpn/sing-box-vpn.json";
|
||||||
@@ -769,6 +774,7 @@ namespace NekoRay {
|
|||||||
.replace("%STACK%", Preset::SingBox::VpnImplementation.value(dataStore->vpn_implementation))
|
.replace("%STACK%", Preset::SingBox::VpnImplementation.value(dataStore->vpn_implementation))
|
||||||
.replace("%PROCESS_NAME_RULE%", process_name_rule)
|
.replace("%PROCESS_NAME_RULE%", process_name_rule)
|
||||||
.replace("%CIDR_RULE%", cidr_rule)
|
.replace("%CIDR_RULE%", cidr_rule)
|
||||||
|
.replace("%TUN_NAME%", tun_name)
|
||||||
.replace("%PORT%", Int2String(dataStore->inbound_socks_port));
|
.replace("%PORT%", Int2String(dataStore->inbound_socks_port));
|
||||||
// write config
|
// write config
|
||||||
QFile file;
|
QFile file;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"inbounds": [
|
"inbounds": [
|
||||||
{
|
{
|
||||||
"type": "tun",
|
"type": "tun",
|
||||||
"interface_name": "nekoray-tun",
|
"interface_name": "%TUN_NAME%",
|
||||||
"inet4_address": "172.19.0.1/28",
|
"inet4_address": "172.19.0.1/28",
|
||||||
%IPV6_ADDRESS%
|
%IPV6_ADDRESS%
|
||||||
"mtu": %MTU%,
|
"mtu": %MTU%,
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ if [ "$EUID" -ne 0 ]; then
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$(uname)" == "Darwin" ]; then
|
||||||
|
IS_MACOS=1
|
||||||
|
fi
|
||||||
|
|
||||||
[ -z $PORT ] && echo "Please set env PORT" && exit
|
[ -z $PORT ] && echo "Please set env PORT" && exit
|
||||||
[ -z $TABLE_FWMARK ] && echo "Please set env TABLE_FWMARK" && exit
|
[ -z $TABLE_FWMARK ] && echo "Please set env TABLE_FWMARK" && exit
|
||||||
command -v pkill >/dev/null 2>&1 || exit
|
command -v pkill >/dev/null 2>&1 || exit
|
||||||
@@ -14,7 +18,7 @@ command -v pkill >/dev/null 2>&1 || exit
|
|||||||
BASEDIR=$(dirname "$0")
|
BASEDIR=$(dirname "$0")
|
||||||
cd $BASEDIR
|
cd $BASEDIR
|
||||||
|
|
||||||
start() {
|
pre_start_linux() {
|
||||||
# set bypass: fwmark
|
# set bypass: fwmark
|
||||||
ip rule add pref 8999 fwmark $TABLE_FWMARK table main || return
|
ip rule add pref 8999 fwmark $TABLE_FWMARK table main || return
|
||||||
ip -6 rule add pref 8999 fwmark $TABLE_FWMARK table main || return
|
ip -6 rule add pref 8999 fwmark $TABLE_FWMARK table main || return
|
||||||
@@ -22,11 +26,15 @@ start() {
|
|||||||
# for Tun2Socket
|
# for Tun2Socket
|
||||||
iptables -I INPUT -s 172.19.0.2 -d 172.19.0.1 -p tcp -j ACCEPT
|
iptables -I INPUT -s 172.19.0.2 -d 172.19.0.1 -p tcp -j ACCEPT
|
||||||
ip6tables -I INPUT -s fdfe:dcba:9876::2 -d fdfe:dcba:9876::1 -p tcp -j ACCEPT
|
ip6tables -I INPUT -s fdfe:dcba:9876::2 -d fdfe:dcba:9876::1 -p tcp -j ACCEPT
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
[ -z $IS_MACOS ] && pre_start_linux
|
||||||
"./nekobox_core" run -c "$CONFIG_PATH" --protect-listen-path "$PROTECT_LISTEN_PATH" --protect-fwmark $TABLE_FWMARK
|
"./nekobox_core" run -c "$CONFIG_PATH" --protect-listen-path "$PROTECT_LISTEN_PATH" --protect-fwmark $TABLE_FWMARK
|
||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
|
[ -z $IS_MACOS ] || return
|
||||||
for local in $BYPASS_IPS; do
|
for local in $BYPASS_IPS; do
|
||||||
ip rule del to $local table main
|
ip rule del to $local table main
|
||||||
done
|
done
|
||||||
|
|||||||
168
sys/AutoRun.cpp
168
sys/AutoRun.cpp
@@ -1,10 +1,16 @@
|
|||||||
#include "AutoRun.hpp"
|
#include "AutoRun.hpp"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
// macOS headers (possibly OBJ-c)
|
||||||
|
#if defined(Q_OS_MACOS)
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
#include <CoreServices/CoreServices.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
|
||||||
//设置程序自启动 appPath程序路径
|
//设置程序自启动 appPath程序路径
|
||||||
@@ -54,16 +60,168 @@ bool GetProcessAutoRunSelf() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#else
|
#endif
|
||||||
|
|
||||||
#include <QMessageBox>
|
#ifdef Q_OS_MACOS
|
||||||
|
|
||||||
void SetProcessAutoRunSelf(bool enable) {
|
void SetProcessAutoRunSelf(bool enable) {
|
||||||
QMessageBox::warning(nullptr, "Error", "Autorun is not yet implemented on your platform.");
|
// From
|
||||||
|
// https://github.com/nextcloud/desktop/blob/master/src/common/utility_mac.cpp
|
||||||
|
QString filePath = QDir(QCoreApplication::applicationDirPath() + QLatin1String("/../..")).absolutePath();
|
||||||
|
CFStringRef folderCFStr = CFStringCreateWithCString(0, filePath.toUtf8().data(), kCFStringEncodingUTF8);
|
||||||
|
CFURLRef urlRef = CFURLCreateWithFileSystemPath(0, folderCFStr, kCFURLPOSIXPathStyle, true);
|
||||||
|
LSSharedFileListRef loginItems = LSSharedFileListCreate(0, kLSSharedFileListSessionLoginItems, 0);
|
||||||
|
|
||||||
|
if (loginItems && enable) {
|
||||||
|
// Insert an item to the list.
|
||||||
|
LSSharedFileListItemRef item =
|
||||||
|
LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemLast, 0, 0, urlRef, 0, 0);
|
||||||
|
|
||||||
|
if (item) CFRelease(item);
|
||||||
|
|
||||||
|
CFRelease(loginItems);
|
||||||
|
} else if (loginItems && !enable) {
|
||||||
|
// We need to iterate over the items and check which one is "ours".
|
||||||
|
UInt32 seedValue;
|
||||||
|
CFArrayRef itemsArray = LSSharedFileListCopySnapshot(loginItems, &seedValue);
|
||||||
|
CFStringRef appUrlRefString = CFURLGetString(urlRef);
|
||||||
|
|
||||||
|
for (int i = 0; i < CFArrayGetCount(itemsArray); i++) {
|
||||||
|
LSSharedFileListItemRef item = (LSSharedFileListItemRef) CFArrayGetValueAtIndex(itemsArray, i);
|
||||||
|
CFURLRef itemUrlRef = NULL;
|
||||||
|
|
||||||
|
if (LSSharedFileListItemResolve(item, 0, &itemUrlRef, NULL) == noErr && itemUrlRef) {
|
||||||
|
CFStringRef itemUrlString = CFURLGetString(itemUrlRef);
|
||||||
|
|
||||||
|
if (CFStringCompare(itemUrlString, appUrlRefString, 0) == kCFCompareEqualTo) {
|
||||||
|
LSSharedFileListItemRemove(loginItems, item); // remove it!
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(itemUrlRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(itemsArray);
|
||||||
|
CFRelease(loginItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(folderCFStr);
|
||||||
|
CFRelease(urlRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetProcessAutoRunSelf() {
|
bool GetProcessAutoRunSelf() {
|
||||||
return false;
|
// From
|
||||||
|
// https://github.com/nextcloud/desktop/blob/master/src/common/utility_mac.cpp
|
||||||
|
// this is quite some duplicate code with setLaunchOnStartup, at some
|
||||||
|
// point we should fix this FIXME.
|
||||||
|
bool returnValue = false;
|
||||||
|
QString filePath = QDir(QCoreApplication::applicationDirPath() + QLatin1String("/../..")).absolutePath();
|
||||||
|
CFStringRef folderCFStr = CFStringCreateWithCString(0, filePath.toUtf8().data(), kCFStringEncodingUTF8);
|
||||||
|
CFURLRef urlRef = CFURLCreateWithFileSystemPath(0, folderCFStr, kCFURLPOSIXPathStyle, true);
|
||||||
|
LSSharedFileListRef loginItems = LSSharedFileListCreate(0, kLSSharedFileListSessionLoginItems, 0);
|
||||||
|
|
||||||
|
if (loginItems) {
|
||||||
|
// We need to iterate over the items and check which one is "ours".
|
||||||
|
UInt32 seedValue;
|
||||||
|
CFArrayRef itemsArray = LSSharedFileListCopySnapshot(loginItems, &seedValue);
|
||||||
|
CFStringRef appUrlRefString = CFURLGetString(urlRef); // no need for release
|
||||||
|
|
||||||
|
for (int i = 0; i < CFArrayGetCount(itemsArray); i++) {
|
||||||
|
LSSharedFileListItemRef item = (LSSharedFileListItemRef) CFArrayGetValueAtIndex(itemsArray, i);
|
||||||
|
CFURLRef itemUrlRef = NULL;
|
||||||
|
|
||||||
|
if (LSSharedFileListItemResolve(item, 0, &itemUrlRef, NULL) == noErr && itemUrlRef) {
|
||||||
|
CFStringRef itemUrlString = CFURLGetString(itemUrlRef);
|
||||||
|
|
||||||
|
if (CFStringCompare(itemUrlString, appUrlRefString, 0) == kCFCompareEqualTo) {
|
||||||
|
returnValue = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(itemUrlRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(itemsArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(loginItems);
|
||||||
|
CFRelease(folderCFStr);
|
||||||
|
CFRelease(urlRef);
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
|
#define NEWLINE "\r\n"
|
||||||
|
|
||||||
|
// launchatlogin.cpp
|
||||||
|
// ShadowClash
|
||||||
|
//
|
||||||
|
// Created by TheWanderingCoel on 2018/6/12.
|
||||||
|
// Copyright © 2019 Coel Wu. All rights reserved.
|
||||||
|
//
|
||||||
|
QString getUserAutostartDir_private() {
|
||||||
|
QString config = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
|
||||||
|
config += QLatin1String("/autostart/");
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetProcessAutoRunSelf(bool enable) {
|
||||||
|
// From https://github.com/nextcloud/desktop/blob/master/src/common/utility_unix.cpp
|
||||||
|
QString appName = QCoreApplication::applicationName();
|
||||||
|
QString userAutoStartPath = getUserAutostartDir_private();
|
||||||
|
QString desktopFileLocation = userAutoStartPath + appName + QLatin1String(".desktop");
|
||||||
|
QStringList appCmdList = {QApplication::applicationFilePath()};
|
||||||
|
|
||||||
|
// nekoray: launcher
|
||||||
|
auto launcherPath = QApplication::applicationDirPath() + "/launcher";
|
||||||
|
if (QFile::exists(launcherPath)) {
|
||||||
|
appCmdList = QStringList{launcherPath};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
if (!QDir().exists(userAutoStartPath) && !QDir().mkpath(userAutoStartPath)) {
|
||||||
|
// qCWarning(lcUtility) << "Could not create autostart folder"
|
||||||
|
// << userAutoStartPath;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile iniFile(desktopFileLocation);
|
||||||
|
|
||||||
|
if (!iniFile.open(QIODevice::WriteOnly)) {
|
||||||
|
// qCWarning(lcUtility) << "Could not write auto start entry" <<
|
||||||
|
// desktopFileLocation;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextStream ts(&iniFile);
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
ts.setCodec("UTF-8");
|
||||||
|
#endif
|
||||||
|
ts << QLatin1String("[Desktop Entry]") << NEWLINE //
|
||||||
|
<< QLatin1String("Name=") << appName << NEWLINE //
|
||||||
|
<< QLatin1String("Exec=") << appCmdList.join(" ") << NEWLINE //
|
||||||
|
<< QLatin1String("Terminal=") << "false" << NEWLINE //
|
||||||
|
<< QLatin1String("Categories=") << "Network" << NEWLINE //
|
||||||
|
<< QLatin1String("Type=") << "Application" << NEWLINE //
|
||||||
|
<< QLatin1String("StartupNotify=") << "false" << NEWLINE //
|
||||||
|
<< QLatin1String("X-GNOME-Autostart-enabled=") << "true" << NEWLINE;
|
||||||
|
ts.flush();
|
||||||
|
iniFile.close();
|
||||||
|
} else {
|
||||||
|
QFile::remove(desktopFileLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetProcessAutoRunSelf() {
|
||||||
|
QString appName = QCoreApplication::applicationName();
|
||||||
|
QString desktopFileLocation = getUserAutostartDir_private() + appName + QLatin1String(".desktop");
|
||||||
|
return QFile::exists(desktopFileLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1477,7 +1477,12 @@ bool MainWindow::StartVPNProcess() {
|
|||||||
});
|
});
|
||||||
//
|
//
|
||||||
vpn_process->setProcessChannelMode(QProcess::ForwardedChannels);
|
vpn_process->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
vpn_process->start("osascript", {"-e", QString("do shell script \"%1\" with administrator privileges")
|
||||||
|
.arg("bash " + scriptPath)});
|
||||||
|
#else
|
||||||
vpn_process->start("pkexec", {"bash", scriptPath});
|
vpn_process->start("pkexec", {"bash", scriptPath});
|
||||||
|
#endif
|
||||||
vpn_process->waitForStarted();
|
vpn_process->waitForStarted();
|
||||||
vpn_pid = vpn_process->processId(); // actually it's pkexec or bash PID
|
vpn_pid = vpn_process->processId(); // actually it's pkexec or bash PID
|
||||||
#endif
|
#endif
|
||||||
@@ -1495,7 +1500,12 @@ bool MainWindow::StopVPNProcess() {
|
|||||||
ok = ret == 0;
|
ok = ret == 0;
|
||||||
#else
|
#else
|
||||||
QProcess p;
|
QProcess p;
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
p.start("osascript", {"-e", QString("do shell script \"%1\" with administrator privileges")
|
||||||
|
.arg("pkill -2 -U 0 nekobox_core")});
|
||||||
|
#else
|
||||||
p.start("pkexec", {"pkill", "-2", "-P", Int2String(vpn_pid)});
|
p.start("pkexec", {"pkill", "-2", "-P", Int2String(vpn_pid)});
|
||||||
|
#endif
|
||||||
p.waitForFinished();
|
p.waitForFinished();
|
||||||
ok = p.exitCode() == 0;
|
ok = p.exitCode() == 0;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user