14 Commits
Author SHA1 Message Date
eventlOwOpandGitHub b3210882dd explanation for 1.14.2 2025-04-05 17:26:31 +08:00
eventlOwOp e2c0c3a515 update rootless app 2024-07-02 13:43:54 +08:00
eventlOwOp 19e9c26f59 fix redirection for ash 2024-07-02 13:28:51 +08:00
eventlOwOp 9b1059acbd rewrite restart logic 2024-07-02 13:12:35 +08:00
eventlOwOp fa2d60e1b8 update zerotier module to support rootless app 2024-07-02 12:25:20 +08:00
eventlOwOp 7394eee0f0 add flutter build 2024-06-06 13:07:58 +08:00
eventlOwOp 8b70f9c4a0 update gcc; change tag to commit hash 2024-06-06 12:59:38 +08:00
eventlOwOp 83e8ff3c0a update action workflow 2024-06-06 12:48:29 +08:00
eventlOwOpandGitHub bffce9e7fe Update customize.sh 2024-06-06 09:20:31 +08:00
eventlOwOpandGitHub 5fdaf2fc5f Update app ld_library_path 2024-06-06 00:13:24 +08:00
eventlOwOpandGitHub 23afcb31b8 Update ld_library_path 2024-06-06 00:11:35 +08:00
eventlOwOpandGitHub ca7697d5d9 Update service.sh 2024-05-23 15:55:48 +08:00
eventlOwOp 162014041d upload android app 2024-05-19 01:37:15 +08:00
eventlOwOp 53e2fca297 update readme 2024-05-19 01:33:05 +08:00
46 changed files with 1600 additions and 186 deletions
+31
View File
@@ -0,0 +1,31 @@
name: build app
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-22.04
steps:
- name: Checkout zerotier-magisk
uses: actions/checkout@v4
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
- name: build target apk
run: |
cd app
flutter pub get
flutter build apk
- id: commit
uses: prompt/actions-commit-hash@v3
- name: Upload AArch64
uses: actions/upload-artifact@v4
with:
name: app-${{ steps.commit.outputs.short }}
path: app/build/app/outputs/flutter-apk/app-release.apk
+20 -26
View File
@@ -16,6 +16,9 @@ jobs:
repository: zerotier/ZeroTierOne
path: ZeroTierOne
- id: commit
uses: prompt/actions-commit-hash@v3
- name: Prepare GCC Toolchain
run: |
sudo apt-get install -qqy gcc-aarch64-linux-gnu gcc-arm-linux-gnueabihf g++-aarch64-linux-gnu g++-arm-linux-gnueabihf
@@ -29,7 +32,7 @@ jobs:
- name: Patch ZeroTier for Cross-Compile
run: |
pip3 install toml
python3 build/build_helper.py
python3 build/patch.py
- name: Build for AArch64
run: |
@@ -43,8 +46,12 @@ jobs:
cd ..
cp ZeroTierOne/zerotier-one magisk/zerotier
cd magisk
zip -q -r ../zerotier-magisk-aarch64-gcc.zip .
- name: Upload AArch64
uses: actions/upload-artifact@v4
with:
name: zerotier-magisk-aarch64-gcc-${{ steps.commit.outputs.short }}
path: magisk/
- name: Build for AArch64 with SSO
run: |
@@ -57,8 +64,12 @@ jobs:
cd ..
cp ZeroTierOne/zerotier-one magisk/zerotier
cd magisk
zip -q -r ../zerotier-magisk-aarch64-gcc-SSO.zip .
- name: Upload AArch64 SSO
uses: actions/upload-artifact@v4
with:
name: zerotier-magisk-aarch64-gcc-SSO-${{ steps.commit.outputs.short }}
path: magisk/
- name: Build for Arm
run: |
@@ -73,26 +84,9 @@ jobs:
cd ..
cp ZeroTierOne/zerotier-one magisk/zerotier/
cd magisk
zip -q -r ../zerotier-magisk-arm-gcc.zip .
- name: Get Date
id: date
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Release
uses: softprops/action-gh-release@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload Arm
uses: actions/upload-artifact@v4
with:
files: |
zerotier-magisk-aarch64-gcc-SSO.zip
zerotier-magisk-aarch64-gcc.zip
zerotier-magisk-arm-gcc.zip
tag_name: SNAPSHOT-GCC-${{ steps.date.outputs.date }}
name: SNAPSHOT-GCC-${{ steps.date.outputs.date }}
draft: false
prerelease: true
# - name: Debugging with tmate
# uses: mxschmitt/action-tmate@v3.18
name: zerotier-magisk-arm-gcc-${{ steps.commit.outputs.short }}
path: magisk/
+14 -23
View File
@@ -26,6 +26,9 @@ jobs:
repository: miniupnp/libnatpmp
path: libnatpmp
- id: commit
uses: prompt/actions-commit-hash@v3
- name: Prepare NDK Toolchain
run: |
wget -qO ndk.zip https://dl.google.com/android/repository/android-ndk-$ndk-linux.zip
@@ -34,7 +37,7 @@ jobs:
- name: Patch ZeroTier for Cross-Compile
run: |
pip3 install toml
python3 build/build_helper.py
python3 build/patch.py
- name: Build for AArch64
run: |
@@ -57,8 +60,12 @@ jobs:
mkdir -p magisk/zerotier/lib
cp ZeroTierOne/zerotier-one magisk/zerotier
cp $NDK_ROOT/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so magisk/zerotier/lib
cd magisk
zip -q -r ../zerotier-magisk-aarch64-ndk.zip .
- name: Upload AArch64
uses: actions/upload-artifact@v4
with:
name: zerotier-magisk-aarch64-ndk-${{ steps.commit.outputs.short }}
path: magisk/
- name: Build for Arm
run: |
@@ -81,25 +88,9 @@ jobs:
cp ZeroTierOne/zerotier-one magisk/zerotier/
cp $NDK_ROOT/sysroot/usr/lib/arm-linux-androideabi/libc++_shared.so magisk/zerotier/lib
cd magisk
zip -q -r ../zerotier-magisk-arm-ndk.zip .
- name: Get Date
id: date
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Release
uses: softprops/action-gh-release@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload Arm
uses: actions/upload-artifact@v4
with:
files: |
zerotier-magisk-aarch64-ndk.zip
zerotier-magisk-arm-ndk.zip
tag_name: SNAPSHOT-NDK-${{ steps.date.outputs.date }}
name: SNAPSHOT-NDK-${{ steps.date.outputs.date }}
draft: false
prerelease: true
# - name: Debugging with tmate
# uses: mxschmitt/action-tmate@v3.18
name: zerotier-magisk-arm-ndk-${{ steps.commit.outputs.short }}
path: magisk/
+73 -26
View File
@@ -10,7 +10,11 @@
**Run zerotier in the background after booting!**
**No conflicts with other android VPN service!**
**No conflicts with other Android VPN service!**
**Use Android App to control ZeroTier**
**Support for Private Root Servers**
## Requirements
@@ -24,39 +28,82 @@ AArch64 suppots ARMv8-A and above; Arm version supports ARMv7-A (compiling with
## Installation
1. download release from github.
2. install with magisk.
3. modify the config file at `/sdcard/Android/zerotier/network_id.txt` and put your 16-character network id in it.
4. restart and enjoy.
1. Download magisk module zip file from github release; install.
2. Download controller app apk file from github release; install.
3. Reboot your phone.
4. Open controller app; enter your 16-character network id; join.
5. Enjoy 😋
To restart, execute (in root) `sh /data/adb/zerotier/zerotier.sh restart`; An android application to control zerotier (networkid, restart, ...) has been added to the todo list.
## Usage
### Files
### Use Private Root Servers
Replace `/data/adb/zerotier/home/planet` with your own `planet` file.
### Controller App
Does not need root privilege
| Feature | Supported? |
| :----------------- | :--------- |
| status | ✅ |
| start/stop | ✅ |
| join/leave network | ✅ |
| join/leave planet | ❎ |
<div>
<img alt="ZeroTier for Magisk Icon" src="https://github.com/eventlOwOp/zerotier-magisk/blob/master/images/app_home.jpg" width="192" />
<img alt="ZeroTier for Magisk Icon" src="https://github.com/eventlOwOp/zerotier-magisk/blob/master/images/app_network.jpg" width="192" />
</div>
### Command line tools
Use `zerotier.sh` to start/stop or inspect status.
`Usage: zerotier.sh {start|stop|restart|status}`
Use `zerotier-cli / zerotier-idtool` for ZeroTierOne command line operations.
(`zerotier-one` not copied to `/system/bin`)
## Files
```
/data/adb/zerotier/
| - run/
| | - pipe # pipe to service.sh
| | - daemon.log # service.sh log
| ` - zerotier.log # zerotier-one log
| - home/ # zerotier-one home directory
| ` - ...
| - lib/
| ` - libc++_shared.so # NDK dynamic library
| - zerotier.sh # tool to communicate with service.sh
| - zerotier-one # zerotier-one executable
| - zerotier-cli -> zerotier-one
` - zerotier-idtool -> zerotier-one
/data/adb/zerotier
├── home # zerotier-one home directory
│   ├── authtoken.secret # zerotier-one http interface authtoken
│   ├── zerotier-one.pid # zerotier-one pid
│   ├── zerotier-one.port # zerotier-one port
│   └── ...
├── lib # only in NDK compiled module
│   └── libc++_shared.so # NDK dynamic library
├── run
│   ├── daemon.log # service.sh log
│   ├── pipe # named pipe to interact with service.sh
│   ├── zerotier.log # zerotier-one log
│   └── ...
├── zerotier-cli -> zerotier-one # zerotier-one command line interface
├── zerotier-idtool -> zerotier-one # zerotier-one id tool
├── zerotier-one # zerotier-one executable
└── zerotier.sh
```
all the scripts and binaries are placed in `/data/adb/zerotier/`.
all the scripts and binaries are placed in `/data/adb/zerotier/`, and all copied to `/system/bin` (in PATH) to be executed directly (except `zerotier-one`)
`zerotier.sh` writes commands to the pipe at `run/pipe` and `service.sh` read from it.
`Usage: sh zerotier.sh {start|stop|restart|join|leave}`
`zerotier.sh` uses named pipe to communicate with `service.sh`, preventing ZeroTier to start as a subprocess of Shell.
log files are placed in `run`, `daemon.log` for `service.sh` and `zerotier.log` for ZeroTierOne.
### Build binaries yourself
## Build binaries yourself
The binaries are built with Android NDK toolchains on Github Action, see `.github/workflow/build.yml` for detailed information.
refer to `.github/workflow/build-{gcc|ndk}.yml` for detailed information.
## Notes
After 1.14.0, ZeroTierOne has introduce `multi-core concurrent packet processing`, which requires `pthread_setaffinity_np`.
However, `pthread_setaffinity_np` won't be available until API level 36, Android 16. (refer to https://android.googlesource.com/platform/bionic/+/master/libc/include/pthread.h)
So in the NDK bulid version, it'll be replaced by the combination of `pthread_gettid_np` from `<pthread.h>` and `sched_getaffinity` from `<sched.h>`.
We'll add support to this soon. Use the GCC build version to get access to the newest ZeroTierOne.
+66 -27
View File
@@ -8,7 +8,13 @@
</div>
将 ZeroTier 保持后台运行,不与其他 Android VPN 应用程序冲突
**将 ZeroTier 保持后台运行**
**不与其他 Android VPN 应用程序冲突**
**使用 Android App 进行控制**
**支持自建 Planet**
## 运行要求
@@ -22,39 +28,72 @@ AArch64 版本支持 ARMv8-A 及以上;Arm 版本均对 ARMv7-A 进行编译 (
## 安装
1. 从 Release 下载压缩包
2. 导入 magisk 进行安装
3. 将你的 16 位 ZeroTier network id 写入 `/sdcard/Android/zerotier/network_id.txt`
4. 重启
1. 从 Release 下载 magisk 模块压缩包,并安装
2. 从 Release 处下载控制器的 apk 安装包,并安装
3. 重启
4. 打开控制器 App,输入 16 位 network id 并加入
5. 享用 😋
你可以用 `su` 执行 `sh /data/adb/zerotier/zerotier.sh restart` 来重启,或者干脆重启手机,计划写一个 app 来完成
## 使用
### 文件
### 自建 Planet
`/data/adb/zerotier/home/planet` 替换为自己的 planet 文件即可
### 控制器 App
无需 root 授权
| 功能 | 支持状态 |
| :--------------- | :------- |
| 查看运行状态 | ✅ |
| 启动停止重启 | ✅ |
| 加入离开 network | ✅ |
| 加入离开 planet | ❎ |
<div>
<img alt="ZeroTier for Magisk Icon" src="https://github.com/eventlOwOp/zerotier-magisk/blob/master/images/app_home.jpg" width="192" />
<img alt="ZeroTier for Magisk Icon" src="https://github.com/eventlOwOp/zerotier-magisk/blob/master/images/app_network.jpg" width="192" />
</div>
### 命令行
查看运行状态,或者启动重启停止,使用 `zerotier.sh`
`Usage: zerotier.sh {start|stop|restart|status}`
ZeroTierOne 支持的所有命令行操作:使用 `zerotier-cli / zerotier-idtool`
`zerotier-one` 并未导出到 `/system/bin`
## 目录结构
```
/data/adb/zerotier/
| - run/
| | - pipe # pipe to service.sh
| | - daemon.log # service.sh log
| ` - zerotier.log # zerotier-one log
| - home/ # zerotier-one home directory
| ` - ...
| - lib/
| ` - libc++_shared.so # NDK dynamic library
| - zerotier.sh # tool to communicate with service.sh
| - zerotier-one # zerotier-one executable
| - zerotier-cli -> zerotier-one
` - zerotier-idtool -> zerotier-one
/data/adb/zerotier
├── home # zerotier-one home directory
│   ├── authtoken.secret # zerotier-one http interface authtoken
│   ├── zerotier-one.pid # zerotier-one pid
│   ├── zerotier-one.port # zerotier-one port
│   └── ...
├── lib # only in NDK compiled module
│   └── libc++_shared.so # NDK dynamic library
├── run
│   ├── daemon.log # service.sh log
│   ├── pipe # named pipe to interact with service.sh
│   ├── zerotier.log # zerotier-one log
│   └── ...
├── zerotier-cli -> zerotier-one # zerotier-one command line interface
├── zerotier-idtool -> zerotier-one # zerotier-one id tool
├── zerotier-one # zerotier-one executable
└── zerotier.sh
```
ZeroTier 可执行文件和操作的 Shell 脚本放在 `/data/adb/zerotier/`
ZeroTier 可执行文件和操作的 Shell 脚本放在 `/data/adb/zerotier/` 下,同时复制到 `/system/bin`PATH 中)以便于直接执行(除了 `zerotier-one`
`zerotier.sh` 向管道 `run/pipe` 写入, `service.sh` 读取管道,然后进行操作
`zerotier.sh` 通过命名管道与 `service.sh` 交互,防止 ZeroTier 作为 Shell 的子进程运行
`Usage: sh zerotier.sh {start|stop|restart|join|leave}`
日志存放在 `/data/adb/zerotier/run` 下,`service.sh``daemon.log`ZeroTier 为 `zerotier.log`.
log files are placed in `run`, `daemon.log` for `service.sh` and `zerotier.log` for ZeroTierOne.
## 自行编译
### 自行编译
使用 NDK,参考 `.github/workflow/build.yml`
参考 `.github/workflow/build-{gcc|ndk}.yml`
+52
View File
@@ -0,0 +1,52 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
# Android related
**/android/**/gradle-wrapper.jar
**/android/.gradle
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/local.properties
**/android/**/GeneratedPluginRegistrant.java
+33
View File
@@ -0,0 +1,33 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "54e66469a933b60ddf175f858f82eaeb97e48c8d"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
- platform: android
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
- platform: web
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
+28
View File
@@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
+13
View File
@@ -0,0 +1,13 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks
+67
View File
@@ -0,0 +1,67 @@
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
android {
namespace "com.eventlowop.zerotier_magisk_app"
compileSdk flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.eventlowop.zerotier_magisk_app"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {}
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
@@ -0,0 +1,46 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="@string/appName"
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility?hl=en and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
@@ -0,0 +1,5 @@
package com.eventlowop.zerotier_magisk_app
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity()
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="appName">ZeroTier for Magisk</string>
</resources>
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
+19
View File
@@ -0,0 +1,19 @@
allprojects {
repositories {
google()
maven { url 'https://mirrors.tuna.tsinghua.edu.cn/flutter/download.flutter.io' }
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
+3
View File
@@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx4G
android.useAndroidX=true
android.enableJetifier=true
+5
View File
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip
+26
View File
@@ -0,0 +1,26 @@
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}
settings.ext.flutterSdkPath = flutterSdkPath()
includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.3.0" apply false
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
}
include ":app"
Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

+39
View File
@@ -0,0 +1,39 @@
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;
final http.Client _inner;
AuthedClientInner(this._secret, this._inner);
@override
Future<http.StreamedResponse> send(http.BaseRequest request) {
request.headers['X-ZT1-Auth'] = _secret;
return _inner.send(request);
}
// @override
// Future<http.Response> post(Uri url,
// {Map<String, String>? headers, Object? body, Encoding? encoding}) {
// Map<String, String> hd = headers ?? <String, String>{};
// hd['content-type'] = 'application/json';
// return super.post(url, headers: hd, body: body, encoding: encoding);
// }
}
class AuthedClient {
late Future<AuthedClientInner> client;
Future<AuthedClientInner> loadSecret() async {
final path = (await getApplicationDocumentsDirectory()).path;
final file = File('$path/run/authtoken');
final token = await file.readAsString();
return AuthedClientInner(token.trim(), http.Client());
}
AuthedClient() {
client = loadSecret();
}
}
+291
View File
@@ -0,0 +1,291 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'dart:io';
import 'dart:developer' as developer;
import 'package:flutter/services.dart';
import './authed_client.dart';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ZeroTier for Magisk',
theme: ThemeData(
colorSchemeSeed: Colors.lightBlue,
useMaterial3: true,
brightness: Brightness.light,
),
darkTheme: ThemeData(
colorSchemeSeed: Colors.lightBlue,
useMaterial3: true,
brightness: Brightness.dark,
),
home: const MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
Future<void> zerotierCommand(String command) async {
final path = (await getApplicationDocumentsDirectory()).path;
final file = File('$path/run/pipe');
await file.writeAsString(command);
}
class _MyHomePageState extends State<MyHomePage> {
List<String> networkList = [];
bool runningStatus = false;
final AuthedClient authed = AuthedClient();
loadNetwork() async {
final client = await authed.client;
final resp = await client.get(
Uri.http('localhost:9993', 'network'),
);
final body = jsonDecode(resp.body);
networkList = List<String>.from(body.map((u) => u['id']));
}
void leaveNetwork(String id) async {
final client = await authed.client;
final resp = await client.delete(Uri.http('localhost:9993', 'network/$id'));
if (resp.statusCode != 200) {
// failed
return;
}
// success
setState(() {
networkList.remove(id);
});
}
Future<void> joinNetwork(String id) async {
final client = await authed.client;
final resp = await client.put(Uri.http('localhost:9993', 'network/$id'));
if (resp.statusCode != 200) {
// failed
return;
}
// success
if (!networkList.contains(id)) {
setState(() {
networkList.add(id);
});
}
}
Future<void> loadStatus() async {
final client = await authed.client;
try {
await client.get(Uri.http('localhost:9993'));
setState(() => runningStatus = true);
return;
} on SocketException {
setState(() => runningStatus = false);
} catch (e) {
developer.log('error', error: e.toString());
// error
}
}
late Future<void> loadingNetworkFuture = loadNetwork();
@override
void initState() {
super.initState();
loadStatus();
}
Function cmdButtonWrapper(func) {
bool doing = false;
return () => doing
? null
: () async {
setState(() => doing = true);
await func();
setState(() => doing = false);
};
}
late Function restartFn, startFn, stopFn, joinFn, leaveFn;
_MyHomePageState() : super() {
restartFn =
cmdButtonWrapper(() => zerotierCommand('restart'));
startFn = cmdButtonWrapper(() => zerotierCommand('start'));
stopFn = cmdButtonWrapper(() => zerotierCommand('stop'));
joinFn = cmdButtonWrapper(() => joinNetwork(_idInputController.text));
}
final _idInputController = TextEditingController();
homePage({bool title = false}) {
if (title) {
return 'Status';
}
return Column(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
Builder(builder: (BuildContext context) {
final color = (runningStatus ? Colors.green : Colors.red)[200];
return Column(children: [
Icon(runningStatus ? Icons.play_arrow : Icons.stop, color: color, size: 72),
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Text(runningStatus ? 'Running' : 'Stopped', style: TextStyle(color: color, fontSize: 18)),
IconButton(icon: const Icon(Icons.refresh), onPressed: loadStatus)
])
]);
}),
ButtonBar(
alignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
OutlinedButton.icon(
onPressed: startFn(),
label: const Text('Start'),
icon: const Icon(Icons.play_arrow),
),
OutlinedButton.icon(
onPressed: restartFn(),
label: const Text('Restart'),
icon: const Icon(Icons.restart_alt),
),
OutlinedButton.icon(
onPressed: stopFn(),
label: const Text('Stop'),
icon: const Icon(Icons.stop),
),
],
)
]);
}
networkPage({bool title = false}) {
if (title) {
return 'Network';
}
return Padding(
padding: const EdgeInsets.all(12),
child: Column(
children: [
Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
SizedBox(
width: 200,
child: TextField(
controller: _idInputController,
textAlign: TextAlign.center,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(RegExp('[0-9a-f]'))
],
maxLength: 16,
decoration: const InputDecoration(
labelText: "network id", icon: Icon(Icons.router)))),
OutlinedButton.icon(
onPressed: joinFn(),
label: const Text('Join'),
icon: const Icon(Icons.add)),
]),
const SizedBox(height: 30),
const Divider(height: 10),
ListTile(
title: const Text('Networks'),
titleTextStyle: const TextStyle(fontSize: 18),
trailing: IconButton(
icon: const Icon(Icons.refresh),
onPressed: () {
setState(() {
loadingNetworkFuture = loadNetwork();
});
})),
const SizedBox(height: 10),
FutureBuilder<void>(
future: loadingNetworkFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
return ListView.builder(
shrinkWrap: true,
itemCount: networkList.length,
itemBuilder: (BuildContext ctx, int i) {
return Card(
child: ListTile(
title: Text(networkList[i]),
trailing: SizedBox(
width: 96,
child: Row(children: [
IconButton(
onPressed: () => Clipboard.setData(
ClipboardData(
text: networkList[i]))
.then,
tooltip: '复制',
icon: const Icon(Icons.copy)),
IconButton(
onPressed: () =>
leaveNetwork(networkList[i]),
tooltip: '离开',
icon: const Icon(Icons.close)),
]))));
});
}
return const CircularProgressIndicator();
},
),
],
));
}
int currentPageIndex = 0;
genWidgetList({bool title = false}) {
return [
homePage(title: title),
networkPage(title: title)
][currentPageIndex];
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(genWidgetList(title: true))),
bottomNavigationBar: NavigationBar(
onDestinationSelected: (int index) {
setState(() {
currentPageIndex = index;
});
},
selectedIndex: currentPageIndex,
destinations: const <Widget>[
NavigationDestination(
selectedIcon: Icon(Icons.home),
icon: Icon(Icons.home_outlined),
label: 'Status',
),
NavigationDestination(
selectedIcon: Icon(Icons.router),
icon: Icon(Icons.router_outlined),
label: 'Network',
),
],
),
body: Center(
child: genWidgetList(),
));
}
}
+429
View File
@@ -0,0 +1,429 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
archive:
dependency: transitive
description:
name: archive
sha256: ecf4273855368121b1caed0d10d4513c7241dfc813f7d3c8933b36622ae9b265
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "3.5.1"
args:
dependency: transitive
description:
name: args
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "2.5.0"
async:
dependency: transitive
description:
name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "2.11.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "2.1.1"
characters:
dependency: transitive
description:
name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "1.3.0"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "2.0.3"
cli_util:
dependency: transitive
description:
name: cli_util
sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "0.4.1"
clock:
dependency: transitive
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "1.1.1"
collection:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "1.18.0"
crypto:
dependency: transitive
description:
name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "3.0.3"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "1.0.8"
fake_async:
dependency: transitive
description:
name: fake_async
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
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
source: sdk
version: "0.0.0"
flutter_launcher_icons:
dependency: "direct dev"
description:
name: flutter_launcher_icons
sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "0.13.1"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "4.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
http:
dependency: "direct main"
description:
name: http
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "1.2.1"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "4.0.2"
image:
dependency: transitive
description:
name: image
sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "4.1.7"
json_annotation:
dependency: transitive
description:
name: json_annotation
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "4.9.0"
launcher_name:
dependency: "direct dev"
description:
name: launcher_name
sha256: "5fc9a8b8de9e255d5f21effc33632b5620771c9b2310d459a7710b725353b305"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "1.0.2"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "10.0.0"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "2.0.1"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "2.0.1"
lints:
dependency: transitive
description:
name: lints
sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "4.0.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "0.12.16+1"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "0.8.0"
meta:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "1.11.0"
path:
dependency: transitive
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
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:
name: petitparser
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
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
source: sdk
version: "0.0.99"
source_span:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "1.11.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "2.1.2"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "1.2.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "0.6.1"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "1.3.2"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "2.1.4"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "13.0.0"
web:
dependency: transitive
description:
name: web
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
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:
name: xml
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "6.5.0"
yaml:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.3.4 <4.0.0"
flutter: ">=3.16.6"
+102
View File
@@ -0,0 +1,102 @@
name: zerotier_magisk_app
description: "Controller app for zerotier-magisk"
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1
environment:
sdk: '>=3.3.4 <4.0.0'
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# 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:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^4.0.0
flutter_launcher_icons: ^0.13.1
launcher_name: ^1.0.2
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
flutter_launcher_icons:
android: "launcher_icon"
ios: false
image_path: "assets/icon.png"
min_sdk_android: 21 # android min sdk min:16, default 21
launcher_name:
default: "ZeroTier for Magisk"
Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

