#!/bin/bash

# ============================================================
# Soga → ZeroTier 内网访问自动配置
#
# 用途：
#   手机 → Soga → ZeroTier → 10.1.4.0/24
#
# 特点：
#   - 零人工输入
#   - 自动检测 iptables
#   - 自动检测 NAT / MASQUERADE
#   - 自动检测 ZeroTier
#   - 自动识别 ZeroTier 网卡
#   - 自动识别 10.1.4.0/24
#   - 自动开启 IPv4 Forward
#   - 不修改 INPUT
#   - 不修改 OUTPUT
#   - 不修改默认防火墙策略
#   - 不删除已有规则
#   - 自动避免重复规则
#   - 自动备份
#   - 支持 install / uninstall
#
# 使用：
#   bash install-soga-zt.sh install
#   bash install-soga-zt.sh uninstall
#
# ============================================================

set -u
set -o pipefail

TARGET_NET="10.1.4.0/24"

RULE_COMMENT="SOGA-ZEROTIER-10.1.4"

BACKUP_DIR="/root/soga-zerotier-backup"

SYSCTL_FILE="/etc/sysctl.d/99-soga-zerotier.conf"

# ============================================================
# 基础函数
# ============================================================

log() {
    echo "[INFO] $1"
}

ok() {
    echo "[ OK ] $1"
}

warn() {
    echo "[WARN] $1"
}

err() {
    echo "[FAIL] $1"
}

die() {
    echo
    err "$1"
    echo
    exit 1
}

# ============================================================
# Root
# ============================================================

check_root() {

    if [ "$(id -u)" != "0" ]; then
        die "必须使用 root 运行"
    fi

}

# ============================================================
# 检查 iptables
# ============================================================

check_iptables() {

    log "检查 iptables..."

    if ! command -v iptables >/dev/null 2>&1; then
        die "系统没有安装 iptables"
    fi

    if ! iptables -L >/dev/null 2>&1; then
        die "iptables 无法正常工作"
    fi

    if ! iptables -t nat -L >/dev/null 2>&1; then
        die "iptables NAT 表不可用"
    fi

    if ! iptables -L FORWARD >/dev/null 2>&1; then
        die "iptables FORWARD 链不可用"
    fi

    ok "iptables: $(iptables --version 2>/dev/null)"
    ok "filter 表正常"
    ok "NAT 表正常"
    ok "FORWARD 正常"

}

# ============================================================
# 检查 MASQUERADE
# ============================================================

check_masquerade() {

    log "检查 MASQUERADE..."

    if iptables -t nat -A POSTROUTING \
        -s 127.0.0.1 \
        -d 127.0.0.1 \
        -j MASQUERADE 2>/dev/null; then

        iptables -t nat -D POSTROUTING \
            -s 127.0.0.1 \
            -d 127.0.0.1 \
            -j MASQUERADE 2>/dev/null || true

        ok "MASQUERADE 可用"

    else

        die "MASQUERADE 不可用"

    fi

}

# ============================================================
# ZeroTier
# ============================================================

check_zerotier() {

    log "检查 ZeroTier..."

    if ! command -v zerotier-cli >/dev/null 2>&1; then
        die "未安装 ZeroTier"
    fi

    if ! zerotier-cli info >/dev/null 2>&1; then
        die "ZeroTier 服务没有正常运行"
    fi

    ok "ZeroTier 正常"

}

# ============================================================
# 自动寻找 ZeroTier 网卡
# ============================================================

find_zerotier_interface() {

    ZT_IF=""

    while read -r IFACE; do

        [ -z "$IFACE" ] && continue

        if ip addr show "$IFACE" 2>/dev/null |
            grep -qE 'inet 10\.1\.4\.[0-9]+/'; then

            ZT_IF="$IFACE"
            break

        fi

    done < <(
        ip -o link show |
        awk -F': ' '{print $2}' |
        grep '^zt'
    )

    if [ -z "$ZT_IF" ]; then
        die "没有找到属于 10.1.4.0/24 的 ZeroTier 网卡"
    fi

    ok "ZeroTier 网卡：$ZT_IF"

}

# ============================================================
# 自动确认 ZeroTier 网段
# ============================================================

check_zerotier_network() {

    log "检查 ZeroTier 网络..."

    if ! ip addr show "$ZT_IF" 2>/dev/null |
        grep -qE 'inet 10\.1\.4\.[0-9]+/'; then

        die "ZeroTier 网卡没有 10.1.4.x 地址"

    fi

    if ! ip route |
        grep -qE "^10\.1\.4\.0/24.*dev $ZT_IF"; then

        die "没有发现 10.1.4.0/24 → $ZT_IF 路由"

    fi

    ZT_IP=$(
        ip -4 addr show "$ZT_IF" |
        awk '/inet 10\.1\.4\./ {print $2}' |
        cut -d/ -f1 |
        head -n1
    )

    ok "ZeroTier IP：$ZT_IP"
    ok "ZeroTier 网段：$TARGET_NET"

}

