Redsocks

Admin留言 | 贡献2026年1月19日 (一) 01:47的版本 (创建页面,内容为“<syntaxhighlight lang="bash" line="1"> #!/usr/bin/env bash set -euo pipefail ### ================= 基本配置 ================= REDSOCKS_CONF="/etc/redsocks.conf" REDSOCKS_BIN="/usr/sbin/redsocks" # 源码版可能是 /usr/local/bin/redsocks REDSOCKS_PORT=12345 CHAIN="NETPROXY" MARK="0x1" STATE_DIR="/run/netproxy" IPTABLES_BACKUP="$STATE_DIR/iptables.bak" ### ================= 工具函数 ================= die() { echo "[ERROR] $*" >&2 exit 1…”)
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
#!/usr/bin/env bash
set -euo pipefail

### ================= 基本配置 =================
REDSOCKS_CONF="/etc/redsocks.conf"
REDSOCKS_BIN="/usr/sbin/redsocks"     # 源码版可能是 /usr/local/bin/redsocks
REDSOCKS_PORT=12345

CHAIN="NETPROXY"
MARK="0x1"

STATE_DIR="/run/netproxy"
IPTABLES_BACKUP="$STATE_DIR/iptables.bak"

### ================= 工具函数 =================
die() {
    echo "[ERROR] $*" >&2
    exit 1
}

need_root() {
    [[ $EUID -eq 0 ]] || die "Must run as root"
}

ensure_dirs() {
    mkdir -p "$STATE_DIR"
}

parse_proxy() {
    [[ "$1" =~ ^([^:]+):([0-9]+)$ ]] || die "Invalid proxy format: ip:port"
    PROXY_IP="${BASH_REMATCH[1]}"
    PROXY_PORT="${BASH_REMATCH[2]}"
}

### ================= redsocks =================
write_redsocks_conf() {
    cat > "$REDSOCKS_CONF" <<EOF
base {
    log_info = on;
    log = "syslog:daemon";
    daemon = on;
    redirector = iptables;
}

redsocks {
    local_ip = 127.0.0.1;
    local_port = $REDSOCKS_PORT;
    ip = $PROXY_IP;
    port = $PROXY_PORT;
    type = socks5;
}
EOF
}

start_redsocks() {
    pkill redsocks 2>/dev/null || true
    "$REDSOCKS_BIN" -c "$REDSOCKS_CONF"
}

stop_redsocks() {
    pkill redsocks 2>/dev/null || true
}

### ================= iptables =================
iptables_save() {
    iptables-save > "$IPTABLES_BACKUP"
}

iptables_restore() {
    [[ -f "$IPTABLES_BACKUP" ]] && iptables-restore < "$IPTABLES_BACKUP"
}

iptables_apply() {
    # nat 链
    iptables -t nat -N $CHAIN 2>/dev/null || true
    iptables -t nat -F $CHAIN

    # 已标记流量直接放行(防回环)
    iptables -t nat -A $CHAIN -m mark --mark $MARK -j RETURN

    # 本地 & 私网放行
    iptables -t nat -A $CHAIN -d 127.0.0.0/8 -j RETURN

    # 排除代理服务器自身(关键)
    iptables -t nat -A $CHAIN -d "$PROXY_IP" -j RETURN

    # TCP 全部重定向
    iptables -t nat -A $CHAIN -p tcp -j REDIRECT --to-ports $REDSOCKS_PORT

    # 挂载到 OUTPUT(只影响本机)
    iptables -t nat -C OUTPUT -p tcp -j $CHAIN 2>/dev/null || \
        iptables -t nat -A OUTPUT -p tcp -j $CHAIN

    # mangle:给 redsocks 出口流量打标记
    iptables -t mangle -C OUTPUT -p tcp --sport $REDSOCKS_PORT -j MARK --set-mark $MARK 2>/dev/null || \
        iptables -t mangle -A OUTPUT -p tcp --sport $REDSOCKS_PORT -j MARK --set-mark $MARK
}

iptables_clear() {
    iptables -t nat -D OUTPUT -p tcp -j $CHAIN 2>/dev/null || true
    iptables -t nat -F $CHAIN 2>/dev/null || true
    iptables -t nat -X $CHAIN 2>/dev/null || true

    iptables -t mangle -D OUTPUT -p tcp --sport $REDSOCKS_PORT -j MARK --set-mark $MARK 2>/dev/null || true
}

### ================= 命令实现 =================
cmd_start() {
    parse_proxy "$1"
    ensure_dirs
    iptables_save
    write_redsocks_conf
    start_redsocks
    iptables_apply
    echo "[OK] netproxy started via $PROXY_IP:$PROXY_PORT"
}

cmd_stop() {
    stop_redsocks
    iptables_restore || iptables_clear
    rm -rf "$STATE_DIR"
    echo "[OK] netproxy stopped and restored"
}

cmd_status() {
    echo "=== redsocks ==="
    pgrep redsocks >/dev/null && echo "running" || echo "stopped"

    echo
    echo "=== iptables nat ==="
    iptables -t nat -S | grep "$CHAIN" || echo "no netproxy nat rules"

    echo
    echo "=== iptables mangle ==="
    iptables -t mangle -S | grep "$REDSOCKS_PORT" || echo "no netproxy mangle rules"
}

### ================= 主入口 =================
need_root

case "${1:-}" in
    start)
        [[ $# -eq 2 ]] || die "Usage: $0 start ip:port"
        cmd_start "$2"
        ;;
    stop)
        cmd_stop
        ;;
    status)
        cmd_status
        ;;
    *)
        echo "Usage:"
        echo "  $0 start ip:port"
        echo "  $0 stop"
        echo "  $0 status"
        exit 1
        ;;
esac