+3
View File
@@ -10,6 +10,7 @@ ui_print "- unzip"
unzip -o $ZIPFILE -x 'META-INF/*' -d $MODPATH >&2
ui_print "- create work dir"
rm -rf $ZTPATH/lib $ZTPATH/run
mkdir -p $ZTPATH/run $ZTPATH/home
mv $MODPATH/zerotier/* $ZTPATH
ln -sf $ZTPATH/zerotier-one $ZTPATH/zerotier-cli
@@ -19,10 +20,12 @@ ui_print "- link to system"
mkdir -p $MODPATH$SYSBIN
ln -sf $ZTPATH/zerotier.sh $MODPATH$SYSBIN/zerotier.sh
ln -sf $ZTPATH/zerotier-cli $MODPATH$SYSBIN/zerotier-cli
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
+82
View File
@@ -0,0 +1,82 @@
#!/system/bin/sh
MODDIR=${0%/*}
# load variables
. $MODDIR/lib.sh
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
log "stopped zerotier-one"
}
_start() {
if pidof zerotier-one > /dev/null; then
log "zerotier-one already running"
else
__start
log "started zerotier-one"
fi
}
_status() {
# fake systemd lol
read pid < $ZTROOT/home/zerotier-one.pid
if pidof zerotier-one > /dev/null; 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
log_cli "○ zerotier-one.service - ZeroTier One - Global Area Networking"
log_cli " Active: inactive (dead)"
log_cli " Main PID: $pid (code=exited)"
fi
}
_restart() {
_stop
__start
log "started zerotier-one"
}
# ----------------------------------------------
# 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") _restart;;
"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
+17
View File
@@ -0,0 +1,17 @@
# 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
# LD_LIBRARY_PATH for NDK
export LD_LIBRARY_PATH=/system/lib64:/data/adb/zerotier/lib
__start() {
nohup $ZTROOT/zerotier-one -d >> $ZT_LOG 2>&1 &
}
+50 -74
View File
@@ -2,87 +2,63 @@
MODDIR=${0%/*}
ZTROOT=/data/adb/zerotier
ZTRUNTIME=$ZTROOT/run
# load variables
. $MODDIR/lib.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
# ----------------------------------------------
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=/data/adb/zerotier/lib
ip -6 rule add from all lookup main pref 1
# start zerotier
__start
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
+8 -10
View File
@@ -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