# ============================================================
# 测试目标
# ============================================================

check_target() {

    log "检查 10.1.4.3..."

    if ! ip route get 10.1.4.3 >/dev/null 2>&1; then
        die "系统没有到 10.1.4.3 的路由"
    fi

    ok "10.1.4.3 路由正常"

    if command -v ping >/dev/null 2>&1; then

        if ping -c 1 -W 2 10.1.4.3 >/dev/null 2>&1; then
            ok "服务器 → 10.1.4.3 连通"
        else
            warn "服务器 → 10.1.4.3 ping 不通"
            warn "可能是目标设备禁止 ICMP，继续配置"
        fi

    fi

}

# ============================================================
# 开启 IP Forward
# ============================================================

enable_forward() {

    log "检查 IPv4 Forward..."

    CURRENT=$(sysctl -n net.ipv4.ip_forward 2>/dev/null || echo 0)

    if [ "$CURRENT" = "1" ]; then

        ok "IPv4 Forward 已开启"

        return

    fi

    sysctl -w net.ipv4.ip_forward=1 >/dev/null

    cat > "$SYSCTL_FILE" <<EOF
# Soga → ZeroTier
net.ipv4.ip_forward=1
EOF

    sysctl --system >/dev/null 2>&1 || true

    ok "IPv4 Forward 已开启"

}

# ============================================================
# 备份
# ============================================================

backup_rules() {

    mkdir -p "$BACKUP_DIR"

    iptables-save > \
        "$BACKUP_DIR/iptables-$(date +%Y%m%d-%H%M%S).rules"

    ok "iptables 已备份到 $BACKUP_DIR"

}

# ============================================================
# 添加 FORWARD
#
# 注意：
# 不修改 INPUT
# 不修改 OUTPUT
# 不修改默认策略
# ============================================================

add_forward_rules() {

    log "配置 FORWARD..."

    # Soga → ZeroTier

    if iptables -C FORWARD \
        -d "$TARGET_NET" \
        -o "$ZT_IF" \
        -m comment \
        --comment "$RULE_COMMENT" \
        -j ACCEPT 2>/dev/null; then

        ok "Soga → ZeroTier FORWARD 已存在"

    else

        iptables -A FORWARD \
            -d "$TARGET_NET" \
            -o "$ZT_IF" \
            -m comment \
            --comment "$RULE_COMMENT" \
            -j ACCEPT

        ok "已添加 Soga → ZeroTier FORWARD"

    fi


    # ZeroTier → Soga 回程

    if iptables -C FORWARD \
        -s "$TARGET_NET" \
        -i "$ZT_IF" \
        -m conntrack \
        --ctstate ESTABLISHED,RELATED \
        -m comment \
        --comment "$RULE_COMMENT" \
        -j ACCEPT 2>/dev/null; then

        ok "ZeroTier → Soga 回程规则已存在"

    else

        iptables -A FORWARD \
            -s "$TARGET_NET" \
            -i "$ZT_IF" \
            -m conntrack \
            --ctstate ESTABLISHED,RELATED \
            -m comment \
            --comment "$RULE_COMMENT" \
            -j ACCEPT

        ok "已添加 ZeroTier → Soga 回程规则"

    fi

}

# ============================================================
# 添加 NAT
# ============================================================

add_nat_rule() {

    log "配置 NAT..."

    if iptables -t nat -C POSTROUTING \
        -d "$TARGET_NET" \
        -o "$ZT_IF" \
        -m comment \
        --comment "$RULE_COMMENT" \
        -j MASQUERADE 2>/dev/null; then

        ok "MASQUERADE 已存在"

    else

        iptables -t nat -A POSTROUTING \
            -d "$TARGET_NET" \
            -o "$ZT_IF" \
            -m comment \
            --comment "$RULE_COMMENT" \
            -j MASQUERADE

        ok "已添加 MASQUERADE"

    fi

}

# ============================================================
# 保存规则
# ============================================================

save_rules() {

    log "保存 iptables..."

    # Debian / Ubuntu
    if command -v netfilter-persistent >/dev/null 2>&1; then

        netfilter-persistent save >/dev/null 2>&1 || true

        ok "通过 netfilter-persistent 保存"

        return

    fi

    # 直接保存
    if command -v iptables-save >/dev/null 2>&1; then

        mkdir -p /etc/iptables

        iptables-save > /etc/iptables/rules.v4

        ok "保存到 /etc/iptables/rules.v4"

        return

    fi

    warn "无法自动保存 iptables"

}

