From b8a51ee1c22fec407c22a7bc553738a8f89da708 Mon Sep 17 00:00:00 2001 From: taamarin <71506581+taamarin@users.noreply.github.com> Date: Sat, 16 Aug 2025 13:44:25 +0700 Subject: [PATCH] feat: introduce network-based service control with Wi-Fi/SSID options --- box/scripts/ctr.inotify | 223 ++++++++++++++++++++++++++++++++++++++++ box/scripts/ctr.utils | 34 ++++++ box/scripts/start.sh | 29 ++++-- box/settings.ini | 31 +++++- 4 files changed, 310 insertions(+), 7 deletions(-) create mode 100755 box/scripts/ctr.inotify create mode 100755 box/scripts/ctr.utils diff --git a/box/scripts/ctr.inotify b/box/scripts/ctr.inotify new file mode 100755 index 0000000..67feeba --- /dev/null +++ b/box/scripts/ctr.inotify @@ -0,0 +1,223 @@ +#!/system/bin/sh + +export PATH="/data/adb/magisk:/data/adb/ksu/bin:/data/adb/ap/bin:$PATH:/data/data/com.termux/files/usr/bin" + +module_dir="/data/adb/modules/box_for_root" +base_dir="/data/adb/box" +variab_dir="${base_dir}/run/variab" +log_file="${base_dir}/run/Networkswitch_debug.log" +log_file_path="/data/local/tmp/" +temp_log_file="${log_file_path}debug.log.tmp" +last_check_file="${variab_dir}/last_check_time" +last_wifi_state_file="${variab_dir}/last_wifi_state" + +if [ ! -d "$variab_dir" ]; then + mkdir -p "$variab_dir" +fi + +scripts=$(realpath "$0") +scripts_dir=$(dirname "${scripts}") + +events=$1 +if [ "$events" != "w" ]; then + return +fi + +source "${base_dir}/settings.ini" + +if [ "$enable_network_service_control" != "true" ]; then + exit 0 +fi + +source "${scripts_dir}/ctr.utils" + +service_script="${scripts_dir}/box.service" +iptables_script="${scripts_dir}/box.iptables" + +log_msg() { + if [ "$inotify_log_enabled" = "true" ]; then + if [ -z "$1" ]; then + echo "" >> "$log_file" + else + echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$log_file" + fi + fi +} + +clean_old_logs() { + # Only keep logs from the past 24 hours + local retention_seconds=86400 # 24 hours + local cutoff_time=$(( $(date +%s) - retention_seconds )) + local cutoff_str + cutoff_str=$(date -d "@${cutoff_time}" '+%Y-%m-%d %H:%M:%S') + + if [ -f "$log_file" ]; then + awk -v cutoff="$cutoff_str" ' + !/^[0-9]{4}-[0-9]{2}-[0-9]{2}/ {print; next} + substr($0, 1, 19) >= cutoff {print} + ' "$log_file" > "$temp_log_file" && mv "$temp_log_file" "$log_file" + fi +} +clean_old_logs + +current_time=$(date +%s) +last_check_time=0 +if [ -f "$last_check_file" ]; then + last_check_time=$(cat "$last_check_file") +fi + +time_diff=$((current_time - last_check_time)) +stability_window=3 + +if [ "$time_diff" -lt "$stability_window" ]; then + log_msg "Skip check: (${time_diff}s), within stability window" + return +fi + +echo "$current_time" > "$last_check_file" + +wifi_status=$(is_wifi_connected) +ssid=$(get_current_ssid) + +get_current_ip() { + ip addr show wlan0 | grep 'inet ' | awk '{print $2}' | cut -d/ -f1 +} + +check_module_service() { + if [ "$enable_network_service_control" = "true" ]; then + if [ -f "$box_pid" ]; then + current_state="enabled" + else + current_state="disabled" + fi + + last_ssid="" + last_ip="" + if [ -f "$last_wifi_state_file" ]; then + last_ssid=$(grep 'ssid:' "$last_wifi_state_file" | cut -d: -f2) + last_ip=$(grep 'ip:' "$last_wifi_state_file" | cut -d: -f2) + fi + + if [ "$wifi_status" = "wifi" ] && [ -n "$ssid" ]; then + for i in {1..3}; do + current_ip=$(get_current_ip) + if [ -n "$current_ip" ]; then + break + fi + sleep 2 + done + + if [ -n "$current_ip" ]; then + log_msg "--- Network state change: WiFi connected ---" + log_msg "SSID: ${ssid}, IP: ${current_ip}" + echo "ssid:${ssid}" > "$last_wifi_state_file" + echo "ip:${current_ip}" >> "$last_wifi_state_file" + + if [ "$use_module_on_wifi" = "false" ]; then + log_msg "Policy: Disable service when on WiFi" + if [ "$current_state" != "disabled" ]; then + "$iptables_script" disable + "$service_script" stop + log_msg "Action: Service stopped" + else + log_msg "State: Service already stopped, no action needed" + fi + else + if [ "$use_ssid_matching" = "true" ]; then + if [ "$use_wifi_list_mode" = "blacklist" ]; then + log_msg "Policy: WiFi blacklist mode, list: ${wifi_ssids_list}" + if is_allowed_wifi "$ssid" "$wifi_ssids_list"; then + log_msg "Result: ${ssid} is in blacklist" + if [ "$current_state" != "disabled" ]; then + "$iptables_script" disable + "$service_script" stop + log_msg "Action: Service stopped" + else + log_msg "State: Service already stopped, no action needed" + fi + else + log_msg "Result: ${ssid} not in blacklist" + if [ "$current_state" != "enabled" ]; then + "$service_script" start + "$iptables_script" enable + log_msg "Action: Service started" + else + log_msg "State: Service already running, no action needed" + fi + fi + elif [ "$use_wifi_list_mode" = "whitelist" ]; then + log_msg "Policy: WiFi whitelist mode, list: ${wifi_ssids_list}" + if is_allowed_wifi "$ssid" "$wifi_ssids_list"; then + log_msg "Result: ${ssid} is in whitelist" + if [ "$current_state" != "enabled" ]; then + "$service_script" start + "$iptables_script" enable + log_msg "Action: Service started" + else + log_msg "State: Service already running, no action needed" + fi + else + log_msg "Result: ${ssid} not in whitelist" + if [ "$current_state" != "disabled" ]; then + "$iptables_script" disable + "$service_script" stop + log_msg "Action: Service stopped" + else + log_msg "State: Service already stopped, no action needed" + fi + fi + else + log_msg "Warning: Unknown WiFi list mode, using default start logic" + if [ "$current_state" != "enabled" ]; then + "$service_script" start + "$iptables_script" enable + log_msg "Action: Service started" + else + log_msg "State: Service already running, no action needed" + fi + fi + else + log_msg "Policy: Default behavior is to start service on WiFi" + if [ "$current_state" != "enabled" ]; then + "$service_script" start + "$iptables_script" enable + log_msg "Action: Service started" + else + log_msg "State: Service already running, no action needed" + fi + fi + fi + else + log_msg "--- Network state change: WiFi connecting ---" + log_msg "State: No valid IP address yet, skipping action" + fi + + elif [ "$wifi_status" = "not_wifi" ]; then + log_msg "--- Network state change: WiFi disconnected ---" + if [ "$use_module_on_wifi_disconnect" = "true" ]; then + log_msg "Policy: Start service when WiFi disconnected" + if [ "$current_state" != "enabled" ]; then + "$service_script" start + "$iptables_script" enable + log_msg "Action: Service started" + else + log_msg "State: Service already running, no action needed" + fi + else + log_msg "Policy: Disable service when WiFi disconnected" + if [ "$current_state" != "disabled" ]; then + "$iptables_script" disable + "$service_script" stop + log_msg "Action: Service stopped" + else + log_msg "State: Service already stopped, no action needed" + fi + fi + fi + else + log_msg "Network control module service is disabled!" + return + fi +} + +check_module_service \ No newline at end of file diff --git a/box/scripts/ctr.utils b/box/scripts/ctr.utils new file mode 100755 index 0000000..1d8aad0 --- /dev/null +++ b/box/scripts/ctr.utils @@ -0,0 +1,34 @@ +#!/system/bin/sh + +get_current_ssid() { + SSID=$(dumpsys wifi | grep 'mWifiInfo' | head -n 1 | cut -d '"' -f 2) + if [ -z "$SSID" ] || [ "$SSID" = "" ]; then + SSID=$(iwconfig wlan0 | grep 'ESSID' | awk -F ':' '{print $2}' | tr -d '"') + if [ -z "$SSID" ] || [ "$SSID" = "off/any" ]; then + echo "unknown" + else + echo "$SSID" + fi + else + echo "$SSID" + fi +} +is_wifi_connected() { + wifi_enabled=$(dumpsys wifi | grep 'Wi-Fi is enabled') + wifi_ip=$(ip addr show wlan0 | grep 'inet ' | awk '{print $2}' | cut -d/ -f1) + + if [ -n "$wifi_enabled" ] && [ -n "$wifi_ip" ]; then + echo "wifi" + else + echo "not_wifi" + fi +} +is_allowed_wifi() { + local ssid=$1 + local allowed_ssids=$2 + if echo " $allowed_ssids " | tr ',' ' ' | grep -q " $ssid "; then + return 0 + else + return 1 + fi +} \ No newline at end of file diff --git a/box/scripts/start.sh b/box/scripts/start.sh index baa1b47..2017e9c 100755 --- a/box/scripts/start.sh +++ b/box/scripts/start.sh @@ -9,6 +9,12 @@ busybox="/data/adb/magisk/busybox" [ -f "/data/adb/ksu/bin/busybox" ] && busybox="/data/adb/ksu/bin/busybox" [ -f "/data/adb/ap/bin/busybox" ] && busybox="/data/adb/ap/bin/busybox" +wait_for_data_ready() { + while [ ! -f "/data/system/packages.xml" ] ; do + sleep 1 + done +} + refresh_box() { if [ -f "/data/adb/box/run/box.pid" ]; then "${scripts_dir}/box.service" stop >> "/dev/null" 2>&1 @@ -37,13 +43,23 @@ enable_iptables() { } net_inotifyd() { - while [ ! -f /data/misc/net/rt_tables ] ; do - sleep 3 + net_dir="/data/misc/net" + ctr_dir="/data/misc/net/rt_tables" + + # Start inotifyd to watch for network-related changes. + # - The /proc filesystem cannot be monitored with inotify. + # - Polling in a loop is inefficient, so inotify is used instead. + # - Here we monitor /data/misc/net and /data/misc/net/rt_tables + # because they reflect changes in routing tables and interfaces. + + # Wait until at least one of the target files/directories exists + while [ ! -f "$ctr_dir" ] && [ ! -f "$net_dir" ]; do + sleep 3 done - net_dir="/data/misc/net" - # Use inotifyd to monitor write events in the /data/misc/net directory for network changes, perhaps we have a better choice of files to monitor (the /proc filesystem is unsupported) and cyclic polling is a bad solution - inotifyd "${scripts_dir}/net.inotify" "${net_dir}" > "/dev/null" 2>&1 & + # Launch inotifyd handlers in the background + inotifyd "${scripts_dir}/ctr.inotify" "$ctr_dir" >/dev/null 2>&1 & + inotifyd "${scripts_dir}/net.inotify" "$net_dir" >/dev/null 2>&1 & } start_inotifyd() { @@ -63,13 +79,14 @@ start_inotifyd() { mkdir -p /data/adb/box/run/ if [ -f "/data/adb/box/manual" ]; then if [ -f "/data/adb/box/run/box.pid" ]; then - rm /data/adb/box/run/box.pid + rm -rf /data/adb/box/run/box.pid fi net_inotifyd exit 1 fi if [ -f "$file_settings" ] && [ -r "$file_settings" ] && [ -s "$file_settings" ]; then + wait_for_data_ready refresh_box start_service enable_iptables diff --git a/box/settings.ini b/box/settings.ini index ca19dcc..96d7bb0 100755 --- a/box/settings.ini +++ b/box/settings.ini @@ -176,11 +176,40 @@ packages_list=($(sed -n '/^[^#]/s/^\([^ ]*\.[^ ]*\).*/\1/p' ${pkg_config})) # gid_list=($(sed -n '/^[^#]/s/^\([0-9]\{1,8\}\).*/\1/p' ${pkg_config})) gid_list=($(busybox awk '!/^#/ && /^[0-9]+$/ {print $1}' ${pkg_config})) +# ----------------------------------------------------------------- +# Network State Control +# ----------------------------------------------------------------- + +# Enable or disable controlling the module service based on network state +# false = "disabled by default" | true = "enabled" +enable_network_service_control=false + +# Enable module service when Wi-Fi is disconnected +use_module_on_wifi_disconnect=true + +# Enable module service when connected to Wi-Fi +use_module_on_wifi=false + +# Enable Wi-Fi SSID matching (requires SSID list) +use_ssid_matching=false + +# Wi-Fi SSID matching mode +# blacklist = deny listed SSIDs | whitelist = allow only listed SSIDs +use_wifi_list_mode="blacklist" + +# Wi-Fi SSID list to match (multiple SSIDs separated by spaces or commas) +wifi_ssids_list="WiFi1 WiFi2" + +# Enable inotify debug logging for network switching +inotify_log_enabled="true" + notify() { + true + # eg: notify $title $content # using Xposed edge app toast # am start -a android.intent.action.VIEW -n com.jozein.xedgepro/.ui.ActivityPerformAction --ei __0 111 --es __1 "$2" >/dev/null 2>&1 - true + # using system notification # su -lp "2000" -c "cmd notification post -S messaging --conversation '$1' --message '$1':'$2' 'Tag' '$(echo $RANDOM)' " >/dev/null 2>&1 }