Repository: twoone-3/AdGuardHomeForMagisk Branch: main Commit: 6a961919a0cc Files: 28 Total size: 99.5 KB Directory structure: gitextract_2fth1gt4/ ├── .gitattributes ├── .github/ │ └── workflows/ │ └── pack.yml ├── .gitignore ├── LICENSE ├── README.md ├── README_en.md ├── changelog.md ├── docs/ │ └── index.md ├── pack.ps1 ├── src/ │ ├── META-INF/ │ │ └── com/ │ │ └── google/ │ │ └── android/ │ │ ├── update-binary │ │ └── updater-script │ ├── action.sh │ ├── bin/ │ │ ├── AdGuardHome.yaml │ │ └── data/ │ │ └── filters/ │ │ └── 1732747955.txt │ ├── customize.sh │ ├── module.prop │ ├── scripts/ │ │ ├── base.sh │ │ ├── debug.sh │ │ ├── inotify.sh │ │ ├── iptables.sh │ │ └── tool.sh │ ├── service.sh │ ├── settings.conf │ ├── uninstall.sh │ └── webroot/ │ ├── app.js │ ├── index.html │ └── style.css └── version.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ * text eol=lf *.ps1 text eol=crlf *.bat text eol=crlf ================================================ FILE: .github/workflows/pack.yml ================================================ name: Pack AdGuardHomeForRoot on: workflow_dispatch: push: tags: - "[0-9]*" permissions: contents: write jobs: package: name: Build ${{ matrix.arch }} package runs-on: ubuntu-latest strategy: fail-fast: false matrix: arch: [arm64, armv7] steps: - name: Checkout repository uses: actions/checkout@v4 - name: Resolve archive URL id: vars shell: bash run: | set -euo pipefail case "${{ matrix.arch }}" in arm64) echo "archive_url=https://github.com/AdguardTeam/AdGuardHome/releases/latest/download/AdGuardHome_linux_arm64.tar.gz" >> "$GITHUB_OUTPUT" ;; armv7) echo "archive_url=https://github.com/AdguardTeam/AdGuardHome/releases/latest/download/AdGuardHome_linux_armv7.tar.gz" >> "$GITHUB_OUTPUT" ;; *) echo "Unsupported arch: ${{ matrix.arch }}" >&2 exit 1 ;; esac - name: Download release archive shell: bash run: | set -euo pipefail mkdir -p cache curl -fL "${{ steps.vars.outputs.archive_url }}" -o "cache/AdGuardHome_linux_${{ matrix.arch }}.tar.gz" - name: Extract archive shell: bash run: | set -euo pipefail mkdir -p "cache/${{ matrix.arch }}" tar -xzf "cache/AdGuardHome_linux_${{ matrix.arch }}.tar.gz" -C "cache/${{ matrix.arch }}" - name: Stage package files shell: bash run: | set -euo pipefail rm -rf staging mkdir -p staging cp -a src/. staging/ cp "cache/${{ matrix.arch }}/AdGuardHome/AdGuardHome" "staging/bin/AdGuardHome" - name: Create zip package shell: bash run: | set -euo pipefail rm -f "AdGuardHomeForRoot_${{ matrix.arch }}.zip" ( cd staging zip -r "../AdGuardHomeForRoot_${{ matrix.arch }}.zip" . ) - name: Upload artifact uses: actions/upload-artifact@v4 with: name: AdGuardHomeForRoot_${{ matrix.arch }} path: AdGuardHomeForRoot_${{ matrix.arch }}.zip if-no-files-found: error release: name: Create GitHub Release runs-on: ubuntu-latest needs: package if: startsWith(github.ref, 'refs/tags/') steps: - name: Checkout repository uses: actions/checkout@v4 - name: Validate tag format shell: bash run: | set -euo pipefail if [[ ! "${GITHUB_REF_NAME}" =~ ^[0-9]{8}$ ]]; then echo "Tag must be an 8-digit date (YYYYMMDD), got: ${GITHUB_REF_NAME}" >&2 exit 1 fi - name: Download build artifacts uses: actions/download-artifact@v4 with: pattern: AdGuardHomeForRoot_* merge-multiple: true - name: Create release uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.ref_name }} name: ${{ github.ref_name }} body_path: changelog.md files: | AdGuardHomeForRoot_arm64.zip AdGuardHomeForRoot_armv7.zip ================================================ FILE: .gitignore ================================================ cache/ ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2025 twoone3 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # AdGuardHome for Root [English](README_en.md) | 简体中文 ![arm-64 support](https://img.shields.io/badge/arm--64-support-ef476f?logo=linux&logoColor=white&color=ef476f) ![arm-v7 support](https://img.shields.io/badge/arm--v7-support-ffa500?logo=linux&logoColor=white&color=ffa500) ![GitHub downloads](https://img.shields.io/github/downloads/twoone-3/AdGuardHomeForRoot/total?logo=github&logoColor=white&color=ffd166) ![License](https://img.shields.io/badge/License-MIT-9b5de5?logo=opensourceinitiative&logoColor=white) [![Docs](https://img.shields.io/badge/Docs-Guide-0066ff?logo=book&logoColor=white)](docs/index.md) [![Join Telegram Channel](https://img.shields.io/badge/Telegram-Join%20Channel-06d6a0?logo=telegram&logoColor=white)](https://t.me/+Q3Ur_HCYdM0xM2I1) [![Join Telegram Group](https://img.shields.io/badge/Telegram-Join%20Group-118ab2?logo=telegram&logoColor=white)](https://t.me/+Q3Ur_HCYdM0xM2I1) 关注我们的频道获取最新消息,或加入我们的群组进行讨论! ## 简介 - 本模块是一个在安卓设备上运行 [AdGuardHome](https://github.com/AdguardTeam/AdGuardHome) 的模块,提供了一个本地 DNS 服务器,能够屏蔽广告、恶意软件和跟踪器。 - 它可以作为一个本地广告拦截模块使用,也可以通过调整配置文件,转变为一个独立运行的 AdGuardHome 工具。 - 该模块支持 Magisk、KernelSU 和 APatch 等多种安装方式,适用于大多数 Android 设备。 - 该模块的设计初衷是为了提供一个轻量级的广告拦截解决方案,避免了使用 VPN 的复杂性和性能损失。 - 它可以与其他代理软件(如 [NekoBox](https://github.com/MatsuriDayo/NekoBoxForAndroid)、[FlClash](https://github.com/chen08209/FlClash)、[box for magisk](https://github.com/taamarin/box_for_magisk)、[akashaProxy](https://github.com/akashaProxy/akashaProxy) 等)共存,提供更好的隐私保护和网络安全。 ## 特性 - 可选将本机 DNS 请求转发到本地 AdGuardHome 服务器 - 使用 [秋风广告规则](https://github.com/TG-Twilight/AWAvenue-Ads-Rule) 过滤广告,轻量,省电,少误杀 - 可从 访问 AdGuardHome 控制面板,支持查询统计,修改 DNS 上游服务器以及自定义规则等功能 ## 教程 1. 前往 [Release](https://github.com/twoone-3/AdGuardHomeForRoot/releases/latest) 页面下载模块 2. 检查 Android 设置 -> 网络和互联网 -> 高级 -> 私人 DNS,确保 `私人 DNS` 关闭 3. 在 root 管理器中安装模块,重启设备 4. 若看到模块运行成功的提示,则可以访问 进入 AdGuardHome 后台,默认用户密码 root/root 5. 若需高级使用教程和常见问题解答,请访问 **[文档与教程](docs/index.md)**。 ## 鸣谢 - [AWAwenue Ads Rule](https://github.com/TG-Twilight/AWAvenue-Ads-Rule) - [AdguardHome_magisk](https://github.com/410154425/AdGuardHome_magisk) - [akashaProxy](https://github.com/ModuleList/akashaProxy) - [box_for_magisk](https://github.com/taamarin/box_for_magisk) > 特别感谢赞助: > > - y******a - 200 > - 偶****** - 10 ================================================ FILE: README_en.md ================================================ # AdGuardHome for Root English | [简体中文](README.md) ![arm-64 support](https://img.shields.io/badge/arm--64-support-ef476f?logo=linux&logoColor=white&color=ef476f) ![arm-v7 support](https://img.shields.io/badge/arm--v7-support-ffa500?logo=linux&logoColor=white&color=ffa500) ![GitHub downloads](https://img.shields.io/github/downloads/twoone-3/AdGuardHomeForRoot/total?logo=github&logoColor=white&color=ffd166) ![License](https://img.shields.io/badge/License-MIT-9b5de5?logo=opensourceinitiative&logoColor=white) [![Docs](https://img.shields.io/badge/Docs-Guide-0066ff?logo=book&logoColor=white)](docs/index.md) [![Join Telegram Channel](https://img.shields.io/badge/Telegram-Join%20Channel-06d6a0?logo=telegram&logoColor=white)](https://t.me/+Q3Ur_HCYdM0xM2I1) [![Join Telegram Group](https://img.shields.io/badge/Telegram-Join%20Group-118ab2?logo=telegram&logoColor=white)](https://t.me/+Q3Ur_HCYdM0xM2I1) Follow our channel for the latest news, or join our group for discussion! ## Introduction - This module is a module that runs [AdGuardHome](https://github.com/AdguardTeam/AdGuardHome) on Android devices, providing a local DNS server that can block ads, malware, and trackers. - It can be used as a local ad-blocking module or transformed into a standalone AdGuardHome tool by adjusting the configuration file. - The module supports multiple installation methods, including Magisk, KernelSU, and APatch, making it compatible with most Android devices. - The design of this module aims to provide a lightweight ad-blocking solution, avoiding the complexity and performance loss associated with using VPNs. - It can coexist with other proxy software (such as [NekoBox](https://github.com/MatsuriDayo/NekoBoxForAndroid), [FlClash](https://github.com/chen08209/FlClash), [box for magisk](https://github.com/taamarin/box_for_magisk), [akashaProxy](https://github.com/akashaProxy/akashaProxy)), providing better privacy protection and network security. ## Features - Optionally forward local DNS requests to the local AdGuardHome server - Filter ads using [AWAvenue-Ads-Rule](https://github.com/TG-Twilight/AWAvenue-Ads-Rule) for lightweight, power-saving, and fewer false positives - Access the AdGuardHome control panel from , supporting query statistics, modifying DNS upstream servers, and custom rules, etc. ## Tutorial 1. Go to the [Release](https://github.com/twoone-3/AdGuardHomeForRoot/releases/latest) page to download the module 2. Check Android Settings -> Network & Internet -> Advanced -> Private DNS, ensure `Private DNS` is turned off 3. Install the module in the root manager and reboot the device 4. If you see a successful module running prompt, you can access to enter the AdGuardHome backend, default username and password are root/root 5. For advanced usage tutorials and FAQs, please visit **[Docs & Tutorials](docs/index.md)**. ## Acknowledgments - [AWAwenue Ads Rule](https://github.com/TG-Twilight/AWAvenue-Ads-Rule) - [AdguardHome_magisk](https://github.com/410154425/AdGuardHome_magisk) - [akashaProxy](https://github.com/ModuleList/akashaProxy) - [box_for_magisk](https://github.com/taamarin/box_for_magisk) > Special thanks to sponsors: > > - y******a - 200 > - 偶****** - 10 ================================================ FILE: changelog.md ================================================ # Changelog - 同步 AdGuard Home v0.107.74 - Sync with AdGuard Home v0.107.74 - 新增 WebUI 配置界面 #61 (wTNTw) - New WebUI interface #61 (wTNTw) ================================================ FILE: docs/index.md ================================================ # 教程 (Tutorials) > **For English Users:** This module is primarily designed for Chinese users. If you require the documentation in English, we kindly recommend using a reliable translation tool. ## 安装 (Installation) 本模块仅适用于已经 root 的安卓设备,支持 [Magisk](https://github.com/topjohnwu/Magisk) / [KernelSU](https://github.com/tiann/KernelSU) / [APatch](https://github.com/bmax121/APatch) 等 root 工具 在 Release 页面下载 zip 文件,提供了 arm64 和 armv7 两个版本。一般推荐使用 arm64 版,因为它在性能上更优,并且与大多数现代设备兼容。 --- ## 配置 (Configuration) 模块默认的 AdGuardHome 后台地址为 `http://127.0.0.1:3000`,可以通过浏览器直接访问,默认账号和密码均为 `root`。 在 AdGuardHome 后台,你可以执行以下操作: - 查看 DNS 查询统计信息 - 修改各种 DNS 配置 - 查看日志 - 添加自定义规则 如果你更倾向于使用app管理AdGuardHome,可以尝试使用 [AdGuard Home Manager](https://github.com/JGeek00/adguard-home-manager) 应用。 --- ## 模块控制 (Module Control) 模块的状态会实时显示在`module.prop`文件中,在root管理器中可以看到模块的状态信息(如果没刷新请手动刷新) 模块实时监测`/data/adb/modules/AdGuardHome`目录下的`disable`文件,如果存在则禁用模块,不存在则启用模块 如果你想用其他方法来启停,你可以在文件管理器中手动创建和删除文件,也可以使用shell命令 ```shell touch /data/adb/modules/AdGuardHome/disable ``` ```shell rm /data/adb/modules/AdGuardHome/disable ``` 本模块可以分为两部分,一部分是 AdGuardHome 本身,它在本地搭建了一个可自定义拦截功能的 DNS 服务器,另一部分是 iptables 转发规则,它负责将本机所有53端口出口流量重定向到 AdGuardHome --- ## 与代理软件共存 (Coexistence with Proxy Software) 代理软件主要分为两类: **代理应用**:如 [NekoBox](https://github.com/MatsuriDayo/NekoBoxForAndroid)、[FlClash](https://github.com/chen08209/FlClash) 等。这些应用通常具有图形化界面,便于用户配置和管理代理规则。 以下是我自用的 FlClash 配置文件示例: ```yaml proxy-providers: provider1: type: http url: "" interval: 86400 provider2: type: http url: "" interval: 86400 proxy-groups: - name: PROXY type: select include-all: true rules: proxy-groups: - name: PROXY type: select include-all: true rules: - GEOSITE,private,DIRECT - GEOSITE,googlefcm,DIRECT - GEOSITE,bilibili,DIRECT - GEOSITE,onedrive,PROXY - GEOSITE,twitter,PROXY - GEOSITE,youtube,PROXY - GEOSITE,telegram,PROXY - GEOSITE,google,PROXY - GEOSITE,microsoft@cn,DIRECT - GEOSITE,category-scholar-!cn,PROXY - GEOSITE,steam@cn,DIRECT - GEOSITE,category-games@cn,DIRECT - GEOSITE,geolocation-!cn,PROXY - GEOSITE,cn,DIRECT - GEOIP,private,DIRECT,no-resolve - GEOIP,google,DIRECT - GEOIP,telegram,PROXY - GEOIP,cn,DIRECT - MATCH,DIRECT ``` 没有写 DNS 部分是因为 FlClash 支持 DNS 覆写,在软件内就可配置 DNS 部分,将域名解析服务器改为 127.0.0.1:5591 即可使用本地的 adgh 作为DNS服务器 **代理模块**:如 [box_for_magisk](https://github.com/taamarin/box_for_magisk)、[akashaProxy](https://github.com/akashaProxy/akashaProxy) 等。这些模块通常运行在系统层级,适合需要更高权限或更深度集成的场景。 代理应用的 `分应用代理/访问控制` 功能非常实用。通过将国内应用设置为绕过模式,可以减少不必要的流量经过代理,同时这些绕过的应用仍然能够正常屏蔽广告。 如果使用代理模块,强烈建议禁用模块的 iptables 转发规则。禁用后,模块仅运行 AdGuardHome 本身。随后,将代理模块的上游 DNS 服务器配置为 `127.0.0.1:5591`,即可确保代理软件的所有 DNS 查询通过 AdGuardHome 进行广告屏蔽。 ```yaml dns: # ... default-nameserver: - 223.5.5.5 nameserver: - 127.0.0.1:5591 # ... ``` --- ## 模块目录与配置文件 (Module Directory and Configuration Files) 模块的文件结构主要分为以下两个目录: - **`/data/adb/agh`**:包含 AdGuardHome 的核心文件,包括二进制文件、工具脚本和配置文件。 - **`/data/adb/modules/AdGuardHome`**:存储模块的启动脚本和运行时数据文件。 模块的配置文件也分为两部分: - **`/data/adb/agh/bin/AdGuardHome.yaml`**:AdGuardHome 的主配置文件。 - **`/data/adb/agh/settings.conf`**:模块的配置文件,具体说明请参考文件内的注释。 在更新模块时,用户可以选择是否保留原有的配置文件。如果选择不保留,系统会自动将原配置文件备份到 **`/data/adb/agh/backup`** 目录,以确保数据安全。 --- ## 模块打包 (Module Packaging) 模块根目录下提供了一个名为 `pack.ps1` 的打包脚本,用户可以通过它快速生成模块的安装包。 在 Windows 系统上,打开 PowerShell 并执行以下命令: ```powershell .\pack.ps1 ``` 运行脚本后,以下操作将自动完成: 1. 创建 `cache` 目录(如果尚未存在)。 2. 下载并缓存最新版本的 AdGuardHome(仅在 `cache` 目录中未找到缓存时执行下载)。 3. 将 AdGuardHome 与模块的其他文件打包成一个 ZIP 文件。 该脚本的设计确保了高效性:如果 `cache` 目录中已存在 AdGuardHome 的缓存版本,则无需重复下载,从而节省时间和带宽。 ## 常见问题 (Frequently Asked Questions) ### **Q: 模块安装后无法正常运行怎么办?** **A:** - 检查 AdGuardHome 是否在运行: 使用以下命令查看进程状态: ```shell ps | grep AdGuardHome ``` - 确保设备的 **私人 DNS** 功能已关闭: 前往 **设置 -> 网络和互联网 -> 高级 -> 私人 DNS**,并将其设置为关闭。 ### **Q: 如何更改 AdGuardHome 的默认端口?** **A:** - 打开 **`/data/adb/agh/bin/AdGuardHome.yaml`** 文件。 - 修改 `bind_host` 的端口号为所需值。 - 保存文件后,重启模块以应用更改。 ### **Q: 如何禁用模块的 iptables 转发规则?** **A:** - 编辑 **`/data/adb/agh/settings.conf`** 文件。 - 将 `ENABLE_IPTABLES` 参数设置为 `false`。 - 保存文件后,重启模块。 ### **Q: 使用代理模块时,广告屏蔽无效怎么办?** **A:** - 确保代理模块的上游 DNS 服务器配置为 **`127.0.0.1:5591`**。 - 检查代理模块的配置文件,确保所有 DNS 查询通过 AdGuardHome。 ### **Q: 模块是否会影响设备性能?** **A:** - 模块对性能的影响较小,但在低性能设备上可能会有轻微延迟。 - 推荐使用 **arm64** 版本以获得更好的性能。 ### **Q:使用模块后,无法访问 Google 怎么办?** **A:** - 如果你用的是 FlClash,可尝试在`settings.conf`填入以下配置: ```ini ignore_src_list="172.19.0.1" ``` 此问题与节点质量有关,有的机场不改也没问题 ================================================ FILE: pack.ps1 ================================================ # 定义下载 URL 和路径变量 $CacheDir = "$PSScriptRoot\cache" $UrlWitchCachePath = @{ "https://github.com/AdguardTeam/AdGuardHome/releases/latest/download/AdGuardHome_linux_arm64.tar.gz" = "$CacheDir\AdGuardHome_linux_arm64.tar.gz" "https://github.com/AdguardTeam/AdGuardHome/releases/latest/download/AdGuardHome_linux_armv7.tar.gz" = "$CacheDir\AdGuardHome_linux_armv7.tar.gz" } # 创建缓存目录 if (-Not (Test-Path -Path $CacheDir)) { Write-Host "Creating cache directory..." New-Item -Path $CacheDir -ItemType Directory } # 下载文件,有缓存时不再下载 Write-Host "Downloading AdGuardHome..." foreach ($url in $UrlWitchCachePath.Keys) { $CachePath = $UrlWitchCachePath[$url] if (-Not (Test-Path -Path $CachePath)) { Write-Host "Downloading $url..." Invoke-WebRequest -Uri $url -OutFile $CachePath if ($?) { Write-Host "Download completed successfully." } else { Write-Host "Download failed. Exiting..." exit 1 } } else { Write-Host "File already exists in cache. Skipping download." } } # 使用 tar 解压文件 Write-Host "Extracting AdGuardHome..." foreach ($url in $UrlWitchCachePath.Keys) { $CachePath = $UrlWitchCachePath[$url] if ($CachePath -match 'AdGuardHome_linux_(arm64|armv7)\.tar\.gz$') { $ExtractDir = "./cache/" + $matches[1] } else { throw "Invalid file path: $CachePath" } if (-Not (Test-Path -Path $ExtractDir)) { New-Item -Path $ExtractDir -ItemType Directory Write-Host "Extracting $CachePath..." tar -xzf $CachePath -C $ExtractDir if ($?) { Write-Host "Extraction completed successfully." } else { Write-Host "Extraction failed" exit 1 } } } # 给项目打包,使用 7-Zip 压缩 zip Write-Host "Packing AdGuardHome..." $OutputPathArm64 = "$CacheDir\AdGuardHomeForRoot_arm64.zip" $OutputPathArmv7 = "$CacheDir\AdGuardHomeForRoot_armv7.zip" if (Test-Path -Path $OutputPathArm64) { Remove-Item -Path $OutputPathArm64 } if (Test-Path -Path $OutputPathArmv7) { Remove-Item -Path $OutputPathArmv7 } # 设置项目根目录 $ProjectRoot = "$PSScriptRoot\src" $env:PATH += ";C:\Program Files\7-Zip" # pack arm64 7z a -tzip $OutputPathArm64 "$ProjectRoot\*.sh" 7z a -tzip $OutputPathArm64 "$ProjectRoot\settings.conf" 7z a -tzip $OutputPathArm64 "$ProjectRoot\module.prop" 7z a -tzip $OutputPathArm64 "$ProjectRoot\META-INF" 7z a -tzip $OutputPathArm64 "$ProjectRoot\scripts" 7z a -tzip $OutputPathArm64 "$ProjectRoot\webroot" 7z a -tzip $OutputPathArm64 "$ProjectRoot\bin\" 7z a -tzip $OutputPathArm64 "$CacheDir\arm64\AdGuardHome\AdGuardHome" 7z rn $OutputPathArm64 "AdGuardHome" "bin/AdGuardHome" # pack armv7 7z a -tzip $OutputPathArmv7 "$ProjectRoot\*.sh" 7z a -tzip $OutputPathArmv7 "$ProjectRoot\settings.conf" 7z a -tzip $OutputPathArmv7 "$ProjectRoot\module.prop" 7z a -tzip $OutputPathArmv7 "$ProjectRoot\META-INF" 7z a -tzip $OutputPathArmv7 "$ProjectRoot\scripts" 7z a -tzip $OutputPathArmv7 "$ProjectRoot\webroot" 7z a -tzip $OutputPathArmv7 "$ProjectRoot\bin\" 7z a -tzip $OutputPathArmv7 "$CacheDir\armv7\AdGuardHome\AdGuardHome" 7z rn $OutputPathArmv7 "AdGuardHome" "bin/AdGuardHome" Write-Host "Packing completed successfully." ================================================ FILE: src/META-INF/com/google/android/update-binary ================================================ #!/sbin/sh ################# # Initialization ################# umask 022 # echo before loading util_functions ui_print() { echo "$1"; } require_new_magisk() { ui_print "*******************************" ui_print " 请升级安装 Magisk v20.4或以上! " ui_print "*******************************" exit 1 } ######################### # Load util_functions.sh ######################### OUTFD=$2 ZIPFILE=$3 mount /data 2>/dev/null [ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk . /data/adb/magisk/util_functions.sh [ $MAGISK_VER_CODE -lt 20400 ] && require_new_magisk install_module exit 0 ================================================ FILE: src/META-INF/com/google/android/updater-script ================================================ #MAGISK ================================================ FILE: src/action.sh ================================================ . /data/adb/agh/settings.conf $SCRIPT_DIR/tool.sh toggle sleep 1 ================================================ FILE: src/bin/AdGuardHome.yaml ================================================ http: pprof: port: 6060 enabled: false address: 127.0.0.1:3000 session_ttl: 720h users: - name: root password: $2b$12$D3zeMIBFfzcQTqGqB.k7GOkMvqx1jgsrdiRCn2kwOHl.kNmmPfMom auth_attempts: 5 block_auth_min: 15 http_proxy: "" language: "" theme: auto dns: bind_hosts: - 127.0.0.1 port: 5591 anonymize_client_ip: false ratelimit: 0 ratelimit_subnet_len_ipv4: 24 ratelimit_subnet_len_ipv6: 56 ratelimit_whitelist: [] refuse_any: true upstream_dns: - https://doh.pub/dns-query - https://dns.alidns.com/dns-query upstream_dns_file: "" bootstrap_dns: - 119.29.29.29 - 223.5.5.5 - 223.6.6.6 - 1.1.1.1 - 8.8.8.8 fallback_dns: - https://dns.google/dns-query - https://cloudflare-dns.com/dns-query upstream_mode: load_balance fastest_timeout: 1s allowed_clients: [] disallowed_clients: [] blocked_hosts: - version.bind - id.server - hostname.bind trusted_proxies: - 127.0.0.0/8 - ::1/128 cache_enabled: true cache_size: 67108864 cache_ttl_min: 0 cache_ttl_max: 0 cache_optimistic: true cache_optimistic_answer_ttl: 30s cache_optimistic_max_age: 12h bogus_nxdomain: [] aaaa_disabled: false enable_dnssec: false edns_client_subnet: custom_ip: "" enabled: true use_custom: false max_goroutines: 300 handle_ddr: true ipset: [] ipset_file: "" bootstrap_prefer_ipv6: false upstream_timeout: 10s private_networks: [] use_private_ptr_resolvers: false local_ptr_upstreams: [] use_dns64: false dns64_prefixes: [] serve_http3: false use_http3_upstreams: false serve_plain_dns: true hostsfile_enabled: true pending_requests: enabled: true tls: enabled: false server_name: "" force_https: false port_https: 443 port_dns_over_tls: 853 port_dns_over_quic: 853 port_dnscrypt: 0 dnscrypt_config_file: "" allow_unencrypted_doh: false certificate_chain: "" private_key: "" certificate_path: "" private_key_path: "" strict_sni_check: false querylog: dir_path: "" ignored: [] interval: 24h size_memory: 1000 enabled: true file_enabled: true statistics: dir_path: "" ignored: [] interval: 24h enabled: true filters: - enabled: true url: https://raw.githubusercontent.com/TG-Twilight/AWAvenue-Ads-Rule/main/AWAvenue-Ads-Rule.txt name: AWAvenue id: 1732747955 whitelist_filters: [] user_rules: - "" dhcp: enabled: false interface_name: "" local_domain_name: lan dhcpv4: gateway_ip: "" subnet_mask: "" range_start: "" range_end: "" lease_duration: 86400 icmp_timeout_msec: 1000 options: [] dhcpv6: range_start: "" lease_duration: 86400 ra_slaac_only: false ra_allow_slaac: false filtering: blocking_ipv4: "" blocking_ipv6: "" blocked_services: schedule: time_zone: Asia/Shanghai ids: [] protection_disabled_until: null safe_search: enabled: false bing: true duckduckgo: true ecosia: true google: true pixabay: true yandex: true youtube: true blocking_mode: default parental_block_host: family-block.dns.adguard.com safebrowsing_block_host: standard-block.dns.adguard.com rewrites: [] safe_fs_patterns: [] safebrowsing_cache_size: 1048576 safesearch_cache_size: 1048576 parental_cache_size: 1048576 cache_time: 30 filters_update_interval: 72 blocked_response_ttl: 10 filtering_enabled: true rewrites_enabled: true parental_enabled: false safebrowsing_enabled: false protection_enabled: true clients: runtime_sources: whois: true arp: true rdns: true dhcp: true hosts: true persistent: [] log: enabled: true file: "" max_backups: 0 max_size: 100 max_age: 3 compress: false local_time: false verbose: false os: group: "" user: "" rlimit_nofile: 0 schema_version: 32 ================================================ FILE: src/bin/data/filters/1732747955.txt ================================================ ||1500020991.vodplayer.wxamedia.com^ ||1500022744.vodplayer.wxamedia.com^ ||1500026601.vodplayer.wxamedia.com^ ||8le8le.com^ ||8rn1y79f02-1.algolianet.com^ ||a0.app.xiaomi.com^ ||aaid.umeng.com^ ||abtest-ch.snssdk.com^ ||ad-cdn.qingting.fm^ ||ad-scope.com^ ||ad-scope.com.cn^ ||ad-sdk-config.youdao.com^ ||ad-splash-tracking.hktvmall.com^ ||ad-splash.hktvmall.com^ ||ad.12306.cn^ ||ad.51wnl.com^ ||ad.api.3g.youku.com^ ||ad.bwton.com^ ||ad.cctv.com^ ||ad.cyapi.cn^ ||ad.doubleclick.net^ ||ad.gameley.com^ ||ad.hpplay.cn^ ||ad.iot.360.cn^ ||ad.jia.360.cn^ ||ad.life.360.cn^ ||ad.partner.gifshow.com^ ||ad.qingting.fm^ ||ad.qq.com^ ||ad.richmob.cn^ ||ad.shenshiads.com^ ||ad.shunchangzhixing.com^ ||ad.tencentmusic.com^ ||ad.toutiao.com^ ||ad.v3mh.com^ ||ad.weibo.com^ ||ad.winrar.com.cn^ ||ad.ximalaya.com^ ||ad.xunkids.com^ ||ad.zijieapi.com^ ||adapi.izuiyou.com^ ||adapi.yynetwk.com^ ||adashbc.ut.taobao.com^ ||adashx.m.taobao.com^ ||adashxgc.ut.taobao.com^ ||adc.hpplay.cn^ ||adcdn.hpplay.cn^ ||adcdn.tencentmusic.com^ ||adclick.g.doubleclick.net^ ||adclick.tencentmusic.com^ ||adcolony.com^ ||addata.jd.com^ ||adeng.hpplay.cn^ ||adexp.chinaliftoff.io^ ||adexp.liftoff.io^ ||adexpo.tencentmusic.com^ ||adfilter.imtt.qq.com^ ||adguanggao.eee114.com^ ||adimg.uve.weibo.com^ ||adjust.cn^ ||adjust.com^ ||adks.hpplay.cn^ ||adlink-api.huan.tv^ ||adm.funshion.com^ ||ads-api-o.api.leiniao.com^ ||ads-api.tiktok.com^ ||ads-api.twitter.com^ ||ads-img-al.xhscdn.com^ ||ads-img-qc.xhscdn.com^ ||ads-jp.tiktok.com^ ||ads-marketing-vivofs.vivo.com.cn^ ||ads-sdk-api.ranfenghd.com^ ||ads-sg.tiktok.com^ ||ads-video-al.xhscdn.com^ ||ads-video-qc.xhscdn.com^ ||ads.95516.com^ ||ads.auctions.yahoo.com^ ||ads.cup.com.cn^ ||ads.google.cn^ ||ads.huan.tv^ ||ads.huantest.com^ ||ads.icloseli.cn^ ||ads.inmobi.com^ ||ads.linkedin.com^ ||ads.pinterest.com^ ||ads.pubmatic.com^ ||ads.raidrive.com^ ||ads.servebom.com^ ||ads.service.kugou.com^ ||ads.tiktok.com^ ||ads.v3mh.com^ ||ads.youtube.com^ ||ads.zhinengxiyifang.cn^ ||ads3-normal-hl.zijieapi.com^ ||ads3-normal-lf.zijieapi.com^ ||ads3-normal-lq.zijieapi.com^ ||ads3-normal.zijieapi.com^ ||ads5-normal-hl.zijieapi.com^ ||ads5-normal-lf.zijieapi.com^ ||ads5-normal-lq.zijieapi.com^ ||ads5-normal.zijieapi.com^ ||adsdk.vivo.com.cn^ ||adse.test.ximalaya.com^ ||adse.wsa.ximalaya.com^ ||adse.ximalaya.com^ ||adsebs.ximalaya.com^ ||adsense.google.cn^ ||adserver.unityads.unity3d.com^ ||adservice.google.com^ ||adservice.sigmob.cn^ ||adserviceretry.kugou.com^ ||adsfile.bssdlbig.kugou.com^ ||adsfile.qq.com^ ||adsfilebssdlbig.ali.kugou.com^ ||adsfileretry.service.kugou.com^ ||adsfs-sdkconfig.heytapimage.com^ ||adsfs.oppomobile.com^ ||adslvfile.qq.com^ ||adsmart.konka.com^ ||adsmind.gdtimg.com^ ||adsmind.ugdtimg.com^ ||adsp.xunlei.com^ ||adstat.izuiyou.com^ ||adstats.tencentmusic.com^ ||adstore-1252524079.file.myqcloud.com^ ||adstore-index-1252524079.file.myqcloud.com^ ||adstrategy.biz.weibo.com^ ||adstudio-assets.scdn.co^ ||adstudio.spotify.com^ ||adtago.s3.amazonaws.com^ ||adtech.yahooinc.com^ ||adtrack.quark.cn^ ||adtracker.medproad.com^ ||adui.tg.meitu.com^ ||adv-api.shenshiads.com^ ||adv.sec.intl.miui.com^ ||adv.sec.miui.com^ ||advertising-api-eu.amazon.com^ ||advertising-api-fe.amazon.com^ ||advertising-api.amazon.com^ ||advertising.apple.com^ ||advertising.yahoo.com^ ||advertising.yandex.ru^ ||advice-ads.s3.amazonaws.com^ ||adview.cn^ ||adx-ad.smart-tv.cn^ ||adx-api.jinmo.tech^ ||adx-bj-req.anythinktech.com^ ||adx-bj.anythinktech.com^ ||adx-cn.anythinktech.com^ ||adx-drcn.op.dbankcloud.cn^ ||adx-open-service.youku.com^ ||adx-os.anythinktech.com^ ||adx-saas.advlion.com^ ||adx-strategy-api-cn.statisticslinks.com^ ||adx.ads.heytapmobi.com^ ||adx.ads.oppomobile.com^ ||adx.appsdk.com.cn^ ||adx.sogaha.cn^ ||adx.tuia.cn^ ||adxlog-adnet.vivo.com.cn^ ||adxserver.ad.cmvideo.cn^ ||aegis.qq.com^ ||aem.dentsuchina.cn^ ||afs.googlesyndication.com^ ||agn.aty.sohu.com^ ||aiseet.aa.atianqi.com^ ||ali-ad.a.yximgs.com^ ||ali-p2p-v2.pull.yximgs.com^ ||alicoccdncnc-xn.inter.71edge.com^ ||alicoccdnct-xn.inter.71edge.com^ ||alog.umeng.com^ ||alogus.umeng.com^ ||als.baidu.com^ ||amdcopen.m.taobao.com^ ||an.facebook.com^ ||analysis.chatglm.cn^ ||analysis.yozocloud.cn^ ||analytics-api.samsunghealthcn.com^ ||analytics.adjust.cn^ ||analytics.oceanengine.com^ ||analytics.pinterest.com^ ||analytics.pointdrive.linkedin.com^ ||analytics.query.yahoo.com^ ||analytics.rayjump.com^ ||analytics.s3.amazonaws.com^ ||analytics.tiktok.com^ ||analytics.woozooo.com^ ||analyticsengine.s3.amazonaws.com^ ||analyze.lemurbrowser.com^ ||andrqd.play.aiseet.atianqi.com^ ||ap.dongdianqiu.com^ ||ap.dongqiudi.com^ ||apd-pcdnwxlogin.teg.tencent-cloud.net^ ||apd-pcdnwxnat.teg.tencent-cloud.net^ ||apd-pcdnwxstat.teg.tencent-cloud.net^ ||api-access.pangolin-sdk-toutiao.com^ ||api-access.pangolin-sdk-toutiao1.com^ ||api-access.pangolin-sdk-toutiao2.com^ ||api-access.pangolin-sdk-toutiao3.com^ ||api-access.pangolin-sdk-toutiao4.com^ ||api-access.pangolin-sdk-toutiao5.com^ ||api-ad-data.kajicam.com^ ||api-ad-product.huxiu.com^ ||api-ad.kajicam.com^ ||api-adservices.apple.com^ ||api-gd.hiaiabc.com^ ||api-htp.beizi.biz^ ||api.ad.xiaomi.com^ ||api.anythinktech.com^ ||api.aqyad.com^ ||api.e.kuaishou.com^ ||api.fu.xcultur.com^ ||api.htp.hubcloud.com.cn^ ||api.hzsanjiaomao.com^ ||api.installer.xiaomi.com^ ||api.jietuhb.com^ ||api.kingdata.ksyun.com^ ||api.shanghailingye.cn^ ||api.ssp.xcultur.com^ ||api.statsig.com^ ||api.touch-moblie.com^ ||api.yfanads.com^ ||api5-normal-quic-lf.ixigua.com^ ||apiyd.my91app.com^ ||app-measurement.com^ ||appcfg.v.qq.com^ ||applog-perf.uc.cn^ ||applog.lc.quark.cn^ ||applog.uc.cn^ ||applog.zijieapi.com^ ||applovin.com^ ||aqyad.com^ ||aspect-upush.umeng.com^ ||auction.unityads.unity3d.com^ ||audid-api.taobao.com^ ||audid.umeng.com^ ||b1-data.ads.heytapmobi.com^ ||badjs.weixinbridge.com^ ||baichuan-sdk.alicdn.com^ ||baichuan-sdk.taobao.com^ ||bdad.123pan.cn^ ||bdapi-ads.realmemobile.com^ ||bdapi-in-ads.realmemobile.com^ ||bdapi.ads.oppomobile.com^ ||bdcdncnc.inter.71edge.com^ ||beacon-api.aliyuncs.com^ ||beacon.qq.com^ ||beaconcdn.qq.com^ ||beacons.gvt2.com^ ||beizi.biz^ ||bes-mtj.baidu.com^ ||bgg.baidu.com^ ||bianxian.com^ ||bingads.microsoft.com^ ||biz.weibo.com^ ||bj-td-menta-01-callback.advlion.com^ ||bj.ad.track.66mobi.com^ ||books-analytics-events.apple.com^ ||bootpreload.uve.weibo.com^ ||browser.events.data.msn.cn^ ||browser.events.data.msn.com^ ||browsercfg-drcn.cloud.dbankcloud.cn^ ||bsrv.qq.com^ ||business-api.tiktok.com^ ||c.bidtoolads.com^ ||c.etoolads.cn^ ||c.evidon.com^ ||c.gj.qq.com^ ||c.kuaiduizuoye.com^ ||c.sayhi.360.cn^ ||c2.gdt.qq.com^ ||canvas-cdn.gdt.qq.com^ ||catalog.fjwhcbsh.com^ ||cbjs.baidu.com^ ||ccc-x.jd.com^ ||ccs.umeng.com^ ||cdn-ad.wtzw.com^ ||cdn-ads.oss-cn-shanghai.aliyuncs.com^ ||cdn-f.adsmoloco.com^ ||cdn-plugin-sync-upgrade-juui.hismarttv.com^ ||cdn.aiclk.com^ ||cdn.chinaliftoff-creatives.io^ ||cdn.hpplay.com.cn^ ||cdn.iads.unitychina.cn^ ||cdn.liftoff-creatives.io^ ||cdn.ynuf.aliapp.org^ ||cfg.imtt.qq.com^ ||chat1.jd.com^ ||chiq-cloud.com^ ||ck.ads.oppomobile.com^ ||click.chinaliftoff.io^ ||click.googleanalytics.com^ ||click.liftoff.io^ ||click.oneplus.cn^ ||click4.chinaliftoff.io^ ||clog.miguvideo.com^ ||cloooud.com^ ||cn-api.anythinktech.com^ ||cnlogs.umeng.com^ ||cnlogs.umengcloud.com^ ||cnzz.com^ ||collect.kugou.com^ ||commdata.v.qq.com^ ||conf.hpplay.cn^ ||config.chsmarttv.com^ ||config.inmobi.com^ ||config.unityads.unity3d.com^ ||cpc-service-square.aiclk.com^ ||cpro.baidustatic.com^ ||crash2.zhihu.com^ ||crashlyticsreports-pa.googleapis.com^ ||csjplatform.com^ ||d.applovin.com^ ||d.applvn.com^ ||da.anythinktech.com^ ||data-sdk-uuid-log.d.meituan.net^ ||data.ads.oppomobile.com^ ||data.chsmarttv.com^ ||data.mistat.india.xiaomi.com^ ||data.mistat.rus.xiaomi.com^ ||data.mistat.xiaomi.com^ ||datacollection.uve.weibo.com^ ||dc.sigmob.cn^ ||de.tynt.com^ ||diagnosis.ad.xiaomi.com^ ||dig.bdurl.net^ ||dlogs.bwton.com^ ||dm.toutiao.com^ ||domain.aishengji.com^ ||doubleclick-cn.net^ ||download.changhong.upgrade2.huan.tv^ ||downloadxml.changhong.upgrade2.huan.tv^ ||drcn-weather.cloud.huawei.com^ ||dsp-x.jd.com^ ||dsp.fcbox.com^ ||dualstack-logs.amap.com^ ||dxp.baidu.com^ ||dyp2p-ali.douyucdn.cn^ ||dyp2p-hw.douyucdn.cn^ ||e.ad.xiaomi.com^ ||eclick.baidu.com^ ||edge.ads.twitch.tv^ ||ef-dongfeng.tanx.com^ ||engine.dcad01.com^ ||entry.baidu.com^ ||et-eus.w.inmobi.com^ ||event.tradplusad.com^ ||events-drcn.op.dbankcloud.cn^ ||events.reddit.com^ ||events.redditmedia.com^ ||fancyapi.com^ ||fclog.baidu.com^ ||feed-image.baidu.com^ ||file.daihuo.qq.com^ ||firebaselogging-pa.googleapis.com^ ||flurry.com^ ||frontend-perf-service.e.kuaishou.com^ ||fxgate.baidu.com^ ||g-adnet.hiaiabc.com^ ||g-staic.ganjingworld.com^ ||g.dtv.cn.miaozhen.com^ ||g.fancyapi.com^ ||g2.ganjing.world^ ||game.loveota.com^ ||gdfp.gifshow.com^ ||gemini.yahoo.com^ ||geo.yahoo.com^ ||getui.cn^ ||ggx.cmvideo.cn^ ||ggx01.miguvideo.com^ ||ggx03.miguvideo.com^ ||globalapi.ad.xiaomi.com^ ||google-analytics.com^ ||googleads.g.doubleclick-cn.net^ ||googleads.g.doubleclick.net^ ||googleadservices-cn.com^ ||googleadservices.com^ ||googletagservices-cn.com^ ||gorgon.youdao.com^ ||gromore.pangolin-sdk-toutiao.com^ ||grs.dbankcloud.com^ ||grs.hicloud.com^ ||gslb.hpplay.cn^ ||gvideo.qpic.cn^ ||h-adashx.ut.taobao.com^ ||h.trace.qq.com^ ||h5.analytics.126.net^ ||h5.hpplay.com.cn^ ||hanlanad.com^ ||hc-ssp.sm.cn^ ||heads-ak.spotify.com.edgesuite.net^ ||heads-fa.spotify.com^ ||hexagon-analytics.com^ ||hlog.bigda.com^ ||hm.baidu.com^ ||hmma.baidu.com^ ||hotupgrade.hpplay.cn^ ||houyi.kkmh.com^ ||hpplay.cdn.cibn.cc^ ||httpdns.bcelive.com^ ||httpdns.ocloud.oppomobile.com^ ||hugelog.fcbox.com^ ||huichuan-mc.sm.cn^ ||huichuan.sm.cn^ ||hw-ot-ad.a.yximgs.com^ ||hw-p2p-pull.video-voip.com^ ||hw-p2p.pull.yximgs.com^ ||hwpub-s01-drcn.cloud.dbankcloud.cn^ ||hybrid.miniapp.taobao.com^ ||hye.comp.360os.com^ ||hyt.comp.360os.com^ ||i.l-new.inmobicdn.net^ ||i.l.inmobicdn.net^ ||iad.apple.com^ ||iad.g.163.com^ ||iadctest.qwapi.com^ ||iadmusicmat.music.126.net^ ||iadsdk.apple.com^ ||iadworkbench.apple.com^ ||ifacelog.iqiyi.com^ ||ifs.tanx.com^ ||ii.gdt.qq.com^ ||image-ad.sm.cn^ ||image.hpplay.cn^ ||images.outbrainimg.com^ ||images.pinduoduo.com^ ||imdns.hpplay.cn^ ||img-c.heytapimage.com^ ||img-x.jd.com^ ||img.adnyg.com.w.kunlungr.com^ ||img2.360buyimg.com^ ||impression-asia.chinaliftoff.io^ ||impression-asia.liftoff.io^ ||impression.appsflyer.com^ ||in.treasuredata.com^ ||ios.bugly.qq.com^ ||iot-eu-logser.realme.com^ ||iot-logser.realme.com^ ||ipv4.kkmh.com^ ||irc.qubiankeji.com^ ||ixav-cse.avlyun.com^ ||iyfbodn.com^ ||janapi.jd.com^ ||jiguang.cn^ ||jpush.cn^ ||jpush.html5.qq.com^ ||jpush.io^ ||jswebcollects.kugou.com^ ||kde.qq.com^ ||kepler.jd.com^ ||kl.67it.com^ ||klink.volceapplog.com^ ||knicks.jd.com^ ||ks-p2p-v2.pull.yximgs.com^ ||ks-p2p.pull.yximgs.com^ ||ks.ferlytc.com^ ||ks.pull.yximgs.com^ ||l6.fancyapi.com^ ||launcher.smart-tv.cn^ ||launcherimg.smart-tv.cn^ ||lf3-ad-union-sdk.pglstatp-toutiao.com^ ||lf6-ad-union-sdk.pglstatp-toutiao.com^ ||lftxali.fancyapi.com^ ||lh3.googleadsserving.cn^ ||litchiads.com^ ||live-api.hktvmall.com^ ||liveats-vod.video.ptqy.gitv.tv^ ||livemonitor.huan.tv^ ||livep.l.aiseet.atianqi.com^ ||lives.l.aiseet.atianqi.com^ ||lives.l.ott.video.qq.com^ ||livewebbs2pcdn.msstatic.com^ ||lm10111.jtrincc.cn^ ||log-api-mn.huxiu.com^ ||log-api.huxiu.com^ ||log-api.pangolin-sdk-toutiao-b.com^ ||log-api.pangolin-sdk-toutiao.com^ ||log-report.com^ ||log-sdk.gifshow.com^ ||log-sdk.ksapisrv.com^ ||log-upload-os.hoyoverse.com^ ||log-upload.mihoyo.com^ ||log-verify.dutils.com^ ||log-verify.hiaiabc.com^ ||log.ad.xiaomi.com^ ||log.aispeech.com^ ||log.amemv.com^ ||log.appstore3.huan.tv^ ||log.avlyun.com^ ||log.byteoversea.com^ ||log.fc.yahoo.com^ ||log.iflytek.com^ ||log.ireader.com^ ||log.kuwo.cn^ ||log.pinterest.com^ ||log.popin.cc^ ||log.stat.kugou.com^ ||log.tagtic.cn^ ||log.tbs.qq.com^ ||log.vcgame.cn^ ||log.web.kugou.com^ ||log.zijieapi.com^ ||log1.cmpassport.com^ ||logbak.hicloud.com^ ||logrcv.aiclk.com^ ||logrcv.yunxish.com^ ||logs.amap.com^ ||logservice.hicloud.com^ ||logservice1.hicloud.com^ ||logtj.kugou.com^ ||logupdate.avlyun.sec.miui.com^ ||logwebs.kugou.com^ ||luimg.baidu.com^ ||m-adnet.hiaiabc.com^ ||m.ad.zhangyue.com^ ||m.atm.youku.com^ ||m.shenshiads.com^ ||mapi.m.jd.com^ ||masdkv6.3g.qq.com^ ||mazu.m.qq.com^ ||mbdlog.iqiyi.com^ ||mcs.zijieapi.com^ ||medproad.com^ ||metrics.data.hicloud.com^ ||metrics.icloud.com^ ||metrics.mzstatic.com^ ||metrics2.data.hicloud.com^ ||metrika.yandex.ru^ ||mi.gdt.qq.com^ ||miav-cse.avlyun.com^ ||micro-xdb.com^ ||mini-prog-drm.vodplayvideo.net^ ||mission-pub.smart-tv.cn^ ||miui-fxcse.avlyun.com^ ||mlog.bigda.com^ ||mnqlog.ldmnq.com^ ||moatads.com^ ||mobads-logs.baidu.com^ ||mobads-pre-config.cdn.bcebos.com^ ||mobads.baidu.com^ ||mobaliyun.res.mgtv.com^ ||mobile.da.mgtv.com^ ||mobilead.kuwo.cn^ ||mobilelog.kugou.com^ ||mobilelog.upqzfile.com^ ||monitor-ads-test.huan.tv^ ||monitor-uu.play.aiseet.atianqi.com^ ||monitor.adxsenmeng.com^ ||monitor.music.qq.com^ ||monitor.uu.qq.com^ ||monsetting.toutiao.com^ ||mores.toponad.com^ ||ms.applovin.com^ ||ms.applvn.com^ ||ms4.applovin.com^ ||ms4.applvn.com^ ||msdk.voiceads.cn^ ||mssdk.volces.com^ ||mssdk.zijieapi.com^ ||mtj.baidu.com^ ||nadvideo2.baidu.com^ ||newvoice.chiq5.smart-tv.cn^ ||nex.163.com^ ||nmetrics.samsung.com^ ||notes-analytics-events.apple.com^ ||notify.sec.miui.com^ ||nsclick.baidu.com^ ||o-sdk.mediation.unity3d.com^ ||o2o.api.xiaomi.com^ ||offerwall.yandex.net^ ||ogads-pa.clients6.google.com^ ||omgmta.play.aiseet.atianqi.com^ ||open-set-api.shenshiads.com^ ||open.e.kuaishou.cn^ ||open.e.kuaishou.com^ ||open.kuaishouzt.com^ ||open.kwaizt.com^ ||open.snssdk.com^ ||openadapi.fancydsp.com^ ||optimus-ads.amap.com^ ||orbit.jd.com^ ||oss.cdn.aiclk.com^ ||oth.eve.mdt.qq.com^ ||oth.str.mdt.qq.com^ ||otheve.play.aiseet.atianqi.com^ ||outlookads.live.com^ ||p.l.qq.com^ ||p.s.360.cn^ ||p1-be-pack-sign.pglstatp-toutiao.com^ ||p1-lm.adkwai.com^ ||p2-be-pack-sign.pglstatp-toutiao.com^ ||p2-lm.adkwai.com^ ||p2pchunk-table.douyucdn.cn^ ||p2plive-ali.douyucdn.cn^ ||p2pupdate.gamedl.qq.com^ ||p2pupgrade.gamedl.qq.com^ ||p3-be-pack-sign.pglstatp-toutiao.com^ ||p3-lm.adkwai.com^ ||p3-tt.byteimg.com^ ||p4-be-pack-sign.pglstatp-toutiao.com^ ||p5-be-pack-sign.pglstatp-toutiao.com^ ||p6-be-pack-sign.pglstatp-toutiao.com^ ||p66-ad.adkwai.com^ ||pagead2.googleadservices.com^ ||pagead2.googlesyndication.com^ ||pangolin-sdk-toutiao-b.com^ ||pay.sboot.cn^ ||pcdn.xmcdn.com^ ||pcdn.yximgs.com^ ||pcm-img.zhls.qq.com^ ||pgdt.gtimg.cn^ ||pgdt.ugdtimg.com^ ||pglstatp-toutiao.com^ ||pig.pupuapi.com^ ||pin.hpplay.cn^ ||pixon.ads-pixiv.net^ ||pkoplink.com^ ||pl.cp31.ott.cibntv.net^ ||plbslog.umeng.com^ ||pms.mb.qq.com^ ||policy.video.ptqy.gitv.tv^ ||pos.baidu.com^ ||prod-mediate-events.applovin.com^ ||promotion-partner.kuaishou.com^ ||proxy.advp.apple.com^ ||public.gdtimg.com^ ||q.i.gdt.qq.com^ ||qcwx.medproad.com^ ||qmlog.baertt.com^ ||qn-cdnfile1pcdn.msstatic.com^ ||qqdata.ab.qq.com^ ||qzs.gdtimg.com^ ||recommend-drcn.hms.dbankcloud.cn^ ||report.tv.kohesport.qq.com^ ||res.hubcloud.com.cn^ ||res1.applovin.com^ ||res1.hubcloud.com.cn^ ||res2.hubcloud.com.cn^ ||res3.hubcloud.com.cn^ ||resolve.umeng.com^ ||review.gdtimg.com^ ||rlog.popin.cc^ ||rms-drcn.platform.dbankcloud.cn^ ||roi.soulapp.cn^ ||rp.hpplay.cn^ ||rps.hpplay.cn^ ||rpt.gdt.qq.com^ ||rt.applovin.com^ ||rt.applvn.com^ ||rtb.adxsenmeng.com^ ||rtb.voiceads.cn^ ||s.amazon-adsystem.com^ ||s1.cdn-sg.advlion.com^ ||s8t.teads.tv^ ||saad.ms.zhangyue.net^ ||saas.hpplay.cn^ ||safebrowsing.urlsec.gg.com^ ||samsung-com.112.2o7.net^ ||samsungads.com^ ||saxysec.com^ ||scs.openspeech.cn^ ||sdk-ab-config.qquanquan.com^ ||sdk-cache.video.ptqy.gitv.tv^ ||sdk.1rtb.net^ ||sdk.ad.smaato.net^ ||sdk.adx.adwangmai.com^ ||sdk.aqyad.com^ ||sdk.beizi.biz^ ||sdk.cferw.com^ ||sdk.e.qq.com^ ||sdk.hzsanjiaomao.com^ ||sdk.markmedia.com.cn^ ||sdk.mobads.adwangmai.com^ ||sdkapi.cloooud.com^ ||sdkapp.uve.weibo.com^ ||sdkauth.hpplay.cn^ ||sdkconf.avlyun.com^ ||sdkconfig.ad.intl.xiaomi.com^ ||sdkconfig.ad.xiaomi.com^ ||sdkconfig.play.aiseet.atianqi.com^ ||sdkconfig.video.qq.com^ ||sdkoptedge.chinanetcenter.com^ ||sdkreport.e.qq.com^ ||sdktmp.hubcloud.com.cn^ ||sdownload.stargame.com^ ||search.ixigua.com^ ||search3-search.ixigua.com^ ||search5-search-hl.ixigua.com^ ||search5-search.ixigua.com^ ||securemetrics.apple.com^ ||securepubads.g.doubleclick.net^ ||sensors-log.dongqiudi.com^ ||sentry.music.163.com^ ||service.changhong.upgrade2.huan.tv^ ||service.vmos.cn^ ||sf16-static.i18n-pglstatp.com^ ||sf3-fe-tos.pglstatp-toutiao.com^ ||shouji.sogou.com^ ||sigmob.com^ ||skdisplay.jd.com^ ||sl.hpplay.cn^ ||slb-p2p.vcloud.ks-live.com^ ||smad.ms.zhangyue.net^ ||smartad.10010.com^ ||smetrics.samsung.com^ ||sms.ads.oppomobile.com^ ||sngmta.qq.com^ ||snowflake.qq.com^ ||ssp.cloooud.com^ ||staging-notify.sec.miui.com^ ||stat.dongqiudi.com^ ||stat.y.qq.com^ ||static-s.iqiyi.com^ ||static.ads-twitter.com^ ||statichf.shihuocdn.cn^ ||statics.woozooo.com^ ||stats.wp.com^ ||statsigapi.net^ ||stg-data.ads.heytapmobi.com^ ||stun.hitv.com^ ||success.ctobsnssdk.com^ ||supply.inmobicdn.net^ ||sv-video.play.aiseet.atianqi.com^ ||syh-imp.cdnjtzy.com^ ||syh.zybang.com^ ||szbdyd.com^ ||t-adx.52qumao.com^ ||t-dsp.pinduoduo.com^ ||t.applovin.com^ ||t.l.qq.com^ ||t.teads.tv^ ||t.track.ad.xiaomi.com^ ||t002.ottcn.com^ ||t1.a.market.xiaomi.com^ ||t1.teads.tv^ ||t2.a.market.xiaomi.com^ ||t2.fancyapi.com^ ||t3.a.market.xiaomi.com^ ||t7z.cupid.ptqy.gitv.tv^ ||tagtic.cn^ ||tangram.e.qq.com^ ||target.ads.jihuoniao.com^ ||tdc.qq.com^ ||tdsdk.cpatrk.net^ ||tdsdk.xdrig.com^ ||telecome.cn^ ||telemetry.sdk.inmobi.com^ ||tencent-dtv.m.cn.miaozhen.com^ ||test.ad.xiaomi.com^ ||test.e.ad.xiaomi.com^ ||tj.b.qq.com^ ||tj.video.qq.com^ ||tk.anythinktech.com^ ||tmead.y.qq.com^ ||tmeadcomm.y.qq.com^ ||tmfmazu-wangka.m.qq.com^ ||tmfmazu.m.qq.com^ ||tmfsdk.m.qq.com^ ||tmfsdktcpv4.m.qq.com^ ||tnc0-aliec2.zijieapi.com^ ||tnc0-alisc1.zijieapi.com^ ||tnc0-bjlgy.zijieapi.com^ ||tnc3-aliec1.toutiaoapi.com^ ||tnc3-aliec2.bytedance.com^ ||tnc3-aliec2.snssdk.com^ ||tnc3-aliec2.toutiaoapi.com^ ||tnc3-aliec2.zijieapi.com^ ||tnc3-alisc1.bytedance.com^ ||tnc3-alisc1.snssdk.com^ ||tnc3-alisc1.toutiaoapi.com^ ||tnc3-alisc1.zijieapi.com^ ||tnc3-alisc2.zijieapi.com^ ||tnc3-bjlgy.bytedance.com^ ||tnc3-bjlgy.snssdk.com^ ||tnc3-bjlgy.toutiaoapi.com^ ||tnc3-bjlgy.zijieapi.com^ ||toblog.ctobsnssdk.com^ ||tpa-hcdn.iqiyi.com^ ||tpc.googlesyndication-cn.com^ ||tpc.googlesyndication.com^ ||tr-asia.adsmoloco.com^ ||trace.aqyad.com^ ||trace.qq.com^ ||tracelog-debug.aiclk.com^ ||tracelog-debug.qquanquan.com^ ||tracelog-debug.yunxish.com^ ||track.lc.quark.cn^ ||track.uc.cn^ ||tracker.ai.xiaomi.com^ ||tracker.gitee.com^ ||tracking.miui.com^ ||tracking.rus.miui.com^ ||tuiguang.meitu.com^ ||tvapp.hpplay.cn^ ||tvuser-ch.cedock.com^ ||tx-ad.a.yximgs.com^ ||tx-kmpaudio.pull.yximgs.com^ ||tx-p2p-pull.live-voip.com^ ||tx-p2p-v2.pull.yximgs.com^ ||tytx.m.cn.miaozhen.com^ ||tz.sec.xiaomi.com^ ||uapi.ads.heytapmobi.com^ ||udc.yahoo.com^ ||udcm.yahoo.com^ ||uedas.qidian.com^ ||uhabo.com^ ||ulog-sdk.gifshow.com^ ||ulogjs.gifshow.com^ ||ulogs.umeng.com^ ||ulogs.umengcloud.com^ ||umengacs.m.taobao.com^ ||umengjmacs.m.taobao.com^ ||umini.shujupie.com^ ||union-mlog.bigda.com^ ||union.baidu.cn^ ||union.baidu.com^ ||update.avlyun.sec.miui.com^ ||update.lejiao.tv^ ||update0.aiclk.com^ ||upgrade-update.hismarttv.com^ ||uranus.jd.com^ ||us.l.qq.com^ ||usr-api.aiclk.com^ ||utoken.umeng.com^ ||v.110route.cn^ ||v.adintl.cn^ ||v.adx.hubcloud.com.cn^ ||v1-ad.video.yximgs.com^ ||v2-ad.video.yximgs.com^ ||v2-api-channel-launcher.hismarttv.com^ ||v2.gdt.qq.com^ ||v2mi.gdt.qq.com^ ||v3-ad.video.yximgs.com^ ||v3.gdt.qq.com^ ||vd6.l.qq.com^ ||vi.l.qq.com^ ||video-ad.sm.cn^ ||video-dsp.pddpic.com^ ||video.dispatch.tc.qq.com^ ||video.market.xiaomi.com^ ||vipauth.hpplay.cn^ ||vipgslb.hpplay.cn^ ||virusinfo-cloudscan-cn.heytapmobi.com^ ||vlive.qqvideo.tc.qq.com^ ||volc.bj.ad.track.66mobi.com^ ||vungle.com^ ||w.l.qq.com^ ||w1.askwai.com^ ||w1.gskwai.com^ ||w1.kskwai.com^ ||watson.microsoft.com^ ||watson.telemetry.microsoft.com^ ||wcp.taobao.com^ ||weather-analytics-events.apple.com^ ||weather-community-drcn.weather.dbankcloud.cn^ ||webstat.qiumibao.com^ ||webview.unityads.unity3d.com^ ||widgets.outbrain.com^ ||widgets.pinterest.com^ ||wildcard.moatads.com.edgekey.net^ ||win.gdt.qq.com^ ||wn.x.jd.com^ ||ws-keyboard.shouji.sogou.com^ ||ws.sj.qq.com^ ||wv.inner-active.mobi^ ||wwads.cn^ ||wxa.wxs.qq.com^ ||wxaintpcos.wxqcloud.qq.com.cn^ ||wximg.wxs.qq.com^ ||wxsmw.wxs.qq.com^ ||wxsnsad.tc.qq.com^ ||wxsnsdy.tc.qq.com^ ||wxsnsdy.wxs.qq.com^ ||wxsnsdythumb.wxs.qq.com^ ||xc.gdt.qq.com^ ||xcx.dcad01.com^ ||xiaomi-dtv.m.cn.miaozhen.com^ ||xlog.jd.com^ ||xlviiirdr.com^ ||xlviirdr.com^ ||xycdn.com^ ||yk-ssp-ad.cp31.ott.cibntv.net^ ||yk-ssp.ad.youku.com^ ||ykad-data.cp31.ott.cibntv.net^ ||ykad-data.youku.com^ ||ykad-gateway.youku.com^ ||youku-acs.m.taobao.com^ ||ytx-file.110route.cn^ ||zeus.ad.xiaomi.com^ ||zhihu-web-analytics.zhihu.com^ ||zjres-ad.kajicam.com^ ||zxid-m.mobileservice.cn^ ||1rtb.com^ ||a.market.xiaomi.com^ ||ad.gameley.com^ ||adintl.cn^ ||adx.adwangmai.com^ ||data.hicloud.com^ ||log.aliyuncs.com^ ||ubixioe.com^ ||vlion.cn^ ||yfanads.com^ ||zhangyuyidong.cn^ *-ad.sm.cn* *-ad.video.yximgs.com* *-ad.wtzw.com* *-be-pack-sign.pglstatp-toutiao.com* *-normal.zijieapi.com* ================================================ FILE: src/customize.sh ================================================ SKIPUNZIP=1 # most of the users are Chinese, so set default language to Chinese language="zh" # try to get the system language locale=$(getprop persist.sys.locale || getprop ro.product.locale || getprop persist.sys.language) # if the system language is English, set language to English if echo "$locale" | grep -qi "en"; then language="en" fi function info() { [ "$language" = "en" ] && ui_print "$1" || ui_print "$2" } function error() { [ "$language" = "en" ] && abort "$1" || abort "$2" } info "- 🚀 Installing AdGuardHome for $ARCH" "- 🚀 开始安装 AdGuardHome for $ARCH" AGH_DIR="/data/adb/agh" BIN_DIR="$AGH_DIR/bin" SCRIPT_DIR="$AGH_DIR/scripts" PID_FILE="$AGH_DIR/bin/agh.pid" info "- 📦 Extracting module basic files..." "- 📦 解压模块基本文件..." unzip -o "$ZIPFILE" "action.sh" -d "$MODPATH" >/dev/null 2>&1 unzip -o "$ZIPFILE" "module.prop" -d "$MODPATH" >/dev/null 2>&1 unzip -o "$ZIPFILE" "service.sh" -d "$MODPATH" >/dev/null 2>&1 unzip -o "$ZIPFILE" "uninstall.sh" -d "$MODPATH" >/dev/null 2>&1 unzip -o "$ZIPFILE" "webroot/*" -d "$MODPATH" >/dev/null 2>&1 extract_keep_config() { info "- 🌈 Keeping old configuration files..." "- 🌈 保留原来的配置文件..." info "- 📜 Extracting script files..." "- 📜 正在解压脚本文件..." unzip -o "$ZIPFILE" "scripts/*" -d $AGH_DIR >/dev/null 2>&1 || { error "- ❌ Failed to extract scripts!" "- ❌ 解压脚本文件失败!" } info "- 🛠️ Extracting binary files except configuration..." "- 🛠️ 正在解压二进制文件(不包括配置文件)..." unzip -o "$ZIPFILE" "bin/*" -x "bin/AdGuardHome.yaml" -d $AGH_DIR >/dev/null 2>&1 || { error "- ❌ Failed to extract binary files!" "- ❌ 解压二进制文件失败!" } info "- 🚫 Skipping configuration file extraction..." "- 🚫 跳过解压配置文件..." } extract_no_config() { info "- 💾 Backing up old configuration files with .bak extension..." "- 💾 使用 .bak 扩展名备份旧配置文件..." [ -f "$AGH_DIR/settings.conf" ] && mv "$AGH_DIR/settings.conf" "$AGH_DIR/settings.conf.bak" [ -f "$AGH_DIR/bin/AdGuardHome.yaml" ] && mv "$AGH_DIR/bin/AdGuardHome.yaml" "$AGH_DIR/bin/AdGuardHome.yaml.bak" extract_all } extract_all() { info "- 🌟 Extracting script files..." "- 🌟 正在解压脚本文件..." unzip -o "$ZIPFILE" "scripts/*" -d $AGH_DIR >/dev/null 2>&1 || { error "- ❌ Failed to extract scripts" "- ❌ 解压脚本文件失败" } info "- 🛠️ Extracting binary files..." "- 🛠️ 正在解压二进制文件..." unzip -o "$ZIPFILE" "bin/*" -d $AGH_DIR >/dev/null 2>&1 || { error "- ❌ Failed to extract binary files" "- ❌ 解压二进制文件失败" } info "- 📜 Extracting configuration files..." "- 📜 正在解压配置文件..." unzip -o "$ZIPFILE" "settings.conf" -d $AGH_DIR >/dev/null 2>&1 || { error "- ❌ Failed to extract configuration files" "- ❌ 解压配置文件失败" } } if [ -d "$AGH_DIR" ]; then info "- ⏹️ Found old version, stopping all AdGuardHome processes..." "- ⏹️ 发现旧版模块,正在停止所有 AdGuardHome 进程..." pkill -f "AdGuardHome" || pkill -9 -f "AdGuardHome" info "- 🔄 Do you want to keep the old configuration? (If not, it will be automatically backed up)" "- 🔄 是否保留原来的配置文件?(若不保留则自动备份)" info "- 🔊 (Volume Up = Yes, Volume Down = No, 30s no input = Yes)" "- 🔊 (音量上键 = 是, 音量下键 = 否,30秒无操作 = 是)" START_TIME=$(date +%s) while true; do NOW_TIME=$(date +%s) timeout 1 getevent -lc 1 2>&1 | grep KEY_VOLUME >"$TMPDIR/events" if [ $((NOW_TIME - START_TIME)) -gt 29 ]; then info "- ⏰ No input detected after 30 seconds, defaulting to keep old configuration." "- ⏰ 30秒无输入,默认保留原配置。" extract_keep_config break elif $(cat $TMPDIR/events | grep -q KEY_VOLUMEUP); then extract_keep_config break elif $(cat $TMPDIR/events | grep -q KEY_VOLUMEDOWN); then extract_no_config break fi done else info "- 📦 First time installation, extracting files..." "- 📦 第一次安装,正在解压文件..." mkdir -p "$AGH_DIR" "$BIN_DIR" "$SCRIPT_DIR" extract_all fi info "- 🔐 Setting permissions..." "- 🔐 设置权限..." chmod +x "$BIN_DIR/AdGuardHome" chown root:net_raw "$BIN_DIR/AdGuardHome" chmod +x "$SCRIPT_DIR"/*.sh "$MODPATH"/*.sh info "- 🎉 Installation completed, please reboot." "- 🎉 安装完成,请重启设备。" ================================================ FILE: src/module.prop ================================================ id=AdGuardHome name=AdGuardHome for Root version=20260419 versionCode=49 author=twoone3 description=none updateJson=https://raw.githubusercontent.com/twoone-3/AdGuardHomeForRoot/main/version.json ================================================ FILE: src/scripts/base.sh ================================================ # add busybox to PATH [ -d "/data/adb/magisk" ] && export PATH="/data/adb/magisk:$PATH" [ -d "/data/adb/ksu/bin" ] && export PATH="/data/adb/ksu/bin:$PATH" [ -d "/data/adb/ap/bin" ] && export PATH="/data/adb/ap/bin:$PATH" # most of the users are Chinese, so set default language to Chinese language="zh" # try to get the system language locale=$(getprop persist.sys.locale || getprop ro.product.locale || getprop persist.sys.language) # if the system language is English, set language to English if echo "$locale" | grep -qi "en"; then language="en" fi function log() { local timestamp=$(date "+%Y-%m-%d %H:%M:%S") local str [ "$language" = "en" ] && str="$timestamp $1" || str="$timestamp $2" echo "$str" | tee -a "$AGH_DIR/history.log" } function update_description() { local description [ "$language" = "en" ] && description="$1" || description="$2" sed -i "/^description=/c\description=$description" "$MOD_PATH/module.prop" } ================================================ FILE: src/scripts/debug.sh ================================================ #!/system/bin/sh AGH_DIR="/data/adb/agh" LOG="$AGH_DIR/debug.log" { echo "==== AdGuardHome Debug Log ====" date echo echo "== System Info ==" uname -a echo "Android Version: $(getprop ro.build.version.release)" echo "Device: $(getprop ro.product.model)" echo "Architecture: $(uname -m)" echo echo "== AdGuardHome Version ==" if [ -f "$AGH_DIR/bin/AdGuardHome" ]; then "$AGH_DIR/bin/AdGuardHome" --version else echo "AdGuardHome binary not found" fi echo echo "== Root Method ==" if [ -d "/data/adb/magisk" ]; then echo "Magisk" elif [ -d "/data/adb/ksu" ]; then echo "KernelSU" elif [ -d "/data/adb/ap" ]; then echo "APatch" else echo "Unknown" fi echo echo "== BusyBox Version ==" [ -d "/data/adb/magisk" ] && export PATH="/data/adb/magisk:$PATH" [ -d "/data/adb/ksu/bin" ] && export PATH="/data/adb/ksu/bin:$PATH" [ -d "/data/adb/ap/bin" ] && export PATH="/data/adb/ap/bin:$PATH" if command -v busybox >/dev/null 2>&1; then busybox --version else echo "BusyBox not found" fi echo "== AGH Directory Listing ==" ls -lR "$AGH_DIR" echo echo "== AGH Bin Log (last 30 lines) ==" tail -n 30 "$AGH_DIR/bin.log" 2>/dev/null echo echo "== AGH Settings ==" cat "$AGH_DIR/settings.conf" 2>/dev/null echo echo "== AGH PID File ==" cat "$AGH_DIR/bin/agh.pid" 2>/dev/null echo echo "== Running Processes (AdGuardHome) ==" ps -A | grep AdGuardHome echo echo "== iptables -t nat -L -n -v ==" iptables -t nat -L -n -v echo echo "== ip6tables -t filter -L -n -v ==" ip6tables -t filter -L -n -v echo echo "== Network Interfaces ==" ip addr echo } >"$LOG" 2>&1 echo "Debug info collected in $LOG" ================================================ FILE: src/scripts/inotify.sh ================================================ . /data/adb/agh/settings.conf readonly EVENTS=$1 readonly MONITOR_DIR=$2 readonly MONITOR_FILE=$3 if [ "${MONITOR_FILE}" = "disable" ]; then if [ "${EVENTS}" = "d" ]; then $SCRIPT_DIR/tool.sh start elif [ "${EVENTS}" = "n" ]; then $SCRIPT_DIR/tool.sh stop fi fi ================================================ FILE: src/scripts/iptables.sh ================================================ . /data/adb/agh/settings.conf . /data/adb/agh/scripts/base.sh iptables_w="iptables -w 64" ip6tables_w="ip6tables -w 64" check_ipv6_nat_support() { if $ip6tables_w -t nat -L >/dev/null 2>&1; then return 0 else return 1 fi } enable_iptables() { if $iptables_w -t nat -L ADGUARD_REDIRECT_DNS >/dev/null 2>&1; then log "ADGUARD_REDIRECT_DNS chain already exists" "ADGUARD_REDIRECT_DNS 链已经存在" return 0 fi log "Creating ADGUARD_REDIRECT_DNS chain and adding rules" "创建 ADGUARD_REDIRECT_DNS 链并添加规则" $iptables_w -t nat -N ADGUARD_REDIRECT_DNS || return 1 $iptables_w -t nat -A ADGUARD_REDIRECT_DNS -m owner --uid-owner $adg_user --gid-owner $adg_group -j RETURN || return 1 for subnet in $ignore_dest_list; do $iptables_w -t nat -A ADGUARD_REDIRECT_DNS -d $subnet -j RETURN || return 1 done for subnet in $ignore_src_list; do $iptables_w -t nat -A ADGUARD_REDIRECT_DNS -s $subnet -j RETURN || return 1 done $iptables_w -t nat -A ADGUARD_REDIRECT_DNS -p udp --dport 53 -j REDIRECT --to-ports $redir_port || return 1 $iptables_w -t nat -A ADGUARD_REDIRECT_DNS -p tcp --dport 53 -j REDIRECT --to-ports $redir_port || return 1 $iptables_w -t nat -I OUTPUT -j ADGUARD_REDIRECT_DNS || return 1 log "Applied iptables rules successfully" "成功应用 iptables 规则" } disable_iptables() { if ! $iptables_w -t nat -L ADGUARD_REDIRECT_DNS >/dev/null 2>&1; then log "ADGUARD_REDIRECT_DNS chain does not exist" "ADGUARD_REDIRECT_DNS 链不存在" return 0 fi log "Deleting ADGUARD_REDIRECT_DNS chain and rules" "删除 ADGUARD_REDIRECT_DNS 链及规则" $iptables_w -t nat -D OUTPUT -j ADGUARD_REDIRECT_DNS || return 1 $iptables_w -t nat -F ADGUARD_REDIRECT_DNS || return 1 $iptables_w -t nat -X ADGUARD_REDIRECT_DNS || return 1 } add_block_ipv6_dns() { if $ip6tables_w -t filter -L ADGUARD_BLOCK_DNS >/dev/null 2>&1; then log "ADGUARD_BLOCK_DNS chain already exists" "ADGUARD_BLOCK_DNS 链已经存在" return 0 fi log "Creating ADGUARD_BLOCK_DNS chain and adding rules" "创建 ADGUARD_BLOCK_DNS 链并添加规则" $ip6tables_w -t filter -N ADGUARD_BLOCK_DNS || return 1 $ip6tables_w -t filter -A ADGUARD_BLOCK_DNS -p udp --dport 53 -j DROP || return 1 $ip6tables_w -t filter -A ADGUARD_BLOCK_DNS -p tcp --dport 53 -j DROP || return 1 $ip6tables_w -t filter -I OUTPUT -j ADGUARD_BLOCK_DNS || return 1 log "Applied ipv6 iptables rules successfully" "成功应用 ipv6 iptables 规则" } del_block_ipv6_dns() { if ! $ip6tables_w -t filter -L ADGUARD_BLOCK_DNS >/dev/null 2>&1; then log "ADGUARD_BLOCK_DNS chain does not exist" "ADGUARD_BLOCK_DNS 链不存在" return 0 fi log "Deleting ADGUARD_BLOCK_DNS chain and rules" "删除 ADGUARD_BLOCK_DNS 链及规则" $ip6tables_w -t filter -F ADGUARD_BLOCK_DNS || return 1 $ip6tables_w -t filter -D OUTPUT -j ADGUARD_BLOCK_DNS || return 1 $ip6tables_w -t filter -X ADGUARD_BLOCK_DNS || return 1 } enable_ipv6_iptables() { if ! check_ipv6_nat_support; then log "IPv6 NAT is not supported, skipping IPv6 DNS hijack" "IPv6 NAT 不支持,跳过 IPv6 DNS 劫持" return 0 fi if $ip6tables_w -t nat -L ADGUARD_REDIRECT_DNS6 >/dev/null 2>&1; then log "ADGUARD_REDIRECT_DNS6 chain already exists" "ADGUARD_REDIRECT_DNS6 链已经存在" return 0 fi log "Creating ADGUARD_REDIRECT_DNS6 chain and adding rules" "创建 ADGUARD_REDIRECT_DNS6 链并添加规则" $ip6tables_w -t nat -N ADGUARD_REDIRECT_DNS6 || return 1 $ip6tables_w -t nat -A ADGUARD_REDIRECT_DNS6 -m owner --uid-owner $adg_user --gid-owner $adg_group -j RETURN || return 1 for subnet in $ignore_dest_list; do $ip6tables_w -t nat -A ADGUARD_REDIRECT_DNS6 -d $subnet -j RETURN || return 1 done for subnet in $ignore_src_list; do $ip6tables_w -t nat -A ADGUARD_REDIRECT_DNS6 -s $subnet -j RETURN || return 1 done $ip6tables_w -t nat -A ADGUARD_REDIRECT_DNS6 -p udp --dport 53 -j REDIRECT --to-ports $redir_port || return 1 $ip6tables_w -t nat -A ADGUARD_REDIRECT_DNS6 -p tcp --dport 53 -j REDIRECT --to-ports $redir_port || return 1 $ip6tables_w -t nat -I OUTPUT -j ADGUARD_REDIRECT_DNS6 || return 1 log "Applied ipv6 iptables rules successfully" "成功应用 ipv6 iptables 规则" } disable_ipv6_iptables() { if ! check_ipv6_nat_support; then log "IPv6 NAT is not supported, skipping IPv6 DNS hijack cleanup" "IPv6 NAT 不支持,跳过 IPv6 DNS 劫持清理" return 0 fi if ! $ip6tables_w -t nat -L ADGUARD_REDIRECT_DNS6 >/dev/null 2>&1; then log "ADGUARD_REDIRECT_DNS6 chain does not exist" "ADGUARD_REDIRECT_DNS6 链不存在" return 0 fi log "Deleting ADGUARD_REDIRECT_DNS6 chain and rules" "删除 ADGUARD_REDIRECT_DNS6 链及规则" $ip6tables_w -t nat -D OUTPUT -j ADGUARD_REDIRECT_DNS6 || return 1 $ip6tables_w -t nat -F ADGUARD_REDIRECT_DNS6 || return 1 $ip6tables_w -t nat -X ADGUARD_REDIRECT_DNS6 || return 1 } case "$1" in enable) log "Enabling iptables and ipv6 DNS blocking if configured" "启用 iptables" enable_iptables || exit 1 if [ "$block_ipv6_dns" = true ]; then log "IPv6 DNS mode: block (DROP IPv6 DNS traffic)" "IPv6 DNS 模式: block (丢弃 IPv6 DNS 流量)" add_block_ipv6_dns || exit 1 else log "IPv6 DNS mode: hijack (NAT REDIRECT to AdGuard Home)" "IPv6 DNS 模式: hijack (劫持 IPv6 到 AdGuard Home)" enable_ipv6_iptables || exit 1 fi ;; disable) log "Disabling iptables and ipv6 DNS blocking" "禁用 iptables 和 ipv6 DNS 阻断" disable_iptables || exit 1 del_block_ipv6_dns || exit 1 disable_ipv6_iptables || exit 1 ;; *) echo "Usage: $0 {enable|disable}" exit 1 ;; esac ================================================ FILE: src/scripts/tool.sh ================================================ . /data/adb/agh/settings.conf . /data/adb/agh/scripts/base.sh start_adguardhome() { # check if AdGuardHome is already running if [ -f "$PID_FILE" ] && ps | grep -w "$adg_pid" | grep -q "AdGuardHome"; then log "AdGuardHome is already running" "AdGuardHome 已经在运行" exit 0 fi # to fix https://github.com/AdguardTeam/AdGuardHome/issues/7002 export SSL_CERT_DIR="/system/etc/security/cacerts/" # set timezone to Shanghai export TZ="Asia/Shanghai" # backup old log and overwrite new log if [ -f "$AGH_DIR/bin.log" ]; then mv "$AGH_DIR/bin.log" "$AGH_DIR/bin.log.bak" fi # run binary busybox setuidgid "$adg_user:$adg_group" "$BIN_DIR/AdGuardHome" >"$AGH_DIR/bin.log" 2>&1 & adg_pid=$! # check if AdGuardHome started successfully if ps | grep -w "$adg_pid" | grep -q "AdGuardHome"; then echo "$adg_pid" >"$PID_FILE" # check if iptables is enabled if [ "$enable_iptables" = true ]; then $SCRIPT_DIR/iptables.sh enable log "🥰 started PID: $adg_pid iptables: enabled" "🥰 启动成功 PID: $adg_pid iptables 已启用" update_description "🥰 Started PID: $adg_pid iptables: enabled" "🥰 启动成功 PID: $adg_pid iptables 已启用" else log "🥰 started PID: $adg_pid iptables: disabled" "🥰 启动成功 PID: $adg_pid iptables 已禁用" update_description "🥰 Started PID: $adg_pid iptables: disabled" "🥰 启动成功 PID: $adg_pid iptables 已禁用" fi else log "😭 Error occurred, check logs for details" "😭 出现错误,请检查日志以获取详细信息" update_description "😭 Error occurred, check logs for details" "😭 出现错误,请检查日志以获取详细信息" $SCRIPT_DIR/debug.sh exit 1 fi } stop_adguardhome() { if [ -f "$PID_FILE" ]; then pid=$(cat "$PID_FILE") kill $pid || kill -9 $pid rm "$PID_FILE" log "AdGuardHome stopped (PID: $pid)" "AdGuardHome 已停止 (PID: $pid)" else pkill -f "AdGuardHome" || pkill -9 -f "AdGuardHome" log "AdGuardHome force stopped" "AdGuardHome 强制停止" fi update_description "❌ Stopped" "❌ 已停止" $SCRIPT_DIR/iptables.sh disable } toggle_adguardhome() { if [ -f "$PID_FILE" ] && ps | grep -w "$(cat $PID_FILE)" | grep -q "AdGuardHome"; then stop_adguardhome else start_adguardhome fi } case "$1" in start) start_adguardhome ;; stop) stop_adguardhome ;; toggle) toggle_adguardhome ;; *) echo "Usage: $0 {start|stop|toggle}" exit 1 ;; esac ================================================ FILE: src/service.sh ================================================ until [ $(getprop init.svc.bootanim) = "stopped" ]; do sleep 12 done /data/adb/agh/scripts/tool.sh start inotifyd /data/adb/agh/scripts/inotify.sh /data/adb/modules/AdGuardHome:d,n & ================================================ FILE: src/settings.conf ================================================ # 是否启用内置的 iptables 规则 # Whether to enable the built-in iptables rules enable_iptables=true # 阻断 ipv6 的 DNS 请求,仅在 enable_iptables=true 时生效 # Block DNS requests for ipv6, only effective when enable_iptables=true block_ipv6_dns=true # 重定向端口,请与 AdGuardHome 的设置保持一致 # Redirect port, please keep it consistent with AdGuardHome settings redir_port=5591 # 用户组和用户,用于绕过 AdGuardHome 本身 # User group and user, used to bypass AdGuardHome itself adg_user=root adg_group=net_raw # 绕过目的地址列表,用空格分隔 # list of destination addresses to bypass, separated by spaces ignore_dest_list="" # 绕过源地址列表,用空格分隔 # list of source addresses to bypass, separated by spaces ignore_src_list="" # 文件路径,请勿修改 # File paths, do not modify readonly AGH_DIR="/data/adb/agh" readonly BIN_DIR="$AGH_DIR/bin" readonly SCRIPT_DIR="$AGH_DIR/scripts" readonly PID_FILE="$AGH_DIR/bin/agh.pid" readonly MOD_PATH="/data/adb/modules/AdGuardHome" ================================================ FILE: src/uninstall.sh ================================================ [ -d "/data/adb/agh" ] && rm -rf "/data/adb/agh" ================================================ FILE: src/webroot/app.js ================================================ /** * AdGuardHome for Root - WebUI Application * * KernelSU API: ksu.exec(cmd) returns stdout string synchronously * KernelSU API: ksu.toast(msg) shows a toast */ // ==================== Module API Layer ==================== var ModuleAPI = { _api: null, init: function() { if (typeof ksu !== 'undefined' && typeof ksu.exec === 'function') { this._api = ksu; } else if (typeof ap !== 'undefined' && typeof ap.exec === 'function') { this._api = ap; } }, isAvailable: function() { return this._api !== null; }, /** * Execute shell command SYNCHRONOUSLY. * ksu.exec(cmd) returns stdout string directly. * Returns { errno, stdout } */ exec: function(command) { if (!this._api) { return { errno: -1, stdout: '' }; } try { var result = this._api.exec(command); return { errno: 0, stdout: (result || '').replace(/\r/g, '') }; } catch (e) { return { errno: -1, stdout: '' }; } }, toast: function(msg) { if (this._api && typeof this._api.toast === 'function') { try { this._api.toast(msg); } catch (e) {} } } }; ModuleAPI.init(); // ==================== Utility Functions ==================== function showToast(message, type, duration) { type = type || 'info'; duration = duration || 3000; var container = document.getElementById('toastContainer'); var toastEl = document.createElement('div'); toastEl.className = 'toast ' + type; toastEl.textContent = message; container.appendChild(toastEl); setTimeout(function() { toastEl.style.animation = 'toastOut 0.3s ease forwards'; setTimeout(function() { toastEl.remove(); }, 300); }, duration); } function showLoading(show) { document.getElementById('loadingOverlay').style.display = show ? 'flex' : 'none'; } // ==================== Paths ==================== var AGH_DIR = '/data/adb/agh'; var CONF_FILE = AGH_DIR + '/settings.conf'; var PID_FILE = AGH_DIR + '/bin/agh.pid'; var LOG_FILE = AGH_DIR + '/history.log'; var SCRIPT_DIR = AGH_DIR + '/scripts'; var BIN_DIR = AGH_DIR + '/bin'; var MODULE_PROP = '/data/adb/modules/AdGuardHome/module.prop'; // ==================== State ==================== var currentSettings = {}; var settingsChanged = false; var isRunning = false; var webPort = '3000'; var webUser = 'root'; var webPassword = 'root'; var statsFailCount = 0; var statsAuthVisible = false; // ==================== Tab / Page Switching ==================== var currentPage = 0; var pageCount = 2; function switchTab(index) { if (index < 0 || index >= pageCount) return; currentPage = index; var container = document.getElementById('pagesContainer'); container.classList.remove('no-transition'); container.style.transform = 'translateX(' + (-index * 50) + '%)'; // Update floating tab active state var tabs = document.querySelectorAll('.floating-tab-item'); for (var i = 0; i < tabs.length; i++) { if (i === index) { tabs[i].classList.add('active'); } else { tabs[i].classList.remove('active'); } } // Always show floating tab when switching pages var floatingTab = document.getElementById('floatingTab'); if (floatingTab) { floatingTab.classList.remove('tab-hidden'); } } // ==================== Touch Swipe Support ==================== (function() { var startX = 0; var startY = 0; var deltaX = 0; var swiping = false; var container = null; function getContainer() { if (!container) { container = document.getElementById('pagesContainer'); } return container; } function onTouchStart(e) { var tag = e.target.tagName.toLowerCase(); if (tag === 'input' || tag === 'textarea' || tag === 'select' || tag === 'button') return; startX = e.touches[0].clientX; startY = e.touches[0].clientY; deltaX = 0; swiping = false; } function onTouchMove(e) { if (!startX && !startY) return; var dx = e.touches[0].clientX - startX; var dy = e.touches[0].clientY - startY; if (!swiping) { if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 10) { swiping = true; getContainer().classList.add('no-transition'); } else { return; } } if (Math.abs(dx) > Math.abs(dy)) { e.preventDefault(); } deltaX = dx; var pageWidth = window.innerWidth; var baseOffset = -currentPage * pageWidth; var offset = baseOffset + deltaX; var minOffset = -(pageCount - 1) * pageWidth; if (offset > 0) offset = offset * 0.3; if (offset < minOffset) offset = minOffset + (offset - minOffset) * 0.3; getContainer().style.transform = 'translateX(' + offset + 'px)'; } function onTouchEnd(e) { if (!swiping) return; swiping = false; var threshold = window.innerWidth * 0.2; if (deltaX < -threshold && currentPage < pageCount - 1) { switchTab(currentPage + 1); } else if (deltaX > threshold && currentPage > 0) { switchTab(currentPage - 1); } else { switchTab(currentPage); } deltaX = 0; } document.addEventListener('DOMContentLoaded', function() { var c = getContainer(); if (c) { c.addEventListener('touchstart', onTouchStart, { passive: true }); c.addEventListener('touchmove', onTouchMove, { passive: false }); c.addEventListener('touchend', onTouchEnd, { passive: true }); } }); })(); // ==================== Status Check ==================== function checkStatus() { var badge = document.getElementById('statusBadge'); var statusText = document.getElementById('statusText'); var pidBadge = document.getElementById('pidBadge'); var running = false; var pid = '-'; var pidResult = ModuleAPI.exec('cat ' + PID_FILE + ' 2>/dev/null'); pid = pidResult.stdout.trim(); if (pid && /^\d+$/.test(pid)) { running = true; } else { pid = '-'; } isRunning = running; badge.className = 'status-badge ' + (running ? 'running' : 'stopped'); statusText.textContent = running ? 'Running' : 'Stopped'; pidBadge.textContent = 'PID: ' + pid; document.getElementById('btnStart').disabled = running; document.getElementById('btnStop').disabled = !running; document.getElementById('btnRestart').disabled = !running; } // ==================== Load Settings ==================== function getConf(key) { var r = ModuleAPI.exec('grep "^' + key + '=" ' + CONF_FILE + ' 2>/dev/null | cut -d= -f2'); return (r.stdout || '').replace(/\r/g, '').trim(); } function getConfQuoted(key) { return getConf(key).replace(/^"|"$/g, ''); } function loadSettings() { var settings = {}; settings.enable_iptables = getConf('enable_iptables'); settings.block_ipv6_dns = getConf('block_ipv6_dns'); settings.redir_port = getConf('redir_port') || '5591'; settings.adg_user = getConf('adg_user') || 'root'; settings.adg_group = getConf('adg_group') || 'net_raw'; settings.ignore_dest_list = getConfQuoted('ignore_dest_list'); settings.ignore_src_list = getConfQuoted('ignore_src_list'); currentSettings = settings; applySettingsToUI(settings); } function applySettingsToUI(settings) { document.getElementById('setEnableIptables').checked = (settings.enable_iptables === 'true'); document.getElementById('setBlockIpv6').checked = (settings.block_ipv6_dns === 'true'); document.getElementById('setRedirPort').value = settings.redir_port || '5591'; document.getElementById('setAdgUser').value = settings.adg_user || 'root'; document.getElementById('setAdgGroup').value = settings.adg_group || 'net_raw'; document.getElementById('setIgnoreDest').value = settings.ignore_dest_list || ''; document.getElementById('setIgnoreSrc').value = settings.ignore_src_list || ''; settingsChanged = false; document.getElementById('btnSaveSettings').disabled = true; } function onSettingChange() { settingsChanged = true; document.getElementById('btnSaveSettings').disabled = false; } // ==================== Save Settings ==================== function saveSettings() { showLoading(true); var enableIptables = document.getElementById('setEnableIptables').checked; var blockIpv6 = document.getElementById('setBlockIpv6').checked; var redirPort = document.getElementById('setRedirPort').value || '5591'; var adgUser = document.getElementById('setAdgUser').value || 'root'; var adgGroup = document.getElementById('setAdgGroup').value || 'net_raw'; var ignoreDest = document.getElementById('setIgnoreDest').value || ''; var ignoreSrc = document.getElementById('setIgnoreSrc').value || ''; var cmd = "sed -i 's#^enable_iptables=.*#enable_iptables=" + enableIptables + "#' " + CONF_FILE + " && sed -i 's#^block_ipv6_dns=.*#block_ipv6_dns=" + blockIpv6 + "#' " + CONF_FILE + " && sed -i 's#^redir_port=.*#redir_port=" + redirPort + "#' " + CONF_FILE + " && sed -i 's#^adg_user=.*#adg_user=" + adgUser + "#' " + CONF_FILE + " && sed -i 's#^adg_group=.*#adg_group=" + adgGroup + "#' " + CONF_FILE + " && sed -i 's#^ignore_dest_list=.*#ignore_dest_list=\"" + ignoreDest + "\"#' " + CONF_FILE + " && sed -i 's#^ignore_src_list=.*#ignore_src_list=\"" + ignoreSrc + "\"#' " + CONF_FILE; var result = ModuleAPI.exec(cmd); if (result.errno === 0) { settingsChanged = false; document.getElementById('btnSaveSettings').disabled = true; showToast('Settings saved successfully', 'success'); } else { showToast('Failed to save settings', 'error'); } showLoading(false); } // ==================== Log Viewer ==================== function loadLog() { if (!ModuleAPI.isAvailable()) return; var result = ModuleAPI.exec("awk '{a[NR]=$0}END{for(i=(NR>5?NR-4:1);i<=NR;i++)printf \"%s::NL::\",a[i]}' " + LOG_FILE + " 2>/dev/null"); var logViewer = document.getElementById('logViewer'); if (logViewer) { var raw = (result.stdout || '').trim(); var lines = raw.split('::NL::').filter(function(l) { return l !== ''; }); var content = lines.join('\n'); logViewer.textContent = content || 'No log entries'; logViewer.scrollTop = logViewer.scrollHeight; } } // ==================== Stats Help Modal ==================== function toggleStatsHelp() { var overlay = document.getElementById('statsHelpOverlay'); if (overlay) { overlay.classList.add('visible'); } } function closeStatsHelp() { var overlay = document.getElementById('statsHelpOverlay'); if (overlay) { overlay.classList.remove('visible'); } } // ==================== Stats View Switching ==================== function showStatsDataView() { statsAuthVisible = false; var dataView = document.getElementById('statsDataView'); var authView = document.getElementById('statsAuthView'); if (dataView) dataView.style.display = ''; if (authView) authView.style.display = 'none'; } function showStatsAuthView() { statsAuthVisible = true; var dataView = document.getElementById('statsDataView'); var authView = document.getElementById('statsAuthView'); if (dataView) dataView.style.display = 'none'; if (authView) authView.style.display = ''; } function submitCredentials() { var userEl = document.getElementById('authUser'); var passEl = document.getElementById('authPassword'); if (userEl) webUser = userEl.value || 'root'; if (passEl) webPassword = passEl.value || 'root'; statsFailCount = 0; showStatsDataView(); loadStats(); } // ==================== Query Log Statistics ==================== function loadStats() { if (!ModuleAPI.isAvailable()) return; if (!isRunning) return; if (webPort === '-') return; if (statsAuthVisible) return; var url = 'http://127.0.0.1:' + webPort + '/control/stats'; var auth = webUser + ':' + webPassword; var cmd = 'wget -qO- --user=' + webUser + ' --password=' + webPassword + ' ' + url + ' 2>/dev/null || curl -s -u ' + auth + ' ' + url + ' 2>/dev/null'; var result = ModuleAPI.exec(cmd); var raw = (result.stdout || '').trim(); var queriesEl = document.getElementById('statQueries'); var blockedEl = document.getElementById('statBlocked'); var timeEl = document.getElementById('statTime'); if (!raw || raw.charAt(0) !== '{') { statsFailCount++; if (queriesEl) queriesEl.textContent = '-'; if (blockedEl) blockedEl.textContent = '-'; if (timeEl) timeEl.textContent = '-'; if (statsFailCount >= 2) { showStatsAuthView(); } return; } try { var stats = JSON.parse(raw); if (queriesEl) queriesEl.textContent = (typeof stats.num_dns_queries === 'number') ? stats.num_dns_queries : '-'; if (blockedEl) blockedEl.textContent = (typeof stats.num_blocked_filtering === 'number') ? stats.num_blocked_filtering : '-'; if (timeEl) timeEl.textContent = (typeof stats.avg_processing_time === 'number') ? stats.avg_processing_time.toFixed(2) + 's' : '-'; statsFailCount = 0; } catch (e) { statsFailCount++; if (queriesEl) queriesEl.textContent = '-'; if (blockedEl) blockedEl.textContent = '-'; if (timeEl) timeEl.textContent = '-'; if (statsFailCount >= 2) { showStatsAuthView(); } } } // ==================== Control ==================== function controlAdGuard(action) { showLoading(true); var cmd; switch (action) { case 'start': cmd = SCRIPT_DIR + '/tool.sh start'; break; case 'stop': cmd = SCRIPT_DIR + '/tool.sh stop'; break; case 'restart': cmd = SCRIPT_DIR + '/tool.sh stop; sleep 1; ' + SCRIPT_DIR + '/tool.sh start'; break; default: showLoading(false); return; } var result = ModuleAPI.exec(cmd); if (result.errno === 0) { var label = action.charAt(0).toUpperCase() + action.slice(1); showToast(label + ' successful', 'success'); } else { showToast(action + ' failed', 'error'); } setTimeout(function() { checkStatus(); loadLog(); showLoading(false); }, 2000); } // ==================== Open AdGuardHome ==================== function openAdGuardHome() { var url = (webPort !== '-') ? ('http://127.0.0.1:' + webPort) : 'http://127.0.0.1:3000'; window.open(url, '_blank'); } // ==================== Debug Info ==================== function collectDebugInfo() { showLoading(true); ModuleAPI.exec(SCRIPT_DIR + '/debug.sh 2>/dev/null'); showToast('Debug info collected to ' + AGH_DIR + '/debug.log', 'success'); showLoading(false); } // ==================== Load Web Port ==================== function loadWebPort() { var result = ModuleAPI.exec("grep 'address:' " + BIN_DIR + "/AdGuardHome.yaml 2>/dev/null | head -1"); var line = result.stdout.trim(); var match = line.match(/address:\s*\S+:(\d+)/); if (match && match[1]) { webPort = match[1]; } else { webPort = '3000'; } } // ==================== Load Version ==================== function loadVersion() { var result = ModuleAPI.exec('grep "^version=" ' + MODULE_PROP + ' 2>/dev/null | cut -d= -f2'); var version = result.stdout.trim(); if (version) { document.getElementById('versionText').textContent = 'v' + version; } } // ==================== Scroll Hide Floating Tab ==================== function setupScrollHideTab() { var pages = document.querySelectorAll('.page'); var floatingTab = document.getElementById('floatingTab'); if (!floatingTab) return; for (var i = 0; i < pages.length; i++) { (function(page) { page.addEventListener('scroll', function() { var atTop = page.scrollTop <= 2; var atBottom = page.scrollTop + page.clientHeight >= page.scrollHeight - 2; if (atTop || atBottom) { floatingTab.classList.remove('tab-hidden'); } else { floatingTab.classList.add('tab-hidden'); } }); })(pages[i]); } } // ==================== Initialize ==================== function init() { if (!ModuleAPI.isAvailable()) { document.getElementById('noApiWarning').style.display = 'block'; document.getElementById('statusBadge').className = 'status-badge stopped'; document.getElementById('statusText').textContent = 'No API'; return; } loadSettings(); checkStatus(); loadWebPort(); loadVersion(); loadLog(); loadStats(); setupScrollHideTab(); switchTab(0); } // Auto-refresh every 5 seconds setInterval(function() { if (ModuleAPI.isAvailable()) { checkStatus(); loadLog(); loadStats(); } }, 5000); // Start document.addEventListener('DOMContentLoaded', init); ================================================ FILE: src/webroot/index.html ================================================ AdGuardHome for Root

