├── box ├── bin │ └── .bin ├── crontab.cfg ├── sing-box │ ├── config.json │ └── README.md ├── clash │ ├── config.yaml │ └── README.md ├── gid.list.cfg ├── package.list.cfg ├── ap.list.cfg ├── hysteria │ ├── README.md │ └── config.yaml ├── scripts │ ├── box.inotify │ ├── net.inotify │ ├── ctr.utils │ ├── start.sh │ ├── ctr.inotify │ ├── box.service │ └── box.iptables ├── xray │ ├── README.md │ └── config.json ├── v2fly │ ├── README.md │ └── config.json └── settings.ini ├── META-INF └── com │ └── google │ └── android │ ├── updater-script │ └── update-binary ├── docs ├── box.png ├── box.svg ├── index_zh.md ├── index_id.md └── index_en.md ├── webroot └── index.html ├── .github ├── FUNDING.yml ├── taamarinbot.py └── workflows │ ├── release.yml │ └── debug.yml ├── update.json ├── module.prop ├── box_service.sh ├── uninstall.sh ├── CHANGELOG.md ├── action.sh ├── sbfr ├── README.md ├── customize.sh └── LICENSE /box/bin/.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /META-INF/com/google/android/updater-script: -------------------------------------------------------------------------------- 1 | #MAGISK 2 | -------------------------------------------------------------------------------- /box/crontab.cfg: -------------------------------------------------------------------------------- 1 | # This is the system crontab in which scheduled tasks can be defined -------------------------------------------------------------------------------- /docs/box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taamarin/box_for_magisk/HEAD/docs/box.png -------------------------------------------------------------------------------- /webroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: ['taamarin'] 4 | custom: ['https://taamarin.github.io'] 5 | -------------------------------------------------------------------------------- /box/sing-box/config.json: -------------------------------------------------------------------------------- 1 | # Please enter or replace with your configuration here, 2 | # 请在此输入或替换为你的配置, 3 | # Silahkan masukkan atau ganti dengan konfigurasi kamu di sini, -------------------------------------------------------------------------------- /box/clash/config.yaml: -------------------------------------------------------------------------------- 1 | # Please enter or replace with your configuration here, 2 | # 请在此输入或替换为你的配置, 3 | # Silahkan masukkan atau ganti dengan konfigurasi kamu di sini, 4 | -------------------------------------------------------------------------------- /box/gid.list.cfg: -------------------------------------------------------------------------------- 1 | # GID ▼ 2 | # This GID list is used by the init script to 3 | # manage iptables whitelist and blacklist. 4 | # Each GID determines which app or group is 5 | # allowed or blocked. 6 | # Default examples: 7 | # 12345 8 | # 1000 -------------------------------------------------------------------------------- /update.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "v1.10.2", 3 | "versionCode": "20250905", 4 | "zipUrl": "https://github.com/taamarin/box_for_magisk/releases/download/v1.10.2/box_for_root-v1.10.2.zip", 5 | "changelog": "https://github.com/taamarin/box_for_magisk/raw/master/CHANGELOG.md" 6 | } 7 | -------------------------------------------------------------------------------- /module.prop: -------------------------------------------------------------------------------- 1 | id=box_for_root 2 | name=Box for Magisk/KernelSU/APatch 3 | version=v1.10.2 4 | versionCode=20250905 5 | author=taamarin.t.me 6 | description=use sing-box, clash, v2ray, hysteria and xray for tunnel proxy on android device 7 | updateJson=https://github.com/taamarin/box_for_magisk/raw/master/update.json -------------------------------------------------------------------------------- /box/package.list.cfg: -------------------------------------------------------------------------------- 1 | # black/white list mode. 2 | mode:blacklist 3 | # +----------------+------+ 4 | # | User | ID | 5 | # +----------------+------+ 6 | # | Owner | 0 | 7 | # | Second Space | 10 | 8 | # | App Clone | 999 | 9 | # +----------------+------+ 10 | 11 | # package_name ▼ 12 | # com.topjohnwu.magisk 13 | # 0:com.termux -------------------------------------------------------------------------------- /box_service.sh: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | 3 | ( 4 | until [ "$(getprop init.svc.bootanim)" = "stopped" ]; do 5 | sleep 10 6 | done 7 | 8 | if [ -f "/data/adb/box/scripts/start.sh" ]; then 9 | chmod -R 755 /data/adb/box/scripts/ 10 | /data/adb/box/scripts/start.sh >/dev/null 2>&1 11 | else 12 | echo "File /data/adb/box/scripts/start.sh not found" > "/data/adb/box/run/box_service.log" 13 | fi 14 | ) & -------------------------------------------------------------------------------- /box/ap.list.cfg: -------------------------------------------------------------------------------- 1 | # Allow access for network interfaces with the following prefixes: ap+, wlan+, rndis+, swlan+, ncm+, and eth+ 2 | # allow 3 | allow ap+ 4 | allow wlan+ 5 | allow rndis+ 6 | allow swlan+ 7 | allow ncm+ 8 | allow eth+ 9 | # -----------------🌼🌼----------------------- # 10 | # Ignore specific network interfaces that may conflict with the allowed list 11 | # ignore 12 | # ignore swlan+ 13 | # ignore wlan+ -------------------------------------------------------------------------------- /uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | 3 | box_data_dir="/data/adb/box" 4 | rm_data() { 5 | if [ ! -d "${box_data_dir}" ]; then 6 | exit 1 7 | else 8 | rm -rf "${box_data_dir}" 9 | fi 10 | 11 | if [ -f "/data/adb/ksu/service.d/box_service.sh" ]; then 12 | rm -rf "/data/adb/ksu/service.d/box_service.sh" 13 | fi 14 | 15 | if [ -f "/data/adb/service.d/box_service.sh" ]; then 16 | rm -rf "/data/adb/service.d/box_service.sh" 17 | fi 18 | 19 | } 20 | 21 | rm_data -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | #### Changelog v1.10.2 - 05-09-25 2 | - fix(scripts): use `/system/bin/sh` and add `curl` timeout options in box.tool 3 | - fix: escape special characters in restore_ini sed replacement 4 | - box.tool(subs): extend protocol detection & clarify error log 5 | - feat: support Base64 subscription(clash/momo) file in box.tool 6 | - refactor(settings): move GID list to separate gid.list.cfg 7 | - Add restore and apply settings.ini functionality 8 | - box: switch sing-box to single config file 9 | 10 | #### Changelog v1.10.1 - 23-08-25 11 | - fix: Improve SSID retrieval accuracy during network switching (network control) -------------------------------------------------------------------------------- /box/hysteria/README.md: -------------------------------------------------------------------------------- 1 | ## 🌐 Hysteria v2 Documentation 2 | 3 | 🔹 **Hysteria v2 (UDP-based VPN / Proxy Protocol)** 4 | 📚 Full Client Config: [v2.hysteria.network/docs/advanced/Full-Client-Config](https://v2.hysteria.network/docs/advanced/Full-Client-Config/) 5 | 6 | ## ⚙️ Sample Hysteria2 Client Configuration 7 | 8 | ```yaml 9 | server: your-server.com:443 10 | auth: your-password-or-token 11 | alpn: 12 | - h3 13 | protocol: udp 14 | obfs: 15 | type: salamander 16 | password: obfs-password 17 | tls: 18 | sni: your-server.com 19 | insecure: true 20 | bandwidth: 21 | up: 50 Mbps 22 | down: 100 Mbps 23 | fastOpen: true 24 | retry: 3 -------------------------------------------------------------------------------- /box/hysteria/config.yaml: -------------------------------------------------------------------------------- 1 | server: free.jeelsboobz.art:16872 2 | auth: "6ebd7494-93ff-4b2f-991c-1aeba9a1e44b" 3 | 4 | tls: 5 | sni: bing.com 6 | insecure: true 7 | 8 | obfs: 9 | type: salamander 10 | salamander: 11 | password: "n0X9yN4T0gWIybkYYEyYdsOub" 12 | 13 | bandwidth: 14 | up: 100 mbps 15 | down: 100 mbps 16 | 17 | lazy: true 18 | 19 | socks5: 20 | listen: 127.0.0.1:1080 21 | # username: user 22 | # password: pass 23 | # disableUDP: false 24 | 25 | http: 26 | listen: 127.0.0.1:7080 27 | # username: king 28 | # password: kong 29 | # realm: martian 30 | 31 | tcpTProxy: 32 | listen: :9898 33 | 34 | udpTProxy: 35 | listen: :9898 36 | timeout: 20s 37 | 38 | tcpRedirect: 39 | listen: :9797 -------------------------------------------------------------------------------- /META-INF/com/google/android/update-binary: -------------------------------------------------------------------------------- 1 | #!/sbin/sh 2 | 3 | ################# 4 | # Initialization 5 | ################# 6 | 7 | umask 022 8 | 9 | # echo before loading util_functions 10 | ui_print() { echo "$1"; } 11 | 12 | require_new_magisk() { 13 | ui_print "*******************************" 14 | ui_print " Please install Magisk v20.4+! " 15 | ui_print "*******************************" 16 | exit 1 17 | } 18 | 19 | ######################### 20 | # Load util_functions.sh 21 | ######################### 22 | 23 | OUTFD=$2 24 | ZIPFILE=$3 25 | 26 | mount /data 2>/dev/null 27 | 28 | [ -f /data/adb/magisk/util_functions.sh ] && { 29 | . /data/adb/magisk/util_functions.sh 30 | [ $MAGISK_VER_CODE -lt 20400 ] && require_new_magisk 31 | install_module 32 | exit 0 33 | } 34 | -------------------------------------------------------------------------------- /action.sh: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | 3 | # Definisi variabel 4 | box_dir="/data/adb/box" 5 | box_run="${box_dir}/run" 6 | box_pid="${box_run}/box.pid" 7 | 8 | run_as_su() { 9 | su -c "$1" 10 | } 11 | 12 | stop_service() { 13 | echo "Service is shutting down" 14 | run_as_su "${box_dir}/scripts/box.iptables disable" 15 | run_as_su "${box_dir}/scripts/box.service stop" 16 | } 17 | 18 | start_service() { 19 | echo "Service is starting, please wait for a moment" 20 | run_as_su "${box_dir}/scripts/box.service start" 21 | run_as_su "${box_dir}/scripts/box.iptables enable" 22 | } 23 | 24 | if [ -f "${box_pid}" ]; then 25 | PID=$(cat "${box_pid}") 26 | if [ -e "/proc/${PID}" ]; then 27 | stop_service 28 | else 29 | start_service 30 | fi 31 | else 32 | start_service 33 | fi -------------------------------------------------------------------------------- /box/clash/README.md: -------------------------------------------------------------------------------- 1 | # 📄 Example Configuration & Documentation 2 | 3 | A quick reference guide for setting up **Clash Premium** or **Mihomo (Clash Meta)** configurations properly. 4 | 5 | ## 📘 Official Documentation 6 | 7 | 🔹 **Mihomo (Clash)** 8 | 📚 [wiki.metacubex.one](https://wiki.metacubex.one/) 9 | 10 | ## 🧪 Sample Configuration (YAML) 11 | 12 | ```yaml 13 | mixed-port: 7890 14 | allow-lan: true 15 | mode: rule 16 | log-level: info 17 | 18 | proxies: 19 | - name: "Example Proxy" 20 | type: vmess 21 | server: server.example.com 22 | port: 443 23 | uuid: abcdefgh-1234-5678-90ab-cdef12345678 24 | alterId: 0 25 | cipher: auto 26 | tls: true 27 | 28 | proxy-groups: 29 | - name: "PROXY" 30 | type: select 31 | proxies: 32 | - "Example Proxy" 33 | - DIRECT 34 | 35 | rules: 36 | - DOMAIN-SUFFIX,example.com,PROXY 37 | - MATCH,DIRECT -------------------------------------------------------------------------------- /box/sing-box/README.md: -------------------------------------------------------------------------------- 1 | ## 🧱 Sing-box Documentation 2 | 3 | 🔹 **Sing-box (Universal Proxy Core by SagerNet)** 4 | 📚 Official Docs: [sing-box.sagernet.org/configuration](http://sing-box.sagernet.org/configuration) 5 | 6 | ## ⚙️ Sample Sing-box Configuration (VMess over WS + TLS) 7 | 8 | ```json 9 | { 10 | "log": { 11 | "level": "info" 12 | }, 13 | "inbounds": [ 14 | { 15 | "type": "mixed", 16 | "listen": "::", 17 | "listen_port": 7890 18 | } 19 | ], 20 | "outbounds": [ 21 | { 22 | "type": "vmess", 23 | "tag": "vmess-ws", 24 | "server": "example.com", 25 | "server_port": 443, 26 | "uuid": "abcdefgh-1234-5678-90ab-cdef12345678", 27 | "security": "auto", 28 | "transport": { 29 | "type": "ws", 30 | "path": "/websocket", 31 | "headers": { 32 | "Host": "example.com" 33 | } 34 | }, 35 | "tls": { 36 | "enabled": true, 37 | "server_name": "example.com", 38 | "insecure": true 39 | } 40 | } 41 | ] 42 | } -------------------------------------------------------------------------------- /box/scripts/box.inotify: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | # Validate settings.ini 3 | if ! /system/bin/sh -n /data/adb/box/settings.ini 2>"/data/adb/box/run/settings_err.log"; then 4 | echo "Err: settings.ini contains a syntax error" | tee -a "/data/adb/box/run/settings_err.log" 5 | exit 1 6 | fi 7 | 8 | scripts_dir="${0%/*}" 9 | service_path="${scripts_dir}/box.service" 10 | iptables_path="${scripts_dir}/box.iptables" 11 | data_box="/data/adb/box" 12 | run_path="/data/adb/box/run" 13 | file_settings="/data/adb/box/settings.ini" 14 | now=$(date +"%I:%M %p") 15 | 16 | events="$1" 17 | monitor_dir="$2" 18 | monitor_file="$3" 19 | 20 | service_control() { 21 | if [ "${monitor_file}" = "disable" ]; then 22 | if [ "${events}" = "d" ]; then 23 | "${service_path}" start > "${run_path}/inotify.log" 2>&1 && 24 | "${iptables_path}" enable >> "${run_path}/inotify.log" 2>&1 25 | elif [ "${events}" = "n" ]; then 26 | "${iptables_path}" disable >> "${run_path}/inotify.log" 2>&1 && 27 | "${service_path}" stop >> "${run_path}/inotify.log" 2>&1 28 | fi 29 | fi 30 | } 31 | 32 | mkdir -p "${run_path}" 33 | if [ -f "${file_settings}" ] && [ -r "${file_settings}" ] && [ -s "${file_settings}" ]; then 34 | service_control 35 | else 36 | echo "${now} [error] file /data/adb/box/settings.ini file not found" > "${run_path}/inotify_report.log" 37 | exit 1 38 | fi -------------------------------------------------------------------------------- /box/xray/README.md: -------------------------------------------------------------------------------- 1 | ## ✴️ Xray (XTLS) Documentation 2 | 3 | 🔹 **Xray Core (XTLS, Reality, and enhancements)** 4 | 📚 Official Docs: [xtls.github.io](https://xtls.github.io/) 5 | 6 | ## ⚙️ Sample Xray Configuration (VLESS + XTLS / Reality) 7 | 8 | ```json 9 | { 10 | "log": { 11 | "loglevel": "info" 12 | }, 13 | "inbounds": [ 14 | { 15 | "port": 1080, 16 | "listen": "127.0.0.1", 17 | "protocol": "socks", 18 | "settings": { 19 | "udp": true 20 | } 21 | } 22 | ], 23 | "outbounds": [ 24 | { 25 | "protocol": "vless", 26 | "settings": { 27 | "vnext": [ 28 | { 29 | "address": "your-server.com", 30 | "port": 443, 31 | "users": [ 32 | { 33 | "id": "abcdefgh-1234-5678-90ab-cdef12345678", 34 | "encryption": "none", 35 | "flow": "xtls-rprx-vision" 36 | } 37 | ] 38 | } 39 | ] 40 | }, 41 | "streamSettings": { 42 | "network": "tcp", 43 | "security": "reality", 44 | "realitySettings": { 45 | "show": false, 46 | "serverName": "target-sni.com", 47 | "publicKey": "Base64ServerPubKeyHere", 48 | "shortId": "0123456789abcdef", 49 | "fingerprint": "chrome" 50 | } 51 | } 52 | } 53 | ] 54 | } -------------------------------------------------------------------------------- /box/v2fly/README.md: -------------------------------------------------------------------------------- 1 | ## ⚡ V2Ray / v2fly Documentation 2 | 3 | 🔹 **V2Ray / v2fly** 4 | 📚 Official Docs: [v2fly.org/en_US](https://www.v2fly.org/en_US/) 5 | 6 | ## ⚙️ Sample V2Ray Configuration (VMess over WS + TLS) 7 | 8 | ```json 9 | { 10 | "log": { 11 | "loglevel": "warning" 12 | }, 13 | "inbounds": [ 14 | { 15 | "port": 1080, 16 | "listen": "127.0.0.1", 17 | "protocol": "socks", 18 | "settings": { 19 | "auth": "noauth", 20 | "udp": true 21 | } 22 | } 23 | ], 24 | "outbounds": [ 25 | { 26 | "protocol": "vmess", 27 | "settings": { 28 | "vnext": [ 29 | { 30 | "address": "example.com", 31 | "port": 443, 32 | "users": [ 33 | { 34 | "id": "abcdefgh-1234-5678-90ab-cdef12345678", 35 | "alterId": 0, 36 | "security": "auto" 37 | } 38 | ] 39 | } 40 | ] 41 | }, 42 | "streamSettings": { 43 | "network": "ws", 44 | "security": "tls", 45 | "tlsSettings": { 46 | "serverName": "example.com", 47 | "allowInsecure": true 48 | }, 49 | "wsSettings": { 50 | "path": "/websocket", 51 | "headers": { 52 | "Host": "example.com" 53 | } 54 | } 55 | } 56 | } 57 | ] 58 | } -------------------------------------------------------------------------------- /box/scripts/net.inotify: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | 3 | events=$1 4 | # monitor_dir=$2 5 | # monitor_file=$3 6 | 7 | [ "$events" = "w" ] && [ -f "/data/adb/box/run/box.pid" ] || exit 0 8 | 9 | export PATH="/data/adb/magisk:/data/adb/ksu/bin:/data/adb/ap/bin:$PATH:/system/bin" 10 | 11 | # ex: 7.1.1 12 | buildVersion=$(getprop ro.build.version.release) 13 | minBuildVersion="11" 14 | IPV="iptables" # Default 15 | IP6V="ip6tables" # Default 16 | # ex: 7.1.1 -> 7 17 | buildVersionMajor=${buildVersion%%.*} 18 | if [ "$buildVersionMajor" -ge "$minBuildVersion" ]; then 19 | IPV="iptables -w 100" 20 | IP6V="ip6tables -w 100" 21 | fi 22 | 23 | iptables="${IPV}" 24 | ip6tables="${IP6V}" 25 | logs="/data/adb/box/run" 26 | 27 | rules_add() { 28 | date > "${logs}/net.log" 29 | iptables -t mangle -F LOCAL_IP_V4 30 | ip -4 a | busybox awk '/inet/ {print $2}' | grep -vE "^127.0.0.1" | while read -r local_ipv4 ; do 31 | ${iptables} -t mangle -A LOCAL_IP_V4 -d $local_ipv4 -j ACCEPT 32 | rv1=$? 33 | ${iptables} -t nat -A LOCAL_IP_V4 -d $local_ipv4 -j ACCEPT 34 | rv2=$? 35 | ( [ $rv1 = "0" ] || [ $rv2 = "0" ] ) && echo "[Info]: local ip is $local_ipv4, anti-loopback rule has been inserted" >> ${logs}/net.log 2>&1 36 | done 37 | 38 | ip6tables -t mangle -F LOCAL_IP_V6 39 | ip -6 a | busybox awk '/inet6/ {print $2}' | grep -vE "^fe80|^::1|^fd00" | while read -r local_ipv6 ; do 40 | ${ip6tables} -t mangle -A LOCAL_IP_V6 -d $local_ipv6 -j ACCEPT 41 | [ $? = "0" ] && echo "[Info]: local ip is $local_ipv6, anti-loopback rule has been inserted" >> ${logs}/net.log 2>&1 42 | done 43 | } 44 | 45 | rules_add 46 | -------------------------------------------------------------------------------- /box/scripts/ctr.utils: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | 3 | get_current_ssid() { 4 | SSID=$(cmd wifi status 2>/dev/null | sed -n 's/.*SSID: "\([^"]*\)".*/\1/p' | head -n1) 5 | # SSID=$(dumpsys wifi | grep 'mWifiInfo' | head -n 1 | busybox awk -F'SSID: |, BSSID' '{print $2}') 6 | 7 | if [ -z "$SSID" ] || [ "$SSID" = "" ]; then 8 | # if command -v iwconfig >/dev/null 2>&1; then 9 | SSID=$(iwconfig wlan0 2>/dev/null | grep 'ESSID' | busybox awk -F ':' '{print $2}' | tr -d '"') 10 | if [ -z "$SSID" ] || [ "$SSID" = "off/any" ]; then 11 | echo "unknown" 12 | else 13 | echo "$SSID" 14 | fi 15 | # else 16 | # log_msg "Warning: 'iwconfig' not found, unable to retrieve SSID." 17 | # log_msg "Warning: The program 'iwconfig' is not installed. You can install it in Termux by running:" 18 | # log_msg "Warning: pkg install root-repo && pkg install wireless-tools" 19 | # echo "unknown" 20 | # fi 21 | else 22 | echo "$SSID" 23 | fi 24 | } 25 | 26 | is_wifi_connected() { 27 | wifi_enabled=$(dumpsys wifi | grep 'Wi-Fi is enabled') 28 | wifi_ip=$(ip addr show wlan0 | grep 'inet ' | busybox awk '{print $2}' | cut -d/ -f1) 29 | 30 | if [ -n "$wifi_enabled" ] && [ -n "$wifi_ip" ]; then 31 | echo "wifi" 32 | else 33 | echo "not_wifi" 34 | fi 35 | } 36 | 37 | is_allowed_wifi() { 38 | ssid_list="$(IFS=,; echo "${wifi_ssids_list[*]}")" 39 | 40 | local ssid=$(echo "$1" | xargs) 41 | local list="$ssid_list" 42 | 43 | IFS=',' 44 | for allowed in $list; do 45 | allowed=$(echo "$allowed" | xargs) 46 | if [ "$ssid" = "$allowed" ]; then 47 | return 0 48 | fi 49 | done 50 | return 1 51 | } -------------------------------------------------------------------------------- /docs/box.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/taamarinbot.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import os 3 | import sys 4 | from telethon import TelegramClient 5 | from telethon.tl.functions.help import GetConfigRequest 6 | 7 | API_ID = os.environ.get("API_ID") 8 | API_HASH = os.environ.get("API_HASH") 9 | 10 | BOT_TOKEN = os.environ.get("BOT_TOKEN") 11 | CHAT_ID = int(os.environ.get("CHAT_ID")) 12 | MESSAGE_THREAD_ID = int(os.environ.get("MESSAGE_THREAD_ID")) 13 | VERSION = os.environ.get("VERSION") 14 | COMMIT = os.environ.get("COMMIT") 15 | MSG_TEMPLATE = """ 16 | {version} 17 | 18 | {commit} 19 | 20 | [Github](https://github.com/taamarin/box_for_magisk) 21 | [Releases](https://github.com/taamarin/box_for_magisk/releases) 22 | 23 | #module #ksu #apatch #magisk #bfr #debug 24 | """.strip() 25 | 26 | def get_caption(): 27 | msg = MSG_TEMPLATE.format( 28 | version=VERSION, 29 | commit=COMMIT 30 | ) 31 | if len(msg) > 1024: 32 | return COMMIT 33 | return msg 34 | 35 | def check_environ(): 36 | if BOT_TOKEN is None: 37 | print("[-] Invalid BOT_TOKEN") 38 | exit(1) 39 | if CHAT_ID is None: 40 | print("[-] Invalid CHAT_ID") 41 | exit(1) 42 | if VERSION is None: 43 | print("[-] Invalid VERSION") 44 | exit(1) 45 | if COMMIT is None: 46 | print("[-] Invalid COMMIT") 47 | exit(1) 48 | 49 | async def main(): 50 | print("[+] Uploading to telegram") 51 | check_environ() 52 | files = sys.argv[1:] 53 | print("[+] Files:", files) 54 | if len(files) <= 0: 55 | print("[-] No files to upload") 56 | exit(1) 57 | print("[+] Logging in Telegram with bot") 58 | script_dir = os.path.dirname(os.path.abspath(sys.argv[0])) 59 | session_dir = os.path.join(script_dir, "bot.session") 60 | async with await TelegramClient(session=session_dir, api_id=API_ID, api_hash=API_HASH).start(bot_token=BOT_TOKEN) as bot: 61 | caption = [""] * len(files) 62 | caption[-1] = get_caption() 63 | print("[+] Caption: ") 64 | print("---") 65 | print(caption) 66 | print("---") 67 | print("[+] Sending") 68 | await bot.send_file(entity=CHAT_ID, file=files, caption=caption, reply_to=MESSAGE_THREAD_ID, parse_mode="markdown") 69 | print("[+] Done!") 70 | 71 | if __name__ == "__main__": 72 | try: 73 | asyncio.run(main()) 74 | except Exception as e: 75 | print(f"[-] An error occurred: {e}") 76 | 77 | -------------------------------------------------------------------------------- /sbfr: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | 3 | # Colors 4 | RED='\033[1;31m' 5 | GREEN='\033[1;32m' 6 | YELLOW='\033[1;33m' 7 | CYAN='\033[1;36m' 8 | RESET='\033[0m' 9 | 10 | # Check if the device has root access 11 | if ! su -c 'echo root' &>/dev/null; then 12 | echo -e "${RED}Error: Device does not have root access.${RESET}" 13 | exit 1 14 | fi 15 | 16 | # Help function 17 | help() { 18 | echo -e "${CYAN}Usage: $0 {start|stop|s |i |u|x|r|t }${RESET}\n" 19 | echo -e " ${YELLOW}start${RESET} : Start Box (service and iptables)" 20 | echo -e " ${YELLOW}stop${RESET} : Stop Box (iptables and service)" 21 | echo -e " ${YELLOW}s ${RESET} : Run command to box.service with extra arguments" 22 | echo -e " ${YELLOW}i ${RESET} : Run command to box.iptables with extra arguments" 23 | echo -e " ${YELLOW}t ${RESET} : Run tools from box.tool with extra arguments" 24 | echo -e " ${YELLOW}u${RESET} : API to upgrade core[clash] (POST to /upgrade)" 25 | echo -e " ${YELLOW}x${RESET} : API to upgrade Dashboard UI [clash/sing] (POST to /upgrade/ui)" 26 | echo -e " ${YELLOW}r${RESET} : API to restart Box[clash] (POST to /restart)" 27 | echo -e " ${YELLOW}help${RESET} : Show this help message" 28 | } 29 | 30 | # Function to POST to local Box UI endpoint 31 | post_ui() { 32 | local endpoint="$1" 33 | curl -s -X POST "http://127.0.0.1:9090$endpoint" \ 34 | && echo -e "${GREEN}Successfully POST to $endpoint${RESET}" \ 35 | || echo -e "${RED}Failed to POST to $endpoint${RESET}" 36 | } 37 | 38 | # Argument handler 39 | case "$1" in 40 | start) 41 | echo -e "${YELLOW}Starting Box...${RESET}" 42 | su -c '/data/adb/box/scripts/box.service start' 43 | su -c '/data/adb/box/scripts/box.iptables enable' 44 | ;; 45 | stop) 46 | echo -e "${YELLOW}Stopping Box...${RESET}" 47 | su -c '/data/adb/box/scripts/box.iptables disable' 48 | su -c '/data/adb/box/scripts/box.service stop' 49 | ;; 50 | s) 51 | su -c "/data/adb/box/scripts/box.service ${2}" 52 | ;; 53 | i) 54 | su -c "/data/adb/box/scripts/box.iptables ${2}" 55 | ;; 56 | u) 57 | post_ui "/upgrade" 58 | ;; 59 | x) 60 | post_ui "/upgrade/ui" 61 | ;; 62 | r) 63 | post_ui "/restart" 64 | ;; 65 | t) 66 | su -c "/data/adb/box/scripts/box.tool $2" 67 | ;; 68 | help|-h|--help) 69 | help 70 | ;; 71 | *) 72 | echo -e "${RED}Unknown argument: $1${RESET}" 73 | help 74 | exit 1 75 | ;; 76 | esac -------------------------------------------------------------------------------- /box/scripts/start.sh: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | # Validate settings.ini 3 | if ! /system/bin/sh -n /data/adb/box/settings.ini 2>"/data/adb/box/run/settings_err.log"; then 4 | echo "Err: settings.ini contains a syntax error" | tee -a "/data/adb/box/run/settings_err.log" 5 | exit 1 6 | fi 7 | 8 | scripts_dir="${0%/*}" 9 | file_settings="/data/adb/box/settings.ini" 10 | moddir="/data/adb/modules/box_for_root" 11 | 12 | # busybox Magisk/KSU/Apatch 13 | busybox="/data/adb/magisk/busybox" 14 | [ -f "/data/adb/ksu/bin/busybox" ] && busybox="/data/adb/ksu/bin/busybox" 15 | [ -f "/data/adb/ap/bin/busybox" ] && busybox="/data/adb/ap/bin/busybox" 16 | 17 | wait_for_data_ready() { 18 | while [ ! -f "/data/system/packages.xml" ] ; do 19 | sleep 1 20 | done 21 | } 22 | 23 | refresh_box() { 24 | if [ -f "/data/adb/box/run/box.pid" ]; then 25 | "${scripts_dir}/box.service" stop >> "/dev/null" 2>&1 26 | "${scripts_dir}/box.iptables" disable >> "/dev/null" 2>&1 27 | fi 28 | } 29 | 30 | start_service() { 31 | if [ ! -f "${moddir}/disable" ]; then 32 | "${scripts_dir}/box.service" start >> "/dev/null" 2>&1 33 | fi 34 | } 35 | 36 | enable_iptables() { 37 | PIDS=("clash" "xray" "sing-box" "v2fly") 38 | PID="" 39 | i=0 40 | while [ -z "$PID" ] && [ "$i" -lt "${#PIDS[@]}" ]; do 41 | PID=$($busybox pidof "${PIDS[$i]}") 42 | i=$((i+1)) 43 | done 44 | 45 | if [ -n "$PID" ]; then 46 | "${scripts_dir}/box.iptables" enable >> "/dev/null" 2>&1 47 | fi 48 | } 49 | 50 | net_inotifyd() { 51 | net_dir="/data/misc/net" 52 | ctr_dir="/data/misc/net/rt_tables" 53 | 54 | # Start inotifyd to watch for network-related changes. 55 | # - The /proc filesystem cannot be monitored with inotify. 56 | # - Polling in a loop is inefficient, so inotify is used instead. 57 | # - Here we monitor /data/misc/net and /data/misc/net/rt_tables 58 | # because they reflect changes in routing tables and interfaces. 59 | 60 | # Wait until at least one of the target files/directories exists 61 | while [ ! -f "$ctr_dir" ] && [ ! -f "$net_dir" ]; do 62 | sleep 3 63 | done 64 | 65 | # Launch inotifyd handlers in the background 66 | inotifyd "${scripts_dir}/ctr.inotify" "$ctr_dir" >/dev/null 2>&1 & 67 | inotifyd "${scripts_dir}/net.inotify" "$net_dir" >/dev/null 2>&1 & 68 | } 69 | 70 | start_inotifyd() { 71 | PIDs=($($busybox pidof inotifyd)) 72 | for PID in "${PIDs[@]}"; do 73 | if grep -q -e "box.inotify" -e "net.inotify" "/proc/$PID/cmdline"; then 74 | kill -9 "$PID" 75 | fi 76 | # if grep -q "box.inotify" "/proc/$PID/cmdline"; then 77 | # kill -9 "$PID" 78 | # fi 79 | done 80 | inotifyd "${scripts_dir}/box.inotify" "${moddir}" > "/dev/null" 2>&1 & 81 | net_inotifyd 82 | } 83 | 84 | mkdir -p /data/adb/box/run/ 85 | if [ -f "/data/adb/box/manual" ]; then 86 | if [ -f "/data/adb/box/run/box.pid" ]; then 87 | rm -rf /data/adb/box/run/box.pid 88 | fi 89 | net_inotifyd 90 | exit 1 91 | fi 92 | 93 | if [ -f "$file_settings" ] && [ -r "$file_settings" ] && [ -s "$file_settings" ]; then 94 | wait_for_data_ready 95 | refresh_box 96 | start_service 97 | enable_iptables 98 | fi 99 | 100 | start_inotifyd 101 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | tag: 7 | description: 'Release Tag' 8 | required: true 9 | branch: 10 | description: 'Push Changes Branch' 11 | required: true 12 | changelog: 13 | description: 'Changelog Content' 14 | required: true 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | # 1. Checkout repository 22 | - uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | 26 | # 2. Generate version date 27 | - name: Get Version 28 | id: get_version 29 | run: echo "date=$(date +%Y%m%d)" >> "$GITHUB_OUTPUT" 30 | 31 | # 3. Update update.json, module.prop, and CHANGELOG.md 32 | - name: Update files 33 | run: | 34 | VERSION="${{ github.event.inputs.tag }}" 35 | DATE_NUM="${{ steps.get_version.outputs.date }}" 36 | DATE_HUMAN=$(date +%d-%m-%y) 37 | CHANGELOG="${{ github.event.inputs.changelog }}" 38 | 39 | # update.json 40 | cat > update.json < CHANGELOG.md 56 | echo "" >> CHANGELOG.md 57 | fi 58 | { 59 | echo "#### Changelog $VERSION - $DATE_HUMAN" 60 | echo "$CHANGELOG" | sed 's/^/- /' 61 | echo "" 62 | cat CHANGELOG.md 63 | } > CHANGELOG.tmp && mv CHANGELOG.tmp CHANGELOG.md 64 | 65 | # 4. Commit and push changes 66 | - name: Commit and push changes 67 | run: | 68 | git config user.name "github-actions[bot]" 69 | git config user.email "41898282+github-actions[bot]@users.noreply.github.com" 70 | git add update.json module.prop CHANGELOG.md 71 | git commit -m "${{ github.event.inputs.tag }}" || echo "No changes to commit" 72 | git push origin "${{ github.event.inputs.branch }}" --force 73 | 74 | # 5. Run build script 75 | - name: Run build.sh 76 | run: | 77 | chmod +x build.sh 78 | ./build.sh 79 | 80 | # 6. Create GitHub Release 81 | - name: Create GitHub Release 82 | uses: softprops/action-gh-release@v1 83 | with: 84 | tag_name: ${{ github.event.inputs.tag }} 85 | files: box_for_root-v*.zip 86 | generate_release_notes: true 87 | body: | 88 | #### Changelog v${{ github.event.inputs.tag }} 89 | ${{ github.event.inputs.changelog }} 90 | 91 | # 7. Upload to Telegram 92 | - name: Upload to Telegram 93 | if: ${{ success() }} 94 | env: 95 | CHAT_ID: "-1001597117128" 96 | MESSAGE_THREAD_ID: "282263" 97 | API_ID: ${{ secrets.API_ID }} 98 | API_HASH: ${{ secrets.API_HASH }} 99 | BOT_TOKEN: ${{ secrets.BOT_TOKEN }} 100 | run: | 101 | pip3 install --quiet telethon==1.31.1 102 | 103 | FILE=$(find . -maxdepth 1 -type f -name "box_for_root-v*.zip" | head -n 1) 104 | [ -z "$FILE" ] && echo "No ZIP file found!" && exit 1 105 | 106 | export VERSION=$(git rev-parse --short HEAD) 107 | export COMMIT=$(git log --oneline -n 10 --no-decorate | sed 's/^[0-9a-f]* //' | sed 's/^/— /') 108 | python3 .github/taamarinbot.py "$FILE" -------------------------------------------------------------------------------- /.github/workflows/debug.yml: -------------------------------------------------------------------------------- 1 | name: debug 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | paths-ignore: 7 | - "docs/**" 8 | - "README.md" 9 | - "CHANGELOG.md" 10 | branches: 11 | - master 12 | 13 | permissions: 14 | contents: write 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v4.1.0 22 | with: 23 | fetch-depth: 0 24 | 25 | - name: Update Module.prop 26 | run: | 27 | sed -i "s/$(grep -oP 'version=\K[^ ]+' module.prop)/$(cat module.prop | grep 'version=' | awk -F '=' '{print $2}')($(git log --oneline -n 1 | awk '{print $1}'))/g" module.prop 28 | sed -i "s/versionCode=.*/versionCode=$(date +%Y%m%d)/g" module.prop 29 | 30 | - name: Get Version 31 | id: get_version 32 | run: | 33 | echo "version=$(grep -oP 'version=\K[^ ]+' module.prop)" >> "$GITHUB_OUTPUT" 34 | 35 | - name: Generate Asset 36 | run: | 37 | sudo mkdir -p /box_for_root 38 | sudo cp -r --parents $(find ./ -type f ! -path './.git/*' ! -name 'CHANGELOG.md' ! -name 'update.json' ! -name 'build.sh' ! -path './.github/*' ! -path './docs/*') /box_for_root/ 39 | 40 | - name: Upload Debug Asset => (box_for_magisk_${{ steps.get_version.outputs.version }}) 41 | uses: actions/upload-artifact@v4 42 | with: 43 | name: "box_for_magisk_${{ steps.get_version.outputs.version }}" 44 | path: /box_for_root/ 45 | 46 | upload: 47 | runs-on: ubuntu-latest 48 | needs: 49 | - build 50 | 51 | steps: 52 | - uses: actions/checkout@v4.1.0 53 | with: 54 | fetch-depth: 0 55 | 56 | - name: Check for [ci] in commit message 57 | id: check_ci 58 | run: | 59 | COMMIT_MSG=$(git log -1 --pretty=%B) 60 | echo "Last commit message: $COMMIT_MSG" 61 | if [[ "$COMMIT_MSG" == *"[ci]"* ]]; then 62 | echo "should_upload=true" >> "$GITHUB_OUTPUT" 63 | else 64 | echo "should_upload=false" >> "$GITHUB_OUTPUT" 65 | fi 66 | 67 | - name: Run build 68 | if: steps.check_ci.outputs.should_upload == 'true' 69 | run: | 70 | sed -i "s/$(grep -oP 'version=\K[^ ]+' module.prop)/$(cat module.prop | grep 'version=' | awk -F '=' '{print $2}')($(git log --oneline -n 1 | awk '{print $1}'))/g" module.prop 71 | zip -r -o -X -ll box_for_root-$(cat module.prop | grep 'version=' | awk -F '=' '{print $2}').zip ./ \ 72 | -x '.git/*' -x 'CHANGELOG.md' -x 'update.json' -x 'build.sh' -x '.github/*' -x 'docs/*' 73 | 74 | - name: Upload to GitHub Pre-release 75 | if: steps.check_ci.outputs.should_upload == 'true' 76 | env: 77 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 78 | run: | 79 | VERSION=$(cat module.prop | grep 'version=' | awk -F '=' '{print $2}') 80 | FILE=$(find . -name "*.zip") 81 | gh release create "pre-${VERSION}" "$FILE" \ 82 | --prerelease \ 83 | --title "Pre-release ${VERSION}" \ 84 | --notes "pre-release build from commit $(git log -1 --pretty=%h)" 85 | 86 | - name: Upload to Telegram 87 | if: steps.check_ci.outputs.should_upload == 'true' 88 | env: 89 | CHAT_ID: "-1001597117128" 90 | MESSAGE_THREAD_ID: "282263" 91 | API_ID: ${{ secrets.API_ID }} 92 | API_HASH: ${{ secrets.API_HASH }} 93 | BOT_TOKEN: ${{ secrets.BOT_TOKEN }} 94 | run: | 95 | if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then 96 | export VERSION=$(cat module.prop | grep 'version=' | awk -F '=' '{print $2}') 97 | export COMMIT=$(git log --oneline -n 5 --no-decorate | sed 's/^[0-9a-f]* //' | sed 's/^/— /') 98 | FILE=$(find . -name "*.zip") 99 | pip3 install telethon==1.31.1 100 | python3 $GITHUB_WORKSPACE/.github/taamarinbot.py "$FILE" 101 | fi -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Box for Root 2 | 3 | [![ID](https://img.shields.io/badge/id-blue.svg?style=for-the-badge)](docs/index_id.md) [![EN](https://img.shields.io/badge/en-blue.svg?style=for-the-badge)](docs/index_en.md) [![ZH](https://img.shields.io/badge/zh-blue.svg?style=for-the-badge)](docs/index_zh.md) 4 | 5 |

