Skip to content

Commit

Permalink
feat: macos vpn
Browse files Browse the repository at this point in the history
feat: macos & linux autorun
  • Loading branch information
arm64v8a committed Oct 22, 2022
1 parent 38de968 commit 062c947
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 7 deletions.
6 changes: 6 additions & 0 deletions db/ConfigBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,11 @@ namespace NekoRay {
{"ip_cidr", QList2QJsonArray(arr)}};
cidr_rule = "," + QJsonObject2QString(rule, false);
}
//
auto tun_name = "nekoray_tun";
#ifdef Q_OS_MACOS
tun_name = "utun9";
#endif
// gen config
auto configFn = ":/neko/vpn/sing-box-vpn.json";
if (QFile::exists("vpn/sing-box-vpn.json")) configFn = "vpn/sing-box-vpn.json";
Expand All @@ -769,6 +774,7 @@ namespace NekoRay {
.replace("%STACK%", Preset::SingBox::VpnImplementation.value(dataStore->vpn_implementation))
.replace("%PROCESS_NAME_RULE%", process_name_rule)
.replace("%CIDR_RULE%", cidr_rule)
.replace("%TUN_NAME%", tun_name)
.replace("%PORT%", Int2String(dataStore->inbound_socks_port));
// write config
QFile file;
Expand Down
2 changes: 1 addition & 1 deletion examples/sing-box-vpn.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"inbounds": [
{
"type": "tun",
"interface_name": "nekoray-tun",
"interface_name": "%TUN_NAME%",
"inet4_address": "172.19.0.1/28",
%IPV6_ADDRESS%
"mtu": %MTU%,
Expand Down
10 changes: 9 additions & 1 deletion examples/vpn-run-root.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,34 @@ if [ "$EUID" -ne 0 ]; then
exit
fi

if [ "$(uname)" == "Darwin" ]; then
IS_MACOS=1
fi

[ -z $PORT ] && echo "Please set env PORT" && exit
[ -z $TABLE_FWMARK ] && echo "Please set env TABLE_FWMARK" && exit
command -v pkill >/dev/null 2>&1 || exit

BASEDIR=$(dirname "$0")
cd $BASEDIR

start() {
pre_start_linux() {
# set bypass: fwmark
ip rule add pref 8999 fwmark $TABLE_FWMARK table main || return
ip -6 rule add pref 8999 fwmark $TABLE_FWMARK table main || return

# for Tun2Socket
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
}

start() {
[ -z $IS_MACOS ] && pre_start_linux
"./nekobox_core" run -c "$CONFIG_PATH" --protect-listen-path "$PROTECT_LISTEN_PATH" --protect-fwmark $TABLE_FWMARK
}

stop() {
[ -z $IS_MACOS ] || return
for local in $BYPASS_IPS; do
ip rule del to $local table main
done
Expand Down
168 changes: 163 additions & 5 deletions sys/AutoRun.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
#include "AutoRun.hpp"

#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

#include <QDir>
#include <QSettings>

//设置程序自启动 appPath程序路径
Expand Down Expand Up @@ -54,16 +60,168 @@ bool GetProcessAutoRunSelf() {
}


#else
#endif

#include <QMessageBox>
#ifdef Q_OS_MACOS

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() {
// 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() {
return false;
QString appName = QCoreApplication::applicationName();
QString desktopFileLocation = getUserAutostartDir_private() + appName + QLatin1String(".desktop");
return QFile::exists(desktopFileLocation);
}

#endif
10 changes: 10 additions & 0 deletions ui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1477,7 +1477,12 @@ bool MainWindow::StartVPNProcess() {
});
//
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});
#endif
vpn_process->waitForStarted();
vpn_pid = vpn_process->processId(); // actually it's pkexec or bash PID
#endif
Expand All @@ -1495,7 +1500,12 @@ bool MainWindow::StopVPNProcess() {
ok = ret == 0;
#else
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)});
#endif
p.waitForFinished();
ok = p.exitCode() == 0;
#endif
Expand Down

0 comments on commit 062c947

Please sign in to comment.