AdGuardHome for Root

v20260315
Loading... PID: -
Query Log Statistics
-
DNS查询
-
规则拦截
-
处理耗时
Settings
Enable Iptables
Redirect DNS requests via iptables
Block IPv6 DNS
Block DNS requests over IPv6
Main
Settings
指标说明
DNS查询

AdGuard Home 核心处理的 DNS 查询总数。

规则拦截

被过滤规则拦截的 DNS 请求数量。

处理耗时

处理每个 DNS 请求的平均耗时(秒)。

数据通过 AdGuard Home OpenAPI 实时获取,统计周期由核心配置决定。
================================================ FILE: src/webroot/style.css ================================================ /* AdGuardHome for Root - WebUI Styles */ /* ===== Dark Theme (default) ===== */ :root { --primary: #68BC71; --primary-dark: #4CAF50; --primary-light: #A5D6A7; --bg: #0c0e14; --surface: #161923; --surface-2: #1e2231; --surface-3: #2a2f42; --text: #E8EAED; --text-secondary: #9AA0A6; --text-hint: #6B7280; --danger: #EF5350; --danger-dark: #C62828; --warning: #FFC107; --info: #42A5F5; --success: #66BB6A; --border: #252a3a; --radius: 14px; --radius-sm: 10px; --shadow: 0 2px 12px rgba(0,0,0,0.35); --transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); --log-bg: #0a0c12; --toggle-off: #3a3f50; } /* ===== Light Theme ===== */ @media (prefers-color-scheme: light) { :root { --bg: #f0f2f5; --surface: #ffffff; --surface-2: #f5f6f8; --surface-3: #e8eaed; --text: #1f1f1f; --text-secondary: #5f6368; --text-hint: #80868b; --border: #dfe1e5; --shadow: 0 2px 12px rgba(0,0,0,0.08); --log-bg: #f8f9fa; --toggle-off: #bdbdbd; } } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', sans-serif; background: var(--bg); color: var(--text); line-height: 1.6; height: 100vh; overflow: hidden; -webkit-font-smoothing: antialiased; } /* ===== App Wrapper ===== */ .app-wrapper { height: 100vh; display: flex; flex-direction: column; overflow: hidden; position: relative; } /* ===== Pages Container (horizontal sliding) ===== */ .pages-container { flex: 1; display: flex; width: 200%; overflow: hidden; transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1); will-change: transform; } .pages-container.no-transition { transition: none; } .page { width: 50%; height: 100%; overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch; touch-action: pan-y; padding-bottom: 88px; /* space for floating tab */ } .page::-webkit-scrollbar { width: 4px; } .page::-webkit-scrollbar-track { background: transparent; } .page::-webkit-scrollbar-thumb { background: var(--surface-3); border-radius: 4px; } .container { max-width: 600px; margin: 0 auto; padding: 16px; } /* ===== Header ===== */ .header { text-align: center; padding: 16px 0 12px; } .header-icon { width: 48px; height: 48px; background: linear-gradient(145deg, var(--primary), var(--primary-dark)); border-radius: 14px; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 8px; box-shadow: 0 4px 16px rgba(104, 188, 113, 0.25); } .header-icon svg { width: 28px; height: 28px; fill: white; } .header h1 { font-size: 20px; font-weight: 700; color: var(--text); margin-bottom: 2px; letter-spacing: -0.3px; } .header .version { font-size: 12px; color: var(--text-hint); } /* ===== Status Row (badge + PID inline) ===== */ .status-row { display: inline-flex; align-items: center; gap: 10px; margin-top: 6px; } /* ===== Status Badge ===== */ .status-badge { display: inline-flex; align-items: center; gap: 6px; padding: 4px 14px; border-radius: 20px; font-size: 13px; font-weight: 600; } .status-badge.running { background: rgba(102, 187, 106, 0.15); color: var(--success); } .status-badge.stopped { background: rgba(239, 83, 80, 0.15); color: var(--danger); } .status-badge.loading { background: rgba(66, 165, 245, 0.15); color: var(--info); } .status-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; } .status-badge.running .status-dot { background: var(--success); box-shadow: 0 0 8px var(--success); animation: pulse 2s infinite; } .status-badge.stopped .status-dot { background: var(--danger); } .status-badge.loading .status-dot { background: var(--info); animation: pulse 1s infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } } /* ===== PID Badge ===== */ .pid-badge { display: inline-flex; align-items: center; padding: 4px 12px; border-radius: 20px; font-size: 12px; font-weight: 600; background: var(--surface-2); color: var(--text-secondary); border: 1px solid var(--border); } /* ===== Card ===== */ .card { background: var(--surface); border-radius: var(--radius); padding: 20px; margin-bottom: 14px; border: 1px solid var(--border); box-shadow: var(--shadow); transition: box-shadow 0.25s ease; } .card.card-action { padding: 10px 20px; border-color: rgba(104, 188, 113, 0.15); } .card-title { font-size: 15px; font-weight: 600; color: var(--text); margin-bottom: 16px; display: flex; align-items: center; gap: 8px; } .card-title .icon { font-size: 18px; } .card-title-icon { width: 18px; height: 18px; fill: var(--primary); flex-shrink: 0; } /* ===== Statistics Card ===== */ .card-stats { padding: 16px 20px; } .stats-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; } .stat-item { text-align: center; padding: 12px 4px; background: var(--surface-2); border-radius: var(--radius-sm); border: 1px solid var(--border); } .stat-value { font-size: 24px; font-weight: 700; color: var(--primary); line-height: 1.2; margin-bottom: 4px; } .stat-label { font-size: 11px; color: var(--text-hint); font-weight: 500; } /* ===== Stats Auth Form ===== */ .stats-auth-form { padding: 4px 0; } .stats-auth-hint { font-size: 12px; color: var(--warning); margin-bottom: 10px; text-align: center; line-height: 1.5; } /* ===== Help Button ===== */ .btn-help { width: 16px; height: 16px; border-radius: 50%; border: 1px solid var(--text-hint); background: transparent; color: var(--text-hint); font-size: 10px; font-weight: 700; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; margin-left: auto; flex-shrink: 0; padding: 0; line-height: 1; transition: var(--transition); font-family: inherit; } .btn-help:hover { border-color: var(--primary); color: var(--primary); background: rgba(104, 188, 113, 0.08); } /* ===== Help Modal ===== */ .help-modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: none; align-items: center; justify-content: center; z-index: 500; backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); padding: 24px; } .help-modal-overlay.visible { display: flex; } .help-modal { background: var(--surface); border-radius: var(--radius); padding: 20px; max-width: 360px; width: 100%; border: 1px solid var(--border); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); animation: modalIn 0.2s ease; } @keyframes modalIn { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } } .help-modal-title { font-size: 16px; font-weight: 700; color: var(--text); margin-bottom: 14px; text-align: center; } .help-modal-item { padding: 8px 0; } .help-modal-item + .help-modal-item { border-top: 1px solid var(--border); } .help-modal-item strong { font-size: 13px; color: var(--primary); display: block; margin-bottom: 2px; } .help-modal-item p { font-size: 12px; color: var(--text-secondary); line-height: 1.5; margin: 0; } .help-modal-note { font-size: 11px; color: var(--text-hint); text-align: center; margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border); line-height: 1.5; } /* ===== Buttons ===== */ .control-buttons { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; } .btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; padding: 11px 16px; border: none; border-radius: var(--radius-sm); font-size: 13px; font-weight: 600; cursor: pointer; transition: var(--transition); outline: none; position: relative; overflow: hidden; font-family: inherit; letter-spacing: 0.2px; } .btn:active { transform: scale(0.97); } .btn:disabled { opacity: 0.45; cursor: not-allowed; transform: none; } .btn-primary { background: linear-gradient(145deg, var(--primary), var(--primary-dark)); color: white; } .btn-primary:hover:not(:disabled) { box-shadow: 0 4px 16px rgba(104, 188, 113, 0.35); } .btn-danger { background: linear-gradient(145deg, var(--danger), var(--danger-dark)); color: white; } .btn-danger:hover:not(:disabled) { box-shadow: 0 4px 16px rgba(239, 83, 80, 0.35); } .btn-secondary { background: var(--surface-2); color: var(--text); border: 1px solid var(--border); } .btn-secondary:hover:not(:disabled) { background: var(--surface-3); border-color: var(--text-hint); } .btn-full { width: 100%; padding: 13px; } .btn-link { background: linear-gradient(135deg, rgba(104, 188, 113, 0.12), rgba(104, 188, 113, 0.04)); color: var(--primary); border: 1px solid rgba(104, 188, 113, 0.2); font-weight: 600; } .btn-link:hover:not(:disabled) { background: linear-gradient(135deg, rgba(104, 188, 113, 0.22), rgba(104, 188, 113, 0.08)); border-color: rgba(104, 188, 113, 0.4); } /* ===== Settings ===== */ .settings-header { padding: 24px 0 8px; } .settings-header .card-title { margin-bottom: 0; } .setting-group { margin-bottom: 12px; } .setting-group:last-child { margin-bottom: 0; } .setting-row { display: flex; align-items: center; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid var(--border); } .setting-row:last-child { border-bottom: none; padding-bottom: 0; } .setting-row:first-child { padding-top: 0; } .setting-label { flex: 1; } .setting-label .title { font-size: 14px; font-weight: 500; color: var(--text); } .setting-label .desc { font-size: 12px; color: var(--text-hint); margin-top: 2px; } /* ===== Toggle Switch ===== */ .toggle { position: relative; width: 48px; height: 26px; flex-shrink: 0; margin-left: 12px; } .toggle input { opacity: 0; width: 0; height: 0; } .toggle-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background: var(--toggle-off); border-radius: 26px; transition: var(--transition); } .toggle-slider:before { content: ''; position: absolute; height: 20px; width: 20px; left: 3px; bottom: 3px; background: white; border-radius: 50%; transition: var(--transition); } .toggle input:checked + .toggle-slider { background: var(--primary); } .toggle input:checked + .toggle-slider:before { transform: translateX(22px); } .toggle input:disabled + .toggle-slider { opacity: 0.5; cursor: not-allowed; } /* ===== Input ===== */ .input-field { width: 100%; padding: 10px 14px; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text); font-size: 14px; font-family: inherit; transition: var(--transition); outline: none; } .input-field:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(104, 188, 113, 0.15); } .input-field:disabled { opacity: 0.5; } .input-group { margin-top: 8px; } .input-label { font-size: 12px; color: var(--text-hint); margin-bottom: 6px; display: block; } /* ===== Log Viewer ===== */ .log-viewer { background: var(--log-bg); border-radius: var(--radius-sm); padding: 10px 12px; font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Consolas', monospace; font-size: 10px; line-height: 1.7; max-height: 160px; min-height: 80px; overflow-y: auto; color: var(--text-hint); white-space: pre-wrap; word-break: break-all; border: 1px solid var(--border); border-top: 2px solid var(--surface-3); margin-top: 12px; } .log-viewer::-webkit-scrollbar { width: 3px; } .log-viewer::-webkit-scrollbar-track { background: transparent; } .log-viewer::-webkit-scrollbar-thumb { background: var(--surface-3); border-radius: 3px; } /* ===== Toast ===== */ .toast-container { position: fixed; bottom: 80px; left: 50%; transform: translateX(-50%); z-index: 1000; display: flex; flex-direction: column; gap: 8px; pointer-events: none; } .toast { padding: 12px 20px; border-radius: var(--radius-sm); font-size: 14px; font-weight: 500; color: white; box-shadow: 0 4px 16px rgba(0,0,0,0.4); animation: toastIn 0.3s ease; white-space: nowrap; pointer-events: auto; } .toast.success { background: var(--success); } .toast.error { background: var(--danger); } .toast.info { background: var(--info); } .toast.warning { background: #E65100; } @keyframes toastIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } @keyframes toastOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-20px); } } /* ===== Loading Overlay ===== */ .loading-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(128, 128, 128, 0.5); display: flex; align-items: center; justify-content: center; z-index: 999; backdrop-filter: blur(4px); } .spinner { width: 40px; height: 40px; border: 3px solid var(--surface-3); border-top-color: var(--primary); border-radius: 50%; animation: spin 0.8s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } /* ===== No API Warning ===== */ .no-api-warning { background: rgba(239, 83, 80, 0.1); border: 1px solid rgba(239, 83, 80, 0.3); border-radius: var(--radius); padding: 20px; text-align: center; margin-bottom: 12px; } .no-api-warning h3 { color: var(--danger); margin-bottom: 8px; font-size: 16px; } .no-api-warning p { color: var(--text-secondary); font-size: 13px; line-height: 1.6; } /* ===== Footer ===== */ .footer { text-align: center; padding: 16px 0 24px; color: var(--text-hint); font-size: 12px; } .footer a { color: var(--primary); text-decoration: none; } .footer a:hover { text-decoration: underline; } /* ===== Floating Tab Bar ===== */ .floating-tab { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%); display: flex; align-items: center; gap: 4px; padding: 5px 6px; background: var(--surface); border: 1px solid var(--border); border-radius: 28px; box-shadow: 0 4px 24px rgba(0,0,0,0.45); z-index: 100; -webkit-tap-highlight-color: transparent; backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease; } .floating-tab.tab-hidden { transform: translateX(-50%) translateY(80px); opacity: 0; pointer-events: none; } .floating-tab-item { display: flex; align-items: center; justify-content: center; gap: 6px; padding: 8px 22px; border-radius: 22px; cursor: pointer; transition: all 0.25s ease; color: var(--text-hint); user-select: none; font-size: 12px; font-weight: 600; } .floating-tab-item.active { background: linear-gradient(145deg, var(--primary), var(--primary-dark)); color: white; box-shadow: 0 2px 10px rgba(104, 188, 113, 0.35); } .tab-icon { width: 18px; height: 18px; fill: currentColor; } .tab-label { font-size: 12px; font-weight: 600; } /* ===== Responsive ===== */ @media (max-width: 400px) { .container { padding: 12px; } .card { padding: 16px; } .control-buttons { grid-template-columns: 1fr 1fr; } } ================================================ FILE: version.json ================================================ { "versionCode": 49, "version": "20260419", "zipUrl": "https://github.com/twoone-3/AdGuardHomeForRoot/releases/latest/download/AdGuardHomeForRoot_arm64.zip", "changelog": "https://raw.githubusercontent.com/twoone-3/AdGuardHomeForRoot/main/changelog.md" }