895 lines
34 KiB
Bash
Executable File
895 lines
34 KiB
Bash
Executable File
#!/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
|