mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-10-08 19:06:14 -08:00
Share a named TUN across instances while keeping unnamed devices dedicated. Track member addresses, routes, and MTU, and reject overlapping destinations except the common Magic DNS host route. Dispatch packets between the physical TUN and member tunnels. Keep IPv4 and ordinary IPv6 source translation for mobile wrong-source traffic. Update platform configuration and runtime host integration, with unit and network namespace coverage for routing and lifecycle. Add the packet dependency and keep core CI matrix jobs independent.
380 lines
13 KiB
YAML
380 lines
13 KiB
YAML
name: EasyTier Core
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
push:
|
|
branches: [ "develop", "main", "releases/**" ]
|
|
pull_request:
|
|
branches: [ "develop", "main" ]
|
|
types: [ opened, synchronize, reopened, ready_for_review ]
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
CARGO_TERM_COLOR: always
|
|
|
|
defaults:
|
|
run:
|
|
# necessary for windows
|
|
shell: bash
|
|
|
|
jobs:
|
|
pre_job:
|
|
runs-on: ubuntu-latest
|
|
if: github.event_name != 'pull_request' || !github.event.pull_request.draft
|
|
env:
|
|
RELEVANT_PATHS: >-
|
|
["Cargo.toml", "Cargo.lock", "rust-toolchain.toml", ".cargo/**",
|
|
"pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "easytier/**",
|
|
"easytier-core/**", "easytier-proto/**", "easytier-rpc-build/**",
|
|
"easytier-web/**", "easytier-contrib/easytier-magisk/**",
|
|
".github/workflows/core.yml", ".github/actions/**"]
|
|
outputs:
|
|
# Release builds must run even if they only change release metadata.
|
|
should_skip: >-
|
|
${{
|
|
(
|
|
steps.skip_check.outputs.should_skip == 'true' ||
|
|
(
|
|
github.event_name == 'pull_request' &&
|
|
steps.path_filter.outputs.relevant != 'true'
|
|
)
|
|
) &&
|
|
!startsWith(github.ref_name, 'releases/')
|
|
}}
|
|
steps:
|
|
- id: skip_check
|
|
uses: fkirc/skip-duplicate-actions@v5
|
|
with:
|
|
concurrent_skipping: 'same_content_newer'
|
|
skip_after_successful_duplicate: 'true'
|
|
cancel_others: 'true'
|
|
paths: ${{ env.RELEVANT_PATHS }}
|
|
|
|
- id: path_filter
|
|
if: >-
|
|
github.event_name == 'pull_request' &&
|
|
steps.skip_check.outputs.should_skip != 'true'
|
|
uses: dorny/paths-filter@v4
|
|
with:
|
|
filters: |
|
|
relevant: ${{ env.RELEVANT_PATHS }}
|
|
build_web:
|
|
runs-on: ubuntu-latest
|
|
needs: pre_job
|
|
if: needs.pre_job.outputs.should_skip != 'true'
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
|
|
- name: Setup Frontend Environment
|
|
uses: ./.github/actions/prepare-pnpm
|
|
with:
|
|
token: ${{ github.token }}
|
|
build-filter: './easytier-web/*'
|
|
|
|
- name: Archive artifact
|
|
uses: actions/upload-artifact@v5
|
|
with:
|
|
name: easytier-web-dashboard
|
|
path: |
|
|
easytier-web/frontend/dist/*
|
|
build:
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- TARGET: x86_64-unknown-linux-musl
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-x86_64
|
|
- TARGET: aarch64-unknown-linux-musl
|
|
OS: ubuntu-24.04-arm
|
|
ARTIFACT_NAME: linux-aarch64
|
|
|
|
- TARGET: riscv64gc-unknown-linux-musl
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-riscv64
|
|
- TARGET: loongarch64-unknown-linux-musl
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-loongarch64
|
|
|
|
- TARGET: armv7-unknown-linux-musleabihf # raspberry pi 2-3-4, not tested
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-armv7hf
|
|
- TARGET: armv7-unknown-linux-musleabi # raspberry pi 2-3-4, not tested
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-armv7
|
|
- TARGET: arm-unknown-linux-musleabihf # raspberry pi 0-1, not tested
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-armhf
|
|
- TARGET: arm-unknown-linux-musleabi # raspberry pi 0-1, not tested
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-arm
|
|
|
|
- TARGET: mips-unknown-linux-musl
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-mips
|
|
- TARGET: mipsel-unknown-linux-musl
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-mipsel
|
|
|
|
- TARGET: x86_64-unknown-freebsd
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: freebsd-13.2-x86_64
|
|
BSD_VERSION: 13.2
|
|
|
|
- TARGET: x86_64-apple-darwin
|
|
OS: macos-latest
|
|
ARTIFACT_NAME: macos-x86_64
|
|
- TARGET: aarch64-apple-darwin
|
|
OS: macos-latest
|
|
ARTIFACT_NAME: macos-aarch64
|
|
|
|
- TARGET: x86_64-pc-windows-msvc
|
|
OS: windows-latest
|
|
ARTIFACT_NAME: windows-x86_64
|
|
- TARGET: i686-pc-windows-msvc
|
|
OS: windows-latest
|
|
ARTIFACT_NAME: windows-i686
|
|
- TARGET: aarch64-pc-windows-msvc
|
|
OS: windows-11-arm
|
|
ARTIFACT_NAME: windows-arm64
|
|
|
|
runs-on: ${{ matrix.OS }}
|
|
env:
|
|
NAME: easytier
|
|
TARGET: ${{ matrix.TARGET }}
|
|
OS: ${{ matrix.OS }}
|
|
OSS_BUCKET: ${{ secrets.ALIYUN_OSS_BUCKET }}
|
|
needs:
|
|
- pre_job
|
|
- build_web
|
|
if: needs.pre_job.outputs.should_skip != 'true'
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
|
|
- name: Set current ref as env variable
|
|
run: |
|
|
echo "GIT_DESC=$(git log -1 --format=%cd.%h --date=format:%Y-%m-%d_%H:%M:%S)" >> $GITHUB_ENV
|
|
|
|
- name: Download web artifact
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: easytier-web-dashboard
|
|
path: easytier-web/frontend/dist/
|
|
|
|
- name: Prepare build environment
|
|
uses: ./.github/actions/prepare-build
|
|
with:
|
|
target: ${{ matrix.TARGET }}
|
|
gui: true
|
|
pnpm: true
|
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
# The prefix cache key, this can be changed to start a new cache manually.
|
|
# default: "v0-rust"
|
|
prefix-key: ""
|
|
shared-key: "core-registry"
|
|
cache-targets: "false"
|
|
|
|
- uses: mlugg/setup-zig@v2
|
|
if: ${{ contains(matrix.OS, 'ubuntu') }}
|
|
with:
|
|
version: 0.16.0
|
|
use-cache: true
|
|
|
|
- uses: taiki-e/install-action@v2
|
|
if: ${{ contains(matrix.OS, 'ubuntu') }}
|
|
with:
|
|
# v0.23.3 emits -mcpu=generic+v6+strict_align for
|
|
# arm-unknown-linux-musleabi, which zig 0.16.0 rejects;
|
|
# unpin only together with a zig bump.
|
|
tool: cargo-zigbuild@0.23.2
|
|
|
|
- name: Build
|
|
if: ${{ !contains(matrix.TARGET, 'mips') }}
|
|
run: |
|
|
if [[ "$TARGET" == *windows* ]]; then
|
|
SUFFIX=.exe
|
|
else
|
|
SUFFIX=""
|
|
fi
|
|
|
|
if [[ "$TARGET" =~ (x86_64-unknown-linux-musl|aarch64-unknown-linux-musl|windows|darwin) ]]; then
|
|
BUILD=build
|
|
else
|
|
BUILD=zigbuild
|
|
fi
|
|
|
|
if [[ "$TARGET" =~ ^(riscv64|loongarch64|aarch64).*$ || "$TARGET" =~ (freebsd|windows) ]]; then
|
|
FEATURES="mimalloc"
|
|
else
|
|
FEATURES="jemalloc"
|
|
fi
|
|
|
|
cargo $BUILD --release --target $TARGET --package=easytier-web --features=embed
|
|
mv ./target/$TARGET/release/easytier-web"$SUFFIX" ./target/$TARGET/release/easytier-web-embed"$SUFFIX"
|
|
|
|
cargo $BUILD --release --target $TARGET --features=$FEATURES
|
|
|
|
- name: Build (MIPS)
|
|
if: ${{ contains(matrix.TARGET, 'mips') }}
|
|
env:
|
|
RUSTC_BOOTSTRAP: 1
|
|
run: |
|
|
cargo build -r --target $TARGET -Z build-std=std,panic_abort --package=easytier --features=jemalloc
|
|
|
|
- name: Compress
|
|
run: |
|
|
mkdir -p ./artifacts/objects/
|
|
|
|
# windows is the only OS using a different convention for executable file name
|
|
if [[ $OS =~ ^windows.*$ ]]; then
|
|
SUFFIX=.exe
|
|
case $TARGET in
|
|
x86_64*) ARCH_DIR=x86_64 ;;
|
|
i686*) ARCH_DIR=i686 ;;
|
|
aarch64*) ARCH_DIR=arm64 ;;
|
|
esac
|
|
if [[ -n "$ARCH_DIR" ]]; then
|
|
find "easytier/third_party/${ARCH_DIR}" -maxdepth 1 -type f \( -name "*.dll" -o -name "*.sys" \) -exec cp {} ./artifacts/objects/ \;
|
|
fi
|
|
fi
|
|
|
|
if [[ $GITHUB_REF_TYPE =~ ^tag$ ]]; then
|
|
TAG=$GITHUB_REF_NAME
|
|
else
|
|
TAG=$GITHUB_SHA
|
|
fi
|
|
|
|
if [[ $OS =~ ^ubuntu.*$ && ! $TARGET =~ (loongarch|freebsd) ]]; then
|
|
HOST_ARCH=$(uname -m)
|
|
case $HOST_ARCH in
|
|
x86_64) UPX_ARCH="amd64" ;;
|
|
aarch64) UPX_ARCH="arm64" ;;
|
|
*) UPX_ARCH="amd64" ;;
|
|
esac
|
|
|
|
UPX_VERSION=4.2.4
|
|
UPX_PKG="upx-${UPX_VERSION}-${UPX_ARCH}_linux"
|
|
curl -L "https://github.com/upx/upx/releases/download/v${UPX_VERSION}/${UPX_PKG}.tar.xz" -s | tar xJvf -
|
|
cp "${UPX_PKG}/upx" .
|
|
UPX_BIN=./upx
|
|
fi
|
|
|
|
for BIN in ./target/$TARGET/release/easytier-{core,cli,web,web-embed}"$SUFFIX"; do
|
|
if [[ -f "$BIN" ]]; then
|
|
if [[ -n "$UPX_BIN" ]]; then
|
|
$UPX_BIN --lzma --best "$BIN" || true
|
|
fi
|
|
|
|
mv "$BIN" ./artifacts/objects/
|
|
fi
|
|
done
|
|
|
|
mv ./artifacts/objects/* ./artifacts/
|
|
rm -rf ./artifacts/objects/
|
|
|
|
- name: Archive artifact
|
|
uses: actions/upload-artifact@v5
|
|
with:
|
|
name: easytier-${{ matrix.ARTIFACT_NAME }}
|
|
path: |
|
|
./artifacts/*
|
|
|
|
- name: Prepare SignPath test artifact
|
|
if: ${{ github.event_name == 'workflow_dispatch' && contains(matrix.TARGET, 'windows') }}
|
|
run: |
|
|
mkdir -p ./signpath-artifacts
|
|
cp \
|
|
./artifacts/easytier-core.exe \
|
|
./artifacts/easytier-cli.exe \
|
|
./artifacts/easytier-web.exe \
|
|
./artifacts/easytier-web-embed.exe \
|
|
./signpath-artifacts/
|
|
|
|
- name: Upload unsigned SignPath test artifact
|
|
if: ${{ github.event_name == 'workflow_dispatch' && contains(matrix.TARGET, 'windows') }}
|
|
id: signpath-upload
|
|
uses: actions/upload-artifact@v5
|
|
with:
|
|
name: signpath-unsigned-${{ matrix.ARTIFACT_NAME }}
|
|
path: ./signpath-artifacts/*
|
|
if-no-files-found: error
|
|
|
|
- name: Submit SignPath test-signing request
|
|
if: ${{ github.event_name == 'workflow_dispatch' && contains(matrix.TARGET, 'windows') }}
|
|
uses: signpath/github-action-submit-signing-request@v2
|
|
with:
|
|
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
|
|
organization-id: 368cf38d-86d5-4bfe-a1fa-82a50dce7e9f
|
|
project-slug: EasyTier
|
|
signing-policy-slug: test-signing
|
|
artifact-configuration-slug: initial
|
|
github-artifact-id: ${{ steps.signpath-upload.outputs.artifact-id }}
|
|
wait-for-completion: true
|
|
output-artifact-directory: ./signpath-signed-artifacts
|
|
|
|
- name: Upload signed SignPath test artifact
|
|
if: ${{ github.event_name == 'workflow_dispatch' && contains(matrix.TARGET, 'windows') }}
|
|
uses: actions/upload-artifact@v5
|
|
with:
|
|
name: signpath-signed-${{ matrix.ARTIFACT_NAME }}
|
|
path: ./signpath-signed-artifacts/*
|
|
if-no-files-found: error
|
|
|
|
build_magisk:
|
|
runs-on: ubuntu-latest
|
|
needs: [ pre_job, build_web, build ]
|
|
if: needs.pre_job.result == 'success' && needs.pre_job.outputs.should_skip != 'true' && !cancelled()
|
|
steps:
|
|
- name: Checkout Code
|
|
uses: actions/checkout@v5 # 必须先检出代码才能获取模块配置
|
|
|
|
# 下载二进制文件到独立目录
|
|
- name: Download Linux aarch64 binaries
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: easytier-linux-aarch64
|
|
path: ./downloaded-binaries/ # 独立目录避免冲突
|
|
|
|
- name: Download Magisk WebUI
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: easytier-web-dashboard
|
|
path: ./downloaded-webui/
|
|
|
|
# 将二进制文件和 WebUI 复制到 Magisk 模块目录
|
|
- name: Prepare Magisk module
|
|
run: |
|
|
module_dir=./easytier-contrib/easytier-magisk
|
|
mkdir -p "$module_dir/webroot"
|
|
cp ./downloaded-binaries/easytier-core "$module_dir/"
|
|
cp ./downloaded-binaries/easytier-cli "$module_dir/"
|
|
cp ./downloaded-binaries/easytier-web "$module_dir/"
|
|
cp -R ./downloaded-webui/config-generator/. "$module_dir/webroot/"
|
|
test -f "$module_dir/webroot/index.html"
|
|
|
|
# 上传生成的模块
|
|
- name: Upload Magisk Module
|
|
uses: actions/upload-artifact@v5
|
|
with:
|
|
name: Easytier-Magisk
|
|
path: |
|
|
./easytier-contrib/easytier-magisk
|
|
!./easytier-contrib/easytier-magisk/build.sh
|
|
!./easytier-contrib/easytier-magisk/magisk_update.json
|
|
if-no-files-found: error
|
|
|
|
core-result:
|
|
runs-on: ubuntu-latest
|
|
needs: [ pre_job, build_web, build, build_magisk ]
|
|
if: needs.pre_job.result == 'success' && needs.pre_job.outputs.should_skip != 'true' && !cancelled()
|
|
steps:
|
|
- name: Mark result as failed
|
|
if: contains(needs.*.result, 'failure')
|
|
run: exit 1
|