#!/system/bin/sh # Validate settings.ini if ! /system/bin/sh -n /data/adb/box/settings.ini 2>"/data/adb/box/run/settings_err.log"; then echo "Err: settings.ini contains a syntax error" | tee -a "/data/adb/box/run/settings_err.log" exit 1 fi scripts_dir="${0%/*}" source /data/adb/box/settings.ini fwmark="16777216/16777216" table="2024" pref="100" # disable or enable QUIC using iptables rules. Note that this may cause some websites to become inaccessible. quic="enable" clash_dns_forward="enable" fake_ip_range="" [ "${stealth_block_quic}" = "true" ] && quic="disable" # ex: 7.1.1 buildVersion=$(getprop ro.build.version.release) minBuildVersion="11" IPV="iptables" # Default IP6V="ip6tables" # Default # ex: 7.1.1 -> 7 buildVersionMajor=${buildVersion%%.*} if [ "$buildVersionMajor" -ge "$minBuildVersion" ]; then IPV="iptables -w 100" IP6V="ip6tables -w 100" fi case "${bin_name}" in "clash") clash_mode=$(busybox awk '!/^ *#/ && /mode: / { print $2;found=1; exit } END{ if(!found) print "rules" }' "${clash_config}" 2>/dev/null) clash_enhanced_mode=$(busybox awk '!/^ *#/ && /enhanced-mode: / { print $2;found=1; exit } END{ if(!found) print "fake-ip" }' "${clash_config}" 2>/dev/null) 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) clash_dns_port=$(sed -n '/^dns:/,/^[^ ]/p' "${clash_config}" | grep -E '^[^#]*listen:.*:[0-9]+' | grep -Eo '[0-9]+' | tail -n 1) clash_dns_port=${clash_dns_port:-1053} if [[ "${network_mode}" == @(mixed|tun) ]]; then tun_device=$(busybox awk '!/^ *#/ && /device: / { print $2;found=1; exit } END{ if(!found) print "meta" }' "${clash_config}" 2>/dev/null) fi ;; "sing-box") if [[ "${network_mode}" == @(mixed|tun) ]]; then 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) if [ -z "$tun_device" ]; then tun_device="tun0" fi fi fake_ip_range=$(find ${box_dir}/sing-box/ -maxdepth 1 -type f -name "*.json" -exec busybox awk -F'"' '/inet4_range/ {print $4}' {} +) fake_ip6_range=$(find ${box_dir}/sing-box/ -maxdepth 1 -type f -name "*.json" -exec busybox awk -F'"' '/inet6_range/ {print $4}' {} +) ;; "hysteria") case "${network_mode}" in redirect|tproxy|enhance) true # do nothing ;; *) log Warning "$bin_name does not support network_mode: $network_mode, return to TProxy" sed -i 's/\(network_mode=\)\"[^\"]*\"/\1"tproxy"/g' ${settings} ;; esac ;; "xray" | "v2fly") if [[ "${network_mode}" != "tproxy" ]]; then log Warning "$bin_name does not support network_mode: $network_mode, return to TProxy" sed -i 's/\(network_mode=\)\"[^\"]*\"/\1"tproxy"/g' ${settings} fi ;; *) log Error "<${bin_name}> unknown binary." exit 1 ;; esac box_etc() { case "${bin_name}" in clash) log Debug "enhanced-mode: $clash_enhanced_mode, fake-ip-range: $fake_ip_range, listen-port: $clash_dns_port, mode: $clash_mode" ;; sing-box) if [ -n "${fake_ip_range}" ] && [ "${bin_name}" = "sing-box" ]; then log Debug "fake-ip-range: ${fake_ip_range}, ${fake_ip6_range}" fi ;; *) true ;; esac if [[ "${network_mode}" == @(mixed|tun) ]]; then log Info "tun device: ($tun_device)" fi } bin_alive() { local PID=$(<"${box_pid}" 2>/dev/null) if ! kill -0 "$PID" >/dev/null; then log Error "$(<"${box_run}/${bin_name}.log")" log Error "${bin_name} service is not running." log Error "please check ${bin_name}.log for more information." log Error "killing stale pid $PID" for bin in "${bin_list[@]}"; do killall -15 "${bin}" >/dev/null 2>&1 || busybox pkill -15 "${bin}" >/dev/null 2>&1 done cleanup_iptables [ -f "${box_pid}" ] && rm -f "${box_pid}" return 1 else return 0 fi } find_packages_uid() { echo -n "" > "${uid_list}" for package in "${packages_list[@]}"; do if [[ "$package" == *:* ]]; then user="${package%%:*}" pkg="${package##*:}" else user=0 pkg="$package" fi appid="$(busybox awk -v p="$pkg" '$1 == p {print $2}' "$system_packages_file")" if [[ -n "$appid" ]]; then uid=$((user * 100000 + appid)) echo "$uid" >> "${uid_list}" fi done } probe_user_group() { if PID=$(busybox pidof ${bin_name}) ; then box_user=$(stat -c %U /proc/$PID) box_group=$(stat -c %G /proc/$PID) return 0 else IFS=':' read -r box_user box_group <<< "${box_user_group}" return 1 fi } disable_ipv6() { sysctl -w net.ipv4.ip_forward=1 sysctl -w net.ipv6.conf.all.forwarding=0 sysctl -w net.ipv6.conf.all.accept_ra=0 sysctl -w net.ipv6.conf.wlan0.accept_ra=0 sysctl -w net.ipv6.conf.all.disable_ipv6=1 sysctl -w net.ipv6.conf.default.disable_ipv6=1 sysctl -w net.ipv6.conf.wlan0.disable_ipv6=1 # add: block Askes ipv6 completely ip -6 rule add unreachable pref "${pref}" } >/dev/null 2>&1 ipv6_enable() { sysctl -w net.ipv4.ip_forward=1 sysctl -w net.ipv6.conf.all.forwarding=1 sysctl -w net.ipv6.conf.all.accept_ra=2 sysctl -w net.ipv6.conf.wlan0.accept_ra=2 sysctl -w net.ipv6.conf.all.disable_ipv6=0 sysctl -w net.ipv6.conf.default.disable_ipv6=0 sysctl -w net.ipv6.conf.wlan0.disable_ipv6=0 # del: block Askes ipv6 completely ip -6 rule del unreachable pref "${pref}" # add: blocks all outgoing IPv6 traffic using the UDP protocol to port 53, effectively preventing DNS queries over IPv6. $IP6V -A OUTPUT -p udp --destination-port 53 -j DROP } >/dev/null 2>&1 intranet=( 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.0.0.0/24 192.0.2.0/24 192.88.99.0/24 192.168.0.0/16 198.51.100.0/24 203.0.113.0/24 224.0.0.0/4 240.0.0.0/4 255.0.0.0/4 255.255.255.0/24 255.255.255.255/32 ) # 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. intranet+=($(ip -4 a | busybox awk '/inet/ {print $2}' | busybox grep -vE "^127.0.0.1")) intranet6=( ::/128 ::1/128 ::ffff:0:0/96 100::/64 64:ff9b::/96 2001::/32 2001:10::/28 2001:20::/28 2001:db8::/32 2002::/16 fc00::/7 fe80::/10 ff00::/8 ) intranet6+=($(ip -6 a | busybox awk '/inet6/ {print $2}' | busybox grep -vE "^fe80|^::1|^fd00")) probe_tun_device() { busybox ifconfig | grep -q "${tun_device}" || return 1 } forward() { local action=$1 # ${iptables} -t nat ${action} POSTROUTING -o ${tun_device} -j MASQUERADE ${iptables} "${action}" FORWARD -i "${tun_device}" -j ACCEPT ${iptables} "${action}" FORWARD -o "${tun_device}" -j ACCEPT sysctl -w net.ipv4.ip_forward=1 sysctl -w net.ipv4.conf.default.rp_filter=2 sysctl -w net.ipv4.conf.all.rp_filter=2 } >/dev/null 2>&1 start_redirect() { if [ "${iptables}" = "$IPV" ]; then ${iptables} -t nat -N BOX_EXTERNAL ${iptables} -t nat -F BOX_EXTERNAL ${iptables} -t nat -N BOX_LOCAL ${iptables} -t nat -F BOX_LOCAL fi if [ "${iptables}" = "$IPV" ]; then if [ "${bin_name}" = "clash" ]; then ${iptables} -t nat -A BOX_EXTERNAL -p udp --dport 53 -j REDIRECT --to-ports "${clash_dns_port}" ${iptables} -t nat -A BOX_LOCAL -p udp --dport 53 -j REDIRECT --to-ports "${clash_dns_port}" # else # Other types of inbound should be added here to receive DNS traffic instead of sniffing # ${iptables} -t nat -A BOX_EXTERNAL -p udp --dport 53 -j REDIRECT --to-ports "${redir_port}" # ${iptables} -t nat -A BOX_LOCAL -p udp --dport 53 -j REDIRECT --to-ports "${redir_port}" fi # Fix ICMP (ping). This does not guarantee that the ping result is valid. Just that it returns a result # if [[ "${bin_name}" == @(clash|sing-box) ]]; then # if [ -n "${fake_ip_range}" ]; then # ${iptables} -t nat -A BOX_EXTERNAL -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 # ${iptables} -t nat -A BOX_LOCAL -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 # fi # fi ${iptables} -t nat -N LOCAL_IP_V4 ${iptables} -t nat -F LOCAL_IP_V4 for subnet in ${intranet[@]} ; do ${iptables} -t nat -A BOX_EXTERNAL -d ${subnet} -j RETURN ${iptables} -t nat -A BOX_LOCAL -d ${subnet} -j RETURN done ${iptables} -t nat -A BOX_EXTERNAL -j LOCAL_IP_V4 ${iptables} -t nat -A BOX_LOCAL -j LOCAL_IP_V4 ${iptables} -t nat -A BOX_EXTERNAL -p tcp -i lo -j REDIRECT --to-ports "${redir_port}" if [ "${ap_list}" != "" ]; then for ap in "${ap_list[@]}"; do ${iptables} -t nat -A BOX_EXTERNAL -p tcp -i "${ap}" -j REDIRECT --to-ports "${redir_port}" done [ ${network_mode} = "enhance" ] || log Info "${ap_list[*]} transparent proxy." fi ${iptables} -t nat -I PREROUTING -j BOX_EXTERNAL ${iptables} -t nat -I BOX_LOCAL -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -j RETURN if [ "${ignore_out_list}" != "" ]; then for ignore in "${ignore_out_list[@]}"; do ${iptables} -t nat -A BOX_LOCAL -o "${ignore}" -j RETURN done [ ${network_mode} = "enhance" ] || log Info "${ignore_out_list[*]} ignore transparent proxy." fi fi if [ "${iptables}" = "$IPV" ]; then case "${proxy_mode}" in blacklist|black) if [ -z "$(cat "${uid_list[@]}")" ] ; then ${iptables} -t nat -A BOX_LOCAL -p tcp -j REDIRECT --to-ports "${redir_port}" [ ${network_mode} = "enhance" ] || log Info "Transparent proxy for all apps." else while read -r appid; do ${iptables} -t nat -A BOX_LOCAL -m owner --uid-owner "${appid}" -j RETURN done < "${uid_list[@]}" ${iptables} -t nat -A BOX_LOCAL -p tcp -j REDIRECT --to-ports "${redir_port}" [ ${network_mode} = "enhance" ] || log Info "proxy mode: ${proxy_mode} (${packages_list[*]}) no transparent proxy." fi if [ "${gid_list}" != "" ] ; then for gid in ${gid_list[@]} ; do ${iptables} -t nat -A BOX_LOCAL -m owner --gid-owner ${gid} -j RETURN done [ ${network_mode} = "enhance" ] || { [ "${iptables}" = "$IPV" ] && log Info "proxy mode: ${proxy_mode}, GID (${gid_list[*]}) no transparent proxy." } fi ;; whitelist|white) if [ -z "$(cat "${uid_list[@]}")" ] ; then ${iptables} -t nat -A BOX_LOCAL -p tcp -j REDIRECT --to-ports "${redir_port}" [ ${network_mode} = "enhance" ] || log Info "Transparent proxy for all apps." else while read -r appid; do ${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --uid-owner "${appid}" -j REDIRECT --to-ports "${redir_port}" done < "${uid_list[@]}" ${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --uid-owner 0 -j REDIRECT --to-ports "${redir_port}" ${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --uid-owner 1052 -j REDIRECT --to-ports "${redir_port}" [ ${network_mode} = "enhance" ] || log Info "proxy mode: ${proxy_mode} (${packages_list[*]}) transparent proxy." fi if [ "${gid_list}" != "" ] ; then for gid in ${gid_list[@]} ; do ${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --gid-owner ${gid} -j REDIRECT --to-ports ${redir_port} done [ ${network_mode} = "enhance" ] || [ "${iptables}" = "$IPV" ] && log Info "proxy mode: ${proxy_mode}, GID (${gid_list[*]}) transparent proxy." fi ;; *) log Warning "proxy mode: ${proxy_mode} < error." ${iptables} -t nat -A BOX_LOCAL -p tcp -j REDIRECT --to-ports "${redir_port}" [ ${network_mode} = "enhance" ] || log Info "Transparent proxy for all apps." ;; esac fi if [ "${iptables}" = "$IPV" ]; then ${iptables} -t nat -I OUTPUT -j BOX_LOCAL fi if [ "${iptables}" = "$IPV" ]; then ${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 else ${iptables} -A OUTPUT -d ::1 -p tcp -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -m tcp --dport "${redir_port}" -j REJECT fi } stop_redirect() { if [ "${iptables}" = "$IPV" ]; then ${iptables} -t nat -D PREROUTING -j BOX_EXTERNAL ${iptables} -t nat -D OUTPUT -j BOX_LOCAL fi if [ "${iptables}" = "$IPV" ]; then ${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 ${iptables} -D OUTPUT -d 127.0.0.1 -p tcp -m owner --uid-owner 0:3005 -m tcp --dport "${redir_port}" -j REJECT else ${iptables} -D OUTPUT -d ::1 -p tcp -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -m tcp --dport "${redir_port}" -j REJECT ${iptables} -D OUTPUT -d ::1 -p tcp -m owner --uid-owner 0:3005 -m tcp --dport "${redir_port}" -j REJECT fi if [ "${iptables}" = "$IPV" ]; then # ${iptables} -t nat -D BOX_EXTERNAL -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 # ${iptables} -t nat -D BOX_LOCAL -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 ${iptables} -t nat -F BOX_EXTERNAL ${iptables} -t nat -X BOX_EXTERNAL ${iptables} -t nat -F BOX_LOCAL ${iptables} -t nat -X BOX_LOCAL ${iptables} -t nat -F LOCAL_IP_V4 ${iptables} -t nat -X LOCAL_IP_V4 fi } start_tproxy() { if [ "${iptables}" = "$IPV" ]; then ip rule add fwmark "${fwmark}" table "${table}" pref "${pref}" ip route add local default dev lo table "${table}" else ip -6 rule add fwmark "${fwmark}" table "${table}" pref "${pref}" ip -6 route add local default dev lo table "${table}" fi ${iptables} -t mangle -N BOX_EXTERNAL >/dev/null 2>&1 ${iptables} -t mangle -F BOX_EXTERNAL >/dev/null 2>&1 # ${iptables} -t mangle -A BOX_EXTERNAL -m mark --mark ${routing_mark} -j RETURN # Bypass other if, notice: Some interface is named with r_ / oem / nm_ / qcom_, it might need more complicated solution. # ${iptables} -t mangle -I BOX_EXTERNAL -i rmnet_data+ -j RETURN # ${iptables} -t mangle -I BOX_EXTERNAL -i ccmni+ -j RETURN if [ "${clash_dns_forward}" = "enable" ] && [[ "${bin_name}" == @(clash|hysteria) ]] ; then [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_EXTERNAL -p tcp --dport 53 -j RETURN ${iptables} -t mangle -A BOX_EXTERNAL -p udp --dport 53 -j RETURN else [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_EXTERNAL -p tcp --dport 53 -j TPROXY --on-port ${tproxy_port} --tproxy-mark ${fwmark} ${iptables} -t mangle -A BOX_EXTERNAL -p udp --dport 53 -j TPROXY --on-port ${tproxy_port} --tproxy-mark ${fwmark} fi # Skip traffic already handled by TProxy # 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' # [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_EXTERNAL -p tcp -m socket --transparent -j MARK --set-xmark ${fwmark} # ${iptables} -t mangle -A BOX_EXTERNAL -p udp -m socket --transparent -j MARK --set-xmark ${fwmark} # ${iptables} -t mangle -A BOX_EXTERNAL -m socket -j RETURN # Bypass intranet, run `su -c 'zcat /proc/config.gz | grep -i addrtype'` to check compatibility # ${iptables} -t mangle -A BOX_EXTERNAL -m addrtype --dst-type LOCAL -j RETURN if [ "${iptables}" = "$IPV" ]; then for subnet in ${intranet[@]} ; do ${iptables} -t mangle -A BOX_EXTERNAL -d ${subnet} -j RETURN done ${iptables} -t mangle -N LOCAL_IP_V4 ${iptables} -t mangle -F LOCAL_IP_V4 ${iptables} -t mangle -A BOX_EXTERNAL -j LOCAL_IP_V4 else for subnet6 in ${intranet6[@]} ; do ${iptables} -t mangle -A BOX_EXTERNAL -d ${subnet6} -j RETURN done ${iptables} -t mangle -N LOCAL_IP_V6 ${iptables} -t mangle -F LOCAL_IP_V6 ${iptables} -t mangle -A BOX_EXTERNAL -j LOCAL_IP_V6 fi [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_EXTERNAL -p tcp -i lo -j TPROXY --on-port "${tproxy_port}" --tproxy-mark "${fwmark}" ${iptables} -t mangle -A BOX_EXTERNAL -p udp -i lo -j TPROXY --on-port "${tproxy_port}" --tproxy-mark "${fwmark}" # 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 if [ "${ap_list}" != "" ]; then for ap in ${ap_list[@]} ; do [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_EXTERNAL -p tcp -i "${ap}" -j TPROXY --on-port "${tproxy_port}" --tproxy-mark "${fwmark}" ${iptables} -t mangle -A BOX_EXTERNAL -p udp -i "${ap}" -j TPROXY --on-port "${tproxy_port}" --tproxy-mark "${fwmark}" done [ "${iptables}" = "$IPV" ] && log Info "${ap_list[*]} transparent proxy." fi ${iptables} -t mangle -I PREROUTING -j BOX_EXTERNAL ${iptables} -t mangle -N BOX_LOCAL ${iptables} -t mangle -F BOX_LOCAL ${iptables} -t mangle -A BOX_LOCAL -m owner --uid-owner ${box_user} --gid-owner ${box_group} -j RETURN # ${iptables} -t mangle -A BOX_LOCAL -m mark --mark ${routing_mark} -j RETURN if [ "${ignore_out_list}" != "" ]; then for ignore in ${ignore_out_list[@]} ; do ${iptables} -t mangle -A BOX_LOCAL -o "${ignore}" -j RETURN done [ "${iptables}" = "$IPV" ] && log Info "${ignore_out_list[*]} ignore transparent proxy." fi if [ "${clash_dns_forward}" = "enable" ] && [[ "${bin_name}" == @(clash|hysteria) ]] ; then [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp --dport 53 -j RETURN ${iptables} -t mangle -A BOX_LOCAL -p udp --dport 53 -j RETURN else [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp --dport 53 -j MARK --set-xmark ${fwmark} ${iptables} -t mangle -A BOX_LOCAL -p udp --dport 53 -j MARK --set-xmark ${fwmark} fi if [ "${iptables}" = "$IPV" ]; then for subnet in ${intranet[@]} ; do ${iptables} -t mangle -A BOX_LOCAL -d ${subnet} -j RETURN done ${iptables} -t mangle -A BOX_LOCAL -j LOCAL_IP_V4 else for subnet6 in ${intranet6[@]} ; do ${iptables} -t mangle -A BOX_LOCAL -d ${subnet6} -j RETURN done ${iptables} -t mangle -A BOX_LOCAL -j LOCAL_IP_V6 fi case "${proxy_mode}" in blacklist|black) if [ -z "$(cat "${uid_list[@]}")" ] ; then [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -j MARK --set-xmark "${fwmark}" ${iptables} -t mangle -A BOX_LOCAL -p udp -j MARK --set-xmark "${fwmark}" [ "${iptables}" = "$IPV" ] && log Info "transparent proxy for all apps." else while read -r appid; do ${iptables} -t mangle -A BOX_LOCAL -m owner --uid-owner "${appid}" -j RETURN done < "${uid_list[@]}" [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -j MARK --set-xmark "${fwmark}" ${iptables} -t mangle -A BOX_LOCAL -p udp -j MARK --set-xmark "${fwmark}" [ "${iptables}" = "$IPV" ] && log Info "proxy mode: ${proxy_mode} (${packages_list[*]}) no transparent proxy." fi if [ "${gid_list}" != "" ] ; then for gid in ${gid_list[@]} ; do ${iptables} -t mangle -A BOX_LOCAL -m owner --gid-owner ${gid} -j RETURN done [ "${iptables}" = "$IPV" ] && log Info "proxy mode: ${proxy_mode}, GID (${gid_list[*]}) no transparent proxy." fi ;; whitelist|white) if [ -z "$(cat "${uid_list[@]}")" ] ; then [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -j MARK --set-xmark "${fwmark}" ${iptables} -t mangle -A BOX_LOCAL -p udp -j MARK --set-xmark "${fwmark}" [ "${iptables}" = "$IPV" ] && log Info "transparent proxy for all apps." else while read -r appid; do [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --uid-owner "${appid}" -j MARK --set-xmark "${fwmark}" ${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --uid-owner "${appid}" -j MARK --set-xmark "${fwmark}" done < "${uid_list[@]}" [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --uid-owner 0 -j MARK --set-xmark "${fwmark}" ${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --uid-owner 0 -j MARK --set-xmark "${fwmark}" [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --uid-owner 1052 -j MARK --set-xmark "${fwmark}" ${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --uid-owner 1052 -j MARK --set-xmark "${fwmark}" [ "${iptables}" = "$IPV" ] && log Info "proxy mode: ${proxy_mode} (${packages_list[*]}) transparent proxy." fi if [ "${gid_list}" != "" ] ; then for gid in ${gid_list[@]} ; do [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --gid-owner ${gid} -j MARK --set-xmark "${fwmark}" ${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --gid-owner ${gid} -j MARK --set-xmark "${fwmark}" done [ "${iptables}" = "$IPV" ] && log Info "proxy mode: ${proxy_mode}, GID (${gid_list[*]}) transparent proxy." fi ;; *) log Debug "proxy mode: ${proxy_mode} < error" [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -A BOX_LOCAL -p tcp -j MARK --set-xmark "${fwmark}" ${iptables} -t mangle -A BOX_LOCAL -p udp -j MARK --set-xmark "${fwmark}" [ "${iptables}" = "$IPV" ] && log Info "transparent proxy for all apps." ;; esac ${iptables} -t mangle -I OUTPUT -j BOX_LOCAL ${iptables} -t mangle -N DIVERT ${iptables} -t mangle -F DIVERT ${iptables} -t mangle -A DIVERT -j MARK --set-xmark "${fwmark}" ${iptables} -t mangle -A DIVERT -j ACCEPT [ ${network_mode} = "enhance" ] || ${iptables} -t mangle -I PREROUTING -p tcp -m socket -j DIVERT # Disable QUIC if [ "${quic}" = "disable" ]; then ${iptables} -A OUTPUT -p udp --dport 443 -j REJECT ${iptables} -A OUTPUT -p udp --dport 80 -j REJECT # ${iptables} -A OUTPUT -p udp -m multiport --dport 443,80 -j REJECT [ "${iptables}" = "$IPV" ] && log Warning "Disabling QUIC" fi if [ ${network_mode} != "enhance" ]; then # This rule blocks local access to tproxy-port to prevent traffic loopback. if [ "${iptables}" = "$IPV" ]; then ${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 else ${iptables} -A OUTPUT -d ::1 -p tcp -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -m tcp --dport "${tproxy_port}" -j REJECT fi fi if [ "${iptables}" = "$IPV" ]; then if [ "${clash_dns_forward}" = "enable" ] && [ "${bin_name}" = "clash" ]; then ${iptables} -t nat -N CLASH_DNS_EXTERNAL ${iptables} -t nat -F CLASH_DNS_EXTERNAL ${iptables} -t nat -A CLASH_DNS_EXTERNAL -p udp --dport 53 -j REDIRECT --to-ports "${clash_dns_port}" ${iptables} -t nat -I PREROUTING -j CLASH_DNS_EXTERNAL ${iptables} -t nat -N CLASH_DNS_LOCAL ${iptables} -t nat -F CLASH_DNS_LOCAL ${iptables} -t nat -A CLASH_DNS_LOCAL -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -j RETURN ${iptables} -t nat -A CLASH_DNS_LOCAL -p udp --dport 53 -j REDIRECT --to-ports "${clash_dns_port}" ${iptables} -t nat -I OUTPUT -j CLASH_DNS_LOCAL fi # 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. if [[ "${bin_name}" == @(clash|sing-box) ]]; then if [ -n "${fake_ip_range}" ]; then ${iptables} -t nat -I OUTPUT -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 ${iptables} -t nat -I PREROUTING -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 fi fi fi } stop_tproxy() { if [ "${iptables}" = "$IPV" ]; then ip rule del fwmark "${fwmark}" table "${table}" pref "${pref}" ip route del local default dev lo table "${table}" ip route flush table "${table}" ip rule del pref "${pref}" else ip -6 rule del fwmark "${fwmark}" table "${table}" pref "${pref}" ip -6 route del local default dev lo table "${table}" ip -6 route flush table "${table}" ip -6 rule del pref "${pref}" fi ${iptables} -t mangle -D PREROUTING -j BOX_EXTERNAL ${iptables} -t mangle -D PREROUTING -p tcp -m socket -j DIVERT ${iptables} -t mangle -D OUTPUT -j BOX_LOCAL ${iptables} -t mangle -D BOX_EXTERNAL -i rmnet_data+ -j RETURN ${iptables} -t mangle -D BOX_EXTERNAL -i ccmni+ -j RETURN ${iptables} -t mangle -F BOX_EXTERNAL ${iptables} -t mangle -X BOX_EXTERNAL ${iptables} -t mangle -F BOX_LOCAL ${iptables} -t mangle -X BOX_LOCAL ${IPV} -t mangle -F LOCAL_IP_V4 ${IPV} -t mangle -X LOCAL_IP_V4 ${IP6V} -t mangle -F LOCAL_IP_V6 ${IP6V} -t mangle -X LOCAL_IP_V6 ${iptables} -t mangle -F DIVERT ${iptables} -t mangle -X DIVERT # flush QUIC ${iptables} -D OUTPUT -p udp -m multiport --dport 443,80 -j REJECT ${iptables} -D OUTPUT -p udp --dport 443 -j REJECT ${iptables} -D OUTPUT -p udp --dport 80 -j REJECT if [ "${iptables}" = "$IPV" ]; then ${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 ${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 else ${iptables} -D OUTPUT -d ::1 -p tcp -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -m tcp --dport "${tproxy_port}" -j REJECT ${iptables} -D OUTPUT -d ::1 -p tcp -m owner --uid-owner 0 --gid-owner 3005 -m tcp --dport "${tproxy_port}" -j REJECT fi if [ "${iptables}" = "$IPV" ]; then ${iptables} -t nat -D PREROUTING -j CLASH_DNS_EXTERNAL ${iptables} -t nat -D OUTPUT -j CLASH_DNS_LOCAL ${iptables} -t nat -F CLASH_DNS_EXTERNAL ${iptables} -t nat -X CLASH_DNS_EXTERNAL ${iptables} -t nat -F CLASH_DNS_LOCAL ${iptables} -t nat -X CLASH_DNS_LOCAL if [ -n "${fake_ip_range}" ]; then ${iptables} -t nat -D OUTPUT -p icmp -d "${fake_ip_range}" -j DNAT --to-destination 127.0.0.1 ${iptables} -t nat -D PREROUTING -p icmp -d "${fake_ip_range}" -j DNAT --to-destination 127.0.0.1 ${iptables} -t nat -D OUTPUT -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 ${iptables} -t nat -D PREROUTING -d "${fake_ip_range}" -p icmp -j DNAT --to-destination 127.0.0.1 fi fi } cleanup_iptables() { for iptables in "$IPV" "$IP6V"; do iptables="${iptables}" && { stop_redirect stop_tproxy forward -D } >/dev/null 2>&1 if [ "${iptables}" = "$IP6V" ]; then ${iptables} -D OUTPUT -p udp --destination-port 53 -j DROP >/dev/null 2>&1 fi done } if [[ "${network_mode}" == @(redirect|mixed|tproxy|enhance) ]]; then case "$1" in enable|renew) box_etc log Info "$IPV + $IP6V" probe_user_group || { log Error "Failed to check BOX user group. Please ensure ${bin_name} kernel is started." } find_packages_uid cleanup_iptables [ $1 = "renew" ] && log Warning "cleaning up iptables transparent proxy rules." case "${network_mode}" in tproxy) log Info "Using Tproxy: tcp + udp." log Info "Creating iptables transparent proxy rules." iptables="$IPV" if start_tproxy; then log Info "Creating iptables transparent proxy rules done." else log Error "Creating iptables transparent proxy rules failed." stop_tproxy >/dev/null 2>&1 fi if [ "${ipv6}" = "true" ]; then log Debug "Using IPv6." ipv6_enable iptables="$IP6V" if start_tproxy; then log Info "Creating ip6tables transparent proxy rules done." else log Error "Creating ip6tables transparent proxy rules failed." stop_tproxy >/dev/null 2>&1 fi else disable_ipv6 log Warning "Disabling IPv6." fi ;; redirect) log Info "Using Redirect: tcp + udp (direct)." log Info "Creating iptables transparent proxy rules." iptables="$IPV" if start_redirect; then log Info "Creating iptables transparent proxy rules done." else log Error "Creating iptables transparent proxy rule failed." stop_redirect >/dev/null 2>&1 fi if [ "${ipv6}" = "true" ]; then log Debug "Using IPv6." ipv6_enable iptables="$IP6V" if start_redirect; then log Info "Creating ip6tables transparent proxy rules done." else log Error "Creating ip6tables transparent proxy rule failed." stop_redirect >/dev/null 2>&1 fi else disable_ipv6 log Warning "Disabling IPv6." fi ;; mixed) log Info "Using Mixed: tcp(redirect) + udp(tun)." log Info "Creating iptables transparent proxy rules." iptables="$IPV" probe_tun_device || log Error "tun device: (${tun_device}) not found" forward -I || forward -D >/dev/null 2>&1 if start_redirect; then log Info "Creating iptables transparent proxy rules done." else log Error "Creating iptables transparent proxy rule failed." stop_redirect >/dev/null 2>&1 fi if [ "${ipv6}" = "true" ]; then log Debug "Using IPv6." ipv6_enable iptables="$IP6V" forward -I || forward -D >/dev/null 2>&1 if start_redirect; then log Info "Creating ip6tables transparent proxy rules done." else log Error "Creating ip6tables transparent proxy rule failed." stop_redirect >/dev/null 2>&1 fi else disable_ipv6 log Warning "Disabling IPv6." fi ;; enhance) log Info "Using Enhance: tcp(redirect) + udp(tproxy)" log Info "Creating iptables transparent proxy rules." iptables="$IPV" if start_redirect && start_tproxy; then log Info "Creating iptables transparent proxy rules done." else log Error "Creating iptables transparent proxy rule failed." stop_redirect >/dev/null 2>&1 fi if [ "${ipv6}" = "true" ]; then log Debug "Using IPv6." ipv6_enable iptables="$IP6V" if start_redirect && start_tproxy; then log Info "Creating ip6tables transparent proxy rules done." else log Error "Creating ip6tables transparent proxy rule failed." stop_redirect >/dev/null 2>&1 fi else disable_ipv6 log Warning "Disabling IPv6." fi ;; *) log Error "network_mode: ${network_mode}, unknown" exit 1 ;; esac [ $1 = "renew" ] && log Debug "restart iptables transparent proxy rules done." bin_alive && log Info "${bin_name} connected." "${scripts_dir}/box.stealth" enable >/dev/null 2>&1 ;; disable) ipv6_enable "${scripts_dir}/box.stealth" disable >/dev/null 2>&1 probe_user_group || log Error "Failed to check BOX user group. Please ensure ${bin_name} kernel is started." log Warning "Cleaning up iptables transparent proxy rules." cleanup_iptables log Warning "Cleaning up iptables transparent proxy rules done." ;; help|-h|--help|"") echo "Usage: $0 {enable|disable|renew}" echo echo "Commands:" echo " enable - Enable iptables rules" echo " disable - Disable iptables rules" echo " renew - Reapply or refresh iptables rules" echo echo "Example:" echo " $0 enable" ;; *) echo "$0: '$1' not found" echo "Run '$0 help' for usage." ;; esac else case "$1" in enable|renew) box_etc log Info "$IPV + $IP6V" log Info "Using Tun: tcp + udp." probe_user_group || { log Error "Failed to check BOX user group. Please ensure ${bin_name} kernel is started." } cleanup_iptables probe_tun_device || log Error "tun device: (${tun_device}) not found" [ $1 = "renew" ] && log Warning "Cleaning up tun rules." iptables="$IPV" [ -n "${packages_list}" ] && log Debug "proxy mode: $proxy_mode (${packages_list[*]})" if forward -I; then log Info "Create iptables tun rules done." else log Error "Create iptables tun rules failed." forward -D >/dev/null 2>&1 fi if [ "${ipv6}" = "true" ]; then log Debug "Using IPv6." ipv6_enable iptables="$IP6V" if forward -I; then log Info "Create ip6tables tun rules done." else log Error "Create ip6tables tun rules failed." forward -D >/dev/null 2>&1 fi else disable_ipv6 log Warning "Disable IPv6." fi [ $1 = "renew" ] && log Info "Restart iptables tun rules done." bin_alive && log Info "${bin_name} connected." ;; disable) ipv6_enable probe_user_group || log Error "Failed to check BOX user group. Please ensure ${bin_name} kernel is started." log Warning "Cleaning up tun rules." cleanup_iptables log Warning "Cleaning up tun rules done." ;; help|-h|--help|"") echo "Usage: $0 {enable|disable|renew}" echo echo "Commands:" echo " enable - Enable iptables rules" echo " disable - Disable iptables rules" echo " renew - Reapply or refresh iptables rules" echo echo "Example:" echo " $0 enable" ;; *) echo "$0: '$1' not found" echo "Run '$0 help' for usage." ;; esac fi