158 lines
5.6 KiB
Bash
158 lines
5.6 KiB
Bash
#!/system/bin/sh
|
|
# BFR Stealth - hardening without LSPosed (iptables port hide + API lockdown)
|
|
|
|
if ! /system/bin/sh -n /data/adb/box/settings.ini 2>/dev/null; then
|
|
echo "Err: settings.ini syntax error" >&2
|
|
exit 1
|
|
fi
|
|
|
|
scripts_dir="${0%/*}"
|
|
. /data/adb/box/settings.ini
|
|
|
|
STEALTH_CHAIN="sbfr_out"
|
|
STEALTH_CHAIN6="sbfr_out6"
|
|
STEALTH_INPUT="sbfr_in"
|
|
STEALTH_INPUT6="sbfr_in6"
|
|
|
|
buildVersion=$(getprop ro.build.version.release)
|
|
IPV="iptables"
|
|
IP6V="ip6tables"
|
|
buildVersionMajor=${buildVersion%%.*}
|
|
if [ "${buildVersionMajor:-0}" -ge 11 ]; then
|
|
IPV="iptables -w 100"
|
|
IP6V="ip6tables -w 100"
|
|
fi
|
|
|
|
stealth_ports_collect() {
|
|
_ports="${tproxy_port} ${redir_port}"
|
|
[ -n "${sidecar_listen_port}" ] && _ports="${_ports} ${sidecar_listen_port}"
|
|
[ -n "${sidecar_tt_port}" ] && _ports="${_ports} ${sidecar_tt_port}"
|
|
[ -n "${sidecar_olc_port}" ] && _ports="${_ports} ${sidecar_olc_port}"
|
|
[ -n "${wgobfs_listen_port}" ] && _ports="${_ports} ${wgobfs_listen_port}"
|
|
[ -n "${stealth_api_port}" ] && _ports="${_ports} ${stealth_api_port}"
|
|
|
|
if [ -f "${clash_config}" ]; then
|
|
_ec=$(busybox awk '!/^ *#/ && /external-controller:/{print $2}' "${clash_config}" 2>/dev/null | head -n1)
|
|
_ec_port=$(echo "${_ec}" | busybox awk -F: '{print $NF}')
|
|
[ -n "${_ec_port}" ] && _ports="${_ports} ${_ec_port}"
|
|
# Clash mixed/socks ports if present
|
|
_socks=$(busybox awk '!/^ *#/ && /socks-port:/{print $2}' "${clash_config}" 2>/dev/null | head -n1)
|
|
[ -n "${_socks}" ] && _ports="${_ports} ${_socks}"
|
|
_mixed=$(busybox awk '!/^ *#/ && /mixed-port:/{print $2}' "${clash_config}" 2>/dev/null | head -n1)
|
|
[ -n "${_mixed}" ] && _ports="${_ports} ${_mixed}"
|
|
fi
|
|
|
|
if [ -f "${sing_config}" ]; then
|
|
_sc=$(${box_dir}/bin/yq '.experimental.clash_api.external_controller // ""' "${sing_config}" 2>/dev/null)
|
|
_sc_port=$(echo "${_sc}" | busybox awk -F: '{print $NF}')
|
|
[ -n "${_sc_port}" ] && _ports="${_ports} ${_sc_port}"
|
|
fi
|
|
|
|
for _p in ${stealth_extra_ports}; do
|
|
_ports="${_ports} ${_p}"
|
|
done
|
|
|
|
echo "${_ports}" | tr ' ' '\n' | grep -E '^[0-9]+$' | sort -u
|
|
}
|
|
|
|
resolve_stealth_uids() {
|
|
stealth_uid_file="${box_run}/stealth_uids.list"
|
|
: > "${stealth_uid_file}"
|
|
|
|
for pkg in "${stealth_packages_list[@]}"; do
|
|
[ -z "${pkg}" ] && continue
|
|
uids=$(pm list packages -U --user all 2>/dev/null | grep "package:${pkg} " | busybox awk -F'uid:' '{print $2}' | busybox awk '{print $1}')
|
|
for uid in ${uids}; do
|
|
[ -n "${uid}" ] && echo "${uid}" >> "${stealth_uid_file}"
|
|
done
|
|
done
|
|
|
|
sort -u "${stealth_uid_file}" -o "${stealth_uid_file}" 2>/dev/null
|
|
}
|
|
|
|
stealth_chain_exists() {
|
|
${IPV} -L "${STEALTH_CHAIN}" -n >/dev/null 2>&1
|
|
}
|
|
|
|
stealth_disable() {
|
|
for ipt in "${IPV}" "${IP6V}"; do
|
|
chain="${STEALTH_CHAIN}"
|
|
in_chain="${STEALTH_INPUT}"
|
|
[ "${ipt}" = "${IP6V}" ] && chain="${STEALTH_CHAIN6}" && in_chain="${STEALTH_INPUT6}"
|
|
|
|
${ipt} -D OUTPUT -j "${chain}" >/dev/null 2>&1
|
|
${ipt} -F "${chain}" >/dev/null 2>&1
|
|
${ipt} -X "${chain}" >/dev/null 2>&1
|
|
|
|
${ipt} -D INPUT -j "${in_chain}" >/dev/null 2>&1
|
|
${ipt} -F "${in_chain}" >/dev/null 2>&1
|
|
${ipt} -X "${in_chain}" >/dev/null 2>&1
|
|
done
|
|
}
|
|
|
|
stealth_enable() {
|
|
[ "${stealth_mode}" != "true" ] && return 0
|
|
|
|
stealth_disable
|
|
resolve_stealth_uids
|
|
|
|
if [ ! -s "${box_run}/stealth_uids.list" ]; then
|
|
log Warning "[Stealth] No observer UIDs resolved - add packages to stealth.list.cfg"
|
|
return 0
|
|
fi
|
|
|
|
${IPV} -N "${STEALTH_CHAIN}" 2>/dev/null || ${IPV} -F "${STEALTH_CHAIN}"
|
|
${IP6V} -N "${STEALTH_CHAIN6}" 2>/dev/null || ${IP6V} -F "${STEALTH_CHAIN6}"
|
|
${IPV} -N "${STEALTH_INPUT}" 2>/dev/null || ${IPV} -F "${STEALTH_INPUT}"
|
|
${IP6V} -N "${STEALTH_INPUT6}" 2>/dev/null || ${IP6V} -F "${STEALTH_INPUT6}"
|
|
|
|
while read -r uid; do
|
|
[ -z "${uid}" ] && continue
|
|
if [ "${stealth_hide_loopback}" = "true" ]; then
|
|
${IPV} -A "${STEALTH_CHAIN}" -m owner --uid-owner "${uid}" -d 127.0.0.0/8 -p tcp -j REJECT --reject-with tcp-reset
|
|
${IPV} -A "${STEALTH_CHAIN}" -m owner --uid-owner "${uid}" -d 127.0.0.0/8 -p udp -j REJECT --reject-with icmp-port-unreachable
|
|
${IP6V} -A "${STEALTH_CHAIN6}" -m owner --uid-owner "${uid}" -d ::1/128 -p tcp -j REJECT --reject-with tcp-reset
|
|
${IP6V} -A "${STEALTH_CHAIN6}" -m owner --uid-owner "${uid}" -d ::1/128 -p udp -j REJECT --reject-with icmp6-port-unreachable
|
|
fi
|
|
done < "${box_run}/stealth_uids.list"
|
|
|
|
if [ "${stealth_block_external_api}" = "true" ]; then
|
|
for port in $(stealth_ports_collect); do
|
|
${IPV} -A "${STEALTH_INPUT}" -p tcp --dport "${port}" ! -s 127.0.0.0/8 -j DROP
|
|
${IP6V} -A "${STEALTH_INPUT6}" -p tcp --dport "${port}" ! -s ::1/128 -j DROP
|
|
done
|
|
fi
|
|
|
|
${IPV} -C OUTPUT -j "${STEALTH_CHAIN}" >/dev/null 2>&1 || ${IPV} -I OUTPUT 1 -j "${STEALTH_CHAIN}"
|
|
${IP6V} -C OUTPUT -j "${STEALTH_CHAIN6}" >/dev/null 2>&1 || ${IP6V} -I OUTPUT 1 -j "${STEALTH_CHAIN6}"
|
|
${IPV} -C INPUT -j "${STEALTH_INPUT}" >/dev/null 2>&1 || ${IPV} -I INPUT 1 -j "${STEALTH_INPUT}"
|
|
${IP6V} -C INPUT -j "${STEALTH_INPUT6}" >/dev/null 2>&1 || ${IP6V} -I INPUT 1 -j "${STEALTH_INPUT6}"
|
|
|
|
_count=$(wc -l < "${box_run}/stealth_uids.list" 2>/dev/null || echo 0)
|
|
log Info "[Stealth] Port-hide active for ${_count} observer UID(s), loopback=${stealth_hide_loopback}"
|
|
}
|
|
|
|
stealth_apply_quic() {
|
|
if [ "${stealth_block_quic}" = "true" ]; then
|
|
quic="disable"
|
|
fi
|
|
}
|
|
|
|
case "$1" in
|
|
enable) stealth_enable ;;
|
|
disable) stealth_disable ;;
|
|
renew) stealth_disable; stealth_enable ;;
|
|
status)
|
|
if stealth_chain_exists; then
|
|
log Info "[Stealth] Rules active"
|
|
${IPV} -L "${STEALTH_CHAIN}" -n -v 2>/dev/null | head -n 20
|
|
else
|
|
log Info "[Stealth] Rules not active"
|
|
fi
|
|
;;
|
|
*)
|
|
echo "usage: $0 {enable|disable|renew|status}"
|
|
exit 1
|
|
;;
|
|
esac
|