#!/bin/sh # This is free software, licensed under the Apache License, Version 2.0 # # Copyright (C) 2024 Hilman Maulana , Anas Fanani # Environment COUNT_FAILURE=0 COUNT_SUCCESS=0 DEVICES_FOUND=0 COMMAND_FOUND=0 DEVICES_ROOT=0 FAILURE_LIMIT=$(uci get droidnet.monitoring.failure_limit) SUCCESS_LIMIT=$(uci get droidnet.monitoring.success_limit) DEVICES_ID=$(uci get droidnet.device.id) WAIT_TIME=$(uci get droidnet.monitoring.wait_time) HOST=$(uci get droidnet.monitoring.host) PORT=$(uci get droidnet.monitoring.ping) INTERFACE_NAME=$(uci get droidnet.monitoring.interface) RESTART_TUNNEL=$(uci get droidnet.monitoring.restart) TOOL_TUNNELING=$(uci get droidnet.monitoring.tunnel_service) PING_SUCCESS="Ping to '$HOST' using '$PORT' succeeded." PING_BACKGROUND="Ping to '$HOST' using '$PORT' successfuly, starting continuous ping in the background." # Functions log() { echo "$(date +"%a, %b %d, %I:%M:%S %p") - Monitoring service: $1" >> /var/log/droidnet.log } check_devices() { log "Checking devices." for DEVICE in $(adb devices -l | awk 'NR>1 && /device/ {print $1}'); do if [ $DEVICE = $DEVICES_ID ]; then DEVICES_FOUND=1 log "Device found in the list of connected devices." break fi done if [ $DEVICES_FOUND -eq 1 ]; then log "Checking root status on device." if adb -s $DEVICES_ID shell su -v 2>&1 | grep -q "/system/bin/sh: su: not found"; then INFO_ROOT="Non-root" log "Device not rooted." else INFO_ROOT="Rooted" DEVICES_ROOT=1 log "Device is rooted." fi log "Checking availability of airplane mode command on device." INFO_ANDROID=$(adb -s $DEVICES_ID shell getprop ro.build.version.release) INFO_VERSION=${INFO_ANDROID%%.*} if [ $INFO_VERSION -lt 10 ]; then if [ $DEVICES_ROOT -eq 1 ]; then COMMAND_FOUND=1 log "Airplane mode can be turned on." else log "Airplane mode can't be turned on." fi else COMMAND_FOUND=1 log "Airplane mode can be turned on." fi log "Device information" GET_INFO=$(adb devices -l | grep $DEVICES_ID) INFO_USB=$(echo $GET_INFO | awk '{for(i=1;i<=NF;i++) if($i ~ /^usb:/) print $i}') INFO_MODEL=$(echo $GET_INFO | awk '{for(i=1;i<=NF;i++) if($i ~ /^model:/) {split($i, a, ":"); print a[2]}}') log "ID: $DEVICES_ID, Model: $INFO_MODEL, Android: $INFO_ANDROID, Status: $INFO_ROOT, Connection: $INFO_USB" else log "Device not found in the list of connected devices." fi } enable_airplane_mode() { log "Turning on Airplane mode." if [ $DEVICES_ROOT -eq 1 ] && [ $INFO_VERSION -lt 10 ]; then adb -s $DEVICES_ID shell su -c 'settings put global airplane_mode_on 1' adb -s $DEVICES_ID shell su -c 'am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true' else adb -s $DEVICES_ID shell cmd connectivity airplane-mode enable fi } disable_airplane_mode() { log "Turning off Airplane mode." if [ $DEVICES_ROOT -eq 1 ] && [ $INFO_VERSION -lt 10 ]; then adb -s $DEVICES_ID shell su -c 'settings put global airplane_mode_on 0' adb -s $DEVICES_ID shell su -c 'am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false' else adb -s $DEVICES_ID shell cmd connectivity airplane-mode disable fi } restart_interface() { log "Restarting interface $INTERFACE_NAME." ifup $INTERFACE_NAME } disable_neko() { log "Disabling Neko." /etc/init.d/neko stop } enable_neko() { log "Enabling Neko." /etc/init.d/neko start } disable_openclash() { log "Disabling OpenClash." /etc/init.d/openclash stop } enable_openclash() { log "Enabling OpenClash." /etc/init.d/openclash start } disable_passwall() { log "Disabling PassWall." /etc/init.d/passwall stop } enable_passwall() { log "Enabling PassWall." /etc/init.d/passwall start } disable_v2ray() { log "Disabling V2Ray." start-stop-daemon -K -p /var/run/v2raya.pid } enable_v2ray() { log "Enabling V2Ray." start-stop-daemon -b -S -m -p /var/run/v2raya.pid -x /usr/bin/enable_v2rayA } reconnection() { log "Starting connection update service on the device." if [ $RESTART_TUNNEL = 1 ]; then log "Disabling tunneling tool." if [ $TOOL_TUNNELING = "neko" ]; then disable_neko elif [ $TOOL_TUNNELING = "openclash" ]; then disable_openclash elif [ $TOOL_TUNNELING = "passwall" ]; then disable_passwall elif [ $TOOL_TUNNELING = "v2ray" ]; then disable_v2ray else log "Tunneling tool '$TOOL_TUNNELING' not found, please install it first." fi elif [ $RESTART_TUNNEL = 0 ]; then log "Skipping disabling tunneling tool." fi enable_airplane_mode sleep $WAIT_TIME disable_airplane_mode sleep $WAIT_TIME restart_interface if [ $RESTART_TUNNEL = 1 ]; then log "Enabling tunneling tool." if [ $TOOL_TUNNELING = "neko" ]; then enable_neko elif [ $TOOL_TUNNELING = "openclash" ]; then enable_openclash elif [ $TOOL_TUNNELING = "passwall" ]; then enable_passwall elif [ $TOOL_TUNNELING = "v2ray" ]; then enable_v2ray else log "Tunneling tool '$TOOL_TUNNELING' not found, please install it first." fi elif [ $RESTART_TUNNEL = 0 ]; then log "Skipping enabling tunneling tool." fi log "Connection update service on the device has completed." COUNT_FAILURE=0 } ping_else() { log "Ping to '$HOST' using '$PORT' failed." COUNT_FAILURE=$((COUNT_FAILURE + 1)) COUNT_SUCCESS=0 if [ $COUNT_FAILURE -ge $FAILURE_LIMIT ]; then log "Failed ping to '$HOST' using '$PORT' $FAILURE_LIMIT times." reconnection fi } ping_http() { if curl -Is "http://$HOST:80" > /dev/null; then COUNT_SUCCESS=$((COUNT_SUCCESS + 1)) if [ $SUCCESS_LIMIT = "unlimited" ] || [ $COUNT_SUCCESS -le $SUCCESS_LIMIT ]; then log $PING_SUCCESS fi COUNT_FAILURE=0 if [ $COUNT_SUCCESS -eq $SUCCESS_LIMIT ]; then log $PING_BACKGROUND fi else ping_else fi } ping_https() { if curl -Is "https://$HOST:443" > /dev/null; then COUNT_SUCCESS=$((COUNT_SUCCESS + 1)) if [ $SUCCESS_LIMIT = "unlimited" ] || [ $COUNT_SUCCESS -le $SUCCESS_LIMIT ]; then log $PING_SUCCESS fi COUNT_FAILURE=0 if [ $COUNT_SUCCESS -eq $SUCCESS_LIMIT ]; then log $PING_BACKGROUND fi else ping_else fi } ping_icmp() { ping -q -c 3 -W 3 -p 0 $HOST > /dev/null if [ $? -eq 0 ]; then COUNT_SUCCESS=$((COUNT_SUCCESS + 1)) if [ $SUCCESS_LIMIT = "unlimited" ] || [ $COUNT_SUCCESS -le $SUCCESS_LIMIT ]; then log $PING_SUCCESS fi COUNT_FAILURE=0 if [ $COUNT_SUCCESS -eq $SUCCESS_LIMIT ]; then log $PING_BACKGROUND fi else ping_else fi } ping_tcp() { if nc -zvw 1 $HOST 80 2>&1 | grep -q succeeded; then COUNT_SUCCESS=$((COUNT_SUCCESS + 1)) if [ $SUCCESS_LIMIT = "unlimited" ] || [ $COUNT_SUCCESS -le $SUCCESS_LIMIT ]; then log $PING_SUCCESS fi COUNT_FAILURE=0 if [ $COUNT_SUCCESS -eq $SUCCESS_LIMIT ]; then log $PING_BACKGROUND fi else ping_else fi } start_service() { log "Starting service." check_devices if [ $DEVICES_FOUND -eq 1 ] && [ $COMMAND_FOUND -eq 1 ]; then log "Starting ping to '$HOST' using '$PORT'." while true; do if [ $PORT = "http" ]; then ping_http elif [ $PORT = "https" ]; then ping_https elif [ $PORT = "icmp" ]; then ping_icmp elif [ $PORT = "tcp" ]; then ping_tcp fi sleep 5 done else log "Failed to start service." exit 1 fi } stop_service() { log "Stopping service." SERVICE_PID=$(pgrep -f /usr/share/droidnet/monitoring) kill $SERVICE_PID } restart_service() { log "Restarting service." SERVICE_PID=$(pgrep -f /usr/share/droidnet/monitoring | head -n 1) start_service } # Main script if [ "$1" = "start" ]; then start_service elif [ "$1" = "stop" ]; then stop_service elif [ "$1" = "restart" ]; then restart_service else echo "Syntax: Monitoring service [DroidNet]" echo "Available commands:" echo " start Start the service" echo " stop Stop the service" echo " restart Restart the service" fi reload_service() { restart }