6 | BOX 7 |
BOX
8 |

9 |

Transparent Proxy for Android (Root)

10 | 11 | 19 | 20 | ## Introduction 21 | `Box for Root` (BFR) is a [Magisk](https://github.com/topjohnwu/Magisk), [KernelSU](https://github.com/tiann/KernelSU), [APatch](https://github.com/bmax121/APatch), module that provides a suite of proxy tools, including `clash`, `sing-box`, `v2ray`, `hysteria` and `xray`. It allows you to configure a transparent proxy on Android devices with root access. 22 | 23 | ## Features 24 | - Support for multiple proxy tools: `clash`, `sing-box`, `v2ray`, `hysteria`, and `xray`. 25 | - Transparent proxy for Android with root access. 26 | - Seamless integration with Magisk, KernelSU, and APatch. 27 | - Manage proxy services with ease. 28 | 29 | ## Apk Manager 30 | You can use the **BFR Manager** app (optional) to manage Box for Root on your device. 31 | [Download BFR Manager](https://t.me/nothing_taamarin) 32 | > ⚠️ If you receive continuous notifications, open Magisk Manager, navigate to SuperUser, search for `BoxForRoot`, and disable logs and notifications. 33 | 34 | ## Module Directory 35 | The core files of the module are stored in the following directories: 36 | - `MODDIR=/data/adb/box` 37 | - `MODLOG=/data/adb/box/run` 38 | - `SETTINGS=/data/adb/box/settings.ini` 39 | > ⚠️ Before editing the `settings.ini` file located at `/data/adb/box/settings.ini`, ensure that BFR is turned off to avoid configuration issues. 40 | 41 | ## Manage Service Start/Stop 42 | The following core services are collectively referred to as **BFR**. By default, the BFR service auto-starts after a system boot. You can manage the service through Magisk/KernelSU Manager App, with the service start taking a few seconds, and stopping it taking effect immediately. 43 | 44 | ### To start the service: 45 | ```bash 46 | su -c /data/adb/box/scripts/box.service start && su -c /data/adb/box/scripts/box.iptables enable 47 | ``` 48 | ### To stop the service: 49 | ```bash 50 | su -c /data/adb/box/scripts/box.iptables disable && su -c /data/adb/box/scripts/box.service stop 51 | ``` 52 | 53 | ## Here are some additional instructions: 54 | - When modifying any of the core configuration files, ensure that the tproxy-related configurations match the definitions in the **/data/adb/box/settings.ini** file. 55 | - If your device has a public IP address, you can add that IP address to the internal network in the **/data/adb/box/scripts/box.iptables** file to prevent loopback traffic. 56 | - The logs for the BFM service can be found in the directory **/data/adb/box/run**. 57 | - Please note that modifying these files requires appropriate permissions. Make sure to carefully follow the instructions and validate any changes made to the configuration files. 58 | 59 | You can run the following command to get other related operating instructions: 60 | ```bash 61 | su -c /data/adb/box/scripts/box.tool 62 | # usage: {check|geosub|geox|subs|upkernel|upxui|upyq|upcurl|reload|all} 63 | su -c /data/adb/box/scripts/box.service 64 | # usage: $0 {start|stop|restart|status|cron|kcron} 65 | su -c /data/adb/box/scripts/box.iptables 66 | # usage: $0 {enable|disable|renew} 67 | ``` 68 | 69 | ## Uninstall 70 | Remove the module from `Magisk/KernelSU/APatch Manager` and run the following command to wipe the data: 71 | ```bash 72 | su -c rm -rf /data/adb/box 73 | su -c rm -rf /data/adb/service.d/box_service.sh 74 | su -c rm -rf /data/adb/modules/box_for_root 75 | ``` 76 | 77 | ## Credits 78 | - [CHIZI-0618/box4magisk](https://github.com/CHIZI-0618/box4magisk) for the original Box for Magisk module. 79 | 80 | ## License 81 | This project is licensed under the GPL-3.0 license - see the [LICENSE](https://github.com/taamarin/box_for_magisk/blob/master/LICENSE) file for details. 82 | -------------------------------------------------------------------------------- /box/xray/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "dns": { 3 | "queryStrategy": "UseIP", 4 | "servers": [ 5 | "1.1.1.1", 6 | { 7 | "address": "1.1.1.1", 8 | "domains": [ 9 | "domain:googleapis.cn", 10 | "domain:gstatic.com" 11 | ] 12 | }, 13 | { 14 | "address": "223.5.5.5", 15 | "domains": [ 16 | "domain:dns.alidns.com", 17 | "domain:doh.pub", 18 | "domain:dot.pub", 19 | "domain:doh.360.cn", 20 | "domain:dot.360.cn", 21 | "geosite:cn", 22 | "geosite:geolocation-cn" 23 | ], 24 | "expectIPs": [ 25 | "geoip:cn" 26 | ], 27 | "skipFallback": true 28 | } 29 | ], 30 | "tag": "dns", 31 | "hosts": { 32 | "geosite:category-ads-all": "127.0.0.1", 33 | "domain:googleapis.cn": "googleapis.com", 34 | "dns.pub": [ 35 | "1.12.12.12", 36 | "120.53.53.53" 37 | ], 38 | "dns.alidns.com": [ 39 | "223.5.5.5", 40 | "223.6.6.6", 41 | "2400:3200::1", 42 | "2400:3200:baba::1" 43 | ], 44 | "one.one.one.one": [ 45 | "1.1.1.1", 46 | "1.0.0.1", 47 | "2606:4700:4700::1111", 48 | "2606:4700:4700::1001" 49 | ], 50 | "dns.google": [ 51 | "8.8.8.8", 52 | "8.8.4.4", 53 | "2001:4860:4860::8888", 54 | "2001:4860:4860::8844" 55 | ] 56 | } 57 | }, 58 | "inbounds": [ 59 | { 60 | "port": 9898, 61 | "protocol": "dokodemo-door", 62 | "tag": "tproxy-in", 63 | "settings": { 64 | "followRedirect": true, 65 | "network": "tcp,udp" 66 | }, 67 | "sniffing": { 68 | "destOverride": [ 69 | "http", 70 | "tls" 71 | ], 72 | "enabled": true, 73 | "routeOnly": false 74 | }, 75 | "streamSettings": { 76 | "sockopt": { 77 | "tproxy": "tproxy" 78 | } 79 | } 80 | } 81 | ], 82 | "log": { 83 | "access": "none", 84 | "dnsLog": true, 85 | "loglevel": "error" 86 | }, 87 | "outbounds": [ 88 | { 89 | "protocol": "vmess", 90 | "tag": "proxy", 91 | "mux": { 92 | "concurrency": 8, 93 | "enabled": false 94 | }, 95 | "settings": { 96 | "vnext": [ 97 | { 98 | "address": "u.taamarin.com", 99 | "port": 443, 100 | "users": [ 101 | { 102 | "alterId": 0, 103 | "encryption": "", 104 | "flow": "", 105 | "id": "", 106 | "level": 8, 107 | "security": "auto" 108 | } 109 | ] 110 | } 111 | ] 112 | }, 113 | "streamSettings": { 114 | "network": "ws", 115 | "security": "tls", 116 | "tlsSettings": { 117 | "allowInsecure": true, 118 | "fingerprint": "", 119 | "publicKey": "", 120 | "serverName": "u.taamarin.com", 121 | "shortId": "", 122 | "show": false, 123 | "spiderX": "" 124 | }, 125 | "wsSettings": { 126 | "path": "/vmess", 127 | "headers": { 128 | "Host": "u.taamarin.com" 129 | } 130 | } 131 | } 132 | }, 133 | { 134 | "protocol": "freedom", 135 | "tag": "direct", 136 | "settings": { 137 | "domainStrategy": "UseIP" 138 | } 139 | }, 140 | { 141 | "protocol": "blackhole", 142 | "tag": "block", 143 | "settings": { 144 | "response": { 145 | "type": "http" 146 | } 147 | } 148 | }, 149 | { 150 | "protocol": "dns", 151 | "tag": "dns-out" 152 | } 153 | ], 154 | "routing": { 155 | "domainMatcher": "mph", 156 | "domainStrategy": "IPIfNonMatch", 157 | "rules": [ 158 | { 159 | "inboundTag": [ 160 | "tproxy-in" 161 | ], 162 | "outboundTag": "dns-out", 163 | "port": 53, 164 | "type": "field" 165 | }, 166 | { 167 | "domain": [ 168 | "regexp:^.*googlesyndication.com$", 169 | "regexp:^.*adtival\\.network$" 170 | ], 171 | "outboundTag": "proxy", 172 | "type": "field" 173 | }, 174 | { 175 | "domain": [ 176 | "geosite:youtube" 177 | ], 178 | "network": "udp", 179 | "outboundTag": "block", 180 | "type": "field" 181 | }, 182 | { 183 | "domain": [ 184 | "geosite:category-ads-all" 185 | ], 186 | "outboundTag": "block", 187 | "type": "field" 188 | }, 189 | { 190 | "network": "tcp,udp", 191 | "outboundTag": "proxy", 192 | "type": "field" 193 | } 194 | ] 195 | } 196 | } -------------------------------------------------------------------------------- /box/v2fly/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "dns": { 3 | "queryStrategy": "UseIP", 4 | "servers": [ 5 | "1.1.1.1", 6 | { 7 | "address": "1.1.1.1", 8 | "domains": [ 9 | "domain:googleapis.cn", 10 | "domain:gstatic.com" 11 | ] 12 | }, 13 | { 14 | "address": "223.5.5.5", 15 | "domains": [ 16 | "domain:dns.alidns.com", 17 | "domain:doh.pub", 18 | "domain:dot.pub", 19 | "domain:doh.360.cn", 20 | "domain:dot.360.cn", 21 | "geosite:cn", 22 | "geosite:geolocation-cn" 23 | ], 24 | "expectIPs": [ 25 | "geoip:cn" 26 | ], 27 | "skipFallback": true 28 | } 29 | ], 30 | "tag": "dns", 31 | "hosts": { 32 | "geosite:category-ads-all": "127.0.0.1", 33 | "domain:googleapis.cn": "googleapis.com", 34 | "dns.pub": [ 35 | "1.12.12.12", 36 | "120.53.53.53" 37 | ], 38 | "dns.alidns.com": [ 39 | "223.5.5.5", 40 | "223.6.6.6", 41 | "2400:3200::1", 42 | "2400:3200:baba::1" 43 | ], 44 | "one.one.one.one": [ 45 | "1.1.1.1", 46 | "1.0.0.1", 47 | "2606:4700:4700::1111", 48 | "2606:4700:4700::1001" 49 | ], 50 | "dns.google": [ 51 | "8.8.8.8", 52 | "8.8.4.4", 53 | "2001:4860:4860::8888", 54 | "2001:4860:4860::8844" 55 | ] 56 | } 57 | }, 58 | "inbounds": [ 59 | { 60 | "port": 9898, 61 | "protocol": "dokodemo-door", 62 | "tag": "tproxy-in", 63 | "settings": { 64 | "followRedirect": true, 65 | "network": "tcp,udp" 66 | }, 67 | "sniffing": { 68 | "destOverride": [ 69 | "http", 70 | "tls" 71 | ], 72 | "enabled": true, 73 | "routeOnly": false 74 | }, 75 | "streamSettings": { 76 | "sockopt": { 77 | "tproxy": "tproxy" 78 | } 79 | } 80 | } 81 | ], 82 | "log": { 83 | "access": "none", 84 | "dnsLog": true, 85 | "loglevel": "error" 86 | }, 87 | "outbounds": [ 88 | { 89 | "protocol": "vmess", 90 | "tag": "proxy", 91 | "mux": { 92 | "concurrency": 8, 93 | "enabled": false 94 | }, 95 | "settings": { 96 | "vnext": [ 97 | { 98 | "address": "u.taamarin.com", 99 | "port": 443, 100 | "users": [ 101 | { 102 | "alterId": 0, 103 | "encryption": "", 104 | "flow": "", 105 | "id": "", 106 | "level": 8, 107 | "security": "auto" 108 | } 109 | ] 110 | } 111 | ] 112 | }, 113 | "streamSettings": { 114 | "network": "ws", 115 | "security": "tls", 116 | "tlsSettings": { 117 | "allowInsecure": true, 118 | "fingerprint": "", 119 | "publicKey": "", 120 | "serverName": "u.taamarin.com", 121 | "shortId": "", 122 | "show": false, 123 | "spiderX": "" 124 | }, 125 | "wsSettings": { 126 | "path": "/vmess", 127 | "headers": { 128 | "Host": "u.taamarin.com" 129 | } 130 | } 131 | } 132 | }, 133 | { 134 | "protocol": "freedom", 135 | "tag": "direct", 136 | "settings": { 137 | "domainStrategy": "UseIP" 138 | } 139 | }, 140 | { 141 | "protocol": "blackhole", 142 | "tag": "block", 143 | "settings": { 144 | "response": { 145 | "type": "http" 146 | } 147 | } 148 | }, 149 | { 150 | "protocol": "dns", 151 | "tag": "dns-out" 152 | } 153 | ], 154 | "routing": { 155 | "domainMatcher": "mph", 156 | "domainStrategy": "IPIfNonMatch", 157 | "rules": [ 158 | { 159 | "inboundTag": [ 160 | "tproxy-in" 161 | ], 162 | "outboundTag": "dns-out", 163 | "port": 53, 164 | "type": "field" 165 | }, 166 | { 167 | "domain": [ 168 | "regexp:^.*googlesyndication.com$", 169 | "regexp:^.*adtival\\.network$" 170 | ], 171 | "outboundTag": "proxy", 172 | "type": "field" 173 | }, 174 | { 175 | "domain": [ 176 | "geosite:youtube" 177 | ], 178 | "network": "udp", 179 | "outboundTag": "block", 180 | "type": "field" 181 | }, 182 | { 183 | "domain": [ 184 | "geosite:category-ads-all" 185 | ], 186 | "outboundTag": "block", 187 | "type": "field" 188 | }, 189 | { 190 | "network": "tcp,udp", 191 | "outboundTag": "proxy", 192 | "type": "field" 193 | } 194 | ] 195 | } 196 | } -------------------------------------------------------------------------------- /docs/index_zh.md: -------------------------------------------------------------------------------- 1 | # 📦 Magisk / KernelSU 的 Box 模块 2 | 3 | ## ⚠️ 警告 4 | 5 | 本项目不对以下情况负责:设备损坏、SD 卡损坏或 SoC 烧毁。 6 | 7 | **请确保您的配置文件不会造成流量循环,否则可能导致手机无限重启。** 8 | 9 | 如果您不清楚如何配置此模块,建议使用以下应用程序:**ClashForAndroid、ClashMetaForAndroid、v2rayNG、Surfboard、SagerNet、AnXray、NekoBox、SFA** 等。 10 | 11 | ## 📦 安装 12 | • 从 [RELEASE](https://github.com/taamarin/box_for_magisk/releases) 下载 zip 模块包,并通过 `Magisk/APatch/KernelSU` 安装。安装时会询问是否下载完整包,您可以选择**完整下载** 或 **稍后分开下载**,然后重启设备。 13 | • 此模块支持通过 `Magisk/APatch/KernelSU 管理器` 直接更新模块(更新后无需重启设备即可生效)。 14 | 15 | ### 内核更新 16 | 此模块包含以下内核: 17 | • [clash](https://github.com/Dreamacro/clash)(仓库已删除) 18 | • [clash.meta](https://github.com/MetaCubeX/mihomo) 19 | • [sing-box](https://github.com/SagerNet/sing-box) 20 | • [v2ray-core](https://github.com/v2fly/v2ray-core) 21 | • [Xray-core](https://github.com/XTLS/Xray-core) 22 | • [hysteria]() 23 | 24 | 适用于每个内核的配置为 `${bin_name}`,可设为(`clash` | `xray` | `v2ray` | `sing-box` | `hysteria`)。 25 | 每个核心位于 `/data/adb/box/bin/${bin_name}` 目录中,核心名称由 `/data/adb/box/settings.ini` 文件中的 `bin_name` 决定。 26 | 27 | 请确保连接互联网后执行以下命令以更新内核文件: 28 | ```shell 29 | su -c /data/adb/box/scripts/box.tool upkernel 30 | ``` 31 | 32 | 如果您使用的是 `clash` 或 `sing-box`,并希望使用控制面板(dashboard),也请执行以下命令: 33 | ```shell 34 | su -c /data/adb/box/scripts/box.tool upxui 35 | ``` 36 | 37 | 或者执行以下命令以一次性更新所有文件(可能会占用较多存储): 38 | ```shell 39 | su -c /data/adb/box/scripts/box.tool all 40 | ``` 41 | 42 | ## ⚙️ 配置 43 | **以下核心服务统称为 BFR** 44 | 您可以通过 Magisk/KernelSU 管理器启用或停用模块,实时启动或停止 BFR 服务,无需重启设备。启动服务可能需要几秒钟,停止服务则立即生效。 45 | 46 | ### 核心配置 47 | • 有关 `bin_name` 的核心配置,请参见“内核更新”部分。 48 | • 每个核心配置文件需用户自行定制,脚本将检查配置有效性,检查结果保存在 `/data/adb/box/run/runs.log`。 49 | • 提示:`clash` 和 `sing-box` 已预设透明代理脚本。更多配置请参考官方文档:[Clash 官方文档](https://github.com/Dreamacro/clash/wiki/configuration)(已删除),[sing-box 官方文档](https://sing-box.sagernet.org/configuration/outbound/) 50 | 51 | ### 应用过滤(黑名单/白名单) 52 | • 默认情况下,BFR 会代理所有 Android 用户的所有应用。 53 | • 若想让 BFR **代理所有应用,排除部分应用**,请打开 `/data/adb/box/package.list.cfg` 文件,将 `mode` 设置为 `blacklist`(默认值),并添加要排除的应用,例如: 54 | ↳ **com.termux** 55 | ↳ **org.telegram.messenger** 56 | • 若只想 **代理指定应用**,请使用 `mode:whitelist` 并添加要代理的应用: 57 | ↳ **com.termux** 58 | ↳ **org.telegram.messenger** 59 | > ⚠️ 若使用 CLASH,黑白名单在 fake-ip 模式下无效 60 | 61 | ### 为特定进程启用透明代理 62 | • 默认情况下,BFR 透明代理所有进程。 63 | • 若要排除某些进程,请在 `/data/adb/box/package.list.cfg` 中将 `mode` 设置为 `blacklist`(默认值),并添加 GID(每个 GID 一行)。 64 | • 若只想代理某些进程,则设置 `mode` 为 `whitelist` 并添加 GID。 65 | > ⚠️ Android 的 iptables 不支持 PID 匹配,Box 通过 GID 间接匹配进程。可通过 busybox 的 setuidgid 命令以特定 UID 启动进程。 66 | 67 | ### 更改代理模式 68 | • 默认使用 TPROXY 模式代理 TCP+UDP。若设备不支持 TPROXY,请修改 `/data/adb/box/settings.ini` 中 `network_mode="tproxy"` 为 `redirect`: 69 | • redirect:redirect(TCP) + Direct(UDP) 70 | • tproxy:tproxy(TCP + UDP) 71 | • mixed:redirect(TCP) + tun(UDP) 72 | • enhance:redirect(TCP) + tproxy(UDP) 73 | • tun:TCP + UDP(自动路由) 74 | 75 | ### 连接 Wi-Fi/热点时绕过透明代理 76 | • 默认情况下,BFR 会透明代理 `localhost` 和热点(包括 USB 共享)。 77 | • 打开 `/data/adb/box/ap.list.cfg` 添加 **ignore wlan+**,则会跳过 wlan 和热点代理。 78 | • 若添加 **allow wlan+**(与 ignore wlan+ 冲突),则 BFR 会代理热点(Mediatek 设备可能为 ap+ / wlan+)。 79 | • 使用 `ifconfig` 命令查看 AP 名称。 80 | 81 | ### 启用计划任务自动更新 Geo 和订阅 82 | • 修改 `/data/adb/box/settings.ini`,将 `run_crontab=true`、`update_geo="true"`、`update_subscription="true"` 并设置 `interva_update="@daily"`(默认值) 83 | • Geo 和订阅将自动按计划更新。 84 | • 可在 `/data/adb/box/crontab.cfg` 添加其他计划任务: 85 | ```shell 86 | su -c /data/adb/box/scripts/box.service cron 87 | su -c /data/adb/box/scripts/box.service kcron 88 | ``` 89 | 90 | ## ▶️ 启动与停止 91 | ### 手动模式 92 | • 若您想完全手动控制 BFR,创建 `/data/adb/box/manual` 文件即可。在此模式下,BFR 不会自动启动,也不能通过 Magisk/KernelSU 管理器控制。 93 | 94 | ### 启动与停止服务脚本 95 | • BFR 服务脚本:/data/adb/box/scripts/box.service 96 | • BFR iptables 脚本:/data/adb/box/scripts/box.iptables 97 | ```shell 98 | # 启动 BFR 99 | su -c /data/adb/box/scripts/box.service start && su -c /data/adb/box/scripts/box.iptables enable 100 | 101 | # 停止 BFR 102 | su -c /data/adb/box/scripts/box.iptables disable && su -c /data/adb/box/scripts/box.service stop 103 | ``` 104 | 105 | ## Geo 与订阅更新 106 | 使用以下命令同时更新订阅与 Geo 数据库: 107 | ```shell 108 | su -c /data/adb/box/scripts/box.tool geosub 109 | ``` 110 | 111 | 或分别更新: 112 | ### 更新订阅(仅支持 Clash) 113 | ```shell 114 | su -c /data/adb/box/scripts/box.tool subs 115 | ``` 116 | 117 | ### 更新 Geo 数据库 118 | ```shell 119 | su -c /data/adb/box/scripts/box.tool geox 120 | ``` 121 | 122 | ## 📘 附加说明 123 | • 修改任何配置文件时,请确保与 `/data/adb/box/settings.ini` 的定义一致。 124 | • 若设备拥有公网 IP,请将其加入 `/data/adb/box/scripts/box.iptables` 中的内部网络以避免流量回环。 125 | • BFR 的日志保存在 **/data/adb/box/run** 目录。 126 | 127 | 查看帮助命令: 128 | ```shell 129 | su -c /data/adb/box/scripts/box.tool 130 | # usage: {check|geosub|geox|subs|upkernel|upxui|upyq|upcurl|reload|all} 131 | su -c /data/adb/box/scripts/box.service 132 | # usage: $0 {start|stop|restart|status|cron|kcron} 133 | su -c /data/adb/box/scripts/box.iptables 134 | # usage: $0 {enable|disable|renew} 135 | ``` 136 | 137 | ## 🗑️ 卸载 138 | • 通过 Magisk/KernelSU 管理器卸载模块将删除 `/data/adb/service.d/box_service.sh` 和 `/data/adb/box` 目录。 139 | • 可使用以下命令手动删除 BFR 数据: 140 | ```shell 141 | su -c rm -rf /data/adb/box 142 | su -c rm -rf /data/adb/service.d/box_service.sh 143 | su -c rm -rf /data/adb/modules/box_for_root 144 | ``` -------------------------------------------------------------------------------- /box/scripts/ctr.inotify: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | # Validate settings.ini 3 | if ! /system/bin/sh -n /data/adb/box/settings.ini 2>"/data/adb/box/run/settings_err.log"; then 4 | echo "Err: settings.ini contains a syntax error" | tee -a "/data/adb/box/run/settings_err.log" 5 | exit 1 6 | fi 7 | 8 | export PATH="/data/adb/magisk:/data/adb/ksu/bin:/data/adb/ap/bin:$PATH:/data/data/com.termux/files/usr/bin" 9 | 10 | module_dir="/data/adb/modules/box_for_root" 11 | base_dir="/data/adb/box" 12 | variab_dir="${base_dir}/run/variab" 13 | log_file="${base_dir}/run/netswitch.log" 14 | log_file_path="/data/local/tmp/" 15 | temp_log_file="${log_file_path}debug.log.tmp" 16 | last_check_file="${variab_dir}/last_check_time" 17 | last_wifi_state_file="${variab_dir}/last_wifi_state" 18 | 19 | if [ ! -d "$variab_dir" ]; then 20 | mkdir -p "$variab_dir" 21 | fi 22 | 23 | scripts=$(realpath "$0") 24 | scripts_dir=$(dirname "${scripts}") 25 | 26 | events=$1 27 | if [ "$events" != "w" ]; then 28 | return 29 | fi 30 | 31 | source "${base_dir}/settings.ini" 32 | 33 | if [ "$enable_network_service_control" != "true" ]; then 34 | exit 0 35 | fi 36 | 37 | source "${scripts_dir}/ctr.utils" 38 | 39 | log_msg() { 40 | if [ "$inotify_log_enabled" = "true" ]; then 41 | if [ -z "$1" ]; then 42 | echo "" >> "$log_file" 43 | else 44 | echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$log_file" 45 | fi 46 | fi 47 | } 48 | 49 | clean_old_logs() { 50 | # Only keep logs from the past 24 hours 51 | local retention_seconds=86400 # 24 hours 52 | local cutoff_time=$(( $(date +%s) - retention_seconds )) 53 | local cutoff_str 54 | cutoff_str=$(date -d "@${cutoff_time}" '+%Y-%m-%d %H:%M:%S') 55 | 56 | if [ -f "$log_file" ]; then 57 | busybox awk -v cutoff="$cutoff_str" ' 58 | !/^[0-9]{4}-[0-9]{2}-[0-9]{2}/ {print; next} 59 | substr($0, 1, 19) >= cutoff {print} 60 | ' "$log_file" > "$temp_log_file" && mv "$temp_log_file" "$log_file" 61 | fi 62 | } 63 | clean_old_logs 64 | 65 | current_time=$(date +%s) 66 | last_check_time=0 67 | 68 | if [ -f "$last_check_file" ]; then 69 | last_check_time=$(grep -oE '[0-9]+' "$last_check_file" | head -n 1) 70 | last_check_time=${last_check_time:-0} 71 | fi 72 | 73 | time_diff=$(( current_time - last_check_time )) 74 | stability_window=3 75 | 76 | if [ "$time_diff" -lt "$stability_window" ]; then 77 | log_msg "Skip check: (${time_diff}s), within stability window" 78 | return 0 79 | fi 80 | 81 | echo -n "$current_time" > "$last_check_file" 82 | 83 | wifi_status=$(is_wifi_connected) 84 | ssid=$(get_current_ssid) 85 | 86 | get_current_ip() { 87 | ip addr show wlan0 | grep 'inet ' | busybox awk '{print $2}' | cut -d/ -f1 88 | } 89 | 90 | check_module_service() { 91 | if [ "$enable_network_service_control" = "true" ]; then 92 | if [ -f "$box_pid" ]; then 93 | current_state="enabled" 94 | else 95 | current_state="disabled" 96 | fi 97 | 98 | last_ssid="" 99 | last_ip="" 100 | if [ -f "$last_wifi_state_file" ]; then 101 | last_ssid=$(grep 'ssid:' "$last_wifi_state_file" | cut -d: -f2) 102 | last_ip=$(grep 'ip:' "$last_wifi_state_file" | cut -d: -f2) 103 | fi 104 | 105 | if [ "$wifi_status" = "wifi" ] && [ -n "$ssid" ]; then 106 | for i in {1..3}; do 107 | current_ip=$(get_current_ip) 108 | if [ -n "$current_ip" ]; then 109 | break 110 | fi 111 | sleep 2 112 | done 113 | 114 | if [ -n "$current_ip" ]; then 115 | echo "-- Notifikasi LOG --" > "$log_file" 116 | log_msg "--- Network state change: WiFi connected ---" 117 | log_msg "SSID: ${ssid}, IP: ${current_ip}" 118 | echo "ssid:${ssid}" > "$last_wifi_state_file" 119 | echo "ip:${current_ip}" >> "$last_wifi_state_file" 120 | 121 | if [ "$use_module_on_wifi" = "false" ]; then 122 | log_msg "Policy: Disable service when on WiFi" 123 | if [ "$current_state" != "disabled" ]; then 124 | "${scripts_dir}/box.iptables" disable 125 | "${scripts_dir}/box.service" stop 126 | log_msg "Action: Service stopped" 127 | else 128 | log_msg "State: Service already stopped, no action needed" 129 | fi 130 | else 131 | if [ "$use_ssid_matching" = "true" ]; then 132 | case "$use_wifi_list_mode" in 133 | blacklist) 134 | log_msg "Policy: WiFi blacklist mode, list: ${wifi_ssids_list[*]}" 135 | if is_allowed_wifi "$ssid" "${ssid_list}"; then 136 | log_msg "Result: ${ssid} is in blacklist" 137 | if [ "$current_state" != "disabled" ]; then 138 | "${scripts_dir}/box.iptables" disable 139 | "${scripts_dir}/box.service" stop 140 | log_msg "Action: Service stopped" 141 | else 142 | log_msg "State: Service already stopped, no action needed" 143 | fi 144 | else 145 | log_msg "Result: ${ssid} not in blacklist" 146 | if [ "$current_state" != "enabled" ]; then 147 | "${scripts_dir}/box.service" start 148 | "${scripts_dir}/box.iptables" enable 149 | log_msg "Action: Service started" 150 | else 151 | log_msg "State: Service already running, no action needed" 152 | fi 153 | fi 154 | ;; 155 | 156 | whitelist) 157 | log_msg "Policy: WiFi whitelist mode, list: ${wifi_ssids_list[*]}" 158 | if is_allowed_wifi "$ssid" "${ssid_list}"; then 159 | log_msg "Result: ${ssid} is in whitelist" 160 | if [ "$current_state" != "enabled" ]; then 161 | "${scripts_dir}/box.service" start 162 | "${scripts_dir}/box.iptables" enable 163 | log_msg "Action: Service started" 164 | else 165 | log_msg "State: Service already running, no action needed" 166 | fi 167 | else 168 | log_msg "Result: ${ssid} not in whitelist" 169 | if [ "$current_state" != "disabled" ]; then 170 | "${scripts_dir}/box.iptables" disable 171 | "${scripts_dir}/box.service" stop 172 | log_msg "Action: Service stopped" 173 | else 174 | log_msg "State: Service already stopped, no action needed" 175 | fi 176 | fi 177 | ;; 178 | 179 | *) 180 | log_msg "Warning: Unknown WiFi list mode, using default start logic" 181 | if [ "$current_state" != "enabled" ]; then 182 | "${scripts_dir}/box.service" start 183 | "${scripts_dir}/box.iptables" enable 184 | log_msg "Action: Service started" 185 | else 186 | log_msg "State: Service already running, no action needed" 187 | fi 188 | ;; 189 | esac 190 | else 191 | log_msg "Policy: Default behavior is to start service on WiFi" 192 | if [ "$current_state" != "enabled" ]; then 193 | "${scripts_dir}/box.service" start 194 | "${scripts_dir}/box.iptables" enable 195 | log_msg "Action: Service started" 196 | else 197 | log_msg "State: Service already running, no action needed" 198 | fi 199 | fi 200 | fi 201 | else 202 | log_msg "--- Network state change: WiFi connecting ---" 203 | log_msg "State: No valid IP address yet, skipping action" 204 | fi 205 | 206 | elif [ "$wifi_status" = "not_wifi" ]; then 207 | log_msg "--- Network state change: WiFi disconnected ---" 208 | if [ "$use_module_on_wifi_disconnect" = "true" ]; then 209 | log_msg "Policy: Start service when WiFi disconnected" 210 | if [ "$current_state" != "enabled" ]; then 211 | "${scripts_dir}/box.service" start 212 | "${scripts_dir}/box.iptables" enable 213 | log_msg "Action: Service started" 214 | else 215 | log_msg "State: Service already running, no action needed" 216 | fi 217 | else 218 | log_msg "Policy: Disable service when WiFi disconnected" 219 | if [ "$current_state" != "disabled" ]; then 220 | "${scripts_dir}/box.iptables" disable 221 | "${scripts_dir}/box.service" stop 222 | log_msg "Action: Service stopped" 223 | else 224 | log_msg "State: Service already stopped, no action needed" 225 | fi 226 | fi 227 | fi 228 | else 229 | log_msg "Network control module service is disabled!" 230 | return 231 | fi 232 | } 233 | 234 | check_module_service -------------------------------------------------------------------------------- /box/settings.ini: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | 3 | # Define the path to the settings file 4 | settings="/data/adb/box/settings.ini" 5 | 6 | # Check if 'busybox' is installed; if not, add the necessary paths to the environment PATH variable 7 | if ! command -v busybox &> /dev/null; then 8 | export PATH="/data/adb/magisk:/data/adb/ksu/bin:/data/adb/ap/bin:$PATH:/system/bin" 9 | fi 10 | 11 | # Retrieve the current time in 12-hour format 12 | current_time=$(date +"%I:%M %P") 13 | 14 | # Set the port numbers for tproxy and redir functionalities 15 | tproxy_port="9898" 16 | redir_port="9797" 17 | 18 | # Enable or disable IPv6 support: true / false 19 | ipv6="false" 20 | 21 | # Define a list of available kernel binaries 22 | bin_list=("clash" "sing-box" "xray" "v2fly" "hysteria") 23 | 24 | # Specify which option to use for running and downloading premium or mihomo. Ensure premium and mihomo kernels are placed in the /data/adb/box/bin directory 25 | xclash_option="mihomo" 26 | 27 | # Select the client to use: clash / sing-box / xray / v2fly / hysteria 28 | bin_name="clash" 29 | 30 | # This script is used to set the user and group for BFM core files, if setgiduid is unknown, set it to 0:3005. 31 | box_user_group="root:net_admin" 32 | 33 | # Define the network modes: 34 | # redirect: handles tcp + udp[direct] 35 | # tproxy: handles tcp + udp 36 | # mixed: redirect[tcp] + tun[udp] 37 | # enhance: redirect[tcp] + tproxy[udp] 38 | # tun: handles tcp + udp (auto-route) 39 | network_mode="tproxy" 40 | 41 | # Configure cgroup to limit memory usage 42 | cgroup_memcg="false" 43 | memcg_limit="100M" 44 | 45 | # Configure cgroup for cpuset usage 46 | cgroup_cpuset="false" 47 | # If empty it will be filled in auto 48 | allow_cpu="0-7" 49 | 50 | # Configure cgroup for blkio usage 51 | cgroup_blkio="false" 52 | # default 900 if empty 53 | weight="" 54 | 55 | # Set box directory variables 56 | box_dir="/data/adb/box" 57 | box_run="${box_dir}/run" 58 | box_log="${box_run}/runs.log" 59 | box_pid="${box_run}/box.pid" 60 | bin_dir="${box_dir}/bin" 61 | bin_path="${bin_dir}/${bin_name}" 62 | 63 | # If you don't want to generate the /run/${bin_name}.log file (because it will grow in size over time), replace "${box_run}/${bin_name}.log" with "/dev/null" 64 | bin_log="${box_run}/${bin_name}.log" 65 | # bin_log="/dev/null" 66 | 67 | system_packages_file="/data/system/packages.list" 68 | uid_list=("/data/adb/box/run/appuid.list") 69 | 70 | # Update subscription & geox. Set update interval using cron, for more information: https://crontab.guru/, set 'true' to enable Cron job 71 | # will update every hour at 00, 06, 12, 18 72 | interva_update="0 0,6,12,18 * * *" 73 | run_crontab="false" 74 | 75 | # Type "su -c /data/adb/box/scripts/box.tool geox" to update geox 76 | update_geo="false" 77 | 78 | # If "renew=true", it will update $name_clash_config; if false, it will only retrieve proxies: [] for proxy-providers: []. 79 | # Type "su -c /data/adb/box/scripts/box.tool subs" to update subscription 80 | renew="false" 81 | update_subscription="false" 82 | 83 | # Source subscription URL for Clash configuration 84 | # if "renew=true" , will only process the first url" 85 | subscription_url_clash=("http://127.0.0.1:12345/api/file/clash1.yaml" "http://127.0.0.1:12345/api/file/clash2.yaml") 86 | 87 | # Source subscription URL for sing-box configuration 88 | subscription_url_singbox="http://127.0.0.1:12345/api/file/sing.json" 89 | 90 | # Clash configuration 91 | name_clash_config="config.yaml" 92 | clash_config="${box_dir}/clash/${name_clash_config}" 93 | 94 | # Clash subscription 95 | name_provide_clash_config=("subscription.yaml" "subscription2.yaml") 96 | clash_provide_path="${box_dir}/clash/subscription" 97 | 98 | # Support rules specified in subscriptions. This is useful when the subscription contains customized rules as well. 99 | # It will fetch rules: [] from the $subscription_url_clash configuration and add them to $name_clash_config; this has no effect if renew=true. 100 | custom_rules_subs="false" 101 | name_provide_clash_rules="rules.yaml" 102 | clash_provide_rules="${box_dir}/clash/subscription/${name_provide_clash_rules}" 103 | 104 | # Sing configuration 105 | name_sing_config="config.json" 106 | sing_config="${box_dir}/sing-box/${name_sing_config}" 107 | 108 | # Xray configuration 109 | name_xray_config="config.json" 110 | xray_config="${box_dir}/xray/${name_xray_config}" 111 | 112 | # V2ray configuration 113 | name_v2fly_config="config.json" 114 | v2fly_config="${box_dir}/v2fly/${name_v2fly_config}" 115 | 116 | # Hysteria configuration 117 | name_hysteria_config="config.yaml" 118 | hysteria_config="${box_dir}/hysteria/${name_hysteria_config}" 119 | 120 | write_listap=$(dirname "$settings")/ap.list.cfg 121 | # Check pkg config file 122 | [ -d ${write_listap} ] && rm -rf ${write_listap} 123 | [ ! -f ${write_listap} ] && cat > ${write_listap}< 126 | allow ap+ 127 | allow wlan+ 128 | allow rndis+ 129 | allow swlan+ 130 | allow ncm+ 131 | allow eth+ 132 | # -----------------🌼🌼----------------------- # 133 | # Ignore specific network interfaces that may conflict with the allowed list 134 | # ignore 135 | # ignore swlan+ 136 | # ignore wlan+ 137 | init 138 | 139 | # Read the list of allowed network interfaces from the configuration file "ap.list.cfg" 140 | ap_list=($(busybox awk '/^allow / {print $2}' ${write_listap})) 141 | # Read the list of ignored network interfaces from the configuration file "ap.list.cfg". These interfaces will be excluded from the output, not applicable in fake-ip mode. 142 | ignore_out_list=($(busybox awk '/^ignore / {print $2}' ${write_listap})) 143 | 144 | # Define the gid.list.cfg path 145 | gid_config=$(dirname "$settings")/gid.list.cfg 146 | [ -d ${gid_config} ] && rm -rf ${gid_config} 147 | [ ! -f ${gid_config} ] && cat > ${gid_config}< ${pkg_config}</dev/null 2>&1 223 | 224 | # using system notification 225 | # su -lp "2000" -c "cmd notification post -S messaging --conversation '$1' --message '$1':'$2' 'Tag' '$(echo $RANDOM)' " >/dev/null 2>&1 226 | } 227 | 228 | log() { 229 | normal="\033[0m" 230 | orange="\033[1;38;5;208m" 231 | red="\033[1;31m" 232 | green="\033[1;32m" 233 | yellow="\033[1;33m" 234 | blue="\033[1;34m" 235 | # Selects the text color according to the parameters 236 | case $1 in 237 | Info) color="${blue}" ;; 238 | Error) color="${red}" ;; 239 | Warning) color="${yellow}" ;; 240 | *) color="${green}" ;; 241 | esac 242 | # Add messages to time and parameters 243 | message="${current_time} [$1]: $2" 244 | if [ -t 1 ]; then 245 | # Prints messages to the console 246 | echo -e "${color}${message}${normal}" 247 | else 248 | # Print messages to a log file 249 | echo "${message}" | tee -a "${box_log}" 250 | fi 251 | 252 | if [[ $TOAST ]]; then 253 | notify "box_for_root" "${message}" 254 | fi 255 | } 256 | -------------------------------------------------------------------------------- /docs/index_id.md: -------------------------------------------------------------------------------- 1 | # 📦 Box for Magisk / KernelSU 2 | 3 | ## ⚠️ Peringatan 4 | 5 | Proyek ini tidak bertanggung jawab atas: perangkat yang rusak, kartu SD yang rusak, atau SoC yang terbakar. 6 | 7 | **Harap pastikan file konfigurasi Anda tidak menyebabkan loop lalu lintas, jika tidak maka dapat menyebabkan ponsel Anda restart tanpa batas.** 8 | 9 | Jika Anda benar-benar tidak tahu cara mengonfigurasi modul ini, Anda mungkin memerlukan aplikasi seperti **ClashForAndroid, ClashMetaForAndroid, v2rayNG, Surfboard, SagerNet, AnXray, NekoBox, SFA**, dll. 10 | 11 | ## 📦 Instalasi 12 | • Unduh paket zip modul dari [RELEASE](https://github.com/taamarin/box_for_magisk/releases) dan instal melalui `Magisk/APatch/KernelSU`. Saat menginstal, Anda akan ditanya apakah akan mengunduh paket lengkap, Anda dapat memilih **unduhan lengkap** atau **unduhan terpisah** nanti, lalu mulai ulang perangkat. 13 | • Module ini mendukung pembaruan Module langsung berikutnya di `Magisk/APatch/KernelSU Manager` (Module yang diperbarui akan berlaku tanpa me-reboot perangkat). 14 | 15 | ### Pembaruan Kernel 16 | Modul ini mencakup kernel berikut: 17 | • [clash](https://github.com/Dreamacro/clash)(repo dihapus) 18 | • [clash.meta](https://github.com/MetaCubeX/mihomo) 19 | • [sing-box](https://github.com/SagerNet/sing-box) 20 | • [v2ray-core](https://github.com/v2fly/v2ray-core) 21 | • [Xray-core](https://github.com/XTLS/Xray-core) 22 | • [hysteria]() 23 | 24 | Konfigurasi yang sesuai dengan kernel adalah `${bin_name}`, yang dapat diatur ke ( `clash` | `xray` | `v2ray` | `sing-box` | `hysteria`). 25 | Setiap core bekerja di direktori `/data/adb/box/bin/${bin_name}`, nama core ditentukan oleh `bin_name` di file `/data/adb/box/settings.ini`. 26 | 27 | Pastikan Anda terhubung ke internet dan jalankan perintah berikut untuk memperbarui file kernel: 28 | ```shell 29 | # perbarui kernel yang dipilih, sesuai dengan `bin_name` 30 | su -c /data/adb/box/scripts/box.tool upkernel 31 | ``` 32 | 33 | Jika Anda menggunakan `clash/sing-box` sebagai kernel yang dipilih, Anda mungkin juga perlu menjalankan perintah berikut untuk dapat menggunakan panel kontro(dashboard): 34 | ```shell 35 | # Perbarui panel admin clash/sing-box 36 | su -c /data/adb/box/scripts/box.tool upxui 37 | ``` 38 | 39 | Alternatifnya, Anda dapat melakukannya sekaligus (yang mungkin menghabiskan ruang penyimpanan secara tidak perlu): 40 | ```shell 41 | # Perbarui semua file (termasuk berbagai jenis kernel dan GeoX) 42 | su -c /data/adb/box/scripts/box.tool all 43 | ``` 44 | 45 | ## ⚙️ Konfigurasi 46 | **Layanan inti berikut disebut sebagai BFR** 47 | • Layanan inti berikut secara kolektif disebut sebagai BFR 48 | • Anda dapat mengaktifkan atau menonaktifkan modul untuk memulai atau menghentikan layanan BFR secara real time melalui aplikasi Magisk/KernelSU Manager tanpa harus me-reboot perangkat. Memulai layanan mungkin memerlukan waktu beberapa detik, penghentian layanan akan segera berlaku. 49 | 50 | ### konfigurasi inti 51 | • Untuk konfigurasi inti `bin_name`, silakan lihat bagian **Pembaruan Kernel** untuk konfigurasi. 52 | • Setiap file konfigurasi inti perlu dikustomisasi oleh pengguna, dan skrip akan memeriksa validitas konfigurasi, dan hasil pemeriksaan akan disimpan di file `/data/adb/box/run/runs.log`. 53 | • Tip: Baik `clash` dan `sing-box` datang dengan pra-konfigurasi dengan skrip proxy transparan. Untuk konfigurasi lebih lanjut, silakan merujuk ke dokumentasi resmi. Alamat: [dokumen resmi Clash](https://github.com/Dreamacro/clash/wiki/configuration) delete, [dokumen resmi sing-box](https://sing-box.sagernet.org/configuration/outbound/). 54 | 55 | ### Menerapkan pemfilteran (blacklist/whitelist) 56 | • BFR menyediakan proxy untuk semua aplikasi (aplikasi) dari semua pengguna Android secara default. 57 | • Jika Anda ingin BFR **mem-proxy semua aplikasi (aplikasi), kecuali beberapa aplikasi**, silakan buka file `/data/adb/box/package.list.cfg`, ubah nilai `mode` menjadi `blacklist` (default), tambahkan aplikasi yang akan dikecualika , misalnya: 58 | ↳ **com.termux** 59 | ↳ **org.telegram.messenger** 60 | • Jika Anda hanya ingin **mem-proxy aplikasi (aplikasi) tertentu**, gunakan `mode:whitelist`, dan tambahkan (aplikasi) yang hanya ingin di proxy, misalnya: 61 | ↳ **com.termux** 62 | ↳ **org.telegram.messenger** 63 | > ⚠️ Jika CLASH digunakan, blacklist/whitelist tidak akan berlaku dalam mode fake-ip. 64 | 65 | ### Proxy Transparan untuk Proses Tertentu 66 | • BFR secara default melakukan proxy transparan untuk semua proses. 67 | • Jika Anda ingin BFR melakukan proxy untuk semua proses kecuali beberapa proses tertentu, buka berkas `/data/adb/box/package.list.cfg`, ubah nilai `mode` menjadi `blacklist` (nilai default), lalu tambahkan elemen GID, dengan GID dipisahkan oleh enter(↳). Ini akan mengakibatkan proses dengan GID yang sesuai **tidak diproksikan**. 68 | • Jika Anda ingin hanya melakukan proxy transparan untuk proses tertentu, buka berkas `/data/adb/box/package.list.cfg`, ubah nilai `mode` menjadi `whitelist`, lalu tambahkan elemen GID, dengan GID dipisahkan oleh enter(↳). Ini akan mengakibatkan proses dengan GID yang sesuai **diproksikan**. 69 | > ⚠️ Karena iptables Android tidak mendukung pencocokan ekstensi PID, pencocokan proses oleh Box dilakukan melalui pencocokan GID secara tidak langsung. Di Android dapat menggunakan perintah setuidgid busybox untuk memulai proses tertentu dengan UID tertentu, GID apa pun. 70 | 71 | ### mengubah mode proxy 72 | • BFR menggunakan TPROXY untuk mem-proxy TCP+UDP secara transparan (default). Jika terdeteksi bahwa perangkat tidak mendukung TPROXY, buka `/data/adb/box/settings.ini` dan ubah `network_mode="tproxy"` menjadi `redirect` yang hanya menggunakan proxy TCP. 73 | • redirect:redirect(TCP) + Direct(UDP) 74 | • tproxy:tproxy(TCP + UDP) 75 | • mixed:redirect(TCP) + tun(UDP). 76 | • enhance: redirect(TCP) + tproxy(UDP) 77 | • tun: TCP + UDP (auto-route) 78 | 79 | ### Lewati proxy transparan saat menghubungkan ke Wi-Fi atau hotspot 80 | • BFR secara transparan memproksi `localhost` dan `hotspot` (termasuk tethering USB) secara default. 81 | • Buka file `/data/adb/box/ap.list.cfg`, tambahkan **ignore wlan+**, sehingga proxy transparan akan mem-bypass `wlan` dan `hotspot` **tidak akan terhubung ke proxy**. 82 | • Buka file `/data/adb/box/ap.list.cfg`, tambahkan **allow wlan+**(konflik dengan **ignore wlan+**). BFR akan **mem-proxy hotspot** (mungkin **ap+ / wlan+** untuk perangkat **Mediatek**). 83 | • Gunakan perintah `ifconfig` di Terminal untuk mengetahui nama AP. 84 | 85 | ### Aktifkan Cron Job untuk memperbarui Geo dan Subs sesuai jadwal secara otomatis 86 | • Buka file `/data/adb/box/settings.ini`, ubah nilai `run_crontab=true`, `update_geo="true"`, `update_subscription="true"` dan atur `interva_update="@daily"` (default), sesuaikan dengan yang anda inginkan. 87 | • Maka secara otomatis Geox dan Subs akan diperbarui sesuai jadwal interva_update. 88 | • Anda bisa menambahkan **scheduled tasks** lainnya di `/data/adb/box/crontab.cfg` 89 | ```shell 90 | # start 91 | su -c /data/adb/box/scripts/box.service cron 92 | # stop 93 | su -c /data/adb/box/scripts/box.service kcron 94 | ``` 95 | 96 | ## ▶️ Memulai & Menghentikan 97 | ### Masuk ke mode manual 98 | • Jika Anda ingin memiliki kontrol penuh atas BFR dengan menjalankan perintah, buat saja file baru bernama `/data/adb/box/manual`. Dalam hal ini, layanan BFR **tidak akan dimulai secara otomatis saat perangkat Anda dihidupkan)**, Anda juga tidak dapat mengatur mulai atau berhentinya layanan melalui aplikasi Magisk/KernelSU Manager. 99 | 100 | ### Memulai dan menghentikan layanan manajemen 101 | • Skrip layanan BFR adalah /data/adb/box/scripts/box.service 102 | • Skrip Iptables BFR adalah /data/adb/box/scripts/box.iptables 103 | 104 | ```shell 105 | # Mulai BFR 106 | su -c /data/adb/box/scripts/box.service start && su -c /data/adb/box/scripts/box.iptables enable 107 | 108 | # Hentikan BFR 109 | su -c /data/adb/box/scripts/box.iptables disable && su -c /data/adb/box/scripts/box.service stop 110 | ``` 111 | • Terminal akan mencetak log pada saat yang sama dan mengeluarkannya ke file log. 112 | 113 | ## Langganan dan pembaruan basis data Geo 114 | Anda dapat memperbarui langganan dan basis data Geo secara bersamaan menggunakan perintah berikut: 115 | ```shell 116 | su -c /data/adb/box/scripts/box.tool geosub 117 | ``` 118 | 119 | Atau Anda dapat memperbaruinya satu per satu. 120 | ### perbarui langganan 121 | • hanya mendukung untuk Clash 122 | ```shell 123 | su -c /data/adb/box/scripts/box.tool subs 124 | ``` 125 | 126 | ### Perbarui basis data Geo 127 | ```shell 128 | su -c /data/adb/box/scripts/box.tool geox 129 | ``` 130 | 131 | ## 📘 Instruksi Tambahan 132 | • Saat memodifikasi salah satu file konfigurasi inti, pastikan konfigurasi terkait cocok dengan definisi di file `/data/adb/box/settings.ini`. 133 | • Jika perangkat memiliki alamat IP publik, tambahkan IP tersebut ke jaringan internal di file `/data/adb/box/scripts/box.iptables` untuk mencegah pengulangan lalu lintas. 134 | • Log untuk layanan BFR dapat ditemukan di direktori **/data/adb/box/run**. 135 | 136 | Anda dapat menjalankan perintah berikut untuk mendapatkan instruksi operasi terkait lainnya: 137 | 138 | ```shell 139 | su -c /data/adb/box/scripts/box.tool 140 | # usage: {check|geosub|geox|subs|upkernel|upxui|upyq|upcurl|reload|all} 141 | su -c /data/adb/box/scripts/box.service 142 | # usage: $0 {start|stop|restart|status|cron|kcron} 143 | su -c /data/adb/box/scripts/box.iptables 144 | # usage: $0 {enable|disable|renew} 145 | ``` 146 | 147 | ## 🗑️ Uninstall 148 | • Instalasi yang menghapus modul ini dari Magisk/KernelSU Manager, akan menghapus file `/data/adb/service.d/box_service.sh` dan direktori data BFR di `/data/adb/box.` 149 | • Anda dapat menghapus data BFR dengan perintah berikut: 150 | 151 | ```shell 152 | su -c rm -rf /data/adb/box 153 | su -c rm -rf /data/adb/service.d/box_service.sh 154 | su -c rm -rf /data/adb/modules/box_for_root 155 | ``` -------------------------------------------------------------------------------- /docs/index_en.md: -------------------------------------------------------------------------------- 1 | ## WARNING 2 | This project is not responsible for: damaged devices, corrupted SD cards, or burnt SoCs. 3 | 4 | **Please ensure that your configuration files do not cause traffic loops, as this can result in your phone continuously restarting.** 5 | 6 | If you have no idea how to configure this module, you may need applications such as **ClashForAndroid, ClashMetaForAndroid, v2rayNG, Surfboard, SagerNet, AnXray, NekoBox,** etc. 7 | 8 | ## Installation 9 | - Download the modules zip package from the [RELEASE](https://github.com/taamarin/box_for_magisk/releases) and install it through `Magisk/KernelSU`. During installation, you will be asked whether to download the complete package. You can choose either **complete download** or **separate download** later, then reboot your device. 10 | - This mod supports direct updates in `Magisk/KernelSU Manager` (updated mods will take effect without rebooting the device). 11 | 12 | ### Kernel Updates 13 | This module includes the following kernels: 14 | - [clash](https://github.com/Dreamacro/clash)(Delete master branch) 15 | - [clash.meta](https://github.com/MetaCubeX/Clash.Meta)(Archive and change branches, the content is still there) 16 | - [sing-box](https://github.com/SagerNet/sing-box) 17 | - [v2ray-core](https://github.com/v2fly/v2ray-core) 18 | - [Xray-core](https://github.com/XTLS/Xray-core) 19 | 20 | The corresponding configuration for the kernel is `${bin_name}`, which can be set to (`clash` | `xray` | `v2ray` | `sing-box`). 21 | 22 | Each core operates in the directory `/data/adb/box/bin/${bin_name}`, and the core name is determined by the `bin_name` in the `/data/adb/box/settings.ini` file. 23 | 24 | Make sure you are connected to the internet and run the following command to update the kernel file: 25 | 26 | ```shell 27 | # Update the selected kernel, based on `${bin_name}`. 28 | su -c /data/adb/box/scripts/box.tool upkernel 29 | ``` 30 | 31 | If you are using `clash/sing-box` as the selected kernel, you may also need to run the following command to open the control panel: 32 | 33 | ```shell 34 | # Update the admin panel for `clash/sing-box`. 35 | su -c /data/adb/box/scripts/box.tool upyacd 36 | ``` 37 | 38 | Alternatively, you can do it all at once (which may consume unnecessary storage space). 39 | 40 | ```shell 41 | # Update all files, including various kernel types. 42 | su -c /data/adb/box/scripts/box.tool all 43 | ``` 44 | 45 | ## Configuration 46 | **The following core services are referred to as BFM:** 47 | - The following core services are collectively referred to as BFM. 48 | - You can enable or disable the module to start or stop the BFM services in real time through the Magisk/KernelSU Manager application without having to reboot the device. Starting the service may take a few seconds, and stopping the service will take effect immediately. 49 | 50 | ### Core configuration 51 | - For the core configuration of `bin_name`, please refer to the **Kernel Updates** section for the configuration. 52 | - Each core configuration file needs to be customized by the user, and the script will check the validity of the configuration. The results of the check will be stored in the `/data/adb/box/run/runs.log` file. 53 | - Tip: Both `clash` and `sing-box` come with pre-configured scripts for transparent proxy. For further configuration, please refer to the official documentation. Documentation links: [Official Clash Documentation](https://github.com/Dreamacro/clash/wiki/configuration)(Delete master branch), [Official sing-box Documentation](https://sing-box.sagernet.org/configuration/outbound) 54 | 55 | ### To apply filtering using a blacklist or whitelist, you can follow these general steps: 56 | - By default, BFM provides a proxy for all applications (APP) from all Android users. 57 | - If you want BFM to proxy all applications (APP), except for some specific applications, please open the file `/data/adb/box/settings.ini`, change the value of `proxy_mode` to `blacklist` (default), and add the applications to be excluded to the `packages_list`, for **example: packages_list=("com.termux" "org.telegram.messenger")**. 58 | - If you only want to proxy specific applications (APP), use the `whitelist` mode. 59 | - When the value of `proxy_mode` is set to `TUN`, transparent proxy will not function, and only the corresponding kernel will start supporting **TUN**. Currently, **only clash and sing-box are available**. 60 | > **Notes: If Clash is used, the blacklist and whitelist will not apply in fake-ip mode** 61 | 62 | ### Transparent Proxies for Specific Processes 63 | - BFM by default performs a transparent proxy for all processes. 64 | - If you want BFM to proxy for all processes except specific ones, open the file `/data/adb/box/settings.ini`, change the value of `proxy_mode` to `blacklist` (the default value), then add GID elements to the `gid_list` array, with GID separated by spaces. This will result in processes with the corresponding GID **not being proxied**. 65 | 66 | - If you wish to perform transparent proxying only for specific processes, open the file `/data/adb/box/settings.ini`, change the value of `proxy_mode` to `whitelist`, then add GID elements to the `gid_list` array, with GID separated by spaces. This will result in only processes with the corresponding GID being **proxied**. 67 | 68 | > Tips: Since Android iptables does not support extension PID matching, process matching by Box is done via GID matching indirectly. On Android you can use busybox setuidgid command to start a specific process with a specific UID, any GID. 69 | 70 | ### Change the proxy mode in BFM, follow these steps: 71 | - BFM utilizes TPROXY to transparently proxy TCP+UDP traffic (default). If it is detected that the device does not support TPROXY, open the file **/data/adb/box/settings.ini** and change `network_mode="redirect"` to `redirect`, which only uses TCP proxying. 72 | - Open the file `/data/adb/box/settings.ini` and change the value of `network_mode` to **redirect, tproxy, or mixed**. 73 | - redirect: Use redirect mode for TCP proxying. 74 | - tproxy: Use tproxy mode for TCP + UDP proxying. 75 | - mixed: Use redirect mode for TCP and tun mode for UDP proxying 76 | - Make sure to save the changes to the configuration file and restart the BFM service or the device for the modifications to take effect. 77 | 78 | ### bypass transparent proxy when connecting to Wi-Fi or hotspot in BFM 79 | - BFM transparently proxies localhost and hotspot (including USB tethering) by default. 80 | - Open the file **/data/adb/box/settings.ini** using a text editor, Find the `ignore_out_list` parameter in the file, update the value of ignore_out_list by adding `wlan+` to it. This will bypass transparent proxy for Wi-Fi connections. 81 | - If you want to enable proxying for hotspots, follow these additional steps: 82 | - Find the `ap_list` parameter in the settings.ini file. 83 | - Update the value of `ap_list` by adding `wlan+`. This will enable proxying for hotspots 84 | - maybe **ap+ / wlan+** for Mediatek devices 85 | - If you are unsure about the name of the access point (AP), you can use the **ifconfig** command in the Terminal to determine the AP name. 86 | 87 | ### To enable Cron Job for automatic updates of Geo and Subs according to a schedule. 88 | - Open the file **/data/adb/box/settings.ini** using a text editor. 89 | - Locate the parameter `run_crontab` in the file. 90 | - Change the value of `run_crontab` to true. 91 | - Set the `interval_update` parameter according to your desired schedule. The default value is **@daily**, which means the updates will occur once daily. You can customize it to your preferred interval using cron syntax. 92 | - Save the changes to the configuration file. 93 | - To execute the Cron Job and trigger the updates, follow these steps: 94 | 95 | ```shell 96 | # run command 97 | su -c /data/adb/box/scripts/box.service cron 98 | ``` 99 | 100 | - This command will execute the Cron Job and initiate the updates for Geo and Subs based on the configured schedule. 101 | - Ensure that you have the necessary permissions to execute the command. The updates will automatically occur according to the specified schedule once you have enabled the Cron Job and executed the command. 102 | 103 | ## Start and Stop 104 | ### manual mode 105 | - If you want to have full control over BFM by running commands manually, you can create a new file named **/data/adb/box/manual**. In this case, the BFM service will not start automatically when your device is powered on, and you will not be able to control the start or stop of the service through the Magisk/KernelSU Manager application. 106 | - By creating the **/data/adb/box/manual** file, you take manual control over BFM and can execute commands as needed to manage its operations. Please note that modifying system files requires appropriate permissions, and any manual changes should be made with caution. 107 | 108 | ### Start and stop the management service 109 | - The BFM service script is /data/adb/box/scripts/box.service 110 | 111 | ```shell 112 | # Start BFM 113 | su -c /data/adb/box/scripts/box.service start && su -c /data/adb/box/scripts/box.iptables enable 114 | 115 | # Stop BFM 116 | su -c /data/adb/box/scripts/box.iptables disable && su -c /data/adb/box/scripts/box.service stop 117 | ``` 118 | 119 | - When executing these commands, the Terminal will print logs simultaneously and output them to the log file. 120 | 121 | ## Geo database subscriptions and updates 122 | To update both the subscription and the Geo database simultaneously, you can use the following command: 123 | 124 | ```shell 125 | # This command will update both the subscription and the Geo database at the same time. 126 | su -c /data/adb/box/scripts/box.tool geosub 127 | ``` 128 | 129 | Alternatively, if you prefer to update them separately, you can use the following commands: 130 | 131 | ### Update the subscription: 132 | 133 | ```shell 134 | # This command will update the subscription data. 135 | su -c /data/adb/box/scripts/box.tool subs 136 | ``` 137 | 138 | By running these commands, you will be able to update the subscription and the Geo database as needed. 139 | 140 | ### Update the Geo database: 141 | 142 | ```shell 143 | # This command will update the Geo database. 144 | su -c /data/adb/box/scripts/box.tool geox 145 | ``` 146 | 147 | ## Here are some additional instructions: 148 | - When modifying any of the core configuration files, ensure that the tproxy-related configurations match the definitions in the **/data/adb/box/settings.ini** file. 149 | - If your device has a public IP address, you can add that IP address to the internal network in the **/data/adb/box/scripts/box.iptables** file to prevent loopback traffic. 150 | - The logs for the BFM service can be found in the directory **/data/adb/box/run**. 151 | - Please note that modifying these files requires appropriate permissions. Make sure to carefully follow the instructions and validate any changes made to the configuration files. 152 | 153 | You can run the following command to get other related operating instructions: 154 | 155 | ```shell 156 | su -c /data/adb/box/scripts/box.tool 157 | # usage: {check|bond0|bond1|memcg|cpuset|blkio|geosub|geox|subs|upkernel|upyacd|upyq|upcurl|port|reload|all} 158 | su -c /data/adb/box/scripts/box.service 159 | # usage: $0 {start|stop|restart|status|cron|kcron} 160 | su -c /data/adb/box/scripts/box.iptables 161 | # usage: $0 {enable|disable|renew} 162 | ``` 163 | 164 | ## uninstall 165 | - An install that removes this module from Magisk/KernelSU Manager, will remove the file **/data/adb/service.d/box_service.sh** and the BFM data directory at **/data/adb/box**. 166 | - Remove the BFM data directory by running the following command: 167 | 168 | ```shell 169 | # This command will delete the BFM data directory located at /data/adb/box. 170 | su -c rm -rf /data/adb/box 171 | su -c rm -rf /data/adb/service.d/box_service.sh 172 | su -c rm -rf /data/adb/modules/box_for_root 173 | ``` -------------------------------------------------------------------------------- /customize.sh: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | 3 | # Script configuration variables 4 | SKIPUNZIP=1 5 | SKIPMOUNT=false 6 | PROPFILE=true 7 | POSTFSDATA=false 8 | LATESTARTSERVICE=true 9 | 10 | # Check installation conditions 11 | if [ "$BOOTMODE" != true ]; then 12 | abort "-----------------------------------------------------------" 13 | ui_print "! Please install in Magisk/KernelSU/APatch Manager" 14 | ui_print "! Install from recovery is NOT supported" 15 | abort "-----------------------------------------------------------" 16 | elif [ "$KSU" = true ] && [ "$KSU_VER_CODE" -lt 10670 ]; then 17 | abort "-----------------------------------------------------------" 18 | ui_print "! Please update your KernelSU and KernelSU Manager" 19 | abort "-----------------------------------------------------------" 20 | fi 21 | 22 | service_dir="/data/adb/service.d" 23 | if [ "$KSU" = "true" ]; then 24 | ui_print "— KernelSU version: $KSU_VER ($KSU_VER_CODE)" 25 | [ "$KSU_VER_CODE" -lt 10683 ] && service_dir="/data/adb/ksu/service.d" 26 | elif [ "$APATCH" = "true" ]; then 27 | APATCH_VER=$(cat "/data/adb/ap/version") 28 | ui_print "— APatch version: $APATCH_VER" 29 | else 30 | ui_print "— Magisk version: $MAGISK_VER ($MAGISK_VER_CODE)" 31 | fi 32 | 33 | # Set up service directory and clean old installations 34 | mkdir -p "${service_dir}" 35 | if [ -d "/data/adb/modules/box_for_magisk" ]; then 36 | rm -rf "/data/adb/modules/box_for_magisk" 37 | ui_print "— Old module deleted." 38 | fi 39 | 40 | # Extract files and configure directories 41 | ui_print "— Installing Box for Magisk/KernelSU/APatch" 42 | unzip -o "$ZIPFILE" -x 'META-INF/*' -x 'webroot/*' -d "$MODPATH" >&2 43 | if [ -d "/data/adb/box" ]; then 44 | ui_print "— Backup existing box data" 45 | temp_bak=$(mktemp -d "/data/adb/box/box.XXXXXXXXXX") 46 | temp_dir="${temp_bak}" 47 | mv /data/adb/box/* "${temp_dir}/" 48 | mv "$MODPATH/box/"* /data/adb/box/ 49 | backup_box="true" 50 | else 51 | mv "$MODPATH/box" /data/adb/ 52 | fi 53 | 54 | # Directory creation and file extraction 55 | ui_print "— Create directories..." 56 | mkdir -p /data/adb/box/ /data/adb/box/run/ /data/adb/box/bin/xclash/ 57 | mkdir -p $MODPATH/system/bin 58 | 59 | ui_print "— Extracting..." 60 | ui_print " ↳ uninstall.sh → $MODPATH" 61 | ui_print " ↳ box_service.sh → ${service_dir}" 62 | ui_print " ↳ sbfr → $MODPATH/system/bin" 63 | unzip -j -o "$ZIPFILE" 'uninstall.sh' -d "$MODPATH" >&2 64 | unzip -j -o "$ZIPFILE" 'box_service.sh' -d "${service_dir}" >&2 65 | unzip -j -o "$ZIPFILE" 'sbfr' -d "$MODPATH/system/bin" >&2 66 | 67 | # Set permissions 68 | ui_print "— Setting permissions..." 69 | set_perm_recursive $MODPATH 0 0 0755 0644 70 | set_perm_recursive /data/adb/box/ 0 3005 0755 0644 71 | set_perm_recursive /data/adb/box/scripts/ 0 3005 0755 0700 72 | set_perm ${service_dir}/box_service.sh 0 0 0755 73 | set_perm $MODPATH/uninstall.sh 0 0 0755 74 | set_perm $MODPATH/system/bin/sbfr 0 0 0755 75 | 76 | chmod ugo+x ${service_dir}/box_service.sh $MODPATH/uninstall.sh /data/adb/box/scripts/* 77 | 78 | apply_mirror() { 79 | ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" 80 | ui_print "— Do you want to use the 'ghfast.top' ?" 81 | ui_print " ↳ mirror to speed up downloads" 82 | ui_print "— [ Vol UP(+): Yes ]" 83 | ui_print "— [ Vol DOWN(-): No ]" 84 | START_TIME=$(date +%s) 85 | while true ; do 86 | NOW_TIME=$(date +%s) 87 | timeout 1 getevent -lc 1 2>&1 | grep KEY_VOLUME > "$TMPDIR/events" 88 | if [ $(( NOW_TIME - START_TIME )) -gt 9 ]; then 89 | ui_print "— No input detected after 10 seconds..." 90 | ui_print "— ghfast acceleration enabled." 91 | sed -i 's/use_ghproxy=.*/use_ghproxy="true"/' /data/adb/box/scripts/box.tool 92 | break 93 | elif $(cat $TMPDIR/events | grep -q KEY_VOLUMEUP); then 94 | ui_print "— ghfast acceleration enabled." 95 | sed -i 's/use_ghproxy=.*/use_ghproxy="true"/' /data/adb/box/scripts/box.tool 96 | break 97 | elif $(cat $TMPDIR/events | grep -q KEY_VOLUMEDOWN); then 98 | ui_print "— ghfast acceleration disabled." 99 | sed -i 's/use_ghproxy=.*/use_ghproxy="false"/' /data/adb/box/scripts/box.tool 100 | break 101 | fi 102 | done 103 | } 104 | 105 | apply_mirror 106 | timeout 1 getevent -cl >/dev/null 107 | 108 | find_bin() { 109 | bin_dir="$temp_bak" 110 | 111 | check_bin() { 112 | local name="$1" 113 | local path="$bin_dir/bin/$name" 114 | if [ -e "$path" ]; then 115 | ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" 116 | ui_print "— $name → ⭕ FOUND" 117 | else 118 | ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" 119 | ui_print "— $name → ❌ NOT FOUND" 120 | fi 121 | } 122 | 123 | handle_download() { 124 | local bin="$1" 125 | local action="" 126 | case "$bin" in 127 | yq) action="upyq" ;; 128 | curl) action="upcurl" ;; 129 | *) action="all $bin" ;; 130 | esac 131 | 132 | START_TIME=$(date +%s) 133 | while true; do 134 | NOW_TIME=$(date +%s) 135 | timeout 1 getevent -lc 1 2>&1 | grep KEY_VOLUME > "$TMPDIR/events" 136 | 137 | if [ $(( NOW_TIME - START_TIME )) -gt 9 ]; then 138 | ui_print "— No input detected after 10 seconds..." 139 | if [ "$bin" = "clash" ]; then 140 | ui_print "— Download enabled for clash." 141 | /data/adb/box/scripts/box.tool $action 142 | else 143 | ui_print "— Download disabled for $bin." 144 | fi 145 | break 146 | elif grep -q KEY_VOLUMEUP "$TMPDIR/events"; then 147 | ui_print "— Download enabled." 148 | /data/adb/box/scripts/box.tool $action 149 | break 150 | elif grep -q KEY_VOLUMEDOWN "$TMPDIR/events"; then 151 | ui_print "— Download disabled." 152 | break 153 | fi 154 | done 155 | } 156 | 157 | # List of binaries to check 158 | for bin in yq curl sing-box v2fly xray hysteria; do 159 | timeout 1 getevent -cl >/dev/null 160 | 161 | check_bin "$bin" 162 | ui_print "— Do you want to download or update it?" 163 | ui_print "— [ Vol UP(+): Yes ]" 164 | ui_print "— [ Vol DOWN(-): No ]" 165 | handle_download "$bin" 166 | sleep 1 167 | done 168 | 169 | # Special case for clash 170 | if [ -e "$bin_dir/bin/xclash/mihomo" ]; then 171 | ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" 172 | ui_print "— mihomo → ⭕ FOUND" 173 | ui_print "-- Do you want to download or update clash?" 174 | ui_print "— [ Vol UP(+): Yes ]" 175 | ui_print "— [ Vol DOWN(-): No ]" 176 | handle_download "clash" 177 | else 178 | ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" 179 | ui_print "— mihomo → ❌ NOT FOUND " 180 | ui_print "— Do you want to download or update mihomo?" 181 | ui_print "— [ Vol UP(+): Yes ]" 182 | ui_print "— [ Vol DOWN(-): No ]" 183 | handle_download "clash" 184 | fi 185 | } 186 | 187 | find_bin 188 | timeout 1 getevent -cl >/dev/null 189 | 190 | restore_ini() { 191 | backup_ini="$temp_dir/settings.ini" 192 | target_ini="/data/adb/box/settings.ini" 193 | 194 | # List of keys to restore (separate with spaces) 195 | keys="network_mode bin_name ipv6 xclash_option renew update_subscription subscription_url_clash subscription_url_singbox name_clash_config clash_config name_provide_clash_config clash_provide_path enable_network_service_control use_module_on_wifi_disconnect use_module_on_wifi use_ssid_matching use_wifi_list_mode wifi_ssids_list inotify_log_enabled" 196 | 197 | for key in $keys; do 198 | value=$(grep "^$key=" "$backup_ini") 199 | if [ -n "$value" ]; then 200 | # Escape special characters to make it safe for sed 201 | esc_value=$(printf '%s\n' "$value" | sed -e 's/[&/\]/\\&/g') 202 | 203 | if grep -q "^$key=" "$target_ini"; then 204 | # Replace old line 205 | # sed -i "s|^$key=.*|$value|" "$target_ini" 206 | sed -i "s|^$key=.*|$esc_value|" "$target_ini" 207 | else 208 | # Append at the end of the file 209 | echo "$value" >> "$target_ini" 210 | fi 211 | ui_print "— Restored: $key" 212 | else 213 | ui_print "— Skipped: $key not found in backup" 214 | fi 215 | done 216 | } 217 | 218 | apply_ini() { 219 | ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" 220 | ui_print "— Would you like to restore settings.ini?" 221 | ui_print "— [ Vol UP(+): Yes ]" 222 | ui_print "— [ Vol DOWN(-): No ]" 223 | START_TIME=$(date +%s) 224 | while true ; do 225 | NOW_TIME=$(date +%s) 226 | timeout 1 getevent -lc 1 2>&1 | grep KEY_VOLUME > "$TMPDIR/events" 227 | if [ $(( NOW_TIME - START_TIME )) -gt 9 ]; then 228 | ui_print "— Skipped restoring settings.ini" 229 | break 230 | elif $(cat $TMPDIR/events | grep -q KEY_VOLUMEUP); then 231 | restore_ini 232 | break 233 | elif $(cat $TMPDIR/events | grep -q KEY_VOLUMEDOWN); then 234 | ui_print "— Skipped restoring settings.ini" 235 | break 236 | fi 237 | done 238 | } 239 | 240 | apply_ini 241 | timeout 1 getevent -cl >/dev/null 242 | 243 | # Restore backup configurations if present 244 | if [ "${backup_box}" = "true" ]; then 245 | ui_print "— Restoring configurations..." 246 | ui_print " ↳ xray" 247 | ui_print " ↳ hysteria" 248 | ui_print " ↳ clash" 249 | ui_print " ↳ sing-box" 250 | ui_print " ↳ v2fly" 251 | restore_config() { 252 | config_dir="$1" 253 | [ -d "${temp_dir}/${config_dir}" ] && cp -rf "${temp_dir}/${config_dir}/"* "/data/adb/box/${config_dir}/" 254 | } 255 | for dir in clash xray v2fly sing-box hysteria; do 256 | restore_config "$dir" 257 | done 258 | 259 | restore_kernel() { 260 | kernel_name="$1" 261 | if [ ! -f "/data/adb/box/bin/$kernel_name" ] && [ -f "${temp_dir}/bin/${kernel_name}" ]; then 262 | ui_print "— Restoring kernel ${kernel_name}..." 263 | cp -rf "${temp_dir}/bin/${kernel_name}" "/data/adb/box/bin/${kernel_name}" 264 | fi 265 | } 266 | 267 | for kernel in curl yq xray sing-box v2fly hysteria xclash/mihomo xclash/premium; do 268 | restore_kernel "$kernel" 269 | done 270 | 271 | ui_print "— Restoring..." 272 | ui_print " ↳ *.logs" 273 | ui_print " ↳ box.pid" 274 | ui_print " ↳ uid.list" 275 | cp -rf "${temp_dir}/run/"* "/data/adb/box/run/" 276 | 277 | ui_print "— Restoring..." 278 | ui_print " ↳ ap.list.cfg" 279 | ui_print " ↳ crontab.cfg" 280 | ui_print " ↳ package.list.cfg" 281 | cp -rf "${temp_dir}/ap.list.cfg" "/data/adb/box/ap.list.cfg" 282 | cp -rf "${temp_dir}/crontab.cfg" "/data/adb/box/crontab.cfg" 283 | cp -rf "${temp_dir}/package.list.cfg" "/data/adb/box/package.list.cfg" 284 | fi 285 | 286 | # create_resolv() { 287 | # # Check if the resolv.conf file exists 288 | # if [ ! -f /system/etc/resolv.conf ]; then 289 | # # Ensure the target directory exists before writing the file 290 | # mkdir -p "$MODPATH/system/etc/security/cacerts/" 291 | # # Create resolv.conf with the specified nameservers 292 | # cat > "$MODPATH/system/etc/resolv.conf" <&2 314 | 315 | # Clean up temporary files 316 | ui_print "— Cleaning up leftover files" 317 | rm -rf /data/adb/box/bin/.bin $MODPATH/box $MODPATH/sbfr $MODPATH/box_service.sh 318 | 319 | ui_print "" 320 | # Create a symbolic link to run /dev/sbfr as a shortcut to sbfr 321 | ln -sf "$MODPATH/system/bin/sbfr" /dev/sbfr 322 | ui_print "— Shortcut '/dev/sbfr' created." 323 | ui_print " ↳ You can now run: su -c /dev/sbfr" 324 | ui_print "" 325 | # Complete installation 326 | ui_print "— Installation complete. Please reboot your device." 327 | ui_print "— Report issues to t.me.taamarin" 328 | -------------------------------------------------------------------------------- /box/scripts/box.service: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | # Validate settings.ini 3 | if ! /system/bin/sh -n /data/adb/box/settings.ini 2>"/data/adb/box/run/settings_err.log"; then 4 | echo "Err: settings.ini contains a syntax error" | tee -a "/data/adb/box/run/settings_err.log" 5 | exit 1 6 | fi 7 | 8 | scripts_dir="${0%/*}" 9 | source /data/adb/box/settings.ini 10 | 11 | PROPFILE="/data/adb/modules/box_for_root/module.prop" 12 | log_backup="false" 13 | 14 | box_check_logs() { 15 | ts=$(date '+%Y-%m-%d_%H-%M-%S') 16 | log Info "Cleaning and backing up logs" 17 | 18 | # Backup logs for each bin in bin_list 19 | if [ "${log_backup}" = "true" ]; then 20 | for bin in "${bin_name}"; do 21 | log_file="${box_run}/${bin}.log" 22 | if [ -f "${log_file}" ]; then 23 | mv "${log_file}" "${box_run}/${bin}_$ts.log.bak" 24 | log Info "Backup: ${bin}.log → ${bin}_${ts}.log.bak" 25 | fi 26 | done 27 | fi 28 | 29 | # Remove specific unnecessary files 30 | find "${box_run}" -maxdepth 1 -type f \( -name "root" -o -name "*.list" -o -name "*.inotify.log" \) -exec rm -f {} + 31 | 32 | # Remove old logs (>1 days) 33 | find "${box_run}" -maxdepth 1 -type f \( -name "*.log" -o -name "*.bak" \) -mtime +1 -exec rm -f {} + 34 | } 35 | 36 | box_bin_alive() { 37 | local PID=$(<"${box_pid}" 2>/dev/null) 38 | if ! kill -0 "$PID" >/dev/null; then 39 | log Error "$(<"${box_run}/${bin_name}.log")" 40 | log Error "${bin_name} service is not running." 41 | log Error "please check ${bin_name}.log for more information." 42 | log Error "killing stale pid $PID" 43 | for bin in "${bin_list[@]}"; do 44 | killall -15 "${bin}" >/dev/null || busybox pkill -15 "${bin}" >/dev/null 2>&1 45 | done 46 | "${scripts_dir}/box.iptables" disable >/dev/null 2>&1 47 | [ -f "${box_pid}" ] && rm -f "${box_pid}" 48 | exit 1 49 | else 50 | return 0 51 | fi 52 | } 53 | 54 | box_run_crontab() { 55 | # Stop crond if it is running (optional) 56 | pkill -f "busybox crond" >/dev/null 2>&1 57 | # Prepare crontab 58 | busybox crontab -c "${box_run}" -r 59 | echo "# cron tasks for root" > "${box_run}/root" 60 | 61 | if [ "${run_crontab}" = "true" ]; then 62 | log Debug "crond enable" 63 | if [ "$update_subscription" = "true" ] || [ "$update_geo" = "true" ]; then 64 | if [ -n "${interva_update}" ]; then 65 | log Debug "Crontab interval: ${interva_update}." 66 | echo "${interva_update} ${scripts_dir}/box.tool geosub" >> "${box_run}/root" 67 | log Info "${bin_name} geox updates: ${update_geo}." 68 | if [ "${bin_name}" = "clash" ]; then 69 | log Info "${bin_name} subscription update: ${update_subscription}." 70 | fi 71 | else 72 | log Debug "Crontab interval is empty, skipping Geox & Subscription schedule setup." 73 | fi 74 | fi 75 | cat "${box_dir}/crontab.cfg" >> "${box_run}/root" 76 | chmod 0644 "${box_run}/root" 77 | # start crond with the "-c" option and keep it in the background 78 | nohup busybox crond -c "${box_run}" >/dev/null 2>&1 & 79 | else 80 | log Info "crond disable" 81 | fi 82 | } 83 | 84 | xclash() { 85 | local xclash_option="${xclash_option:-mihomo}" 86 | # default to "mihomo" if xclash_option is not set 87 | current_clash="$(readlink "${bin_dir}/clash")" 88 | 89 | if [ "$current_clash" != "${bin_dir}/xclash/${xclash_option}" ]; then 90 | if [ -f "${bin_dir}/xclash/${xclash_option}" ]; then 91 | if ! ln -sf "${bin_dir}/xclash/${xclash_option}" "${bin_dir}/clash"; then 92 | log Error "Failed to use ${xclash_option}" 93 | return 1 94 | fi 95 | else 96 | mkdir -p "${bin_dir}/xclash" 97 | log Error "${bin_dir}/xclash/${xclash_option} file not found" 98 | return 1 99 | fi 100 | fi 101 | log Info "xclash [ $xclash_option ] setup completed" 102 | return 0 103 | } 104 | 105 | box_ownership() { 106 | # Set ownership and permission of kernel directory 107 | chown -R ${box_user_group} ${box_dir} 108 | chmod -R 644 ${box_dir}/${bin_name} 109 | 110 | chown ${box_user_group} ${bin_path} 111 | chmod 6755 ${bin_path} 112 | 113 | chmod 0700 ${box_dir}/bin/yq 114 | chmod 0700 ${box_dir}/bin/curl 115 | } 116 | 117 | box_permission() { 118 | if [[ "${box_user_group}" == @(root:net_admin|0:3005) && -f "${bin_path}" ]]; then 119 | # Set ownership and permission of kernel directory 120 | box_ownership 121 | log Info "Using kernel in ${bin_path}." 122 | else 123 | if [[ "${box_user_group}" != @(root:net_admin|0:3005) ]]; then 124 | log Error "does't support user_group [ $box_user_group ]" 125 | sed -i "s/box_user_group=.*/box_user_group=\"root:net_admin\"/g" ${settings} 126 | log Debug "automatically changed to [ root:net_admin ], restart box" 127 | exit 1 128 | fi 129 | log Error "Kernel [ ${bin_name} ] is missing." 130 | log Error "Please download the [ ${bin_name} ] kernel and place it in the ${bin_dir}/ directory." 131 | log Debug "exec 'su -c /data/adb/box/scripts/box.tool upkernel' in terminal" 132 | exit 1 133 | fi 134 | } 135 | 136 | box_check_bin() { 137 | if [ ! -x "${bin_path}" ]; then 138 | log Error "${bin_path} is not executable." 139 | exit 1 140 | fi 141 | 142 | local version_output 143 | case "${bin_name}" in 144 | clash) 145 | version_output=$("${bin_path}" -v 2>/dev/null) || { 146 | log Error "${bin_name} version information not available." 147 | exit 1 148 | } 149 | ;; 150 | *) 151 | version_output=$("${bin_path}" version 2>/dev/null) || { 152 | log Error "${bin_name} version information not available." 153 | exit 1 154 | } 155 | ;; 156 | esac 157 | 158 | log Info "${version_output}" 159 | } 160 | 161 | # create_tun_link() { 162 | # mkdir -p /dev/net 163 | # [ ! -L /dev/net/tun ] && ln -s /dev/tun /dev/net/tun 164 | 165 | # if [ ! -c "/dev/net/tun" ]; then 166 | # log Error "Cannot create /dev/net/tun. Possible reasons:" 167 | # log Warning "Your system does not support the TUN/TAP driver." 168 | # log Warning "Your system kernel version is not compatible with the TUN/TAP driver." 169 | # sed -i 's/network_mode=.*/network_mode="tproxy"/g' "${settings}" 170 | # exit 1 171 | # fi 172 | # } 173 | 174 | prepare_singbox() { 175 | # Check configuration file 176 | if ! [ -f "${sing_config}" ]; then 177 | log Error "Configuration file ${sing_config} not found" 178 | exit 1 179 | else 180 | log Info "Config ${sing_config} found" 181 | fi 182 | 183 | # Check yq 184 | yq="yq" 185 | if ! command -v yq &>/dev/null; then 186 | if [ ! -e "${box_dir}/bin/yq" ]; then 187 | log Debug "yq file not found, starting download from GitHub" 188 | ${scripts_dir}/box.tool upyq 189 | fi 190 | yq="${box_dir}/bin/yq" 191 | fi 192 | 193 | # Set auto_detect_interface/auto_route 194 | ${yq} '.route.auto_detect_interface = true' -i --output-format=json "${sing_config}" 195 | ${yq} '(.inbounds[] | select(.type == "tun") | .auto_route) |= true' -i --output-format=json "${sing_config}" 196 | 197 | # Format sing-box configuration 198 | if ${bin_path} format -w -D "${box_dir}/${bin_name}" -C "${box_dir}/${bin_name}" > "${box_run}/${bin_name}.log" 2>&1; then 199 | # Set auto_route based on network_mode 200 | if [[ "${network_mode}" == @(mixed|tun) ]]; then 201 | # Check if "type" is "tun" in configuration 202 | if ! busybox grep -q '"type": "tun"' "${sing_config}"; then 203 | # Add "tun" configuration if missing 204 | ${yq} '.inbounds += [{ 205 | "type": "tun", 206 | "tag": "tun-in", 207 | "interface_name": "sing", 208 | "address": ["172.18.0.1/30","fdfe:dcba:9876::1/126"], 209 | "mtu": 9000, 210 | "stack": "mixed", 211 | "auto_route": true, 212 | "strict_route": true, 213 | "auto_redirect": true, 214 | "include_android_user": [0,10,999], 215 | "include_package": [], 216 | "exclude_package": [] 217 | }]' -i --output-format=json "${sing_config}" 218 | log Debug "[Tun] configuration added to ${sing_config}" 219 | fi 220 | else 221 | # Set auto_route to false for non-"tun" network_mode 222 | sed -i 's/auto_route": true/auto_route": false/g' "${box_dir}/sing-box/"*.json 223 | # Set auto_detect_interface to false 224 | sed -i 's/"auto_detect_interface": true/"auto_detect_interface": false/g' "${box_dir}/sing-box/"*.json 225 | 226 | # Check if "type" is "tproxy" in configuration 227 | if ! busybox grep -q '"type": "tproxy"' "${sing_config}"; then 228 | # Add "tproxy" configuration if missing 229 | ${yq} '.inbounds += [{ 230 | "type": "tproxy", 231 | "tag": "tproxy-in", 232 | "listen": "::", 233 | "listen_port": '"${tproxy_port}"' 234 | }]' -i --output-format=json "${sing_config}" 235 | log Debug "[Tproxy] configuration added to ${sing_config}" 236 | fi 237 | 238 | # del tun 239 | ${yq} 'del(.inbounds[] | select(.type == "tun"))' -i --output-format=json "${sing_config}" 240 | 241 | # Sync tproxy port in sing-box configuration 242 | for file in "${box_dir}/sing-box/"*.json; do 243 | if busybox grep -q '"type": "tproxy"' "${file}"; then 244 | ${yq} '(.inbounds[] | select(.type == "tproxy") | .listen_port) = '"${tproxy_port}" -i --output-format=json "${file}" 245 | fi 246 | done 247 | fi 248 | 249 | # add exclude_package/include_package for tun 250 | "${yq}" '(.inbounds[] | select(.type == "tun") | .include_package) = []' -i --output-format=json "${sing_config}" 251 | "${yq}" '(.inbounds[] | select(.type == "tun") | .exclude_package) = []' -i --output-format=json "${sing_config}" 252 | [[ ${proxy_mode} = "blacklist" || ${proxy_mode} = "black" ]] && mode="exclude" || mode="include" 253 | 254 | # Clean up the "0:" prefix and insert one by one into the config 255 | for raw in "${packages_list[@]}"; do 256 | package=$(echo "$raw" | cut -d':' -f2) 257 | "${yq}" eval '(.inbounds[] | select(.type == "tun") | .'${mode}'_package) += ["'${package}'"]' -i --output-format=json "${sing_config}" 258 | done 259 | 260 | # Add "redirect" configuration based on network_mode 261 | if [[ "${network_mode}" == @(mixed|enhance|redirect) ]]; then 262 | if ! busybox grep -q '"type": "redirect"' "${sing_config}"; then 263 | # Add "redirect" configuration if missing 264 | ${yq} '.inbounds += [{ 265 | "type": "redirect", 266 | "tag": "redirect-in", 267 | "listen": "::", 268 | "listen_port": '"${redir_port}"' 269 | }]' -i --output-format=json "${sing_config}" 270 | log Debug "[Redirect] configuration added to ${sing_config}" 271 | fi 272 | 273 | # Sync redir_port port in sing-box configuration 274 | for file in "${box_dir}/sing-box/"*.json; do 275 | if busybox grep -q '"type": "redirect"' "${file}"; then 276 | ${yq} '(.inbounds[] | select(.type == "redirect") | .listen_port) = '"${redir_port}" -i --output-format=json "${file}" 277 | fi 278 | done 279 | fi 280 | else 281 | log Error "$(<"${box_run}/${bin_name}.log")" 282 | log Error "Configuration failed. Please check the ${box_run}/${bin_name}.log file." 283 | exit 1 284 | fi 285 | } 286 | 287 | prepare_clash() { 288 | # check configuration file 289 | if ! [ -f "${clash_config}" ]; then 290 | log Error "configuration file ${clash_config} not found" 291 | exit 1 292 | else 293 | log Info "config ${clash_config}" 294 | fi 295 | 296 | # ipv6=$(busybox awk '/ipv6:/ { print $2; found=1; exit } END{ if(!found) print "false" }' "${clash_config}" | head -n 1 2>/dev/null) 297 | # sed -i "s/ipv6=.*/ipv6=\"${ipv6}\"/g" ${settings} 298 | # sed -i "s/ipv6:.*/ipv6: ${ipv6}/g" "${clash_config}" 299 | 300 | # write external_controller, if not in $clash_config 301 | clash_external_controller=$(busybox awk '!/^ *#/ && /external-controller: /{print $1}' "${clash_config}") 302 | if [ -z "${clash_external_controller}" ]; then 303 | printf "\nexternal-controller: 0.0.0.0:9090" >> "${clash_config}" 304 | fi 305 | 306 | # write external_ui, if not in $clash_config 307 | clash_external_ui=$(busybox awk '!/^ *#/ && /external-ui: /{print $1}' "${clash_config}") 308 | if [ -z "${clash_external_ui}" ]; then 309 | printf "\nexternal-ui: ./dashboard" >> "${clash_config}" 310 | fi 311 | 312 | # write tproxy-port, if not in $clash_config 313 | clash_tproxy_port=$(busybox awk '!/^ *#/ && /tproxy-port: /{print $1}' "${clash_config}") 314 | if [ -z "${clash_tproxy_port}" ]; then 315 | printf "\ntproxy-port: ${tproxy_port}" >> "${clash_config}" 316 | fi 317 | 318 | # write redir-port, if not in $clash_config 319 | clash_redir_port=$(busybox awk '!/^ *#/ && /redir-port: /{print $1}' "${clash_config}") 320 | if [ -z "${clash_redir_port}" ]; then 321 | printf "\nredir-port: ${redir_port}" >> "${clash_config}" 322 | fi 323 | 324 | if [[ "${network_mode}" == @(mixed|tun) ]]; then 325 | clash_tun_status=$(busybox awk '!/^ *#/ && /tun:/ { getline; split($0, arr, ": "); print arr[2]; found=1; exit } END{ if (!found) print "" }' "${clash_config}" 2>/dev/null) 326 | # write TUN settings, if not in $clash_config 327 | if [ -z "${clash_tun_status}" ]; then 328 | printf '%s\n' '' 'tun:' \ 329 | ' enable: true' \ 330 | ' mtu: 9000' \ 331 | ' device: meta' \ 332 | ' stack: mixed # / gvisor / system' \ 333 | ' dns-hijack:' \ 334 | ' - any:53' \ 335 | ' - tcp://any:53' \ 336 | ' auto-route: true' \ 337 | ' strict-route: true' \ 338 | ' auto-redirect: true' \ 339 | ' auto-detect-interface: true' \ 340 | ' include-android-user: [0, 10, 999]' \ 341 | ' exclude-package: []' \ 342 | ' include-package: []' \ >> "${clash_config}" 343 | log Debug "[tun] configuration has been added to ${clash_config}" 344 | else 345 | log Info "type [tun] already exists in ${clash_config}" 346 | fi 347 | 348 | # add exclude-package/include-package for tun 349 | package=$(IFS=","; echo "${packages_list[*]}" | tr ' ' ',') 350 | list_package="${package}" 351 | 352 | if [[ "${proxy_mode}" = "whitelist" || "${proxy_mode}" = "white" ]]; then 353 | mode="include" 354 | elif [[ "${proxy_mode}" = "blacklist" || "${proxy_mode}" = "black" ]]; then 355 | mode="exclude" 356 | fi 357 | 358 | # Check if include-package is inside a tun block: 359 | include_package_found=$(busybox awk '/^tun:/{f=1} f && /'"$mode-package:"'/{print $0; exit}' "$clash_config") 360 | if [ -z "$include_package_found" ]; then 361 | sed -i "/^tun:/a \ $mode-package: []" "$clash_config" 362 | fi 363 | 364 | sed -i "s/exclude-package:.*/exclude-package: []/g" "${clash_config}" 365 | sed -i "s/include-package:.*/include-package: []/g" "${clash_config}" 366 | 367 | if [ -n "${list_package}" ]; then 368 | list_package_clean=$(echo "$list_package" | sed 's/999://g' | sed 's/10://g' | sed 's/0://g' | busybox paste -sd, -) 369 | 370 | # list_package_clean=$(echo "$list_package" | sed 's/999://g' | sed 's/10://g' | sed 's/0://g' | tr '\n' ',' | sed 's/,$//') 371 | 372 | sed -i "s/${mode}-package:.*/${mode}-package: [\"${list_package_clean//,/\",\"}\"]/g" "${clash_config}" 373 | fi 374 | 375 | sed -i "/tun:/,/enable:/ { /enable: false/ s/enable: false/enable: true/ }" "${clash_config}" 376 | else 377 | sed -i "/tun:/,/enable:/ { /enable: true/ s/enable: true/enable: false/ }" "${clash_config}" 378 | fi 379 | 380 | # sync tproxy/redir port 381 | sed -i -E "s/(tproxy-port: )[0-9]+/\1${tproxy_port}/" "${clash_config}" 382 | sed -i -E "s/(redir-port: )[0-9]+/\1${redir_port}/" "${clash_config}" 383 | 384 | clash_enhanced_mode=$(busybox awk '!/^ *#/ && /enhanced-mode: / { print $2 }' "${clash_config}" 2>/dev/null) 385 | if [ -z "${clash_enhanced_mode}" ]; then 386 | # Add enhanced-mode: fake-ip 387 | sed -i "/^dns:/a \ enhanced-mode: fake-ip" "$clash_config" 388 | log Debug "enhanced-mode: fake-ip add success" 389 | fi 390 | 391 | if [[ "${network_mode}" == @(mixed|tproxy|redirect|enhance) ]]; then 392 | if [[ -n "${packages_list[*]}" || -n "${ignore_out_list[*]}" || -n "${gid_list[*]}" ]] && [ "${clash_enhanced_mode}" = "fake-ip" ]; then 393 | log Warning "${proxy_mode} Only works in enhanced-mode: redir-host xclash[mihomo]" 394 | log Warning "replace fake-ip to redir-host in clash config" 395 | sed -i "s/enhanced-mode:.*/enhanced-mode: redir-host/g" "${clash_config}" 396 | sed -i "/sniffer:/,/enable:/ { /enable: false/ s/enable: false/enable: true/ }" "${clash_config}" 397 | fi 398 | fi 399 | } 400 | 401 | prop_description() { 402 | sed -Ei "s/^description=(\[.*][[:space:]]*)?/description=[ $current_time | ⚠️ Your $bin_name configuration has an error, check the log for more details ] /g" "$PROPFILE" 403 | } 404 | 405 | box_run_bin() { 406 | log Info "client-list: [ ${bin_list[*]} ]" 407 | log Info "choose: ${bin_name}, start the service." 408 | ulimit -SHn 1000000 409 | # Use ulimit to limit the memory usage of a process to 200MB 410 | # ulimit -v 200000 # Set the virtual memory limit in KB 411 | case "${bin_name}" in 412 | hysteria) 413 | # sync port 414 | if [ -f "${hysteria_config}" ]; then 415 | sed -i -e "/tcpTProxy:/,/listen:/s/listen: :.*/listen: :${tproxy_port}/" "${hysteria_config}" 416 | sed -i -e "/udpTProxy:/,/listen:/s/listen: :.*/listen: :${tproxy_port}/" "${hysteria_config}" 417 | sed -i -e "/tcpRedirect:/,/listen:/s/listen: :.*/listen: :${redir_port}/" "${hysteria_config}" 418 | fi 419 | 420 | case "${network_mode}" in 421 | redirect|tproxy|enhance) 422 | # do nothing 423 | ;; 424 | *) 425 | sed -i 's/\(network_mode=\)\"[^\"]*\"/\1"tproxy"/g' ${settings} 426 | ;; 427 | esac 428 | 429 | nohup busybox setuidgid "${box_user_group}" "${bin_path}" -c "${hysteria_config}" > "${bin_log}" 2>&1 & 430 | PID=$! 431 | 432 | sleep 1 433 | 434 | # Cek apakah proses benar-benar berjalan 435 | if kill -0 "${PID}" 2>/dev/null; then 436 | echo -n "${PID}" > "${box_pid}" 437 | else 438 | prop_description 439 | log Error "$(cat "${box_run}/${bin_name}.log")" 440 | log Error "Configuration failed. Please check the log file: ${box_run}/${bin_name}.log" 441 | exit 1 442 | fi 443 | ;; 444 | sing-box) 445 | prepare_singbox 446 | if ${bin_path} check -D "${box_dir}/${bin_name}" -c "${sing_config}" > "${box_run}/${bin_name}.log" 2>&1; then 447 | nohup busybox setuidgid "${box_user_group}" "${bin_path}" run -D "${box_dir}/${bin_name}" -c "${sing_config}" > "${bin_log}" 2>&1 & 448 | PID=$! 449 | echo -n $PID > "${box_pid}" 450 | sleep 1 451 | else 452 | prop_description 453 | log Error "$(<"${box_run}/${bin_name}.log")" 454 | log Error "configuration failed. Please check the ${box_run}/${bin_name}.log file." 455 | exit 1 456 | fi 457 | ;; 458 | clash) 459 | prepare_clash 460 | if ${bin_path} -t -d "${box_dir}/${bin_name}" -f "${clash_config}" > "${box_run}/${bin_name}.log" 2>&1; then 461 | nohup busybox setuidgid "${box_user_group}" "${bin_path}" -d "${box_dir}/${bin_name}" -f "${clash_config}" > "${bin_log}" 2>&1 & 462 | PID=$! 463 | echo -n $PID > "${box_pid}" 464 | sleep 1 465 | else 466 | prop_description 467 | log Error "$(<"${box_run}/${bin_name}.log")" 468 | log Error "configuration failed. Please check the ${box_run}/${bin_name}.log file." 469 | exit 1 470 | fi 471 | ;; 472 | xray) 473 | # set network_mode variable value to "tproxy" 474 | if [[ "${network_mode}" != "tproxy" ]]; then 475 | sed -i 's/\(network_mode=\)\"[^\"]*\"/\1"tproxy"/g' ${settings} 476 | fi 477 | 478 | # check configuration file 479 | if [ ! -f "${xray_config}" ]; then 480 | log Error "No configuration file found in ${xray_config}" 481 | exit 1 482 | else 483 | # sync port 484 | if [[ "${xray_config}" == *.yaml ]]; then 485 | ${box_dir}/bin/yq '(.inbounds[] | select(.protocol == "dokodemo-door") | .port) = '"${tproxy_port}"'' -i --output-format=yaml "${xray_config}" >/dev/null 2>&1 486 | elif [[ "${xray_config}" == *.json ]]; then 487 | ${box_dir}/bin/yq '(.inbounds[] | select(.protocol == "dokodemo-door") | select(.tag == "tproxy-in") | .port) = '"${tproxy_port}" -i --output-format=json "${xray_config}" >/dev/null 2>&1 488 | fi 489 | log Info "Configuration file located in ${xray_config}" 490 | fi 491 | 492 | # run xray 493 | export XRAY_LOCATION_ASSET="${box_dir}/${bin_name}" 494 | if ${bin_path} -test -confdir "${box_dir}/${bin_name}" > "${box_run}/${bin_name}.log" 2>&1; then 495 | nohup busybox setuidgid "${box_user_group}" "${bin_path}" run -confdir "${box_dir}/${bin_name}" > "${bin_log}" 2>&1 & 496 | PID=$! 497 | echo -n $PID > "${box_pid}" 498 | sleep 1 499 | else 500 | prop_description 501 | log Error "$(<"${box_run}/${bin_name}.log")" 502 | log Error "configuration failed. Please check the ${box_run}/${bin_name}.log file." 503 | exit 1 504 | fi 505 | ;; 506 | v2fly) 507 | # set network_mode variable value to "tproxy" 508 | if [[ "${network_mode}" != "tproxy" ]]; then 509 | sed -i 's/\(network_mode=\)\"[^\"]*\"/\1"tproxy"/g' ${settings} 510 | fi 511 | 512 | # check configuration file 513 | if [ ! -f "${v2fly_config}" ]; then 514 | log Error "No configuration file found in ${v2fly_config}" 515 | exit 1 516 | else 517 | # sync port 518 | if [[ "${v2fly_config}" == *.yaml ]]; then 519 | ${box_dir}/bin/yq '(.inbounds[] | select(.protocol == "dokodemo-door") | .port) = '"${tproxy_port}"'' -i --output-format=yaml "${v2fly_config}" >/dev/null 2>&1 520 | elif [[ "${v2fly_config}" == *.json ]]; then 521 | ${box_dir}/bin/yq '(.inbounds[] | select(.protocol == "dokodemo-door") | select(.tag == "tproxy-in") | .port) = '"${tproxy_port}" -i --output-format=json "${v2fly_config}" >/dev/null 2>&1 522 | fi 523 | log Info "Configuration file located in ${v2fly_config}" 524 | fi 525 | 526 | # run v2ray 527 | export V2RAY_LOCATION_ASSET="${box_dir}/${bin_name}" 528 | if ${bin_path} test -d "${box_dir}/${bin_name}" > "${box_run}/${bin_name}.log" 2>&1; then 529 | nohup busybox setuidgid "${box_user_group}" "${bin_path}" run -d "${box_dir}/${bin_name}" > "${bin_log}" 2>&1 & 530 | PID=$! 531 | echo -n $PID > "${box_pid}" 532 | sleep 1 533 | else 534 | prop_description 535 | log Error "$(<"${box_run}/${bin_name}.log")" 536 | log Error "configuration failed. Please check the ${box_run}/${bin_name}.log file." 537 | exit 1 538 | fi 539 | ;; 540 | *) 541 | log Error "[ ${bin_name} ] unknown binary." 542 | exit 1 543 | ;; 544 | esac 545 | } 546 | 547 | box_cgroup() { 548 | set_cgroup_config() { 549 | local cgroup_attr="$1" 550 | local cgroup_value="$2" 551 | 552 | if [ "${cgroup_value}" = "true" ]; then 553 | if ${scripts_dir}/box.tool "${cgroup_attr}"; then 554 | true 555 | else 556 | log Warning "failed to enable ${cgroup_attr} for ${bin_name}." 557 | log Warning "cgroups ${cgroup_attr} is turned off" 558 | sed -i -E "/cgroup_${cgroup_attr}/ s/(true)/false/" "${settings}" 559 | fi 560 | fi 561 | } 562 | set_cgroup_config "memcg" "${cgroup_memcg}" 563 | set_cgroup_config "cpuset" "${cgroup_cpuset}" 564 | set_cgroup_config "blkio" "${cgroup_blkio}" 565 | } 566 | 567 | # Function to display the usage of a binary 568 | # This script retrieves information about a running binary process and logs it to a log file. 569 | box_bin_status() { 570 | # Get the process ID of the binary 571 | local PID=$(busybox pidof ${bin_name}) 572 | 573 | if [ -z "$PID" ]; then 574 | log Error "${bin_name} is not running." 575 | return 1 576 | fi 577 | 578 | stack=$(if [ "${bin_name}" != "clash" ]; then find "/data/adb/box/sing-box" -type f -name "*.json" -exec busybox awk -F'"' '/"stack"/{print $4}' {} +; else busybox awk '!/^ *#/ && /stack: / { print $2;found=1; exit}' "${clash_config}"; fi) 579 | TOAST=1 log Info "${bin_name} service is running." 580 | 581 | log Info "proxy: ${proxy_mode} + network: ${network_mode} + $(if [[ "${network_mode}" == @(mixed|tun) ]]; then echo "stack: ${stack}"; fi)" 582 | 583 | # Get the memory usage of the binary 584 | rss=$(grep VmRSS /proc/$PID/status | busybox awk '{ print $2 }') 585 | [ "${rss}" -ge 1024 ] && bin_rss="$(expr ${rss} / 1024) MB" || bin_rss="${rss} KB" 586 | swap=$(grep VmSwap /proc/$PID/status | busybox awk '{ print $2 }') 587 | [ "${swap}" -ge 1024 ] && bin_swap="$(expr ${swap} / 1024) MB" || bin_swap="${swap} KB" 588 | 589 | # Get the state of the binary 590 | state=$(grep State /proc/$PID/status | busybox awk '{ print $2" "$3 }') 591 | 592 | # Get the user and group of the binary 593 | user_group=$(stat -c %U:%G /proc/$PID) 594 | 595 | # Log the information 596 | log Info "${bin_name} has started with the '${user_group}' user group." 597 | log Info "${bin_name} status: ${state} (PID: $PID)" 598 | log Info "${bin_name} memory usage: ${bin_rss}, swap: ${bin_swap}" 599 | 600 | # Get the CPU usage of the binary 601 | cpu=$(ps -p $PID -o %cpu | busybox awk 'NR==2{print $1}' 2>/dev/null) 602 | 603 | cpus_allowed=$(grep Cpus_allowed_list /proc/$PID/status | busybox awk '{ print $2" "$3 }') 604 | core=$(busybox awk '{print $39}' /proc/$PID/stat 2>/dev/null) 605 | 606 | if [ -n "${cpu}" ]; then 607 | log Info "${bin_name} CPU usage: ${cpu}%" 608 | else 609 | log Info "${bin_name} CPU usage: not available" 610 | fi 611 | if [ -n "${cpus_allowed}" ]; then 612 | log Info "${bin_name} list of allowed CPUs : ${cpus_allowed}" 613 | log Info "${bin_name} process $PID last ran on CPU core: ${core}" 614 | else 615 | log Info "${bin_name} Which CPU running on : not available" 616 | fi 617 | 618 | # Check battery temperature 619 | temperature_celsius=$(($(cat /sys/class/power_supply/battery/temp) / 10)) 620 | log Info "battery temperature: ${temperature_celsius}°C" 621 | 622 | # Get the running time of the binary 623 | running_time=$(busybox ps -o comm,etime | grep ${bin_name} | busybox awk '{print $2}') 624 | if [ -n "${running_time}" ]; then 625 | log Info "${bin_name} running time: ${running_time}" 626 | else 627 | log Info "${bin_name} running time: not available." 628 | fi 629 | # local IP 630 | localIP=($(ip -4 a | awk '/inet / && !/127.0.0.1/ { split($2, a, "/"); print a[1] }')) 631 | log Info "local IP: ${localIP[*]}" 632 | # local DNS 633 | localDNS=($(dumpsys connectivity | awk -F'[ ,]' '/DnsAddresses:/ { for (i=1; i<=NF; i++) if ($i ~ /^\/.*$/) print substr($i, 2) }' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | sort -u)) 634 | log Info "local DNS: ${localDNS[*]}" 635 | 636 | # Save the process ID to the pid file 637 | if [ -n "$PID" ]; then 638 | sed -Ei "s/^description=(\[.*][[:space:]]*)?/description=[ $current_time | ⭕ $bin_name service is running!!! ] /g" "$PROPFILE" 639 | echo -n "$PID" > "${box_pid}" 640 | fi 641 | } 642 | 643 | start_box() { 644 | # Clear the log file and add the timestamp and delimiter 645 | # cd /data/adb/box/bin; chmod 755 * 646 | sed -Ei "s/^description=(\[.*][[:space:]]*)?/description=[ $current_time | ⚠️ Module is working! but no service is running ] /g" "$PROPFILE" 647 | 648 | echo -n "" > "${box_log}" 649 | box_version=$(busybox awk '!/^ *#/ && /version=/ { print $0 }' "/data/adb/modules/box_for_root/module.prop" 2>/dev/null) 650 | 651 | if [ -t 1 ]; then 652 | echo -e "${yellow}$(getprop persist.sys.timezone) $(date)${normal}" 653 | echo -e "${yellow}$(getprop gsm.sim.operator.alpha) $(getprop gsm.network.type)${normal}" 654 | echo -e "${yellow}${box_version}($(getprop ro.product.cpu.abi))${normal}" 655 | echo -e "${white}━━━━━━━━━━━━━━━━━━${normal}" 656 | else 657 | { 658 | echo "$(getprop persist.sys.timezone) $(date)" 659 | echo "$(getprop gsm.sim.operator.alpha) $(getprop gsm.network.type)" 660 | echo "${box_version}($(getprop ro.product.cpu.abi))" 661 | echo "━━━━━━━━━━━━━━━━━━" 662 | } | tee -a "${box_log}" >/dev/null 2>&1 663 | fi 664 | 665 | # Update iptables if bin_name is still running 666 | # PIDS=("clash" "xray" "sing-box" "v2fly") 667 | PIDS=("${bin_list[@]}") 668 | PID="" 669 | i=0 670 | 671 | while [ -z "$PID" ] && [ "$i" -lt "${#PIDS[@]}" ]; do 672 | PID=$(busybox pidof "${PIDS[$i]}") 673 | i=$((i+1)) 674 | done 675 | 676 | if [ -n "$PID" ]; then 677 | pid_name="${box_dir}/run/pid_name.txt" 678 | ps -p $PID -o comm= > "${pid_name}" 679 | sed -i '/^[[:space:]]*$/d' "${pid_name}" 680 | log Debug "$(<"${pid_name}")(PID: $PID) service is still running, auto restart BOX." 681 | rm -f "${pid_name}" 682 | stop_box 683 | start_box && "${scripts_dir}/box.iptables" renew 684 | exit 1 685 | fi 686 | 687 | # Checks if bin_name is defined 688 | case "${bin_name}" in 689 | clash|xray|sing-box|v2fly|hysteria) 690 | log Info "Good day" 691 | [ "${bin_name}" = "clash" ] && { 692 | xclash || exit 1 693 | } 694 | ;; 695 | *) 696 | log Error "bin_name: [ ${bin_name} ] unknown not defined." 697 | exit 1 698 | ;; 699 | esac 700 | 701 | # apk manager check 702 | # versionName=$(dumpsys package xyz.chz.bfm | grep versionName | busybox awk -F '=' '{print $2}' | sed 's/-.*//') 703 | # if [[ -n "${versionName}" && $(echo "${versionName}" | busybox awk '{print ($1 < 1.13)}') -eq 1 ]]; then 704 | # log Error "Update BFR Manager Apps, Use version 1.13.+" 705 | # log Error "current version: ${versionName}" 706 | # exit 1 707 | # else 708 | # [ -n "${versionName}" ] && log Info "BFR Manager: ${versionName}" 709 | # fi 710 | 711 | # busybox check 712 | busybox_code=$(busybox | busybox grep -oE '[0-9.]*' | head -n 1) 713 | if [ "$(echo "${busybox_code}" | busybox awk -F. '{printf "%03d%03d%03d\n", $1, $2, $3}')" -lt "$(echo "1.36.1" | busybox awk -F. '{printf "%03d%03d%03d\n", $1, $2, $3}')" ]; then 714 | log Info "Current $(which busybox) v${busybox_code}" 715 | log Warning "Please update your busybox to v1.36.1+" 716 | else 717 | log Info "Current $(which busybox) v${busybox_code}" 718 | fi 719 | 720 | # Check permissions, check for bin existence, delete old logs, create a TUN if necessary, run box, and wait for 1 second 721 | box_permission 722 | box_check_bin 723 | box_check_logs 724 | 725 | # Execute the create_tun_link functions 726 | # if [[ "${network_mode}" == @(mixed|tun) ]]; then 727 | # create_tun_link 728 | # fi 729 | 730 | # Execute box_run_crontab if run_crontab is not equal to "false" 731 | [ "${run_crontab}" = "true" ] && box_run_crontab || log Info "crontab disabled." 732 | 733 | if [ -z "${proxy_mode}" ]; then 734 | M1=$(busybox awk '!/^ *#/ && /mode:/{print $0}' "${pkg_config}") 735 | [ -z $M1 ] && printf "\nmode:white" >> "${pkg_config}" 736 | log Debug "prox mode is empty, add mode:white in ${pkg_config}" 737 | fi 738 | 739 | # Execute the box_cgroup, box_run_bin, box_detected_port, box_bin_alive,box_bin_status functions 740 | box_run_bin 741 | box_cgroup 742 | 743 | count=0 744 | while [ $count -le 10 ]; do 745 | sleep 0.17 746 | box_bin_alive || break 747 | count=$((count + 1)) 748 | done 749 | box_bin_status 750 | 751 | # OOM Killer 752 | # box_pid=$(cat ${box_pid}) 753 | # # Setting oom_adj 754 | # echo -17 > /proc/$box_pid/oom_adj 755 | # if [ $? -eq 0 ]; then 756 | # log Info "set oom_adj for PID $box_pid to -17" 757 | # else 758 | # log Error "failed to set oom_adj for PID $box_pid" 759 | # fi 760 | # # Setting process priorities 761 | # renice -n -20 -p $box_pid 762 | # if [ $? -eq 0 ]; then 763 | # log Info "set priority for PID $box_pid to -20" 764 | # else 765 | # log Error "failed to set priority for PID $box_pid" 766 | # fi 767 | 768 | true 769 | } 770 | 771 | stop_box() { 772 | stop_cron 773 | # Kill each binary using a loop 774 | for bin in "${bin_list[@]}"; do 775 | # Check if the binary is running using pgrep 776 | if busybox pgrep "${bin}" >/dev/null; then 777 | # Use `busybox pkill` to kill the binary with signal 15, otherwise use `killall`. 778 | if busybox pkill -15 "${bin}" >/dev/null; then 779 | : # Do nothing if busybox pkill is successful 780 | else 781 | killall -15 "${bin}" >/dev/null || kill -15 "$(busybox pidof "${bin}")" >/dev/null 2>&1 782 | fi 783 | fi 784 | done 785 | # Check if the binary has stopped 786 | sleep 0.5 787 | if ! busybox pidof "${bin_name}" >/dev/null; then 788 | # Delete the `box.pid` file if it exists 789 | if [ -f "${box_pid}" ]; then 790 | rm -f "${box_pid}" 791 | fi 792 | log Warning "${bin_name} shutting down, service is stopped." 793 | TOAST=1 log Warning "${bin_name} disconnected." 794 | 795 | [ -t 1 ] && echo -e "${white}━━━━━━━━━━━━━━━━━━${normal}" 796 | else 797 | log Warning "${bin_name} Not stopped; may still be shutting down or failed to shut down." 798 | force_stop 799 | fi 800 | 801 | sed -Ei "s/^description=(\[.*][[:space:]]*)?/description=[ $current_time | ❌ $bin_name shutting down, service is stopped !!! ] /g" "$PROPFILE" 802 | } 803 | 804 | stop_cron() { 805 | # Stop crond with pkill 806 | if ! busybox pkill -f "busybox crond" >/dev/null; then 807 | # If pkill fails, find and kill the process 808 | cronkill=$(busybox pgrep -f "crond -c ${box_run}") 809 | for cron in ${cronkill[@]}; do 810 | kill -15 "${cron}" >/dev/null 2>&1 811 | done 812 | fi 813 | } 814 | 815 | force_stop() { 816 | # try forcing it to shut down. 817 | log Warning "try forcing it to shut down." 818 | for bin in "${bin_list[@]}"; do 819 | # Use `busybox pkill` to kill the binary with signal 9, otherwise use `killall`. 820 | if busybox pkill -9 "${bin}"; then 821 | : # Do nothing if busybox pkill is successful 822 | else 823 | if command -v killall >/dev/null; then 824 | killall -9 "${bin}" >/dev/null || true 825 | else 826 | pkill -9 "${bin}" >/dev/null || true 827 | fi 828 | fi 829 | done 830 | sleep 0.5 831 | if ! busybox pidof "${bin_name}" >/dev/null; then 832 | log Warning "done, YOU can sleep peacefully." 833 | rm -f "${box_pid}" 834 | fi 835 | } 836 | 837 | # Check whether busybox is installed or not on the system using command -v 838 | if ! command -v busybox &> /dev/null; then 839 | log Error "$(which busybox) command not found." 840 | exit 1 841 | fi 842 | 843 | if command -v ksud &>/dev/null; then 844 | $scripts_dir/box.tool webroot >/dev/null 2>&1 845 | fi 846 | 847 | case "$1" in 848 | start) 849 | stop_box >/dev/null 2>&1 850 | start_box 851 | ;; 852 | stop) 853 | stop_box 854 | ;; 855 | restart) 856 | "${scripts_dir}/box.iptables" disable && stop_box 857 | sleep 0.5 858 | start_box && "${scripts_dir}/box.iptables" renew 859 | ;; 860 | status) 861 | if busybox pidof "${bin_name}" >/dev/null; then 862 | case "${bin_name}" in 863 | clash) echo "${yellow}$("${bin_path}" -v)${normal}";; 864 | *) echo "${yellow}$("${bin_path}" version)${normal}";; 865 | esac 866 | box_bin_status 867 | else 868 | log Warning "${bin_name} shutting down, service is stopped." 869 | fi 870 | ;; 871 | cron) 872 | run_crontab="true" 873 | stop_cron 874 | sleep 0.5 875 | box_run_crontab 876 | ;; 877 | kcron) 878 | stop_cron 879 | ;; 880 | help|-h|--help|"") 881 | echo "${yellow}Usage${normal}: ${green}$0${normal} {${yellow}start|stop|restart|status|cron|kcron${normal}}" 882 | echo 883 | echo "Commands:" 884 | echo " ${yellow}start${normal} - Stop (if running) then start the service" 885 | echo " ${yellow}stop${normal} - Stop the service" 886 | echo " ${yellow}restart${normal} - Restart the service and refresh iptables rules" 887 | echo " ${yellow}status${normal} - Show service status and version" 888 | echo " ${yellow}cron${normal} - Enable and start scheduled tasks" 889 | echo " ${yellow}kcron${normal} - Kill/disable scheduled tasks" 890 | echo 891 | echo "Example:" 892 | echo " $0 start" 893 | ;; 894 | *) 895 | echo "${red}$0 $1 not found${normal}" 896 | echo "Run '${green}$0 help${normal}' for usage." 897 | ;; 898 | esac -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /box/scripts/box.iptables: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | # Validate settings.ini 3 | if ! /system/bin/sh -n /data/adb/box/settings.ini 2>"/data/adb/box/run/settings_err.log"; then 4 | echo "Err: settings.ini contains a syntax error" | tee -a "/data/adb/box/run/settings_err.log" 5 | exit 1 6 | fi 7 | 8 | scripts_dir="${0%/*}" 9 | source /data/adb/box/settings.ini 10 | 11 | fwmark="16777216/16777216" 12 | table="2024" 13 | pref="100" 14 | # disable or enable QUIC using iptables rules. Note that this may cause some websites to become inaccessible. 15 | quic="enable" 16 | clash_dns_forward="enable" 17 | fake_ip_range="" 18 | 19 | # ex: 7.1.1 20 | buildVersion=$(getprop ro.build.version.release) 21 | minBuildVersion="11" 22 | IPV="iptables" # Default 23 | IP6V="ip6tables" # Default 24 | # ex: 7.1.1 -> 7 25 | buildVersionMajor=${buildVersion%%.*} 26 | if [ "$buildVersionMajor" -ge "$minBuildVersion" ]; then 27 | IPV="iptables -w 100" 28 | IP6V="ip6tables -w 100" 29 | fi 30 | 31 | case "${bin_name}" in 32 | "clash") 33 | clash_mode=$(busybox awk '!/^ *#/ && /mode: / { print $2;found=1; exit } END{ if(!found) print "rules" }' "${clash_config}" 2>/dev/null) 34 | 35 | clash_enhanced_mode=$(busybox awk '!/^ *#/ && /enhanced-mode: / { print $2;found=1; exit } END{ if(!found) print "fake-ip" }' "${clash_config}" 2>/dev/null) 36 | 37 | fake_ip_range=$(busybox awk '!/^ *#/ && /fake-ip-range:/ { print $2; found=1; exit } END { if (!found) print "198.18.0.1/16" }' "${clash_config}" 2>/dev/null) 38 | 39 | clash_dns_port=$(sed -n '/^dns:/,/^[^ ]/p' "${clash_config}" | grep -E '^[^#]*listen:.*:[0-9]+' | grep -Eo '[0-9]+' | tail -n 1) 40 | clash_dns_port=${clash_dns_port:-1053} 41 | 42 | if [[ "${network_mode}" == @(mixed|tun) ]]; then 43 | tun_device=$(busybox awk '!/^ *#/ && /device: / { print $2;found=1; exit } END{ if(!found) print "meta" }' "${clash_config}" 2>/dev/null) 44 | fi 45 | ;; 46 | "sing-box") 47 | if [[ "${network_mode}" == @(mixed|tun) ]]; then 48 | tun_device=$(find "${box_dir}/sing-box/" -maxdepth 1 -type f -name "*.json" -exec busybox grep -oE '"interface_name": "[^"]*' {} + | busybox awk -F'"' '{print $4}' 2>/dev/null | head -n 1) 49 | 50 | if [ -z "$tun_device" ]; then 51 | tun_device="tun0" 52 | fi 53 | fi 54 | 55 | fake_ip_range=$(find ${box_dir}/sing-box/ -maxdepth 1 -type f -name "*.json" -exec busybox awk -F'"' '/inet4_range/ {print $4}' {} +) 56 | fake_ip6_range=$(find ${box_dir}/sing-box/ -maxdepth 1 -type f -name "*.json" -exec busybox awk -F'"' '/inet6_range/ {print $4}' {} +) 57 | ;; 58 | "hysteria") 59 | case "${network_mode}" in 60 | redirect|tproxy|enhance) 61 | true # do nothing 62 | ;; 63 | *) 64 | log Warning "$bin_name does not support network_mode: $network_mode, return to TProxy" 65 | sed -i 's/\(network_mode=\)\"[^\"]*\"/\1"tproxy"/g' ${settings} 66 | ;; 67 | esac 68 | ;; 69 | "xray" | "v2fly") 70 | if [[ "${network_mode}" != "tproxy" ]]; then 71 | log Warning "$bin_name does not support network_mode: $network_mode, return to TProxy" 72 | sed -i 's/\(network_mode=\)\"[^\"]*\"/\1"tproxy"/g' ${settings} 73 | fi 74 | ;; 75 | *) 76 | log Error "<${bin_name}> unknown binary." 77 | exit 1 78 | ;; 79 | esac 80 | 81 | box_etc() { 82 | case "${bin_name}" in 83 | clash) 84 | log Debug "enhanced-mode: $clash_enhanced_mode, fake-ip-range: $fake_ip_range, listen-port: $clash_dns_port, mode: $clash_mode" 85 | ;; 86 | sing-box) 87 | if [ -n "${fake_ip_range}" ] && [ "${bin_name}" = "sing-box" ]; then 88 | log Debug "fake-ip-range: ${fake_ip_range}, ${fake_ip6_range}" 89 | fi 90 | ;; 91 | *) 92 | true 93 | ;; 94 | esac 95 | if [[ "${network_mode}" == @(mixed|tun) ]]; then 96 | log Info "tun device: ($tun_device)" 97 | fi 98 | } 99 | 100 | bin_alive() { 101 | local PID=$(<"${box_pid}" 2>/dev/null) 102 | if ! kill -0 "$PID" >/dev/null; then 103 | log Error "$(<"${box_run}/${bin_name}.log")" 104 | log Error "${bin_name} service is not running." 105 | log Error "please check ${bin_name}.log for more information." 106 | log Error "killing stale pid $PID" 107 | for bin in "${bin_list[@]}"; do 108 | killall -15 "${bin}" >/dev/null 2>&1 || busybox pkill -15 "${bin}" >/dev/null 2>&1 109 | done 110 | cleanup_iptables 111 | [ -f "${box_pid}" ] && rm -f "${box_pid}" 112 | return 1 113 | else 114 | return 0 115 | fi 116 | } 117 | 118 | find_packages_uid() { 119 | echo -n "" > "${uid_list}" 120 | 121 | for package in "${packages_list[@]}"; do 122 | if [[ "$package" == *:* ]]; then 123 | user="${package%%:*}" 124 | pkg="${package##*:}" 125 | else 126 | user=0 127 | pkg="$package" 128 | fi 129 | 130 | appid="$(busybox awk -v p="$pkg" '$1 == p {print $2}' "$system_packages_file")" 131 | 132 | if [[ -n "$appid" ]]; then 133 | uid=$((user * 100000 + appid)) 134 | echo "$uid" >> "${uid_list}" 135 | fi 136 | done 137 | } 138 | 139 | probe_user_group() { 140 | if PID=$(busybox pidof ${bin_name}) ; then 141 | box_user=$(stat -c %U /proc/$PID) 142 | box_group=$(stat -c %G /proc/$PID) 143 | return 0 144 | else 145 | IFS=':' read -r box_user box_group <<< "${box_user_group}" 146 | return 1 147 | fi 148 | } 149 | 150 | disable_ipv6() { 151 | sysctl -w net.ipv4.ip_forward=1 152 | sysctl -w net.ipv6.conf.all.forwarding=0 153 | 154 | sysctl -w net.ipv6.conf.all.accept_ra=0 155 | sysctl -w net.ipv6.conf.wlan0.accept_ra=0 156 | sysctl -w net.ipv6.conf.all.disable_ipv6=1 157 | sysctl -w net.ipv6.conf.default.disable_ipv6=1 158 | sysctl -w net.ipv6.conf.wlan0.disable_ipv6=1 159 | 160 | # add: block Askes ipv6 completely 161 | ip -6 rule add unreachable pref "${pref}" 162 | } >/dev/null 2>&1 163 | 164 | ipv6_enable() { 165 | sysctl -w net.ipv4.ip_forward=1 166 | sysctl -w net.ipv6.conf.all.forwarding=1 167 | 168 | sysctl -w net.ipv6.conf.all.accept_ra=2 169 | sysctl -w net.ipv6.conf.wlan0.accept_ra=2 170 | sysctl -w net.ipv6.conf.all.disable_ipv6=0 171 | sysctl -w net.ipv6.conf.default.disable_ipv6=0 172 | sysctl -w net.ipv6.conf.wlan0.disable_ipv6=0 173 | 174 | # del: block Askes ipv6 completely 175 | ip -6 rule del unreachable pref "${pref}" 176 | 177 | # add: blocks all outgoing IPv6 traffic using the UDP protocol to port 53, effectively preventing DNS queries over IPv6. 178 | $IP6V -A OUTPUT -p udp --destination-port 53 -j DROP 179 | } >/dev/null 2>&1 180 | 181 | intranet=( 182 | 0.0.0.0/8 183 | 10.0.0.0/8 184 | 100.64.0.0/10 185 | 127.0.0.0/8 186 | 169.254.0.0/16 187 | 172.16.0.0/12 188 | 192.0.0.0/24 189 | 192.0.2.0/24 190 | 192.88.99.0/24 191 | 192.168.0.0/16 192 | 198.51.100.0/24 193 | 203.0.113.0/24 194 | 224.0.0.0/4 195 | 240.0.0.0/4 196 | 255.0.0.0/4 197 | 255.255.255.0/24 198 | 255.255.255.255/32 199 | ) 200 | # The use of 100.0.0.0/8 instead of 100.64.0.0/10 is purely due to a mistake by China Telecom's service provider, and you can change it back. 201 | intranet+=($(ip -4 a | busybox awk '/inet/ {print $2}' | busybox grep -vE "^127.0.0.1")) 202 | 203 | intranet6=( 204 | ::/128 205 | ::1/128 206 | ::ffff:0:0/96 207 | 100::/64 208 | 64:ff9b::/96 209 | 2001::/32 210 | 2001:10::/28 211 | 2001:20::/28 212 | 2001:db8::/32 213 | 2002::/16 214 | fc00::/7 215 | fe80::/10 216 | ff00::/8 217 | ) 218 | intranet6+=($(ip -6 a | busybox awk '/inet6/ {print $2}' | busybox grep -vE "^fe80|^::1|^fd00")) 219 | 220 | probe_tun_device() { 221 | busybox ifconfig | grep -q "${tun_device}" || return 1 222 | } 223 | 224 | forward() { 225 | local action=$1 226 | 227 | # ${iptables} -t nat ${action} POSTROUTING -o ${tun_device} -j MASQUERADE 228 | ${iptables} "${action}" FORWARD -i "${tun_device}" -j ACCEPT 229 | ${iptables} "${action}" FORWARD -o "${tun_device}" -j ACCEPT 230 | 231 | sysctl -w net.ipv4.ip_forward=1 232 | sysctl -w net.ipv4.conf.default.rp_filter=2 233 | sysctl -w net.ipv4.conf.all.rp_filter=2 234 | 235 | } >/dev/null 2>&1 236 | 237 | start_redirect() { 238 | if [ "${iptables}" = "$IPV" ]; then 239 | ${iptables} -t nat -N BOX_EXTERNAL 240 | ${iptables} -t nat -F BOX_EXTERNAL 241 | ${iptables} -t nat -N BOX_LOCAL 242 | ${iptables} -t nat -F BOX_LOCAL 243 | fi 244 | 245 | if [ "${iptables}" = "$IPV" ]; then 246 | if [ "${bin_name}" = "clash" ]; then 247 | ${iptables} -t nat -A BOX_EXTERNAL -p udp --dport 53 -j REDIRECT --to-ports "${clash_dns_port}" 248 | ${iptables} -t nat -A BOX_LOCAL -p udp --dport 53 -j REDIRECT --to-ports "${clash_dns_port}" 249 | # else 250 | # Other types of inbound should be added here to receive DNS traffic instead of sniffing 251 | # ${iptables} -t nat -A BOX_EXTERNAL -p udp --dport 53 -j REDIRECT --to-ports "${redir_port}" 252 | # ${iptables} -t nat -A BOX_LOCAL -p udp --dport 53 -j REDIRECT --to-ports "${redir_port}" 253 | fi 254 | 255 | # Fix ICMP (ping). This does not guarantee that the ping result is valid. Just that it returns a result 256 | # if [[ "${bin_name}" == @(clash|sing-box) ]]; then 257 | # if [ -n "${fake_ip_range}" ]; then 258 | # ${iptables} -t nat -A BOX_EXTERNAL -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 259 | # ${iptables} -t nat -A BOX_LOCAL -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 260 | # fi 261 | # fi 262 | 263 | ${iptables} -t nat -N LOCAL_IP_V4 264 | ${iptables} -t nat -F LOCAL_IP_V4 265 | 266 | for subnet in ${intranet[@]} ; do 267 | ${iptables} -t nat -A BOX_EXTERNAL -d ${subnet} -j RETURN 268 | ${iptables} -t nat -A BOX_LOCAL -d ${subnet} -j RETURN 269 | done 270 | 271 | ${iptables} -t nat -A BOX_EXTERNAL -j LOCAL_IP_V4 272 | ${iptables} -t nat -A BOX_LOCAL -j LOCAL_IP_V4 273 | 274 | ${iptables} -t nat -A BOX_EXTERNAL -p tcp -i lo -j REDIRECT --to-ports "${redir_port}" 275 | 276 | if [ "${ap_list}" != "" ]; then 277 | for ap in "${ap_list[@]}"; do 278 | ${iptables} -t nat -A BOX_EXTERNAL -p tcp -i "${ap}" -j REDIRECT --to-ports "${redir_port}" 279 | done 280 | [ ${network_mode} = "enhance" ] || log Info "${ap_list[*]} transparent proxy." 281 | fi 282 | 283 | ${iptables} -t nat -I PREROUTING -j BOX_EXTERNAL 284 | ${iptables} -t nat -I BOX_LOCAL -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -j RETURN 285 | 286 | if [ "${ignore_out_list}" != "" ]; then 287 | for ignore in "${ignore_out_list[@]}"; do 288 | ${iptables} -t nat -A BOX_LOCAL -o "${ignore}" -j RETURN 289 | done 290 | [ ${network_mode} = "enhance" ] || log Info "${ignore_out_list[*]} ignore transparent proxy." 291 | fi 292 | fi 293 | 294 | if [ "${iptables}" = "$IPV" ]; then 295 | case "${proxy_mode}" in 296 | blacklist|black) 297 | if [ -z "$(cat "${uid_list[@]}")" ] ; then 298 | ${iptables} -t nat -A BOX_LOCAL -p tcp -j REDIRECT --to-ports "${redir_port}" 299 | [ ${network_mode} = "enhance" ] || log Info "Transparent proxy for all apps." 300 | else 301 | while read -r appid; do 302 | ${iptables} -t nat -A BOX_LOCAL -m owner --uid-owner "${appid}" -j RETURN 303 | done < "${uid_list[@]}" 304 | ${iptables} -t nat -A BOX_LOCAL -p tcp -j REDIRECT --to-ports "${redir_port}" 305 | [ ${network_mode} = "enhance" ] || log Info "proxy mode: ${proxy_mode} (${packages_list[*]}) no transparent proxy." 306 | fi 307 | 308 | if [ "${gid_list}" != "" ] ; then 309 | for gid in ${gid_list[@]} ; do 310 | ${iptables} -t nat -A BOX_LOCAL -m owner --gid-owner ${gid} -j RETURN 311 | done 312 | [ ${network_mode} = "enhance" ] || { 313 | [ "${iptables}" = "$IPV" ] && log Info "proxy mode: ${proxy_mode}, GID (${gid_list[*]}) no transparent proxy." 314 | } 315 | fi 316 | ;; 317 | whitelist|white) 318 | if [ -z "$(cat "${uid_list[@]}")" ] ; then 319 | ${iptables} -t nat -A BOX_LOCAL -p tcp -j REDIRECT --to-ports "${redir_port}" 320 | [ ${network_mode} = "enhance" ] || log Info "Transparent proxy for all apps." 321 | else 322 | while read -r appid; do 323 | ${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --uid-owner "${appid}" -j REDIRECT --to-ports "${redir_port}" 324 | done < "${uid_list[@]}" 325 | ${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --uid-owner 0 -j REDIRECT --to-ports "${redir_port}" 326 | ${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --uid-owner 1052 -j REDIRECT --to-ports "${redir_port}" 327 | [ ${network_mode} = "enhance" ] || log Info "proxy mode: ${proxy_mode} (${packages_list[*]}) transparent proxy." 328 | fi 329 | 330 | if [ "${gid_list}" != "" ] ; then 331 | for gid in ${gid_list[@]} ; do 332 | ${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --gid-owner ${gid} -j REDIRECT --to-ports ${redir_port} 333 | done 334 | [ ${network_mode} = "enhance" ] || [ "${iptables}" = "$IPV" ] && log Info "proxy mode: ${proxy_mode}, GID (${gid_list[*]}) transparent proxy." 335 | fi 336 | ;; 337 | *) 338 | log Warning "proxy mode: ${proxy_mode} < error." 339 | ${iptables} -t nat -A BOX_LOCAL -p tcp -j REDIRECT --to-ports "${redir_port}" 340 | [ ${network_mode} = "enhance" ] || log Info "Transparent proxy for all apps." 341 | ;; 342 | esac 343 | fi 344 | 345 | if [ "${iptables}" = "$IPV" ]; then 346 | ${iptables} -t nat -I OUTPUT -j BOX_LOCAL 347 | fi 348 | 349 | if [ "${iptables}" = "$IPV" ]; then 350 | ${iptables} -A OUTPUT -d 127.0.0.1 -p tcp -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -m tcp --dport "${redir_port}" -j REJECT 351 | else 352 | ${iptables} -A OUTPUT -d ::1 -p tcp -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -m tcp --dport "${redir_port}" -j REJECT 353 | fi 354 | } 355 | 356 | stop_redirect() { 357 | if [ "${iptables}" = "$IPV" ]; then 358 | ${iptables} -t nat -D PREROUTING -j BOX_EXTERNAL 359 | ${iptables} -t nat -D OUTPUT -j BOX_LOCAL 360 | fi 361 | 362 | if [ "${iptables}" = "$IPV" ]; then 363 | ${iptables} -D OUTPUT -d 127.0.0.1 -p tcp -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -m tcp --dport "${redir_port}" -j REJECT 364 | ${iptables} -D OUTPUT -d 127.0.0.1 -p tcp -m owner --uid-owner 0:3005 -m tcp --dport "${redir_port}" -j REJECT 365 | else 366 | ${iptables} -D OUTPUT -d ::1 -p tcp -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -m tcp --dport "${redir_port}" -j REJECT 367 | ${iptables} -D OUTPUT -d ::1 -p tcp -m owner --uid-owner 0:3005 -m tcp --dport "${redir_port}" -j REJECT 368 | fi 369 | 370 | if [ "${iptables}" = "$IPV" ]; then 371 | # ${iptables} -t nat -D BOX_EXTERNAL -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 372 | # ${iptables} -t nat -D BOX_LOCAL -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 373 | ${iptables} -t nat -F BOX_EXTERNAL 374 | ${iptables} -t nat -X BOX_EXTERNAL 375 | ${iptables} -t nat -F BOX_LOCAL 376 | ${iptables} -t nat -X BOX_LOCAL 377 | ${iptables} -t nat -F LOCAL_IP_V4 378 | ${iptables} -t nat -X LOCAL_IP_V4 379 | fi 380 | } 381 | 382 | start_tproxy() { 383 | if [ "${iptables}" = "$IPV" ]; then 384 | ip rule add fwmark "${fwmark}" table "${table}" pref "${pref}" 385 | ip route add local default dev lo table "${table}" 386 | else 387 | ip -6 rule add fwmark "${fwmark}" table "${table}" pref "${pref}" 388 | ip -6 route add local default dev lo table "${table}" 389 | fi 390 | 391 | ${iptables} -t mangle -N BOX_EXTERNAL >/dev/null 2>&1 392 | ${iptables} -t mangle -F BOX_EXTERNAL >/dev/null 2>&1 393 | 394 | # ${iptables} -t mangle -A BOX_EXTERNAL -m mark --mark ${routing_mark} -j RETURN 395 | 396 | # Bypass other if, notice: Some interface is named with r_ / oem / nm_ / qcom_, it might need more complicated solution. 397 | # ${iptables} -t mangle -I BOX_EXTERNAL -i rmnet_data+ -j RETURN 398 | # ${iptables} -t mangle -I BOX_EXTERNAL -i ccmni+ -j RETURN 399 | 400 | if [ "${clash_dns_forward}" = "enable" ] && [[ "${bin_name}" == @(clash|hysteria) ]] ; then 401 | [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_EXTERNAL -p tcp --dport 53 -j RETURN 402 | ${iptables} -t mangle -A BOX_EXTERNAL -p udp --dport 53 -j RETURN 403 | else 404 | [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_EXTERNAL -p tcp --dport 53 -j TPROXY --on-port ${tproxy_port} --tproxy-mark ${fwmark} 405 | ${iptables} -t mangle -A BOX_EXTERNAL -p udp --dport 53 -j TPROXY --on-port ${tproxy_port} --tproxy-mark ${fwmark} 406 | fi 407 | 408 | # Skip traffic already handled by TProxy 409 | # If the interface of the default route has a public IPv4 or IPv6 address assigned by the ISP, omitting these rules will result in abnormal proxy behavior for local traffic' 410 | # [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_EXTERNAL -p tcp -m socket --transparent -j MARK --set-xmark ${fwmark} 411 | # ${iptables} -t mangle -A BOX_EXTERNAL -p udp -m socket --transparent -j MARK --set-xmark ${fwmark} 412 | # ${iptables} -t mangle -A BOX_EXTERNAL -m socket -j RETURN 413 | 414 | # Bypass intranet, run `su -c 'zcat /proc/config.gz | grep -i addrtype'` to check compatibility 415 | # ${iptables} -t mangle -A BOX_EXTERNAL -m addrtype --dst-type LOCAL -j RETURN 416 | if [ "${iptables}" = "$IPV" ]; then 417 | for subnet in ${intranet[@]} ; do 418 | ${iptables} -t mangle -A BOX_EXTERNAL -d ${subnet} -j RETURN 419 | done 420 | ${iptables} -t mangle -N LOCAL_IP_V4 421 | ${iptables} -t mangle -F LOCAL_IP_V4 422 | ${iptables} -t mangle -A BOX_EXTERNAL -j LOCAL_IP_V4 423 | else 424 | for subnet6 in ${intranet6[@]} ; do 425 | ${iptables} -t mangle -A BOX_EXTERNAL -d ${subnet6} -j RETURN 426 | done 427 | ${iptables} -t mangle -N LOCAL_IP_V6 428 | ${iptables} -t mangle -F LOCAL_IP_V6 429 | ${iptables} -t mangle -A BOX_EXTERNAL -j LOCAL_IP_V6 430 | fi 431 | 432 | [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_EXTERNAL -p tcp -i lo -j TPROXY --on-port "${tproxy_port}" --tproxy-mark "${fwmark}" 433 | ${iptables} -t mangle -A BOX_EXTERNAL -p udp -i lo -j TPROXY --on-port "${tproxy_port}" --tproxy-mark "${fwmark}" 434 | 435 | # Allow ap interface, Notice: Old android device may only have one wlan interface. Some new android device have multiple wlan interface like wlan0(for internet), wlan1(for AP), loop through the access point list 436 | if [ "${ap_list}" != "" ]; then 437 | for ap in ${ap_list[@]} ; do 438 | [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_EXTERNAL -p tcp -i "${ap}" -j TPROXY --on-port "${tproxy_port}" --tproxy-mark "${fwmark}" 439 | ${iptables} -t mangle -A BOX_EXTERNAL -p udp -i "${ap}" -j TPROXY --on-port "${tproxy_port}" --tproxy-mark "${fwmark}" 440 | done 441 | [ "${iptables}" = "$IPV" ] && log Info "${ap_list[*]} transparent proxy." 442 | fi 443 | 444 | ${iptables} -t mangle -I PREROUTING -j BOX_EXTERNAL 445 | ${iptables} -t mangle -N BOX_LOCAL 446 | ${iptables} -t mangle -F BOX_LOCAL 447 | 448 | ${iptables} -t mangle -A BOX_LOCAL -m owner --uid-owner ${box_user} --gid-owner ${box_group} -j RETURN 449 | # ${iptables} -t mangle -A BOX_LOCAL -m mark --mark ${routing_mark} -j RETURN 450 | 451 | if [ "${ignore_out_list}" != "" ]; then 452 | for ignore in ${ignore_out_list[@]} ; do 453 | ${iptables} -t mangle -A BOX_LOCAL -o "${ignore}" -j RETURN 454 | done 455 | [ "${iptables}" = "$IPV" ] && log Info "${ignore_out_list[*]} ignore transparent proxy." 456 | fi 457 | 458 | if [ "${clash_dns_forward}" = "enable" ] && [[ "${bin_name}" == @(clash|hysteria) ]] ; then 459 | [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp --dport 53 -j RETURN 460 | ${iptables} -t mangle -A BOX_LOCAL -p udp --dport 53 -j RETURN 461 | else 462 | [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp --dport 53 -j MARK --set-xmark ${fwmark} 463 | ${iptables} -t mangle -A BOX_LOCAL -p udp --dport 53 -j MARK --set-xmark ${fwmark} 464 | fi 465 | 466 | if [ "${iptables}" = "$IPV" ]; then 467 | for subnet in ${intranet[@]} ; do 468 | ${iptables} -t mangle -A BOX_LOCAL -d ${subnet} -j RETURN 469 | done 470 | ${iptables} -t mangle -A BOX_LOCAL -j LOCAL_IP_V4 471 | else 472 | for subnet6 in ${intranet6[@]} ; do 473 | ${iptables} -t mangle -A BOX_LOCAL -d ${subnet6} -j RETURN 474 | done 475 | ${iptables} -t mangle -A BOX_LOCAL -j LOCAL_IP_V6 476 | fi 477 | 478 | case "${proxy_mode}" in 479 | blacklist|black) 480 | if [ -z "$(cat "${uid_list[@]}")" ] ; then 481 | [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -j MARK --set-xmark "${fwmark}" 482 | ${iptables} -t mangle -A BOX_LOCAL -p udp -j MARK --set-xmark "${fwmark}" 483 | [ "${iptables}" = "$IPV" ] && log Info "transparent proxy for all apps." 484 | else 485 | while read -r appid; do 486 | ${iptables} -t mangle -A BOX_LOCAL -m owner --uid-owner "${appid}" -j RETURN 487 | done < "${uid_list[@]}" 488 | [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -j MARK --set-xmark "${fwmark}" 489 | ${iptables} -t mangle -A BOX_LOCAL -p udp -j MARK --set-xmark "${fwmark}" 490 | [ "${iptables}" = "$IPV" ] && log Info "proxy mode: ${proxy_mode} (${packages_list[*]}) no transparent proxy." 491 | fi 492 | 493 | if [ "${gid_list}" != "" ] ; then 494 | for gid in ${gid_list[@]} ; do 495 | ${iptables} -t mangle -A BOX_LOCAL -m owner --gid-owner ${gid} -j RETURN 496 | done 497 | [ "${iptables}" = "$IPV" ] && log Info "proxy mode: ${proxy_mode}, GID (${gid_list[*]}) no transparent proxy." 498 | fi 499 | ;; 500 | whitelist|white) 501 | if [ -z "$(cat "${uid_list[@]}")" ] ; then 502 | [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -j MARK --set-xmark "${fwmark}" 503 | ${iptables} -t mangle -A BOX_LOCAL -p udp -j MARK --set-xmark "${fwmark}" 504 | [ "${iptables}" = "$IPV" ] && log Info "transparent proxy for all apps." 505 | else 506 | while read -r appid; do 507 | [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --uid-owner "${appid}" -j MARK --set-xmark "${fwmark}" 508 | ${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --uid-owner "${appid}" -j MARK --set-xmark "${fwmark}" 509 | done < "${uid_list[@]}" 510 | [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --uid-owner 0 -j MARK --set-xmark "${fwmark}" 511 | ${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --uid-owner 0 -j MARK --set-xmark "${fwmark}" 512 | [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --uid-owner 1052 -j MARK --set-xmark "${fwmark}" 513 | ${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --uid-owner 1052 -j MARK --set-xmark "${fwmark}" 514 | [ "${iptables}" = "$IPV" ] && log Info "proxy mode: ${proxy_mode} (${packages_list[*]}) transparent proxy." 515 | fi 516 | 517 | if [ "${gid_list}" != "" ] ; then 518 | for gid in ${gid_list[@]} ; do 519 | [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --gid-owner ${gid} -j MARK --set-xmark "${fwmark}" 520 | ${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --gid-owner ${gid} -j MARK --set-xmark "${fwmark}" 521 | done 522 | [ "${iptables}" = "$IPV" ] && log Info "proxy mode: ${proxy_mode}, GID (${gid_list[*]}) transparent proxy." 523 | fi 524 | ;; 525 | *) 526 | log Debug "proxy mode: ${proxy_mode} < error" 527 | [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -j MARK --set-xmark "${fwmark}" 528 | ${iptables} -t mangle -A BOX_LOCAL -p udp -j MARK --set-xmark "${fwmark}" 529 | [ "${iptables}" = "$IPV" ] && log Info "transparent proxy for all apps." 530 | ;; 531 | esac 532 | 533 | ${iptables} -t mangle -I OUTPUT -j BOX_LOCAL 534 | 535 | ${iptables} -t mangle -N DIVERT 536 | ${iptables} -t mangle -F DIVERT 537 | ${iptables} -t mangle -A DIVERT -j MARK --set-xmark "${fwmark}" 538 | ${iptables} -t mangle -A DIVERT -j ACCEPT 539 | [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -I PREROUTING -p tcp -m socket -j DIVERT 540 | 541 | # Disable QUIC 542 | if [ "${quic}" = "disable" ]; then 543 | ${iptables} -A OUTPUT -p udp --dport 443 -j REJECT 544 | ${iptables} -A OUTPUT -p udp --dport 80 -j REJECT 545 | # ${iptables} -A OUTPUT -p udp -m multiport --dport 443,80 -j REJECT 546 | [ "${iptables}" = "$IPV" ] && log Warning "Disabling QUIC" 547 | fi 548 | 549 | if [ ${network_mode} != "enhance" ]; then 550 | # This rule blocks local access to tproxy-port to prevent traffic loopback. 551 | if [ "${iptables}" = "$IPV" ]; then 552 | ${iptables} -A OUTPUT -d 127.0.0.1 -p tcp -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -m tcp --dport "${tproxy_port}" -j REJECT 553 | else 554 | ${iptables} -A OUTPUT -d ::1 -p tcp -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -m tcp --dport "${tproxy_port}" -j REJECT 555 | fi 556 | fi 557 | 558 | if [ "${iptables}" = "$IPV" ]; then 559 | if [ "${clash_dns_forward}" = "enable" ] && [ "${bin_name}" = "clash" ]; then 560 | ${iptables} -t nat -N CLASH_DNS_EXTERNAL 561 | ${iptables} -t nat -F CLASH_DNS_EXTERNAL 562 | ${iptables} -t nat -A CLASH_DNS_EXTERNAL -p udp --dport 53 -j REDIRECT --to-ports "${clash_dns_port}" 563 | ${iptables} -t nat -I PREROUTING -j CLASH_DNS_EXTERNAL 564 | 565 | ${iptables} -t nat -N CLASH_DNS_LOCAL 566 | ${iptables} -t nat -F CLASH_DNS_LOCAL 567 | ${iptables} -t nat -A CLASH_DNS_LOCAL -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -j RETURN 568 | ${iptables} -t nat -A CLASH_DNS_LOCAL -p udp --dport 53 -j REDIRECT --to-ports "${clash_dns_port}" 569 | ${iptables} -t nat -I OUTPUT -j CLASH_DNS_LOCAL 570 | fi 571 | 572 | # Fix ICMP (ping), this does not guarantee that the ping result is valid (proxies such as clash do not support forwarding ICMP),just that it returns a result, "--to-destination" can be set to a reachable address. 573 | if [[ "${bin_name}" == @(clash|sing-box) ]]; then 574 | if [ -n "${fake_ip_range}" ]; then 575 | ${iptables} -t nat -I OUTPUT -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 576 | ${iptables} -t nat -I PREROUTING -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 577 | fi 578 | fi 579 | fi 580 | } 581 | 582 | stop_tproxy() { 583 | if [ "${iptables}" = "$IPV" ]; then 584 | ip rule del fwmark "${fwmark}" table "${table}" pref "${pref}" 585 | ip route del local default dev lo table "${table}" 586 | ip route flush table "${table}" 587 | ip rule del pref "${pref}" 588 | else 589 | ip -6 rule del fwmark "${fwmark}" table "${table}" pref "${pref}" 590 | ip -6 route del local default dev lo table "${table}" 591 | ip -6 route flush table "${table}" 592 | ip -6 rule del pref "${pref}" 593 | fi 594 | 595 | ${iptables} -t mangle -D PREROUTING -j BOX_EXTERNAL 596 | ${iptables} -t mangle -D PREROUTING -p tcp -m socket -j DIVERT 597 | 598 | ${iptables} -t mangle -D OUTPUT -j BOX_LOCAL 599 | 600 | ${iptables} -t mangle -D BOX_EXTERNAL -i rmnet_data+ -j RETURN 601 | ${iptables} -t mangle -D BOX_EXTERNAL -i ccmni+ -j RETURN 602 | 603 | ${iptables} -t mangle -F BOX_EXTERNAL 604 | ${iptables} -t mangle -X BOX_EXTERNAL 605 | 606 | ${iptables} -t mangle -F BOX_LOCAL 607 | ${iptables} -t mangle -X BOX_LOCAL 608 | 609 | ${IPV} -t mangle -F LOCAL_IP_V4 610 | ${IPV} -t mangle -X LOCAL_IP_V4 611 | ${IP6V} -t mangle -F LOCAL_IP_V6 612 | ${IP6V} -t mangle -X LOCAL_IP_V6 613 | 614 | ${iptables} -t mangle -F DIVERT 615 | ${iptables} -t mangle -X DIVERT 616 | 617 | # flush QUIC 618 | ${iptables} -D OUTPUT -p udp -m multiport --dport 443,80 -j REJECT 619 | ${iptables} -D OUTPUT -p udp --dport 443 -j REJECT 620 | ${iptables} -D OUTPUT -p udp --dport 80 -j REJECT 621 | 622 | if [ "${iptables}" = "$IPV" ]; then 623 | ${iptables} -D OUTPUT -d 127.0.0.1 -p tcp -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -m tcp --dport "${tproxy_port}" -j REJECT 624 | ${iptables} -D OUTPUT -d 127.0.0.1 -p tcp -m owner --uid-owner 0 --gid-owner 3005 -m tcp --dport "${tproxy_port}" -j REJECT 625 | else 626 | ${iptables} -D OUTPUT -d ::1 -p tcp -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -m tcp --dport "${tproxy_port}" -j REJECT 627 | ${iptables} -D OUTPUT -d ::1 -p tcp -m owner --uid-owner 0 --gid-owner 3005 -m tcp --dport "${tproxy_port}" -j REJECT 628 | fi 629 | 630 | if [ "${iptables}" = "$IPV" ]; then 631 | ${iptables} -t nat -D PREROUTING -j CLASH_DNS_EXTERNAL 632 | ${iptables} -t nat -D OUTPUT -j CLASH_DNS_LOCAL 633 | ${iptables} -t nat -F CLASH_DNS_EXTERNAL 634 | ${iptables} -t nat -X CLASH_DNS_EXTERNAL 635 | ${iptables} -t nat -F CLASH_DNS_LOCAL 636 | ${iptables} -t nat -X CLASH_DNS_LOCAL 637 | 638 | if [ -n "${fake_ip_range}" ]; then 639 | ${iptables} -t nat -D OUTPUT -p icmp -d "${fake_ip_range}" -j DNAT --to-destination 127.0.0.1 640 | ${iptables} -t nat -D PREROUTING -p icmp -d "${fake_ip_range}" -j DNAT --to-destination 127.0.0.1 641 | ${iptables} -t nat -D OUTPUT -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 642 | ${iptables} -t nat -D PREROUTING -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 643 | fi 644 | fi 645 | } 646 | 647 | cleanup_iptables() { 648 | for iptables in "$IPV" "$IP6V"; do 649 | iptables="${iptables}" && { 650 | stop_redirect 651 | stop_tproxy 652 | forward -D 653 | } >/dev/null 2>&1 654 | 655 | if [ "${iptables}" = "$IP6V" ]; then 656 | ${iptables} -D OUTPUT -p udp --destination-port 53 -j DROP >/dev/null 2>&1 657 | fi 658 | done 659 | } 660 | 661 | if [[ "${network_mode}" == @(redirect|mixed|tproxy|enhance) ]]; then 662 | case "$1" in 663 | enable|renew) 664 | box_etc 665 | log Info "$IPV + $IP6V" 666 | probe_user_group || { 667 | log Error "Failed to check BOX user group. Please ensure ${bin_name} kernel is started." 668 | } 669 | 670 | find_packages_uid 671 | cleanup_iptables 672 | 673 | [ $1 = "renew" ] && log Warning "cleaning up iptables transparent proxy rules." 674 | 675 | case "${network_mode}" in 676 | tproxy) 677 | log Info "Using Tproxy: tcp + udp." 678 | log Info "Creating iptables transparent proxy rules." 679 | 680 | iptables="$IPV" 681 | if start_tproxy; then 682 | log Info "Creating iptables transparent proxy rules done." 683 | else 684 | log Error "Creating iptables transparent proxy rules failed." 685 | stop_tproxy >/dev/null 2>&1 686 | fi 687 | 688 | if [ "${ipv6}" = "true" ]; then 689 | log Debug "Using IPv6." 690 | ipv6_enable 691 | iptables="$IP6V" 692 | 693 | if start_tproxy; then 694 | log Info "Creating ip6tables transparent proxy rules done." 695 | else 696 | log Error "Creating ip6tables transparent proxy rules failed." 697 | stop_tproxy >/dev/null 2>&1 698 | fi 699 | else 700 | disable_ipv6 701 | log Warning "Disabling IPv6." 702 | fi 703 | ;; 704 | redirect) 705 | log Info "Using Redirect: tcp + udp (direct)." 706 | log Info "Creating iptables transparent proxy rules." 707 | 708 | iptables="$IPV" 709 | if start_redirect; then 710 | log Info "Creating iptables transparent proxy rules done." 711 | else 712 | log Error "Creating iptables transparent proxy rule failed." 713 | stop_redirect >/dev/null 2>&1 714 | fi 715 | 716 | if [ "${ipv6}" = "true" ]; then 717 | log Debug "Using IPv6." 718 | ipv6_enable 719 | iptables="$IP6V" 720 | 721 | if start_redirect; then 722 | log Info "Creating ip6tables transparent proxy rules done." 723 | else 724 | log Error "Creating ip6tables transparent proxy rule failed." 725 | stop_redirect >/dev/null 2>&1 726 | fi 727 | else 728 | disable_ipv6 729 | log Warning "Disabling IPv6." 730 | fi 731 | ;; 732 | mixed) 733 | log Info "Using Mixed: tcp(redirect) + udp(tun)." 734 | log Info "Creating iptables transparent proxy rules." 735 | 736 | iptables="$IPV" 737 | probe_tun_device || log Error "tun device: (${tun_device}) not found" 738 | forward -I || forward -D >/dev/null 2>&1 739 | 740 | if start_redirect; then 741 | log Info "Creating iptables transparent proxy rules done." 742 | else 743 | log Error "Creating iptables transparent proxy rule failed." 744 | stop_redirect >/dev/null 2>&1 745 | fi 746 | 747 | if [ "${ipv6}" = "true" ]; then 748 | log Debug "Using IPv6." 749 | ipv6_enable 750 | iptables="$IP6V" 751 | forward -I || forward -D >/dev/null 2>&1 752 | if start_redirect; then 753 | log Info "Creating ip6tables transparent proxy rules done." 754 | else 755 | log Error "Creating ip6tables transparent proxy rule failed." 756 | stop_redirect >/dev/null 2>&1 757 | fi 758 | else 759 | disable_ipv6 760 | log Warning "Disabling IPv6." 761 | fi 762 | ;; 763 | enhance) 764 | log Info "Using Enhance: tcp(redirect) + udp(tproxy)" 765 | log Info "Creating iptables transparent proxy rules." 766 | 767 | iptables="$IPV" 768 | if start_redirect && start_tproxy; then 769 | log Info "Creating iptables transparent proxy rules done." 770 | else 771 | log Error "Creating iptables transparent proxy rule failed." 772 | stop_redirect >/dev/null 2>&1 773 | fi 774 | 775 | if [ "${ipv6}" = "true" ]; then 776 | log Debug "Using IPv6." 777 | ipv6_enable 778 | iptables="$IP6V" 779 | if start_redirect && start_tproxy; then 780 | log Info "Creating ip6tables transparent proxy rules done." 781 | else 782 | log Error "Creating ip6tables transparent proxy rule failed." 783 | stop_redirect >/dev/null 2>&1 784 | fi 785 | else 786 | disable_ipv6 787 | log Warning "Disabling IPv6." 788 | fi 789 | ;; 790 | *) 791 | log Error "network_mode: ${network_mode}, unknown" 792 | exit 1 793 | ;; 794 | esac 795 | [ $1 = "renew" ] && log Debug "restart iptables transparent proxy rules done." 796 | bin_alive && log Info "${bin_name} connected." 797 | ;; 798 | disable) 799 | ipv6_enable 800 | probe_user_group || log Error "Failed to check BOX user group. Please ensure ${bin_name} kernel is started." 801 | log Warning "Cleaning up iptables transparent proxy rules." 802 | 803 | cleanup_iptables 804 | 805 | log Warning "Cleaning up iptables transparent proxy rules done." 806 | ;; 807 | help|-h|--help|"") 808 | echo "Usage: $0 {enable|disable|renew}" 809 | echo 810 | echo "Commands:" 811 | echo " enable - Enable iptables rules" 812 | echo " disable - Disable iptables rules" 813 | echo " renew - Reapply or refresh iptables rules" 814 | echo 815 | echo "Example:" 816 | echo " $0 enable" 817 | ;; 818 | *) 819 | echo "$0: '$1' not found" 820 | echo "Run '$0 help' for usage." 821 | ;; 822 | esac 823 | else 824 | case "$1" in 825 | enable|renew) 826 | box_etc 827 | log Info "$IPV + $IP6V" 828 | log Info "Using Tun: tcp + udp." 829 | 830 | probe_user_group || { 831 | log Error "Failed to check BOX user group. Please ensure ${bin_name} kernel is started." 832 | } 833 | 834 | cleanup_iptables 835 | probe_tun_device || log Error "tun device: (${tun_device}) not found" 836 | [ $1 = "renew" ] && log Warning "Cleaning up tun rules." 837 | iptables="$IPV" 838 | 839 | [ -n "${packages_list}" ] && log Debug "proxy mode: $proxy_mode (${packages_list[*]})" 840 | 841 | if forward -I; then 842 | log Info "Create iptables tun rules done." 843 | else 844 | log Error "Create iptables tun rules failed." 845 | forward -D >/dev/null 2>&1 846 | fi 847 | 848 | if [ "${ipv6}" = "true" ]; then 849 | log Debug "Using IPv6." 850 | ipv6_enable 851 | iptables="$IP6V" 852 | if forward -I; then 853 | log Info "Create ip6tables tun rules done." 854 | else 855 | log Error "Create ip6tables tun rules failed." 856 | forward -D >/dev/null 2>&1 857 | fi 858 | else 859 | disable_ipv6 860 | log Warning "Disable IPv6." 861 | fi 862 | [ $1 = "renew" ] && log Info "Restart iptables tun rules done." 863 | bin_alive && log Info "${bin_name} connected." 864 | ;; 865 | disable) 866 | ipv6_enable 867 | probe_user_group || log Error "Failed to check BOX user group. Please ensure ${bin_name} kernel is started." 868 | log Warning "Cleaning up tun rules." 869 | 870 | cleanup_iptables 871 | 872 | log Warning "Cleaning up tun rules done." 873 | ;; 874 | help|-h|--help|"") 875 | echo "Usage: $0 {enable|disable|renew}" 876 | echo 877 | echo "Commands:" 878 | echo " enable - Enable iptables rules" 879 | echo " disable - Disable iptables rules" 880 | echo " renew - Reapply or refresh iptables rules" 881 | echo 882 | echo "Example:" 883 | echo " $0 enable" 884 | ;; 885 | *) 886 | echo "$0: '$1' not found" 887 | echo "Run '$0 help' for usage." 888 | ;; 889 | esac 890 | fi 891 | --------------------------------------------------------------------------------