feat: cellular-proxy 一键安装 — 走代理一律数据出口
- sing-box 单进程 bind 数据网卡 - mixed HTTP+SOCKS + 中文静态面板 - install.sh 支持 curl | sudo bash - 512MB 友好 MemoryMax 默认 96MB
This commit is contained in:
Executable
+159
@@ -0,0 +1,159 @@
|
||||
#!/usr/bin/env bash
|
||||
# 公共库
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
CONFIG_FILE="${CONFIG_FILE:-$ROOT_DIR/config/settings.conf}"
|
||||
|
||||
log() { printf '[%s] %s\n' "$(date '+%F %T')" "$*" >&2; }
|
||||
info() { log "INFO $*"; }
|
||||
warn() { log "WARN $*"; }
|
||||
err() { log "ERROR $*"; }
|
||||
die() { err "$*"; exit 1; }
|
||||
|
||||
need_root() {
|
||||
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
|
||||
die "请用 root 运行(sudo)"
|
||||
fi
|
||||
}
|
||||
|
||||
load_config() {
|
||||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||||
die "缺少配置: $CONFIG_FILE
|
||||
请先: cp $ROOT_DIR/config/settings.conf.example $ROOT_DIR/config/settings.conf"
|
||||
fi
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
source "$CONFIG_FILE"
|
||||
set +a
|
||||
|
||||
INSTALL_DIR="${INSTALL_DIR:-/opt/cellular-proxy}"
|
||||
LOG_DIR="${LOG_DIR:-/var/log/cellular-proxy}"
|
||||
CELLULAR_IFACE="${CELLULAR_IFACE:-}"
|
||||
CELLULAR_SOURCE_IP="${CELLULAR_SOURCE_IP:-}"
|
||||
REQUIRE_CELLULAR_IFACE="${REQUIRE_CELLULAR_IFACE:-true}"
|
||||
CELLULAR_IFACE_PATTERNS="${CELLULAR_IFACE_PATTERNS:-wwan,wwp,usb,enx,ppp,cdc}"
|
||||
PROXY_LISTEN_HOST="${PROXY_LISTEN_HOST:-0.0.0.0}"
|
||||
PROXY_MIXED_PORT="${PROXY_MIXED_PORT:-7890}"
|
||||
PROXY_USER="${PROXY_USER:-}"
|
||||
PROXY_PASS="${PROXY_PASS:-}"
|
||||
PANEL_LISTEN_HOST="${PANEL_LISTEN_HOST:-0.0.0.0}"
|
||||
PANEL_PORT="${PANEL_PORT:-9090}"
|
||||
PANEL_SECRET="${PANEL_SECRET:-please-change-me}"
|
||||
ENABLE_DNS="${ENABLE_DNS:-true}"
|
||||
LOG_LEVEL="${LOG_LEVEL:-warn}"
|
||||
SING_BOX_SOURCE="${SING_BOX_SOURCE:-release}"
|
||||
SING_BOX_VERSION="${SING_BOX_VERSION:-1.11.7}"
|
||||
SING_BOX_BIN="${SING_BOX_BIN:-}"
|
||||
MEMORY_MAX_MB="${MEMORY_MAX_MB:-96}"
|
||||
EGRESS_CHECK_URL="${EGRESS_CHECK_URL:-https://ifconfig.me}"
|
||||
EXPECTED_CELLULAR_PUBLIC_IP="${EXPECTED_CELLULAR_PUBLIC_IP:-}"
|
||||
|
||||
for v in REQUIRE_CELLULAR_IFACE ENABLE_DNS; do
|
||||
val="${!v}"
|
||||
case "${val,,}" in
|
||||
1|true|yes|on) printf -v "$v" '%s' true ;;
|
||||
*) printf -v "$v" '%s' false ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
iface_exists() {
|
||||
local ifc="$1"
|
||||
[[ -n "$ifc" ]] && [[ -d "/sys/class/net/$ifc" ]]
|
||||
}
|
||||
|
||||
is_virtual_or_skip_iface() {
|
||||
local name="$1"
|
||||
case "$name" in
|
||||
lo|docker*|br-*|veth*|virbr*|cni*|flannel*|tun*|tap*|wg*|zt*|tailscale*|easy*|et*)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
list_ifaces() {
|
||||
local name state ip
|
||||
for name in $(ls /sys/class/net 2>/dev/null | sort); do
|
||||
[[ "$name" == "lo" ]] && continue
|
||||
state="$(cat "/sys/class/net/$name/operstate" 2>/dev/null || echo unknown)"
|
||||
ip="$(ip -4 -o addr show dev "$name" 2>/dev/null | awk '{print $4}' | head -1)"
|
||||
printf '%s|%s|%s\n' "$name" "$state" "${ip:-}"
|
||||
done
|
||||
}
|
||||
|
||||
detect_default_iface() {
|
||||
ip route show default 2>/dev/null | awk '/default/ {print $5; exit}'
|
||||
}
|
||||
|
||||
detect_cellular_iface() {
|
||||
local configured="$1"
|
||||
if [[ -n "$configured" ]]; then
|
||||
if [[ "$configured" == "lo" ]]; then
|
||||
warn "CELLULAR_IFACE=lo 无效,将尝试自动探测"
|
||||
elif iface_exists "$configured"; then
|
||||
echo "$configured"
|
||||
return 0
|
||||
else
|
||||
warn "配置的 CELLULAR_IFACE=$configured 不存在"
|
||||
if [[ "$REQUIRE_CELLULAR_IFACE" == "true" ]]; then
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
local patterns name state ip p cand=""
|
||||
IFS=',' read -r -a patterns <<< "$CELLULAR_IFACE_PATTERNS"
|
||||
while IFS='|' read -r name state ip; do
|
||||
[[ -z "$name" ]] && continue
|
||||
is_virtual_or_skip_iface "$name" && continue
|
||||
for p in "${patterns[@]}"; do
|
||||
p="${p// /}"
|
||||
[[ -z "$p" ]] && continue
|
||||
if [[ "$name" == *"$p"* ]]; then
|
||||
if [[ "$state" == "up" || "$state" == "unknown" ]] && [[ -n "$ip" ]]; then
|
||||
echo "$name"
|
||||
return 0
|
||||
fi
|
||||
cand="${cand:-$name}"
|
||||
fi
|
||||
done
|
||||
done < <(list_ifaces)
|
||||
|
||||
if [[ -n "$cand" ]]; then
|
||||
echo "$cand"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
detect_source_ip() {
|
||||
local ifc="$1"
|
||||
ip -4 -o addr show dev "$ifc" 2>/dev/null | awk '{print $4}' | head -1 | cut -d/ -f1
|
||||
}
|
||||
|
||||
arch_go() {
|
||||
case "$(uname -m)" in
|
||||
x86_64|amd64) echo amd64 ;;
|
||||
aarch64|arm64) echo arm64 ;;
|
||||
armv7l|armhf) echo armv7 ;;
|
||||
*) die "不支持的架构: $(uname -m)" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
ensure_dirs() {
|
||||
mkdir -p "$INSTALL_DIR"/{bin,etc,ui,generated} "$LOG_DIR"
|
||||
}
|
||||
|
||||
resolve_cellular() {
|
||||
local cell
|
||||
if ! cell="$(detect_cellular_iface "$CELLULAR_IFACE")"; then
|
||||
if [[ "$REQUIRE_CELLULAR_IFACE" == "true" ]]; then
|
||||
die "无法确定数据网卡。请设置 CELLULAR_IFACE= 或运行 scripts/detect.sh"
|
||||
fi
|
||||
warn "未找到数据网卡"
|
||||
cell=""
|
||||
fi
|
||||
echo "$cell"
|
||||
}
|
||||
Reference in New Issue
Block a user