183 lines
5.4 KiB
Bash
183 lines
5.4 KiB
Bash
#!/system/bin/sh
|
|
# VeilBox - WireGuard Obfuscator (ClusterM/wg-obfuscator) lifecycle
|
|
# Docs: https://github.com/ClusterM/wg-obfuscator
|
|
#
|
|
# Client flow:
|
|
# sing-box WireGuard peer → 127.0.0.1:wgobfs_listen_port
|
|
# → wg-obfuscator → real server obfuscator (or server WG via obfuscator)
|
|
#
|
|
# REQUIRED: the same key + matching ports on the VPS (server-side obfuscator).
|
|
# Without the server half this cannot work.
|
|
|
|
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
|
|
|
|
: "${wgobfs_enable:=false}"
|
|
: "${wgobfs_bin:=${box_dir}/bin/wg-obfuscator}"
|
|
: "${wgobfs_config:=${box_dir}/sidecar/wg-obfuscator.conf}"
|
|
: "${wgobfs_listen_port:=41320}"
|
|
: "${wgobfs_masking:=AUTO}"
|
|
: "${wgobfs_patch_config:=true}"
|
|
|
|
wgobfs_pid="${box_run}/wg-obfuscator.pid"
|
|
wgobfs_log="${box_run}/wg-obfuscator.log"
|
|
|
|
wgobfs_stop() {
|
|
if [ -f "${wgobfs_pid}" ]; then
|
|
spid=$(cat "${wgobfs_pid}" 2>/dev/null)
|
|
[ -n "${spid}" ] && kill -15 "${spid}" >/dev/null 2>&1
|
|
rm -f "${wgobfs_pid}"
|
|
fi
|
|
busybox pkill -15 wg-obfuscator >/dev/null 2>&1
|
|
}
|
|
|
|
wgobfs_wait_udp() {
|
|
# UDP listen is hard to probe with nc -z; rely on process + brief sleep
|
|
sleep 1
|
|
if [ -f "${wgobfs_pid}" ]; then
|
|
spid=$(cat "${wgobfs_pid}" 2>/dev/null)
|
|
kill -0 "${spid}" 2>/dev/null && return 0
|
|
fi
|
|
busybox pidof wg-obfuscator >/dev/null 2>&1
|
|
}
|
|
|
|
# Rewrite sing-box wireguard peers to localhost obfuscator listen port.
|
|
# Real endpoints are saved to ${box_run}/wgobfs-real-peers.txt (sing-box rejects unknown JSON fields).
|
|
wgobfs_patch_singbox() {
|
|
[ "${wgobfs_patch_config}" = "true" ] || return 0
|
|
[ "${bin_name}" != "sing-box" ] && return 0
|
|
[ ! -f "${sing_config}" ] && return 0
|
|
|
|
yq="${box_dir}/bin/yq"
|
|
[ -x "${yq}" ] || yq="yq"
|
|
if ! command -v "${yq}" >/dev/null 2>&1 && [ ! -x "${yq}" ]; then
|
|
log Warning "[wgobfs] yq missing - cannot patch WireGuard endpoint"
|
|
return 1
|
|
fi
|
|
|
|
if ! "${yq}" -e '.endpoints[] | select(.type == "wireguard")' "${sing_config}" >/dev/null 2>&1; then
|
|
log Warning "[wgobfs] no wireguard endpoint in ${sing_config}"
|
|
return 1
|
|
fi
|
|
|
|
state="${box_run}/wgobfs-real-peers.txt"
|
|
mkdir -p "${box_run}"
|
|
: > "${state}"
|
|
|
|
# Capture current non-loopback peers, then rewrite to local obfuscator
|
|
"${yq}" -r '
|
|
.endpoints[]? | select(.type == "wireguard") | .peers[]? |
|
|
((.address // "") + ":" + ((.port // 0)|tostring))
|
|
' "${sing_config}" 2>/dev/null | while read -r ep; do
|
|
case "${ep}" in
|
|
127.*|""|:0) continue ;;
|
|
*) echo "${ep}" >> "${state}" ;;
|
|
esac
|
|
done
|
|
|
|
"${yq}" -i -o=json '
|
|
(.endpoints[] | select(.type == "wireguard") | .peers[] | .address) = "127.0.0.1" |
|
|
(.endpoints[] | select(.type == "wireguard") | .peers[] | .port) = '"${wgobfs_listen_port}"'
|
|
' "${sing_config}" && \
|
|
log Info "[wgobfs] WireGuard peers → 127.0.0.1:${wgobfs_listen_port}"
|
|
|
|
# Direct route for real WG/obfuscator server IPs (avoid TPROXY loop)
|
|
if [ -f "${state}" ]; then
|
|
while read -r ep; do
|
|
ip="${ep%%:*}"
|
|
case "${ip}" in
|
|
127.*|"") continue ;;
|
|
esac
|
|
if ! "${yq}" -e ".route.rules[] | select(.ip_cidr[] == \"${ip}/32\")" "${sing_config}" >/dev/null 2>&1; then
|
|
"${yq}" -i -o=json ".route.rules = [{\"ip_cidr\":[\"${ip}/32\"],\"outbound\":\"direct\"}] + (.route.rules // [])" "${sing_config}" && \
|
|
log Info "[wgobfs] route direct ${ip}/32"
|
|
fi
|
|
done < "${state}"
|
|
fi
|
|
}
|
|
|
|
wgobfs_ensure_conf() {
|
|
mkdir -p "$(dirname "${wgobfs_config}")" "${box_run}"
|
|
if [ -f "${wgobfs_config}" ]; then
|
|
return 0
|
|
fi
|
|
if [ -f "${box_dir}/sidecar/wg-obfuscator.example.conf" ]; then
|
|
cp -f "${box_dir}/sidecar/wg-obfuscator.example.conf" "${wgobfs_config}"
|
|
log Warning "[wgobfs] created ${wgobfs_config} from example - edit key/target"
|
|
return 0
|
|
fi
|
|
log Error "[wgobfs] missing ${wgobfs_config}"
|
|
return 1
|
|
}
|
|
|
|
wgobfs_start() {
|
|
if [ "${wgobfs_enable}" != "true" ]; then
|
|
return 0
|
|
fi
|
|
|
|
if [ ! -x "${wgobfs_bin}" ]; then
|
|
log Error "[wgobfs] binary not found: ${wgobfs_bin}"
|
|
log Error "[wgobfs] download linux-arm64 from https://github.com/ClusterM/wg-obfuscator/releases"
|
|
return 1
|
|
fi
|
|
|
|
wgobfs_ensure_conf || return 1
|
|
wgobfs_stop
|
|
|
|
# Prefer source-if / source-lport from settings if config still has placeholders
|
|
# Launch with config file (multi-section supported)
|
|
nohup busybox setuidgid "${box_user_group}" \
|
|
"${wgobfs_bin}" -c "${wgobfs_config}" >> "${wgobfs_log}" 2>&1 &
|
|
echo -n "$!" > "${wgobfs_pid}"
|
|
log Info "[wgobfs] starting pid=$! config=${wgobfs_config}"
|
|
|
|
if wgobfs_wait_udp; then
|
|
log Info "[wgobfs] running (listen see config source-lport, default ${wgobfs_listen_port})"
|
|
else
|
|
log Error "[wgobfs] process died - see ${wgobfs_log}"
|
|
tail -n 15 "${wgobfs_log}" 2>/dev/null | while read -r line; do log Error "[wgobfs] ${line}"; done
|
|
return 1
|
|
fi
|
|
|
|
wgobfs_patch_singbox
|
|
return 0
|
|
}
|
|
|
|
wgobfs_status() {
|
|
echo "wgobfs_enable=${wgobfs_enable}"
|
|
echo "config=${wgobfs_config}"
|
|
echo "bin=${wgobfs_bin}"
|
|
if busybox pidof wg-obfuscator >/dev/null 2>&1; then
|
|
echo "pid=$(busybox pidof wg-obfuscator)"
|
|
echo "state=running"
|
|
else
|
|
echo "state=stopped"
|
|
fi
|
|
[ -f "${wgobfs_log}" ] && tail -n 8 "${wgobfs_log}"
|
|
}
|
|
|
|
case "$1" in
|
|
start)
|
|
wgobfs_start
|
|
;;
|
|
stop)
|
|
wgobfs_stop
|
|
log Info "[wgobfs] stopped"
|
|
;;
|
|
patch)
|
|
wgobfs_patch_singbox
|
|
;;
|
|
status)
|
|
wgobfs_status
|
|
;;
|
|
*)
|
|
echo "usage: $0 {start|stop|patch|status}"
|
|
exit 1
|
|
;;
|
|
esac
|