# ============================================================
# 安装
# ============================================================

install_mode() {

    echo
    echo "=============================================="
    echo " Soga → ZeroTier 安装"
    echo "=============================================="
    echo

    check_root

    check_iptables

    check_masquerade

    check_zerotier

    find_zerotier_interface

    check_zerotier_network

    check_target

    enable_forward

    backup_rules

    add_forward_rules

    add_nat_rule

    save_rules

    echo
    echo "=============================================="
    echo " 配置完成"
    echo "=============================================="
    echo
    echo "ZeroTier 网卡 : $ZT_IF"
    echo "ZeroTier IP   : $ZT_IP"
    echo "ZeroTier 网段 : $TARGET_NET"
    echo
    echo "访问路径："
    echo
    echo "手机"
    echo " ↓"
    echo "Soga"
    echo " ↓"
    echo "$ZT_IF"
    echo " ↓"
    echo "$TARGET_NET"
    echo " ↓"
    echo "10.1.4.3"
    echo
    echo "=============================================="
    echo

}

# ============================================================
# 删除规则
# ============================================================

remove_rules() {

    echo
    echo "=============================================="
    echo " Soga → ZeroTier 卸载"
    echo "=============================================="
    echo

    check_root

    if ! command -v iptables >/dev/null 2>&1; then
        echo "iptables 未安装，无需处理"
        exit 0
    fi

    log "寻找 ZeroTier 网卡..."

    ZT_IF=""

    while read -r IFACE; do

        [ -z "$IFACE" ] && continue

        if ip addr show "$IFACE" 2>/dev/null |
            grep -qE 'inet 10\.1\.4\.[0-9]+/'; then

            ZT_IF="$IFACE"
            break

        fi

    done < <(
        ip -o link show |
        awk -F': ' '{print $2}' |
        grep '^zt'
    )

    if [ -z "$ZT_IF" ]; then

        warn "没有找到 ZeroTier 10.1.4.x 网卡"

    else

        ok "ZeroTier 网卡：$ZT_IF"

        # 删除 FORWARD

        while iptables -C FORWARD \
            -d "$TARGET_NET" \
            -o "$ZT_IF" \
            -m comment \
            --comment "$RULE_COMMENT" \
            -j ACCEPT 2>/dev/null; do

            iptables -D FORWARD \
                -d "$TARGET_NET" \
                -o "$ZT_IF" \
                -m comment \
                --comment "$RULE_COMMENT" \
                -j ACCEPT

            ok "删除 Soga → ZeroTier FORWARD"

        done


        # 删除回程

        while iptables -C FORWARD \
            -s "$TARGET_NET" \
            -i "$ZT_IF" \
            -m conntrack \
            --ctstate ESTABLISHED,RELATED \
            -m comment \
            --comment "$RULE_COMMENT" \
            -j ACCEPT 2>/dev/null; do

            iptables -D FORWARD \
                -s "$TARGET_NET" \
                -i "$ZT_IF" \
                -m conntrack \
                --ctstate ESTABLISHED,RELATED \
                -m comment \
                --comment "$RULE_COMMENT" \
                -j ACCEPT

            ok "删除 ZeroTier → Soga 回程规则"

        done


        # 删除 NAT

        while iptables -t nat -C POSTROUTING \
            -d "$TARGET_NET" \
            -o "$ZT_IF" \
            -m comment \
            --comment "$RULE_COMMENT" \
            -j MASQUERADE 2>/dev/null; do

            iptables -t nat -D POSTROUTING \
                -d "$TARGET_NET" \
                -o "$ZT_IF" \
                -m comment \
                --comment "$RULE_COMMENT" \
                -j MASQUERADE

            ok "删除 MASQUERADE"

        done

    fi

    # 删除我们创建的 sysctl 文件

    if [ -f "$SYSCTL_FILE" ]; then

        rm -f "$SYSCTL_FILE"

        ok "删除 IPv4 Forward 配置文件"

    fi

    # 注意：
    # 不主动关闭 ip_forward。
    #
    # 因为这台机器可能本来就需要 IPv4 forwarding。
    # 为避免影响 Soga / Docker / 其他服务，
    # 卸载时只删除我们自己的配置文件。

    save_rules

    echo
    echo "=============================================="
    echo " 卸载完成"
    echo "=============================================="
    echo

}

# ============================================================
# 参数
# ============================================================

case "${1:-install}" in

    install)
        install_mode
        ;;

    uninstall)
        remove_rules
        ;;

    *)
        echo
        echo "用法："
        echo
        echo "  $0 install"
        echo "  $0 uninstall"
        echo
        exit 1
        ;;

esac