263 lines
8.4 KiB
Bash
263 lines
8.4 KiB
Bash
#!/system/bin/sh
|
|
# BFR Sidecar - olcrtc / TrustTunnel local protocol adapters (SOCKS5 upstream for sing-box)
|
|
|
|
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
|
|
|
|
sidecar_dir="${box_dir}/sidecar"
|
|
sidecar_pid="${box_run}/sidecar.pid"
|
|
sidecar_pid_olc="${box_run}/sidecar-olcrtc.pid"
|
|
sidecar_pid_tt="${box_run}/sidecar-trusttunnel.pid"
|
|
sidecar_log="${box_run}/sidecar.log"
|
|
|
|
# Defaults for dual mode
|
|
: "${sidecar_tt_port:=10800}"
|
|
: "${sidecar_olc_port:=10801}"
|
|
: "${sidecar_olc_tag:=olcrtc-proxy}"
|
|
|
|
sidecar_stop() {
|
|
for pf in "${sidecar_pid}" "${sidecar_pid_olc}" "${sidecar_pid_tt}"; do
|
|
if [ -f "${pf}" ]; then
|
|
spid=$(cat "${pf}" 2>/dev/null)
|
|
[ -n "${spid}" ] && kill -15 "${spid}" >/dev/null 2>&1
|
|
rm -f "${pf}"
|
|
fi
|
|
done
|
|
for bin in olcrtc trusttunnel_client; do
|
|
busybox pkill -15 "${bin}" >/dev/null 2>&1
|
|
done
|
|
}
|
|
|
|
sidecar_wait_port() {
|
|
port="$1"
|
|
i=0
|
|
while [ "${i}" -lt 45 ]; do
|
|
if busybox nc -z 127.0.0.1 "${port}" 2>/dev/null; then
|
|
return 0
|
|
fi
|
|
sleep 1
|
|
i=$((i + 1))
|
|
done
|
|
return 1
|
|
}
|
|
|
|
sidecar_start_one() {
|
|
# $1=protocol $2=bin $3=cfg $4=port $5=pidfile $6=extra_args...
|
|
_proto="$1"; _bin="$2"; _cfg="$3"; _port="$4"; _pf="$5"
|
|
shift 5
|
|
|
|
if [ ! -x "${_bin}" ]; then
|
|
log Error "[Sidecar] Binary not found: ${_bin}"
|
|
return 1
|
|
fi
|
|
if [ ! -f "${_cfg}" ]; then
|
|
log Error "[Sidecar] Config not found: ${_cfg}"
|
|
return 1
|
|
fi
|
|
|
|
case "${_proto}" in
|
|
olcrtc)
|
|
nohup busybox setuidgid "${box_user_group}" "${_bin}" "${_cfg}" >> "${sidecar_log}" 2>&1 &
|
|
;;
|
|
trusttunnel)
|
|
nohup busybox setuidgid "${box_user_group}" "${_bin}" -s -c "${_cfg}" >> "${sidecar_log}" 2>&1 &
|
|
;;
|
|
*)
|
|
log Error "[Sidecar] Unknown protocol: ${_proto}"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
echo -n "$!" > "${_pf}"
|
|
# Also keep legacy sidecar.pid pointing at last/primary
|
|
echo -n "$!" > "${sidecar_pid}"
|
|
log Info "[Sidecar] Starting ${_proto} on 127.0.0.1:${_port} (pid $!)"
|
|
|
|
if sidecar_wait_port "${_port}"; then
|
|
log Info "[Sidecar] ${_proto} SOCKS ready on :${_port}"
|
|
return 0
|
|
fi
|
|
|
|
log Error "[Sidecar] Timeout waiting for ${_proto} port ${_port}"
|
|
tail -n 20 "${sidecar_log}" 2>/dev/null | while read -r line; do log Error "[Sidecar] ${line}"; done
|
|
return 1
|
|
}
|
|
|
|
sidecar_inject_socks() {
|
|
# $1=tag $2=port
|
|
tag="$1"
|
|
port="$2"
|
|
yq="${box_dir}/bin/yq"
|
|
[ -x "${yq}" ] || yq="yq"
|
|
|
|
if ! "${yq}" ".outbounds[] | select(.tag == \"${tag}\")" "${sing_config}" 2>/dev/null | grep -q .; then
|
|
"${yq}" ".outbounds += [{
|
|
\"type\": \"socks\",
|
|
\"tag\": \"${tag}\",
|
|
\"server\": \"127.0.0.1\",
|
|
\"server_port\": ${port},
|
|
\"version\": \"5\"
|
|
}]" -i --output-format=json "${sing_config}" && \
|
|
log Info "[Sidecar] Injected socks '${tag}' -> 127.0.0.1:${port}"
|
|
else
|
|
# Keep port in sync
|
|
"${yq}" "(.outbounds[] | select(.tag == \"${tag}\") | .server_port) = ${port}" -i --output-format=json "${sing_config}" 2>/dev/null
|
|
log Info "[Sidecar] Outbound '${tag}' already present (port=${port})"
|
|
fi
|
|
}
|
|
|
|
sidecar_patch_dns() {
|
|
tag="$1"
|
|
yq="${box_dir}/bin/yq"
|
|
[ -x "${yq}" ] || yq="yq"
|
|
|
|
"${yq}" '
|
|
( [.dns.servers[]? | select(.tag == "dns-direct")] | length) as $n |
|
|
if $n == 0 then .dns.servers = [{"type":"local","tag":"dns-direct"}] + (.dns.servers // []) else . end
|
|
' -i --output-format=json "${sing_config}" 2>/dev/null || true
|
|
|
|
"${yq}" '(.dns.servers[] | select(.detour == "proxy" or .tag == "dns-remote") | .detour) = "'"${tag}"'"' -i --output-format=json "${sing_config}" 2>/dev/null && \
|
|
log Info "[Sidecar] dns-remote detour -> ${tag}"
|
|
|
|
"${yq}" '
|
|
(.dns.servers[] | select(.tag == "dns-remote")) = {"type":"https","tag":"dns-remote","detour":"'"${tag}"'","server":"1.1.1.1","path":"/dns-query"} |
|
|
.dns.final = "dns-remote" |
|
|
.dns.strategy = "ipv4_only"
|
|
' -i --output-format=json "${sing_config}" 2>/dev/null && \
|
|
log Info "[Sidecar] dns-remote -> https/1.1.1.1 via ${tag}, strategy ipv4_only"
|
|
}
|
|
|
|
sidecar_inject_singbox() {
|
|
[ "${sidecar_enable}" != "true" ] && return 0
|
|
[ "${bin_name}" != "sing-box" ] && return 0
|
|
[ ! -f "${sing_config}" ] && return 0
|
|
|
|
yq="${box_dir}/bin/yq"
|
|
if [ ! -x "${yq}" ]; then
|
|
if command -v yq >/dev/null 2>&1; then
|
|
yq="yq"
|
|
else
|
|
log Error "[Sidecar] yq not found - cannot inject socks outbound"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
case "${sidecar_protocol}" in
|
|
both)
|
|
# Fixed tags for BFR Manager profiles (ignore mis-set sidecar_outbound_tag)
|
|
sidecar_inject_socks "sidecar-proxy" "${sidecar_tt_port}"
|
|
sidecar_inject_socks "${sidecar_olc_tag}" "${sidecar_olc_port}"
|
|
# Prefer final already set in the active profile (BFR Manager Manage Profiles)
|
|
cur_final=$("${yq}" -r '.route.final // ""' "${sing_config}" 2>/dev/null)
|
|
case "${cur_final}" in
|
|
"${sidecar_olc_tag}"|sidecar-proxy|"${sidecar_outbound_tag}")
|
|
final_tag="${cur_final}"
|
|
;;
|
|
*)
|
|
final_tag="sidecar-proxy"
|
|
;;
|
|
esac
|
|
;;
|
|
olcrtc)
|
|
sidecar_inject_socks "${sidecar_outbound_tag}" "${sidecar_listen_port}"
|
|
final_tag="${sidecar_outbound_tag}"
|
|
;;
|
|
trusttunnel|*)
|
|
sidecar_inject_socks "${sidecar_outbound_tag}" "${sidecar_listen_port}"
|
|
final_tag="${sidecar_outbound_tag}"
|
|
;;
|
|
esac
|
|
|
|
if [ "${sidecar_set_final}" = "true" ]; then
|
|
"${yq}" ".route.final = \"${final_tag}\"" -i --output-format=json "${sing_config}" && \
|
|
log Info "[Sidecar] route.final -> ${final_tag}"
|
|
sidecar_patch_dns "${final_tag}"
|
|
else
|
|
log Info "[Sidecar] sidecar_set_final=false - keep profile route.final (BFR Manager switch)"
|
|
fi
|
|
}
|
|
|
|
sidecar_start_process() {
|
|
if [ "${sidecar_enable}" != "true" ]; then
|
|
return 0
|
|
fi
|
|
|
|
if [ -z "${sidecar_protocol}" ]; then
|
|
log Error "[Sidecar] sidecar_protocol is empty (olcrtc | trusttunnel | both)"
|
|
return 1
|
|
fi
|
|
|
|
sidecar_stop
|
|
mkdir -p "${sidecar_dir}" "${box_run}" /data/adb/box/run/olcrtc-data
|
|
: > "${sidecar_log}"
|
|
|
|
case "${sidecar_protocol}" in
|
|
olcrtc)
|
|
sidecar_start_one olcrtc "${box_dir}/bin/olcrtc" "${sidecar_dir}/olcrtc.yaml" \
|
|
"${sidecar_listen_port}" "${sidecar_pid_olc}" || return 1
|
|
;;
|
|
trusttunnel)
|
|
sidecar_start_one trusttunnel "${box_dir}/bin/trusttunnel_client" "${sidecar_dir}/trusttunnel.toml" \
|
|
"${sidecar_listen_port}" "${sidecar_pid_tt}" || return 1
|
|
;;
|
|
both)
|
|
# TT + olcrtc for BFR Manager profile flipping; missing one must not block the other
|
|
sidecar_start_one trusttunnel "${box_dir}/bin/trusttunnel_client" "${sidecar_dir}/trusttunnel.toml" \
|
|
"${sidecar_tt_port}" "${sidecar_pid_tt}" || \
|
|
log Warning "[Sidecar] trusttunnel failed/missing - continue without it"
|
|
sleep 2
|
|
sidecar_start_one olcrtc "${box_dir}/bin/olcrtc" "${sidecar_dir}/olcrtc.yaml" \
|
|
"${sidecar_olc_port}" "${sidecar_pid_olc}" || {
|
|
log Warning "[Sidecar] olcrtc failed to start - continuing without it"
|
|
log Warning "[Sidecar] Tip: telemost room.id = full https://telemost.yandex.ru/j/<id> URL (or numeric id)"
|
|
log Warning "[Sidecar] Tip: under root:net_admin set net.dns to LAN resolver (e.g. gateway:53)"
|
|
}
|
|
# Only hard-fail if neither SOCKS came up
|
|
if ! busybox nc -z 127.0.0.1 "${sidecar_tt_port}" 2>/dev/null && \
|
|
! busybox nc -z 127.0.0.1 "${sidecar_olc_port}" 2>/dev/null; then
|
|
log Error "[Sidecar] neither trusttunnel nor olcrtc is listening"
|
|
return 1
|
|
fi
|
|
;;
|
|
*)
|
|
log Error "[Sidecar] Unknown protocol: ${sidecar_protocol}"
|
|
return 1
|
|
;;
|
|
esac
|
|
return 0
|
|
}
|
|
|
|
case "$1" in
|
|
start)
|
|
sidecar_start_process && sidecar_inject_singbox
|
|
;;
|
|
stop)
|
|
sidecar_stop
|
|
log Info "[Sidecar] Stopped"
|
|
;;
|
|
inject)
|
|
sidecar_inject_singbox
|
|
;;
|
|
status)
|
|
echo "protocol=${sidecar_protocol}"
|
|
for pf in "${sidecar_pid_tt}" "${sidecar_pid_olc}" "${sidecar_pid}"; do
|
|
[ -f "${pf}" ] || continue
|
|
spid=$(cat "${pf}" 2>/dev/null)
|
|
if [ -n "${spid}" ] && kill -0 "${spid}" 2>/dev/null; then
|
|
log Info "[Sidecar] alive pid=${spid} file=$(basename "${pf}")"
|
|
fi
|
|
done
|
|
busybox nc -z 127.0.0.1 "${sidecar_tt_port}" 2>/dev/null && echo "port ${sidecar_tt_port} open" || true
|
|
busybox nc -z 127.0.0.1 "${sidecar_olc_port}" 2>/dev/null && echo "port ${sidecar_olc_port} open" || true
|
|
;;
|
|
*)
|
|
echo "usage: $0 {start|stop|inject|status}"
|
|
exit 1
|
|
;;
|
|
esac
|