From fa2d60e1b801f040e48da4e00b85eb41b0c522fe Mon Sep 17 00:00:00 2001 From: eventlOwOp <3064273390@qq.com> Date: Tue, 2 Jul 2024 12:25:20 +0800 Subject: [PATCH] update zerotier module to support rootless app --- README.md | 8 ++- README_ZH.md | 8 ++- app/lib/authed_client.dart | 9 ++- app/lib/main.dart | 11 ++- app/pubspec.lock | 90 +++++++++++++++++++++++- app/pubspec.yaml | 1 + magisk/customize.sh | 1 + magisk/handle.sh | 83 ++++++++++++++++++++++ magisk/service.sh | 134 ++++++++++++++---------------------- magisk/vars.sh | 12 ++++ magisk/zerotier/zerotier.sh | 18 +++-- 11 files changed, 271 insertions(+), 104 deletions(-) create mode 100644 magisk/handle.sh create mode 100644 magisk/vars.sh diff --git a/README.md b/README.md index 4d354aa..28efcc6 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ **Use Android App to control ZeroTier** +**Support for Private Root Servers** + ## Requirements 1. a version is built with Android NDK Toolchain, supporting api 28 (Android 9.0) and above. @@ -34,9 +36,13 @@ AArch64 suppots ARMv8-A and above; Arm version supports ARMv7-A (compiling with ## Usage +### Use Private Root Servers + +Replace `/data/adb/zerotier/home/planet` with your own `planet` file. + ### Controller App -Needs root privilege +Does not need root privilege | Feature | Supported? | | :----------------- | :--------- | diff --git a/README_ZH.md b/README_ZH.md index dac56fe..07d2563 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -14,6 +14,8 @@ **使用 Android App 进行控制** +**支持自建 Planet** + ## 运行要求 1. 使用 NDK 编译的版本,支持 api 28 (Android 9.0) 及以上的设备 @@ -34,9 +36,13 @@ AArch64 版本支持 ARMv8-A 及以上;Arm 版本均对 ARMv7-A 进行编译 ( ## 使用 +### 自建 Planet + +将 `/data/adb/zerotier/home/planet` 替换为自己的 planet 文件即可 + ### 控制器 App -需要 root 授权 +无需 root 授权 | 功能 | 支持状态 | | :--------------- | :------- | diff --git a/app/lib/authed_client.dart b/app/lib/authed_client.dart index 881fdca..6f3a2c7 100644 --- a/app/lib/authed_client.dart +++ b/app/lib/authed_client.dart @@ -1,5 +1,6 @@ import 'dart:io'; import 'package:http/http.dart' as http; +import 'package:path_provider/path_provider.dart'; class AuthedClientInner extends http.BaseClient { final String _secret; @@ -25,9 +26,11 @@ class AuthedClientInner extends http.BaseClient { class AuthedClient { late Future client; Future loadSecret() async { - final results = await Process.run( - 'su', ['-c', 'cat', '/data/adb/zerotier/home/authtoken.secret']); - return AuthedClientInner(results.stdout.toString().trim(), http.Client()); + final path = (await getApplicationDocumentsDirectory()).path; + final file = File('$path/authtoken'); + final token = await file.readAsString(); + + return AuthedClientInner(token.trim(), http.Client()); } AuthedClient() { diff --git a/app/lib/main.dart b/app/lib/main.dart index 74f2e7e..8aca9bc 100644 --- a/app/lib/main.dart +++ b/app/lib/main.dart @@ -40,9 +40,8 @@ class MyHomePage extends StatefulWidget { State createState() => _MyHomePageState(); } -Future zerotierCommand(String exe, String command) { - return Process.run('su', ['-c', '/data/adb/zerotier/$exe', command], - environment: {'LD_LIBRARY_PATH': '/system/lib64:/data/adb/zerotier/lib'}); +Future zerotierCommand(String command) { + return Process.run('echo', [command, '>/data/data/com.eventlowop.zerotier_magisk_app/files/pipe']); } class _MyHomePageState extends State { @@ -125,9 +124,9 @@ class _MyHomePageState extends State { _MyHomePageState() : super() { restartFn = - cmdButtonWrapper(() => zerotierCommand('zerotier.sh', 'restart')); - startFn = cmdButtonWrapper(() => zerotierCommand('zerotier.sh', 'start')); - stopFn = cmdButtonWrapper(() => zerotierCommand('zerotier.sh', 'stop')); + cmdButtonWrapper(() => zerotierCommand('restart')); + startFn = cmdButtonWrapper(() => zerotierCommand('start')); + stopFn = cmdButtonWrapper(() => zerotierCommand('stop')); joinFn = cmdButtonWrapper(() => joinNetwork(_idInputController.text)); } diff --git a/app/pubspec.lock b/app/pubspec.lock index 7e225d1..1e63f0c 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -97,6 +97,14 @@ packages: url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "2.1.2" flutter: dependency: "direct main" description: flutter @@ -227,6 +235,54 @@ packages: url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.9.0" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "2.1.3" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "2.2.4" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "2.4.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "2.2.1" petitparser: dependency: transitive description: @@ -235,6 +291,22 @@ packages: url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "6.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "3.1.5" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "2.1.8" sky_engine: dependency: transitive description: flutter @@ -320,6 +392,22 @@ packages: url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.5.1" + win32: + dependency: transitive + description: + name: win32 + sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "5.5.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "1.0.4" xml: dependency: transitive description: @@ -338,4 +426,4 @@ packages: version: "3.1.2" sdks: dart: ">=3.3.4 <4.0.0" - flutter: ">=1.17.0" + flutter: ">=3.16.6" diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 8ee27bd..ee50743 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -36,6 +36,7 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.6 http: ^1.2.1 + path_provider: ^2.1.3 dev_dependencies: flutter_test: diff --git a/magisk/customize.sh b/magisk/customize.sh index 447e6c0..070f086 100644 --- a/magisk/customize.sh +++ b/magisk/customize.sh @@ -25,6 +25,7 @@ ln -sf $ZTPATH/zerotier-idtool $MODPATH$SYSBIN/zerotier-idtool ui_print "- set file permission" set_perm_recursive $MODPATH 0 0 0755 0644 set_perm_recursive $ZTPATH 0 0 0755 0644 +set_perm $MODPATH/handle.sh 0 0 0755 set_perm $ZTPATH/zerotier.sh 0 0 0755 set_perm $ZTPATH/zerotier-one 0 0 0755 diff --git a/magisk/handle.sh b/magisk/handle.sh new file mode 100644 index 0000000..8ad19b9 --- /dev/null +++ b/magisk/handle.sh @@ -0,0 +1,83 @@ +#!/system/bin/sh + +MODDIR=${0%/*} + +# load variables +. $MODDIR/vars.sh + +# LD_LIBRARY_PATH for NDK +export LD_LIBRARY_PATH=/system/lib64:/data/adb/zerotier/lib + +log_cli() { + echo -e "$1" >> $ZTROOT/run/cli.out +} +log() { + t=`date +"%m-%d %H:%M:%S.%3N"` + echo -e "[$t][$$][L] $@" >> $DAEMON_LOG + log_cli "$@" +} +_stop() { + pid=`pidof zerotier-one` + if [[ $? -ne 0 ]]; then + log "zerotier-one not running" + return + fi + + kill -9 $pid + if [[ $? -ne 0 ]]; then + log "kill zerotier-one failed" + return + fi + + wait + sleep 1 # sometimes it fails without sleeping + + log "stopped zerotier-one" +} +_start() { + if pid=`pidof zerotier-one`; then + log "zerotier-one already running pid $pid" + else + $ZTROOT/zerotier-one -d >> $ZT_LOG 2>&1 & + pid=`pidof zerotier-one` + log "started zerotier-one pid $pid" + fi +} +_status() { + # fake systemd lol + if pid=`pidof zerotier-one`; then + log_cli "\033[32m●\033[0m zerotier-one.service - ZeroTier One - Global Area Networking" + log_cli " Active: \033[32mactive (running)\033[0m" + log_cli " Main PID: $pid (zerotier-one)" + else + read pid_ < $ZTROOT/home/zerotier-one.pid + log_cli "○ zerotier-one.service - ZeroTier One - Global Area Networking" + log_cli " Active: inactive (dead)" + log_cli " Main PID: $pid_ (code=exited)" + fi +} + +# ---------------------------------------------- +# call from inotifyd +# ---------------------------------------------- + +if [[ $# == 2 && "$1" == "w" ]]; then + read cmd < $2 + rm -f $ZTROOT/run/cli.out + + case "$cmd" in + "start") _start;; + "stop") _stop;; + "restart") _stop; _start;; + "status") _status;; + *) log "unknown command $cmd";; + esac + + if [[ -f "$ZTROOT/run/cli.pid" ]]; then + read cpid < $ZTROOT/run/cli.pid + rm -f $ZTROOT/run/cli.pid + kill -SIGUSR1 $cpid + fi + + exit 0 +fi \ No newline at end of file diff --git a/magisk/service.sh b/magisk/service.sh index c5be34e..639228b 100644 --- a/magisk/service.sh +++ b/magisk/service.sh @@ -2,96 +2,66 @@ MODDIR=${0%/*} -ZTROOT=/data/adb/zerotier -ZTRUNTIME=$ZTROOT/run -APPROOT=/data/data/com.eventlowop.zerotier_magisk_app/files +# load variables +. $MODDIR/vars.sh -pipe=$ZTRUNTIME/pipe -ZTLOG=$ZTRUNTIME/zerotier.log -daemon_log=$ZTRUNTIME/daemon.log +# wait_until_login from yc9559/uperf at uperf/magisk/script/libcommon.sh +wait_until_login() { + # in case of /data encryption is disabled + while [ "$(getprop sys.boot_completed)" != "1" ]; do + sleep 1 + done -cli_output=$ZTRUNTIME/cli.out -cli_pid=$ZTRUNTIME/cli.pid - -log() { - t=`date +"%m-%d %H:%M:%S.%3N"` - echo -e "[$t][$$][L] $1" >> $daemon_log - echo -e "$1" >> $cli_output -} -log_cli() { - echo -e "$1" >> $cli_output -} -_stop() { - pid=`pidof zerotier-one` - if [[ $? -ne 0 ]]; then - log "zerotier-one not running" - return - fi - - kill -9 $pid - if [[ $? -ne 0 ]]; then - log "kill zerotier-one failed" - return - fi - - wait - log "stopped zerotier-one" -} -__start() { - $ZTROOT/zerotier-one -d >> $ZTLOG 2>&1 & -} -_start() { - if pid=`pidof zerotier-one`; then - log "zerotier-one already running pid $pid" - else - __start - pid=`pidof zerotier-one` - log "started zerotier-one pid $pid" - fi -} -_status() { - # fake systemd lol - if pid=`pidof zerotier-one`; then - log_cli "\033[32m●\033[0m zerotier-one.service - ZeroTier One - Global Area Networking" - log_cli " Active: \033[32mactive (running)\033[0m" - log_cli " Main PID: $pid (zerotier-one)" - else - pid_=`cat $zerotier_root/home/zerotier-one.pid` - log_cli "○ zerotier-one.service - ZeroTier One - Global Area Networking" - log_cli " Active: inactive (dead)" - log_cli " Main PID: $pid_ (code=exited)" - fi + # we doesn't have the permission to rw "/sdcard" before the user unlocks the screen + local test_file="/sdcard/Android/.PERMISSION_TEST" + true >"$test_file" + while [ ! -f "$test_file" ]; do + true >"$test_file" + sleep 1 + done + rm "$test_file" } -cd $ZTROOT -rm -f $ZTRUNTIME -mkfifo $pipe +# ---------------------------------------------- +# clean before start +# ---------------------------------------------- -chmod 666 $pipe $cli_output $cli_pid +rm -rf $ZTROOT/run +mkdir -p $ZTROOT/run +# ---------------------------------------------- +# start zerotier +# ---------------------------------------------- + +# add main route table to lookup rules ip rule add from all lookup main pref 1 -export LD_LIBRARY_PATH=/system/lib64:/data/adb/zerotier/lib +ip -6 rule add from all lookup main pref 1 -if [[ -e /data/data/com.eventlowop.zerotier_magisk_app/files ]]; then - ln -sf $pipe $APPROOT/pipe - ln -sf $cli_output $APPROOT/cli.out - ln -sf $cli_pid $APPROOT/cli.pid -fi +# LD_LIBRARY_PATH for NDK +export LD_LIBRARY_PATH=$ZTROOT/lib -__start +# start zerotier +$ZTROOT/zerotier-one -d >> $ZT_LOG 2>&1 & -while true -do - if read cmd < $pipe; then - case "$cmd" in - "start") _start;; - "stop") _stop;; - "restart") _stop; _start;; - "status") _status;; - *) log "unknown command $cmd";; - esac +# ---------------------------------------------- +# CLI before login +# ---------------------------------------------- - cpid=`cat $cli_pid` - kill -SIGUSR1 $cpid; - fi -done +touch $PIPE_CLI +inotifyd $MODDIR/handle.sh $PIPE_CLI:w &>/dev/null & # toybox inotifyd bug: needs an extra character after colon + +# ---------------------------------------------- +# APP after login +# ---------------------------------------------- + +wait_until_login + +if [[ -d "$APPROOT" ]]; then + rm -rf $APPROOT/run + mkdir -p $APPROOT/run + + cp $ZTROOT/home/authtoken.secret $APPROOT/run/authtoken + touch $PIPE_APP + chmod 666 $APPROOT/run/authtoken $PIPE_APP + inotifyd $MODDIR/handle.sh $PIPE_APP:w &>/dev/null & +fi \ No newline at end of file diff --git a/magisk/vars.sh b/magisk/vars.sh new file mode 100644 index 0000000..cc9ca63 --- /dev/null +++ b/magisk/vars.sh @@ -0,0 +1,12 @@ +# variables + +ZTROOT=/data/adb/zerotier +APPROOT=/data/data/com.eventlowop.zerotier_magisk_app/app_flutter + +ZT_LOG=$ZTROOT/run/zerotier.log +DAEMON_LOG=$ZTROOT/run/daemon.log + +PIPE_CLI=$ZTROOT/run/pipe +PIPE_APP=$APPROOT/run/pipe + +BB=/data/adb/magisk/busybox \ No newline at end of file diff --git a/magisk/zerotier/zerotier.sh b/magisk/zerotier/zerotier.sh index 0f8f33e..cc7ffcf 100644 --- a/magisk/zerotier/zerotier.sh +++ b/magisk/zerotier/zerotier.sh @@ -1,26 +1,24 @@ #!/system/bin/sh -pipe=/data/adb/zerotier/run/pipe -cli_output=/data/adb/zerotier/run/cli.out -cli_pid=/data/adb/zerotier/run/cli.pid +ZTROOT=/data/adb/zerotier +PIPE=$ZTROOT/run/pipe -help_text="Usage: zerotier.sh {start|stop|restart|status}" +HELP="Usage: zerotier.sh {start|stop|restart|status}" -if [[ ! -p $pipe ]]; then +if [[ ! -f $PIPE ]]; then echo "daemon not running" exit 1 fi -rm -f $cli_output -echo $$ > $cli_pid +echo $$ > $ZTROOT/run/cli.pid on_receive() { kill -9 %% - cat $cli_output + cat $ZTROOT/run/cli.out exit 0 } run() { - echo $cmd > $pipe + echo $cmd > $PIPE } trap 'on_receive' SIGUSR1 @@ -35,7 +33,7 @@ if [[ $# -eq 1 ]]; then *) echo "unknown command $cmd";; esac else - echo $help_text + echo $HELP exit 1 fi